experiments in a post-browser web
10
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat tile-ipc + tile-preload: strict handlers for remaining 13 datastore methods

+241 -20
+221
backend/electron/tile-ipc.ts
··· 53 53 getItemsByTag as dsGetItemsByTag, 54 54 getOrCreateTag as dsGetOrCreateTag, 55 55 getTagsByFrecency as dsGetTagsByFrecency, 56 + renameTag as dsRenameTag, 57 + updateTagColor as dsUpdateTagColor, 58 + deleteTag as dsDeleteTag, 59 + getStats as dsGetStats, 60 + hardDeleteItem as dsHardDeleteItem, 61 + updateItemTitle as dsUpdateItemTitle, 62 + updateItemFavicon as dsUpdateItemFavicon, 63 + recordItemVisit as dsRecordItemVisit, 64 + getItemVisits as dsGetItemVisits, 65 + queryItemVisits as dsQueryItemVisits, 66 + trackNavigation as dsTrackNavigation, 67 + queryItemsByFrecency as dsQueryItemsByFrecency, 56 68 addItemEvent as dsAddItemEvent, 57 69 queryItemEvents as dsQueryItemEvents, 58 70 getLatestItemEvent as dsGetLatestItemEvent, ··· 3753 3765 if ('error' in check) { handleDatastoreViolation(args?.token, 'datastore:delete-item-events', check.error); return { error: check.error }; } 3754 3766 try { 3755 3767 const data = dsDeleteItemEvents(args.itemId); 3768 + return { success: true, data }; 3769 + } catch (error) { 3770 + return { success: false, error: error instanceof Error ? error.message : String(error) }; 3771 + } 3772 + }); 3773 + 3774 + // ── Additional tag operations ── 3775 + 3776 + ipcMain.handle('tile:datastore:rename-tag', async (_event, args: { 3777 + token: string; 3778 + tagId: string; 3779 + newName: string; 3780 + }) => { 3781 + const check = validateTileDatastoreRequest(args?.token, ['tags']); 3782 + if ('error' in check) { handleDatastoreViolation(args?.token, 'datastore:rename-tag', check.error); return { error: check.error }; } 3783 + try { 3784 + const data = dsRenameTag(args.tagId, args.newName); 3785 + return { success: true, data }; 3786 + } catch (error) { 3787 + return { success: false, error: error instanceof Error ? error.message : String(error) }; 3788 + } 3789 + }); 3790 + 3791 + ipcMain.handle('tile:datastore:update-tag-color', async (_event, args: { 3792 + token: string; 3793 + tagId: string; 3794 + color: string; 3795 + }) => { 3796 + const check = validateTileDatastoreRequest(args?.token, ['tags']); 3797 + if ('error' in check) { handleDatastoreViolation(args?.token, 'datastore:update-tag-color', check.error); return { error: check.error }; } 3798 + try { 3799 + const data = dsUpdateTagColor(args.tagId, args.color); 3800 + return { success: true, data }; 3801 + } catch (error) { 3802 + return { success: false, error: error instanceof Error ? error.message : String(error) }; 3803 + } 3804 + }); 3805 + 3806 + ipcMain.handle('tile:datastore:delete-tag', async (_event, args: { 3807 + token: string; 3808 + tagId: string; 3809 + }) => { 3810 + const check = validateTileDatastoreRequest(args?.token, ['tags']); 3811 + if ('error' in check) { handleDatastoreViolation(args?.token, 'datastore:delete-tag', check.error); return { error: check.error }; } 3812 + try { 3813 + const data = dsDeleteTag(args.tagId); 3814 + return { success: true, data }; 3815 + } catch (error) { 3816 + return { success: false, error: error instanceof Error ? error.message : String(error) }; 3817 + } 3818 + }); 3819 + 3820 + // ── Stats (no table restriction) ── 3821 + 3822 + ipcMain.handle('tile:datastore:get-stats', async (_event, args: { 3823 + token: string; 3824 + }) => { 3825 + const check = validateTileDatastoreRequest(args?.token, []); 3826 + if ('error' in check) { handleDatastoreViolation(args?.token, 'datastore:get-stats', check.error); return { error: check.error }; } 3827 + try { 3828 + const data = dsGetStats(); 3829 + return { success: true, data }; 3830 + } catch (error) { 3831 + return { success: false, error: error instanceof Error ? error.message : String(error) }; 3832 + } 3833 + }); 3834 + 3835 + // ── Additional item operations ── 3836 + 3837 + ipcMain.handle('tile:datastore:hard-delete-item', async (_event, args: { 3838 + token: string; 3839 + id: string; 3840 + }) => { 3841 + const check = validateTileDatastoreRequest(args?.token, ['items']); 3842 + if ('error' in check) { handleDatastoreViolation(args?.token, 'datastore:hard-delete-item', check.error); return { error: check.error }; } 3843 + try { 3844 + const data = dsHardDeleteItem(args.id); 3845 + return { success: true, data }; 3846 + } catch (error) { 3847 + return { success: false, error: error instanceof Error ? error.message : String(error) }; 3848 + } 3849 + }); 3850 + 3851 + ipcMain.handle('tile:datastore:update-item-title', async (_event, args: { 3852 + token: string; 3853 + url: string; 3854 + title: string; 3855 + }) => { 3856 + const check = validateTileDatastoreRequest(args?.token, ['items']); 3857 + if ('error' in check) { handleDatastoreViolation(args?.token, 'datastore:update-item-title', check.error); return { error: check.error }; } 3858 + try { 3859 + const data = dsUpdateItemTitle(args.url, args.title); 3860 + return { success: true, data }; 3861 + } catch (error) { 3862 + return { success: false, error: error instanceof Error ? error.message : String(error) }; 3863 + } 3864 + }); 3865 + 3866 + ipcMain.handle('tile:datastore:update-item-favicon', async (_event, args: { 3867 + token: string; 3868 + url: string; 3869 + faviconUrl: string; 3870 + }) => { 3871 + const check = validateTileDatastoreRequest(args?.token, ['items']); 3872 + if ('error' in check) { handleDatastoreViolation(args?.token, 'datastore:update-item-favicon', check.error); return { error: check.error }; } 3873 + try { 3874 + const data = dsUpdateItemFavicon(args.url, args.faviconUrl); 3875 + return { success: true, data }; 3876 + } catch (error) { 3877 + return { success: false, error: error instanceof Error ? error.message : String(error) }; 3878 + } 3879 + }); 3880 + 3881 + // ── Visit / history operations (require 'items') ── 3882 + 3883 + ipcMain.handle('tile:datastore:record-item-visit', async (_event, args: { 3884 + token: string; 3885 + itemId: string; 3886 + options?: Record<string, unknown>; 3887 + }) => { 3888 + const check = validateTileDatastoreRequest(args?.token, ['items']); 3889 + if ('error' in check) { handleDatastoreViolation(args?.token, 'datastore:record-item-visit', check.error); return { error: check.error }; } 3890 + try { 3891 + const data = dsRecordItemVisit(args.itemId, args.options as Parameters<typeof dsRecordItemVisit>[1]); 3892 + return { success: true, data }; 3893 + } catch (error) { 3894 + return { success: false, error: error instanceof Error ? error.message : String(error) }; 3895 + } 3896 + }); 3897 + 3898 + ipcMain.handle('tile:datastore:get-item-visits', async (_event, args: { 3899 + token: string; 3900 + itemId: string; 3901 + filter?: Record<string, unknown>; 3902 + }) => { 3903 + const check = validateTileDatastoreRequest(args?.token, ['items']); 3904 + if ('error' in check) { handleDatastoreViolation(args?.token, 'datastore:get-item-visits', check.error); return { error: check.error }; } 3905 + try { 3906 + const data = dsGetItemVisits(args.itemId, args.filter as Parameters<typeof dsGetItemVisits>[1]); 3907 + return { success: true, data }; 3908 + } catch (error) { 3909 + return { success: false, error: error instanceof Error ? error.message : String(error) }; 3910 + } 3911 + }); 3912 + 3913 + ipcMain.handle('tile:datastore:query-item-visits', async (_event, args: { 3914 + token: string; 3915 + filter?: Record<string, unknown>; 3916 + }) => { 3917 + const check = validateTileDatastoreRequest(args?.token, ['items']); 3918 + if ('error' in check) { handleDatastoreViolation(args?.token, 'datastore:query-item-visits', check.error); return { error: check.error }; } 3919 + try { 3920 + const data = dsQueryItemVisits(args.filter as Parameters<typeof dsQueryItemVisits>[0]); 3921 + return { success: true, data }; 3922 + } catch (error) { 3923 + return { success: false, error: error instanceof Error ? error.message : String(error) }; 3924 + } 3925 + }); 3926 + 3927 + ipcMain.handle('tile:datastore:get-history', async (_event, args: { 3928 + token: string; 3929 + filter?: Record<string, unknown>; 3930 + }) => { 3931 + const check = validateTileDatastoreRequest(args?.token, ['items']); 3932 + if ('error' in check) { handleDatastoreViolation(args?.token, 'datastore:get-history', check.error); return { error: check.error }; } 3933 + try { 3934 + const filter = (args.filter as Parameters<typeof dsQueryItemVisits>[0]) || {}; 3935 + const visits = dsQueryItemVisits(filter); 3936 + const enriched = visits.map(v => { 3937 + const item = dsGetItem(v.itemId); 3938 + return { 3939 + ...v, 3940 + addressId: v.itemId, 3941 + uri: item?.content || '', 3942 + title: item?.title || '', 3943 + domain: item?.domain || '', 3944 + protocol: '', 3945 + favicon: item?.favicon || '', 3946 + }; 3947 + }); 3948 + return { success: true, data: enriched }; 3949 + } catch (error) { 3950 + return { success: false, error: error instanceof Error ? error.message : String(error) }; 3951 + } 3952 + }); 3953 + 3954 + ipcMain.handle('tile:datastore:track-navigation', async (_event, args: { 3955 + token: string; 3956 + uri: string; 3957 + options?: Record<string, unknown>; 3958 + }) => { 3959 + const check = validateTileDatastoreRequest(args?.token, ['items']); 3960 + if ('error' in check) { handleDatastoreViolation(args?.token, 'datastore:track-navigation', check.error); return { error: check.error }; } 3961 + try { 3962 + const data = dsTrackNavigation(args.uri, args.options as Parameters<typeof dsTrackNavigation>[1]); 3963 + return { success: true, data }; 3964 + } catch (error) { 3965 + return { success: false, error: error instanceof Error ? error.message : String(error) }; 3966 + } 3967 + }); 3968 + 3969 + ipcMain.handle('tile:datastore:query-items-by-frecency', async (_event, args: { 3970 + token: string; 3971 + filter?: Record<string, unknown>; 3972 + }) => { 3973 + const check = validateTileDatastoreRequest(args?.token, ['items']); 3974 + if ('error' in check) { handleDatastoreViolation(args?.token, 'datastore:query-items-by-frecency', check.error); return { error: check.error }; } 3975 + try { 3976 + const data = dsQueryItemsByFrecency(args.filter as Parameters<typeof dsQueryItemsByFrecency>[0]); 3756 3977 return { success: true, data }; 3757 3978 } catch (error) { 3758 3979 return { success: false, error: error instanceof Error ? error.message : String(error) };
+20 -20
backend/electron/tile-preload.cts
··· 783 783 ipcRenderer.invoke('datastore-set-row', { tableName, rowId, rowData }), 784 784 getRow: (tableName: string, rowId: string) => 785 785 ipcRenderer.invoke('datastore-get-row', { tableName, rowId }), 786 - getStats: () => ipcRenderer.invoke('datastore-get-stats'), 786 + getStats: () => ipcRenderer.invoke('tile:datastore:get-stats', { token: tileToken }), 787 787 // Tag helpers 788 788 getOrCreateTag: (name: string) => 789 789 ipcRenderer.invoke('datastore-get-or-create-tag', { name }), ··· 794 794 getTagsByFrecency: (domain?: string) => 795 795 ipcRenderer.invoke('datastore-get-tags-by-frecency', { domain }), 796 796 renameTag: (tagId: string, newName: string) => 797 - ipcRenderer.invoke('datastore-rename-tag', { tagId, newName }), 797 + ipcRenderer.invoke('tile:datastore:rename-tag', { token: tileToken, tagId, newName }), 798 798 updateTagColor: (tagId: string, color: string) => 799 - ipcRenderer.invoke('datastore-update-tag-color', { tagId, color }), 799 + ipcRenderer.invoke('tile:datastore:update-tag-color', { token: tileToken, tagId, color }), 800 800 deleteTag: (tagId: string) => 801 - ipcRenderer.invoke('datastore-delete-tag', { tagId }), 801 + ipcRenderer.invoke('tile:datastore:delete-tag', { token: tileToken, tagId }), 802 802 getAddressTags: (addressId: string) => 803 803 ipcRenderer.invoke('datastore-get-address-tags', { addressId }), 804 804 getAddressesByTag: (tagId: string) => ··· 815 815 deleteItem: (id: string) => 816 816 ipcRenderer.invoke('datastore-delete-item', { id }), 817 817 hardDeleteItem: (id: string) => 818 - ipcRenderer.invoke('datastore-hard-delete-item', { id }), 819 - updateItemTitle: (id: string, title: string) => 820 - ipcRenderer.invoke('datastore-update-item-title', { id, title }), 821 - updateItemFavicon: (id: string, favicon: string) => 822 - ipcRenderer.invoke('datastore-update-item-favicon', { id, favicon }), 818 + ipcRenderer.invoke('tile:datastore:hard-delete-item', { token: tileToken, id }), 819 + updateItemTitle: (url: string, title: string) => 820 + ipcRenderer.invoke('tile:datastore:update-item-title', { token: tileToken, url, title }), 821 + updateItemFavicon: (url: string, faviconUrl: string) => 822 + ipcRenderer.invoke('tile:datastore:update-item-favicon', { token: tileToken, url, faviconUrl }), 823 823 queryItems: (filter: unknown = {}) => 824 824 ipcRenderer.invoke('datastore-query-items', { filter }), 825 825 tagItem: (itemId: string, tagId: string) => ··· 831 831 getItemsByTag: (tagId: string) => 832 832 ipcRenderer.invoke('datastore-get-items-by-tag', { tagId }), 833 833 getHistory: (filter: unknown = {}) => 834 - ipcRenderer.invoke('datastore-get-history', filter), 835 - recordItemVisit: (data: unknown) => 836 - ipcRenderer.invoke('datastore-record-item-visit', data), 837 - getItemVisits: (data: unknown) => 838 - ipcRenderer.invoke('datastore-get-item-visits', data), 839 - queryItemVisits: (data: unknown = {}) => 840 - ipcRenderer.invoke('datastore-query-item-visits', data), 841 - trackNavigation: (data: unknown) => 842 - ipcRenderer.invoke('datastore-track-navigation', data), 843 - queryItemsByFrecency: (data: unknown = {}) => 844 - ipcRenderer.invoke('datastore-query-items-by-frecency', data), 834 + ipcRenderer.invoke('tile:datastore:get-history', { token: tileToken, filter }), 835 + recordItemVisit: (itemId: string, options?: unknown) => 836 + ipcRenderer.invoke('tile:datastore:record-item-visit', { token: tileToken, itemId, options }), 837 + getItemVisits: (itemId: string, filter?: unknown) => 838 + ipcRenderer.invoke('tile:datastore:get-item-visits', { token: tileToken, itemId, filter }), 839 + queryItemVisits: (filter: unknown = {}) => 840 + ipcRenderer.invoke('tile:datastore:query-item-visits', { token: tileToken, filter }), 841 + trackNavigation: (uri: string, options?: unknown) => 842 + ipcRenderer.invoke('tile:datastore:track-navigation', { token: tileToken, uri, options }), 843 + queryItemsByFrecency: (filter: unknown = {}) => 844 + ipcRenderer.invoke('tile:datastore:query-items-by-frecency', { token: tileToken, filter }), 845 845 // Item events 846 846 addItemEvent: (data: unknown) => 847 847 ipcRenderer.invoke('datastore-add-item-event', data),