@oxy.so/services 13.1.0 → 13.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/lib/commonjs/ui/context/OxyContext.js +17 -15
  2. package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
  3. package/lib/commonjs/ui/hooks/accountQueryPersistence.js +50 -15
  4. package/lib/commonjs/ui/hooks/accountQueryPersistence.js.map +1 -1
  5. package/lib/commonjs/ui/hooks/persistedQueryCache.js +10 -4
  6. package/lib/commonjs/ui/hooks/persistedQueryCache.js.map +1 -1
  7. package/lib/commonjs/ui/hooks/queryClient.js +9 -15
  8. package/lib/commonjs/ui/hooks/queryClient.js.map +1 -1
  9. package/lib/module/ui/context/OxyContext.js +17 -14
  10. package/lib/module/ui/context/OxyContext.js.map +1 -1
  11. package/lib/module/ui/hooks/accountQueryPersistence.js +50 -15
  12. package/lib/module/ui/hooks/accountQueryPersistence.js.map +1 -1
  13. package/lib/module/ui/hooks/persistedQueryCache.js +10 -4
  14. package/lib/module/ui/hooks/persistedQueryCache.js.map +1 -1
  15. package/lib/module/ui/hooks/queryClient.js +9 -15
  16. package/lib/module/ui/hooks/queryClient.js.map +1 -1
  17. package/lib/typescript/commonjs/index.d.ts +1 -1
  18. package/lib/typescript/commonjs/index.d.ts.map +1 -1
  19. package/lib/typescript/commonjs/ui/context/OxyContext.d.ts.map +1 -1
  20. package/lib/typescript/commonjs/ui/hooks/accountQueryPersistence.d.ts +22 -4
  21. package/lib/typescript/commonjs/ui/hooks/accountQueryPersistence.d.ts.map +1 -1
  22. package/lib/typescript/commonjs/ui/hooks/persistedQueryCache.d.ts +5 -3
  23. package/lib/typescript/commonjs/ui/hooks/persistedQueryCache.d.ts.map +1 -1
  24. package/lib/typescript/commonjs/ui/hooks/queryClient.d.ts +5 -4
  25. package/lib/typescript/commonjs/ui/hooks/queryClient.d.ts.map +1 -1
  26. package/lib/typescript/commonjs/ui/icons/Ionicons.d.ts +1 -1
  27. package/lib/typescript/commonjs/ui/icons/MaterialCommunityIcons.d.ts +1 -1
  28. package/lib/typescript/commonjs/ui/index.d.ts +1 -1
  29. package/lib/typescript/commonjs/ui/index.d.ts.map +1 -1
  30. package/lib/typescript/commonjs/ui/types/navigation.d.ts +2 -0
  31. package/lib/typescript/commonjs/ui/types/navigation.d.ts.map +1 -1
  32. package/lib/typescript/module/index.d.ts +1 -1
  33. package/lib/typescript/module/index.d.ts.map +1 -1
  34. package/lib/typescript/module/ui/context/OxyContext.d.ts.map +1 -1
  35. package/lib/typescript/module/ui/hooks/accountQueryPersistence.d.ts +22 -4
  36. package/lib/typescript/module/ui/hooks/accountQueryPersistence.d.ts.map +1 -1
  37. package/lib/typescript/module/ui/hooks/persistedQueryCache.d.ts +5 -3
  38. package/lib/typescript/module/ui/hooks/persistedQueryCache.d.ts.map +1 -1
  39. package/lib/typescript/module/ui/hooks/queryClient.d.ts +5 -4
  40. package/lib/typescript/module/ui/hooks/queryClient.d.ts.map +1 -1
  41. package/lib/typescript/module/ui/icons/Ionicons.d.ts +1 -1
  42. package/lib/typescript/module/ui/icons/MaterialCommunityIcons.d.ts +1 -1
  43. package/lib/typescript/module/ui/index.d.ts +1 -1
  44. package/lib/typescript/module/ui/index.d.ts.map +1 -1
  45. package/lib/typescript/module/ui/types/navigation.d.ts +2 -0
  46. package/lib/typescript/module/ui/types/navigation.d.ts.map +1 -1
  47. package/package.json +1 -1
  48. package/src/index.ts +1 -1
  49. package/src/ui/context/OxyContext.tsx +27 -19
  50. package/src/ui/hooks/accountQueryPersistence.ts +61 -16
  51. package/src/ui/hooks/persistedQueryCache.ts +13 -5
  52. package/src/ui/hooks/queryClient.ts +12 -18
  53. package/src/ui/index.ts +1 -1
  54. package/src/ui/types/navigation.ts +2 -0
