@seedprotocol/sdk 0.7.8-next.1071.g2a141c1 → 0.7.8

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 (211) hide show
  1. package/dist/{ClientManager-Bv15o3Oz.js → ClientManager-B1r_8P5Z.js} +37 -40
  2. package/dist/ClientManager-B1r_8P5Z.js.map +1 -0
  3. package/dist/{Item-tX3kpbj4.js → Item-CjTEShfk.js} +384 -399
  4. package/dist/Item-CjTEShfk.js.map +1 -0
  5. package/dist/{ModelProperty-N-3gBfu5.js → ModelProperty-C3749Wjq.js} +36 -36
  6. package/dist/{ModelProperty-N-3gBfu5.js.map → ModelProperty-C3749Wjq.js.map} +1 -1
  7. package/dist/{Schema-CY3OxwKS.js → Schema-CX9CTtho.js} +35 -35
  8. package/dist/{Schema-CY3OxwKS.js.map → Schema-CX9CTtho.js.map} +1 -1
  9. package/dist/{SchemaValidationService-BR2ABK2r.js → SchemaValidationService-T5mqnY8q.js} +6 -6
  10. package/dist/{SchemaValidationService-BR2ABK2r.js.map → SchemaValidationService-T5mqnY8q.js.map} +1 -1
  11. package/dist/{backfillMetadataPropertyIds-vc_1RoDT.js → backfillMetadataPropertyIds-DWWkh-Ex.js} +3 -3
  12. package/dist/{backfillMetadataPropertyIds-vc_1RoDT.js.map → backfillMetadataPropertyIds-DWWkh-Ex.js.map} +1 -1
  13. package/dist/{tabEvents-BuorBItJ.js → changeFeed-DcsZ7deG.js} +369 -10
  14. package/dist/changeFeed-DcsZ7deG.js.map +1 -0
  15. package/dist/{configurePlatform-D-Pj9gTx.js → configurePlatform-AWild9o4.js} +2 -2
  16. package/dist/{configurePlatform-D-Pj9gTx.js.map → configurePlatform-AWild9o4.js.map} +1 -1
  17. package/dist/db/drizzle/0022_add_read_indexes.sql +5 -0
  18. package/dist/db/drizzle/0023_add_entity_changes.sql +48 -0
  19. package/dist/db/drizzle/meta/0022_snapshot.json +1585 -0
  20. package/dist/db/drizzle/meta/0023_snapshot.json +1645 -0
  21. package/dist/db/drizzle/meta/_journal.json +14 -0
  22. package/dist/{detachRowsBeforeDelete-sK1ye2W6.js → detachRowsBeforeDelete-Bo_pky-R.js} +2 -2
  23. package/dist/{detachRowsBeforeDelete-sK1ye2W6.js.map → detachRowsBeforeDelete-Bo_pky-R.js.map} +1 -1
  24. package/dist/dist/{ClientManager-Bv15o3Oz.d.ts → ClientManager-B1r_8P5Z.d.ts} +1 -1
  25. package/dist/dist/ClientManager-B1r_8P5Z.d.ts.map +1 -0
  26. package/dist/dist/{Item-tX3kpbj4.d.ts → Item-CjTEShfk.d.ts} +3 -2
  27. package/dist/dist/Item-CjTEShfk.d.ts.map +1 -0
  28. package/dist/dist/{ModelProperty-N-3gBfu5.d.ts → ModelProperty-C3749Wjq.d.ts} +1 -1
  29. package/dist/dist/{ModelProperty-N-3gBfu5.d.ts.map → ModelProperty-C3749Wjq.d.ts.map} +1 -1
  30. package/dist/dist/{Schema-CY3OxwKS.d.ts → Schema-CX9CTtho.d.ts} +2 -2
  31. package/dist/dist/{Schema-CY3OxwKS.d.ts.map → Schema-CX9CTtho.d.ts.map} +1 -1
  32. package/dist/dist/{SchemaValidationService-BR2ABK2r.d.ts → SchemaValidationService-T5mqnY8q.d.ts} +1 -1
  33. package/dist/dist/{SchemaValidationService-BR2ABK2r.d.ts.map → SchemaValidationService-T5mqnY8q.d.ts.map} +1 -1
  34. package/dist/dist/{backfillMetadataPropertyIds-vc_1RoDT.d.ts → backfillMetadataPropertyIds-DWWkh-Ex.d.ts} +1 -1
  35. package/dist/dist/backfillMetadataPropertyIds-DWWkh-Ex.d.ts.map +1 -0
  36. package/dist/dist/{tabEvents-BuorBItJ.d.ts → changeFeed-DcsZ7deG.d.ts} +101 -36
  37. package/dist/dist/changeFeed-DcsZ7deG.d.ts.map +1 -0
  38. package/dist/dist/{configurePlatform-D-Pj9gTx.d.ts → configurePlatform-AWild9o4.d.ts} +1 -1
  39. package/dist/dist/configurePlatform-AWild9o4.d.ts.map +1 -0
  40. package/dist/dist/{detachRowsBeforeDelete-sK1ye2W6.d.ts → detachRowsBeforeDelete-Bo_pky-R.d.ts} +1 -1
  41. package/dist/dist/detachRowsBeforeDelete-Bo_pky-R.d.ts.map +1 -0
  42. package/dist/dist/{eas-BSQxj7gN.d.ts → eas--9vtNkma.d.ts} +1 -1
  43. package/dist/dist/eas--9vtNkma.d.ts.map +1 -0
  44. package/dist/dist/{errors-a4Tj6hly.d.ts → errors-rIWK7gwJ.d.ts} +1 -1
  45. package/dist/dist/{errors-a4Tj6hly.d.ts.map → errors-rIWK7gwJ.d.ts.map} +1 -1
  46. package/dist/dist/{getItem-Ctps9gSs.d.ts → getItem-5j22EWWE.d.ts} +1 -1
  47. package/dist/dist/getItem-5j22EWWE.d.ts.map +1 -0
  48. package/dist/dist/{getPublishPayload-C2g5pPD2.d.ts → getPublishPayload-BGl2SaGK.d.ts} +1 -1
  49. package/dist/dist/{getPublishPayload-C2g5pPD2.d.ts.map → getPublishPayload-BGl2SaGK.d.ts.map} +1 -1
  50. package/dist/dist/{getPublishUploads-CaJHy3SL.d.ts → getPublishUploads-DVsDx6Xf.d.ts} +1 -1
  51. package/dist/dist/{getPublishUploads-CaJHy3SL.d.ts.map → getPublishUploads-DVsDx6Xf.d.ts.map} +1 -1
  52. package/dist/dist/{index-s73wD_LC.d.ts → index-C0SetTd1.d.ts} +1190 -1065
  53. package/dist/dist/index-C0SetTd1.d.ts.map +1 -0
  54. package/dist/dist/{index-BgEwcREa.d.ts → index-CJK3F_MK.d.ts} +13 -13
  55. package/dist/dist/index-CJK3F_MK.d.ts.map +1 -0
  56. package/dist/dist/{index-B6hPWSM4.d.ts → index-CZQrNqvq.d.ts} +130 -13
  57. package/dist/dist/{index-B6hPWSM4.d.ts.map → index-CZQrNqvq.d.ts.map} +1 -1
  58. package/dist/dist/{index-bOwhhJJL.d.ts → index-Dp4uyZYx.d.ts} +5 -5
  59. package/dist/dist/index-Dp4uyZYx.d.ts.map +1 -0
  60. package/dist/dist/{index.browser-C7iZp7mx.d.ts → index.browser-Ll71Y_Dl.d.ts} +391 -39
  61. package/dist/dist/{index.browser-C7iZp7mx.d.ts.map → index.browser-Ll71Y_Dl.d.ts.map} +1 -1
  62. package/dist/dist/{index.node-MPVTJR2J.d.ts → index.node-CgltN0cC.d.ts} +517 -49
  63. package/dist/dist/{index.node-MPVTJR2J.d.ts.map → index.node-CgltN0cC.d.ts.map} +1 -1
  64. package/dist/dist/modelPropertyRecordSchemas-C_lYTzMr.d.ts +7 -0
  65. package/dist/dist/modelPropertyRecordSchemas-C_lYTzMr.d.ts.map +1 -0
  66. package/dist/dist/platform.browser.d.ts +2 -2
  67. package/dist/dist/platform.node.d.ts +2 -2
  68. package/dist/dist/{property-mP9mOZ2L.d.ts → property-pcDxNEpy.d.ts} +3 -3
  69. package/dist/dist/property-pcDxNEpy.d.ts.map +1 -0
  70. package/dist/dist/{propertyValidationRules-DwzrYA7c.d.ts → propertyValidationRules-BEjN0f3-.d.ts} +6 -1
  71. package/dist/dist/propertyValidationRules-BEjN0f3-.d.ts.map +1 -0
  72. package/dist/dist/{publishDraftGraph-BzYVblZZ.d.ts → publishDraftGraph-I5yKe1Xz.d.ts} +1 -1
  73. package/dist/dist/{publishDraftGraph-BzYVblZZ.d.ts.map → publishDraftGraph-I5yKe1Xz.d.ts.map} +1 -1
  74. package/dist/dist/{resetAmbiguousLegacyItemData-B_IUQA09.d.ts → resetAmbiguousLegacyItemData-0Tin9-JK.d.ts} +1 -1
  75. package/dist/dist/resetAmbiguousLegacyItemData-0Tin9-JK.d.ts.map +1 -0
  76. package/dist/dist/{resolveModelForSyncedSeed-H-4tmU6l.d.ts → resolveModelForSyncedSeed-C5KXn6ex.d.ts} +1 -1
  77. package/dist/dist/resolveModelForSyncedSeed-C5KXn6ex.d.ts.map +1 -0
  78. package/dist/dist/{syncDbWithEas-y5VF623G.d.ts → syncDbWithEas-b4fESZ7C.d.ts} +1 -1
  79. package/dist/dist/syncDbWithEas-b4fESZ7C.d.ts.map +1 -0
  80. package/dist/dist/{tolerantWebAccess-DoI7QYT-.d.ts → tolerantWebAccess-CIpS7RLk.d.ts} +1 -1
  81. package/dist/dist/{tolerantWebAccess-DoI7QYT-.d.ts.map → tolerantWebAccess-CIpS7RLk.d.ts.map} +1 -1
  82. package/dist/dist/{updateSeedRevokedAt-BIzkbsUd.d.ts → updateSeedRevokedAt-CR4zwn-6.d.ts} +1 -1
  83. package/dist/dist/updateSeedRevokedAt-CR4zwn-6.d.ts.map +1 -0
  84. package/dist/{eas-BSQxj7gN.js → eas--9vtNkma.js} +3 -3
  85. package/dist/{eas-BSQxj7gN.js.map → eas--9vtNkma.js.map} +1 -1
  86. package/dist/{errors-a4Tj6hly.js → errors-rIWK7gwJ.js} +35 -35
  87. package/dist/{errors-a4Tj6hly.js.map → errors-rIWK7gwJ.js.map} +1 -1
  88. package/dist/{getItem-Ctps9gSs.js → getItem-5j22EWWE.js} +5 -5
  89. package/dist/{getItem-Ctps9gSs.js.map → getItem-5j22EWWE.js.map} +1 -1
  90. package/dist/{getPublishPayload-C2g5pPD2.js → getPublishPayload-BGl2SaGK.js} +14 -14
  91. package/dist/{getPublishPayload-C2g5pPD2.js.map → getPublishPayload-BGl2SaGK.js.map} +1 -1
  92. package/dist/{getPublishUploads-CaJHy3SL.js → getPublishUploads-DVsDx6Xf.js} +7 -7
  93. package/dist/{getPublishUploads-CaJHy3SL.js.map → getPublishUploads-DVsDx6Xf.js.map} +1 -1
  94. package/dist/{index-s73wD_LC.js → index-C0SetTd1.js} +52 -13
  95. package/dist/index-C0SetTd1.js.map +1 -0
  96. package/dist/{index-BgEwcREa.js → index-CJK3F_MK.js} +8 -8
  97. package/dist/index-CJK3F_MK.js.map +1 -0
  98. package/dist/{index-B6hPWSM4.js → index-CZQrNqvq.js} +3 -2
  99. package/dist/index-CZQrNqvq.js.map +1 -0
  100. package/dist/{index-bOwhhJJL.js → index-Dp4uyZYx.js} +8 -8
  101. package/dist/index-Dp4uyZYx.js.map +1 -0
  102. package/dist/{index.browser-C7iZp7mx.js → index.browser-Ll71Y_Dl.js} +243 -18
  103. package/dist/index.browser-Ll71Y_Dl.js.map +1 -0
  104. package/dist/{index.node-MPVTJR2J.js → index.node-CgltN0cC.js} +50 -15
  105. package/dist/index.node-CgltN0cC.js.map +1 -0
  106. package/dist/main.js +23 -30
  107. package/dist/main.js.map +1 -1
  108. package/dist/modelPropertyRecordSchemas-C_lYTzMr.js +94 -0
  109. package/dist/modelPropertyRecordSchemas-C_lYTzMr.js.map +1 -0
  110. package/dist/node.js +11 -11
  111. package/dist/platform.browser.js +5 -5
  112. package/dist/platform.node.js +4 -4
  113. package/dist/{property-mP9mOZ2L.js → property-pcDxNEpy.js} +7 -7
  114. package/dist/{property-mP9mOZ2L.js.map → property-pcDxNEpy.js.map} +1 -1
  115. package/dist/propertyValidationRules-BEjN0f3-.js +73 -0
  116. package/dist/propertyValidationRules-BEjN0f3-.js.map +1 -0
  117. package/dist/{publishDraftGraph-BzYVblZZ.js → publishDraftGraph-I5yKe1Xz.js} +6 -6
  118. package/dist/{publishDraftGraph-BzYVblZZ.js.map → publishDraftGraph-I5yKe1Xz.js.map} +1 -1
  119. package/dist/{resetAmbiguousLegacyItemData-B_IUQA09.js → resetAmbiguousLegacyItemData-0Tin9-JK.js} +2 -2
  120. package/dist/{resetAmbiguousLegacyItemData-B_IUQA09.js.map → resetAmbiguousLegacyItemData-0Tin9-JK.js.map} +1 -1
  121. package/dist/{resolveModelForSyncedSeed-H-4tmU6l.js → resolveModelForSyncedSeed-C5KXn6ex.js} +2 -2
  122. package/dist/{resolveModelForSyncedSeed-H-4tmU6l.js.map → resolveModelForSyncedSeed-C5KXn6ex.js.map} +1 -1
  123. package/dist/seedSchema/EntityChangeSchema.ts +28 -0
  124. package/dist/seedSchema/MetadataSchema.ts +12 -4
  125. package/dist/seedSchema/SeedSchema.ts +9 -3
  126. package/dist/seedSchema/VersionSchema.ts +9 -4
  127. package/dist/seedSchema/index.ts +1 -0
  128. package/dist/src/Item/Item.d.ts +2 -1
  129. package/dist/src/Item/Item.d.ts.map +1 -1
  130. package/dist/src/Item/service/actors/loadOrCreateItem.d.ts.map +1 -1
  131. package/dist/src/ItemProperty/ItemProperty.d.ts.map +1 -1
  132. package/dist/src/ItemProperty/service/actors/loadOrCreateProperty.d.ts.map +1 -1
  133. package/dist/src/ItemProperty/service/actors/modelPropertyRecordSchemas.d.ts +21 -0
  134. package/dist/src/ItemProperty/service/actors/modelPropertyRecordSchemas.d.ts.map +1 -0
  135. package/dist/src/browser/db/Db.d.ts +2 -2
  136. package/dist/src/browser/db/Db.d.ts.map +1 -1
  137. package/dist/src/browser/db/changeFeed.d.ts +77 -0
  138. package/dist/src/browser/db/changeFeed.d.ts.map +1 -0
  139. package/dist/src/browser/db/drizzleFiles.d.ts +4 -2
  140. package/dist/src/browser/db/drizzleFiles.d.ts.map +1 -1
  141. package/dist/src/db/write/applyArweaveL1TransactionIdLocal.d.ts.map +1 -1
  142. package/dist/src/db/write/claimUnpublishedDrafts.d.ts.map +1 -1
  143. package/dist/src/db/write/createMetadata.d.ts.map +1 -1
  144. package/dist/src/db/write/createSeed.d.ts.map +1 -1
  145. package/dist/src/db/write/createVersion.d.ts.map +1 -1
  146. package/dist/src/db/write/restoreDataItemIdsOverwrittenByL1.d.ts.map +1 -1
  147. package/dist/src/db/write/saveMetadata.d.ts.map +1 -1
  148. package/dist/src/db/write/updateItemPropertyValue.d.ts.map +1 -1
  149. package/dist/src/db/write/updateSeedRevokedAt.d.ts.map +1 -1
  150. package/dist/src/db/write/updateSeedUid.d.ts.map +1 -1
  151. package/dist/src/db/write/updateVersionUid.d.ts.map +1 -1
  152. package/dist/src/events/item/syncDbWithEas.d.ts.map +1 -1
  153. package/dist/src/helpers/propertyValidationRules.d.ts +8 -0
  154. package/dist/src/helpers/propertyValidationRules.d.ts.map +1 -1
  155. package/dist/src/helpers/timing.d.ts +36 -0
  156. package/dist/src/helpers/timing.d.ts.map +1 -1
  157. package/dist/src/index.d.ts +2 -0
  158. package/dist/src/index.d.ts.map +1 -1
  159. package/dist/src/node/db/singleConnectionTransactions.d.ts +6 -0
  160. package/dist/src/node/db/singleConnectionTransactions.d.ts.map +1 -1
  161. package/dist/src/outbox/itemAppliers.d.ts.map +1 -1
  162. package/dist/src/outbox/outbox.d.ts +2 -0
  163. package/dist/src/outbox/outbox.d.ts.map +1 -1
  164. package/dist/src/outbox/pendingValues.d.ts.map +1 -1
  165. package/dist/src/seedSchema/EntityChangeSchema.d.ts +126 -0
  166. package/dist/src/seedSchema/EntityChangeSchema.d.ts.map +1 -0
  167. package/dist/src/seedSchema/MetadataSchema.d.ts +4 -4
  168. package/dist/src/seedSchema/MetadataSchema.d.ts.map +1 -1
  169. package/dist/src/seedSchema/SeedSchema.d.ts +4 -4
  170. package/dist/src/seedSchema/SeedSchema.d.ts.map +1 -1
  171. package/dist/src/seedSchema/VersionSchema.d.ts +4 -4
  172. package/dist/src/seedSchema/VersionSchema.d.ts.map +1 -1
  173. package/dist/src/seedSchema/index.d.ts +1 -0
  174. package/dist/src/seedSchema/index.d.ts.map +1 -1
  175. package/dist/{syncDbWithEas-y5VF623G.js → syncDbWithEas-b4fESZ7C.js} +17 -23
  176. package/dist/syncDbWithEas-b4fESZ7C.js.map +1 -0
  177. package/dist/{tolerantWebAccess-DoI7QYT-.js → tolerantWebAccess-CIpS7RLk.js} +6 -6
  178. package/dist/{tolerantWebAccess-DoI7QYT-.js.map → tolerantWebAccess-CIpS7RLk.js.map} +1 -1
  179. package/dist/{updateSeedRevokedAt-BIzkbsUd.js → updateSeedRevokedAt-CR4zwn-6.js} +5 -6
  180. package/dist/updateSeedRevokedAt-CR4zwn-6.js.map +1 -0
  181. package/package.json +6 -6
  182. package/dist/ClientManager-Bv15o3Oz.js.map +0 -1
  183. package/dist/Item-tX3kpbj4.js.map +0 -1
  184. package/dist/dist/ClientManager-Bv15o3Oz.d.ts.map +0 -1
  185. package/dist/dist/Item-tX3kpbj4.d.ts.map +0 -1
  186. package/dist/dist/backfillMetadataPropertyIds-vc_1RoDT.d.ts.map +0 -1
  187. package/dist/dist/configurePlatform-D-Pj9gTx.d.ts.map +0 -1
  188. package/dist/dist/detachRowsBeforeDelete-sK1ye2W6.d.ts.map +0 -1
  189. package/dist/dist/eas-BSQxj7gN.d.ts.map +0 -1
  190. package/dist/dist/getItem-Ctps9gSs.d.ts.map +0 -1
  191. package/dist/dist/index-BgEwcREa.d.ts.map +0 -1
  192. package/dist/dist/index-bOwhhJJL.d.ts.map +0 -1
  193. package/dist/dist/index-s73wD_LC.d.ts.map +0 -1
  194. package/dist/dist/property-mP9mOZ2L.d.ts.map +0 -1
  195. package/dist/dist/propertyValidationRules-DwzrYA7c.d.ts.map +0 -1
  196. package/dist/dist/resetAmbiguousLegacyItemData-B_IUQA09.d.ts.map +0 -1
  197. package/dist/dist/resolveModelForSyncedSeed-H-4tmU6l.d.ts.map +0 -1
  198. package/dist/dist/syncDbWithEas-y5VF623G.d.ts.map +0 -1
  199. package/dist/dist/tabEvents-BuorBItJ.d.ts.map +0 -1
  200. package/dist/dist/updateSeedRevokedAt-BIzkbsUd.d.ts.map +0 -1
  201. package/dist/index-B6hPWSM4.js.map +0 -1
  202. package/dist/index-BgEwcREa.js.map +0 -1
  203. package/dist/index-bOwhhJJL.js.map +0 -1
  204. package/dist/index-s73wD_LC.js.map +0 -1
  205. package/dist/index.browser-C7iZp7mx.js.map +0 -1
  206. package/dist/index.node-MPVTJR2J.js.map +0 -1
  207. package/dist/propertyValidationRules-DwzrYA7c.js +0 -51
  208. package/dist/propertyValidationRules-DwzrYA7c.js.map +0 -1
  209. package/dist/syncDbWithEas-y5VF623G.js.map +0 -1
  210. package/dist/tabEvents-BuorBItJ.js.map +0 -1
  211. package/dist/updateSeedRevokedAt-BIzkbsUd.js.map +0 -1
