experiments in a post-browser web
10
fork

Configure Feed

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

refactor(tile-preload,ipc): flip datastore-* to strict + delete legacy (Phase 3.6g)

Flipped 19 remaining legacy ipcRenderer.invoke('datastore-*') calls in
tile-preload.cts to the corresponding tile:datastore:* strict channels
(with { token: tileToken, ...args }). Channels flipped:
get-table, set-row, get-row,
add-item, get-item, update-item, delete-item, query-items,
tag-item, untag-item, get-item-tags, get-items-by-tag,
add-item-event, get-item-event, query-item-events,
delete-item-event, delete-item-events, get-latest-item-event,
count-item-events

Item-event methods were also de-objectified: legacy API took raw `data`
objects; strict API uses named params matching tile-ipc.ts signatures.

Deleted all 46 ipcMain.handle('datastore-*') blocks from ipc.ts (the
entire legacy registerDatastoreHandlers body, keeping only the
extract-page-content handler that shared the function). Removed ~670 LOC.

Also pruned ~25 now-dead datastore imports and the tagItemAndPublish
import from ipc.ts.

Validation: `tsc --noEmit` clean; both grep checks return zero.

+26 -733
-707
backend/electron/ipc.ts
··· 10 10 import path from 'node:path'; 11 11 12 12 import { 13 - // Datastore operations 14 - addContent, 15 - queryContent, 16 - getOrCreateTag, 17 - renameTag, 18 - updateTagColor, 19 - deleteTag, 20 - getTagsByFrecency, 21 - getTable, 22 - setRow, 23 - getRow, 24 - getStats, 25 - isValidTable, 26 13 getDb, 27 14 // Item operations 28 - addItem, 29 15 getItem, 30 16 updateItem, 31 17 updateItemTitle, 32 18 updateItemFavicon, 33 19 updateItemThumbnail, 34 - deleteItem, 35 20 hardDeleteItem, 36 - queryItems, 37 - untagItem, 38 - getItemTags, 39 - getItemsByTag, 40 - // Item visit operations 41 - recordItemVisit, 42 - getItemVisits, 43 - queryItemVisits, 44 - trackNavigation, 45 - // Item event operations (series & feeds) 46 - addItemEvent, 47 - getItemEvent, 48 - queryItemEvents, 49 - deleteItemEvent, 50 - deleteItemEvents, 51 - getLatestItemEvent, 52 - countItemEvents, 53 - // History operations 54 21 trackWindowLoad, 55 22 normalizeUrl, 56 23 // Context operations ··· 160 127 syncAll, 161 128 getSyncStatus, 162 129 } from './sync.js'; 163 - 164 - import { tagItemAndPublish } from './tag-events.js'; 165 130 166 131 import { 167 132 getBackupConfig, ··· 323 288 }; 324 289 } 325 290 326 - // tagItemAndPublish / untagItemAndPublish live in ./tag-events.js so 327 - // non-IPC main-process callers (e.g. sync.ts) can use them without 328 - // introducing a circular import through ipc.ts. 329 291 330 292 /** 331 293 * Register datastore IPC handlers 332 294 */ 333 295 export function registerDatastoreHandlers(): void { 334 - // Address IPC handlers — redirected to items system for backward compatibility 335 - ipcMain.handle('datastore-add-address', async (ev, data) => { 336 - try { 337 - const opts = data.options || {}; 338 - const normalizedUri = normalizeUrl(data.uri); 339 - const metadata: Record<string, unknown> = {}; 340 - if (opts.title) metadata.title = opts.title; 341 - if (opts.description) metadata.description = opts.description; 342 - if (opts.favicon) metadata.favicon = opts.favicon; 343 - 344 - const result = addItem('url', { 345 - content: normalizedUri, 346 - mimeType: opts.mimeType || 'text/html', 347 - metadata: JSON.stringify(metadata), 348 - starred: opts.starred || 0, 349 - archived: opts.archived || 0, 350 - }); 351 - // Set title/favicon/domain columns directly (addItem only sets title from metadata.title and domain from URL) 352 - if (opts.favicon) { 353 - getDb().prepare('UPDATE items SET favicon = ? WHERE id = ?').run(opts.favicon, result.id); 354 - } 355 - 356 - // Emit item:created event for consistency 357 - const callingWinId1 = BrowserWindow.fromWebContents(ev.sender)?.id ?? null; 358 - publish('system', PubSubScopes.GLOBAL, 'item:created', { 359 - itemId: result.id, 360 - itemType: 'url', 361 - content: normalizedUri, 362 - windowId: callingWinId1 363 - }); 364 - 365 - return { success: true, data: result, id: result.id }; 366 - } catch (error) { 367 - const message = error instanceof Error ? error.message : String(error); 368 - return { success: false, error: message }; 369 - } 370 - }); 371 - 372 - ipcMain.handle('datastore-get-address', async (ev, data) => { 373 - try { 374 - const item = getItem(data.id); 375 - if (!item) return { success: true, data: undefined }; 376 - // Transform item to address-like shape 377 - return { success: true, data: itemToAddress(item) }; 378 - } catch (error) { 379 - const message = error instanceof Error ? error.message : String(error); 380 - return { success: false, error: message }; 381 - } 382 - }); 383 - 384 - ipcMain.handle('datastore-update-address', async (ev, data) => { 385 - try { 386 - const updates = data.updates || {}; 387 - const itemOpts: Record<string, unknown> = {}; 388 - if (updates.metadata !== undefined) itemOpts.metadata = updates.metadata; 389 - if (updates.starred !== undefined) itemOpts.starred = updates.starred; 390 - if (updates.archived !== undefined) itemOpts.archived = updates.archived; 391 - if (updates.mimeType !== undefined) itemOpts.mimeType = updates.mimeType; 392 - if (updates.uri !== undefined) itemOpts.content = updates.uri; 393 - 394 - updateItem(data.id, itemOpts); 395 - // Update title/favicon directly if provided 396 - if (updates.title !== undefined) { 397 - getDb().prepare('UPDATE items SET title = ?, updatedAt = ? WHERE id = ?').run(updates.title, Date.now(), data.id); 398 - } 399 - if (updates.favicon !== undefined) { 400 - getDb().prepare('UPDATE items SET favicon = ?, updatedAt = ? WHERE id = ?').run(updates.favicon, Date.now(), data.id); 401 - } 402 - 403 - const updated = getItem(data.id); 404 - return { success: true, data: updated ? itemToAddress(updated) : undefined }; 405 - } catch (error) { 406 - const message = error instanceof Error ? error.message : String(error); 407 - return { success: false, error: message }; 408 - } 409 - }); 410 - 411 - ipcMain.handle('datastore-query-addresses', async (ev, data) => { 412 - try { 413 - const filter = data.filter || {}; 414 - const itemFilter: Record<string, unknown> = { type: 'url' }; 415 - if (filter.domain) itemFilter.domain = filter.domain; 416 - if (filter.starred !== undefined) itemFilter.starred = filter.starred; 417 - if (filter.sortBy) itemFilter.sortBy = filter.sortBy; 418 - if (filter.limit) itemFilter.limit = filter.limit; 419 - if (filter.search) itemFilter.search = filter.search; 420 - 421 - const items = queryItems(itemFilter); 422 - return { success: true, data: items.map(itemToAddress) }; 423 - } catch (error) { 424 - const message = error instanceof Error ? error.message : String(error); 425 - return { success: false, error: message }; 426 - } 427 - }); 428 - 429 - ipcMain.handle('datastore-add-visit', async (ev, data) => { 430 - try { 431 - const opts = data.options || {}; 432 - const result = recordItemVisit(data.addressId, { 433 - source: opts.source || 'direct', 434 - sourceId: opts.sourceId || '', 435 - windowType: opts.windowType || 'main', 436 - interacted: opts.interacted || 0, 437 - }); 438 - return { success: true, data: result, id: result.id }; 439 - } catch (error) { 440 - const message = error instanceof Error ? error.message : String(error); 441 - return { success: false, error: message }; 442 - } 443 - }); 444 - 445 - ipcMain.handle('datastore-query-visits', async (ev, data) => { 446 - try { 447 - const filter = data.filter || {}; 448 - const itemFilter: Record<string, unknown> = {}; 449 - if (filter.addressId) itemFilter.itemId = filter.addressId; 450 - if (filter.source) itemFilter.source = filter.source; 451 - if (filter.since) itemFilter.since = filter.since; 452 - if (filter.until) itemFilter.until = filter.until; 453 - if (filter.limit) itemFilter.limit = filter.limit; 454 - 455 - const visits = queryItemVisits(itemFilter); 456 - // Map itemId to addressId for backward compat 457 - const mapped = visits.map(v => ({ ...v, addressId: v.itemId })); 458 - return { success: true, data: mapped }; 459 - } catch (error) { 460 - const message = error instanceof Error ? error.message : String(error); 461 - return { success: false, error: message }; 462 - } 463 - }); 464 - 465 - ipcMain.handle('datastore-add-content', async (ev, data) => { 466 - try { 467 - const result = addContent(data.options); 468 - return { success: true, data: result }; 469 - } catch (error) { 470 - const message = error instanceof Error ? error.message : String(error); 471 - return { success: false, error: message }; 472 - } 473 - }); 474 - 475 - ipcMain.handle('datastore-query-content', async (ev, data) => { 476 - try { 477 - const result = queryContent(data.filter); 478 - return { success: true, data: result }; 479 - } catch (error) { 480 - const message = error instanceof Error ? error.message : String(error); 481 - return { success: false, error: message }; 482 - } 483 - }); 484 - 485 - ipcMain.handle('datastore-get-table', async (ev, data) => { 486 - try { 487 - const tableName = data.tableName || data.table; 488 - if (!isValidTable(tableName)) { 489 - return { success: false, error: `Invalid table: ${tableName}` }; 490 - } 491 - const result = getTable(tableName); 492 - return { success: true, data: result }; 493 - } catch (error) { 494 - const message = error instanceof Error ? error.message : String(error); 495 - return { success: false, error: message }; 496 - } 497 - }); 498 - 499 - ipcMain.handle('datastore-set-row', async (ev, data) => { 500 - try { 501 - const tableName = data.tableName || data.table; 502 - const rowId = data.rowId || data.id; 503 - const rowData = data.rowData || data.row; 504 - if (!isValidTable(tableName)) { 505 - return { success: false, error: `Invalid table: ${tableName}` }; 506 - } 507 - 508 - const result = setRow(tableName, rowId, rowData); 509 - 510 - return { success: true, data: result }; 511 - } catch (error) { 512 - const message = error instanceof Error ? error.message : String(error); 513 - return { success: false, error: message }; 514 - } 515 - }); 516 - 517 - ipcMain.handle('datastore-get-row', async (ev, data) => { 518 - try { 519 - const tableName = data.tableName || data.table; 520 - const rowId = data.rowId || data.id; 521 - if (!isValidTable(tableName)) { 522 - return { success: false, error: `Invalid table: ${tableName}` }; 523 - } 524 - const result = getRow(tableName, rowId); 525 - return { success: true, data: result }; 526 - } catch (error) { 527 - const message = error instanceof Error ? error.message : String(error); 528 - return { success: false, error: message }; 529 - } 530 - }); 531 - 532 - ipcMain.handle('datastore-get-stats', async () => { 533 - try { 534 - const result = getStats(); 535 - return { success: true, data: result }; 536 - } catch (error) { 537 - const message = error instanceof Error ? error.message : String(error); 538 - return { success: false, error: message }; 539 - } 540 - }); 541 - 542 - // Tag operations 543 - ipcMain.handle('datastore-get-or-create-tag', async (ev, data) => { 544 - try { 545 - // NOTE: getOrCreateTag() itself publishes 'tag:created' on new inserts 546 - // (see datastore.ts). Keeping the publish there ensures tile-ipc / 547 - // direct-import callers also emit the lifecycle event. 548 - const result = getOrCreateTag(data.name); 549 - return { success: true, data: result }; 550 - } catch (error) { 551 - const message = error instanceof Error ? error.message : String(error); 552 - return { success: false, error: message }; 553 - } 554 - }); 555 - 556 - // Tag-address handlers — redirected to item tagging 557 - ipcMain.handle('datastore-tag-address', async (ev, data) => { 558 - try { 559 - // Route through the publishing helper so the canonical tag:item-added 560 - // event (with itemType) is emitted alongside the legacy 561 - // tag:address-added event kept here for backward compatibility. 562 - const result = tagItemAndPublish(data.addressId, data.tagId); 563 - 564 - if (!result.alreadyExists) { 565 - const tag = getDb().prepare('SELECT name FROM tags WHERE id = ?').get(data.tagId) as { name: string } | undefined; 566 - publish('system', PubSubScopes.GLOBAL, 'tag:address-added', { 567 - tagId: data.tagId, 568 - tagName: tag?.name, 569 - addressId: data.addressId 570 - }); 571 - if (DEBUG) console.log('[ipc] tag:address-added (redirected to tagItem)', data.tagId, data.addressId); 572 - } 573 - 574 - return { success: true, data: result }; 575 - } catch (error) { 576 - const message = error instanceof Error ? error.message : String(error); 577 - return { success: false, error: message }; 578 - } 579 - }); 580 - 581 - ipcMain.handle('datastore-untag-address', async (ev, data) => { 582 - try { 583 - const tag = getDb().prepare('SELECT name FROM tags WHERE id = ?').get(data.tagId) as { name: string } | undefined; 584 - 585 - const result = untagItem(data.addressId, data.tagId); 586 - 587 - if (result) { 588 - publish('system', PubSubScopes.GLOBAL, 'tag:address-removed', { 589 - tagId: data.tagId, 590 - tagName: tag?.name, 591 - addressId: data.addressId 592 - }); 593 - publish('system', PubSubScopes.GLOBAL, 'tag:item-removed', { 594 - tagId: data.tagId, 595 - tagName: tag?.name, 596 - itemId: data.addressId 597 - }); 598 - if (DEBUG) console.log('[ipc] tag:address-removed (redirected to untagItem)', data.tagId, data.addressId); 599 - } 600 - 601 - return { success: true, data: result }; 602 - } catch (error) { 603 - const message = error instanceof Error ? error.message : String(error); 604 - return { success: false, error: message }; 605 - } 606 - }); 607 - 608 - ipcMain.handle('datastore-get-tags-by-frecency', async (ev, data = {}) => { 609 - try { 610 - const result = getTagsByFrecency(data.limit); 611 - return { success: true, data: result }; 612 - } catch (error) { 613 - const message = error instanceof Error ? error.message : String(error); 614 - return { success: false, error: message }; 615 - } 616 - }); 617 - 618 - ipcMain.handle('datastore-rename-tag', async (ev, data) => { 619 - try { 620 - // renameTag() publishes 'tag:renamed' internally (datastore.ts). 621 - const result = renameTag(data.tagId, data.newName); 622 - return { success: true, data: result }; 623 - } catch (error) { 624 - const message = error instanceof Error ? error.message : String(error); 625 - return { success: false, error: message }; 626 - } 627 - }); 628 - 629 - ipcMain.handle('datastore-update-tag-color', async (ev, data) => { 630 - try { 631 - // updateTagColor() publishes 'tag:color-changed' internally (datastore.ts). 632 - const result = updateTagColor(data.tagId, data.color); 633 - return { success: true, data: result }; 634 - } catch (error) { 635 - const message = error instanceof Error ? error.message : String(error); 636 - return { success: false, error: message }; 637 - } 638 - }); 639 - 640 - ipcMain.handle('datastore-delete-tag', async (ev, data) => { 641 - try { 642 - // deleteTag() publishes 'tag:deleted' internally (datastore.ts). 643 - const result = deleteTag(data.tagId); 644 - return { success: true, data: result }; 645 - } catch (error) { 646 - const message = error instanceof Error ? error.message : String(error); 647 - return { success: false, error: message }; 648 - } 649 - }); 650 - 651 - // Address-tag query handlers — redirected to item tagging 652 - ipcMain.handle('datastore-get-address-tags', async (ev, data) => { 653 - try { 654 - const result = getItemTags(data.addressId); 655 - return { success: true, data: result }; 656 - } catch (error) { 657 - const message = error instanceof Error ? error.message : String(error); 658 - return { success: false, error: message }; 659 - } 660 - }); 661 - 662 - ipcMain.handle('datastore-get-addresses-by-tag', async (ev, data) => { 663 - try { 664 - const items = getItemsByTag(data.tagId); 665 - return { success: true, data: items.map(itemToAddress) }; 666 - } catch (error) { 667 - const message = error instanceof Error ? error.message : String(error); 668 - return { success: false, error: message }; 669 - } 670 - }); 671 - 672 - ipcMain.handle('datastore-get-untagged-addresses', async (ev, data) => { 673 - try { 674 - // Query URL items that have no tags 675 - const items = getDb().prepare(` 676 - SELECT i.* FROM items i 677 - LEFT JOIN item_tags it ON i.id = it.itemId 678 - WHERE i.type = 'url' AND i.deletedAt = 0 AND it.id IS NULL 679 - ORDER BY i.visitCount DESC 680 - `).all() as import('../types/index.js').Item[]; 681 - return { success: true, data: items.map(itemToAddress) }; 682 - } catch (error) { 683 - const message = error instanceof Error ? error.message : String(error); 684 - return { success: false, error: message }; 685 - } 686 - }); 687 - 688 - // Item operations (mobile-style lightweight content) 689 - ipcMain.handle('datastore-add-item', async (ev, data) => { 690 - try { 691 - const result = addItem(data.type, data.options); 692 - 693 - // Emit item:created event 694 - const callingWinId2 = BrowserWindow.fromWebContents(ev.sender)?.id ?? null; 695 - publish('system', PubSubScopes.GLOBAL, 'item:created', { 696 - itemId: result.id, 697 - itemType: data.type, 698 - content: data.options?.content, 699 - windowId: callingWinId2 700 - }); 701 - if (DEBUG) console.log('[ipc] item:created', result.id, data.type); 702 - 703 - return { success: true, data: result }; 704 - } catch (error) { 705 - const message = error instanceof Error ? error.message : String(error); 706 - return { success: false, error: message }; 707 - } 708 - }); 709 - 710 - ipcMain.handle('datastore-get-item', async (ev, data) => { 711 - try { 712 - const result = getItem(data.id); 713 - return { success: true, data: result }; 714 - } catch (error) { 715 - const message = error instanceof Error ? error.message : String(error); 716 - return { success: false, error: message }; 717 - } 718 - }); 719 - 720 - ipcMain.handle('datastore-update-item', async (ev, data) => { 721 - try { 722 - const result = updateItem(data.id, data.options); 723 - 724 - // Emit item:updated event if update was successful 725 - if (result) { 726 - const db = getDb(); 727 - const item = db.prepare('SELECT type FROM items WHERE id = ?').get(data.id) as { type: string } | undefined; 728 - publish('system', PubSubScopes.GLOBAL, 'item:updated', { 729 - itemId: data.id, 730 - itemType: item?.type 731 - }); 732 - if (DEBUG) console.log('[ipc] item:updated', data.id, item?.type); 733 - } 734 - 735 - return { success: true, data: result }; 736 - } catch (error) { 737 - const message = error instanceof Error ? error.message : String(error); 738 - return { success: false, error: message }; 739 - } 740 - }); 741 - 742 - ipcMain.handle('datastore-delete-item', async (ev, data) => { 743 - try { 744 - // Fetch item type before deletion (need it for event payload) 745 - const db = getDb(); 746 - const item = db.prepare('SELECT type FROM items WHERE id = ?').get(data.id) as { type: string } | undefined; 747 - 748 - const result = deleteItem(data.id); 749 - 750 - // Emit item:deleted event if deletion was successful 751 - if (result) { 752 - publish('system', PubSubScopes.GLOBAL, 'item:deleted', { 753 - itemId: data.id, 754 - itemType: item?.type 755 - }); 756 - if (DEBUG) console.log('[ipc] item:deleted', data.id, item?.type); 757 - } 758 - 759 - return { success: true, data: result }; 760 - } catch (error) { 761 - const message = error instanceof Error ? error.message : String(error); 762 - return { success: false, error: message }; 763 - } 764 - }); 765 - 766 - ipcMain.handle('datastore-hard-delete-item', async (ev, data) => { 767 - try { 768 - const result = hardDeleteItem(data.id); 769 - return { success: true, data: result }; 770 - } catch (error) { 771 - const message = error instanceof Error ? error.message : String(error); 772 - return { success: false, error: message }; 773 - } 774 - }); 775 - 776 - ipcMain.handle('datastore-update-item-title', async (ev, data) => { 777 - try { 778 - const result = updateItemTitle(data.url, data.title); 779 - return { success: true, data: result }; 780 - } catch (error) { 781 - const message = error instanceof Error ? error.message : String(error); 782 - return { success: false, error: message }; 783 - } 784 - }); 785 - 786 - ipcMain.handle('datastore-update-item-favicon', async (ev, data) => { 787 - try { 788 - const result = updateItemFavicon(data.url, data.faviconUrl); 789 - return { success: true, data: result }; 790 - } catch (error) { 791 - const message = error instanceof Error ? error.message : String(error); 792 - return { success: false, error: message }; 793 - } 794 - }); 795 - 796 - ipcMain.handle('datastore-query-items', async (ev, data = {}) => { 797 - try { 798 - const result = queryItems(data.filter); 799 - return { success: true, data: result }; 800 - } catch (error) { 801 - const message = error instanceof Error ? error.message : String(error); 802 - return { success: false, error: message }; 803 - } 804 - }); 805 - 806 - ipcMain.handle('datastore-tag-item', async (ev, data) => { 807 - try { 808 - // Use the helper so every caller goes through one publish path — 809 - // avoids drift between handlers when the event payload evolves. 810 - const result = tagItemAndPublish(data.itemId, data.tagId); 811 - if (DEBUG && !result.alreadyExists) { 812 - console.log('[ipc] tag:item-added', data.tagId, data.itemId); 813 - } 814 - return { success: true, data: result }; 815 - } catch (error) { 816 - const message = error instanceof Error ? error.message : String(error); 817 - return { success: false, error: message }; 818 - } 819 - }); 820 - 821 - ipcMain.handle('datastore-untag-item', async (ev, data) => { 822 - try { 823 - // Fetch tag name before untagging (need it for event payload) 824 - const tag = getDb().prepare('SELECT name FROM tags WHERE id = ?').get(data.tagId) as { name: string } | undefined; 825 - 826 - const result = untagItem(data.itemId, data.tagId); 827 - 828 - // Emit event if the untag actually removed something 829 - if (result) { 830 - publish('system', PubSubScopes.GLOBAL, 'tag:item-removed', { 831 - tagId: data.tagId, 832 - tagName: tag?.name, 833 - itemId: data.itemId 834 - }); 835 - if (DEBUG) console.log('[ipc] tag:item-removed', data.tagId, data.itemId); 836 - } 837 - 838 - return { success: true, data: result }; 839 - } catch (error) { 840 - const message = error instanceof Error ? error.message : String(error); 841 - return { success: false, error: message }; 842 - } 843 - }); 844 - 845 - ipcMain.handle('datastore-get-item-tags', async (ev, data) => { 846 - try { 847 - const result = getItemTags(data.itemId); 848 - return { success: true, data: result }; 849 - } catch (error) { 850 - const message = error instanceof Error ? error.message : String(error); 851 - return { success: false, error: message }; 852 - } 853 - }); 854 - 855 - ipcMain.handle('datastore-get-items-by-tag', async (ev, data) => { 856 - try { 857 - const result = getItemsByTag(data.tagId); 858 - return { success: true, data: result }; 859 - } catch (error) { 860 - const message = error instanceof Error ? error.message : String(error); 861 - return { success: false, error: message }; 862 - } 863 - }); 864 - 865 - // History operations — redirected to item_visits system 866 - ipcMain.handle('datastore-get-history', async (ev, data = {}) => { 867 - try { 868 - const filter = data.filter || {}; 869 - const visits = queryItemVisits(filter); 870 - // Enrich with item data to match HistoryEntry shape 871 - const enriched = visits.map(v => { 872 - const item = getItem(v.itemId); 873 - return { 874 - ...v, 875 - addressId: v.itemId, 876 - uri: item?.content || '', 877 - title: item?.title || '', 878 - domain: item?.domain || '', 879 - protocol: '', 880 - favicon: item?.favicon || '', 881 - }; 882 - }); 883 - return { success: true, data: enriched }; 884 - } catch (error) { 885 - const message = error instanceof Error ? error.message : String(error); 886 - return { success: false, error: message }; 887 - } 888 - }); 889 - 890 - // Item visit operations (URL history unification) 891 - ipcMain.handle('datastore-record-item-visit', async (ev, data) => { 892 - try { 893 - const result = recordItemVisit(data.itemId, data.options); 894 - return { success: true, data: result }; 895 - } catch (error) { 896 - const message = error instanceof Error ? error.message : String(error); 897 - return { success: false, error: message }; 898 - } 899 - }); 900 - 901 - ipcMain.handle('datastore-get-item-visits', async (ev, data) => { 902 - try { 903 - const result = getItemVisits(data.itemId, data.filter); 904 - return { success: true, data: result }; 905 - } catch (error) { 906 - const message = error instanceof Error ? error.message : String(error); 907 - return { success: false, error: message }; 908 - } 909 - }); 910 - 911 - ipcMain.handle('datastore-query-item-visits', async (ev, data = {}) => { 912 - try { 913 - const result = queryItemVisits(data.filter); 914 - return { success: true, data: result }; 915 - } catch (error) { 916 - const message = error instanceof Error ? error.message : String(error); 917 - return { success: false, error: message }; 918 - } 919 - }); 920 - 921 - ipcMain.handle('datastore-track-navigation', async (ev, data) => { 922 - try { 923 - const result = trackNavigation(data.uri, data.options); 924 - 925 - return { success: true, data: result }; 926 - } catch (error) { 927 - const message = error instanceof Error ? error.message : String(error); 928 - return { success: false, error: message }; 929 - } 930 - }); 931 - 932 - // Item event operations (series & feeds) 933 - ipcMain.handle('datastore-add-item-event', async (ev, data) => { 934 - try { 935 - const result = addItemEvent(data.itemId, data.options); 936 - return { success: true, data: result }; 937 - } catch (error) { 938 - const message = error instanceof Error ? error.message : String(error); 939 - return { success: false, error: message }; 940 - } 941 - }); 942 - 943 - ipcMain.handle('datastore-get-item-event', async (ev, data) => { 944 - try { 945 - const result = getItemEvent(data.eventId); 946 - return { success: true, data: result }; 947 - } catch (error) { 948 - const message = error instanceof Error ? error.message : String(error); 949 - return { success: false, error: message }; 950 - } 951 - }); 952 - 953 - ipcMain.handle('datastore-query-item-events', async (ev, data = {}) => { 954 - try { 955 - const result = queryItemEvents(data.filter); 956 - return { success: true, data: result }; 957 - } catch (error) { 958 - const message = error instanceof Error ? error.message : String(error); 959 - return { success: false, error: message }; 960 - } 961 - }); 962 - 963 - ipcMain.handle('datastore-delete-item-event', async (ev, data) => { 964 - try { 965 - const result = deleteItemEvent(data.eventId); 966 - return { success: true, data: result }; 967 - } catch (error) { 968 - const message = error instanceof Error ? error.message : String(error); 969 - return { success: false, error: message }; 970 - } 971 - }); 972 - 973 - ipcMain.handle('datastore-delete-item-events', async (ev, data) => { 974 - try { 975 - const result = deleteItemEvents(data.itemId); 976 - return { success: true, data: result }; 977 - } catch (error) { 978 - const message = error instanceof Error ? error.message : String(error); 979 - return { success: false, error: message }; 980 - } 981 - }); 982 - 983 - ipcMain.handle('datastore-get-latest-item-event', async (ev, data) => { 984 - try { 985 - const result = getLatestItemEvent(data.itemId); 986 - return { success: true, data: result }; 987 - } catch (error) { 988 - const message = error instanceof Error ? error.message : String(error); 989 - return { success: false, error: message }; 990 - } 991 - }); 992 - 993 - ipcMain.handle('datastore-count-item-events', async (ev, data) => { 994 - try { 995 - const result = countItemEvents(data.itemId, data.filter); 996 - return { success: true, data: result }; 997 - } catch (error) { 998 - const message = error instanceof Error ? error.message : String(error); 999 - return { success: false, error: message }; 1000 - } 1001 - }); 1002 - 1003 296 // Extract page content from a live webContents by URL 1004 297 ipcMain.handle('extract-page-content', async (ev, data) => { 1005 298 try {
+26 -26
backend/electron/tile-preload.cts
··· 922 922 queryContent: (filter?: unknown) => 923 923 ipcRenderer.invoke('tile:datastore:query-content', { token: tileToken, filter }), 924 924 getTable: (tableName: string) => 925 - ipcRenderer.invoke('datastore-get-table', { tableName }), 925 + ipcRenderer.invoke('tile:datastore:get-table', { token: tileToken, tableName }), 926 926 setRow: (tableName: string, rowId: string, rowData: unknown) => 927 - ipcRenderer.invoke('datastore-set-row', { tableName, rowId, rowData }), 927 + ipcRenderer.invoke('tile:datastore:set-row', { token: tileToken, tableName, rowId, rowData }), 928 928 getRow: (tableName: string, rowId: string) => 929 - ipcRenderer.invoke('datastore-get-row', { tableName, rowId }), 929 + ipcRenderer.invoke('tile:datastore:get-row', { token: tileToken, tableName, rowId }), 930 930 getStats: () => ipcRenderer.invoke('tile:datastore:get-stats', { token: tileToken }), 931 931 // Tag helpers 932 932 getOrCreateTag: (name: string) => ··· 951 951 ipcRenderer.invoke('tile:datastore:get-untagged-addresses', { token: tileToken }), 952 952 // Item helpers 953 953 addItem: (type: string, options: unknown = {}) => 954 - ipcRenderer.invoke('datastore-add-item', { type, options }), 954 + ipcRenderer.invoke('tile:datastore:add-item', { token: tileToken, type, options }), 955 955 getItem: (id: string) => 956 - ipcRenderer.invoke('datastore-get-item', { id }), 956 + ipcRenderer.invoke('tile:datastore:get-item', { token: tileToken, id }), 957 957 updateItem: (id: string, options: unknown) => 958 - ipcRenderer.invoke('datastore-update-item', { id, options }), 958 + ipcRenderer.invoke('tile:datastore:update-item', { token: tileToken, id, options }), 959 959 deleteItem: (id: string) => 960 - ipcRenderer.invoke('datastore-delete-item', { id }), 960 + ipcRenderer.invoke('tile:datastore:delete-item', { token: tileToken, id }), 961 961 hardDeleteItem: (id: string) => 962 962 ipcRenderer.invoke('tile:datastore:hard-delete-item', { token: tileToken, id }), 963 963 updateItemTitle: (url: string, title: string) => ··· 965 965 updateItemFavicon: (url: string, faviconUrl: string) => 966 966 ipcRenderer.invoke('tile:datastore:update-item-favicon', { token: tileToken, url, faviconUrl }), 967 967 queryItems: (filter: unknown = {}) => 968 - ipcRenderer.invoke('datastore-query-items', { filter }), 968 + ipcRenderer.invoke('tile:datastore:query-items', { token: tileToken, filter }), 969 969 tagItem: (itemId: string, tagId: string) => 970 - ipcRenderer.invoke('datastore-tag-item', { itemId, tagId }), 970 + ipcRenderer.invoke('tile:datastore:tag-item', { token: tileToken, itemId, tagId }), 971 971 untagItem: (itemId: string, tagId: string) => 972 - ipcRenderer.invoke('datastore-untag-item', { itemId, tagId }), 972 + ipcRenderer.invoke('tile:datastore:untag-item', { token: tileToken, itemId, tagId }), 973 973 getItemTags: (itemId: string) => 974 - ipcRenderer.invoke('datastore-get-item-tags', { itemId }), 974 + ipcRenderer.invoke('tile:datastore:get-item-tags', { token: tileToken, itemId }), 975 975 getItemsByTag: (tagId: string) => 976 - ipcRenderer.invoke('datastore-get-items-by-tag', { tagId }), 976 + ipcRenderer.invoke('tile:datastore:get-items-by-tag', { token: tileToken, tagId }), 977 977 getHistory: (filter: unknown = {}) => 978 978 ipcRenderer.invoke('tile:datastore:get-history', { token: tileToken, filter }), 979 979 recordItemVisit: (itemId: string, options?: unknown) => ··· 987 987 queryItemsByFrecency: (filter: unknown = {}) => 988 988 ipcRenderer.invoke('tile:datastore:query-items-by-frecency', { token: tileToken, filter }), 989 989 // Item events 990 - addItemEvent: (data: unknown) => 991 - ipcRenderer.invoke('datastore-add-item-event', data), 992 - getItemEvent: (data: unknown) => 993 - ipcRenderer.invoke('datastore-get-item-event', data), 994 - queryItemEvents: (data: unknown = {}) => 995 - ipcRenderer.invoke('datastore-query-item-events', data), 996 - deleteItemEvent: (data: unknown) => 997 - ipcRenderer.invoke('datastore-delete-item-event', data), 998 - deleteItemEvents: (data: unknown) => 999 - ipcRenderer.invoke('datastore-delete-item-events', data), 1000 - getLatestItemEvent: (data: unknown) => 1001 - ipcRenderer.invoke('datastore-get-latest-item-event', data), 1002 - countItemEvents: (data: unknown) => 1003 - ipcRenderer.invoke('datastore-count-item-events', data), 990 + addItemEvent: (itemId: string, options?: unknown) => 991 + ipcRenderer.invoke('tile:datastore:add-item-event', { token: tileToken, itemId, options }), 992 + getItemEvent: (eventId: string) => 993 + ipcRenderer.invoke('tile:datastore:get-item-event', { token: tileToken, eventId }), 994 + queryItemEvents: (filter: unknown = {}) => 995 + ipcRenderer.invoke('tile:datastore:query-item-events', { token: tileToken, filter }), 996 + deleteItemEvent: (eventId: string) => 997 + ipcRenderer.invoke('tile:datastore:delete-item-event', { token: tileToken, eventId }), 998 + deleteItemEvents: (itemId: string) => 999 + ipcRenderer.invoke('tile:datastore:delete-item-events', { token: tileToken, itemId }), 1000 + getLatestItemEvent: (itemId: string) => 1001 + ipcRenderer.invoke('tile:datastore:get-latest-item-event', { token: tileToken, itemId }), 1002 + countItemEvents: (itemId: string, filter?: unknown) => 1003 + ipcRenderer.invoke('tile:datastore:count-item-events', { token: tileToken, itemId, filter }), 1004 1004 }; 1005 1005 1006 1006 // ── Network (if granted) ──