@seedprotocol/sdk 0.7.8-next.1034.g2acd2a2 → 0.7.8-next.1071.g2a141c1
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.
- package/dist/{ClientManager-DBKvmJov.js → ClientManager-Bv15o3Oz.js} +806 -79
- package/dist/ClientManager-Bv15o3Oz.js.map +1 -0
- package/dist/{Item-BiMHgg-_.js → Item-tX3kpbj4.js} +1704 -939
- package/dist/Item-tX3kpbj4.js.map +1 -0
- package/dist/{ModelProperty-C1Fzcnbm.js → ModelProperty-N-3gBfu5.js} +37 -37
- package/dist/{ModelProperty-C1Fzcnbm.js.map → ModelProperty-N-3gBfu5.js.map} +1 -1
- package/dist/{Schema-COTbavcm.js → Schema-CY3OxwKS.js} +44 -44
- package/dist/{Schema-COTbavcm.js.map → Schema-CY3OxwKS.js.map} +1 -1
- package/dist/{SchemaValidationService-paOfbcwd.js → SchemaValidationService-BR2ABK2r.js} +6 -6
- package/dist/{SchemaValidationService-paOfbcwd.js.map → SchemaValidationService-BR2ABK2r.js.map} +1 -1
- package/dist/{backfillMetadataPropertyIds-BkpBahbz.js → backfillMetadataPropertyIds-vc_1RoDT.js} +3 -3
- package/dist/{backfillMetadataPropertyIds-BkpBahbz.js.map → backfillMetadataPropertyIds-vc_1RoDT.js.map} +1 -1
- package/dist/{configurePlatform-_XR45RnJ.js → configurePlatform-D-Pj9gTx.js} +2 -2
- package/dist/{configurePlatform-_XR45RnJ.js.map → configurePlatform-D-Pj9gTx.js.map} +1 -1
- package/dist/db/drizzle/0020_add_pending_writes.sql +24 -0
- package/dist/db/drizzle/0021_add_pending_write_error_name.sql +1 -0
- package/dist/db/drizzle/meta/0020_snapshot.json +1542 -0
- package/dist/db/drizzle/meta/0021_snapshot.json +1549 -0
- package/dist/db/drizzle/meta/_journal.json +14 -0
- package/dist/{detachRowsBeforeDelete-C1iapUFl.js → detachRowsBeforeDelete-sK1ye2W6.js} +2 -2
- package/dist/{detachRowsBeforeDelete-C1iapUFl.js.map → detachRowsBeforeDelete-sK1ye2W6.js.map} +1 -1
- package/dist/dist/{ClientManager-DBKvmJov.d.ts → ClientManager-Bv15o3Oz.d.ts} +375 -293
- package/dist/dist/ClientManager-Bv15o3Oz.d.ts.map +1 -0
- package/dist/dist/{Item-BiMHgg-_.d.ts → Item-tX3kpbj4.d.ts} +434 -305
- package/dist/dist/Item-tX3kpbj4.d.ts.map +1 -0
- package/dist/dist/{ModelProperty-C1Fzcnbm.d.ts → ModelProperty-N-3gBfu5.d.ts} +1 -1
- package/dist/dist/{ModelProperty-C1Fzcnbm.d.ts.map → ModelProperty-N-3gBfu5.d.ts.map} +1 -1
- package/dist/dist/{Schema-COTbavcm.d.ts → Schema-CY3OxwKS.d.ts} +2 -2
- package/dist/dist/{Schema-COTbavcm.d.ts.map → Schema-CY3OxwKS.d.ts.map} +1 -1
- package/dist/dist/{SchemaValidationService-paOfbcwd.d.ts → SchemaValidationService-BR2ABK2r.d.ts} +1 -1
- package/dist/dist/{SchemaValidationService-paOfbcwd.d.ts.map → SchemaValidationService-BR2ABK2r.d.ts.map} +1 -1
- package/dist/dist/{backfillMetadataPropertyIds-BkpBahbz.d.ts → backfillMetadataPropertyIds-vc_1RoDT.d.ts} +1 -1
- package/dist/dist/backfillMetadataPropertyIds-vc_1RoDT.d.ts.map +1 -0
- package/dist/dist/{configurePlatform-_XR45RnJ.d.ts → configurePlatform-D-Pj9gTx.d.ts} +1 -1
- package/dist/dist/configurePlatform-D-Pj9gTx.d.ts.map +1 -0
- package/dist/dist/{detachRowsBeforeDelete-C1iapUFl.d.ts → detachRowsBeforeDelete-sK1ye2W6.d.ts} +1 -1
- package/dist/dist/detachRowsBeforeDelete-sK1ye2W6.d.ts.map +1 -0
- package/dist/dist/{eas-BRVEGT97.d.ts → eas-BSQxj7gN.d.ts} +1 -1
- package/dist/dist/eas-BSQxj7gN.d.ts.map +1 -0
- package/dist/dist/{errors-CQagdED2.d.ts → errors-a4Tj6hly.d.ts} +1 -1
- package/dist/dist/{errors-CQagdED2.d.ts.map → errors-a4Tj6hly.d.ts.map} +1 -1
- package/dist/dist/{getItem-Jpr1SKIL.d.ts → getItem-Ctps9gSs.d.ts} +1 -1
- package/dist/dist/getItem-Ctps9gSs.d.ts.map +1 -0
- package/dist/dist/{getPublishPayload-Bmeqtq4l.d.ts → getPublishPayload-C2g5pPD2.d.ts} +1 -1
- package/dist/dist/getPublishPayload-C2g5pPD2.d.ts.map +1 -0
- package/dist/dist/{getPublishUploads-7nW1kMZV.d.ts → getPublishUploads-CaJHy3SL.d.ts} +1 -1
- package/dist/dist/{getPublishUploads-7nW1kMZV.d.ts.map → getPublishUploads-CaJHy3SL.d.ts.map} +1 -1
- package/dist/dist/{index-3_hGVu7v.d.ts → index-B6hPWSM4.d.ts} +378 -1
- package/dist/dist/{index-3_hGVu7v.d.ts.map → index-B6hPWSM4.d.ts.map} +1 -1
- package/dist/dist/index-BgEwcREa.d.ts +14 -0
- package/dist/dist/index-BgEwcREa.d.ts.map +1 -0
- package/dist/dist/{index-DM3zrNtX.d.ts → index-bOwhhJJL.d.ts} +5 -5
- package/dist/dist/index-bOwhhJJL.d.ts.map +1 -0
- package/dist/dist/{index-C-NqjjY_.d.ts → index-s73wD_LC.d.ts} +837 -433
- package/dist/dist/index-s73wD_LC.d.ts.map +1 -0
- package/dist/dist/{index.browser-DGoOSs1J.d.ts → index.browser-C7iZp7mx.d.ts} +2892 -1754
- package/dist/dist/{index.browser-DGoOSs1J.d.ts.map → index.browser-C7iZp7mx.d.ts.map} +1 -1
- package/dist/dist/{index.node-CTv62R2a.d.ts → index.node-MPVTJR2J.d.ts} +4125 -2613
- package/dist/dist/{index.node-CTv62R2a.d.ts.map → index.node-MPVTJR2J.d.ts.map} +1 -1
- package/dist/dist/platform.browser.d.ts +2 -2
- package/dist/dist/platform.node.d.ts +2 -2
- package/dist/dist/{property-DaUy4XMe.d.ts → property-mP9mOZ2L.d.ts} +3 -3
- package/dist/dist/property-mP9mOZ2L.d.ts.map +1 -0
- package/dist/dist/{propertyValidationRules-DbbWvBzj.d.ts → propertyValidationRules-DwzrYA7c.d.ts} +1 -1
- package/dist/dist/propertyValidationRules-DwzrYA7c.d.ts.map +1 -0
- package/dist/dist/{publishDraftGraph-CCa6EzeO.d.ts → publishDraftGraph-BzYVblZZ.d.ts} +1 -1
- package/dist/dist/{publishDraftGraph-CCa6EzeO.d.ts.map → publishDraftGraph-BzYVblZZ.d.ts.map} +1 -1
- package/dist/dist/{resetAmbiguousLegacyItemData--PN1v53N.d.ts → resetAmbiguousLegacyItemData-B_IUQA09.d.ts} +1 -1
- package/dist/dist/resetAmbiguousLegacyItemData-B_IUQA09.d.ts.map +1 -0
- package/dist/dist/{resolveModelForSyncedSeed-VDzkS6Rs.d.ts → resolveModelForSyncedSeed-H-4tmU6l.d.ts} +1 -1
- package/dist/dist/resolveModelForSyncedSeed-H-4tmU6l.d.ts.map +1 -0
- package/dist/dist/{syncDbWithEas-D0gyJ58h.d.ts → syncDbWithEas-y5VF623G.d.ts} +1 -1
- package/dist/dist/syncDbWithEas-y5VF623G.d.ts.map +1 -0
- package/dist/dist/{tabEvents-UH-wNsZC.d.ts → tabEvents-BuorBItJ.d.ts} +31 -17
- package/dist/dist/tabEvents-BuorBItJ.d.ts.map +1 -0
- package/dist/dist/{tolerantWebAccess-CpcTCAZv.d.ts → tolerantWebAccess-DoI7QYT-.d.ts} +1 -1
- package/dist/dist/{tolerantWebAccess-CpcTCAZv.d.ts.map → tolerantWebAccess-DoI7QYT-.d.ts.map} +1 -1
- package/dist/dist/{updateSeedRevokedAt-D230zfWk.d.ts → updateSeedRevokedAt-BIzkbsUd.d.ts} +1 -1
- package/dist/dist/updateSeedRevokedAt-BIzkbsUd.d.ts.map +1 -0
- package/dist/{eas-BRVEGT97.js → eas-BSQxj7gN.js} +3 -3
- package/dist/{eas-BRVEGT97.js.map → eas-BSQxj7gN.js.map} +1 -1
- package/dist/{errors-CQagdED2.js → errors-a4Tj6hly.js} +35 -35
- package/dist/{errors-CQagdED2.js.map → errors-a4Tj6hly.js.map} +1 -1
- package/dist/{getItem-Jpr1SKIL.js → getItem-Ctps9gSs.js} +5 -5
- package/dist/{getItem-Jpr1SKIL.js.map → getItem-Ctps9gSs.js.map} +1 -1
- package/dist/{getPublishPayload-Bmeqtq4l.js → getPublishPayload-C2g5pPD2.js} +17 -14
- package/dist/getPublishPayload-C2g5pPD2.js.map +1 -0
- package/dist/{getPublishUploads-7nW1kMZV.js → getPublishUploads-CaJHy3SL.js} +9 -6
- package/dist/getPublishUploads-CaJHy3SL.js.map +1 -0
- package/dist/{index-3_hGVu7v.js → index-B6hPWSM4.js} +3 -2
- package/dist/index-B6hPWSM4.js.map +1 -0
- package/dist/index-BgEwcREa.js +28 -0
- package/dist/index-BgEwcREa.js.map +1 -0
- package/dist/{index-DM3zrNtX.js → index-bOwhhJJL.js} +8 -8
- package/dist/index-bOwhhJJL.js.map +1 -0
- package/dist/{index-C-NqjjY_.js → index-s73wD_LC.js} +117 -9
- package/dist/index-s73wD_LC.js.map +1 -0
- package/dist/{index.browser-DGoOSs1J.js → index.browser-C7iZp7mx.js} +267 -65
- package/dist/index.browser-C7iZp7mx.js.map +1 -0
- package/dist/{index.node-CTv62R2a.js → index.node-MPVTJR2J.js} +93 -6
- package/dist/index.node-MPVTJR2J.js.map +1 -0
- package/dist/main.js +84 -26
- package/dist/main.js.map +1 -1
- package/dist/node.js +11 -11
- package/dist/platform.browser.js +5 -5
- package/dist/platform.node.js +4 -4
- package/dist/{property-DaUy4XMe.js → property-mP9mOZ2L.js} +7 -7
- package/dist/{property-DaUy4XMe.js.map → property-mP9mOZ2L.js.map} +1 -1
- package/dist/{propertyValidationRules-DbbWvBzj.js → propertyValidationRules-DwzrYA7c.js} +10 -10
- package/dist/{propertyValidationRules-DbbWvBzj.js.map → propertyValidationRules-DwzrYA7c.js.map} +1 -1
- package/dist/{publishDraftGraph-CCa6EzeO.js → publishDraftGraph-BzYVblZZ.js} +6 -6
- package/dist/{publishDraftGraph-CCa6EzeO.js.map → publishDraftGraph-BzYVblZZ.js.map} +1 -1
- package/dist/{resetAmbiguousLegacyItemData--PN1v53N.js → resetAmbiguousLegacyItemData-B_IUQA09.js} +2 -2
- package/dist/{resetAmbiguousLegacyItemData--PN1v53N.js.map → resetAmbiguousLegacyItemData-B_IUQA09.js.map} +1 -1
- package/dist/{resolveModelForSyncedSeed-VDzkS6Rs.js → resolveModelForSyncedSeed-H-4tmU6l.js} +2 -2
- package/dist/{resolveModelForSyncedSeed-VDzkS6Rs.js.map → resolveModelForSyncedSeed-H-4tmU6l.js.map} +1 -1
- package/dist/seedSchema/PendingWriteSchema.ts +57 -0
- package/dist/seedSchema/index.ts +1 -0
- package/dist/src/Item/Item.d.ts +15 -1
- package/dist/src/Item/Item.d.ts.map +1 -1
- package/dist/src/ItemProperty/ItemProperty.d.ts +28 -3
- package/dist/src/ItemProperty/ItemProperty.d.ts.map +1 -1
- package/dist/src/ItemProperty/service/actors/hydrateFromDb.d.ts.map +1 -1
- package/dist/src/ItemProperty/service/actors/loadOrCreateProperty.d.ts.map +1 -1
- package/dist/src/ItemProperty/service/actors/saveValueToDb/analyzeInput.d.ts.map +1 -1
- package/dist/src/ItemProperty/service/actors/saveValueToDb/saveFile.d.ts.map +1 -1
- package/dist/src/ItemProperty/service/actors/saveValueToDb/saveHtml.d.ts.map +1 -1
- package/dist/src/ItemProperty/service/actors/saveValueToDb/saveImage.d.ts.map +1 -1
- package/dist/src/ItemProperty/service/actors/saveValueToDb/saveItemStorage.d.ts +5 -0
- package/dist/src/ItemProperty/service/actors/saveValueToDb/saveItemStorage.d.ts.map +1 -1
- package/dist/src/ItemProperty/service/actors/saveValueToDb/storageValue.d.ts +22 -0
- package/dist/src/ItemProperty/service/actors/saveValueToDb/storageValue.d.ts.map +1 -0
- package/dist/src/browser/db/Db.d.ts +7 -0
- package/dist/src/browser/db/Db.d.ts.map +1 -1
- package/dist/src/browser/db/drizzleFiles.d.ts +4 -2
- package/dist/src/browser/db/drizzleFiles.d.ts.map +1 -1
- package/dist/src/browser/db/sqliteBusyRetry.d.ts.map +1 -1
- package/dist/src/browser/helpers/EasClient.d.ts +1 -1
- package/dist/src/browser/helpers/EasClient.d.ts.map +1 -1
- package/dist/src/client/ClientManager.d.ts.map +1 -1
- package/dist/src/client/actors/saveConfig.d.ts.map +1 -1
- package/dist/src/client/addressesPersisted.d.ts +10 -0
- package/dist/src/client/addressesPersisted.d.ts.map +1 -0
- package/dist/src/client/clientManagerMachine.d.ts.map +1 -1
- package/dist/src/db/Db/BaseDb.d.ts +10 -0
- package/dist/src/db/Db/BaseDb.d.ts.map +1 -1
- package/dist/src/db/read/getItemProperties.d.ts.map +1 -1
- package/dist/src/db/read/getPublishPayload.d.ts.map +1 -1
- package/dist/src/db/read/getPublishUploads.d.ts.map +1 -1
- package/dist/src/db/read/getSeedData.d.ts +4 -1
- package/dist/src/db/read/getSeedData.d.ts.map +1 -1
- package/dist/src/db/read/getSeedPublisher.d.ts +4 -1
- package/dist/src/db/read/getSeedPublisher.d.ts.map +1 -1
- package/dist/src/db/read/getVersionData.d.ts +4 -1
- package/dist/src/db/read/getVersionData.d.ts.map +1 -1
- package/dist/src/db/write/claimUnpublishedDrafts.d.ts +6 -0
- package/dist/src/db/write/claimUnpublishedDrafts.d.ts.map +1 -1
- package/dist/src/db/write/createMetadata.d.ts +13 -0
- package/dist/src/db/write/createMetadata.d.ts.map +1 -1
- package/dist/src/db/write/createNewItem.d.ts +5 -0
- package/dist/src/db/write/createNewItem.d.ts.map +1 -1
- package/dist/src/db/write/createSeed.d.ts +20 -1
- package/dist/src/db/write/createSeed.d.ts.map +1 -1
- package/dist/src/db/write/createVersion.d.ts +5 -1
- package/dist/src/db/write/createVersion.d.ts.map +1 -1
- package/dist/src/db/write/removeLocalCopiesForAddresses.d.ts +9 -2
- package/dist/src/db/write/removeLocalCopiesForAddresses.d.ts.map +1 -1
- package/dist/src/db/write/updateItemPropertyValue.d.ts +9 -1
- package/dist/src/db/write/updateItemPropertyValue.d.ts.map +1 -1
- package/dist/src/db/write/updateMetadata.d.ts +8 -1
- package/dist/src/db/write/updateMetadata.d.ts.map +1 -1
- package/dist/src/events/item/syncDbWithEas.d.ts.map +1 -1
- package/dist/src/helpers/db.d.ts +4 -2
- package/dist/src/helpers/db.d.ts.map +1 -1
- package/dist/src/helpers/entity/entityDestroy.d.ts +1 -1
- package/dist/src/helpers/entity/entityDestroy.d.ts.map +1 -1
- package/dist/src/helpers/itemStorageFile.d.ts +7 -0
- package/dist/src/helpers/itemStorageFile.d.ts.map +1 -1
- package/dist/src/helpers/propertySchemaUid.d.ts +13 -0
- package/dist/src/helpers/propertySchemaUid.d.ts.map +1 -0
- package/dist/src/helpers/propertyWriteTickets.d.ts +11 -0
- package/dist/src/helpers/propertyWriteTickets.d.ts.map +1 -0
- package/dist/src/helpers/tabCoordinator.d.ts +9 -0
- package/dist/src/helpers/tabCoordinator.d.ts.map +1 -1
- package/dist/src/helpers/tabLocks.d.ts +11 -0
- package/dist/src/helpers/tabLocks.d.ts.map +1 -1
- package/dist/src/helpers/timing.d.ts +10 -0
- package/dist/src/helpers/timing.d.ts.map +1 -0
- package/dist/src/index.d.ts +1 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/interfaces/IDb.d.ts +2 -0
- package/dist/src/interfaces/IDb.d.ts.map +1 -1
- package/dist/src/interfaces/IItem.d.ts +1 -0
- package/dist/src/interfaces/IItem.d.ts.map +1 -1
- package/dist/src/interfaces/IItemProperty.d.ts +5 -0
- package/dist/src/interfaces/IItemProperty.d.ts.map +1 -1
- package/dist/src/node/db/Db.d.ts +3 -0
- package/dist/src/node/db/Db.d.ts.map +1 -1
- package/dist/src/node/db/singleConnectionTransactions.d.ts +22 -0
- package/dist/src/node/db/singleConnectionTransactions.d.ts.map +1 -0
- package/dist/src/outbox/conflicts.d.ts +60 -0
- package/dist/src/outbox/conflicts.d.ts.map +1 -0
- package/dist/src/outbox/index.d.ts +9 -0
- package/dist/src/outbox/index.d.ts.map +1 -0
- package/dist/src/outbox/itemAppliers.d.ts +153 -0
- package/dist/src/outbox/itemAppliers.d.ts.map +1 -0
- package/dist/src/outbox/outbox.d.ts +143 -0
- package/dist/src/outbox/outbox.d.ts.map +1 -0
- package/dist/src/outbox/pendingValues.d.ts +36 -0
- package/dist/src/outbox/pendingValues.d.ts.map +1 -0
- package/dist/src/seedSchema/PendingWriteSchema.d.ts +385 -0
- package/dist/src/seedSchema/PendingWriteSchema.d.ts.map +1 -0
- package/dist/src/seedSchema/index.d.ts +1 -0
- package/dist/src/seedSchema/index.d.ts.map +1 -1
- package/dist/src/types/property.d.ts +5 -0
- package/dist/src/types/property.d.ts.map +1 -1
- package/dist/{syncDbWithEas-D0gyJ58h.js → syncDbWithEas-y5VF623G.js} +20 -15
- package/dist/syncDbWithEas-y5VF623G.js.map +1 -0
- package/dist/{tabEvents-UH-wNsZC.js → tabEvents-BuorBItJ.js} +56 -42
- package/dist/tabEvents-BuorBItJ.js.map +1 -0
- package/dist/{tolerantWebAccess-CpcTCAZv.js → tolerantWebAccess-DoI7QYT-.js} +6 -6
- package/dist/{tolerantWebAccess-CpcTCAZv.js.map → tolerantWebAccess-DoI7QYT-.js.map} +1 -1
- package/dist/{updateSeedRevokedAt-D230zfWk.js → updateSeedRevokedAt-BIzkbsUd.js} +3 -3
- package/dist/{updateSeedRevokedAt-D230zfWk.js.map → updateSeedRevokedAt-BIzkbsUd.js.map} +1 -1
- package/package.json +7 -7
- package/dist/ClientManager-DBKvmJov.js.map +0 -1
- package/dist/Item-BiMHgg-_.js.map +0 -1
- package/dist/discardNewDraft-D4nrwp3T.js +0 -78
- package/dist/discardNewDraft-D4nrwp3T.js.map +0 -1
- package/dist/dist/ClientManager-DBKvmJov.d.ts.map +0 -1
- package/dist/dist/Item-BiMHgg-_.d.ts.map +0 -1
- package/dist/dist/backfillMetadataPropertyIds-BkpBahbz.d.ts.map +0 -1
- package/dist/dist/configurePlatform-_XR45RnJ.d.ts.map +0 -1
- package/dist/dist/detachRowsBeforeDelete-C1iapUFl.d.ts.map +0 -1
- package/dist/dist/discardNewDraft-D4nrwp3T.d.ts +0 -8
- package/dist/dist/discardNewDraft-D4nrwp3T.d.ts.map +0 -1
- package/dist/dist/eas-BRVEGT97.d.ts.map +0 -1
- package/dist/dist/getItem-Jpr1SKIL.d.ts.map +0 -1
- package/dist/dist/getPublishPayload-Bmeqtq4l.d.ts.map +0 -1
- package/dist/dist/index-C-NqjjY_.d.ts.map +0 -1
- package/dist/dist/index-DM3zrNtX.d.ts.map +0 -1
- package/dist/dist/property-DaUy4XMe.d.ts.map +0 -1
- package/dist/dist/propertyValidationRules-DbbWvBzj.d.ts.map +0 -1
- package/dist/dist/resetAmbiguousLegacyItemData--PN1v53N.d.ts.map +0 -1
- package/dist/dist/resolveModelForSyncedSeed-VDzkS6Rs.d.ts.map +0 -1
- package/dist/dist/syncDbWithEas-D0gyJ58h.d.ts.map +0 -1
- package/dist/dist/tabEvents-UH-wNsZC.d.ts.map +0 -1
- package/dist/dist/updateSeedRevokedAt-D230zfWk.d.ts.map +0 -1
- package/dist/getPublishPayload-Bmeqtq4l.js.map +0 -1
- package/dist/getPublishUploads-7nW1kMZV.js.map +0 -1
- package/dist/index-3_hGVu7v.js.map +0 -1
- package/dist/index-C-NqjjY_.js.map +0 -1
- package/dist/index-DM3zrNtX.js.map +0 -1
- package/dist/index.browser-DGoOSs1J.js.map +0 -1
- package/dist/index.node-CTv62R2a.js.map +0 -1
- package/dist/src/db/write/discardNewDraft.d.ts +0 -8
- package/dist/src/db/write/discardNewDraft.d.ts.map +0 -1
- package/dist/src/helpers/propertyWriteQueue.d.ts +0 -15
- package/dist/src/helpers/propertyWriteQueue.d.ts.map +0 -1
- package/dist/syncDbWithEas-D0gyJ58h.js.map +0 -1
- package/dist/tabEvents-UH-wNsZC.js.map +0 -1
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { startCase, isEqual } from 'lodash-es';
|
|
2
|
-
import {
|
|
2
|
+
import { F as BaseDb, l as easSyncProcesses, I as eventEmitter, am as isBrowser, a2 as isNode, aG as normalizeAddressConfig, aU as isTestOrSeedDev, h as appState, aV as downloadAllFilesRequestHandler, aW as downloadAllFilesBinaryRequestHandler, N as BaseFileManager, af as loadNameMatchLevels, s as models$1, r as modelUids, B as seeds, aH as normalizeAddressList, A as schemas, aR as loadModelsFromDbForSchema, aO as addSchemaToDb, aL as isInternalSchema, ai as generateId, aT as clearNameMatchLevels, aX as warnOnInvalidNameMatch, aY as INTERNAL_SCHEMA_IDS, aZ as linkModelToSchema, n as normalizeDataType, ac as easPropertyNameForPublish, aw as SEED_PROTOCOL_SCHEMA_NAME, q as modelSchemas, a0 as getItemStorageSubdir, a1 as getItemStorageLocalFileName, m as metadata$1, v as properties, L as resolveItemModelFileId, E as versions, ad as normalizePublisher, u as pendingWrites, a_ as getMetadataPropertyNamesForQuery, o as htmlEmbeddedImageCoPublish, j as arweaveL1FinalizeJobs, z as publishProcesses, a$ as getWatchedAddressesFromDb, b0 as getOwnedAddressesFromDb, b1 as CLIENT_NOT_INITIALIZED } from './index-s73wD_LC.js';
|
|
3
3
|
import debug from 'debug';
|
|
4
4
|
import { createActor, setup, assign, fromPromise, fromCallback, waitFor } from 'xstate';
|
|
5
|
-
import {
|
|
6
|
-
import { eq, inArray, and, isNotNull, ne, desc, countDistinct, isNull, or, sql, like } from 'drizzle-orm';
|
|
7
|
-
import { a as withDbTabLock, i as isLeaderTab, d as postTabMessage, o as onTabMessage, w as whenLeaderTab, l as listenForOtherTabsEvents, s as startTabCoordination, b as withSeedDbLock, e as emitAcrossTabs, A as ADDRESSES_PERSISTED_EVENT, p as parseAddressesPersistedPayload, L as LOCAL_COPIES_REMOVED_EVENT } from './tabEvents-
|
|
5
|
+
import { Y as MachineIds, an as ClientManagerEvents, D as compareMetadataRowsLatestFirst, u as writeInBatches, ao as resolvePublisherFromSeedRow, ap as getSeedPublisher, aq as propertyNameVariants, M as METADATA_LATEST_FIRST_ORDER_SQL, L as selectInBatches, ar as createSeed, as as createMetadata, at as updateItemPropertyValue, s as registerOutboxApplier, q as outboxOpValue, i as OutboxOpDeferredError, t as startOutbox, j as OutboxOpFailedError, z as OwnershipError, B as isItemOwned, G as parseListPropertyValueFromStorage, X as ClientManagerState, a5 as isLocalUnsealedDraft, I as Item } from './Item-tX3kpbj4.js';
|
|
6
|
+
import { eq, inArray, and, isNotNull, ne, desc, countDistinct, isNull, or, sql, like, lt } from 'drizzle-orm';
|
|
7
|
+
import { a as withDbTabLock, i as isLeaderTab, d as postTabMessage, o as onTabMessage, w as whenLeaderTab, l as listenForOtherTabsEvents, s as startTabCoordination, b as withSeedDbLock, e as emitAcrossTabs, A as ADDRESSES_PERSISTED_EVENT, t as tryWithTabLock, f as withTabLock, g as notifyFileSaved, p as parseAddressesPersistedPayload, L as LOCAL_COPIES_REMOVED_EVENT } from './tabEvents-BuorBItJ.js';
|
|
8
8
|
import { seedGatewayConfigFromSeedConfig, setPreferredArweaveReadBaseUrls, resolveSeedGatewayEndpoints, setResolvedSeedGatewayEndpoints, BaseArweaveClient, ensureReadGatewaySelected, DEFAULT_ARWEAVE_HOST } from '@seedprotocol/arweave';
|
|
9
9
|
import { configureEasReadChain, easName, BaseQueryClient, BaseEasClient, GET_SCHEMAS, whenEasReadChainSettled, getEasReadChainId, DEFAULT_EAS_CHAIN_ID, isEasReadChainConfigured, isPlaceholderUid, localNamesInBestMatchTier, isValidEasAttestationUid } from '@seedprotocol/eas';
|
|
10
10
|
import 'pluralize';
|
|
@@ -212,7 +212,7 @@ function toRunSyncArg(options) {
|
|
|
212
212
|
return undefined;
|
|
213
213
|
}
|
|
214
214
|
const runEasSync = fromPromise(async ({ input, }) => {
|
|
215
|
-
const { runSyncFromEas } = await import('./syncDbWithEas-
|
|
215
|
+
const { runSyncFromEas } = await import('./syncDbWithEas-y5VF623G.js');
|
|
216
216
|
// Sync checks for rows and then inserts the rest (no unique index on uids), so syncs in
|
|
217
217
|
// different tabs take turns. A sync can run for minutes, so wait without a timeout.
|
|
218
218
|
await withDbTabLock('eas-sync', async () => {
|
|
@@ -590,7 +590,7 @@ const platformClassesInit = fromCallback(({ sendBack, input: { context, event }
|
|
|
590
590
|
if (!config) {
|
|
591
591
|
throw new Error('client.init requires a config');
|
|
592
592
|
}
|
|
593
|
-
const _mod_0 = await import('./configurePlatform-
|
|
593
|
+
const _mod_0 = await import('./configurePlatform-D-Pj9gTx.js');
|
|
594
594
|
const _ns_0 = _mod_0.a;
|
|
595
595
|
const { configurePlatform } = _ns_0;
|
|
596
596
|
if (isBrowser()) {
|
|
@@ -1141,6 +1141,29 @@ async function assertLocalDbChain() {
|
|
|
1141
1141
|
configureEasReadChain('localDb', { chainId: localChainId ?? chainId });
|
|
1142
1142
|
}
|
|
1143
1143
|
|
|
1144
|
+
/** The addresses this tab last announced, as a comparable key. Cleared when the client stops. */
|
|
1145
|
+
let lastAnnounced;
|
|
1146
|
+
const addressKey = ({ owned, watched }) => {
|
|
1147
|
+
const norm = (list) => [...new Set(list.map((a) => a.trim().toLowerCase()))].sort();
|
|
1148
|
+
return JSON.stringify({ owned: norm(owned), watched: norm(watched) });
|
|
1149
|
+
};
|
|
1150
|
+
/**
|
|
1151
|
+
* Emits ADDRESSES_PERSISTED_EVENT when the stored addresses differ from the ones this tab last
|
|
1152
|
+
* announced. Listeners re-key their queries on it (React's `useItems` reloads its list from
|
|
1153
|
+
* scratch), and wallets save the same addresses on every connect.
|
|
1154
|
+
*/
|
|
1155
|
+
function announceAddressesPersisted(payload) {
|
|
1156
|
+
const key = addressKey(payload);
|
|
1157
|
+
if (key === lastAnnounced)
|
|
1158
|
+
return;
|
|
1159
|
+
lastAnnounced = key;
|
|
1160
|
+
emitAcrossTabs(ADDRESSES_PERSISTED_EVENT, payload);
|
|
1161
|
+
}
|
|
1162
|
+
/** Forgets the last announcement, so the next client's first save is announced. */
|
|
1163
|
+
function resetAddressesPersistedAnnouncement() {
|
|
1164
|
+
lastAnnounced = undefined;
|
|
1165
|
+
}
|
|
1166
|
+
|
|
1144
1167
|
const logger$9 = debug('seedSdk:client:actors:saveConfig');
|
|
1145
1168
|
let warnedKeptStoredAddresses = false;
|
|
1146
1169
|
/**
|
|
@@ -1179,7 +1202,7 @@ async function persistInitAddresses(appDb, { addresses, addressesProvided, owned
|
|
|
1179
1202
|
.onConflictDoUpdate({ target: appState.key, set: { value } });
|
|
1180
1203
|
// Same event setAddresses emits, so listeners (e.g. React's session context) also see the
|
|
1181
1204
|
// addresses init saved. Their sync is init's startup sync, which reads them from the DB.
|
|
1182
|
-
|
|
1205
|
+
announceAddressesPersisted({ owned, watched });
|
|
1183
1206
|
}
|
|
1184
1207
|
const saveConfig = fromCallback(({ sendBack, input: { context } }) => {
|
|
1185
1208
|
logger$9('saveConfig starting');
|
|
@@ -1980,8 +2003,8 @@ function getRefValueType(prop) {
|
|
|
1980
2003
|
* @returns Promise that resolves when properties are found, or rejects if not found after max retries
|
|
1981
2004
|
*/
|
|
1982
2005
|
const verifyPropertiesPersisted = async (db, modelId, modelName, maxRetries = 10, retryDelay = 100) => {
|
|
1983
|
-
const _mod_1 = await import('./index-
|
|
1984
|
-
const _ns_1 = _mod_1.
|
|
2006
|
+
const _mod_1 = await import('./index-s73wD_LC.js');
|
|
2007
|
+
const _ns_1 = _mod_1.bh;
|
|
1985
2008
|
const modelSchemaMod = _ns_1;
|
|
1986
2009
|
const { properties: propertiesTable } = modelSchemaMod;
|
|
1987
2010
|
const drizzleMod = await import('drizzle-orm');
|
|
@@ -2387,8 +2410,8 @@ async function importSchema(importFilePathOrContents, version, options) {
|
|
|
2387
2410
|
// Check DB for existing schema by name+version (same as minimal path)
|
|
2388
2411
|
const db = BaseDb.getAppDb();
|
|
2389
2412
|
if (db) {
|
|
2390
|
-
const _mod_2 = await import('./index-
|
|
2391
|
-
const _ns_2 = _mod_2.
|
|
2413
|
+
const _mod_2 = await import('./index-s73wD_LC.js');
|
|
2414
|
+
const _ns_2 = _mod_2.bj;
|
|
2392
2415
|
const schemaSchemaMod = _ns_2;
|
|
2393
2416
|
const { schemas: schemasTable } = schemaSchemaMod;
|
|
2394
2417
|
const drizzleMod = await import('drizzle-orm');
|
|
@@ -2479,8 +2502,8 @@ async function importSchema(importFilePathOrContents, version, options) {
|
|
|
2479
2502
|
// For minimal imports: check DB for existing schema before creating new file
|
|
2480
2503
|
const db = BaseDb.getAppDb();
|
|
2481
2504
|
if (db) {
|
|
2482
|
-
const _mod_3 = await import('./index-
|
|
2483
|
-
const _ns_3 = _mod_3.
|
|
2505
|
+
const _mod_3 = await import('./index-s73wD_LC.js');
|
|
2506
|
+
const _ns_3 = _mod_3.bj;
|
|
2484
2507
|
const schemaSchemaMod = _ns_3;
|
|
2485
2508
|
const { schemas: schemasTable } = schemaSchemaMod;
|
|
2486
2509
|
const drizzleMod = await import('drizzle-orm');
|
|
@@ -2662,8 +2685,8 @@ async function importSchema(importFilePathOrContents, version, options) {
|
|
|
2662
2685
|
updatedAt: new Date(schemaFile.metadata.updatedAt).getTime(),
|
|
2663
2686
|
};
|
|
2664
2687
|
// Use dynamic import to break circular dependency
|
|
2665
|
-
const _mod_4 = await import('./index-
|
|
2666
|
-
const _ns_4 = _mod_4.
|
|
2688
|
+
const _mod_4 = await import('./index-s73wD_LC.js');
|
|
2689
|
+
const _ns_4 = _mod_4.bm;
|
|
2667
2690
|
const dbMod = _ns_4;
|
|
2668
2691
|
const { addSchemaToDb, addModelsToDb } = dbMod;
|
|
2669
2692
|
// Try to add schema and models to database if database is available
|
|
@@ -2684,12 +2707,12 @@ async function importSchema(importFilePathOrContents, version, options) {
|
|
|
2684
2707
|
});
|
|
2685
2708
|
// Verify expected models are linked (single attempt - addModelsToDb already confirmed)
|
|
2686
2709
|
const expectedModelNames = Object.keys(schemaFile.models || {});
|
|
2687
|
-
const _mod_5 = await import('./index-
|
|
2688
|
-
const _ns_5 = _mod_5.
|
|
2710
|
+
const _mod_5 = await import('./index-s73wD_LC.js');
|
|
2711
|
+
const _ns_5 = _mod_5.bk;
|
|
2689
2712
|
const modelSchemaSchemaMod = _ns_5;
|
|
2690
2713
|
const { modelSchemas } = modelSchemaSchemaMod;
|
|
2691
|
-
const _mod_6 = await import('./index-
|
|
2692
|
-
const _ns_6 = _mod_6.
|
|
2714
|
+
const _mod_6 = await import('./index-s73wD_LC.js');
|
|
2715
|
+
const _ns_6 = _mod_6.bh;
|
|
2693
2716
|
const modelSchemaMod = _ns_6;
|
|
2694
2717
|
const { models: modelsTable } = modelSchemaMod;
|
|
2695
2718
|
const drizzleMod = await import('drizzle-orm');
|
|
@@ -2890,8 +2913,8 @@ async function applySchemaToDb(schemaFile, modelDefinitions, modelFileIds, prope
|
|
|
2890
2913
|
createdAt: new Date(schemaFile.metadata.createdAt).getTime(),
|
|
2891
2914
|
updatedAt: new Date(schemaFile.metadata.updatedAt).getTime(),
|
|
2892
2915
|
};
|
|
2893
|
-
const _mod_7 = await import('./index-
|
|
2894
|
-
const _ns_7 = _mod_7.
|
|
2916
|
+
const _mod_7 = await import('./index-s73wD_LC.js');
|
|
2917
|
+
const _ns_7 = _mod_7.bm;
|
|
2895
2918
|
const dbMod = _ns_7;
|
|
2896
2919
|
const { addSchemaToDb, addModelsToDb } = dbMod;
|
|
2897
2920
|
const db = BaseDb.getAppDb();
|
|
@@ -2922,8 +2945,8 @@ async function applySchemaToDb(schemaFile, modelDefinitions, modelFileIds, prope
|
|
|
2922
2945
|
* draft (its edits aren't the app's to undo) or a newer version than schemaFile.
|
|
2923
2946
|
*/
|
|
2924
2947
|
async function getModelsDroppedFromStoredSchema(db, schemaFile) {
|
|
2925
|
-
const _mod_8 = await import('./index-
|
|
2926
|
-
const _ns_8 = _mod_8.
|
|
2948
|
+
const _mod_8 = await import('./index-s73wD_LC.js');
|
|
2949
|
+
const _ns_8 = _mod_8.bj;
|
|
2927
2950
|
const { schemas: schemasTable } = _ns_8;
|
|
2928
2951
|
const { eq } = await import('drizzle-orm');
|
|
2929
2952
|
const rows = await db
|
|
@@ -2950,11 +2973,11 @@ async function getModelsDroppedFromStoredSchema(db, schemaFile) {
|
|
|
2950
2973
|
}
|
|
2951
2974
|
/** Delete the model_schemas rows linking the named models to the schema. The models and their items stay. */
|
|
2952
2975
|
async function unlinkModelsFromSchema(db, schemaId, modelNames) {
|
|
2953
|
-
const _mod_9 = await import('./index-
|
|
2954
|
-
const _ns_9 = _mod_9.
|
|
2976
|
+
const _mod_9 = await import('./index-s73wD_LC.js');
|
|
2977
|
+
const _ns_9 = _mod_9.bk;
|
|
2955
2978
|
const { modelSchemas } = _ns_9;
|
|
2956
|
-
const _mod_10 = await import('./index-
|
|
2957
|
-
const _ns_10 = _mod_10.
|
|
2979
|
+
const _mod_10 = await import('./index-s73wD_LC.js');
|
|
2980
|
+
const _ns_10 = _mod_10.bh;
|
|
2958
2981
|
const { models: modelsTable } = _ns_10;
|
|
2959
2982
|
const { and, eq, inArray } = await import('drizzle-orm');
|
|
2960
2983
|
const links = await db
|
|
@@ -3116,12 +3139,12 @@ const loadSchemaFromFile = async (schemaFilePath) => {
|
|
|
3116
3139
|
]));
|
|
3117
3140
|
const { schemaRecord } = await applySchemaToDb(schemaFile, modelDefinitions, modelFileIds, propertyFileIds, propertyDefinitions).finally(rowsWritten.settle);
|
|
3118
3141
|
// Query the database to get model IDs that were just created
|
|
3119
|
-
const _mod_11 = await import('./index-
|
|
3120
|
-
const _ns_11 = _mod_11.
|
|
3142
|
+
const _mod_11 = await import('./index-s73wD_LC.js');
|
|
3143
|
+
const _ns_11 = _mod_11.bk;
|
|
3121
3144
|
const modelSchemaSchemaMod = _ns_11;
|
|
3122
3145
|
const { modelSchemas } = modelSchemaSchemaMod;
|
|
3123
|
-
const _mod_12 = await import('./index-
|
|
3124
|
-
const _ns_12 = _mod_12.
|
|
3146
|
+
const _mod_12 = await import('./index-s73wD_LC.js');
|
|
3147
|
+
const _ns_12 = _mod_12.bh;
|
|
3125
3148
|
const modelSchemaMod = _ns_12;
|
|
3126
3149
|
const { models: modelsTable } = modelSchemaMod;
|
|
3127
3150
|
const drizzleMod = await import('drizzle-orm');
|
|
@@ -3186,8 +3209,8 @@ const loadSchemaFromFile = async (schemaFilePath) => {
|
|
|
3186
3209
|
// After properties are created (file path), ensure schemaFile has the correct IDs from database
|
|
3187
3210
|
// Query the database to get the actual schemaFileId values that were used
|
|
3188
3211
|
// This ensures schemaData matches what's actually in the database
|
|
3189
|
-
const _mod_13 = await import('./index-
|
|
3190
|
-
const _ns_13 = _mod_13.
|
|
3212
|
+
const _mod_13 = await import('./index-s73wD_LC.js');
|
|
3213
|
+
const _ns_13 = _mod_13.bh;
|
|
3191
3214
|
const modelSchemaMod2 = _ns_13;
|
|
3192
3215
|
const { properties: propertiesTable } = modelSchemaMod2;
|
|
3193
3216
|
let schemaFileUpdated = false;
|
|
@@ -3222,8 +3245,8 @@ const loadSchemaFromFile = async (schemaFilePath) => {
|
|
|
3222
3245
|
// This is important even if nothing changed, to ensure consistency
|
|
3223
3246
|
const updatedSchemaData = JSON.stringify(schemaFile, null, 2);
|
|
3224
3247
|
// Update the schema record in the database with current schemaData
|
|
3225
|
-
const _mod_14 = await import('./index-
|
|
3226
|
-
const _ns_14 = _mod_14.
|
|
3248
|
+
const _mod_14 = await import('./index-s73wD_LC.js');
|
|
3249
|
+
const _ns_14 = _mod_14.bj;
|
|
3227
3250
|
const schemaSchemaMod = _ns_14;
|
|
3228
3251
|
const { schemas: schemasTable } = schemaSchemaMod;
|
|
3229
3252
|
await db
|
|
@@ -3349,7 +3372,7 @@ const createRowsWrittenSignal = () => {
|
|
|
3349
3372
|
const createModelFromJson = async (modelName, modelDef, schemaName, modelFileId, // Optional modelFileId from JSON file
|
|
3350
3373
|
propertyFileIds, // Optional map of property names to their file IDs from the JSON file
|
|
3351
3374
|
persistedBy) => {
|
|
3352
|
-
const _mod_15 = await import('./errors-
|
|
3375
|
+
const _mod_15 = await import('./errors-a4Tj6hly.js');
|
|
3353
3376
|
const _ns_15 = _mod_15.i;
|
|
3354
3377
|
const modelMod = _ns_15;
|
|
3355
3378
|
const { Model } = modelMod;
|
|
@@ -3959,6 +3982,90 @@ const processSchemaFiles = fromCallback(({ sendBack, input: { context } }) => {
|
|
|
3959
3982
|
};
|
|
3960
3983
|
});
|
|
3961
3984
|
|
|
3985
|
+
/** Absolute path of the file {@link writeItemStorageFile} writes for `target`. */
|
|
3986
|
+
const getItemStorageFilePath = (target) => BaseFileManager.getFilesPath(getItemStorageSubdir(target.localStorageDir), target.fileName || getItemStorageLocalFileName(target.seedId, target.filenameSuffix));
|
|
3987
|
+
/**
|
|
3988
|
+
* Write an ItemStorage property's content to its local file, where saveItemStorage, reads, publish
|
|
3989
|
+
* (resolveItemStorageChildFile) and download all look for it. Returns what the metadata row records:
|
|
3990
|
+
* `refResolvedValue` (the file name) and `localStorageDir` (with a leading slash).
|
|
3991
|
+
*
|
|
3992
|
+
* Callers that also update the file's metadata row hold {@link withItemStorageFileLock} around
|
|
3993
|
+
* both, so another writer of the same file can't land in between.
|
|
3994
|
+
*/
|
|
3995
|
+
const writeItemStorageFile = async (target, content) => {
|
|
3996
|
+
const dir = getItemStorageSubdir(target.localStorageDir);
|
|
3997
|
+
const fileName = target.fileName || getItemStorageLocalFileName(target.seedId, target.filenameSuffix);
|
|
3998
|
+
await BaseFileManager.createDirIfNotExists(BaseFileManager.getFilesPath(dir));
|
|
3999
|
+
const filePath = BaseFileManager.getFilesPath(dir, fileName);
|
|
4000
|
+
await BaseFileManager.saveFile(filePath, content);
|
|
4001
|
+
return { fileName, filePath, localStorageDir: target.localStorageDir || `/${dir}` };
|
|
4002
|
+
};
|
|
4003
|
+
/**
|
|
4004
|
+
* Lock name for one ItemStorage file: `seed:item-storage:<absolute file path>`. The path starts
|
|
4005
|
+
* with the files root, which also names the database (`<filesDir>/db/seed.db`), so the name is
|
|
4006
|
+
* per database as well as per file.
|
|
4007
|
+
*/
|
|
4008
|
+
const itemStorageFileLockName = (filePath) => `seed:item-storage:${filePath}`;
|
|
4009
|
+
/**
|
|
4010
|
+
* Runs `fn` holding the lock of one ItemStorage file, across tabs (Web Locks) and within this JS
|
|
4011
|
+
* realm (an in-process queue where Web Locks are missing, e.g. Node < 24.5; see `withTabLock`).
|
|
4012
|
+
*
|
|
4013
|
+
* Writers of a local draft's file (saveItemStorage, convertVerbatimItemStorageRow, createNewItem)
|
|
4014
|
+
* hold it across "read the row → write the file → update the row", so the file and the row end
|
|
4015
|
+
* with the same writer's content. See docs/MULTI_TAB.md.
|
|
4016
|
+
*
|
|
4017
|
+
* Lock ordering: this lock is always the innermost. It may be taken while holding a broader lock
|
|
4018
|
+
* (`seed:item-storage-migration:<db>`, `seed:publish:<seedLocalId>`), never the other way round,
|
|
4019
|
+
* and no other lock (nor a second file lock) is requested while it is held. Keep the section to
|
|
4020
|
+
* local DB and file I/O: no network. Not re-entrant.
|
|
4021
|
+
*/
|
|
4022
|
+
function withItemStorageFileLock(filePath, fn) {
|
|
4023
|
+
return withTabLock(itemStorageFileLockName(filePath), fn);
|
|
4024
|
+
}
|
|
4025
|
+
/** {@link withItemStorageFileLock} only if the lock is free now (see `tryWithTabLock`). */
|
|
4026
|
+
function tryWithItemStorageFileLock(filePath, fn) {
|
|
4027
|
+
return tryWithTabLock(itemStorageFileLockName(filePath), fn);
|
|
4028
|
+
}
|
|
4029
|
+
/** Lock attempts before giving up when the row's target file keeps changing under us. */
|
|
4030
|
+
const ROW_LOCK_ATTEMPTS = 3;
|
|
4031
|
+
const readRow = async (localId) => {
|
|
4032
|
+
const rows = await BaseDb.getAppDb()
|
|
4033
|
+
.select()
|
|
4034
|
+
.from(metadata$1)
|
|
4035
|
+
.where(eq(metadata$1.localId, localId))
|
|
4036
|
+
.limit(1);
|
|
4037
|
+
return rows[0];
|
|
4038
|
+
};
|
|
4039
|
+
/**
|
|
4040
|
+
* Runs `fn` with a fresh read of metadata row `localId`, holding the lock of the file that row's
|
|
4041
|
+
* content goes to. `fileOf` names that file (absolute path) for a row, or returns undefined when
|
|
4042
|
+
* there is nothing to write (then `fn` isn't called and the result is undefined).
|
|
4043
|
+
*
|
|
4044
|
+
* The file depends on the row, so the row is read once to pick the lock and again once it is held;
|
|
4045
|
+
* if the row now points at another file (another writer changed it meanwhile), the lock is
|
|
4046
|
+
* released and taken again for that file.
|
|
4047
|
+
*/
|
|
4048
|
+
async function withLockedItemStorageRow(localId, fileOf, fn) {
|
|
4049
|
+
for (let attempt = 0; attempt < ROW_LOCK_ATTEMPTS; attempt++) {
|
|
4050
|
+
const row = await readRow(localId);
|
|
4051
|
+
const filePath = row && fileOf(row);
|
|
4052
|
+
if (!filePath)
|
|
4053
|
+
return undefined;
|
|
4054
|
+
const outcome = await withItemStorageFileLock(filePath, async () => {
|
|
4055
|
+
const fresh = await readRow(localId);
|
|
4056
|
+
const freshPath = fresh && fileOf(fresh);
|
|
4057
|
+
if (!freshPath)
|
|
4058
|
+
return { done: true, value: undefined };
|
|
4059
|
+
if (freshPath !== filePath)
|
|
4060
|
+
return { done: false };
|
|
4061
|
+
return { done: true, value: await fn(fresh, filePath) };
|
|
4062
|
+
});
|
|
4063
|
+
if (outcome.done)
|
|
4064
|
+
return outcome.value;
|
|
4065
|
+
}
|
|
4066
|
+
throw new Error(`ItemStorage file of metadata row ${localId} kept changing; not written`);
|
|
4067
|
+
}
|
|
4068
|
+
|
|
3962
4069
|
/**
|
|
3963
4070
|
* A legacy ItemStorage draft row: a local edit (no attestation uid, not derived from one) that holds
|
|
3964
4071
|
* the content itself in property_value, with no file reference. Item.create / createNewItem stored
|
|
@@ -4597,6 +4704,584 @@ function startCanonicalizeModelTypes() {
|
|
|
4597
4704
|
});
|
|
4598
4705
|
}
|
|
4599
4706
|
|
|
4707
|
+
const createVersion = async ({ seedLocalId, seedUid, seedType, uid, }, options = {}) => {
|
|
4708
|
+
const appDb = options.db ?? BaseDb.getAppDb();
|
|
4709
|
+
const newVersionLocalId = generateId();
|
|
4710
|
+
// A version belongs to its seed's wallet (none yet for a draft made with no wallet connected).
|
|
4711
|
+
const publisher = await getSeedPublisher(seedLocalId, appDb);
|
|
4712
|
+
await appDb.insert(versions).values({
|
|
4713
|
+
localId: newVersionLocalId,
|
|
4714
|
+
createdAt: Date.now(),
|
|
4715
|
+
seedLocalId,
|
|
4716
|
+
seedUid: seedUid ?? null,
|
|
4717
|
+
seedType,
|
|
4718
|
+
uid: uid ?? null,
|
|
4719
|
+
...(publisher && { publisher }),
|
|
4720
|
+
});
|
|
4721
|
+
return newVersionLocalId;
|
|
4722
|
+
};
|
|
4723
|
+
|
|
4724
|
+
/**
|
|
4725
|
+
* Conflicts between a local edit and a value sync wrote after it (ADR 0019). The local edit wins:
|
|
4726
|
+
* a pending edit applies over the synced row as a new draft, and a draft already written stays the
|
|
4727
|
+
* newest row. The conflict is recorded on an op row, so the app can show both values and let the
|
|
4728
|
+
* user pick.
|
|
4729
|
+
*/
|
|
4730
|
+
/**
|
|
4731
|
+
* The conflict a `set` op meets when it applies: sync wrote an attested row for the property after
|
|
4732
|
+
* the edit was made, and its value differs from both the value the edit was made against and the
|
|
4733
|
+
* edit's own. A row with the base row's uid (the same attestation synced again) is not a conflict,
|
|
4734
|
+
* nor is a published row carrying the base value (a publish of the edit's base). Reads through `db`
|
|
4735
|
+
* (the op's transaction).
|
|
4736
|
+
*/
|
|
4737
|
+
async function findSetConflict(op, value, db) {
|
|
4738
|
+
if (!op.propertyName)
|
|
4739
|
+
return null;
|
|
4740
|
+
const names = getMetadataPropertyNamesForQuery(op.propertyName, value.dataType, value.refValueType);
|
|
4741
|
+
const [newest] = await db
|
|
4742
|
+
.select({
|
|
4743
|
+
localId: metadata$1.localId,
|
|
4744
|
+
uid: metadata$1.uid,
|
|
4745
|
+
propertyValue: metadata$1.propertyValue,
|
|
4746
|
+
createdAt: metadata$1.createdAt,
|
|
4747
|
+
})
|
|
4748
|
+
.from(metadata$1)
|
|
4749
|
+
.where(and(eq(metadata$1.seedLocalId, op.seedLocalId), inArray(metadata$1.propertyName, names)))
|
|
4750
|
+
.orderBy(sql.raw(METADATA_LATEST_FIRST_ORDER_SQL))
|
|
4751
|
+
.limit(1);
|
|
4752
|
+
if (!newest?.uid || newest.localId === op.baseRowId)
|
|
4753
|
+
return null;
|
|
4754
|
+
const [base] = op.baseRowId
|
|
4755
|
+
? await db
|
|
4756
|
+
.select({ uid: metadata$1.uid, propertyValue: metadata$1.propertyValue })
|
|
4757
|
+
.from(metadata$1)
|
|
4758
|
+
.where(eq(metadata$1.localId, op.baseRowId))
|
|
4759
|
+
.limit(1)
|
|
4760
|
+
: [];
|
|
4761
|
+
if (base?.uid && base.uid === newest.uid)
|
|
4762
|
+
return null;
|
|
4763
|
+
// With no base row, only a row written after the edit counts: an older one was there to see
|
|
4764
|
+
if (!base && (newest.createdAt ?? 0) <= op.createdAt)
|
|
4765
|
+
return null;
|
|
4766
|
+
const baseValue = base?.propertyValue ?? null;
|
|
4767
|
+
const remoteValue = newest.propertyValue ?? null;
|
|
4768
|
+
if (remoteValue === baseValue || remoteValue === value.newValue)
|
|
4769
|
+
return null;
|
|
4770
|
+
return {
|
|
4771
|
+
seedLocalId: op.seedLocalId,
|
|
4772
|
+
propertyName: op.propertyName,
|
|
4773
|
+
baseValue,
|
|
4774
|
+
remoteValue,
|
|
4775
|
+
localValue: value.newValue,
|
|
4776
|
+
remoteUid: newest.uid,
|
|
4777
|
+
opId: op.opId,
|
|
4778
|
+
};
|
|
4779
|
+
}
|
|
4780
|
+
/**
|
|
4781
|
+
* Records `conflict` on the op that met it, and clears the property's earlier conflicts: a newer
|
|
4782
|
+
* local edit settles them (it was made with the synced value in view, or overrides it again).
|
|
4783
|
+
*/
|
|
4784
|
+
async function recordPropertyEdit(op, conflict, db) {
|
|
4785
|
+
if (!op.propertyName)
|
|
4786
|
+
return;
|
|
4787
|
+
await db
|
|
4788
|
+
.update(pendingWrites)
|
|
4789
|
+
.set({ conflictResolvedAt: Date.now() })
|
|
4790
|
+
.where(and(eq(pendingWrites.seedLocalId, op.seedLocalId), eq(pendingWrites.propertyName, op.propertyName), lt(pendingWrites.id, op.id), isNotNull(pendingWrites.conflict), isNull(pendingWrites.conflictResolvedAt)));
|
|
4791
|
+
if (conflict) {
|
|
4792
|
+
await db.update(pendingWrites).set({ conflict: JSON.stringify(conflict) }).where(eq(pendingWrites.opId, op.opId));
|
|
4793
|
+
}
|
|
4794
|
+
}
|
|
4795
|
+
const unresolved = (seedLocalId) => and(eq(pendingWrites.status, 'applied'), eq(pendingWrites.seedLocalId, seedLocalId), isNotNull(pendingWrites.conflict), isNull(pendingWrites.conflictResolvedAt));
|
|
4796
|
+
const parse = (row) => {
|
|
4797
|
+
try {
|
|
4798
|
+
return row.conflict ? JSON.parse(row.conflict) : null;
|
|
4799
|
+
}
|
|
4800
|
+
catch {
|
|
4801
|
+
return null;
|
|
4802
|
+
}
|
|
4803
|
+
};
|
|
4804
|
+
/** The item's unresolved conflicts, the newest per property. */
|
|
4805
|
+
async function getItemConflicts(seedLocalId) {
|
|
4806
|
+
const db = BaseDb.getAppDb();
|
|
4807
|
+
if (!db || !seedLocalId)
|
|
4808
|
+
return [];
|
|
4809
|
+
const rows = await db
|
|
4810
|
+
.select({ propertyName: pendingWrites.propertyName, conflict: pendingWrites.conflict })
|
|
4811
|
+
.from(pendingWrites)
|
|
4812
|
+
.where(unresolved(seedLocalId))
|
|
4813
|
+
.orderBy(desc(pendingWrites.id));
|
|
4814
|
+
const seen = new Set();
|
|
4815
|
+
const conflicts = [];
|
|
4816
|
+
for (const row of rows) {
|
|
4817
|
+
if (!row.propertyName || seen.has(row.propertyName))
|
|
4818
|
+
continue;
|
|
4819
|
+
seen.add(row.propertyName);
|
|
4820
|
+
const conflict = parse(row);
|
|
4821
|
+
if (conflict)
|
|
4822
|
+
conflicts.push(conflict);
|
|
4823
|
+
}
|
|
4824
|
+
return conflicts;
|
|
4825
|
+
}
|
|
4826
|
+
/** The property's unresolved conflict, if it has one. */
|
|
4827
|
+
async function getPropertyConflict(seedLocalId, propertyName) {
|
|
4828
|
+
if (!seedLocalId || !propertyName)
|
|
4829
|
+
return null;
|
|
4830
|
+
const db = BaseDb.getAppDb();
|
|
4831
|
+
if (!db)
|
|
4832
|
+
return null;
|
|
4833
|
+
const [row] = await db
|
|
4834
|
+
.select({ conflict: pendingWrites.conflict })
|
|
4835
|
+
.from(pendingWrites)
|
|
4836
|
+
.where(and(unresolved(seedLocalId), inArray(pendingWrites.propertyName, propertyNameVariants(propertyName))))
|
|
4837
|
+
.orderBy(desc(pendingWrites.id))
|
|
4838
|
+
.limit(1);
|
|
4839
|
+
return row ? parse(row) : null;
|
|
4840
|
+
}
|
|
4841
|
+
/** Marks the property's conflicts resolved. */
|
|
4842
|
+
async function markPropertyConflictsResolved(seedLocalId, propertyName) {
|
|
4843
|
+
const db = BaseDb.getAppDb();
|
|
4844
|
+
if (!db)
|
|
4845
|
+
return;
|
|
4846
|
+
await db
|
|
4847
|
+
.update(pendingWrites)
|
|
4848
|
+
.set({ conflictResolvedAt: Date.now() })
|
|
4849
|
+
.where(and(unresolved(seedLocalId), inArray(pendingWrites.propertyName, propertyNameVariants(propertyName))));
|
|
4850
|
+
}
|
|
4851
|
+
/**
|
|
4852
|
+
* The conflict rule for rows sync just inserted (`synced`) over a local draft already written: the
|
|
4853
|
+
* draft stays the property's value. When a synced row is newer than the draft, the draft's time is
|
|
4854
|
+
* moved just past it (readers take the newest row). A conflict is recorded, on an `applied` op row
|
|
4855
|
+
* of its own, when the synced value differs from both the draft's and the attested value the draft
|
|
4856
|
+
* replaced. Properties with a pending value op are left to the drainer, which applies the same rule.
|
|
4857
|
+
*/
|
|
4858
|
+
async function keepLocalDraftsOverSyncedRows(synced) {
|
|
4859
|
+
const db = BaseDb.getAppDb();
|
|
4860
|
+
if (!db)
|
|
4861
|
+
return;
|
|
4862
|
+
const live = synced.filter((row) => row.seedLocalId && row.propertyName && row.uid && row.revokedAt == null);
|
|
4863
|
+
if (live.length === 0)
|
|
4864
|
+
return;
|
|
4865
|
+
const seedIds = [...new Set(live.map((row) => row.seedLocalId))];
|
|
4866
|
+
const candidates = await selectInBatches(seedIds, (chunk) => db
|
|
4867
|
+
.select()
|
|
4868
|
+
.from(metadata$1)
|
|
4869
|
+
.where(and(inArray(metadata$1.seedLocalId, chunk), isNull(metadata$1.derivedFromUid), isNull(metadata$1.revokedAt))));
|
|
4870
|
+
const drafts = candidates.filter((row) => isPlaceholderUid(row.uid));
|
|
4871
|
+
if (drafts.length === 0)
|
|
4872
|
+
return;
|
|
4873
|
+
const syncedIds = new Set(live.map((row) => row.localId ?? ''));
|
|
4874
|
+
for (const draft of drafts) {
|
|
4875
|
+
const key = (row) => row.seedLocalId === draft.seedLocalId && row.propertyName === draft.propertyName;
|
|
4876
|
+
const remote = live
|
|
4877
|
+
.filter(key)
|
|
4878
|
+
.sort((a, b) => (b.attestationCreatedAt ?? 0) - (a.attestationCreatedAt ?? 0))[0];
|
|
4879
|
+
if (!remote || !draft.localId || !draft.seedLocalId || !draft.propertyName)
|
|
4880
|
+
continue;
|
|
4881
|
+
const [pending] = await db
|
|
4882
|
+
.select({ id: pendingWrites.id })
|
|
4883
|
+
.from(pendingWrites)
|
|
4884
|
+
.where(and(eq(pendingWrites.seedLocalId, draft.seedLocalId), eq(pendingWrites.propertyName, draft.propertyName), eq(pendingWrites.status, 'pending')))
|
|
4885
|
+
.limit(1);
|
|
4886
|
+
if (pending)
|
|
4887
|
+
continue;
|
|
4888
|
+
const now = Date.now();
|
|
4889
|
+
const remoteAt = remote.attestationCreatedAt ?? 0;
|
|
4890
|
+
if (remoteAt >= (draft.createdAt ?? 0)) {
|
|
4891
|
+
await db
|
|
4892
|
+
.update(metadata$1)
|
|
4893
|
+
.set({ createdAt: remoteAt + 1, updatedAt: now })
|
|
4894
|
+
.where(eq(metadata$1.localId, draft.localId));
|
|
4895
|
+
}
|
|
4896
|
+
// The attested value the draft replaced: the newest attested row that sync didn't just write
|
|
4897
|
+
const base = candidates
|
|
4898
|
+
.filter((row) => key(row) && !isPlaceholderUid(row.uid) && !syncedIds.has(row.localId ?? ''))
|
|
4899
|
+
.sort((a, b) => (b.attestationCreatedAt ?? 0) - (a.attestationCreatedAt ?? 0))[0];
|
|
4900
|
+
const baseValue = base?.propertyValue ?? null;
|
|
4901
|
+
const remoteValue = remote.propertyValue ?? null;
|
|
4902
|
+
const localValue = draft.propertyValue ?? null;
|
|
4903
|
+
if (remoteValue === localValue || remoteValue === baseValue)
|
|
4904
|
+
continue;
|
|
4905
|
+
const opId = generateId();
|
|
4906
|
+
const conflict = {
|
|
4907
|
+
seedLocalId: draft.seedLocalId,
|
|
4908
|
+
propertyName: draft.propertyName,
|
|
4909
|
+
baseValue,
|
|
4910
|
+
remoteValue,
|
|
4911
|
+
localValue,
|
|
4912
|
+
remoteUid: remote.uid,
|
|
4913
|
+
opId,
|
|
4914
|
+
};
|
|
4915
|
+
await db.insert(pendingWrites).values({
|
|
4916
|
+
opId,
|
|
4917
|
+
seedLocalId: draft.seedLocalId,
|
|
4918
|
+
propertyName: draft.propertyName,
|
|
4919
|
+
kind: 'set',
|
|
4920
|
+
value: JSON.stringify({ newValue: localValue }),
|
|
4921
|
+
baseRowId: draft.localId,
|
|
4922
|
+
createdAt: now,
|
|
4923
|
+
status: 'applied',
|
|
4924
|
+
appliedAt: now,
|
|
4925
|
+
conflict: JSON.stringify(conflict),
|
|
4926
|
+
});
|
|
4927
|
+
eventEmitter.emit('itemProperty.conflict', conflict);
|
|
4928
|
+
}
|
|
4929
|
+
}
|
|
4930
|
+
|
|
4931
|
+
var conflicts = /*#__PURE__*/Object.freeze({
|
|
4932
|
+
__proto__: null,
|
|
4933
|
+
findSetConflict: findSetConflict,
|
|
4934
|
+
getItemConflicts: getItemConflicts,
|
|
4935
|
+
getPropertyConflict: getPropertyConflict,
|
|
4936
|
+
keepLocalDraftsOverSyncedRows: keepLocalDraftsOverSyncedRows,
|
|
4937
|
+
markPropertyConflictsResolved: markPropertyConflictsResolved,
|
|
4938
|
+
recordPropertyEdit: recordPropertyEdit
|
|
4939
|
+
});
|
|
4940
|
+
|
|
4941
|
+
/**
|
|
4942
|
+
* The appliers for item ops (ADR 0019). Every tab registers them at init: the leader applies ops
|
|
4943
|
+
* that other tabs appended.
|
|
4944
|
+
*/
|
|
4945
|
+
/**
|
|
4946
|
+
* Writes a storage value's rows on `db`. The property's row is looked up here, on `db`, rather than
|
|
4947
|
+
* taken from the edit: two quick edits of a property that had no row would otherwise both create one.
|
|
4948
|
+
*/
|
|
4949
|
+
async function applyStorageValue(seedLocalId, propertyName, value, db) {
|
|
4950
|
+
const { storageSeed } = value;
|
|
4951
|
+
// The item's publisher as it is now: a draft claimed while the op waited passes it on
|
|
4952
|
+
const parentPublisher = await getSeedPublisher(seedLocalId, db);
|
|
4953
|
+
await createSeed({ type: storageSeed.type, modelFileId: storageSeed.modelFileId }, {
|
|
4954
|
+
db,
|
|
4955
|
+
fields: { ...storageSeed.fields, publisher: parentPublisher ?? storageSeed.fields.publisher },
|
|
4956
|
+
localId: storageSeed.localId,
|
|
4957
|
+
});
|
|
4958
|
+
await createVersion({ seedLocalId: storageSeed.localId, seedType: storageSeed.type }, { db });
|
|
4959
|
+
// Html and File store the property as e.g. htmlId; older rows may use the plain name
|
|
4960
|
+
const baseName = propertyName.endsWith('Id') ? propertyName.slice(0, -2) : propertyName;
|
|
4961
|
+
const [existing] = await db
|
|
4962
|
+
.select({ localId: metadata$1.localId })
|
|
4963
|
+
.from(metadata$1)
|
|
4964
|
+
.where(and(eq(metadata$1.seedLocalId, seedLocalId), or(eq(metadata$1.propertyName, propertyName), eq(metadata$1.propertyName, baseName))))
|
|
4965
|
+
.limit(1);
|
|
4966
|
+
if (existing?.localId) {
|
|
4967
|
+
const result = await updateItemPropertyValue({ ...value.update, localId: existing.localId, seedLocalId, propertyName }, { db });
|
|
4968
|
+
return result ?? null;
|
|
4969
|
+
}
|
|
4970
|
+
const row = await createMetadata({ ...value.create.values, seedLocalId, propertyName }, value.create.propertyRecordSchema, { db });
|
|
4971
|
+
return row.localId ? { localId: row.localId, uid: row.uid ?? null, schemaUid: row.schemaUid ?? '' } : null;
|
|
4972
|
+
}
|
|
4973
|
+
/** A local edit: no attestation uid of its own and not derived from one. */
|
|
4974
|
+
const isLocalDraft = (row) => !row.uid && row.derivedFromUid == null;
|
|
4975
|
+
/** The ItemStorage file a new draft of this item writes to (and so the lock to hold). */
|
|
4976
|
+
const itemStorageTargetPath = (seedLocalId, value) => getItemStorageFilePath({
|
|
4977
|
+
seedId: value.seedUid || seedLocalId,
|
|
4978
|
+
localStorageDir: value.propertyRecordSchema.localStorageDir,
|
|
4979
|
+
filenameSuffix: value.propertyRecordSchema.filenameSuffix,
|
|
4980
|
+
});
|
|
4981
|
+
/**
|
|
4982
|
+
* Moves a staged file into place. A retry after the move but before the commit finds the staged
|
|
4983
|
+
* file gone and the target there: already moved.
|
|
4984
|
+
*/
|
|
4985
|
+
async function moveStagedFile(from, to) {
|
|
4986
|
+
if (!(await BaseFileManager.pathExists(from))) {
|
|
4987
|
+
if (await BaseFileManager.pathExists(to))
|
|
4988
|
+
return;
|
|
4989
|
+
throw new Error(`Staged file ${from} is missing`);
|
|
4990
|
+
}
|
|
4991
|
+
await BaseFileManager.createDirIfNotExists(to.slice(0, to.lastIndexOf('/')));
|
|
4992
|
+
const fs = await BaseFileManager.getFs();
|
|
4993
|
+
await fs.promises.rename(from, to);
|
|
4994
|
+
notifyFileSaved(to);
|
|
4995
|
+
}
|
|
4996
|
+
/**
|
|
4997
|
+
* Writes an ItemStorage value on `db`: the edit goes into the property's current local draft, or a
|
|
4998
|
+
* new one when there is none or a published row is newer (readers show the newest row). A synced
|
|
4999
|
+
* or derived row is published content and is never written to.
|
|
5000
|
+
*/
|
|
5001
|
+
async function applyItemStorageValue(seedLocalId, propertyName, op, db) {
|
|
5002
|
+
const value = op.itemStorage;
|
|
5003
|
+
const schema = value.propertyRecordSchema;
|
|
5004
|
+
const where = [eq(metadata$1.propertyName, propertyName), eq(metadata$1.seedLocalId, seedLocalId)];
|
|
5005
|
+
if (value.versionLocalId)
|
|
5006
|
+
where.push(eq(metadata$1.versionLocalId, value.versionLocalId));
|
|
5007
|
+
const rows = await db.select().from(metadata$1).where(and(...where));
|
|
5008
|
+
const latest = [...rows].sort(compareMetadataRowsLatestFirst)[0];
|
|
5009
|
+
let draft = latest && isLocalDraft(latest) ? latest : undefined;
|
|
5010
|
+
if (!draft) {
|
|
5011
|
+
draft = await createMetadata({
|
|
5012
|
+
propertyName,
|
|
5013
|
+
propertyValue: getItemStorageLocalFileName(value.seedUid || seedLocalId, schema.filenameSuffix),
|
|
5014
|
+
modelType: value.modelType ?? undefined,
|
|
5015
|
+
seedLocalId,
|
|
5016
|
+
seedUid: value.seedUid ?? undefined,
|
|
5017
|
+
versionLocalId: value.versionLocalId ?? undefined,
|
|
5018
|
+
versionUid: value.versionUid ?? undefined,
|
|
5019
|
+
localStorageDir: schema.localStorageDir,
|
|
5020
|
+
refValueType: 'file',
|
|
5021
|
+
}, schema, { db });
|
|
5022
|
+
}
|
|
5023
|
+
// No storage.path: the `files` directory, as resolveItemStorageChildFile and download assume.
|
|
5024
|
+
const localStorageDir = schema.localStorageDir || draft.localStorageDir || '/files';
|
|
5025
|
+
const fileName = draft.refResolvedValue ||
|
|
5026
|
+
getItemStorageLocalFileName(draft.seedUid || draft.seedLocalId || seedLocalId, schema.filenameSuffix);
|
|
5027
|
+
await moveStagedFile(value.stagedPath, BaseFileManager.getFilesPath(getItemStorageSubdir(localStorageDir), fileName));
|
|
5028
|
+
// A legacy row (made before Item.create saved ItemStorage values) holds the old content itself in
|
|
5029
|
+
// propertyValue. The file is the content now: drop it, or a fresh load shows the old text until
|
|
5030
|
+
// the file is read. A row whose propertyValue is the file name keeps it.
|
|
5031
|
+
const clearsVerbatimValue = !draft.refResolvedValue && draft.propertyValue != null && draft.propertyValue !== '' && draft.propertyValue !== fileName;
|
|
5032
|
+
const now = Date.now();
|
|
5033
|
+
await db
|
|
5034
|
+
.update(metadata$1)
|
|
5035
|
+
.set({
|
|
5036
|
+
refResolvedValue: fileName,
|
|
5037
|
+
localStorageDir,
|
|
5038
|
+
// The draft is as new as its content (see updateItemPropertyValue).
|
|
5039
|
+
createdAt: now,
|
|
5040
|
+
updatedAt: now,
|
|
5041
|
+
// Same shape as a row the migration or publish converted (convertVerbatimItemStorageRow).
|
|
5042
|
+
...(clearsVerbatimValue && { propertyValue: null, refValueType: 'file' }),
|
|
5043
|
+
})
|
|
5044
|
+
.where(eq(metadata$1.localId, draft.localId));
|
|
5045
|
+
return { localId: draft.localId, uid: draft.uid ?? null, schemaUid: draft.schemaUid ?? '', fileName, localStorageDir };
|
|
5046
|
+
}
|
|
5047
|
+
/** Writes a new item's rows on `db` (see CreateItemOp). */
|
|
5048
|
+
async function applyCreateItem(seedLocalId, value, db) {
|
|
5049
|
+
await createSeed({ type: value.seed.type, modelFileId: value.seed.modelFileId }, { db, fields: value.seed.fields, localId: seedLocalId });
|
|
5050
|
+
const versionLocalId = await createVersion({ seedLocalId, seedType: value.seed.type }, { db });
|
|
5051
|
+
for (const row of value.rows) {
|
|
5052
|
+
if (row.itemStorage) {
|
|
5053
|
+
const { stagedPath, fileName, localStorageDir } = row.itemStorage;
|
|
5054
|
+
await moveStagedFile(stagedPath, BaseFileManager.getFilesPath(getItemStorageSubdir(localStorageDir), fileName));
|
|
5055
|
+
}
|
|
5056
|
+
await createMetadata({
|
|
5057
|
+
seedLocalId,
|
|
5058
|
+
versionLocalId,
|
|
5059
|
+
propertyName: row.propertyName,
|
|
5060
|
+
propertyValue: row.itemStorage ? undefined : row.propertyValue,
|
|
5061
|
+
...(row.itemStorage && {
|
|
5062
|
+
refResolvedValue: row.itemStorage.fileName,
|
|
5063
|
+
localStorageDir: row.itemStorage.localStorageDir,
|
|
5064
|
+
refValueType: 'file',
|
|
5065
|
+
}),
|
|
5066
|
+
...(row.schemaUid && { schemaUid: row.schemaUid }),
|
|
5067
|
+
modelName: value.modelName,
|
|
5068
|
+
}, row.propertyRecordSchema, { db, skipValidation: true, modelFileId: value.seed.modelFileId });
|
|
5069
|
+
}
|
|
5070
|
+
return { seedLocalId, versionLocalId };
|
|
5071
|
+
}
|
|
5072
|
+
/** Storage seeds a property row points at: Html, Image and File values are seeds of their own. */
|
|
5073
|
+
const STORAGE_REF_TYPES = new Set(['html', 'image', 'file']);
|
|
5074
|
+
async function applyDelete(op, value, db) {
|
|
5075
|
+
if (value.mode === 'item') {
|
|
5076
|
+
await db.update(seeds).set({ _markedForDeletion: 1 }).where(eq(seeds.localId, op.seedLocalId));
|
|
5077
|
+
return { filePaths: [] };
|
|
5078
|
+
}
|
|
5079
|
+
if (value.mode === 'property') {
|
|
5080
|
+
await db
|
|
5081
|
+
.delete(metadata$1)
|
|
5082
|
+
.where(and(eq(metadata$1.seedLocalId, op.seedLocalId), inArray(metadata$1.propertyName, value.propertyNames)));
|
|
5083
|
+
return { filePaths: [] };
|
|
5084
|
+
}
|
|
5085
|
+
if (value.mode === 'drafts') {
|
|
5086
|
+
await db
|
|
5087
|
+
.delete(metadata$1)
|
|
5088
|
+
.where(and(eq(metadata$1.seedLocalId, op.seedLocalId), inArray(metadata$1.propertyName, value.propertyNames), isNull(metadata$1.uid)));
|
|
5089
|
+
return { filePaths: [] };
|
|
5090
|
+
}
|
|
5091
|
+
const rows = await db
|
|
5092
|
+
.select({
|
|
5093
|
+
propertyValue: metadata$1.propertyValue,
|
|
5094
|
+
refSeedType: metadata$1.refSeedType,
|
|
5095
|
+
refResolvedValue: metadata$1.refResolvedValue,
|
|
5096
|
+
localStorageDir: metadata$1.localStorageDir,
|
|
5097
|
+
})
|
|
5098
|
+
.from(metadata$1)
|
|
5099
|
+
.where(eq(metadata$1.seedLocalId, op.seedLocalId));
|
|
5100
|
+
const childSeedLocalIds = [];
|
|
5101
|
+
const filePaths = [];
|
|
5102
|
+
for (const row of rows) {
|
|
5103
|
+
if (row.refSeedType && STORAGE_REF_TYPES.has(row.refSeedType) && row.propertyValue) {
|
|
5104
|
+
childSeedLocalIds.push(row.propertyValue);
|
|
5105
|
+
}
|
|
5106
|
+
if (row.localStorageDir && row.refResolvedValue) {
|
|
5107
|
+
filePaths.push(BaseFileManager.getFilesPath(row.localStorageDir, row.refResolvedValue));
|
|
5108
|
+
}
|
|
5109
|
+
}
|
|
5110
|
+
const { hardDeleteLocalSeedsByLocalIds } = await Promise.resolve().then(function () { return removeLocalCopiesForAddresses; });
|
|
5111
|
+
await hardDeleteLocalSeedsByLocalIds([op.seedLocalId, ...childSeedLocalIds], { db, keepOpId: op.opId });
|
|
5112
|
+
return { filePaths };
|
|
5113
|
+
}
|
|
5114
|
+
/** Deletes files after the op that removed their rows applied; best-effort. */
|
|
5115
|
+
async function deleteFiles(filePaths) {
|
|
5116
|
+
if (filePaths.length === 0)
|
|
5117
|
+
return;
|
|
5118
|
+
const fs = await BaseFileManager.getFs();
|
|
5119
|
+
for (const path of filePaths) {
|
|
5120
|
+
try {
|
|
5121
|
+
if (!(await BaseFileManager.pathExists(path)))
|
|
5122
|
+
continue;
|
|
5123
|
+
if (fs?.promises?.unlink)
|
|
5124
|
+
await fs.promises.unlink(path);
|
|
5125
|
+
else
|
|
5126
|
+
fs?.unlinkSync?.(path);
|
|
5127
|
+
}
|
|
5128
|
+
catch {
|
|
5129
|
+
// Best-effort: a file left behind has no row pointing at it
|
|
5130
|
+
}
|
|
5131
|
+
}
|
|
5132
|
+
}
|
|
5133
|
+
const isItemStorageOp = (value) => typeof value === 'object' && value !== null && 'itemStorage' in value;
|
|
5134
|
+
/** Deletes the file a storage op wrote, once the op will never apply. */
|
|
5135
|
+
async function discardStorageValue(op) {
|
|
5136
|
+
const value = outboxOpValue(op);
|
|
5137
|
+
const path = value && (isItemStorageOp(value) ? value.itemStorage.stagedPath : value.ownedFilePath);
|
|
5138
|
+
if (!path || !(await BaseFileManager.pathExists(path)))
|
|
5139
|
+
return;
|
|
5140
|
+
const fs = await BaseFileManager.getFs();
|
|
5141
|
+
if (fs?.promises?.unlink)
|
|
5142
|
+
await fs.promises.unlink(path);
|
|
5143
|
+
else
|
|
5144
|
+
fs?.unlinkSync?.(path);
|
|
5145
|
+
}
|
|
5146
|
+
/**
|
|
5147
|
+
* The ownership rule, checked before an op applies (ADR 0019's async rules): the op may come from
|
|
5148
|
+
* another tab, or from before a reload, and the client may have lost the item's wallet since it
|
|
5149
|
+
* was appended. OwnershipError fails the op without a retry.
|
|
5150
|
+
*/
|
|
5151
|
+
async function requireOwned(op) {
|
|
5152
|
+
if (!(await isItemOwned({ seedLocalId: op.seedLocalId })))
|
|
5153
|
+
throw new OwnershipError();
|
|
5154
|
+
}
|
|
5155
|
+
/** A Relation value names a local seed that doesn't exist. */
|
|
5156
|
+
class RelationTargetError extends Error {
|
|
5157
|
+
constructor(targets) {
|
|
5158
|
+
super(`Relation target not found: ${targets.join(', ')}`);
|
|
5159
|
+
this.targets = targets;
|
|
5160
|
+
this.name = 'RelationTargetError';
|
|
5161
|
+
}
|
|
5162
|
+
}
|
|
5163
|
+
/** The seed ids a Relation or List-of-Relation value names; none for other values. */
|
|
5164
|
+
function relationTargets(value) {
|
|
5165
|
+
const dataType = normalizeDataType(value.dataType);
|
|
5166
|
+
const refValueType = normalizeDataType(value.refValueType);
|
|
5167
|
+
if (!value.newValue)
|
|
5168
|
+
return [];
|
|
5169
|
+
if (dataType === 'Relation' && refValueType !== 'Image')
|
|
5170
|
+
return [value.newValue];
|
|
5171
|
+
if (dataType === 'List' && refValueType === 'Relation')
|
|
5172
|
+
return parseListPropertyValueFromStorage(value.newValue);
|
|
5173
|
+
return [];
|
|
5174
|
+
}
|
|
5175
|
+
/**
|
|
5176
|
+
* The relation-target rule, checked before a `set` applies: each seed a Relation value names by
|
|
5177
|
+
* local id must exist. An attestation uid may name a seed with no local copy, so uids pass. A
|
|
5178
|
+
* target whose create op is still pending defers the op (OutboxOpDeferredError) until it applies;
|
|
5179
|
+
* any other missing target fails it with RelationTargetError.
|
|
5180
|
+
*/
|
|
5181
|
+
async function requireRelationTargets(op) {
|
|
5182
|
+
const value = outboxOpValue(op);
|
|
5183
|
+
const localIds = [...new Set(value ? relationTargets(value) : [])].filter((id) => !isValidEasAttestationUid(id));
|
|
5184
|
+
if (localIds.length === 0)
|
|
5185
|
+
return;
|
|
5186
|
+
const db = BaseDb.getAppDb();
|
|
5187
|
+
const found = await db.select({ localId: seeds.localId }).from(seeds).where(inArray(seeds.localId, localIds));
|
|
5188
|
+
const missing = localIds.filter((id) => !found.some((row) => row.localId === id));
|
|
5189
|
+
if (missing.length === 0)
|
|
5190
|
+
return;
|
|
5191
|
+
const creating = await db
|
|
5192
|
+
.select({ seedLocalId: pendingWrites.seedLocalId })
|
|
5193
|
+
.from(pendingWrites)
|
|
5194
|
+
.where(and(inArray(pendingWrites.seedLocalId, missing), eq(pendingWrites.kind, 'create'), eq(pendingWrites.status, 'pending')));
|
|
5195
|
+
if (creating.length > 0)
|
|
5196
|
+
throw new OutboxOpDeferredError(`Relation target ${creating[0].seedLocalId} is being created`);
|
|
5197
|
+
throw new RelationTargetError(missing);
|
|
5198
|
+
}
|
|
5199
|
+
/**
|
|
5200
|
+
* Rethrows a failed item op's error as its caller expects it: OwnershipError when the drainer
|
|
5201
|
+
* refused the op for ownership, else the OutboxOpFailedError as is.
|
|
5202
|
+
*/
|
|
5203
|
+
function throwItemWriteError(error) {
|
|
5204
|
+
if (error instanceof OutboxOpFailedError && error.errorName === 'OwnershipError') {
|
|
5205
|
+
throw new OwnershipError(error.message);
|
|
5206
|
+
}
|
|
5207
|
+
throw error;
|
|
5208
|
+
}
|
|
5209
|
+
let registered$1 = false;
|
|
5210
|
+
/** Registers the item appliers and starts draining. Safe to call more than once. */
|
|
5211
|
+
function startItemOutbox() {
|
|
5212
|
+
if (!registered$1) {
|
|
5213
|
+
registered$1 = true;
|
|
5214
|
+
registerOutboxApplier('set', {
|
|
5215
|
+
prepare: async (op) => {
|
|
5216
|
+
await requireOwned(op);
|
|
5217
|
+
await requireRelationTargets(op);
|
|
5218
|
+
},
|
|
5219
|
+
apply: async (op, tx) => {
|
|
5220
|
+
const value = outboxOpValue(op);
|
|
5221
|
+
// Before the write, which makes the edit the newest row
|
|
5222
|
+
const conflict = await findSetConflict(op, value, tx);
|
|
5223
|
+
const result = await updateItemPropertyValue({ ...value, seedLocalId: op.seedLocalId, propertyName: op.propertyName ?? undefined }, { db: tx });
|
|
5224
|
+
await recordPropertyEdit(op, conflict, tx);
|
|
5225
|
+
return result ?? null;
|
|
5226
|
+
},
|
|
5227
|
+
});
|
|
5228
|
+
registerOutboxApplier('storage', {
|
|
5229
|
+
prepare: requireOwned,
|
|
5230
|
+
// Storage values record no conflicts: their ops carry no base row (ADR 0019)
|
|
5231
|
+
apply: async (op, tx) => {
|
|
5232
|
+
const value = outboxOpValue(op);
|
|
5233
|
+
const result = isItemStorageOp(value)
|
|
5234
|
+
? await applyItemStorageValue(op.seedLocalId, op.propertyName, value, tx)
|
|
5235
|
+
: await applyStorageValue(op.seedLocalId, op.propertyName, value, tx);
|
|
5236
|
+
await recordPropertyEdit(op, null, tx);
|
|
5237
|
+
return result;
|
|
5238
|
+
},
|
|
5239
|
+
// ItemStorage: the file's lock before the transaction, the order its other writers use. Taken
|
|
5240
|
+
// only when free: another writer holding it would otherwise hold up every other op.
|
|
5241
|
+
around: async (op, run) => {
|
|
5242
|
+
const value = outboxOpValue(op);
|
|
5243
|
+
if (!value || !isItemStorageOp(value))
|
|
5244
|
+
return run();
|
|
5245
|
+
const path = itemStorageTargetPath(op.seedLocalId, value.itemStorage);
|
|
5246
|
+
const outcome = await tryWithItemStorageFileLock(path, run);
|
|
5247
|
+
if (!outcome.acquired)
|
|
5248
|
+
throw new OutboxOpDeferredError(`ItemStorage file ${path} is locked`);
|
|
5249
|
+
return outcome.value;
|
|
5250
|
+
},
|
|
5251
|
+
discard: discardStorageValue,
|
|
5252
|
+
});
|
|
5253
|
+
registerOutboxApplier('create', {
|
|
5254
|
+
apply: async (op, tx) => applyCreateItem(op.seedLocalId, outboxOpValue(op), tx),
|
|
5255
|
+
// Staged ItemStorage values of a create that never applied
|
|
5256
|
+
discard: async (op) => {
|
|
5257
|
+
const paths = (outboxOpValue(op)?.rows ?? []).flatMap((row) => row.itemStorage ? [row.itemStorage.stagedPath] : []);
|
|
5258
|
+
await deleteFiles(paths);
|
|
5259
|
+
},
|
|
5260
|
+
});
|
|
5261
|
+
registerOutboxApplier('delete', {
|
|
5262
|
+
// A discarded draft is the client's own create rolled back
|
|
5263
|
+
prepare: async (op) => {
|
|
5264
|
+
if (outboxOpValue(op)?.mode !== 'discard')
|
|
5265
|
+
await requireOwned(op);
|
|
5266
|
+
},
|
|
5267
|
+
apply: async (op, tx) => applyDelete(op, outboxOpValue(op), tx),
|
|
5268
|
+
});
|
|
5269
|
+
}
|
|
5270
|
+
startOutbox();
|
|
5271
|
+
}
|
|
5272
|
+
|
|
5273
|
+
var itemAppliers = /*#__PURE__*/Object.freeze({
|
|
5274
|
+
__proto__: null,
|
|
5275
|
+
RelationTargetError: RelationTargetError,
|
|
5276
|
+
applyCreateItem: applyCreateItem,
|
|
5277
|
+
applyDelete: applyDelete,
|
|
5278
|
+
applyItemStorageValue: applyItemStorageValue,
|
|
5279
|
+
applyStorageValue: applyStorageValue,
|
|
5280
|
+
deleteFiles: deleteFiles,
|
|
5281
|
+
startItemOutbox: startItemOutbox,
|
|
5282
|
+
throwItemWriteError: throwItemWriteError
|
|
5283
|
+
});
|
|
5284
|
+
|
|
4600
5285
|
const { UNINITIALIZED, PLATFORM_CLASSES_INIT, FILE_SYSTEM_INIT, DB_INIT, SAVE_CONFIG, PROCESS_SCHEMA_FILES, ADD_MODELS_TO_STORE, ADD_MODELS_TO_DB, IDLE, INIT_FAILED, } = ClientManagerState;
|
|
4601
5286
|
const { UPDATE_CONTEXT, PLATFORM_CLASSES_READY, FILE_SYSTEM_READY, DB_READY, SAVE_CONFIG_SUCCESS, SAVE_APP_STATE_SUCCESS, SAVE_APP_STATE_ERROR, SET_ADDRESSES, ADD_MODELS_TO_STORE_SUCCESS, ADD_MODELS_TO_DB_SUCCESS, PROCESS_SCHEMA_FILES_SUCCESS, } = ClientManagerEvents;
|
|
4602
5287
|
const logSyncAfterAddressSave = debug("seedSdk:client:clientManagerMachine:syncAfterAddressSave");
|
|
@@ -4640,7 +5325,7 @@ function emitAddressesPersistedIfAddressesKey(event) {
|
|
|
4640
5325
|
if (event.key !== "addresses")
|
|
4641
5326
|
return;
|
|
4642
5327
|
const payload = parseAddressesPersistedPayload(event.value);
|
|
4643
|
-
|
|
5328
|
+
announceAddressesPersisted(payload);
|
|
4644
5329
|
}
|
|
4645
5330
|
function errorFromEvent(event, fallbackMessage) {
|
|
4646
5331
|
const error = event?.error;
|
|
@@ -4833,6 +5518,9 @@ const clientManagerMachine = setup({
|
|
|
4833
5518
|
() => startClearStoredDisplayUrls(),
|
|
4834
5519
|
// Stored model types to the ADR 0008 form (html_page), so exact type filters find old rows.
|
|
4835
5520
|
() => startCanonicalizeModelTypes(),
|
|
5521
|
+
// Registers the item appliers and resumes outbox ops left pending (a reload, a closed
|
|
5522
|
+
// leader tab) once this tab leads
|
|
5523
|
+
() => startItemOutbox(),
|
|
4836
5524
|
],
|
|
4837
5525
|
on: {
|
|
4838
5526
|
[SAVE_APP_STATE_SUCCESS]: {
|
|
@@ -5414,15 +6102,21 @@ async function findLocalOnchainCopiesForAddresses(addresses) {
|
|
|
5414
6102
|
};
|
|
5415
6103
|
}
|
|
5416
6104
|
/**
|
|
5417
|
-
* Hard-delete the given seed local ids and related local rows (cascade)
|
|
6105
|
+
* Hard-delete the given seed local ids and related local rows (cascade), their outbox ops included
|
|
6106
|
+
* (ADR 0019: an edit of a removed seed has nothing left to apply to; a waiter on one rejects).
|
|
5418
6107
|
* Does not touch schemas, app_state, or chain.
|
|
5419
6108
|
*/
|
|
5420
|
-
async function hardDeleteLocalSeedsByLocalIds(seedLocalIds) {
|
|
6109
|
+
async function hardDeleteLocalSeedsByLocalIds(seedLocalIds, options = {}) {
|
|
5421
6110
|
if (seedLocalIds.length === 0)
|
|
5422
6111
|
return;
|
|
5423
|
-
const appDb = BaseDb.getAppDb();
|
|
6112
|
+
const appDb = options.db ?? BaseDb.getAppDb();
|
|
5424
6113
|
if (!appDb)
|
|
5425
6114
|
return;
|
|
6115
|
+
await appDb
|
|
6116
|
+
.delete(pendingWrites)
|
|
6117
|
+
.where(options.keepOpId
|
|
6118
|
+
? and(inArray(pendingWrites.seedLocalId, seedLocalIds), ne(pendingWrites.opId, options.keepOpId))
|
|
6119
|
+
: inArray(pendingWrites.seedLocalId, seedLocalIds));
|
|
5426
6120
|
await appDb
|
|
5427
6121
|
.delete(htmlEmbeddedImageCoPublish)
|
|
5428
6122
|
.where(or(inArray(htmlEmbeddedImageCoPublish.parentSeedLocalId, seedLocalIds), inArray(htmlEmbeddedImageCoPublish.htmlSeedLocalId, seedLocalIds), inArray(htmlEmbeddedImageCoPublish.imageSeedLocalId, seedLocalIds)));
|
|
@@ -5437,10 +6131,17 @@ async function hardDeleteLocalSeedsByLocalIds(seedLocalIds) {
|
|
|
5437
6131
|
await appDb.delete(seeds).where(inArray(seeds.localId, seedLocalIds));
|
|
5438
6132
|
}
|
|
5439
6133
|
|
|
6134
|
+
var removeLocalCopiesForAddresses = /*#__PURE__*/Object.freeze({
|
|
6135
|
+
__proto__: null,
|
|
6136
|
+
findLocalOnchainCopiesForAddresses: findLocalOnchainCopiesForAddresses,
|
|
6137
|
+
hardDeleteLocalSeedsByLocalIds: hardDeleteLocalSeedsByLocalIds
|
|
6138
|
+
});
|
|
6139
|
+
|
|
5440
6140
|
const emptyResult = () => ({
|
|
5441
6141
|
seeds: 0,
|
|
5442
6142
|
versions: 0,
|
|
5443
6143
|
metadata: 0,
|
|
6144
|
+
pendingCreates: 0,
|
|
5444
6145
|
seedLocalIds: [],
|
|
5445
6146
|
});
|
|
5446
6147
|
/**
|
|
@@ -5448,53 +6149,78 @@ const emptyResult = () => ({
|
|
|
5448
6149
|
* uid and no attestationRaw, and those seeds' versions and property rows that are unsealed too.
|
|
5449
6150
|
* Versions and property rows go only with their seed, so rows of a seed that already has a
|
|
5450
6151
|
* publisher are never claimed. Sealed rows (real EAS uid or attestationRaw) are never touched.
|
|
6152
|
+
*
|
|
6153
|
+
* Pending Item.create ops with no publisher get it too, in the same transaction: the drainer applies
|
|
6154
|
+
* an op's value as its claim reads it (ADR 0019), so a create applied before or after this one ends
|
|
6155
|
+
* up claimed either way.
|
|
5451
6156
|
*/
|
|
5452
6157
|
async function claimUnpublishedDrafts(publisher) {
|
|
5453
6158
|
const normalized = normalizePublisher(publisher);
|
|
5454
6159
|
if (!normalized)
|
|
5455
6160
|
return emptyResult();
|
|
5456
|
-
|
|
5457
|
-
if (!appDb)
|
|
6161
|
+
if (!BaseDb.getAppDb())
|
|
5458
6162
|
return emptyResult();
|
|
5459
6163
|
const now = Date.now();
|
|
5460
6164
|
const isClaimable = (row) => typeof row.localId === 'string' && row.localId !== '' && isLocalUnsealedDraft(row);
|
|
5461
|
-
|
|
5462
|
-
|
|
5463
|
-
|
|
5464
|
-
|
|
5465
|
-
|
|
5466
|
-
|
|
5467
|
-
uid: seeds.uid,
|
|
5468
|
-
publisher: seeds.publisher,
|
|
5469
|
-
attestationRaw: seeds.attestationRaw,
|
|
5470
|
-
})
|
|
5471
|
-
.from(seeds));
|
|
5472
|
-
const seedIds = seedRows.filter(isClaimable).map((row) => row.localId);
|
|
5473
|
-
if (seedIds.length === 0)
|
|
5474
|
-
return emptyResult();
|
|
5475
|
-
const claimChildren = async (table) => {
|
|
5476
|
-
const rows = (await selectInBatches(seedIds, (chunk) => appDb
|
|
6165
|
+
return BaseDb.transaction(async (tx) => {
|
|
6166
|
+
const stamp = async (table, ids) => {
|
|
6167
|
+
await writeInBatches(ids, (chunk) => tx.update(table).set({ publisher: normalized, updatedAt: now }).where(inArray(table.localId, chunk)));
|
|
6168
|
+
};
|
|
6169
|
+
const pendingCreateIds = await claimPendingCreates(tx, normalized);
|
|
6170
|
+
const seedRows = (await tx
|
|
5477
6171
|
.select({
|
|
5478
|
-
localId:
|
|
5479
|
-
uid:
|
|
5480
|
-
publisher:
|
|
5481
|
-
attestationRaw:
|
|
6172
|
+
localId: seeds.localId,
|
|
6173
|
+
uid: seeds.uid,
|
|
6174
|
+
publisher: seeds.publisher,
|
|
6175
|
+
attestationRaw: seeds.attestationRaw,
|
|
5482
6176
|
})
|
|
5483
|
-
.from(
|
|
5484
|
-
|
|
5485
|
-
|
|
5486
|
-
|
|
5487
|
-
|
|
5488
|
-
|
|
5489
|
-
|
|
5490
|
-
|
|
5491
|
-
|
|
5492
|
-
|
|
5493
|
-
|
|
5494
|
-
|
|
5495
|
-
|
|
5496
|
-
|
|
5497
|
-
|
|
6177
|
+
.from(seeds));
|
|
6178
|
+
const seedIds = seedRows.filter(isClaimable).map((row) => row.localId);
|
|
6179
|
+
if (seedIds.length === 0) {
|
|
6180
|
+
return { ...emptyResult(), pendingCreates: pendingCreateIds.length, seedLocalIds: pendingCreateIds };
|
|
6181
|
+
}
|
|
6182
|
+
const claimChildren = async (table) => {
|
|
6183
|
+
const rows = (await selectInBatches(seedIds, (chunk) => tx
|
|
6184
|
+
.select({
|
|
6185
|
+
localId: table.localId,
|
|
6186
|
+
uid: table.uid,
|
|
6187
|
+
publisher: table.publisher,
|
|
6188
|
+
attestationRaw: table.attestationRaw,
|
|
6189
|
+
})
|
|
6190
|
+
.from(table)
|
|
6191
|
+
.where(inArray(table.seedLocalId, chunk))));
|
|
6192
|
+
const ids = rows.filter(isClaimable).map((row) => row.localId);
|
|
6193
|
+
await stamp(table, ids);
|
|
6194
|
+
return ids;
|
|
6195
|
+
};
|
|
6196
|
+
await stamp(seeds, seedIds);
|
|
6197
|
+
const versionIds = await claimChildren(versions);
|
|
6198
|
+
const metadataIds = await claimChildren(metadata$1);
|
|
6199
|
+
return {
|
|
6200
|
+
seeds: seedIds.length,
|
|
6201
|
+
versions: versionIds.length,
|
|
6202
|
+
metadata: metadataIds.length,
|
|
6203
|
+
pendingCreates: pendingCreateIds.length,
|
|
6204
|
+
seedLocalIds: [...seedIds, ...pendingCreateIds],
|
|
6205
|
+
};
|
|
6206
|
+
});
|
|
6207
|
+
}
|
|
6208
|
+
/** Sets `publisher` on pending create ops that have none; returns their seeds' local ids. */
|
|
6209
|
+
async function claimPendingCreates(tx, publisher) {
|
|
6210
|
+
const ops = await tx
|
|
6211
|
+
.select({ opId: pendingWrites.opId, seedLocalId: pendingWrites.seedLocalId, value: pendingWrites.value })
|
|
6212
|
+
.from(pendingWrites)
|
|
6213
|
+
.where(and(eq(pendingWrites.kind, 'create'), eq(pendingWrites.status, 'pending')));
|
|
6214
|
+
const claimed = [];
|
|
6215
|
+
for (const op of ops) {
|
|
6216
|
+
const value = op.value ? JSON.parse(op.value) : undefined;
|
|
6217
|
+
if (!value || value.seed.fields.publisher)
|
|
6218
|
+
continue;
|
|
6219
|
+
value.seed.fields = { ...value.seed.fields, publisher };
|
|
6220
|
+
await tx.update(pendingWrites).set({ value: JSON.stringify(value) }).where(eq(pendingWrites.opId, op.opId));
|
|
6221
|
+
claimed.push(op.seedLocalId);
|
|
6222
|
+
}
|
|
6223
|
+
return claimed;
|
|
5498
6224
|
}
|
|
5499
6225
|
|
|
5500
6226
|
const logger = debug('seedSdk:client');
|
|
@@ -5552,6 +6278,7 @@ const stopClient = ({ unsubscribe }) => {
|
|
|
5552
6278
|
activeInitConfig = undefined;
|
|
5553
6279
|
cancelAllRetriesWhenOnline();
|
|
5554
6280
|
unregisterSeedQueryLocalSource();
|
|
6281
|
+
resetAddressesPersistedAnnouncement();
|
|
5555
6282
|
clientManager.stop();
|
|
5556
6283
|
if (unsubscribe)
|
|
5557
6284
|
subscription.unsubscribe();
|
|
@@ -5815,5 +6542,5 @@ var ClientManager$1 = /*#__PURE__*/Object.freeze({
|
|
|
5815
6542
|
getClient: getClient
|
|
5816
6543
|
});
|
|
5817
6544
|
|
|
5818
|
-
export {
|
|
5819
|
-
//# sourceMappingURL=ClientManager-
|
|
6545
|
+
export { ClientManager$1 as $, getPublishedSeedRecord as A, getSchemaNameFromId as B, ClientManager as C, isSeedQueryLocalSourceRegistered as D, EAS_CHAIN_ID_APP_STATE_KEY as E, listCompleteSchemaFiles as F, loadAllSchemasFromDb as G, mergeEasSyncRequestIntents as H, INIT_CONFIG_CONFLICT_MESSAGE as I, readSchema as J, registerSeedQueryLocalSource as K, requestEasSyncFromAddressChange as L, requestEasSyncFromEventBus as M, requestEasSyncFromModelsInit as N, sendEasSyncClientRequest as O, setRetriesWhenOnlineEnabled as P, startEasSyncActor as Q, RelationTargetError as R, unregisterSeedQueryLocalSource as S, createRowsWrittenSignal as T, createModelsFromJson as U, getLatestSchemaVersion as V, jsonPropertiesToSchemaProperties as W, schema as X, SEEDPROTOCOL_Seed_Protocol_v1 as Y, conflicts as Z, itemAppliers as _, applyCreateItem as a, applyDelete as b, applyItemStorageValue as c, deleteFiles as d, applyStorageValue as e, getPropertyConflict as f, getItemConflicts as g, getRefValueType as h, importJsonSchema as i, syncSchemaFromSource as j, transformImportToSchemaFile as k, loadSchemaFromFile as l, markPropertyConflictsResolved as m, getContentHash as n, isVerbatimItemStorageDraftRow as o, convertVerbatimItemStorageRow as p, assertLocalDbChain as q, readJsonImportFile as r, startItemOutbox as s, throwItemWriteError as t, claimUnpublishedDrafts as u, createLocalQueryDataSource as v, waitForEasReadChain as w, createSchema as x, easSyncActor as y, getClient as z };
|
|
6546
|
+
//# sourceMappingURL=ClientManager-Bv15o3Oz.js.map
|