@@ -1,5 +1,132 @@
1
1
  import debug from 'debug';
2
- import { am as isBrowser, I as eventEmitter, N as BaseFileManager, ah as EAS_SEED_DATA_SYNCED_TO_DB_EVENT } from './index-s73wD_LC.js';
2
+ import { au as isBrowser, J as eventEmitter, Q as BaseFileManager, ai as EAS_SEED_DATA_SYNCED_TO_DB_EVENT, o as entityChanges } from './index-C0SetTd1.js';
3
+ import { sql, gt, lt } from 'drizzle-orm';
4
+
5
+ /**
6
+ * Phase timings for item creates, finds and property saves, and ready waits that timed out but
7
+ * were allowed to continue, under `DEBUG=seedSdk:timing`. Timing lines are `<label> <ms>ms` plus
8
+ * any details, so an app can report where a slow call spent its time.
9
+ */
10
+ const timingLogger = debug('seedSdk:timing');
11
+ const now = () => (typeof performance !== 'undefined' ? performance.now() : Date.now());
12
+ /** Runs `fn` and logs how long it took (also when it throws). Costs nothing when the namespace is off. */
13
+ async function timed(label, fn, details) {
14
+ if (!timingLogger.enabled)
15
+ return fn();
16
+ const start = now();
17
+ let failed = false;
18
+ try {
19
+ return await fn();
20
+ }
21
+ catch (error) {
22
+ failed = true;
23
+ throw error;
24
+ }
25
+ finally {
26
+ const extra = details?.();
27
+ timingLogger(`${label} ${Math.round(now() - start)}ms${failed ? ' (failed)' : ''}${extra ? ` ${extra}` : ''}`);
28
+ }
29
+ }
30
+ /**
31
+ * Database work counted while the namespace is on, so a timing line can say how much of its time
32
+ * was the SQLite worker. Statements are the ones the SDK sends through the driver; their time runs
33
+ * from send to result, so it includes the wait behind everything queued before them on the one
34
+ * worker. Live-query runs are SQLocal reactive-query results (the first run and every re-run after
35
+ * a write to a watched table), which go through the same worker but not through the driver.
36
+ */
37
+ const dbTimingCounters = {
38
+ statements: 0,
39
+ statementMs: 0,
40
+ inFlight: 0,
41
+ liveQueryRuns: 0,
42
+ liveQueryFirstRuns: 0,
43
+ liveQueryFirstRunMs: 0,
44
+ };
45
+ const snapshotCounters = () => ({ ...dbTimingCounters });
46
+ /** Wraps a driver function so each call is counted while timing is on. */
47
+ function countDbStatements(driver) {
48
+ return async (...args) => {
49
+ if (!timingLogger.enabled)
50
+ return driver(...args);
51
+ const start = now();
52
+ dbTimingCounters.inFlight += 1;
53
+ try {
54
+ return await driver(...args);
55
+ }
56
+ finally {
57
+ dbTimingCounters.inFlight -= 1;
58
+ dbTimingCounters.statements += 1;
59
+ dbTimingCounters.statementMs += now() - start;
60
+ }
61
+ };
62
+ }
63
+ /** Starts the clock for one live query; call the result on each of its runs. */
64
+ function countLiveQueryRuns() {
65
+ if (!timingLogger.enabled)
66
+ return () => { };
67
+ const start = now();
68
+ let first = true;
69
+ return () => {
70
+ dbTimingCounters.liveQueryRuns += 1;
71
+ if (!first)
72
+ return;
73
+ first = false;
74
+ dbTimingCounters.liveQueryFirstRuns += 1;
75
+ dbTimingCounters.liveQueryFirstRunMs += now() - start;
76
+ };
77
+ }
78
+ const describeDbDelta = (before) => {
79
+ const after = dbTimingCounters;
80
+ const statements = after.statements - before.statements;
81
+ const statementMs = after.statementMs - before.statementMs;
82
+ const liveRuns = after.liveQueryRuns - before.liveQueryRuns;
83
+ const firstRuns = after.liveQueryFirstRuns - before.liveQueryFirstRuns;
84
+ const firstMs = after.liveQueryFirstRunMs - before.liveQueryFirstRunMs;
85
+ const parts = [`queued ${before.inFlight}`];
86
+ if (statements)
87
+ parts.push(`${statements} stmts avg ${Math.round(statementMs / statements)}ms`);
88
+ if (liveRuns)
89
+ parts.push(`${liveRuns} live runs`);
90
+ if (firstRuns)
91
+ parts.push(`${firstRuns} new live queries, first run avg ${Math.round(firstMs / firstRuns)}ms`);
92
+ return `[db: ${parts.join(', ')}]`;
93
+ };
94
+ /**
95
+ * Like `timed`, and the line also says how many statements and live-query runs went through the
96
+ * worker meanwhile (from any caller, since they share the queue) and how many statements were
97
+ * already queued when it started.
98
+ */
99
+ async function timedDb(label, fn, details) {
100
+ if (!timingLogger.enabled)
101
+ return fn();
102
+ const before = snapshotCounters();
103
+ return timed(label, fn, () => [details?.(), describeDbDelta(before)].filter(Boolean).join(' '));
104
+ }
105
+ /** Milliseconds since `start` (a `timingNow()` value), rounded. */
106
+ const timingSince = (start) => Math.round(now() - start);
107
+ const timingNow = now;
108
+ /**
109
+ * Split timer for one multi-step call: `mark(step)` records the time since the previous mark, and
110
+ * `log(label)` writes one line with the total and every step. Does nothing when timing is off.
111
+ */
112
+ function timingMarks() {
113
+ if (!timingLogger.enabled)
114
+ return { mark: () => { }, log: () => { } };
115
+ const start = now();
116
+ const before = snapshotCounters();
117
+ let last = start;
118
+ const steps = [];
119
+ return {
120
+ mark: (step) => {
121
+ const t = now();
122
+ steps.push(`${step} ${Math.round(t - last)}`);
123
+ last = t;
124
+ },
125
+ log: (label) => {
126
+ timingLogger(`${label} ${Math.round(now() - start)}ms: ${steps.join(', ')} ${describeDbDelta(before)}`);
127
+ },
128
+ };
129
+ }
3
130
 