@@ -48,10 +48,11 @@ export interface AttachPersistenceResult {
48
48
  * Restore, then keep writing, the account-agnostic cache.
49
49
  *
50
50
  * Queries written by another build are dropped; queued mutations are kept
51
- * (`persistedQueryCache.ts`). Whatever the app declared account-scoped
52
- * (`accountQueries`) is left to `createAccountQueryPersistence`, even under
53
- * one of the SDK's prefixes, so private rows never land in the shared blob and
54
- * a paused mutation cannot replay twice or under another account.
51
+ * (`persistedQueryCache.ts`). Whatever belongs to the account (`accountQueries`,
52
+ * or a query marked `meta: { persist: 'account' }`) is left to
53
+ * `createAccountQueryPersistence`, even under one of the SDK's prefixes, so
54
+ * private rows never land in the shared blob and a paused mutation cannot
55
+ * replay twice or under another account.
55
56
  *
56
57
  * Safe to no-op if `storage` is null/undefined (e.g. server-side render
57
58
  * with no host storage).
@@ -1 +1 @@
1
- {"version":3,"file":"queryClient.d.ts","sourceRoot":"","sources":["../../../../../src/ui/hooks/queryClient.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,EAAE,WAAW,EAA4C,MAAM,uBAAuB,CAAC;AAC9F,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sCAAsC,CAAC;AAE5E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,4BAAyB,CAAC;AAChE,OAAO,EAAyB,KAAK,oBAAoB,EAAE,MAAM,8BAA2B,CAAC;AAoB7F,qEAAqE;AACrE,wBAAgB,gBAAgB,CAAC,YAAY,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CAK9E;AAeD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,iBAAiB,QAAO,WA6CpC,CAAC;AAEF,MAAM,WAAW,uBAAuB;IACtC,wEAAwE;IACxE,QAAQ,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IACxB,8DAA8D;IAC9D,WAAW,EAAE,MAAM,IAAI,CAAC;CACzB;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,sBAAsB,GACjC,aAAa,WAAW,EACxB,SAAS,gBAAgB,GAAG,IAAI,GAAG,SAAS,EAC5C,iBAAiB,oBAAoB,KACpC,uBA6CF,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,eAAe,GAAU,SAAS,gBAAgB,KAAG,OAAO,CAAC,IAAI,CAQ7E,CAAC;AAEF;;GAEG;AACH,YAAY,EAAE,eAAe,EAAE,CAAC"}
1
+ {"version":3,"file":"queryClient.d.ts","sourceRoot":"","sources":["../../../../../src/ui/hooks/queryClient.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,EAAE,WAAW,EAA6B,MAAM,uBAAuB,CAAC;AAC/E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sCAAsC,CAAC;AAE5E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,4BAAyB,CAAC;AAChE,OAAO,EAAyB,KAAK,oBAAoB,EAAE,MAAM,8BAA2B,CAAC;AAqB7F,qEAAqE;AACrE,wBAAgB,gBAAgB,CAAC,YAAY,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CAK9E;AAQD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,iBAAiB,QAAO,WA6CpC,CAAC;AAEF,MAAM,WAAW,uBAAuB;IACtC,wEAAwE;IACxE,QAAQ,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IACxB,8DAA8D;IAC9D,WAAW,EAAE,MAAM,IAAI,CAAC;CACzB;AAED;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,sBAAsB,GACjC,aAAa,WAAW,EACxB,SAAS,gBAAgB,GAAG,IAAI,GAAG,SAAS,EAC5C,iBAAiB,oBAAoB,KACpC,uBA4CF,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,eAAe,GAAU,SAAS,gBAAgB,KAAG,OAAO,CAAC,IAAI,CAQ7E,CAAC;AAEF;;GAEG;AACH,YAAY,EAAE,eAAe,EAAE,CAAC"}
@@ -1,4 +1,4 @@
1
1
  /** Glyphs are decorative: hidden from assistive technology (see `decorativeIconSet`). */
2
- declare const Ionicons: import("@expo/vector-icons/build/createIconSet").Icon<"push" | "at" | "code" | "business" | "navigate" | "key" | "open" | "add" | "search" | "list" | "settings" | "infinite" | "trash" | "wallet" | "link" | "text" | "scale" | "image" | "alert" | "radio" | "grid" | "warning" | "people" | "ellipse" | "add-circle-outline" | "alert-circle" | "alert-circle-outline" | "apps" | "archive" | "arrow-back" | "arrow-down" | "arrow-forward" | "arrow-undo" | "arrow-up" | "briefcase-outline" | "bug" | "bulb" | "business-outline" | "calendar" | "calendar-outline" | "camera" | "camera-outline" | "card" | "card-outline" | "cart-outline" | "cash-outline" | "chatbubble" | "checkmark" | "checkmark-circle" | "chevron-back" | "chevron-down" | "chevron-forward" | "chevron-up" | "close" | "close-circle" | "cloud-offline-outline" | "cloud-outline" | "cloud-upload" | "cloud-upload-outline" | "cog" | "cog-outline" | "construct-outline" | "copy-outline" | "cube-outline" | "desktop" | "document" | "document-outline" | "document-text" | "documents" | "download" | "download-outline" | "earth" | "ellipse-outline" | "ellipsis-horizontal" | "eye" | "eye-off-outline" | "filter-outline" | "flame" | "flash" | "folder" | "folder-open-outline" | "folder-outline" | "footsteps" | "gift" | "gift-outline" | "hand-left" | "hardware-chip-outline" | "heart" | "heart-outline" | "help-circle" | "help-circle-outline" | "hourglass-outline" | "image-outline" | "images" | "images-outline" | "information" | "information-circle" | "information-outline" | "leaf" | "library" | "link-outline" | "location" | "location-outline" | "lock-closed" | "log-out-outline" | "mail" | "musical-notes" | "pencil-outline" | "people-outline" | "play" | "pricetag-outline" | "pulse" | "qr-code-outline" | "receipt-outline" | "refresh-outline" | "remove" | "repeat-outline" | "resize" | "rocket" | "school-outline" | "search-outline" | "server" | "share-outline" | "shield" | "shield-checkmark" | "shield-checkmark-outline" | "star" | "swap-horizontal-outline" | "swap-vertical-outline" | "sync" | "time-outline" | "trash-outline" | "trophy" | "trophy-outline" | "videocam" | "volume-off" | "wallet-outline" | "watch" | "wifi", "OxyServicesIonicons">;
2
+ declare const Ionicons: import("@expo/vector-icons/build/createIconSet").Icon<"push" | "at" | "infinite" | "code" | "business" | "navigate" | "key" | "open" | "add" | "search" | "list" | "settings" | "trash" | "wallet" | "link" | "text" | "scale" | "image" | "alert" | "radio" | "grid" | "warning" | "people" | "ellipse" | "add-circle-outline" | "alert-circle" | "alert-circle-outline" | "apps" | "archive" | "arrow-back" | "arrow-down" | "arrow-forward" | "arrow-undo" | "arrow-up" | "briefcase-outline" | "bug" | "bulb" | "business-outline" | "calendar" | "calendar-outline" | "camera" | "camera-outline" | "card" | "card-outline" | "cart-outline" | "cash-outline" | "chatbubble" | "checkmark" | "checkmark-circle" | "chevron-back" | "chevron-down" | "chevron-forward" | "chevron-up" | "close" | "close-circle" | "cloud-offline-outline" | "cloud-outline" | "cloud-upload" | "cloud-upload-outline" | "cog" | "cog-outline" | "construct-outline" | "copy-outline" | "cube-outline" | "desktop" | "document" | "document-outline" | "document-text" | "documents" | "download" | "download-outline" | "earth" | "ellipse-outline" | "ellipsis-horizontal" | "eye" | "eye-off-outline" | "filter-outline" | "flame" | "flash" | "folder" | "folder-open-outline" | "folder-outline" | "footsteps" | "gift" | "gift-outline" | "hand-left" | "hardware-chip-outline" | "heart" | "heart-outline" | "help-circle" | "help-circle-outline" | "hourglass-outline" | "image-outline" | "images" | "images-outline" | "information" | "information-circle" | "information-outline" | "leaf" | "library" | "link-outline" | "location" | "location-outline" | "lock-closed" | "log-out-outline" | "mail" | "musical-notes" | "pencil-outline" | "people-outline" | "play" | "pricetag-outline" | "pulse" | "qr-code-outline" | "receipt-outline" | "refresh-outline" | "remove" | "repeat-outline" | "resize" | "rocket" | "school-outline" | "search-outline" | "server" | "share-outline" | "shield" | "shield-checkmark" | "shield-checkmark-outline" | "star" | "swap-horizontal-outline" | "swap-vertical-outline" | "sync" | "time-outline" | "trash-outline" | "trophy" | "trophy-outline" | "videocam" | "volume-off" | "wallet-outline" | "watch" | "wifi", "OxyServicesIonicons">;
3
3
  export default Ionicons;
4
4
  //# sourceMappingURL=Ionicons.d.ts.map
@@ -1,4 +1,4 @@
1
1
  /** Glyphs are decorative: hidden from assistive technology (see `decorativeIconSet`). */
2
- declare const MaterialCommunityIcons: import("@expo/vector-icons/build/createIconSet").Icon<"function" | "android" | "web" | "devices" | "at" | "security" | "account" | "message" | "email" | "bio" | "phone" | "key" | "network" | "logout" | "label" | "history" | "wallet" | "link" | "text" | "translate" | "scale" | "solid" | "wrap" | "image" | "alert" | "radio" | "switch" | "grid" | "numeric" | "loading" | "decimal" | "contacts" | "ellipse" | "alert-circle" | "alert-circle-outline" | "apps" | "archive" | "arrow-down" | "arrow-up" | "briefcase-outline" | "bug" | "calendar" | "calendar-outline" | "camera" | "camera-outline" | "card" | "card-outline" | "cart-outline" | "chevron-down" | "chevron-up" | "close" | "close-circle" | "cloud-outline" | "cloud-upload" | "cloud-upload-outline" | "cog" | "cog-outline" | "cube-outline" | "download" | "download-outline" | "earth" | "ellipse-outline" | "eye" | "eye-off-outline" | "filter-outline" | "flash" | "folder" | "folder-open-outline" | "folder-outline" | "gift" | "gift-outline" | "heart" | "heart-outline" | "help-circle" | "help-circle-outline" | "image-outline" | "information" | "information-outline" | "leaf" | "library" | "mail" | "pencil-outline" | "play" | "pulse" | "receipt-outline" | "resize" | "rocket" | "school-outline" | "server" | "share-outline" | "shield" | "star" | "sync" | "trophy" | "trophy-outline" | "volume-off" | "wallet-outline" | "watch" | "wifi" | "delete" | "forward" | "account-circle" | "account-cog-outline" | "account-eye-outline" | "account-group" | "account-multiple" | "account-outline" | "account-plus" | "account-search" | "account-switch" | "archive-arrow-down" | "arrow-left" | "bell" | "bell-outline" | "bullhorn" | "cake-variant" | "cake-variant-outline" | "cancel" | "cellphone" | "cellphone-basic" | "cellphone-message" | "cellphone-screenshot" | "chart-line" | "check-all" | "check-circle" | "chip" | "circle-outline" | "clock" | "clock-outline" | "code-tags" | "contain" | "content-copy" | "controller" | "cookie" | "credit-card" | "database-outline" | "delete-outline" | "dots-horizontal" | "email-outline" | "file" | "file-document" | "file-document-edit-outline" | "file-document-outline" | "file-excel-outline" | "file-outline" | "file-pdf-box" | "folder-image" | "folder-zip-outline" | "ghost" | "image-multiple-outline" | "inbox" | "link-variant" | "lock-outline" | "magnify" | "map-marker" | "map-marker-multiple" | "map-marker-outline" | "message-outline" | "minus-circle" | "motion" | "music-note-outline" | "null" | "open-in-app" | "openid" | "palette" | "palette-outline" | "pan" | "phone-outline" | "plus" | "plus-circle" | "post" | "presentation" | "react" | "read" | "shield-account-outline" | "shield-check" | "shield-search" | "signature" | "sort-alphabetical-variant" | "sort-numeric-variant" | "store" | "tag" | "tag-outline" | "text-box-outline" | "theme-light-dark" | "transfer" | "trash-can-outline" | "tray-arrow-down" | "update" | "upload" | "video-outline" | "wifi-off" | "wrench" | "xml", "OxyServicesMaterialCommunityIcons">;
2
+ declare const MaterialCommunityIcons: import("@expo/vector-icons/build/createIconSet").Icon<"function" | "android" | "web" | "devices" | "at" | "forward" | "account" | "security" | "message" | "email" | "bio" | "phone" | "key" | "network" | "logout" | "label" | "history" | "wallet" | "link" | "text" | "translate" | "scale" | "solid" | "wrap" | "image" | "alert" | "radio" | "switch" | "grid" | "numeric" | "loading" | "decimal" | "contacts" | "ellipse" | "alert-circle" | "alert-circle-outline" | "apps" | "archive" | "arrow-down" | "arrow-up" | "briefcase-outline" | "bug" | "calendar" | "calendar-outline" | "camera" | "camera-outline" | "card" | "card-outline" | "cart-outline" | "chevron-down" | "chevron-up" | "close" | "close-circle" | "cloud-outline" | "cloud-upload" | "cloud-upload-outline" | "cog" | "cog-outline" | "cube-outline" | "download" | "download-outline" | "earth" | "ellipse-outline" | "eye" | "eye-off-outline" | "filter-outline" | "flash" | "folder" | "folder-open-outline" | "folder-outline" | "gift" | "gift-outline" | "heart" | "heart-outline" | "help-circle" | "help-circle-outline" | "image-outline" | "information" | "information-outline" | "leaf" | "library" | "mail" | "pencil-outline" | "play" | "pulse" | "receipt-outline" | "resize" | "rocket" | "school-outline" | "server" | "share-outline" | "shield" | "star" | "sync" | "trophy" | "trophy-outline" | "volume-off" | "wallet-outline" | "watch" | "wifi" | "delete" | "account-circle" | "account-cog-outline" | "account-eye-outline" | "account-group" | "account-multiple" | "account-outline" | "account-plus" | "account-search" | "account-switch" | "archive-arrow-down" | "arrow-left" | "bell" | "bell-outline" | "bullhorn" | "cake-variant" | "cake-variant-outline" | "cancel" | "cellphone" | "cellphone-basic" | "cellphone-message" | "cellphone-screenshot" | "chart-line" | "check-all" | "check-circle" | "chip" | "circle-outline" | "clock" | "clock-outline" | "code-tags" | "contain" | "content-copy" | "controller" | "cookie" | "credit-card" | "database-outline" | "delete-outline" | "dots-horizontal" | "email-outline" | "file" | "file-document" | "file-document-edit-outline" | "file-document-outline" | "file-excel-outline" | "file-outline" | "file-pdf-box" | "folder-image" | "folder-zip-outline" | "ghost" | "image-multiple-outline" | "inbox" | "link-variant" | "lock-outline" | "magnify" | "map-marker" | "map-marker-multiple" | "map-marker-outline" | "message-outline" | "minus-circle" | "motion" | "music-note-outline" | "null" | "open-in-app" | "openid" | "palette" | "palette-outline" | "pan" | "phone-outline" | "plus" | "plus-circle" | "post" | "presentation" | "react" | "read" | "shield-account-outline" | "shield-check" | "shield-search" | "signature" | "sort-alphabetical-variant" | "sort-numeric-variant" | "store" | "tag" | "tag-outline" | "text-box-outline" | "theme-light-dark" | "transfer" | "trash-can-outline" | "tray-arrow-down" | "update" | "upload" | "video-outline" | "wifi-off" | "wrench" | "xml", "OxyServicesMaterialCommunityIcons">;
3
3
  export default MaterialCommunityIcons;
4
4
  //# sourceMappingURL=MaterialCommunityIcons.d.ts.map
@@ -20,7 +20,7 @@ export { LogoIcon } from './components/logo/LogoIcon.js';
20
20
  export { LogoText } from './components/logo/LogoText.js';
21
21
  export { RequireOxyAuth } from './components/RequireOxyAuth.js';
22
22
  export type { RequireOxyAuthProps, RequireOxyAuthPrompt } from './components/RequireOxyAuth.js';
23
- export type { AccountQueriesConfig } from './hooks/accountQueryPersistence.js';
23
+ export type { AccountQueriesConfig, AccountQueryMeta } from './hooks/accountQueryPersistence.js';
24
24
  export { default as FollowButton } from './components/FollowButton.js';
25
25
  export { default as PeableButton } from './components/PeableButton.js';
26
26
  export type { PeableButtonProps } from './components/PeableButton.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/ui/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAMH,OAAO,wBAAqB,CAAC;AAS7B,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,6BAA0B,CAAC;AAClE,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,iCAA8B,CAAC;AAC1E,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,+BAA4B,CAAC;AACtE,YAAY,EAAE,kBAAkB,EAAE,MAAM,+BAA4B,CAAC;AACrE,OAAO,EAAE,QAAQ,EAAE,MAAM,+BAA4B,CAAC;AACtD,OAAO,EAAE,QAAQ,EAAE,MAAM,+BAA4B,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,gCAA6B,CAAC;AAC7D,YAAY,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,gCAA6B,CAAC;AAE7F,YAAY,EAAE,oBAAoB,EAAE,MAAM,oCAAiC,CAAC;AAC5E,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,8BAA2B,CAAC;AACpE,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,8BAA2B,CAAC;AACpE,YAAY,EAAE,iBAAiB,EAAE,MAAM,8BAA2B,CAAC;AACnE,8CAA8C;AAC9C,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,8BAA2B,CAAC;AACpE,mDAAmD;AACnD,YAAY,EAAE,iBAAiB,EAAE,MAAM,8BAA2B,CAAC;AACnE,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,+BAA4B,CAAC;AAGtE,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,uBAAuB,EAAE,MAAM,yBAAsB,CAAC;AACvF,OAAO,EAAE,eAAe,EAAE,MAAM,uCAAoC,CAAC;AACrE,YAAY,EAAE,qBAAqB,EAAE,MAAM,uCAAoC,CAAC;AAChF,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAiB,CAAC;AAC1C,YAAY,EAAE,WAAW,EAAE,SAAS,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,oBAAiB,CAAC;AAC5F,OAAO,EAAE,SAAS,EAAE,qBAAqB,EAAE,MAAM,sBAAmB,CAAC;AACrE,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAoB,CAAC;AAChD,YAAY,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,uBAAoB,CAAC;AAM9E,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAoB,CAAC;AAGlD,OAAO,EACL,eAAe,EACf,qBAAqB,EACrB,uBAAuB,EACvB,mBAAmB,GACpB,MAAM,0BAAuB,CAAC;AAC/B,YAAY,EAAE,sBAAsB,EAAE,MAAM,0BAAuB,CAAC;AAEpE,OAAO,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,mCAAgC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/ui/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAMH,OAAO,wBAAqB,CAAC;AAS7B,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,6BAA0B,CAAC;AAClE,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,iCAA8B,CAAC;AAC1E,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,+BAA4B,CAAC;AACtE,YAAY,EAAE,kBAAkB,EAAE,MAAM,+BAA4B,CAAC;AACrE,OAAO,EAAE,QAAQ,EAAE,MAAM,+BAA4B,CAAC;AACtD,OAAO,EAAE,QAAQ,EAAE,MAAM,+BAA4B,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,gCAA6B,CAAC;AAC7D,YAAY,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,gCAA6B,CAAC;AAE7F,YAAY,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,oCAAiC,CAAC;AAC9F,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,8BAA2B,CAAC;AACpE,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,8BAA2B,CAAC;AACpE,YAAY,EAAE,iBAAiB,EAAE,MAAM,8BAA2B,CAAC;AACnE,8CAA8C;AAC9C,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,8BAA2B,CAAC;AACpE,mDAAmD;AACnD,YAAY,EAAE,iBAAiB,EAAE,MAAM,8BAA2B,CAAC;AACnE,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,+BAA4B,CAAC;AAGtE,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,uBAAuB,EAAE,MAAM,yBAAsB,CAAC;AACvF,OAAO,EAAE,eAAe,EAAE,MAAM,uCAAoC,CAAC;AACrE,YAAY,EAAE,qBAAqB,EAAE,MAAM,uCAAoC,CAAC;AAChF,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAiB,CAAC;AAC1C,YAAY,EAAE,WAAW,EAAE,SAAS,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,oBAAiB,CAAC;AAC5F,OAAO,EAAE,SAAS,EAAE,qBAAqB,EAAE,MAAM,sBAAmB,CAAC;AACrE,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAoB,CAAC;AAChD,YAAY,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,uBAAoB,CAAC;AAM9E,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAoB,CAAC;AAGlD,OAAO,EACL,eAAe,EACf,qBAAqB,EACrB,uBAAuB,EACvB,mBAAmB,GACpB,MAAM,0BAAuB,CAAC;AAC/B,YAAY,EAAE,sBAAsB,EAAE,MAAM,0BAAuB,CAAC;AAEpE,OAAO,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,mCAAgC,CAAC"}
@@ -129,6 +129,8 @@ export interface OxyProviderProps {
129
129
  * account switch and deleted on sign-out. `RequireOxyAuth` waits for the
130
130
  * signed-in account's cache to restore, so another account's rows never
131
131
  * render. Works with the SDK's client or one passed as `queryClient`.
132
+ * A single query opts in with `meta: { persist: 'account' }` and needs no
133
+ * declaration here (`AccountQueryMeta`).
132
134
  */
133
135
  accountQueries?: AccountQueriesConfig;
134
136
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"navigation.d.ts","sourceRoot":"","sources":["../../../../../src/ui/types/navigation.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"navigation.d.ts","sourceRoot":"","sources":["../../../../../src/ui/types/navigation.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oxy.so/services",
3
- "version": "13.1.0",
3
+ "version": "13.2.0",
4
4
  "description": "OxyHQ Expo/React Native SDK — UI components, screens, and native features",
5
5
  "main": "lib/commonjs/index.js",
6
6
  "module": "lib/module/index.js",
package/src/index.ts CHANGED
@@ -323,7 +323,7 @@ export type {
323
323
  export { RequireOxyAuth } from './ui/components/RequireOxyAuth';
324
324
  export type { RequireOxyAuthProps, RequireOxyAuthPrompt } from './ui/components/RequireOxyAuth';
325
325
  // `OxyProvider`'s `accountQueries`: the app's per-account offline cache.
326
- export type { AccountQueriesConfig } from './ui/hooks/accountQueryPersistence';
326
+ export type { AccountQueriesConfig, AccountQueryMeta } from './ui/hooks/accountQueryPersistence';
327
327
 
328
328
  export { default as FollowButton } from './ui/components/FollowButton';
329
329
  export type {
@@ -130,8 +130,6 @@ export {
130
130
  OxyProviderMissingError,
131
131
  } from './oxyRuntimeContext';
132
132
 
133
- const subscribeNever = (): (() => void) => () => undefined;
134
-
135
133
  /**
136
134
  * The SDK's internal runtime provider — the session/account state machine that
137
135
  * backs `useOxy()`.
@@ -350,24 +348,23 @@ export const OxyRuntimeProvider: React.FC<OxyRuntimeProviderProps> = ({
350
348
  // a persistence write is never dropped because it raced storage init.
351
349
  const queryClient = useQueryClient();
352
350
 
353
- // The app's per-account offline cache (`accountQueries`). Built once, like the
354
- // runtime. `handleSubjectChange` activates it BEFORE anyone is woken, so a
355
- // consumer of the new account never reads the previous account's rows.
356
- const accountQueryPersistenceRef = useRef<AccountQueryPersistence | null | undefined>(undefined);
357
- if (accountQueryPersistenceRef.current === undefined) {
358
- accountQueryPersistenceRef.current = accountQueries
359
- ? createAccountQueryPersistence(queryClient, accountQueries)
360
- : null;
351
+ // The account's offline cache: the app's `accountQueries` roots and every
352
+ // query marked `meta: { persist: 'account' }`. Built once, like the runtime.
353
+ // `handleSubjectChange` activates it BEFORE anyone is woken, so a consumer of
354
+ // the new account never reads the previous account's rows.
355
+ const accountQueryPersistenceRef = useRef<AccountQueryPersistence | null>(null);
356
+ if (accountQueryPersistenceRef.current === null) {
357
+ accountQueryPersistenceRef.current = createAccountQueryPersistence(queryClient, accountQueries);
361
358
  }
362
359
  const accountQueryPersistence = accountQueryPersistenceRef.current;
363
360
  useEffect(() => {
364
- accountQueryPersistence?.attach();
365
- return () => accountQueryPersistence?.detach();
361
+ accountQueryPersistence.attach();
362
+ return () => accountQueryPersistence.detach();
366
363
  }, [accountQueryPersistence]);
367
364
  const isAccountCacheReady = useSyncExternalStore(
368
- accountQueryPersistence ? accountQueryPersistence.subscribe : subscribeNever,
369
- () => accountQueryPersistence?.isReady() ?? true,
370
- () => accountQueryPersistence?.isReady() ?? true,
365
+ accountQueryPersistence.subscribe,
366
+ accountQueryPersistence.isReady,
367
+ accountQueryPersistence.isReady,
371
368
  );
372
369
 
373
370
  const storageRef = useRef<StorageInterface | null>(null);
@@ -409,7 +406,7 @@ export const OxyRuntimeProvider: React.FC<OxyRuntimeProviderProps> = ({
409
406
  .then((storageInstance) => {
410
407
  storageRef.current = storageInstance;
411
408
  storageReady.resolve(storageInstance);
412
- accountQueryPersistence?.setStorage(storageInstance);
409
+ accountQueryPersistence.setStorage(storageInstance);
413
410
  if (mounted) {
414
411
  setStorage(storageInstance);
415
412
  runtime.setStorageReady(true);
@@ -418,7 +415,7 @@ export const OxyRuntimeProvider: React.FC<OxyRuntimeProviderProps> = ({
418
415
  .catch((err) => {
419
416
  // Nothing persisted can be restored; the account cache still has to
420
417
  // become ready, or RequireOxyAuth would wait forever.
421
- accountQueryPersistence?.setStorage(createMemoryStorage());
418
+ accountQueryPersistence.setStorage(createMemoryStorage());
422
419
  if (mounted) {
423
420
  logger('Failed to initialize storage', err);
424
421
  onError?.({
@@ -1378,9 +1375,20 @@ export const OxyRuntimeProvider: React.FC<OxyRuntimeProviderProps> = ({
1378
1375
  runtime.setAccount(cached.user);
1379
1376
  });
1380
1377
  onAuthStateChangeRef.current?.(cached.user);
1378
+ // The account's cached queries are part of this paint: one local read,
1379
+ // started by the subject change above, so nothing renders without them.
1380
+ await accountQueryPersistence.whenReady();
1381
1381
  markAuthResolvedRef.current();
1382
1382
  return true;
1383
- }, [identity, clientIdProp, authStore, oxyServices, runtime, syncDeviceCredentialToHost]);
1383
+ }, [
1384
+ identity,
1385
+ clientIdProp,
1386
+ authStore,
1387
+ oxyServices,
1388
+ runtime,
1389
+ syncDeviceCredentialToHost,
1390
+ accountQueryPersistence,
1391
+ ]);
1384
1392
 
1385
1393
  // A painted session the server could not be asked about yet stays on screen
1386
1394
  // and is asked again: on the lost-token backoff, and at once when the device
@@ -1687,7 +1695,7 @@ export const OxyRuntimeProvider: React.FC<OxyRuntimeProviderProps> = ({
1687
1695
  ({ previous, next }: SubjectTransition): void => {
1688
1696
  // Every transition, the first sign-in included: the account cache is
1689
1697
  // keyed by the subject, and a sign-out deletes the signed-out one's.
1690
- accountQueryPersistence?.activate(next);
1698
+ accountQueryPersistence.activate(next);
1691
1699
  if (previous === null) {
1692
1700
  return;
1693
1701
  }
@@ -4,7 +4,9 @@
4
4
  * The SDK's own persister (`attachQueryPersistence`) keeps account-agnostic
5
5
  * data. An app's mail, library or drafts belong to one account, and every app
6
6
  * that wanted them to survive a restart had to scope a persister to the session
7
- * itself. The SDK owns the session, so it owns this too:
7
+ * itself. The SDK owns the session, so it owns this too, for every root an app
8
+ * declares (`accountQueries`) and for any single query marked
9
+ * `meta: { persist: 'account' }`, with no declaration at all:
8
10
  *
9
11
  * - Storage is keyed by the account (`oxy_account_queries:<accountId>`), so a
10
12
  * restore can only ever hydrate the account that is signed in.
@@ -15,7 +17,9 @@
15
17
  * is woken. The leaving account's latest state is written first, a sign-out
16
18
  * then deletes it, and only then is the next account's blob read.
17
19
  * - `isReady()` is false until the signed-in account's blob is restored, and
18
- * `RequireOxyAuth` waits on it, so another account's rows never render.
20
+ * `RequireOxyAuth` waits on it, so another account's rows never render. A
21
+ * cold boot that paints a cached session waits on it too (`whenReady()`), so
22
+ * the first paint already has the account's rows.
19
23
  *
20
24
  * Every storage operation runs through one queue, in order, and a restore
21
25
  * checks that its account is still the active one in the same tick it hydrates.
@@ -39,12 +43,29 @@ import {
39
43
  type PersistFilters,
40
44
  } from './persistedQueryCache';
41
45
 
46
+ /**
47
+ * The `meta` that makes one query the signed-in account's and keeps it across
48
+ * restarts, exactly like a query under a declared root: for the few reads that
49
+ * shape a returning user's first paint (the tabs, the theme), not for lists.
50
+ *
51
+ * `useQuery({ queryKey, queryFn, meta: { persist: 'account' } })`
52
+ */
53
+ export interface AccountQueryMeta {
54
+ persist: 'account';
55
+ }
56
+
57
+ function isAccountQuery(query: Query): boolean {
58
+ return (query.meta as Partial<AccountQueryMeta> | undefined)?.persist === 'account';
59
+ }
60
+
42
61
  /** An app's declaration of which data is private to the signed-in account. */
43
62
  export interface AccountQueriesConfig {
44
63
  /**
45
64
  * Query-key roots (`queryKey[0]`) whose data belongs to the signed-in account
46
65
  * and survives a restart. `'all'`: every query the app runs, for an app whose
47
66
  * every read may depend on who is signed in, so no root can be forgotten.
67
+ * Every root's queries are written on every change to any of them: for one
68
+ * or two queries under a busy root, mark those instead (`AccountQueryMeta`).
48
69
  *
49
70
  * The roots `accounts`, `sessions` and `devices` are reserved for the SDK's
50
71
  * device-level data: an app must not use them. `users` and `privacy` are the
@@ -75,13 +96,19 @@ export interface AccountQueryOwnership {
75
96
  /** SDK roots that hold device-level data, the same whoever is signed in. */
76
97
  const DEVICE_ROOTS = new Set(['accounts', 'sessions', 'devices']);
77
98
 
78
- export function accountQueryOwnership(config: AccountQueriesConfig): AccountQueryOwnership {
99
+ /** No declared roots: only the queries marked `AccountQueryMeta` are the account's. */
100
+ const NO_ROOTS: AccountQueriesConfig = { roots: [] };
101
+
102
+ export function accountQueryOwnership(
103
+ config: AccountQueriesConfig = NO_ROOTS,
104
+ ): AccountQueryOwnership {
79
105
  const memoryOnly = new Set([...(config.memoryOnlyRoots ?? []), ...SDK_MEMORY_ONLY_ROOTS]);
80
106
  const sdkRoots = new Set(PERSISTED_QUERY_PREFIXES);
81
107
  const declared = config.roots === 'all' ? null : new Set(config.roots);
82
108
  const mutationHashes = new Set((config.mutationKeys ?? []).map((key) => hashKey(key)));
83
109
 
84
110
  const ownsQuery = (query: Query): boolean => {
111
+ if (isAccountQuery(query)) return true;
85
112
  const root = rootOf(query);
86
113
  if (root !== null && memoryOnly.has(root)) return true;
87
114
  if (declared === null) return root === null || !DEVICE_ROOTS.has(root);
@@ -94,7 +121,9 @@ export function accountQueryOwnership(config: AccountQueriesConfig): AccountQuer
94
121
  const root = rootOf(query);
95
122
  if (root === null) return true;
96
123
  // The SDK's own roots stay with the SDK persister.
97
- return !memoryOnly.has(root) && (declared !== null || !sdkRoots.has(root));
124
+ return (
125
+ !memoryOnly.has(root) && (isAccountQuery(query) || declared !== null || !sdkRoots.has(root))
126
+ );
98
127
  },
99
128
  ownsMutation: (mutation) => {
100
129
  const key = mutation.options.mutationKey;
@@ -118,6 +147,8 @@ export interface AccountQueryPersistence {
118
147
  detach(): void;
119
148
  /** True once the active account's cache is restored (always true signed out). */
120
149
  isReady(): boolean;
150
+ /** Resolves once `isReady()`, or once the account it waited for is left. */
151
+ whenReady(): Promise<void>;
121
152
  subscribe(listener: () => void): () => void;
122
153
  }
123
154
 
@@ -127,11 +158,11 @@ function storageKeyFor(accountId: string): string {
127
158
 
128
159
  export function createAccountQueryPersistence(
129
160
  queryClient: QueryClient,
130
- config: AccountQueriesConfig,
161
+ config?: AccountQueriesConfig,
131
162
  ): AccountQueryPersistence {
132
163
  const { ownsQuery, persistsQuery, ownsMutation } = accountQueryOwnership(config);
133
164
  const filters: PersistFilters = {
134
- shouldDehydrateQuery: (query) => query.state.status === 'success' && persistsQuery(query),
165
+ persistsQuery,
135
166
  shouldDehydrateMutation: (mutation) => mutation.state.isPaused && ownsMutation(mutation),
136
167
  };
137
168
  const listeners = new Set<() => void>();
@@ -159,6 +190,13 @@ export function createAccountQueryPersistence(
159
190
  const notify = () => {
160
191
  for (const listener of listeners) listener();
161
192
  };
193
+ const subscribe = (listener: () => void) => {
194
+ listeners.add(listener);
195
+ return () => {
196
+ listeners.delete(listener);
197
+ };
198
+ };
199
+ const isReady = () => accountId === null || restoredFor === accountId;
162
200
 
163
201
  const dropScopedData = () => {
164
202
  queryClient.removeQueries({ predicate: ownsQuery });
@@ -179,11 +217,12 @@ export function createAccountQueryPersistence(
179
217
  const current = generation;
180
218
  const key = storageKeyFor(id);
181
219
  enqueue(async (storage) => {
182
- const raw = await storage.getItem(key);
220
+ // An unreadable blob restores nothing; it must not leave the account unready.
221
+ const raw = await storage.getItem(key).catch(() => null);
183
222
  // Same tick as the hydrate: a switch in between cannot be missed.
184
223
  if (current !== generation) return;
185
224
  if (!hydrateSnapshot(queryClient, raw, ACCOUNT_QUERY_CACHE_MAX_AGE) && raw) {
186
- await storage.removeItem(key);
225
+ await storage.removeItem(key).catch(() => undefined);
187
226
  if (current !== generation) return;
188
227
  }
189
228
  restoredFor = id;
@@ -245,15 +284,21 @@ export function createAccountQueryPersistence(
245
284
  restoredFor = null;
246
285
  },
247
286
 
248
- isReady() {
249
- return accountId === null || restoredFor === accountId;
250
- },
287
+ isReady,
251
288
 
252
- subscribe(listener) {
253
- listeners.add(listener);
254
- return () => {
255
- listeners.delete(listener);
256
- };
289
+ whenReady() {
290
+ const waitingFor = generation;
291
+ const settled = () => isReady() || generation !== waitingFor;
292
+ if (settled()) return Promise.resolve();
293
+ return new Promise((resolve) => {
294
+ const off = subscribe(() => {
295
+ if (!settled()) return;
296
+ off();
297
+ resolve();
298
+ });
299
+ });
257
300
  },
301
+
302
+ subscribe,
258
303
  };
259
304
  }
@@ -44,7 +44,8 @@ export const SDK_MEMORY_ONLY_ROOTS: ReadonlyArray<string> = [
44
44
  ];
45
45
 
46
46
  export interface PersistFilters {
47
- shouldDehydrateQuery: (query: Query) => boolean;
47
+ /** The queries this cache keeps, whatever their state; only successful ones are written. */
48
+ persistsQuery: (query: Query) => boolean;
48
49
  shouldDehydrateMutation: (mutation: Mutation) => boolean;
49
50
  }
50
51
 
@@ -64,7 +65,11 @@ export function snapshot(queryClient: QueryClient, filters: PersistFilters): str
64
65
  const blob: PersistedBlob = {
65
66
  buster: getOxyBuildId(),
66
67
  timestamp: Date.now(),
67
- clientState: dehydrate(queryClient, filters),
68
+ clientState: dehydrate(queryClient, {
69
+ shouldDehydrateQuery: (query) =>
70
+ query.state.status === 'success' && filters.persistsQuery(query),
71
+ shouldDehydrateMutation: filters.shouldDehydrateMutation,
72
+ }),
68
73
  };
69
74
  return JSON.stringify(blob);
70
75
  }
@@ -102,8 +107,9 @@ export function hydrateSnapshot(
102
107
  }
103
108
 
104
109
  /**
105
- * Write the filtered cache on every change, at most once per `throttleMs`.
106
- * `write` receives the serialized snapshot; `flush()` writes now.
110
+ * Write the filtered cache whenever one of its queries or any mutation changes,
111
+ * at most once per `throttleMs`. Activity in queries it does not keep (feeds,
112
+ * search) never serializes it. `write` receives the snapshot; `flush()` writes now.
107
113
  */
108
114
  export function subscribeSnapshots(
109
115
  queryClient: QueryClient,
@@ -120,7 +126,9 @@ export function subscribeSnapshots(
120
126
  const schedule = () => {
121
127
  if (!timer) timer = setTimeout(flush, throttleMs);
122
128
  };
123
- const offQueries = queryClient.getQueryCache().subscribe(schedule);
129
+ const offQueries = queryClient.getQueryCache().subscribe((event) => {
130
+ if (filters.persistsQuery(event.query)) schedule();
131
+ });
124
132
  const offMutations = queryClient.getMutationCache().subscribe(schedule);
125
133
  return {
126
134
  flush,
@@ -21,7 +21,7 @@
21
21
  * (`persistedQueryCache.ts`) when introducing reads that should survive restart.
22
22
  */
23
23
 
24
- import { QueryClient, onlineManager, type Mutation, type Query } from '@tanstack/react-query';
24
+ import { QueryClient, onlineManager, type Query } from '@tanstack/react-query';
25
25
  import type { PersistedClient } from '@tanstack/react-query-persist-client';
26
26
  import { isDev } from '@oxy.so/core';
27
27
  import type { StorageInterface } from '../utils/storageHelpers';
@@ -30,6 +30,7 @@ import {
30
30
  PERSISTED_QUERY_PREFIXES,
31
31
  hydrateSnapshot,
32
32
  subscribeSnapshots,
33
+ type PersistFilters,
33
34
  } from './persistedQueryCache';
34
35
 
35
36
  const QUERY_CACHE_KEY = 'oxy_query_cache_v3';
@@ -53,15 +54,8 @@ export function shouldRetryQuery(failureCount: number, error: unknown): boolean
53
54
  return status === 408 || status === 425 || status === 429 || status >= 500;
54
55
  }
55
56
 
56
- /**
57
- * Whether a query belongs in the account-agnostic cache: successful (a
58
- * `pending`/`error` state is not worth keeping, and an error would leak
59
- * failure objects across restarts) and under one of the SDK's own prefixes.
60
- */
57
+ /** Whether a query is under one of the SDK's own account-agnostic prefixes. */
61
58
  function isSharedQuery(query: Query): boolean {
62
- if (query.state.status !== 'success') {
63
- return false;
64
- }
65
59
  const head = query.queryKey[0];
66
60
  return typeof head === 'string' && PERSISTED_QUERY_PREFIXES.includes(head);
67
61
  }
@@ -135,10 +129,11 @@ export interface AttachPersistenceResult {
135
129
  * Restore, then keep writing, the account-agnostic cache.
136
130
  *
137
131
  * Queries written by another build are dropped; queued mutations are kept
138
- * (`persistedQueryCache.ts`). Whatever the app declared account-scoped
139
- * (`accountQueries`) is left to `createAccountQueryPersistence`, even under
140
- * one of the SDK's prefixes, so private rows never land in the shared blob and
141
- * a paused mutation cannot replay twice or under another account.
132
+ * (`persistedQueryCache.ts`). Whatever belongs to the account (`accountQueries`,
133
+ * or a query marked `meta: { persist: 'account' }`) is left to
134
+ * `createAccountQueryPersistence`, even under one of the SDK's prefixes, so
135
+ * private rows never land in the shared blob and a paused mutation cannot
136
+ * replay twice or under another account.
142
137
  *
143
138
  * Safe to no-op if `storage` is null/undefined (e.g. server-side render
144
139
  * with no host storage).
@@ -155,13 +150,12 @@ export const attachQueryPersistence = (
155
150
  };
156
151
  }
157
152
 
158
- const account = accountQueries ? accountQueryOwnership(accountQueries) : null;
159
- const filters = {
160
- shouldDehydrateQuery: (query: Query) =>
161
- isSharedQuery(query) && !(account?.ownsQuery(query) ?? false),
153
+ const account = accountQueryOwnership(accountQueries);
154
+ const filters: PersistFilters = {
155
+ persistsQuery: (query) => isSharedQuery(query) && !account.ownsQuery(query),
162
156
  // Every other mutation, whatever its status: paused ones are exactly the
163
157
  // ones that must survive a restart to replay when online.
164
- shouldDehydrateMutation: (mutation: Mutation) => !(account?.ownsMutation(mutation) ?? false),
158
+ shouldDehydrateMutation: (mutation) => !account.ownsMutation(mutation),
165
159
  };
166
160
 
167
161
  let stopped = false;
package/src/ui/index.ts CHANGED
@@ -34,7 +34,7 @@ export { LogoText } from './components/logo/LogoText';
34
34
  export { RequireOxyAuth } from './components/RequireOxyAuth';
35
35
  export type { RequireOxyAuthProps, RequireOxyAuthPrompt } from './components/RequireOxyAuth';
36
36
  // `OxyProvider`'s `accountQueries`: the app's per-account offline cache.
37
- export type { AccountQueriesConfig } from './hooks/accountQueryPersistence';
37
+ export type { AccountQueriesConfig, AccountQueryMeta } from './hooks/accountQueryPersistence';
38
38
  export { default as FollowButton } from './components/FollowButton';
39
39
  export { default as PeableButton } from './components/PeableButton';
40
40
  export type { PeableButtonProps } from './components/PeableButton';
@@ -150,6 +150,8 @@ export interface OxyProviderProps {
150
150
  * account switch and deleted on sign-out. `RequireOxyAuth` waits for the
151
151
  * signed-in account's cache to restore, so another account's rows never
152
152
  * render. Works with the SDK's client or one passed as `queryClient`.
153
+ * A single query opts in with `meta: { persist: 'account' }` and needs no
154
+ * declaration here (`AccountQueryMeta`).
153
155
  */
154
156
  accountQueries?: AccountQueriesConfig;
155
157
  /**