4
131
  /**
5
132
  * Cross-tab exclusive sections, using the Web Locks API. All tabs of an origin share one SQLite
@@ -101,7 +228,7 @@ function waitForTurn(previous, name, timeoutMs) {
101
228
  return Promise.race([previous, timedOut]).finally(() => clearTimeout(timer));
102
229
  }
103
230
 
104
- const logger$1 = debug('seedSdk:helpers:tabCoordinator');
231
+ const logger$2 = debug('seedSdk:helpers:tabCoordinator');
105
232
  /** Identifies this tab (this page's SDK instance) in the messages it sends. */
106
233
  const TAB_ID = typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function'
107
234
  ? crypto.randomUUID()
@@ -148,7 +275,7 @@ function becomeLeader() {
148
275
  if (leader)
149
276
  return;
150
277
  leader = true;
151
- logger$1(`this tab leads ${state?.dbKey}`);
278
+ logger$2(`this tab leads ${state?.dbKey}`);
152
279
  const waiters = leaderWaiters;
153
280
  leaderWaiters = [];
154
281
  for (const resolve of waiters)
@@ -215,7 +342,7 @@ function parseAddressesPersistedPayload(value) {
215
342
  return { owned, watched };
216
343
  }
217
344
 
218
- const logger = debug('seedSdk:helpers:tabEvents');
345
+ const logger$1 = debug('seedSdk:helpers:tabEvents');
219
346
  /**
220
347
  * Keeps other tabs current (docs/MULTI_TAB.md). The event bus is per tab, so events that mean "the
221
348
  * shared database or OPFS changed" are also posted to the other tabs, which refresh their caches
@@ -303,14 +430,14 @@ function flushFilesChangedNotices() {
303
430
  /** Refreshes this tab's in-memory state for an event another tab emitted, before re-emitting it. */
304
431
  async function catchUpOn(name, payload) {
305
432
  if (name === EAS_SEED_DATA_SYNCED_TO_DB_EVENT) {
306
- const _mod_0 = await import('./Item-tX3kpbj4.js');
433
+ const _mod_0 = await import('./Item-CjTEShfk.js');
307
434
  const _ns_0 = _mod_0.av;
308
435
  const { Item } = _ns_0;
309
436
  await Item.rehydrateCachedItemsFromDbAfterEasSync();
310
437
  }
311
438
  else if (name === LOCAL_COPIES_REMOVED_EVENT) {
312
439
  const { removedSeedLocalIds = [], removedSeedUids = [] } = (payload ?? {});
313
- const _mod_1 = await import('./Item-tX3kpbj4.js');
440
+ const _mod_1 = await import('./Item-CjTEShfk.js');
314
441
  const _ns_1 = _mod_1.av;
315
442
  const { Item } = _ns_1;
316
443
  Item.dropCachedInstancesForSeedIds([...removedSeedLocalIds, ...removedSeedUids]);
@@ -330,7 +457,7 @@ function listenForOtherTabsEvents() {
330
457
  onTabMessage((message) => {
331
458
  if (message.type === 'event' && RELAYED_EVENTS.has(message.name)) {
332
459
  void catchUpOn(message.name, message.payload)
333
- .catch((error) => logger(`catching up on ${message.name} failed`, error))
460
+ .catch((error) => logger$1(`catching up on ${message.name} failed`, error))
334
461
  .then(() => {
335
462
  if (message.payload === undefined) {
336
463
  eventEmitter.emit(message.name);
@@ -343,7 +470,7 @@ function listenForOtherTabsEvents() {
343
470
  else if (message.type === 'files-changed') {
344
471
  // Only refreshes caches: never writes, so never sends files-changed back.
345
472
  void BaseFileManager.invalidateCachedPaths(message.paths)
346
- .catch((error) => logger('refreshing changed files failed', error))
473
+ .catch((error) => logger$1('refreshing changed files failed', error))
347
474
  .then(() => eventEmitter.emit(FILES_CHANGED_EVENT, message.paths));
348
475
  }
349
476
  });
@@ -362,5 +489,237 @@ var tabEvents = /*#__PURE__*/Object.freeze({
362
489
  queueFilesChangedNotice: queueFilesChangedNotice
363
490
  });
364
491
 
365
- export { ADDRESSES_PERSISTED_EVENT as A, FILES_CHANGED_EVENT as F, LOCAL_COPIES_REMOVED_EVENT as L, TabLockTimeoutError as T, withDbTabLock as a, withSeedDbLock as b, createSessionObjectUrl as c, postTabMessage as d, emitAcrossTabs as e, withTabLock as f, notifyFileSaved as g, TAB_ID as h, isLeaderTab as i, isSessionObjectUrl as j, tabEvents as k, listenForOtherTabsEvents as l, notifyFilesWrittenOutsideCache as n, onTabMessage as o, parseAddressesPersistedPayload as p, revokeSessionObjectUrl as r, startTabCoordination as s, tryWithTabLock as t, whenLeaderTab as w };
366
- //# sourceMappingURL=tabEvents-BuorBItJ.js.map
492
+ const logger = debug('seedSdk:browser:db:changeFeed');
493
+ /** Log rows older than this are pruned by the leader tab. */
494
+ const ENTITY_CHANGES_RETENTION_MS = 10 * 60000;
495
+ /** The leader prunes at most this often. */
496
+ const ENTITY_CHANGES_PRUNE_EVERY_MS = 60000;
497
+ const byLocalId = new Map();
498
+ const byUid = new Map();
499
+ const registrations = new Set();
500
+ let feed;
501
+ let cursor = 0;
502
+ let reading;
503
+ let readAgain = false;
504
+ let lastPrunedAt = 0;
505
+ const addTo = (map, key, registration) => {
506
+ let set = map.get(key);
507
+ if (!set)
508
+ map.set(key, (set = new Set()));
509
+ set.add(registration);
510
+ };
511
+ const removeFrom = (map, key, registration) => {
512
+ const set = map.get(key);
513
+ if (!set)
514
+ return;
515
+ set.delete(registration);
516
+ if (set.size === 0)
517
+ map.delete(key);
518
+ };
519
+ /**
520
+ * Calls `listener` after a committed write to one of `watch.tables` for the watched seed, matched
521
+ * by local id or (case-insensitively) by uid. A read of the log that has several matching rows
522
+ * calls it once. When the tab missed rows (its cursor is older than the oldest kept row), every
523
+ * listener is called once. Returns the unregister function.
524
+ */
525
+ function watchEntityChanges(watch, listener) {
526
+ const registration = {
527
+ watch,
528
+ tables: new Set(watch.tables),
529
+ propertyNames: watch.propertyNames ? new Set(watch.propertyNames) : undefined,
530
+ listener,
531
+ };
532
+ const localId = watch.seedLocalId || undefined;
533
+ const uid = watch.seedUid ? watch.seedUid.toLowerCase() : undefined;
534
+ registrations.add(registration);
535
+ if (localId)
536
+ addTo(byLocalId, localId, registration);
537
+ if (uid)
538
+ addTo(byUid, uid, registration);
539
+ return () => {
540
+ registrations.delete(registration);
541
+ if (localId)
542
+ removeFrom(byLocalId, localId, registration);
543
+ if (uid)
544
+ removeFrom(byUid, uid, registration);
545
+ };
546
+ }
547
+ /**
548
+ * Watches `watch` and runs `read` once per dispatch, handing its result to `onRows` when it differs
549
+ * from the last one handed over. A read that finishes after a newer one started is dropped, so an
550
+ * older result never replaces a newer one.
551
+ *
552
+ * Pass `since` (the `changeFeedCursor()` taken before the caller's own initial read) to run `read`
553
+ * once right away when the feed moved on in between: a change dispatched before this watch was
554
+ * registered would otherwise be missed. Pass `immediate` to run it once right away regardless, as
555
+ * a liveQuery's first emission does.
556
+ */
557
+ function watchEntityRows(watch, read, onRows, options = {}) {
558
+ let latest = 0;
559
+ let closed = false;
560
+ let lastJson;
561
+ const run = () => {
562
+ const token = ++latest;
563
+ read().then((rows) => {
564
+ if (closed || token !== latest)
565
+ return;
566
+ // Like BaseDb.liveQuery's distinctUntilChanged: a write that left these rows as they were
567
+ // (this entity's own write, read back) doesn't reach the handler again.
568
+ const json = JSON.stringify(rows);
569
+ if (json === lastJson)
570
+ return;
571
+ lastJson = json;
572
+ onRows(rows);
573
+ }, (error) => {
574
+ if (closed || token !== latest)
575
+ return;
576
+ if (options.onError)
577
+ options.onError(error);
578
+ else
579
+ logger('entity read failed', error);
580
+ });
581
+ };
582
+ const unregister = watchEntityChanges(watch, run);
583
+ if (options.immediate || (options.since !== undefined && cursor > options.since))
584
+ run();
585
+ return {
586
+ unsubscribe: () => {
587
+ closed = true;
588
+ unregister();
589
+ },
590
+ };
591
+ }
592
+ /**
593
+ * Runs an SQL-tag query once, the way BaseDb.liveQuery's query function is written
594
+ * (`(sql) => sql\`SELECT ...\``), so an entity can keep its liveQuery's text for its feed reads.
595
+ */
596
+ async function queryEntityRows(query) {
597
+ if (!feed)
598
+ throw new Error('The change feed has not started');
599
+ return (await query(feed.sql));
600
+ }
601
+ /** Whether this tab's feed runs (a browser database is open); Node has none. */
602
+ function isChangeFeedRunning() {
603
+ return feed !== undefined;
604
+ }
605
+ const callAll = (targets) => {
606
+ for (const registration of targets) {
607
+ try {
608
+ registration.listener();
609
+ }
610
+ catch (error) {
611
+ logger('listener threw', error);
612
+ }
613
+ }
614
+ };
615
+ const dispatch = (rows) => {
616
+ const targets = new Set();
617
+ for (const row of rows) {
618
+ const candidates = [
619
+ ...(row.seedLocalId ? byLocalId.get(row.seedLocalId) ?? [] : []),
620
+ ...(row.seedUid ? byUid.get(row.seedUid.toLowerCase()) ?? [] : []),
621
+ ];
622
+ for (const registration of candidates) {
623
+ if (!registration.tables.has(row.tbl))
624
+ continue;
625
+ if (row.tbl === 'metadata' &&
626
+ registration.propertyNames &&
627
+ row.propertyName != null &&
628
+ !registration.propertyNames.has(row.propertyName)) {
629
+ continue;
630
+ }
631
+ targets.add(registration);
632
+ }
633
+ }
634
+ callAll(targets);
635
+ };
636
+ const readNewRows = async (db) => {
637
+ const rows = await db
638
+ .select({
639
+ seq: entityChanges.seq,
640
+ tbl: entityChanges.tbl,
641
+ seedLocalId: entityChanges.seedLocalId,
642
+ seedUid: entityChanges.seedUid,
643
+ propertyName: entityChanges.propertyName,
644
+ })
645
+ .from(entityChanges)
646
+ .where(gt(entityChanges.seq, cursor))
647
+ .orderBy(entityChanges.seq);
648
+ if (feed?.db !== db || rows.length === 0)
649
+ return;
650
+ // Writers are serialized, so committed seqs have no holes: a missing first row was pruned.
651
+ const missed = rows[0].seq > cursor + 1;
652
+ cursor = rows[rows.length - 1].seq;
653
+ if (missed) {
654
+ logger(`cursor fell behind the log; notifying all ${registrations.size} watches`);
655
+ callAll([...registrations]);
656
+ }
657
+ else {
658
+ dispatch(rows);
659
+ }
660
+ await maybePrune(db);
661
+ };
662
+ const maybePrune = async (db) => {
663
+ const now = Date.now();
664
+ if (!isLeaderTab() || now - lastPrunedAt < ENTITY_CHANGES_PRUNE_EVERY_MS)
665
+ return;
666
+ lastPrunedAt = now;
667
+ try {
668
+ await pruneEntityChanges(db, now);
669
+ }
670
+ catch (error) {
671
+ logger('prune failed', error);
672
+ }
673
+ };
674
+ /** Deletes log rows older than ENTITY_CHANGES_RETENTION_MS. Deleting doesn't raise max(seq), so it dispatches nothing. */
675
+ async function pruneEntityChanges(db, now = Date.now()) {
676
+ await db.delete(entityChanges).where(lt(entityChanges.at, now - ENTITY_CHANGES_RETENTION_MS));
677
+ }
678
+ /** Reads once at a time; an emission during a read makes it read once more. */
679
+ const scheduleRead = (db) => {
680
+ if (reading) {
681
+ readAgain = true;
682
+ return;
683
+ }
684
+ reading = (async () => {
685
+ try {
686
+ do {
687
+ readAgain = false;
688
+ await readNewRows(db);
689
+ } while (readAgain && feed?.db === db);
690
+ }
691
+ catch (error) {
692
+ logger('read failed', error);
693
+ }
694
+ finally {
695
+ reading = undefined;
696
+ }
697
+ })();
698
+ };
699
+ /**
700
+ * Starts this tab's feed on `db` (once its migrations ran), at the newest seq allocated so far:
701
+ * entities do their own initial read. A second call replaces the first feed.
702
+ */
703
+ async function startChangeFeed(db, { liveQuery, sql: sqlTag }) {
704
+ stopChangeFeed();
705
+ // sqlite_sequence keeps the last seq even when pruning emptied the table.
706
+ const [row] = await db.all(sql `SELECT seq FROM sqlite_sequence WHERE name = 'entity_changes'`);
707
+ cursor = Number(row?.seq ?? 0);
708
+ const subscription = liveQuery((tag) => tag `SELECT max(seq) AS seq FROM entity_changes`).subscribe({
709
+ next: ([latest]) => {
710
+ if (latest?.seq != null && Number(latest.seq) > cursor)
711
+ scheduleRead(db);
712
+ },
713
+ error: (error) => logger('feed query failed', error),
714
+ });
715
+ feed = { db, sql: sqlTag, unsubscribe: () => subscription.unsubscribe() };
716
+ logger(`started at seq ${cursor}`);
717
+ }
718
+ function stopChangeFeed() {
719
+ feed?.unsubscribe();
720
+ feed = undefined;
721
+ readAgain = false;
722
+ }
723
+
724
+ export { ADDRESSES_PERSISTED_EVENT as A, timed as B, revokeSessionObjectUrl as C, queryEntityRows as D, isSessionObjectUrl as E, FILES_CHANGED_EVENT as F, timedDb as G, tabEvents as H, LOCAL_COPIES_REMOVED_EVENT as L, TabLockTimeoutError as T, isLeaderTab as a, watchEntityRows as b, whenLeaderTab as c, withDbTabLock as d, emitAcrossTabs as e, createSessionObjectUrl as f, withSeedDbLock as g, countDbStatements as h, isChangeFeedRunning as i, countLiveQueryRuns as j, postTabMessage as k, listenForOtherTabsEvents as l, startTabCoordination as m, notifyFilesWrittenOutsideCache as n, onTabMessage as o, parseAddressesPersistedPayload as p, tryWithTabLock as q, withTabLock as r, startChangeFeed as s, timingMarks as t, notifyFileSaved as u, timingNow as v, watchEntityChanges as w, timingSince as x, timingLogger as y, TAB_ID as z };
725
+ //# sourceMappingURL=changeFeed-DcsZ7deG.js.map