@seedprotocol/sdk 0.7.9-next.1110.g7eb9e57 → 0.7.9-next.1177.ga3e08ed
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/README.md +1 -1
- package/dist/{ClientManager-B1r_8P5Z.js → ClientManager-GZfXErDX.js} +187 -1451
- package/dist/ClientManager-GZfXErDX.js.map +1 -0
- package/dist/{Item-CjTEShfk.js → Item-0oDoTPhi.js} +175 -238
- package/dist/Item-0oDoTPhi.js.map +1 -0
- package/dist/{ModelProperty-C3749Wjq.js → ModelProperty-i5flwzQG.js} +41 -40
- package/dist/ModelProperty-i5flwzQG.js.map +1 -0
- package/dist/{Schema-CX9CTtho.js → Schema-PFZwG9Nl.js} +88 -1623
- package/dist/Schema-PFZwG9Nl.js.map +1 -0
- package/dist/{SchemaValidationService-T5mqnY8q.js → SchemaValidationService-DnGKel4V.js} +7 -6
- package/dist/{SchemaValidationService-T5mqnY8q.js.map → SchemaValidationService-DnGKel4V.js.map} +1 -1
- package/dist/{backfillMetadataPropertyIds-DWWkh-Ex.js → backfillMetadataPropertyIds-BbxgavEQ.js} +4 -4
- package/dist/{backfillMetadataPropertyIds-DWWkh-Ex.js.map → backfillMetadataPropertyIds-BbxgavEQ.js.map} +1 -1
- package/dist/{changeFeed-DcsZ7deG.js → changeFeed-DKdVlUmt.js} +8 -7
- package/dist/changeFeed-DKdVlUmt.js.map +1 -0
- package/dist/configurePlatform-CrMafpMW.js +29 -0
- package/dist/configurePlatform-CrMafpMW.js.map +1 -0
- package/dist/db/drizzle/0024_merge_republished_ghost_seeds.sql +29 -0
- package/dist/db/drizzle/meta/0024_snapshot.json +1645 -0
- package/dist/db/drizzle/meta/_journal.json +7 -0
- package/dist/{detachRowsBeforeDelete-Bo_pky-R.js → detachRowsBeforeDelete-DXFYSHRR.js} +2 -3
- package/dist/{detachRowsBeforeDelete-Bo_pky-R.js.map → detachRowsBeforeDelete-DXFYSHRR.js.map} +1 -1
- package/dist/dist/{ClientManager-B1r_8P5Z.d.ts → ClientManager-GZfXErDX.d.ts} +323 -406
- package/dist/dist/ClientManager-GZfXErDX.d.ts.map +1 -0
- package/dist/dist/{Item-CjTEShfk.d.ts → Item-0oDoTPhi.d.ts} +85 -91
- package/dist/dist/Item-0oDoTPhi.d.ts.map +1 -0
- package/dist/dist/{ModelProperty-C3749Wjq.d.ts → ModelProperty-i5flwzQG.d.ts} +1 -1
- package/dist/dist/{ModelProperty-C3749Wjq.d.ts.map → ModelProperty-i5flwzQG.d.ts.map} +1 -1
- package/dist/dist/{Schema-CX9CTtho.d.ts → Schema-PFZwG9Nl.d.ts} +7 -183
- package/dist/dist/Schema-PFZwG9Nl.d.ts.map +1 -0
- package/dist/dist/{SchemaValidationService-T5mqnY8q.d.ts → SchemaValidationService-DnGKel4V.d.ts} +1 -1
- package/dist/dist/{SchemaValidationService-T5mqnY8q.d.ts.map → SchemaValidationService-DnGKel4V.d.ts.map} +1 -1
- package/dist/dist/{backfillMetadataPropertyIds-DWWkh-Ex.d.ts → backfillMetadataPropertyIds-BbxgavEQ.d.ts} +1 -1
- package/dist/dist/backfillMetadataPropertyIds-BbxgavEQ.d.ts.map +1 -0
- package/dist/dist/{changeFeed-DcsZ7deG.d.ts → changeFeed-DKdVlUmt.d.ts} +17 -20
- package/dist/dist/changeFeed-DKdVlUmt.d.ts.map +1 -0
- package/dist/dist/configurePlatform-CrMafpMW.d.ts +5 -0
- package/dist/dist/configurePlatform-CrMafpMW.d.ts.map +1 -0
- package/dist/dist/{detachRowsBeforeDelete-Bo_pky-R.d.ts → detachRowsBeforeDelete-DXFYSHRR.d.ts} +1 -1
- package/dist/dist/detachRowsBeforeDelete-DXFYSHRR.d.ts.map +1 -0
- package/dist/dist/{eas--9vtNkma.d.ts → eas-dyepi5jz.d.ts} +1 -1
- package/dist/dist/eas-dyepi5jz.d.ts.map +1 -0
- package/dist/dist/{errors-Do7v6RKu.d.ts → errors-C1qUEZ7A.d.ts} +5 -2
- package/dist/dist/errors-C1qUEZ7A.d.ts.map +1 -0
- package/dist/dist/{errors-rIWK7gwJ.d.ts → errors-D1zHAqjr.d.ts} +1 -1
- package/dist/dist/{errors-rIWK7gwJ.d.ts.map → errors-D1zHAqjr.d.ts.map} +1 -1
- package/dist/dist/eventBus-7vxTCc3a.d.ts +18 -0
- package/dist/dist/eventBus-7vxTCc3a.d.ts.map +1 -0
- package/dist/dist/findSeedRowsByUid-CT3sOXXw.d.ts +13 -0
- package/dist/dist/findSeedRowsByUid-CT3sOXXw.d.ts.map +1 -0
- package/dist/dist/{getItem-5j22EWWE.d.ts → getItem-Bhjecbia.d.ts} +1 -1
- package/dist/dist/getItem-Bhjecbia.d.ts.map +1 -0
- package/dist/dist/{getPublishPayload-BGl2SaGK.d.ts → getPublishPayload-DH4rMqXG.d.ts} +1 -1
- package/dist/dist/getPublishPayload-DH4rMqXG.d.ts.map +1 -0
- package/dist/dist/{getPublishUploads-DVsDx6Xf.d.ts → getPublishUploads-BzUIDA2G.d.ts} +5 -5
- package/dist/dist/getPublishUploads-BzUIDA2G.d.ts.map +1 -0
- package/dist/dist/index-CkYb3wcU.d.ts +14 -0
- package/dist/dist/index-CkYb3wcU.d.ts.map +1 -0
- package/dist/dist/{index-Dp4uyZYx.d.ts → index-DJmWkVIK.d.ts} +5 -5
- package/dist/dist/index-DJmWkVIK.d.ts.map +1 -0
- package/dist/dist/{index-C0SetTd1.d.ts → index-Dx_GTdyQ.d.ts} +1457 -1513
- package/dist/dist/index-Dx_GTdyQ.d.ts.map +1 -0
- package/dist/dist/{index-CZQrNqvq.d.ts → index-PbnKw2es.d.ts} +1 -1
- package/dist/dist/{index-CZQrNqvq.d.ts.map → index-PbnKw2es.d.ts.map} +1 -1
- package/dist/dist/{index.browser-Ll71Y_Dl.d.ts → index.browser-i9uPJice.d.ts} +13 -40
- package/dist/dist/{index.browser-Ll71Y_Dl.d.ts.map → index.browser-i9uPJice.d.ts.map} +1 -1
- package/dist/dist/{index.node-CgltN0cC.d.ts → index.node-CzMwMr_d.d.ts} +2 -45
- package/dist/dist/{index.node-CgltN0cC.d.ts.map → index.node-CzMwMr_d.d.ts.map} +1 -1
- package/dist/dist/minimumUpgradeVersion-BDhHvHtr.d.ts +9 -0
- package/dist/dist/minimumUpgradeVersion-BDhHvHtr.d.ts.map +1 -0
- package/dist/dist/{modelPropertyRecordSchemas-C_lYTzMr.d.ts → modelPropertyRecordSchemas-C5lW9aA-.d.ts} +1 -1
- package/dist/dist/modelPropertyRecordSchemas-C5lW9aA-.d.ts.map +1 -0
- package/dist/dist/platform.browser.d.ts +2 -2
- package/dist/dist/platform.node.d.ts +2 -2
- package/dist/dist/{property-pcDxNEpy.d.ts → property-BwYtg5Q_.d.ts} +3 -3
- package/dist/dist/property-BwYtg5Q_.d.ts.map +1 -0
- package/dist/dist/{propertyValidationRules-BEjN0f3-.d.ts → propertyValidationRules-CyHdpcPP.d.ts} +1 -1
- package/dist/dist/propertyValidationRules-CyHdpcPP.d.ts.map +1 -0
- package/dist/dist/{publishDraftGraph-I5yKe1Xz.d.ts → publishDraftGraph-C5F6b7GK.d.ts} +23 -6
- package/dist/dist/publishDraftGraph-C5F6b7GK.d.ts.map +1 -0
- package/dist/dist/{resolveModelForSyncedSeed-C5KXn6ex.d.ts → resolveModelForSyncedSeed-4gO9Hfn2.d.ts} +1 -1
- package/dist/dist/resolveModelForSyncedSeed-4gO9Hfn2.d.ts.map +1 -0
- package/dist/dist/syncDbWithEas-DUu_wjUG.d.ts +13 -0
- package/dist/dist/syncDbWithEas-DUu_wjUG.d.ts.map +1 -0
- package/dist/dist/{tolerantWebAccess-CIpS7RLk.d.ts → tolerantWebAccess-DecKDGen.d.ts} +1 -1
- package/dist/dist/{tolerantWebAccess-CIpS7RLk.d.ts.map → tolerantWebAccess-DecKDGen.d.ts.map} +1 -1
- package/dist/dist/{updateSeedRevokedAt-CR4zwn-6.d.ts → updateSeedRevokedAt-CP606vKs.d.ts} +1 -1
- package/dist/dist/updateSeedRevokedAt-CP606vKs.d.ts.map +1 -0
- package/dist/{eas--9vtNkma.js → eas-dyepi5jz.js} +3 -4
- package/dist/eas-dyepi5jz.js.map +1 -0
- package/dist/{errors-Do7v6RKu.js → errors-C1qUEZ7A.js} +12 -6
- package/dist/errors-C1qUEZ7A.js.map +1 -0
- package/dist/{errors-rIWK7gwJ.js → errors-D1zHAqjr.js} +46 -98
- package/dist/errors-D1zHAqjr.js.map +1 -0
- package/dist/eventBus-7vxTCc3a.js +64 -0
- package/dist/eventBus-7vxTCc3a.js.map +1 -0
- package/dist/findSeedRowsByUid-CT3sOXXw.js +47 -0
- package/dist/findSeedRowsByUid-CT3sOXXw.js.map +1 -0
- package/dist/{getItem-5j22EWWE.js → getItem-Bhjecbia.js} +5 -5
- package/dist/{getItem-5j22EWWE.js.map → getItem-Bhjecbia.js.map} +1 -1
- package/dist/{getPublishPayload-BGl2SaGK.js → getPublishPayload-DH4rMqXG.js} +27 -27
- package/dist/getPublishPayload-DH4rMqXG.js.map +1 -0
- package/dist/{getPublishUploads-DVsDx6Xf.js → getPublishUploads-BzUIDA2G.js} +64 -95
- package/dist/getPublishUploads-BzUIDA2G.js.map +1 -0
- package/dist/{index-CJK3F_MK.js → index-CkYb3wcU.js} +9 -8
- package/dist/index-CkYb3wcU.js.map +1 -0
- package/dist/{index-Dp4uyZYx.js → index-DJmWkVIK.js} +9 -8
- package/dist/index-DJmWkVIK.js.map +1 -0
- package/dist/{index-C0SetTd1.js → index-Dx_GTdyQ.js} +27 -463
- package/dist/index-Dx_GTdyQ.js.map +1 -0
- package/dist/{index-CZQrNqvq.js → index-PbnKw2es.js} +2 -2
- package/dist/index-PbnKw2es.js.map +1 -0
- package/dist/{index.browser-Ll71Y_Dl.js → index.browser-i9uPJice.js} +239 -179
- package/dist/index.browser-i9uPJice.js.map +1 -0
- package/dist/{index.node-CgltN0cC.js → index.node-CzMwMr_d.js} +51 -216
- package/dist/index.node-CzMwMr_d.js.map +1 -0
- package/dist/main.js +165 -241
- package/dist/main.js.map +1 -1
- package/dist/minimumUpgradeVersion-BDhHvHtr.js +81 -0
- package/dist/minimumUpgradeVersion-BDhHvHtr.js.map +1 -0
- package/dist/{modelPropertyRecordSchemas-C_lYTzMr.js → modelPropertyRecordSchemas-C5lW9aA-.js} +5 -5
- package/dist/{modelPropertyRecordSchemas-C_lYTzMr.js.map → modelPropertyRecordSchemas-C5lW9aA-.js.map} +1 -1
- package/dist/node.js +14 -221
- package/dist/node.js.map +1 -1
- package/dist/platform.browser.js +8 -7
- package/dist/platform.browser.js.map +1 -1
- package/dist/platform.node.js +7 -7
- package/dist/{property-pcDxNEpy.js → property-BwYtg5Q_.js} +8 -9
- package/dist/property-BwYtg5Q_.js.map +1 -0
- package/dist/{propertyValidationRules-BEjN0f3-.js → propertyValidationRules-CyHdpcPP.js} +10 -10
- package/dist/{propertyValidationRules-BEjN0f3-.js.map → propertyValidationRules-CyHdpcPP.js.map} +1 -1
- package/dist/{publishDraftGraph-I5yKe1Xz.js → publishDraftGraph-C5F6b7GK.js} +104 -35
- package/dist/publishDraftGraph-C5F6b7GK.js.map +1 -0
- package/dist/{resolveModelForSyncedSeed-C5KXn6ex.js → resolveModelForSyncedSeed-4gO9Hfn2.js} +3 -2
- package/dist/{resolveModelForSyncedSeed-C5KXn6ex.js.map → resolveModelForSyncedSeed-4gO9Hfn2.js.map} +1 -1
- package/dist/seedSchema/PendingWriteSchema.ts +3 -2
- package/dist/src/Item/Item.d.ts +1 -0
- package/dist/src/Item/Item.d.ts.map +1 -1
- package/dist/src/Item/service/actors/runPublish.d.ts.map +1 -1
- package/dist/src/ItemProperty/ItemProperty.d.ts +2 -2
- package/dist/src/ItemProperty/ItemProperty.d.ts.map +1 -1
- package/dist/src/ItemProperty/service/propertyMachine.d.ts +1 -1
- package/dist/src/ItemProperty/service/propertyMachine.d.ts.map +1 -1
- package/dist/src/Model/Model.d.ts.map +1 -1
- package/dist/src/Model/service/modelMachine.d.ts +0 -20
- package/dist/src/Model/service/modelMachine.d.ts.map +1 -1
- package/dist/src/ModelProperty/service/modelPropertyMachine.d.ts +0 -20
- package/dist/src/ModelProperty/service/modelPropertyMachine.d.ts.map +1 -1
- package/dist/src/Schema/service/schemaMachine.d.ts +1 -107
- package/dist/src/Schema/service/schemaMachine.d.ts.map +1 -1
- package/dist/src/Schema/validation.d.ts +0 -1
- package/dist/src/Schema/validation.d.ts.map +1 -1
- package/dist/src/browser/db/Db.d.ts +8 -3
- package/dist/src/browser/db/Db.d.ts.map +1 -1
- package/dist/src/browser/db/createSqlocalDrizzle.d.ts +20 -2
- package/dist/src/browser/db/createSqlocalDrizzle.d.ts.map +1 -1
- package/dist/src/browser/db/drizzleFiles.d.ts +3 -2
- package/dist/src/browser/db/drizzleFiles.d.ts.map +1 -1
- package/dist/src/browser/workers/FileDownloader.d.ts +1 -1
- package/dist/src/browser/workers/FileDownloader.d.ts.map +1 -1
- package/dist/src/browser/workers/filesDownload.d.ts.map +1 -1
- package/dist/src/client/actors/fileSystemInit.d.ts.map +1 -1
- package/dist/src/client/actors/platformClassesInit.d.ts +1 -1
- package/dist/src/client/actors/platformClassesInit.d.ts.map +1 -1
- package/dist/src/client/actors/processSchemaFiles.d.ts.map +1 -1
- package/dist/src/client/clientManagerMachine.d.ts.map +1 -1
- package/dist/src/client/constants.d.ts +0 -51
- package/dist/src/client/constants.d.ts.map +1 -1
- package/dist/src/db/minimumUpgradeVersion.d.ts +33 -0
- package/dist/src/db/minimumUpgradeVersion.d.ts.map +1 -0
- package/dist/src/db/read/batchLatestPublishedVersionBySeedLocalIds.d.ts +2 -1
- package/dist/src/db/read/batchLatestPublishedVersionBySeedLocalIds.d.ts.map +1 -1
- package/dist/src/db/read/findSeedRowsByUid.d.ts +13 -0
- package/dist/src/db/read/findSeedRowsByUid.d.ts.map +1 -0
- package/dist/src/db/read/getItemData.d.ts.map +1 -1
- package/dist/src/db/read/getLatestPublishedVersionRow.d.ts +2 -1
- package/dist/src/db/read/getLatestPublishedVersionRow.d.ts.map +1 -1
- package/dist/src/db/read/getLatestVersionRow.d.ts +1 -1
- package/dist/src/db/read/getLatestVersionRow.d.ts.map +1 -1
- package/dist/src/db/read/getPublishPayload.d.ts +4 -0
- package/dist/src/db/read/getPublishPayload.d.ts.map +1 -1
- package/dist/src/db/read/getPublishUploads.d.ts +1 -3
- package/dist/src/db/read/getPublishUploads.d.ts.map +1 -1
- package/dist/src/db/read/getRelatedItemsForPublish.d.ts +2 -0
- package/dist/src/db/read/getRelatedItemsForPublish.d.ts.map +1 -1
- package/dist/src/db/read/itemLoads.d.ts +20 -0
- package/dist/src/db/read/itemLoads.d.ts.map +1 -0
- package/dist/src/db/read/publishDraftGraph.d.ts +7 -0
- package/dist/src/db/read/publishDraftGraph.d.ts.map +1 -1
- package/dist/src/db/read/resolveRelatedSeedRef.d.ts +4 -4
- package/dist/src/db/read/resolveRelatedSeedRef.d.ts.map +1 -1
- package/dist/src/db/read/subqueries/latestVersion.d.ts +14 -0
- package/dist/src/db/read/subqueries/latestVersion.d.ts.map +1 -0
- package/dist/src/db/read/subqueries/versionData.d.ts +2 -2
- package/dist/src/db/read/subqueries/versionData.d.ts.map +1 -1
- package/dist/src/db/read/summarizePublishWork.d.ts.map +1 -1
- package/dist/src/db/write/applyPropertyAttestationUidsFromPublish.d.ts +6 -0
- package/dist/src/db/write/applyPropertyAttestationUidsFromPublish.d.ts.map +1 -1
- package/dist/src/db/write/easSyncProcess.d.ts +1 -1
- package/dist/src/db/write/easSyncProcess.d.ts.map +1 -1
- package/dist/src/db/write/updateVersionUid.d.ts +2 -2
- package/dist/src/db/write/updateVersionUid.d.ts.map +1 -1
- package/dist/src/events/files/download.d.ts +1 -10
- package/dist/src/events/files/download.d.ts.map +1 -1
- package/dist/src/events/item/easSyncManager.d.ts +0 -1
- package/dist/src/events/item/easSyncManager.d.ts.map +1 -1
- package/dist/src/events/item/index.d.ts.map +1 -1
- package/dist/src/events/item/syncDbWithEas.d.ts +0 -10
- package/dist/src/events/item/syncDbWithEas.d.ts.map +1 -1
- package/dist/src/helpers/FileManager/BaseFileManager.d.ts +1 -1
- package/dist/src/helpers/FileManager/BaseFileManager.d.ts.map +1 -1
- package/dist/src/helpers/FileManager/IFileManager.d.ts +7 -0
- package/dist/src/helpers/FileManager/IFileManager.d.ts.map +1 -1
- package/dist/src/helpers/FileManager/errors.d.ts +4 -1
- package/dist/src/helpers/FileManager/errors.d.ts.map +1 -1
- package/dist/src/helpers/arweaveContentTags.d.ts +1 -2
- package/dist/src/helpers/arweaveContentTags.d.ts.map +1 -1
- package/dist/src/helpers/constants.d.ts +3 -12
- package/dist/src/helpers/constants.d.ts.map +1 -1
- package/dist/src/helpers/db.d.ts +3 -28
- package/dist/src/helpers/db.d.ts.map +1 -1
- package/dist/src/helpers/ethereumUtils.d.ts +0 -2
- package/dist/src/helpers/ethereumUtils.d.ts.map +1 -1
- package/dist/src/helpers/htmlEmbeddedDataUriPublish.d.ts +2 -1
- package/dist/src/helpers/htmlEmbeddedDataUriPublish.d.ts.map +1 -1
- package/dist/src/helpers/index.d.ts +0 -7
- package/dist/src/helpers/index.d.ts.map +1 -1
- package/dist/src/helpers/itemStorageFile.d.ts +2 -2
- package/dist/src/helpers/reconcilePropertyDraftRows.d.ts +2 -1
- package/dist/src/helpers/reconcilePropertyDraftRows.d.ts.map +1 -1
- package/dist/src/helpers/schema.d.ts +0 -73
- package/dist/src/helpers/schema.d.ts.map +1 -1
- package/dist/src/helpers/updateSchema.d.ts +0 -46
- package/dist/src/helpers/updateSchema.d.ts.map +1 -1
- package/dist/src/imports/index.d.ts +0 -1
- package/dist/src/imports/index.d.ts.map +1 -1
- package/dist/src/imports/json.d.ts +2 -1
- package/dist/src/imports/json.d.ts.map +1 -1
- package/dist/src/index.d.ts +4 -6
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/node/db/Db.d.ts.map +1 -1
- package/dist/src/node/helpers/dotSeedDir.d.ts +7 -0
- package/dist/src/node/helpers/dotSeedDir.d.ts.map +1 -0
- package/dist/src/node/index.d.ts +0 -5
- package/dist/src/node/index.d.ts.map +1 -1
- package/dist/src/outbox/index.d.ts +1 -1
- package/dist/src/outbox/index.d.ts.map +1 -1
- package/dist/src/outbox/itemAppliers.d.ts.map +1 -1
- package/dist/src/outbox/outbox.d.ts +3 -19
- package/dist/src/outbox/outbox.d.ts.map +1 -1
- package/dist/src/platform/configurePlatform.d.ts.map +1 -1
- package/dist/src/platform/index.browser.d.ts.map +1 -1
- package/dist/src/platform/index.node.d.ts.map +1 -1
- package/dist/src/platform/types.d.ts +0 -2
- package/dist/src/platform/types.d.ts.map +1 -1
- package/dist/src/query/createLocalQueryDataSource.d.ts.map +1 -1
- package/dist/src/seedSchema/PendingWriteSchema.d.ts.map +1 -1
- package/dist/src/services/write/actors/validateEntity.d.ts +1 -1
- package/dist/src/services/write/actors/validateEntity.d.ts.map +1 -1
- package/dist/src/services/write/actors/writeToDatabase.d.ts.map +1 -1
- package/dist/src/services/write/writeProcessMachine.d.ts +1 -23
- package/dist/src/services/write/writeProcessMachine.d.ts.map +1 -1
- package/dist/src/stores/eas.d.ts +0 -1
- package/dist/src/stores/eas.d.ts.map +1 -1
- package/dist/src/types/index.d.ts +1 -18
- package/dist/src/types/index.d.ts.map +1 -1
- package/dist/src/types/machines.d.ts +1 -32
- package/dist/src/types/machines.d.ts.map +1 -1
- package/dist/{syncDbWithEas-b4fESZ7C.js → syncDbWithEas-DUu_wjUG.js} +37 -105
- package/dist/syncDbWithEas-DUu_wjUG.js.map +1 -0
- package/dist/{tolerantWebAccess-CIpS7RLk.js → tolerantWebAccess-DecKDGen.js} +9 -8
- package/dist/{tolerantWebAccess-CIpS7RLk.js.map → tolerantWebAccess-DecKDGen.js.map} +1 -1
- package/dist/{updateSeedRevokedAt-CR4zwn-6.js → updateSeedRevokedAt-CP606vKs.js} +3 -3
- package/dist/{updateSeedRevokedAt-CR4zwn-6.js.map → updateSeedRevokedAt-CP606vKs.js.map} +1 -1
- package/package.json +6 -8
- package/dist/ClientManager-B1r_8P5Z.js.map +0 -1
- package/dist/Item-CjTEShfk.js.map +0 -1
- package/dist/ModelProperty-C3749Wjq.js.map +0 -1
- package/dist/Schema-CX9CTtho.js.map +0 -1
- package/dist/changeFeed-DcsZ7deG.js.map +0 -1
- package/dist/configurePlatform-AWild9o4.js +0 -81
- package/dist/configurePlatform-AWild9o4.js.map +0 -1
- package/dist/dist/ClientManager-B1r_8P5Z.d.ts.map +0 -1
- package/dist/dist/Item-CjTEShfk.d.ts.map +0 -1
- package/dist/dist/Schema-CX9CTtho.d.ts.map +0 -1
- package/dist/dist/backfillMetadataPropertyIds-DWWkh-Ex.d.ts.map +0 -1
- package/dist/dist/changeFeed-DcsZ7deG.d.ts.map +0 -1
- package/dist/dist/configurePlatform-AWild9o4.d.ts +0 -30
- package/dist/dist/configurePlatform-AWild9o4.d.ts.map +0 -1
- package/dist/dist/detachRowsBeforeDelete-Bo_pky-R.d.ts.map +0 -1
- package/dist/dist/eas--9vtNkma.d.ts.map +0 -1
- package/dist/dist/errors-Do7v6RKu.d.ts.map +0 -1
- package/dist/dist/getItem-5j22EWWE.d.ts.map +0 -1
- package/dist/dist/getPublishPayload-BGl2SaGK.d.ts.map +0 -1
- package/dist/dist/getPublishUploads-DVsDx6Xf.d.ts.map +0 -1
- package/dist/dist/index-C0SetTd1.d.ts.map +0 -1
- package/dist/dist/index-CJK3F_MK.d.ts +0 -14
- package/dist/dist/index-CJK3F_MK.d.ts.map +0 -1
- package/dist/dist/index-Dp4uyZYx.d.ts.map +0 -1
- package/dist/dist/modelPropertyRecordSchemas-C_lYTzMr.d.ts.map +0 -1
- package/dist/dist/property-pcDxNEpy.d.ts.map +0 -1
- package/dist/dist/propertyValidationRules-BEjN0f3-.d.ts.map +0 -1
- package/dist/dist/publishDraftGraph-I5yKe1Xz.d.ts.map +0 -1
- package/dist/dist/resetAmbiguousLegacyItemData-0Tin9-JK.d.ts +0 -17
- package/dist/dist/resetAmbiguousLegacyItemData-0Tin9-JK.d.ts.map +0 -1
- package/dist/dist/resolveModelForSyncedSeed-C5KXn6ex.d.ts.map +0 -1
- package/dist/dist/syncDbWithEas-b4fESZ7C.d.ts +0 -22
- package/dist/dist/syncDbWithEas-b4fESZ7C.d.ts.map +0 -1
- package/dist/dist/updateSeedRevokedAt-CR4zwn-6.d.ts.map +0 -1
- package/dist/eas--9vtNkma.js.map +0 -1
- package/dist/errors-Do7v6RKu.js.map +0 -1
- package/dist/errors-rIWK7gwJ.js.map +0 -1
- package/dist/getPublishPayload-BGl2SaGK.js.map +0 -1
- package/dist/getPublishUploads-DVsDx6Xf.js.map +0 -1
- package/dist/index-C0SetTd1.js.map +0 -1
- package/dist/index-CJK3F_MK.js.map +0 -1
- package/dist/index-CZQrNqvq.js.map +0 -1
- package/dist/index-Dp4uyZYx.js.map +0 -1
- package/dist/index.browser-Ll71Y_Dl.js.map +0 -1
- package/dist/index.node-CgltN0cC.js.map +0 -1
- package/dist/property-pcDxNEpy.js.map +0 -1
- package/dist/publishDraftGraph-I5yKe1Xz.js.map +0 -1
- package/dist/resetAmbiguousLegacyItemData-0Tin9-JK.js +0 -98
- package/dist/resetAmbiguousLegacyItemData-0Tin9-JK.js.map +0 -1
- package/dist/src/Schema/service/actors/loadOrCreateSchema.d.ts +0 -5
- package/dist/src/Schema/service/actors/loadOrCreateSchema.d.ts.map +0 -1
- package/dist/src/browser/db/sqlWasmClient.d.ts +0 -1
- package/dist/src/browser/db/sqlWasmClient.d.ts.map +0 -1
- package/dist/src/browser/helpers/PathResolver.d.ts +0 -41
- package/dist/src/browser/helpers/PathResolver.d.ts.map +0 -1
- package/dist/src/browser/index.d.ts +0 -3
- package/dist/src/browser/index.d.ts.map +0 -1
- package/dist/src/browser/seed.d.ts +0 -21
- package/dist/src/browser/seed.d.ts.map +0 -1
- package/dist/src/browser/workers/content-hash.d.ts +0 -2
- package/dist/src/browser/workers/content-hash.d.ts.map +0 -1
- package/dist/src/browser/workers/dbWorker.d.ts +0 -1
- package/dist/src/browser/workers/dbWorker.d.ts.map +0 -1
- package/dist/src/client/BaseClientManager.d.ts +0 -7
- package/dist/src/client/BaseClientManager.d.ts.map +0 -1
- package/dist/src/client/actions/setAddresses.d.ts +0 -2
- package/dist/src/client/actions/setAddresses.d.ts.map +0 -1
- package/dist/src/db/alignRowPublishers.d.ts +0 -25
- package/dist/src/db/alignRowPublishers.d.ts.map +0 -1
- package/dist/src/db/clearStoredDisplayUrls.d.ts +0 -18
- package/dist/src/db/clearStoredDisplayUrls.d.ts.map +0 -1
- package/dist/src/db/migrateLegacyItemStorageRows.d.ts +0 -57
- package/dist/src/db/migrateLegacyItemStorageRows.d.ts.map +0 -1
- package/dist/src/db/read/getExistingItem.d.ts +0 -12
- package/dist/src/db/read/getExistingItem.d.ts.map +0 -1
- package/dist/src/db/read/getModels.d.ts +0 -5
- package/dist/src/db/read/getModels.d.ts.map +0 -1
- package/dist/src/db/read/getVersionsForVersionUids.d.ts +0 -10
- package/dist/src/db/read/getVersionsForVersionUids.d.ts.map +0 -1
- package/dist/src/db/removeForeignAttestationRows.d.ts +0 -27
- package/dist/src/db/removeForeignAttestationRows.d.ts.map +0 -1
- package/dist/src/db/resetAmbiguousLegacyItemData.d.ts +0 -17
- package/dist/src/db/resetAmbiguousLegacyItemData.d.ts.map +0 -1
- package/dist/src/db/write/applyArweaveL1TransactionIdLocal.d.ts +0 -14
- package/dist/src/db/write/applyArweaveL1TransactionIdLocal.d.ts.map +0 -1
- package/dist/src/db/write/convertVerbatimItemStorageRow.d.ts +0 -44
- package/dist/src/db/write/convertVerbatimItemStorageRow.d.ts.map +0 -1
- package/dist/src/db/write/restoreDataItemIdsOverwrittenByL1.d.ts +0 -18
- package/dist/src/db/write/restoreDataItemIdsOverwrittenByL1.d.ts.map +0 -1
- package/dist/src/db/write/saveAppState.d.ts +0 -2
- package/dist/src/db/write/saveAppState.d.ts.map +0 -1
- package/dist/src/eslint-rules/align-imports.d.ts +0 -12
- package/dist/src/eslint-rules/align-imports.d.ts.map +0 -1
- package/dist/src/events/files/index.d.ts +0 -4
- package/dist/src/events/files/index.d.ts.map +0 -1
- package/dist/src/events/index.d.ts +0 -13
- package/dist/src/events/index.d.ts.map +0 -1
- package/dist/src/events/services/allItems.d.ts +0 -6
- package/dist/src/events/services/allItems.d.ts.map +0 -1
- package/dist/src/events/services/index.d.ts +0 -3
- package/dist/src/events/services/index.d.ts.map +0 -1
- package/dist/src/helpers/ArweaveClient/index.d.ts +0 -30
- package/dist/src/helpers/ArweaveClient/index.d.ts.map +0 -1
- package/dist/src/helpers/PathResolver/BasePathResolver.d.ts +0 -26
- package/dist/src/helpers/PathResolver/BasePathResolver.d.ts.map +0 -1
- package/dist/src/helpers/PathResolver/IPathResolver.d.ts +0 -16
- package/dist/src/helpers/PathResolver/IPathResolver.d.ts.map +0 -1
- package/dist/src/helpers/easRevokedFilter.d.ts +0 -2
- package/dist/src/helpers/easRevokedFilter.d.ts.map +0 -1
- package/dist/src/helpers/file/fetchAll/actors.d.ts +0 -16
- package/dist/src/helpers/file/fetchAll/actors.d.ts.map +0 -1
- package/dist/src/helpers/file/fetchAll/index.d.ts +0 -58
- package/dist/src/helpers/file/fetchAll/index.d.ts.map +0 -1
- package/dist/src/helpers/files.d.ts +0 -10
- package/dist/src/helpers/files.d.ts.map +0 -1
- package/dist/src/helpers/updateMachineContext.d.ts +0 -7
- package/dist/src/helpers/updateMachineContext.d.ts.map +0 -1
- package/dist/src/imports/markdown.d.ts +0 -40
- package/dist/src/imports/markdown.d.ts.map +0 -1
- package/dist/src/node/constants.d.ts +0 -2
- package/dist/src/node/constants.d.ts.map +0 -1
- package/dist/src/node/db/index.d.ts +0 -5
- package/dist/src/node/db/index.d.ts.map +0 -1
- package/dist/src/node/helpers/PathResolver.d.ts +0 -44
- package/dist/src/node/helpers/PathResolver.d.ts.map +0 -1
- package/dist/src/node/helpers/scripts.d.ts +0 -14
- package/dist/src/node/helpers/scripts.d.ts.map +0 -1
- package/dist/src/node/seed.d.ts +0 -1
- package/dist/src/node/seed.d.ts.map +0 -1
- package/dist/src/node/webpack/fs-proxy.d.ts +0 -4
- package/dist/src/node/webpack/fs-proxy.d.ts.map +0 -1
- package/dist/src/node/webpack/index.d.ts +0 -7
- package/dist/src/node/webpack/index.d.ts.map +0 -1
- package/dist/src/services/events.d.ts +0 -2
- package/dist/src/services/events.d.ts.map +0 -1
- package/dist/src/testing/platformTestHandle.d.ts +0 -8
- package/dist/src/testing/platformTestHandle.d.ts.map +0 -1
- package/dist/src/types/browser.d.ts +0 -24
- package/dist/src/types/browser.d.ts.map +0 -1
- package/dist/src/types/seedProtocol.d.ts +0 -16
- package/dist/src/types/seedProtocol.d.ts.map +0 -1
- package/dist/src/types/services.d.ts +0 -1
- package/dist/src/types/services.d.ts.map +0 -1
- package/dist/syncDbWithEas-b4fESZ7C.js.map +0 -1
|
@@ -1,15 +1,16 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { isEqual } from 'lodash-es';
|
|
2
|
+
import { L as BaseDb, u as easSyncProcesses, am as isBrowser, $ as isNode, aA as normalizeAddressConfig, aQ as isTestOrSeedDev, h as appState, Q as BaseFileManager, aa as loadNameMatchLevels, p as models$1, o as modelUids, s as seeds, aB as normalizeAddressList, J as schemas, aL as loadModelsFromDbForSchema, aN as addSchemaToDb, aF as isInternalSchema, ad as generateId, aR as warnOnInvalidNameMatch, aS as INTERNAL_SCHEMA_IDS, aT as linkModelToSchema, n as normalizeDataType, a7 as easPropertyNameForPublish, aq as SEED_PROTOCOL_SCHEMA_NAME, z as modelSchemas, v as versions, m as metadata$1, Z as getItemStorageSubdir, _ as getItemStorageLocalFileName, C as pendingWrites, aU as getMetadataPropertyNamesForQuery, x as htmlEmbeddedImageCoPublish, t as arweaveL1FinalizeJobs, I as publishProcesses, a8 as normalizePublisher, aV as getWatchedAddressesFromDb, aW as getOwnedAddressesFromDb, aX as CLIENT_NOT_INITIALIZED } from './index-Dx_GTdyQ.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,
|
|
7
|
-
import { d as withDbTabLock, a as isLeaderTab, k as postTabMessage, o as onTabMessage, c as whenLeaderTab, l as listenForOtherTabsEvents, m as startTabCoordination, g as withSeedDbLock, e as emitAcrossTabs, A as ADDRESSES_PERSISTED_EVENT, q as tryWithTabLock, r as
|
|
5
|
+
import { X as MachineIds, am as ClientManagerEvents, an as getSeedPublisher, ao as propertyNameVariants, M as METADATA_LATEST_FIRST_ORDER_SQL, z as selectInBatches, ap as createSeed, aq as createMetadata, C as compareMetadataRowsLatestFirst, ar as updateItemPropertyValue, r as registerOutboxApplier, n as outboxOpValue, i as OutboxOpDeferredError, s as startOutbox, j as OutboxOpFailedError, u as OwnershipError, x as isItemOwned, F as parseListPropertyValueFromStorage, W as ClientManagerState, as as resolvePublisherFromSeedRow, a4 as isLocalUnsealedDraft, y as writeInBatches, I as Item } from './Item-0oDoTPhi.js';
|
|
6
|
+
import { eq, inArray, and, isNotNull, ne, desc, countDistinct, isNull, sql, lt, or, like } from 'drizzle-orm';
|
|
7
|
+
import { d as withDbTabLock, a as isLeaderTab, k as postTabMessage, o as onTabMessage, c as whenLeaderTab, l as listenForOtherTabsEvents, m as startTabCoordination, g as withSeedDbLock, e as emitAcrossTabs, A as ADDRESSES_PERSISTED_EVENT, q as tryWithTabLock, r as notifyFileSaved, p as parseAddressesPersistedPayload, L as LOCAL_COPIES_REMOVED_EVENT } from './changeFeed-DKdVlUmt.js';
|
|
8
8
|
import { seedGatewayConfigFromSeedConfig, setPreferredArweaveReadBaseUrls, resolveSeedGatewayEndpoints, setResolvedSeedGatewayEndpoints, BaseArweaveClient, ensureReadGatewaySelected, DEFAULT_ARWEAVE_HOST } from '@seedprotocol/arweave';
|
|
9
|
-
import { configureEasReadChain, easName, BaseQueryClient, BaseEasClient, GET_SCHEMAS, whenEasReadChainSettled, getEasReadChainId, DEFAULT_EAS_CHAIN_ID, isEasReadChainConfigured,
|
|
9
|
+
import { configureEasReadChain, easName, BaseQueryClient, BaseEasClient, GET_SCHEMAS, whenEasReadChainSettled, getEasReadChainId, DEFAULT_EAS_CHAIN_ID, isEasReadChainConfigured, localNamesInBestMatchTier, isPlaceholderUid, isValidEasAttestationUid } from '@seedprotocol/eas';
|
|
10
10
|
import 'pluralize';
|
|
11
11
|
import { sha3_256 } from '@noble/hashes/sha3';
|
|
12
12
|
import { utf8ToBytes, bytesToHex } from '@noble/hashes/utils';
|
|
13
|
+
import { e as eventEmitter } from './eventBus-7vxTCc3a.js';
|
|
13
14
|
import { clearLocalQuerySource, registerLocalQuerySource, getSeed } from '@seedprotocol/query';
|
|
14
15
|
|
|
15
16
|
let writeTail = Promise.resolve();
|
|
@@ -212,7 +213,7 @@ function toRunSyncArg(options) {
|
|
|
212
213
|
return undefined;
|
|
213
214
|
}
|
|
214
215
|
const runEasSync = fromPromise(async ({ input, }) => {
|
|
215
|
-
const { runSyncFromEas } = await import('./syncDbWithEas-
|
|
216
|
+
const { runSyncFromEas } = await import('./syncDbWithEas-DUu_wjUG.js');
|
|
216
217
|
// Sync checks for rows and then inserts the rest (no unique index on uids), so syncs in
|
|
217
218
|
// different tabs take turns. A sync can run for minutes, so wait without a timeout.
|
|
218
219
|
await withDbTabLock('eas-sync', async () => {
|
|
@@ -271,7 +272,8 @@ const syncRetry = createRetryWhenOnline(() => {
|
|
|
271
272
|
const initialContext = {
|
|
272
273
|
runOptions: {},
|
|
273
274
|
activeCorrelationIds: [],
|
|
274
|
-
|
|
275
|
+
// Replaced by the first request's source before any run.
|
|
276
|
+
activePrimarySource: 'models_init',
|
|
275
277
|
pendingMergedOptions: undefined,
|
|
276
278
|
pendingCorrelationIds: [],
|
|
277
279
|
pendingPrimarySource: null,
|
|
@@ -394,7 +396,7 @@ const easSyncMachine = setup({
|
|
|
394
396
|
activeCorrelationIds: ({ context }) => [
|
|
395
397
|
...context.pendingCorrelationIds,
|
|
396
398
|
],
|
|
397
|
-
activePrimarySource: ({ context }) => context.pendingPrimarySource ?? '
|
|
399
|
+
activePrimarySource: ({ context }) => context.pendingPrimarySource ?? 'models_init',
|
|
398
400
|
pendingMergedOptions: () => undefined,
|
|
399
401
|
pendingCorrelationIds: () => [],
|
|
400
402
|
pendingPrimarySource: () => null,
|
|
@@ -422,7 +424,7 @@ function newCorrelationId() {
|
|
|
422
424
|
return `${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
423
425
|
}
|
|
424
426
|
/** Requests deferred in this tab until it leads, by source; each runs once on takeover. */
|
|
425
|
-
const deferredUntilLeader$
|
|
427
|
+
const deferredUntilLeader$1 = new Set();
|
|
426
428
|
/**
|
|
427
429
|
* Automatic syncs run in the leader tab only (docs/MULTI_TAB.md). A tab that skips one runs it if
|
|
428
430
|
* it later becomes leader, so closing the leader doesn't lose the catch-up sync.
|
|
@@ -433,11 +435,11 @@ function runInLeaderTab(source, request) {
|
|
|
433
435
|
return;
|
|
434
436
|
}
|
|
435
437
|
log(`${source} sync skipped: another tab leads`);
|
|
436
|
-
if (deferredUntilLeader$
|
|
438
|
+
if (deferredUntilLeader$1.has(source))
|
|
437
439
|
return;
|
|
438
|
-
deferredUntilLeader$
|
|
440
|
+
deferredUntilLeader$1.add(source);
|
|
439
441
|
void whenLeaderTab().then(() => {
|
|
440
|
-
deferredUntilLeader$
|
|
442
|
+
deferredUntilLeader$1.delete(source);
|
|
441
443
|
request();
|
|
442
444
|
});
|
|
443
445
|
}
|
|
@@ -453,17 +455,6 @@ function listenForEasSyncRequestsFromOtherTabs() {
|
|
|
453
455
|
}
|
|
454
456
|
});
|
|
455
457
|
}
|
|
456
|
-
function requestEasSyncFromEventBus() {
|
|
457
|
-
runInLeaderTab('event_bus', sendEventBusRequest);
|
|
458
|
-
}
|
|
459
|
-
function sendEventBusRequest() {
|
|
460
|
-
startEasSyncActor();
|
|
461
|
-
easSyncActor.send({
|
|
462
|
-
type: 'REQUEST',
|
|
463
|
-
correlationId: newCorrelationId(),
|
|
464
|
-
source: 'event_bus',
|
|
465
|
-
});
|
|
466
|
-
}
|
|
467
458
|
function requestEasSyncFromAddressChange(addresses) {
|
|
468
459
|
if (!isLeaderTab()) {
|
|
469
460
|
// The leader syncs these addresses; its own address list may be stale.
|
|
@@ -505,43 +496,18 @@ var easSyncManager = /*#__PURE__*/Object.freeze({
|
|
|
505
496
|
easSyncMachine: easSyncMachine,
|
|
506
497
|
listenForEasSyncRequestsFromOtherTabs: listenForEasSyncRequestsFromOtherTabs,
|
|
507
498
|
requestEasSyncFromAddressChange: requestEasSyncFromAddressChange,
|
|
508
|
-
requestEasSyncFromEventBus: requestEasSyncFromEventBus,
|
|
509
499
|
requestEasSyncFromModelsInit: requestEasSyncFromModelsInit,
|
|
510
500
|
sendEasSyncClientRequest: sendEasSyncClientRequest,
|
|
511
501
|
startEasSyncActor: startEasSyncActor
|
|
512
502
|
});
|
|
513
503
|
|
|
514
|
-
const logger$g = debug('seedSdk:services:events');
|
|
515
|
-
const handleServiceSaveState = (event) => {
|
|
516
|
-
const { serviceId } = event;
|
|
517
|
-
logger$g(`[browser] [service.saveState.request] serviceId: ${serviceId}`);
|
|
518
|
-
// TODO: This is called from Node as well. Do we need it? If so, need to generalize this to all platforms.
|
|
519
|
-
// localStorage.setItem(`seed_sdk_service_${serviceId}`, JSON.stringify(state))
|
|
520
|
-
};
|
|
521
|
-
const setupServicesEventHandlers = () => {
|
|
522
|
-
eventEmitter.addListener('service.saveState.request', handleServiceSaveState);
|
|
523
|
-
};
|
|
524
|
-
|
|
525
504
|
const setupAllItemsEventHandlers = () => {
|
|
526
505
|
startEasSyncActor();
|
|
527
506
|
listenForEasSyncRequestsFromOtherTabs();
|
|
528
507
|
listenForOtherTabsEvents();
|
|
529
|
-
eventEmitter.addListener('syncDbWithEas', requestEasSyncFromEventBus);
|
|
530
508
|
};
|
|
531
509
|
// Note: getAreItemEventHandlersReady removed - was only used by useItemIsReady hook which has been removed
|
|
532
510
|
|
|
533
|
-
// AllItems services have been removed - this handler is no longer needed
|
|
534
|
-
// Service state persistence is now handled by entity instances directly
|
|
535
|
-
const saveServiceHandler = async (_event) => {
|
|
536
|
-
// AllItems services removed - this functionality is no longer needed
|
|
537
|
-
// Entity instances (Schema, Model, Item) manage their own state
|
|
538
|
-
console.warn('[saveServiceHandler] AllItems services removed - handler is a no-op');
|
|
539
|
-
};
|
|
540
|
-
|
|
541
|
-
const setupServiceHandlers = () => {
|
|
542
|
-
eventEmitter.addListener('service.save', saveServiceHandler);
|
|
543
|
-
};
|
|
544
|
-
|
|
545
511
|
/** `filesDir` when the config sets neither it nor `endpoints.files`. */
|
|
546
512
|
const DEFAULT_FILES_DIR = '.seed';
|
|
547
513
|
/**
|
|
@@ -563,9 +529,9 @@ function applySeedConfigDefaults(config) {
|
|
|
563
529
|
return { ...config, filesDir, endpoints: next };
|
|
564
530
|
}
|
|
565
531
|
|
|
566
|
-
const logger$
|
|
532
|
+
const logger$b = debug('seedSdk:ClientManager:initialize');
|
|
567
533
|
const platformClassesInit = fromCallback(({ sendBack, input: { context, event } }) => {
|
|
568
|
-
logger$
|
|
534
|
+
logger$b('initialize from ClientManager');
|
|
569
535
|
const { isInitialized } = context;
|
|
570
536
|
if (!event || !('options' in event)) {
|
|
571
537
|
throw new Error('Initialize event must include options');
|
|
@@ -590,9 +556,7 @@ const platformClassesInit = fromCallback(({ sendBack, input: { context, event }
|
|
|
590
556
|
if (!config) {
|
|
591
557
|
throw new Error('client.init requires a config');
|
|
592
558
|
}
|
|
593
|
-
const
|
|
594
|
-
const _ns_0 = _mod_0.a;
|
|
595
|
-
const { configurePlatform } = _ns_0;
|
|
559
|
+
const { configurePlatform } = await import('./configurePlatform-CrMafpMW.js');
|
|
596
560
|
if (isBrowser()) {
|
|
597
561
|
const { createPlatformServices } = await import('./platform.browser.js');
|
|
598
562
|
configurePlatform(createPlatformServices());
|
|
@@ -630,7 +594,7 @@ const platformClassesInit = fromCallback(({ sendBack, input: { context, event }
|
|
|
630
594
|
BaseArweaveClient.setHost(`${resolvedGateway.arweaveProtocol}://${resolvedGateway.arweaveHost}`);
|
|
631
595
|
// filesDir falls back to endpoints.files (applySeedConfigDefaults fills both)
|
|
632
596
|
let normalizedFilesDir = filesDir || endpoints?.files;
|
|
633
|
-
// jsdom (and any env with both Node + window) is "browser" for SDK:
|
|
597
|
+
// jsdom (and any env with both Node + window) is "browser" for SDK: filesDir is an OPFS path.
|
|
634
598
|
// Do not run real fs against those paths (e.g. mkdir '/.seed').
|
|
635
599
|
if (isNode() && !isBrowser() && normalizedFilesDir) {
|
|
636
600
|
// Lives in the Node platform so browser bundles (and Next.js server builds, which
|
|
@@ -671,8 +635,6 @@ const platformClassesInit = fromCallback(({ sendBack, input: { context, event }
|
|
|
671
635
|
// Models are now Model instances, no registration needed
|
|
672
636
|
// They should be created via Model.create() and are accessible via Model static methods
|
|
673
637
|
setupAllItemsEventHandlers();
|
|
674
|
-
setupServicesEventHandlers();
|
|
675
|
-
setupServiceHandlers();
|
|
676
638
|
});
|
|
677
639
|
// Handle the promise immediately - this ensures rejections are caught synchronously
|
|
678
640
|
// The catch handler is attached synchronously before the async function executes
|
|
@@ -703,7 +665,7 @@ const platformClassesInit = fromCallback(({ sendBack, input: { context, event }
|
|
|
703
665
|
};
|
|
704
666
|
});
|
|
705
667
|
|
|
706
|
-
const logger$
|
|
668
|
+
const logger$a = debug('seedSdk:client:writeToDb');
|
|
707
669
|
const saveAppState = fromCallback(({ sendBack, input: { key, value } }) => {
|
|
708
670
|
const _saveAppState = async () => {
|
|
709
671
|
try {
|
|
@@ -711,7 +673,7 @@ const saveAppState = fromCallback(({ sendBack, input: { key, value } }) => {
|
|
|
711
673
|
if (!appDb) {
|
|
712
674
|
// In test environments, continue anyway
|
|
713
675
|
if (isTestOrSeedDev()) {
|
|
714
|
-
logger$
|
|
676
|
+
logger$a('[client/actors] [saveAppState] App DB not found, but continuing in test environment');
|
|
715
677
|
return;
|
|
716
678
|
}
|
|
717
679
|
throw new Error('App DB not found');
|
|
@@ -727,13 +689,13 @@ const saveAppState = fromCallback(({ sendBack, input: { key, value } }) => {
|
|
|
727
689
|
value: JSON.stringify(value),
|
|
728
690
|
},
|
|
729
691
|
});
|
|
730
|
-
logger$
|
|
692
|
+
logger$a('result', result);
|
|
731
693
|
}
|
|
732
694
|
catch (error) {
|
|
733
|
-
logger$
|
|
695
|
+
logger$a('[client/actors] [saveAppState] Error saving app state:', error);
|
|
734
696
|
// In test environments, continue anyway
|
|
735
697
|
if (isTestOrSeedDev()) {
|
|
736
|
-
logger$
|
|
698
|
+
logger$a('[client/actors] [saveAppState] Continuing despite error in test environment');
|
|
737
699
|
return;
|
|
738
700
|
}
|
|
739
701
|
throw error;
|
|
@@ -748,10 +710,10 @@ const saveAppState = fromCallback(({ sendBack, input: { key, value } }) => {
|
|
|
748
710
|
});
|
|
749
711
|
})
|
|
750
712
|
.catch((error) => {
|
|
751
|
-
logger$
|
|
713
|
+
logger$a('[client/actors] [saveAppState] Error in promise chain:', error);
|
|
752
714
|
// In test environments, still send success to allow state machine to progress
|
|
753
715
|
if (isTestOrSeedDev()) {
|
|
754
|
-
logger$
|
|
716
|
+
logger$a('[client/actors] [saveAppState] Sending success despite error in test environment');
|
|
755
717
|
sendBack({
|
|
756
718
|
type: 'saveAppStateSuccess',
|
|
757
719
|
key,
|
|
@@ -769,29 +731,7 @@ const saveAppState = fromCallback(({ sendBack, input: { key, value } }) => {
|
|
|
769
731
|
});
|
|
770
732
|
});
|
|
771
733
|
|
|
772
|
-
let isInitialized = false;
|
|
773
|
-
const fsInitHandler = async () => {
|
|
774
|
-
if (isInitialized) {
|
|
775
|
-
return;
|
|
776
|
-
}
|
|
777
|
-
isInitialized = true;
|
|
778
|
-
};
|
|
779
|
-
let areReady = false;
|
|
780
|
-
const setupFsListeners = () => {
|
|
781
|
-
eventEmitter.addListener('fs.downloadAll.request', downloadAllFilesRequestHandler);
|
|
782
|
-
eventEmitter.addListener('fs.downloadAllBinary.request', downloadAllFilesBinaryRequestHandler);
|
|
783
|
-
eventEmitter.addListener('fs.init', fsInitHandler);
|
|
784
|
-
areReady = true;
|
|
785
|
-
};
|
|
786
|
-
const areFsListenersReady = () => {
|
|
787
|
-
return areReady;
|
|
788
|
-
};
|
|
789
|
-
|
|
790
734
|
const fileSystemInit = fromCallback(({ sendBack, input: { context }, }) => {
|
|
791
|
-
setupFsListeners();
|
|
792
|
-
if (!areFsListenersReady()) {
|
|
793
|
-
throw new Error('fs listeners not ready during init');
|
|
794
|
-
}
|
|
795
735
|
// Check for filesDir synchronously before starting async operation
|
|
796
736
|
// This ensures the error is thrown synchronously and caught by XState
|
|
797
737
|
const { filesDir } = context;
|
|
@@ -800,7 +740,6 @@ const fileSystemInit = fromCallback(({ sendBack, input: { context }, }) => {
|
|
|
800
740
|
}
|
|
801
741
|
const _fileSystemInit = async () => {
|
|
802
742
|
await BaseFileManager.initializeFileSystem(filesDir);
|
|
803
|
-
eventEmitter.emit('fs.init');
|
|
804
743
|
};
|
|
805
744
|
_fileSystemInit()
|
|
806
745
|
.then(() => {
|
|
@@ -820,7 +759,7 @@ const fileSystemInit = fromCallback(({ sendBack, input: { context }, }) => {
|
|
|
820
759
|
};
|
|
821
760
|
});
|
|
822
761
|
|
|
823
|
-
const logger$
|
|
762
|
+
const logger$9 = debug('seedSdk:client:actors:dbInit');
|
|
824
763
|
const dbInit = fromCallback(({ sendBack, input: { context } }) => {
|
|
825
764
|
const _dbInit = async () => {
|
|
826
765
|
const { filesDir, dbConfig } = context;
|
|
@@ -834,14 +773,14 @@ const dbInit = fromCallback(({ sendBack, input: { context } }) => {
|
|
|
834
773
|
if (!appDb) {
|
|
835
774
|
throw new Error('Database not available after preparation');
|
|
836
775
|
}
|
|
837
|
-
logger$
|
|
776
|
+
logger$9('[client/actors] [dbInit] Database prepared and ready');
|
|
838
777
|
};
|
|
839
778
|
_dbInit()
|
|
840
779
|
.then(() => {
|
|
841
780
|
sendBack({ type: ClientManagerEvents.DB_READY });
|
|
842
781
|
})
|
|
843
782
|
.catch((error) => {
|
|
844
|
-
logger$
|
|
783
|
+
logger$9('Error in dbInit:', error);
|
|
845
784
|
sendBack({
|
|
846
785
|
type: 'error',
|
|
847
786
|
error: error instanceof Error ? error : new Error(String(error))
|
|
@@ -849,7 +788,7 @@ const dbInit = fromCallback(({ sendBack, input: { context } }) => {
|
|
|
849
788
|
});
|
|
850
789
|
});
|
|
851
790
|
|
|
852
|
-
const logger$
|
|
791
|
+
const logger$8 = debug('seedSdk:client:actors:addModelsToStore');
|
|
853
792
|
const addModelsToStore = fromCallback(({ sendBack, input: { context } }) => {
|
|
854
793
|
const _addModelsToStore = async () => {
|
|
855
794
|
let { models } = context;
|
|
@@ -863,7 +802,7 @@ const addModelsToStore = fromCallback(({ sendBack, input: { context } }) => {
|
|
|
863
802
|
// Models are now Model instances, no registration needed
|
|
864
803
|
// They should be created via Model.create() and are accessible via Model static methods
|
|
865
804
|
for (const [key] of Object.entries(allModels)) {
|
|
866
|
-
logger$
|
|
805
|
+
logger$8('model available:', key);
|
|
867
806
|
}
|
|
868
807
|
};
|
|
869
808
|
_addModelsToStore()
|
|
@@ -871,7 +810,7 @@ const addModelsToStore = fromCallback(({ sendBack, input: { context } }) => {
|
|
|
871
810
|
sendBack({ type: ClientManagerEvents.ADD_MODELS_TO_STORE_SUCCESS });
|
|
872
811
|
})
|
|
873
812
|
.catch((error) => {
|
|
874
|
-
logger$
|
|
813
|
+
logger$8('[client/actors] [addModelsToStore] Error:', error);
|
|
875
814
|
sendBack({
|
|
876
815
|
type: 'error',
|
|
877
816
|
error: error instanceof Error ? error : new Error(String(error)),
|
|
@@ -879,7 +818,7 @@ const addModelsToStore = fromCallback(({ sendBack, input: { context } }) => {
|
|
|
879
818
|
});
|
|
880
819
|
});
|
|
881
820
|
|
|
882
|
-
const logger$
|
|
821
|
+
const logger$7 = debug('seedSdk:client:actors:addModelsToDb');
|
|
883
822
|
/**
|
|
884
823
|
* Returns every `models` row named in `modelNames`, inserting a null-schemaFileId stub for each name
|
|
885
824
|
* with no row yet (the schema import adopts stubs via findOrCreateModelRecord). Check-then-insert:
|
|
@@ -902,7 +841,7 @@ async function ensureModelStubs(appDb, modelNames, filesDir) {
|
|
|
902
841
|
.returning({ id: models$1.id, name: models$1.name, schemaFileId: models$1.schemaFileId }));
|
|
903
842
|
rows.push(...newlyInserted);
|
|
904
843
|
for (const name of modelsToInsert) {
|
|
905
|
-
logger$
|
|
844
|
+
logger$7('[client/actors] [addModelsToDb] inserted model:', name);
|
|
906
845
|
}
|
|
907
846
|
}
|
|
908
847
|
return rows;
|
|
@@ -942,7 +881,7 @@ const addModelsToDb = fromCallback(({ sendBack, input: { context } }) => {
|
|
|
942
881
|
for (const modelName of modelNames) {
|
|
943
882
|
const foundModel = rowFor(modelName);
|
|
944
883
|
if (!foundModel) {
|
|
945
|
-
logger$
|
|
884
|
+
logger$7('[client/actors] [addModelsToDb] Warning: Could not find or create model:', modelName);
|
|
946
885
|
hasModelsInDb = false;
|
|
947
886
|
continue;
|
|
948
887
|
}
|
|
@@ -954,7 +893,7 @@ const addModelsToDb = fromCallback(({ sendBack, input: { context } }) => {
|
|
|
954
893
|
}
|
|
955
894
|
// If we have no models to process, still send success (empty models is valid)
|
|
956
895
|
if (schemaDefsByModelName.size === 0) {
|
|
957
|
-
logger$
|
|
896
|
+
logger$7('[client/actors] [addModelsToDb] No models to process, but continuing');
|
|
958
897
|
return;
|
|
959
898
|
}
|
|
960
899
|
const schemaDefs = Array.from(schemaDefsByModelName.values()).map(({ schemaDef }) => schemaDef);
|
|
@@ -1001,15 +940,15 @@ const addModelsToDb = fromCallback(({ sendBack, input: { context } }) => {
|
|
|
1001
940
|
requestEasSyncFromModelsInit();
|
|
1002
941
|
}
|
|
1003
942
|
else {
|
|
1004
|
-
logger$
|
|
943
|
+
logger$7('[client/actors] [addModelsToDb] No schemas found from EAS, but continuing');
|
|
1005
944
|
}
|
|
1006
945
|
}
|
|
1007
946
|
catch (error) {
|
|
1008
947
|
if (isTestOrSeedDev()) {
|
|
1009
|
-
logger$
|
|
948
|
+
logger$7('[client/actors] [addModelsToDb] Warning: Could not fetch schemas from EAS (background):', error.message);
|
|
1010
949
|
}
|
|
1011
950
|
else {
|
|
1012
|
-
logger$
|
|
951
|
+
logger$7('[client/actors] [addModelsToDb] Error fetching schemas (background):', error.message);
|
|
1013
952
|
}
|
|
1014
953
|
// Probably offline: the startup sync waits for this lookup, so try again.
|
|
1015
954
|
modelUidsRetry.schedule();
|
|
@@ -1023,16 +962,16 @@ const addModelsToDb = fromCallback(({ sendBack, input: { context } }) => {
|
|
|
1023
962
|
_addModelsToDb()
|
|
1024
963
|
// Model.findByModelType reads the nameMatch levels synchronously: have them before init is ready.
|
|
1025
964
|
.then(() => loadNameMatchLevels().catch((error) => {
|
|
1026
|
-
logger$
|
|
965
|
+
logger$7('[client/actors] [addModelsToDb] Could not load nameMatch levels:', error);
|
|
1027
966
|
}))
|
|
1028
967
|
.then(() => {
|
|
1029
968
|
sendBack({ type: ClientManagerEvents.ADD_MODELS_TO_DB_SUCCESS });
|
|
1030
969
|
})
|
|
1031
970
|
.catch((error) => {
|
|
1032
|
-
logger$
|
|
971
|
+
logger$7('[client/actors] [addModelsToDb] Error:', error);
|
|
1033
972
|
// In test environments, still send success to allow initialization to complete
|
|
1034
973
|
if (isTestOrSeedDev()) {
|
|
1035
|
-
logger$
|
|
974
|
+
logger$7('[client/actors] [addModelsToDb] Continuing despite error in test environment');
|
|
1036
975
|
sendBack({ type: ClientManagerEvents.ADD_MODELS_TO_DB_SUCCESS });
|
|
1037
976
|
}
|
|
1038
977
|
else {
|
|
@@ -1045,7 +984,7 @@ const addModelsToDb = fromCallback(({ sendBack, input: { context } }) => {
|
|
|
1045
984
|
return () => { };
|
|
1046
985
|
});
|
|
1047
986
|
|
|
1048
|
-
const logger$
|
|
987
|
+
const logger$6 = debug('seedSdk:helpers:localDbChain');
|
|
1049
988
|
/** appState key recording which EAS chain the local database holds attestations from. */
|
|
1050
989
|
const EAS_CHAIN_ID_APP_STATE_KEY = 'easChainId';
|
|
1051
990
|
/**
|
|
@@ -1115,7 +1054,7 @@ async function loadLocalDbChain() {
|
|
|
1115
1054
|
const localChainId = await resolveLocalDbChainId(appDb);
|
|
1116
1055
|
if (localChainId !== undefined) {
|
|
1117
1056
|
configureEasReadChain('localDb', { chainId: localChainId });
|
|
1118
|
-
logger$
|
|
1057
|
+
logger$6('local DB holds chain %d', localChainId);
|
|
1119
1058
|
return;
|
|
1120
1059
|
}
|
|
1121
1060
|
if (isEasReadChainConfigured()) {
|
|
@@ -1164,7 +1103,7 @@ function resetAddressesPersistedAnnouncement() {
|
|
|
1164
1103
|
lastAnnounced = undefined;
|
|
1165
1104
|
}
|
|
1166
1105
|
|
|
1167
|
-
const logger$
|
|
1106
|
+
const logger$5 = debug('seedSdk:client:actors:saveConfig');
|
|
1168
1107
|
let warnedKeptStoredAddresses = false;
|
|
1169
1108
|
/**
|
|
1170
1109
|
* Saves the addresses passed to init.
|
|
@@ -1205,13 +1144,13 @@ async function persistInitAddresses(appDb, { addresses, addressesProvided, owned
|
|
|
1205
1144
|
announceAddressesPersisted({ owned, watched });
|
|
1206
1145
|
}
|
|
1207
1146
|
const saveConfig = fromCallback(({ sendBack, input: { context } }) => {
|
|
1208
|
-
logger$
|
|
1147
|
+
logger$5('saveConfig starting');
|
|
1209
1148
|
const { endpoints, addresses, addressesProvided, ownedAddresses, watchedAddresses, arweaveDomain, uploadApiBaseUrl, gatewayTransport, gatewayHyperKey, gatewaySidecarHost, gatewaySidecarPort, gatewayProxyBaseUrl, } = context;
|
|
1210
1149
|
// Validate endpoints - required for proper initialization
|
|
1211
1150
|
// If endpoints are missing or invalid, initialization should fail
|
|
1212
1151
|
if (!endpoints || !endpoints.filePaths || !endpoints.files) {
|
|
1213
1152
|
const error = new Error('saveConfig called with invalid endpoints: endpoints must include both filePaths and files');
|
|
1214
|
-
logger$
|
|
1153
|
+
logger$5('[internal/actors] [saveConfig] Invalid endpoints:', { endpoints });
|
|
1215
1154
|
throw error;
|
|
1216
1155
|
}
|
|
1217
1156
|
const _saveConfig = async () => {
|
|
@@ -1220,7 +1159,7 @@ const saveConfig = fromCallback(({ sendBack, input: { context } }) => {
|
|
|
1220
1159
|
if (!appDb) {
|
|
1221
1160
|
// In test environments, continue anyway
|
|
1222
1161
|
if (isTestOrSeedDev()) {
|
|
1223
|
-
logger$
|
|
1162
|
+
logger$5('[internal/actors] [saveConfig] App DB not found, but continuing in test environment');
|
|
1224
1163
|
return;
|
|
1225
1164
|
}
|
|
1226
1165
|
throw new Error('App DB not found');
|
|
@@ -1275,10 +1214,10 @@ const saveConfig = fromCallback(({ sendBack, input: { context } }) => {
|
|
|
1275
1214
|
await loadLocalDbChain();
|
|
1276
1215
|
}
|
|
1277
1216
|
catch (error) {
|
|
1278
|
-
logger$
|
|
1217
|
+
logger$5('[internal/actors] [saveConfig] Error saving config:', error);
|
|
1279
1218
|
// In test environments, continue anyway
|
|
1280
1219
|
if (isTestOrSeedDev()) {
|
|
1281
|
-
logger$
|
|
1220
|
+
logger$5('[internal/actors] [saveConfig] Continuing despite error in test environment');
|
|
1282
1221
|
return;
|
|
1283
1222
|
}
|
|
1284
1223
|
throw error;
|
|
@@ -1287,14 +1226,14 @@ const saveConfig = fromCallback(({ sendBack, input: { context } }) => {
|
|
|
1287
1226
|
// Init writes run one tab at a time (docs/MULTI_TAB.md).
|
|
1288
1227
|
withSeedDbLock('init', context.filesDir, _saveConfig)
|
|
1289
1228
|
.then(() => {
|
|
1290
|
-
logger$
|
|
1229
|
+
logger$5('[internal/actors] [saveConfig] saveConfig success');
|
|
1291
1230
|
return sendBack({ type: ClientManagerEvents.SAVE_CONFIG_SUCCESS });
|
|
1292
1231
|
})
|
|
1293
1232
|
.catch((error) => {
|
|
1294
|
-
logger$
|
|
1233
|
+
logger$5('[internal/actors] [saveConfig] Error in saveConfig promise chain:', error);
|
|
1295
1234
|
// In test environments, still send success to allow state machine to progress
|
|
1296
1235
|
if (isTestOrSeedDev()) {
|
|
1297
|
-
logger$
|
|
1236
|
+
logger$5('[internal/actors] [saveConfig] Sending success despite error in test environment');
|
|
1298
1237
|
sendBack({ type: ClientManagerEvents.SAVE_CONFIG_SUCCESS });
|
|
1299
1238
|
}
|
|
1300
1239
|
else {
|
|
@@ -1307,140 +1246,7 @@ const saveConfig = fromCallback(({ sendBack, input: { context } }) => {
|
|
|
1307
1246
|
return () => { };
|
|
1308
1247
|
});
|
|
1309
1248
|
|
|
1310
|
-
const logger$
|
|
1311
|
-
/**
|
|
1312
|
-
* Sanitize a schema name to be filesystem-safe
|
|
1313
|
-
* Replaces all special characters (except alphanumeric, hyphens, underscores) with underscores
|
|
1314
|
-
* Converts spaces to underscores
|
|
1315
|
-
* Removes leading/trailing underscores
|
|
1316
|
-
*
|
|
1317
|
-
* @param name - Schema name to sanitize
|
|
1318
|
-
* @returns Sanitized name safe for use in filenames
|
|
1319
|
-
*/
|
|
1320
|
-
const sanitizeSchemaName$1 = (name) => {
|
|
1321
|
-
return name
|
|
1322
|
-
.replace(/[^a-zA-Z0-9\s_-]/g, '_') // Replace special chars (except spaces, hyphens, underscores) with underscore
|
|
1323
|
-
.replace(/\s+/g, '_') // Convert spaces to underscores
|
|
1324
|
-
.replace(/^_+|_+$/g, '') // Remove leading/trailing underscores
|
|
1325
|
-
.replace(/_+/g, '_'); // Collapse multiple underscores to single
|
|
1326
|
-
};
|
|
1327
|
-
/**
|
|
1328
|
-
* Generate filename for a schema
|
|
1329
|
-
* Format: {schemaFileId}_{schemaName}_v{version}.json
|
|
1330
|
-
*
|
|
1331
|
-
* The ID-first format ensures all files for a schema group together when sorted alphabetically.
|
|
1332
|
-
*
|
|
1333
|
-
* @param name - Schema name
|
|
1334
|
-
* @param version - Schema version
|
|
1335
|
-
* @param schemaFileId - Schema file ID (required)
|
|
1336
|
-
*/
|
|
1337
|
-
const getSchemaFilename = (name, version, schemaFileId) => {
|
|
1338
|
-
const sanitizedName = sanitizeSchemaName$1(name);
|
|
1339
|
-
return `${schemaFileId}_${sanitizedName}_v${version}.json`;
|
|
1340
|
-
};
|
|
1341
|
-
/**
|
|
1342
|
-
* Get the full file path for a schema
|
|
1343
|
-
* Format: {schemaFileId}_{schemaName}_v{version}.json
|
|
1344
|
-
*
|
|
1345
|
-
* The ID-first format ensures all files for a schema group together when sorted alphabetically.
|
|
1346
|
-
*
|
|
1347
|
-
* @param name - Schema name
|
|
1348
|
-
* @param version - Schema version
|
|
1349
|
-
* @param schemaFileId - Schema file ID (required)
|
|
1350
|
-
*/
|
|
1351
|
-
const getSchemaFilePath$1 = (name, version, schemaFileId) => {
|
|
1352
|
-
const path = BaseFileManager.getPathModule();
|
|
1353
|
-
const filename = getSchemaFilename(name, version, schemaFileId);
|
|
1354
|
-
const workingDir = BaseFileManager.getWorkingDir();
|
|
1355
|
-
return path.join(workingDir, filename);
|
|
1356
|
-
};
|
|
1357
|
-
/**
|
|
1358
|
-
* Create a new schema file
|
|
1359
|
-
* @param schema - The schema object to save
|
|
1360
|
-
* @param schemaFileId - Schema file ID (required)
|
|
1361
|
-
* @throws Error if schema already exists or if workingDir is invalid
|
|
1362
|
-
*/
|
|
1363
|
-
const createSchema = async (schema, schemaFileId) => {
|
|
1364
|
-
if (!schema.name || !schema.version) {
|
|
1365
|
-
throw new Error('Schema must have a name and version');
|
|
1366
|
-
}
|
|
1367
|
-
const filePath = getSchemaFilePath$1(schema.name, schema.version, schemaFileId);
|
|
1368
|
-
// Check if schema already exists
|
|
1369
|
-
const exists = await BaseFileManager.pathExists(filePath);
|
|
1370
|
-
if (exists) {
|
|
1371
|
-
throw new Error(`Schema ${schema.name} v${schema.version} already exists`);
|
|
1372
|
-
}
|
|
1373
|
-
// Ensure working directory exists
|
|
1374
|
-
const workingDir = BaseFileManager.getWorkingDir();
|
|
1375
|
-
await BaseFileManager.createDirIfNotExists(workingDir);
|
|
1376
|
-
// Write schema to file
|
|
1377
|
-
const content = JSON.stringify(schema, null, 2);
|
|
1378
|
-
await BaseFileManager.saveFile(filePath, content);
|
|
1379
|
-
};
|
|
1380
|
-
/**
|
|
1381
|
-
* Read a schema file by name and version
|
|
1382
|
-
* @param name - The name of the schema
|
|
1383
|
-
* @param version - The version of the schema
|
|
1384
|
-
* @param schemaFileId - Schema file ID (required)
|
|
1385
|
-
* @returns The schema object, or null if not found
|
|
1386
|
-
*/
|
|
1387
|
-
const readSchema = async (name, version, schemaFileId) => {
|
|
1388
|
-
const filePath = getSchemaFilePath$1(name, version, schemaFileId);
|
|
1389
|
-
const exists = await BaseFileManager.pathExists(filePath);
|
|
1390
|
-
if (!exists) {
|
|
1391
|
-
return null;
|
|
1392
|
-
}
|
|
1393
|
-
try {
|
|
1394
|
-
const content = await BaseFileManager.readFileAsString(filePath);
|
|
1395
|
-
return JSON.parse(content);
|
|
1396
|
-
}
|
|
1397
|
-
catch (error) {
|
|
1398
|
-
throw new Error(`Failed to read schema ${name} v${version}: ${error instanceof Error ? error.message : String(error)}`);
|
|
1399
|
-
}
|
|
1400
|
-
};
|
|
1401
|
-
/**
|
|
1402
|
-
* Update an existing schema file
|
|
1403
|
-
* @param schema - The updated schema object (must have same name and version as existing)
|
|
1404
|
-
* @param schemaFileId - Schema file ID (required)
|
|
1405
|
-
* @throws Error if schema doesn't exist
|
|
1406
|
-
*/
|
|
1407
|
-
async function updateSchema(schema, schemaFileId) {
|
|
1408
|
-
if (!schema.name || !schema.version) {
|
|
1409
|
-
throw new Error('Schema must have a name and version');
|
|
1410
|
-
}
|
|
1411
|
-
const filePath = getSchemaFilePath$1(schema.name, schema.version, schemaFileId);
|
|
1412
|
-
// Check if schema exists
|
|
1413
|
-
const exists = await BaseFileManager.pathExists(filePath);
|
|
1414
|
-
if (!exists) {
|
|
1415
|
-
throw new Error(`Schema ${schema.name} v${schema.version} does not exist`);
|
|
1416
|
-
}
|
|
1417
|
-
// Write updated schema to file
|
|
1418
|
-
const content = JSON.stringify(schema, null, 2);
|
|
1419
|
-
await BaseFileManager.saveFile(filePath, content);
|
|
1420
|
-
}
|
|
1421
|
-
/**
|
|
1422
|
-
* Delete a schema file
|
|
1423
|
-
* @param name - The name of the schema
|
|
1424
|
-
* @param version - The version of the schema
|
|
1425
|
-
* @param schemaFileId - Schema file ID (required)
|
|
1426
|
-
* @throws Error if schema doesn't exist
|
|
1427
|
-
*/
|
|
1428
|
-
async function deleteSchema(name, version, schemaFileId) {
|
|
1429
|
-
const filePath = getSchemaFilePath$1(name, version, schemaFileId);
|
|
1430
|
-
// Check if schema exists
|
|
1431
|
-
const exists = await BaseFileManager.pathExists(filePath);
|
|
1432
|
-
if (!exists) {
|
|
1433
|
-
throw new Error(`Schema ${name} v${version} does not exist`);
|
|
1434
|
-
}
|
|
1435
|
-
// Delete the file
|
|
1436
|
-
const fs = await BaseFileManager.getFs();
|
|
1437
|
-
try {
|
|
1438
|
-
await fs.promises.unlink(filePath);
|
|
1439
|
-
}
|
|
1440
|
-
catch (error) {
|
|
1441
|
-
throw new Error(`Failed to delete schema ${name} v${version}: ${error instanceof Error ? error.message : String(error)}`);
|
|
1442
|
-
}
|
|
1443
|
-
}
|
|
1249
|
+
const logger$4 = debug('seedSdk:helpers:schema');
|
|
1444
1250
|
/**
|
|
1445
1251
|
* List all schema files in the working directory
|
|
1446
1252
|
* Only returns files that are NOT already complete schema files (i.e., files without $schema field)
|
|
@@ -1502,7 +1308,7 @@ async function listCompleteSchemaFiles() {
|
|
|
1502
1308
|
const dirExists = await BaseFileManager.pathExists(workingDir);
|
|
1503
1309
|
if (!dirExists) {
|
|
1504
1310
|
// Directory doesn't exist yet - return empty array (not an error condition)
|
|
1505
|
-
logger$
|
|
1311
|
+
logger$4(`Working directory does not exist yet: ${workingDir}, returning empty schema list`);
|
|
1506
1312
|
return [];
|
|
1507
1313
|
}
|
|
1508
1314
|
const files = await fs.promises.readdir(workingDir);
|
|
@@ -1546,24 +1352,6 @@ async function listCompleteSchemaFiles() {
|
|
|
1546
1352
|
throw new Error(`Failed to list complete schemas: ${error instanceof Error ? error.message : String(error)}`);
|
|
1547
1353
|
}
|
|
1548
1354
|
}
|
|
1549
|
-
/**
|
|
1550
|
-
* Find a schema by name (returns the latest version if multiple versions exist)
|
|
1551
|
-
* @param name - The name of the schema
|
|
1552
|
-
* @returns The schema with the highest version, or null if not found
|
|
1553
|
-
*/
|
|
1554
|
-
async function findSchemaByName(name) {
|
|
1555
|
-
const schemas = await listCompleteSchemaFiles();
|
|
1556
|
-
const matchingSchemas = schemas.filter((s) => s.name === name);
|
|
1557
|
-
if (matchingSchemas.length === 0) {
|
|
1558
|
-
return null;
|
|
1559
|
-
}
|
|
1560
|
-
// Find the schema with the highest version
|
|
1561
|
-
const latest = matchingSchemas.reduce((prev, current) => current.version > prev.version ? current : prev);
|
|
1562
|
-
if (!latest.schemaFileId) {
|
|
1563
|
-
throw new Error(`Schema ${latest.name} v${latest.version} is missing schemaFileId`);
|
|
1564
|
-
}
|
|
1565
|
-
return readSchema(latest.name, latest.version, latest.schemaFileId);
|
|
1566
|
-
}
|
|
1567
1355
|
/**
|
|
1568
1356
|
* Get the latest version number for a schema by name
|
|
1569
1357
|
* Only considers complete schema files (with $schema field)
|
|
@@ -1596,27 +1384,6 @@ async function listLatestSchemaFiles() {
|
|
|
1596
1384
|
}
|
|
1597
1385
|
return Array.from(schemaMap.values());
|
|
1598
1386
|
}
|
|
1599
|
-
/**
|
|
1600
|
-
* Filter an array of schemas to only include the latest version for each schema name
|
|
1601
|
-
* Works with any object that has a name (via metadata.name or name property) and a version property
|
|
1602
|
-
* @param schemas - Array of schema objects
|
|
1603
|
-
* @returns Array containing only the latest version of each schema
|
|
1604
|
-
*/
|
|
1605
|
-
function filterLatestSchemas(schemas) {
|
|
1606
|
-
// Group by schema name and keep only the latest version of each
|
|
1607
|
-
const schemaMap = new Map();
|
|
1608
|
-
for (const schema of schemas) {
|
|
1609
|
-
const schemaName = schema.metadata?.name || schema.name;
|
|
1610
|
-
if (!schemaName) {
|
|
1611
|
-
continue; // Skip schemas without a name
|
|
1612
|
-
}
|
|
1613
|
-
const existing = schemaMap.get(schemaName);
|
|
1614
|
-
if (!existing || schema.version > existing.version) {
|
|
1615
|
-
schemaMap.set(schemaName, schema);
|
|
1616
|
-
}
|
|
1617
|
-
}
|
|
1618
|
-
return Array.from(schemaMap.values());
|
|
1619
|
-
}
|
|
1620
1387
|
async function loadAllSchemasFromDb() {
|
|
1621
1388
|
const db = BaseDb.getAppDb();
|
|
1622
1389
|
if (!db) {
|
|
@@ -1639,7 +1406,7 @@ async function loadAllSchemasFromDb() {
|
|
|
1639
1406
|
}
|
|
1640
1407
|
catch (error) {
|
|
1641
1408
|
// If we can't list schema files (e.g., directory doesn't exist yet), continue without file-based loading
|
|
1642
|
-
logger$
|
|
1409
|
+
logger$4(`Error listing complete schema files (continuing with DB data): ${error instanceof Error ? error.message : String(error)}`);
|
|
1643
1410
|
completeSchemaFiles = [];
|
|
1644
1411
|
}
|
|
1645
1412
|
}
|
|
@@ -1692,7 +1459,7 @@ async function loadAllSchemasFromDb() {
|
|
|
1692
1459
|
continue;
|
|
1693
1460
|
}
|
|
1694
1461
|
catch (error) {
|
|
1695
|
-
logger$
|
|
1462
|
+
logger$4(`Error parsing schemaData for ${schemaName}:`, error);
|
|
1696
1463
|
// Fall through to file-based loading
|
|
1697
1464
|
}
|
|
1698
1465
|
}
|
|
@@ -1734,7 +1501,7 @@ async function loadAllSchemasFromDb() {
|
|
|
1734
1501
|
continue;
|
|
1735
1502
|
}
|
|
1736
1503
|
catch (error) {
|
|
1737
|
-
logger$
|
|
1504
|
+
logger$4(`Error loading schema file for ${schemaName}:`, error);
|
|
1738
1505
|
// Fall through to try loading from schemaData if available
|
|
1739
1506
|
}
|
|
1740
1507
|
}
|
|
@@ -1778,7 +1545,7 @@ async function loadAllSchemasFromDb() {
|
|
|
1778
1545
|
continue;
|
|
1779
1546
|
}
|
|
1780
1547
|
catch (error) {
|
|
1781
|
-
logger$
|
|
1548
|
+
logger$4(`Error parsing schemaData for ${schemaName}:`, error);
|
|
1782
1549
|
}
|
|
1783
1550
|
}
|
|
1784
1551
|
}
|
|
@@ -1789,11 +1556,11 @@ async function loadAllSchemasFromDb() {
|
|
|
1789
1556
|
// Only process if not already in result
|
|
1790
1557
|
if (!processedSchemaNames.has(schemaFileInfo.name)) {
|
|
1791
1558
|
if (isInternalSchema(schemaFileInfo.name, schemaFileInfo.schemaFileId)) {
|
|
1792
|
-
logger$
|
|
1559
|
+
logger$4(`STEP 3: skipping internal schema file: ${schemaFileInfo.filePath}`);
|
|
1793
1560
|
continue;
|
|
1794
1561
|
}
|
|
1795
1562
|
try {
|
|
1796
|
-
logger$
|
|
1563
|
+
logger$4(`STEP 3: processing schema file: ${schemaFileInfo.name} from ${schemaFileInfo.filePath}`);
|
|
1797
1564
|
const content = await BaseFileManager.readFileAsString(schemaFileInfo.filePath);
|
|
1798
1565
|
const schemaFile = JSON.parse(content);
|
|
1799
1566
|
// Import this schema to database (mark as non-draft since it's in a file)
|
|
@@ -1813,68 +1580,12 @@ async function loadAllSchemasFromDb() {
|
|
|
1813
1580
|
processedSchemaNames.add(schemaFileInfo.name);
|
|
1814
1581
|
}
|
|
1815
1582
|
catch (error) {
|
|
1816
|
-
logger$
|
|
1583
|
+
logger$4(`Error loading schema file ${schemaFileInfo.filePath}:`, error);
|
|
1817
1584
|
}
|
|
1818
1585
|
}
|
|
1819
1586
|
}
|
|
1820
1587
|
return result;
|
|
1821
1588
|
}
|
|
1822
|
-
/**
|
|
1823
|
-
* Migration helper: Migrate existing file-based schemas to the database
|
|
1824
|
-
* This function should be called once to migrate existing schema files to the new database-first approach
|
|
1825
|
-
* All existing schemas will be marked as published (isDraft = false) since they already exist in files
|
|
1826
|
-
* @returns Number of schemas migrated
|
|
1827
|
-
*/
|
|
1828
|
-
async function migrateFileSchemasToDb() {
|
|
1829
|
-
const db = BaseDb.getAppDb();
|
|
1830
|
-
if (!db) {
|
|
1831
|
-
throw new Error('Database not found');
|
|
1832
|
-
}
|
|
1833
|
-
logger$8('Starting migration of file-based schemas to database');
|
|
1834
|
-
// Get all complete schema files
|
|
1835
|
-
const completeSchemas = await listCompleteSchemaFiles();
|
|
1836
|
-
let migratedCount = 0;
|
|
1837
|
-
for (const schemaFileInfo of completeSchemas) {
|
|
1838
|
-
try {
|
|
1839
|
-
// Read the schema file
|
|
1840
|
-
const content = await BaseFileManager.readFileAsString(schemaFileInfo.filePath);
|
|
1841
|
-
const schemaFile = JSON.parse(content);
|
|
1842
|
-
if (!schemaFile.$schema || !schemaFile.metadata?.name) {
|
|
1843
|
-
logger$8(`Skipping invalid schema file: ${schemaFileInfo.filePath}`);
|
|
1844
|
-
continue;
|
|
1845
|
-
}
|
|
1846
|
-
const schemaName = schemaFile.metadata.name;
|
|
1847
|
-
// Check if schema already exists in database
|
|
1848
|
-
const existingSchemas = await db
|
|
1849
|
-
.select()
|
|
1850
|
-
.from(schemas)
|
|
1851
|
-
.where(eq(schemas.name, schemaName))
|
|
1852
|
-
.limit(1);
|
|
1853
|
-
// Only migrate if it doesn't exist or if existing record doesn't have schemaFileId
|
|
1854
|
-
if (existingSchemas.length === 0 || !existingSchemas[0].schemaFileId) {
|
|
1855
|
-
// Add schema to database as published (isDraft = false)
|
|
1856
|
-
await addSchemaToDb({
|
|
1857
|
-
name: schemaName,
|
|
1858
|
-
version: schemaFile.version,
|
|
1859
|
-
createdAt: new Date(schemaFile.metadata.createdAt).getTime(),
|
|
1860
|
-
updatedAt: new Date(schemaFile.metadata.updatedAt).getTime(),
|
|
1861
|
-
}, schemaFile.id, // schemaFileId
|
|
1862
|
-
JSON.stringify(schemaFile, null, 2), // schemaData
|
|
1863
|
-
false);
|
|
1864
|
-
migratedCount++;
|
|
1865
|
-
logger$8(`Migrated schema: ${schemaName} v${schemaFile.version}`);
|
|
1866
|
-
}
|
|
1867
|
-
else {
|
|
1868
|
-
logger$8(`Schema ${schemaName} already exists in database, skipping`);
|
|
1869
|
-
}
|
|
1870
|
-
}
|
|
1871
|
-
catch (error) {
|
|
1872
|
-
logger$8(`Error migrating schema file ${schemaFileInfo.filePath}:`, error);
|
|
1873
|
-
}
|
|
1874
|
-
}
|
|
1875
|
-
logger$8(`Migration complete: ${migratedCount} schemas migrated`);
|
|
1876
|
-
return migratedCount;
|
|
1877
|
-
}
|
|
1878
1589
|
/**
|
|
1879
1590
|
* Extract the schema name from a schemaId string
|
|
1880
1591
|
* @param schemaId - Schema ID in the format `${schemaName}-${schemaVersion}`
|
|
@@ -1891,19 +1602,12 @@ function getSchemaNameFromId(schemaId) {
|
|
|
1891
1602
|
|
|
1892
1603
|
var schema = /*#__PURE__*/Object.freeze({
|
|
1893
1604
|
__proto__: null,
|
|
1894
|
-
createSchema: createSchema,
|
|
1895
|
-
deleteSchema: deleteSchema,
|
|
1896
|
-
filterLatestSchemas: filterLatestSchemas,
|
|
1897
|
-
findSchemaByName: findSchemaByName,
|
|
1898
1605
|
getLatestSchemaVersion: getLatestSchemaVersion,
|
|
1899
1606
|
getSchemaNameFromId: getSchemaNameFromId,
|
|
1900
1607
|
listCompleteSchemaFiles: listCompleteSchemaFiles,
|
|
1901
1608
|
listLatestSchemaFiles: listLatestSchemaFiles,
|
|
1902
1609
|
listSchemaFiles: listSchemaFiles,
|
|
1903
|
-
loadAllSchemasFromDb: loadAllSchemasFromDb
|
|
1904
|
-
migrateFileSchemasToDb: migrateFileSchemasToDb,
|
|
1905
|
-
readSchema: readSchema,
|
|
1906
|
-
updateSchema: updateSchema
|
|
1610
|
+
loadAllSchemasFromDb: loadAllSchemasFromDb
|
|
1907
1611
|
});
|
|
1908
1612
|
|
|
1909
1613
|
function toBytes(data) {
|
|
@@ -1925,7 +1629,7 @@ const getDeterministicIdsWithPrefix = (prefix) => {
|
|
|
1925
1629
|
return (suffix) => bytesToHex(prefixHash.clone().update(utf8ToBytes(suffix)).digest()).slice(0, 10);
|
|
1926
1630
|
};
|
|
1927
1631
|
|
|
1928
|
-
const logger$
|
|
1632
|
+
const logger$3 = debug('seedSdk:imports:json');
|
|
1929
1633
|
/**
|
|
1930
1634
|
* Get refValueType from a property object with case-insensitive key lookup.
|
|
1931
1635
|
* Handles refValueType, refvaluetype, ref_value_type, elementType, and legacy items.type / items.Type.
|
|
@@ -1992,119 +1696,6 @@ function getRefValueType(prop) {
|
|
|
1992
1696
|
}
|
|
1993
1697
|
return undefined;
|
|
1994
1698
|
}
|
|
1995
|
-
/**
|
|
1996
|
-
* Verify that properties are persisted to the database for a given model
|
|
1997
|
-
* This is important in browser environments where database writes may not be immediately visible
|
|
1998
|
-
* @param db - Database instance
|
|
1999
|
-
* @param modelId - Database ID of the model
|
|
2000
|
-
* @param modelName - Name of the model (for logging)
|
|
2001
|
-
* @param maxRetries - Maximum number of retry attempts
|
|
2002
|
-
* @param retryDelay - Delay between retries in milliseconds
|
|
2003
|
-
* @returns Promise that resolves when properties are found, or rejects if not found after max retries
|
|
2004
|
-
*/
|
|
2005
|
-
const verifyPropertiesPersisted = async (db, modelId, modelName, maxRetries = 10, retryDelay = 100) => {
|
|
2006
|
-
const _mod_1 = await import('./index-C0SetTd1.js');
|
|
2007
|
-
const _ns_1 = _mod_1.bj;
|
|
2008
|
-
const modelSchemaMod = _ns_1;
|
|
2009
|
-
const { properties: propertiesTable } = modelSchemaMod;
|
|
2010
|
-
const drizzleMod = await import('drizzle-orm');
|
|
2011
|
-
const { eq } = drizzleMod;
|
|
2012
|
-
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
2013
|
-
const props = await db
|
|
2014
|
-
.select()
|
|
2015
|
-
.from(propertiesTable)
|
|
2016
|
-
.where(eq(propertiesTable.modelId, modelId))
|
|
2017
|
-
.limit(1);
|
|
2018
|
-
if (props.length > 0) {
|
|
2019
|
-
logger$7(`Verified properties exist for model "${modelName}" (modelId: ${modelId}) after ${attempt + 1} attempt(s)`);
|
|
2020
|
-
return;
|
|
2021
|
-
}
|
|
2022
|
-
if (attempt < maxRetries - 1) {
|
|
2023
|
-
logger$7(`Properties not yet visible for model "${modelName}" (modelId: ${modelId}), retrying in ${retryDelay}ms (attempt ${attempt + 1}/${maxRetries})`);
|
|
2024
|
-
await new Promise(resolve => setTimeout(resolve, retryDelay));
|
|
2025
|
-
}
|
|
2026
|
-
}
|
|
2027
|
-
throw new Error(`Properties not found for model "${modelName}" (modelId: ${modelId}) after ${maxRetries} attempts. This may indicate a database write issue in the browser environment.`);
|
|
2028
|
-
};
|
|
2029
|
-
/**
|
|
2030
|
-
* Compare two schema files structurally, ignoring metadata timestamps
|
|
2031
|
-
* This is used to determine if an existing schema file matches the schema being imported
|
|
2032
|
-
* @param schema1 - First schema to compare
|
|
2033
|
-
* @param schema2 - Second schema to compare
|
|
2034
|
-
* @returns true if schemas are structurally equivalent, false otherwise
|
|
2035
|
-
*/
|
|
2036
|
-
function compareSchemasStructurally(schema1, schema2) {
|
|
2037
|
-
// Compare basic fields
|
|
2038
|
-
if (schema1.$schema !== schema2.$schema)
|
|
2039
|
-
return false;
|
|
2040
|
-
if (schema1.version !== schema2.version)
|
|
2041
|
-
return false;
|
|
2042
|
-
if (schema1.id !== schema2.id)
|
|
2043
|
-
return false;
|
|
2044
|
-
// Compare metadata (ignoring timestamps)
|
|
2045
|
-
if (schema1.metadata?.name !== schema2.metadata?.name)
|
|
2046
|
-
return false;
|
|
2047
|
-
// Compare models structure
|
|
2048
|
-
const models1 = schema1.models || {};
|
|
2049
|
-
const models2 = schema2.models || {};
|
|
2050
|
-
const modelNames1 = Object.keys(models1).sort();
|
|
2051
|
-
const modelNames2 = Object.keys(models2).sort();
|
|
2052
|
-
if (modelNames1.length !== modelNames2.length)
|
|
2053
|
-
return false;
|
|
2054
|
-
if (!modelNames1.every((name, i) => name === modelNames2[i]))
|
|
2055
|
-
return false;
|
|
2056
|
-
// Compare each model's structure
|
|
2057
|
-
for (const modelName of modelNames1) {
|
|
2058
|
-
const model1 = models1[modelName];
|
|
2059
|
-
const model2 = models2[modelName];
|
|
2060
|
-
// Compare model IDs if both have them
|
|
2061
|
-
if (model1.id !== model2.id)
|
|
2062
|
-
return false;
|
|
2063
|
-
// Compare properties
|
|
2064
|
-
const props1 = model1.properties || {};
|
|
2065
|
-
const props2 = model2.properties || {};
|
|
2066
|
-
const propNames1 = Object.keys(props1).sort();
|
|
2067
|
-
const propNames2 = Object.keys(props2).sort();
|
|
2068
|
-
if (propNames1.length !== propNames2.length)
|
|
2069
|
-
return false;
|
|
2070
|
-
if (!propNames1.every((name, i) => name === propNames2[i]))
|
|
2071
|
-
return false;
|
|
2072
|
-
// Compare each property's structure
|
|
2073
|
-
for (const propName of propNames1) {
|
|
2074
|
-
const prop1 = props1[propName];
|
|
2075
|
-
const prop2 = props2[propName];
|
|
2076
|
-
// Compare property IDs if both have them
|
|
2077
|
-
if (prop1.id !== prop2.id)
|
|
2078
|
-
return false;
|
|
2079
|
-
// Compare property types
|
|
2080
|
-
if (prop1.type !== prop2.type)
|
|
2081
|
-
return false;
|
|
2082
|
-
// Compare other relevant fields (ref, refValueType for List, etc.)
|
|
2083
|
-
if (prop1.ref !== prop2.ref)
|
|
2084
|
-
return false;
|
|
2085
|
-
const refVal1 = prop1.refValueType ?? prop1.items?.type;
|
|
2086
|
-
const refVal2 = prop2.refValueType ?? prop2.items?.type;
|
|
2087
|
-
if (refVal1 !== refVal2)
|
|
2088
|
-
return false;
|
|
2089
|
-
const model1 = prop1.ref ?? prop1.items?.model;
|
|
2090
|
-
const model2 = prop2.ref ?? prop2.items?.model;
|
|
2091
|
-
if (model1 !== model2)
|
|
2092
|
-
return false;
|
|
2093
|
-
}
|
|
2094
|
-
}
|
|
2095
|
-
// Compare enums
|
|
2096
|
-
const enums1 = schema1.enums || {};
|
|
2097
|
-
const enums2 = schema2.enums || {};
|
|
2098
|
-
const enumNames1 = Object.keys(enums1).sort();
|
|
2099
|
-
const enumNames2 = Object.keys(enums2).sort();
|
|
2100
|
-
if (enumNames1.length !== enumNames2.length)
|
|
2101
|
-
return false;
|
|
2102
|
-
if (!enumNames1.every((name, i) => name === enumNames2[i]))
|
|
2103
|
-
return false;
|
|
2104
|
-
// Note: We don't compare migrations as they're historical records
|
|
2105
|
-
// and may differ even for the same schema structure
|
|
2106
|
-
return true;
|
|
2107
|
-
}
|
|
2108
1699
|
/**
|
|
2109
1700
|
* Create a canonical JSON string for schema comparison (ignores IDs and timestamps).
|
|
2110
1701
|
* Used to detect if schema content has changed via string comparison of schemaData.
|
|
@@ -2319,7 +1910,7 @@ const readCompleteSchemaFile = async (filePath) => {
|
|
|
2319
1910
|
return schema;
|
|
2320
1911
|
}
|
|
2321
1912
|
catch (error) {
|
|
2322
|
-
logger$
|
|
1913
|
+
logger$3(`Could not read schema file ${filePath}:`, error);
|
|
2323
1914
|
return undefined;
|
|
2324
1915
|
}
|
|
2325
1916
|
};
|
|
@@ -2384,7 +1975,7 @@ async function importSchema(importFilePathOrContents, version, options) {
|
|
|
2384
1975
|
if (parsed.$schema && parsed.metadata?.name) {
|
|
2385
1976
|
// It's already a complete schema format - preserve it (id may be missing, will be generated)
|
|
2386
1977
|
originalSchemaFile = parsed;
|
|
2387
|
-
logger$
|
|
1978
|
+
logger$3(`Input is complete schema format (${originalSchemaFile.id ? `preserving ID: ${originalSchemaFile.id}` : 'id will be generated'})`);
|
|
2388
1979
|
}
|
|
2389
1980
|
}
|
|
2390
1981
|
catch {
|
|
@@ -2396,7 +1987,6 @@ async function importSchema(importFilePathOrContents, version, options) {
|
|
|
2396
1987
|
}
|
|
2397
1988
|
// Use original schema file if available, otherwise transform from import format
|
|
2398
1989
|
let schemaFile;
|
|
2399
|
-
let replacingStoredFile = false;
|
|
2400
1990
|
if (originalSchemaFile) {
|
|
2401
1991
|
schemaFile = originalSchemaFile;
|
|
2402
1992
|
// Normalize models if provided as array (some tools output array format)
|
|
@@ -2410,9 +2000,9 @@ async function importSchema(importFilePathOrContents, version, options) {
|
|
|
2410
2000
|
// Check DB for existing schema by name+version (same as minimal path)
|
|
2411
2001
|
const db = BaseDb.getAppDb();
|
|
2412
2002
|
if (db) {
|
|
2413
|
-
const
|
|
2414
|
-
const
|
|
2415
|
-
const schemaSchemaMod =
|
|
2003
|
+
const _mod_0 = await import('./index-Dx_GTdyQ.js');
|
|
2004
|
+
const _ns_0 = _mod_0.bc;
|
|
2005
|
+
const schemaSchemaMod = _ns_0;
|
|
2416
2006
|
const { schemas: schemasTable } = schemaSchemaMod;
|
|
2417
2007
|
const drizzleMod = await import('drizzle-orm');
|
|
2418
2008
|
const { eq, and, desc } = drizzleMod;
|
|
@@ -2424,16 +2014,16 @@ async function importSchema(importFilePathOrContents, version, options) {
|
|
|
2424
2014
|
.limit(1);
|
|
2425
2015
|
if (existingByName.length > 0 && existingByName[0].schemaData) {
|
|
2426
2016
|
const existing = existingByName[0];
|
|
2427
|
-
logger$
|
|
2017
|
+
logger$3(`Idempotency: found existing schema by name+version: ${schemaFile.metadata.name} v${schemaFile.version ?? version}`);
|
|
2428
2018
|
const existingSchema = JSON.parse(existing.schemaData);
|
|
2429
2019
|
const contentMatches = compareSchemaContent(schemaFile, existingSchema);
|
|
2430
|
-
logger$
|
|
2020
|
+
logger$3(`Idempotency: compareSchemaContent=${contentMatches} for ${schemaFile.metadata.name}`);
|
|
2431
2021
|
if (contentMatches) {
|
|
2432
2022
|
if (existing.schemaFileId) {
|
|
2433
2023
|
const workingDir = BaseFileManager.getWorkingDir();
|
|
2434
2024
|
const existingFilePath = getSchemaFilePath(workingDir, schemaFile.metadata.name, schemaFile.version ?? version, existing.schemaFileId);
|
|
2435
2025
|
if (await BaseFileManager.pathExists(existingFilePath)) {
|
|
2436
|
-
logger$
|
|
2026
|
+
logger$3(`Schema ${schemaFile.metadata.name} v${schemaFile.version} already exists with same content, loading existing file`);
|
|
2437
2027
|
return await loadSchemaFromFile(existingFilePath);
|
|
2438
2028
|
}
|
|
2439
2029
|
await BaseFileManager.createDirIfNotExists(workingDir);
|
|
@@ -2441,7 +2031,7 @@ async function importSchema(importFilePathOrContents, version, options) {
|
|
|
2441
2031
|
await BaseFileManager.waitForFileWithContent(existingFilePath, 100, 5000);
|
|
2442
2032
|
return await loadSchemaFromFile(existingFilePath);
|
|
2443
2033
|
}
|
|
2444
|
-
logger$
|
|
2034
|
+
logger$3(`Schema ${schemaFile.metadata.name} v${schemaFile.version} already exists with same content (no schemaFileId), using DB`);
|
|
2445
2035
|
return '';
|
|
2446
2036
|
}
|
|
2447
2037
|
}
|
|
@@ -2457,7 +2047,7 @@ async function importSchema(importFilePathOrContents, version, options) {
|
|
|
2457
2047
|
// processSchemaFiles runs multiple times (React StrictMode, app restarts).
|
|
2458
2048
|
if (!schemaFile.id) {
|
|
2459
2049
|
schemaFile.id = await getDeterministicSchemaFileId(schemaFile);
|
|
2460
|
-
logger$
|
|
2050
|
+
logger$3(`Generated deterministic schema ID for ${schemaFile.metadata.name}:`, schemaFile.id);
|
|
2461
2051
|
}
|
|
2462
2052
|
// A file with this schemaFileId and version is reused only when its content matches. A pinned id
|
|
2463
2053
|
// (one the schema file sets) keeps the same path when the content changes.
|
|
@@ -2466,7 +2056,7 @@ async function importSchema(importFilePathOrContents, version, options) {
|
|
|
2466
2056
|
if (await BaseFileManager.pathExists(existingFilePath)) {
|
|
2467
2057
|
const storedSchema = await readCompleteSchemaFile(existingFilePath);
|
|
2468
2058
|
if (storedSchema && compareSchemaContent(schemaFile, storedSchema)) {
|
|
2469
|
-
logger$
|
|
2059
|
+
logger$3(`Schema file already exists with schemaFileId ${schemaFile.id} and the same content, loading it`);
|
|
2470
2060
|
return await loadSchemaFromFile(existingFilePath);
|
|
2471
2061
|
}
|
|
2472
2062
|
if (!options.replaceStoredFile) {
|
|
@@ -2475,7 +2065,6 @@ async function importSchema(importFilePathOrContents, version, options) {
|
|
|
2475
2065
|
}
|
|
2476
2066
|
console.warn(`[seed] schema ${schemaFile.metadata.name} v${schemaFile.version}: content changed but id ` +
|
|
2477
2067
|
`${schemaFile.id} and version did not; replacing the stored schema file. Bump "version" when the schema changes.`);
|
|
2478
|
-
replacingStoredFile = true;
|
|
2479
2068
|
}
|
|
2480
2069
|
// Generate missing model and property IDs.
|
|
2481
2070
|
// Use deterministic IDs (from schema content hash) so addModelsToDb finds existing
|
|
@@ -2485,12 +2074,12 @@ async function importSchema(importFilePathOrContents, version, options) {
|
|
|
2485
2074
|
for (const [modelName, model] of Object.entries(schemaFile.models || {})) {
|
|
2486
2075
|
if (!model.id) {
|
|
2487
2076
|
model.id = getDeterministicId(modelName);
|
|
2488
|
-
logger$
|
|
2077
|
+
logger$3(`Generated deterministic model ID for ${modelName}:`, model.id);
|
|
2489
2078
|
}
|
|
2490
2079
|
for (const [propName, prop] of Object.entries(model.properties || {})) {
|
|
2491
2080
|
if (!prop.id) {
|
|
2492
2081
|
prop.id = getDeterministicId(modelName + propName);
|
|
2493
|
-
logger$
|
|
2082
|
+
logger$3(`Generated deterministic property ID for ${modelName}.${propName}:`, prop.id);
|
|
2494
2083
|
}
|
|
2495
2084
|
}
|
|
2496
2085
|
}
|
|
@@ -2502,9 +2091,9 @@ async function importSchema(importFilePathOrContents, version, options) {
|
|
|
2502
2091
|
// For minimal imports: check DB for existing schema before creating new file
|
|
2503
2092
|
const db = BaseDb.getAppDb();
|
|
2504
2093
|
if (db) {
|
|
2505
|
-
const
|
|
2506
|
-
const
|
|
2507
|
-
const schemaSchemaMod =
|
|
2094
|
+
const _mod_1 = await import('./index-Dx_GTdyQ.js');
|
|
2095
|
+
const _ns_1 = _mod_1.bc;
|
|
2096
|
+
const schemaSchemaMod = _ns_1;
|
|
2508
2097
|
const { schemas: schemasTable } = schemaSchemaMod;
|
|
2509
2098
|
const drizzleMod = await import('drizzle-orm');
|
|
2510
2099
|
const { eq, and, desc } = drizzleMod;
|
|
@@ -2526,14 +2115,14 @@ async function importSchema(importFilePathOrContents, version, options) {
|
|
|
2526
2115
|
const workingDir = BaseFileManager.getWorkingDir();
|
|
2527
2116
|
const existingFilePath = getSchemaFilePath(workingDir, importData.name, version, existing.schemaFileId);
|
|
2528
2117
|
if (await BaseFileManager.pathExists(existingFilePath)) {
|
|
2529
|
-
logger$
|
|
2118
|
+
logger$3(`Schema ${importData.name} v${version} already exists with same content, loading existing file`);
|
|
2530
2119
|
return await loadSchemaFromFile(existingFilePath);
|
|
2531
2120
|
}
|
|
2532
2121
|
// File missing but schemaData exists - restore file from schemaData
|
|
2533
2122
|
await BaseFileManager.createDirIfNotExists(workingDir);
|
|
2534
2123
|
await BaseFileManager.saveFile(existingFilePath, existing.schemaData);
|
|
2535
2124
|
await BaseFileManager.waitForFileWithContent(existingFilePath, 100, 5000);
|
|
2536
|
-
logger$
|
|
2125
|
+
logger$3(`Restored schema file from schemaData for ${importData.name} v${version}`);
|
|
2537
2126
|
return await loadSchemaFromFile(existingFilePath);
|
|
2538
2127
|
}
|
|
2539
2128
|
// No schemaFileId - restore file from schemaData using id from parsed schema
|
|
@@ -2544,10 +2133,10 @@ async function importSchema(importFilePathOrContents, version, options) {
|
|
|
2544
2133
|
await BaseFileManager.createDirIfNotExists(workingDir);
|
|
2545
2134
|
await BaseFileManager.saveFile(existingFilePath, existing.schemaData);
|
|
2546
2135
|
await BaseFileManager.waitForFileWithContent(existingFilePath, 100, 5000);
|
|
2547
|
-
logger$
|
|
2136
|
+
logger$3(`Restored schema file from schemaData for ${importData.name} v${version}`);
|
|
2548
2137
|
return await loadSchemaFromFile(existingFilePath);
|
|
2549
2138
|
}
|
|
2550
|
-
logger$
|
|
2139
|
+
logger$3(`Schema ${importData.name} v${version} already exists with same content (no id), using DB`);
|
|
2551
2140
|
return '';
|
|
2552
2141
|
}
|
|
2553
2142
|
// Content differs - create new version
|
|
@@ -2558,7 +2147,7 @@ async function importSchema(importFilePathOrContents, version, options) {
|
|
|
2558
2147
|
.orderBy(desc(schemasTable.version))
|
|
2559
2148
|
.limit(1);
|
|
2560
2149
|
const newVersion = latestVersionRows.length > 0 ? latestVersionRows[0].version + 1 : version;
|
|
2561
|
-
logger$
|
|
2150
|
+
logger$3(`Schema ${importData.name} content changed, creating new version v${newVersion}`);
|
|
2562
2151
|
schemaFile = transformImportToSchemaFile(importData, newVersion);
|
|
2563
2152
|
version = newVersion;
|
|
2564
2153
|
}
|
|
@@ -2584,7 +2173,7 @@ async function importSchema(importFilePathOrContents, version, options) {
|
|
|
2584
2173
|
// Check if this is an internal SDK schema (should not create files in app directory)
|
|
2585
2174
|
const isInternal = isInternalSchema(schemaFile.metadata.name, schemaFile.id);
|
|
2586
2175
|
if (isInternal) {
|
|
2587
|
-
logger$
|
|
2176
|
+
logger$3(`Skipping file creation for internal schema: ${schemaFile.metadata.name}`);
|
|
2588
2177
|
// For internal schemas, just load to database and store, don't create file
|
|
2589
2178
|
// Extract schema name and version
|
|
2590
2179
|
const schemaName = schemaFile.metadata?.name;
|
|
@@ -2641,7 +2230,7 @@ async function importSchema(importFilePathOrContents, version, options) {
|
|
|
2641
2230
|
// Use fixed internal schema ID if missing (never generate for internal)
|
|
2642
2231
|
if (!schemaFile.id) {
|
|
2643
2232
|
schemaFile.id = INTERNAL_SCHEMA_IDS[0];
|
|
2644
|
-
logger$
|
|
2233
|
+
logger$3('Using fixed internal schema ID:', schemaFile.id);
|
|
2645
2234
|
}
|
|
2646
2235
|
// Extract schemaFileIds from JSON file and generate missing ones BEFORE creating models
|
|
2647
2236
|
// This ensures Model instances are created with correct IDs
|
|
@@ -2651,7 +2240,7 @@ async function importSchema(importFilePathOrContents, version, options) {
|
|
|
2651
2240
|
// Generate model ID if missing
|
|
2652
2241
|
if (!model.id) {
|
|
2653
2242
|
model.id = generateId();
|
|
2654
|
-
logger$
|
|
2243
|
+
logger$3(`Generated model ID for ${modelName}:`, model.id);
|
|
2655
2244
|
// Update the schemaFile object so it's included in schemaData
|
|
2656
2245
|
schemaFile.models[modelName].id = model.id;
|
|
2657
2246
|
}
|
|
@@ -2661,7 +2250,7 @@ async function importSchema(importFilePathOrContents, version, options) {
|
|
|
2661
2250
|
// Generate property ID if missing
|
|
2662
2251
|
if (!prop.id) {
|
|
2663
2252
|
prop.id = generateId();
|
|
2664
|
-
logger$
|
|
2253
|
+
logger$3(`Generated property ID for ${modelName}.${propName}:`, prop.id);
|
|
2665
2254
|
// Update the schemaFile object so it's included in schemaData
|
|
2666
2255
|
schemaFile.models[modelName].properties[propName].id = prop.id;
|
|
2667
2256
|
}
|
|
@@ -2675,7 +2264,7 @@ async function importSchema(importFilePathOrContents, version, options) {
|
|
|
2675
2264
|
// addModelsToDb below writes their rows; the models adopt them once it has run.
|
|
2676
2265
|
const rowsWritten = createRowsWrittenSignal();
|
|
2677
2266
|
const modelDefinitions = await createModelsFromJson(importDataForInternal, modelFileIds, propertyFileIds, rowsWritten.promise);
|
|
2678
|
-
logger$
|
|
2267
|
+
logger$3('loadSchemaFromFile (internal) - modelDefinitions length:', Object.keys(modelDefinitions).length);
|
|
2679
2268
|
// Convert schema file metadata to schema input for database
|
|
2680
2269
|
const schemaInput = {
|
|
2681
2270
|
name: schemaName,
|
|
@@ -2685,9 +2274,9 @@ async function importSchema(importFilePathOrContents, version, options) {
|
|
|
2685
2274
|
updatedAt: new Date(schemaFile.metadata.updatedAt).getTime(),
|
|
2686
2275
|
};
|
|
2687
2276
|
// Use dynamic import to break circular dependency
|
|
2688
|
-
const
|
|
2689
|
-
const
|
|
2690
|
-
const dbMod =
|
|
2277
|
+
const _mod_2 = await import('./index-Dx_GTdyQ.js');
|
|
2278
|
+
const _ns_2 = _mod_2.bf;
|
|
2279
|
+
const dbMod = _ns_2;
|
|
2691
2280
|
const { addSchemaToDb, addModelsToDb } = dbMod;
|
|
2692
2281
|
// Try to add schema and models to database if database is available
|
|
2693
2282
|
try {
|
|
@@ -2707,13 +2296,13 @@ async function importSchema(importFilePathOrContents, version, options) {
|
|
|
2707
2296
|
});
|
|
2708
2297
|
// Verify expected models are linked (single attempt - addModelsToDb already confirmed)
|
|
2709
2298
|
const expectedModelNames = Object.keys(schemaFile.models || {});
|
|
2710
|
-
const
|
|
2711
|
-
const
|
|
2712
|
-
const modelSchemaSchemaMod =
|
|
2299
|
+
const _mod_3 = await import('./index-Dx_GTdyQ.js');
|
|
2300
|
+
const _ns_3 = _mod_3.bd;
|
|
2301
|
+
const modelSchemaSchemaMod = _ns_3;
|
|
2713
2302
|
const { modelSchemas } = modelSchemaSchemaMod;
|
|
2714
|
-
const
|
|
2715
|
-
const
|
|
2716
|
-
const modelSchemaMod =
|
|
2303
|
+
const _mod_4 = await import('./index-Dx_GTdyQ.js');
|
|
2304
|
+
const _ns_4 = _mod_4.ba;
|
|
2305
|
+
const modelSchemaMod = _ns_4;
|
|
2717
2306
|
const { models: modelsTable } = modelSchemaMod;
|
|
2718
2307
|
const drizzleMod = await import('drizzle-orm');
|
|
2719
2308
|
const { eq, and, isNull } = drizzleMod;
|
|
@@ -2791,7 +2380,6 @@ async function importSchema(importFilePathOrContents, version, options) {
|
|
|
2791
2380
|
}
|
|
2792
2381
|
}
|
|
2793
2382
|
}
|
|
2794
|
-
// Skip expensive verifyPropertiesPersisted - addModelsToDb already persisted; verification was for browser quirks
|
|
2795
2383
|
// Skip "After properties" block for internal schema: addSchemaToDb/addModelsToDb already stored
|
|
2796
2384
|
// correct schemaData. The per-model ID sync (6 model + 6 property selects + schema update) is
|
|
2797
2385
|
// redundant during init and causes slow OPFS writes. Ad-hoc loadSchemaFromFile uses the same
|
|
@@ -2801,7 +2389,7 @@ async function importSchema(importFilePathOrContents, version, options) {
|
|
|
2801
2389
|
}
|
|
2802
2390
|
catch (dbError) {
|
|
2803
2391
|
// Database not available - log warning but continue
|
|
2804
|
-
logger$
|
|
2392
|
+
logger$3('Database not available, skipping database operations:', dbError instanceof Error ? dbError.message : String(dbError));
|
|
2805
2393
|
}
|
|
2806
2394
|
finally {
|
|
2807
2395
|
rowsWritten.settle();
|
|
@@ -2809,78 +2397,20 @@ async function importSchema(importFilePathOrContents, version, options) {
|
|
|
2809
2397
|
// Models are now Model instances, no registration needed
|
|
2810
2398
|
// They should be created via Model.create() and are accessible via Model static methods
|
|
2811
2399
|
for (const [modelName] of Object.entries(modelDefinitions)) {
|
|
2812
|
-
logger$
|
|
2400
|
+
logger$3('loadSchemaFromFile (internal) - model available:', modelName);
|
|
2813
2401
|
}
|
|
2814
2402
|
// Schema is now saved to database
|
|
2815
2403
|
// useSchemas hook will pick it up via database queries
|
|
2816
2404
|
return ''; // Return empty string to indicate no file was created
|
|
2817
2405
|
}
|
|
2818
2406
|
const workingDir = BaseFileManager.getWorkingDir();
|
|
2819
|
-
const path = BaseFileManager.getPathModule();
|
|
2820
2407
|
// Ensure schema ID is defined (should always be set by this point, but check for safety)
|
|
2821
2408
|
if (!schemaFile.id) {
|
|
2822
2409
|
schemaFile.id = generateId();
|
|
2823
|
-
logger$
|
|
2410
|
+
logger$3('Generated schema ID before file path creation:', schemaFile.id);
|
|
2824
2411
|
}
|
|
2825
2412
|
// Get the target file path using ID-based naming (preferred)
|
|
2826
2413
|
const filePath = getSchemaFilePath(workingDir, schemaFile.metadata.name, version, schemaFile.id);
|
|
2827
|
-
// Check if schema already exists
|
|
2828
|
-
const exists = !replacingStoredFile && (await BaseFileManager.pathExists(filePath));
|
|
2829
|
-
if (exists) {
|
|
2830
|
-
// If we have a file path and the import file is the same as the target file,
|
|
2831
|
-
// and it's already a complete schema, just load it without writing
|
|
2832
|
-
if (importFilePath) {
|
|
2833
|
-
const normalizedImportPath = path.resolve(importFilePath);
|
|
2834
|
-
const normalizedTargetPath = path.resolve(filePath);
|
|
2835
|
-
if (normalizedImportPath === normalizedTargetPath) {
|
|
2836
|
-
// Check if the file is already a complete schema
|
|
2837
|
-
try {
|
|
2838
|
-
const content = await BaseFileManager.readFileAsString(importFilePath);
|
|
2839
|
-
const data = JSON.parse(content);
|
|
2840
|
-
if (data.$schema) {
|
|
2841
|
-
// File is already a complete schema, just load it
|
|
2842
|
-
logger$7(`Schema file ${filePath} already exists and is complete, loading it`);
|
|
2843
|
-
return await loadSchemaFromFile(filePath);
|
|
2844
|
-
}
|
|
2845
|
-
}
|
|
2846
|
-
catch {
|
|
2847
|
-
// If we can't read the file, proceed with the error
|
|
2848
|
-
}
|
|
2849
|
-
}
|
|
2850
|
-
}
|
|
2851
|
-
// File exists - check if it matches the schema we're trying to import
|
|
2852
|
-
try {
|
|
2853
|
-
const existingContent = await BaseFileManager.readFileAsString(filePath);
|
|
2854
|
-
const existingSchema = JSON.parse(existingContent);
|
|
2855
|
-
// Verify it's a complete schema file
|
|
2856
|
-
if (existingSchema.$schema) {
|
|
2857
|
-
// Compare schemas structurally
|
|
2858
|
-
if (compareSchemasStructurally(schemaFile, existingSchema)) {
|
|
2859
|
-
// Schemas match - just load the existing file
|
|
2860
|
-
logger$7(`Schema ${schemaFile.metadata.name} v${version} already exists with matching content, loading it`);
|
|
2861
|
-
return await loadSchemaFromFile(filePath);
|
|
2862
|
-
}
|
|
2863
|
-
else {
|
|
2864
|
-
// Schemas don't match - throw error to prevent data loss
|
|
2865
|
-
throw new Error(`Schema ${schemaFile.metadata.name} v${version} already exists with different content. ` +
|
|
2866
|
-
`To update the schema, delete the existing file first or use a different version.`);
|
|
2867
|
-
}
|
|
2868
|
-
}
|
|
2869
|
-
else {
|
|
2870
|
-
// File exists but is not a complete schema - this shouldn't happen with ID-based naming
|
|
2871
|
-
// but we'll treat it as a conflict
|
|
2872
|
-
throw new Error(`Schema ${schemaFile.metadata.name} v${version} already exists but file is not a complete schema`);
|
|
2873
|
-
}
|
|
2874
|
-
}
|
|
2875
|
-
catch (error) {
|
|
2876
|
-
// If error is already our custom error, re-throw it
|
|
2877
|
-
if (error instanceof Error && error.message.includes('already exists')) {
|
|
2878
|
-
throw error;
|
|
2879
|
-
}
|
|
2880
|
-
// If we can't read/parse the existing file, throw a generic error
|
|
2881
|
-
throw new Error(`Schema ${schemaFile.metadata.name} v${version} already exists but could not be read: ${error instanceof Error ? error.message : String(error)}`);
|
|
2882
|
-
}
|
|
2883
|
-
}
|
|
2884
2414
|
// Ensure working directory exists
|
|
2885
2415
|
await BaseFileManager.createDirIfNotExists(workingDir);
|
|
2886
2416
|
// Write schema to file
|
|
@@ -2913,9 +2443,9 @@ async function applySchemaToDb(schemaFile, modelDefinitions, modelFileIds, prope
|
|
|
2913
2443
|
createdAt: new Date(schemaFile.metadata.createdAt).getTime(),
|
|
2914
2444
|
updatedAt: new Date(schemaFile.metadata.updatedAt).getTime(),
|
|
2915
2445
|
};
|
|
2916
|
-
const
|
|
2917
|
-
const
|
|
2918
|
-
const dbMod =
|
|
2446
|
+
const _mod_5 = await import('./index-Dx_GTdyQ.js');
|
|
2447
|
+
const _ns_5 = _mod_5.bf;
|
|
2448
|
+
const dbMod = _ns_5;
|
|
2919
2449
|
const { addSchemaToDb, addModelsToDb } = dbMod;
|
|
2920
2450
|
const db = BaseDb.getAppDb();
|
|
2921
2451
|
if (!db) {
|
|
@@ -2945,9 +2475,9 @@ async function applySchemaToDb(schemaFile, modelDefinitions, modelFileIds, prope
|
|
|
2945
2475
|
* draft (its edits aren't the app's to undo) or a newer version than schemaFile.
|
|
2946
2476
|
*/
|
|
2947
2477
|
async function getModelsDroppedFromStoredSchema(db, schemaFile) {
|
|
2948
|
-
const
|
|
2949
|
-
const
|
|
2950
|
-
const { schemas: schemasTable } =
|
|
2478
|
+
const _mod_6 = await import('./index-Dx_GTdyQ.js');
|
|
2479
|
+
const _ns_6 = _mod_6.bc;
|
|
2480
|
+
const { schemas: schemasTable } = _ns_6;
|
|
2951
2481
|
const { eq } = await import('drizzle-orm');
|
|
2952
2482
|
const rows = await db
|
|
2953
2483
|
.select({ version: schemasTable.version, isDraft: schemasTable.isDraft, schemaData: schemasTable.schemaData })
|
|
@@ -2973,12 +2503,12 @@ async function getModelsDroppedFromStoredSchema(db, schemaFile) {
|
|
|
2973
2503
|
}
|
|
2974
2504
|
/** Delete the model_schemas rows linking the named models to the schema. The models and their items stay. */
|
|
2975
2505
|
async function unlinkModelsFromSchema(db, schemaId, modelNames) {
|
|
2976
|
-
const
|
|
2977
|
-
const
|
|
2978
|
-
const { modelSchemas } =
|
|
2979
|
-
const
|
|
2980
|
-
const
|
|
2981
|
-
const { models: modelsTable } =
|
|
2506
|
+
const _mod_7 = await import('./index-Dx_GTdyQ.js');
|
|
2507
|
+
const _ns_7 = _mod_7.bd;
|
|
2508
|
+
const { modelSchemas } = _ns_7;
|
|
2509
|
+
const _mod_8 = await import('./index-Dx_GTdyQ.js');
|
|
2510
|
+
const _ns_8 = _mod_8.ba;
|
|
2511
|
+
const { models: modelsTable } = _ns_8;
|
|
2982
2512
|
const { and, eq, inArray } = await import('drizzle-orm');
|
|
2983
2513
|
const links = await db
|
|
2984
2514
|
.select({ id: modelSchemas.id })
|
|
@@ -2988,7 +2518,7 @@ async function unlinkModelsFromSchema(db, schemaId, modelNames) {
|
|
|
2988
2518
|
if (links.length === 0)
|
|
2989
2519
|
return;
|
|
2990
2520
|
await db.delete(modelSchemas).where(inArray(modelSchemas.id, links.map((link) => link.id)));
|
|
2991
|
-
logger$
|
|
2521
|
+
logger$3(`Unlinked models dropped from the schema (schema id ${schemaId}): ${modelNames.join(', ')}`);
|
|
2992
2522
|
}
|
|
2993
2523
|
/**
|
|
2994
2524
|
* Sync a canonical schema from a file path or inlined object to the database.
|
|
@@ -3091,7 +2621,7 @@ const loadSchemaFromFile = async (schemaFilePath) => {
|
|
|
3091
2621
|
// Generate schema ID if missing (before creating schemaInput)
|
|
3092
2622
|
if (!schemaFile.id) {
|
|
3093
2623
|
schemaFile.id = generateId();
|
|
3094
|
-
logger$
|
|
2624
|
+
logger$3('Generated schema ID for schema file:', schemaFile.id);
|
|
3095
2625
|
}
|
|
3096
2626
|
// Extract schemaFileIds from JSON file and generate missing ones BEFORE creating models
|
|
3097
2627
|
// This ensures Model instances are created with correct IDs
|
|
@@ -3101,7 +2631,7 @@ const loadSchemaFromFile = async (schemaFilePath) => {
|
|
|
3101
2631
|
// Generate model ID if missing
|
|
3102
2632
|
if (!model.id) {
|
|
3103
2633
|
model.id = generateId();
|
|
3104
|
-
logger$
|
|
2634
|
+
logger$3(`Generated model ID for ${modelName}:`, model.id);
|
|
3105
2635
|
// Update the schemaFile object so it's included in schemaData
|
|
3106
2636
|
schemaFile.models[modelName].id = model.id;
|
|
3107
2637
|
}
|
|
@@ -3111,7 +2641,7 @@ const loadSchemaFromFile = async (schemaFilePath) => {
|
|
|
3111
2641
|
// Generate property ID if missing
|
|
3112
2642
|
if (!prop.id) {
|
|
3113
2643
|
prop.id = generateId();
|
|
3114
|
-
logger$
|
|
2644
|
+
logger$3(`Generated property ID for ${modelName}.${propName}:`, prop.id);
|
|
3115
2645
|
// Update the schemaFile object so it's included in schemaData
|
|
3116
2646
|
schemaFile.models[modelName].properties[propName].id = prop.id;
|
|
3117
2647
|
}
|
|
@@ -3125,7 +2655,7 @@ const loadSchemaFromFile = async (schemaFilePath) => {
|
|
|
3125
2655
|
// applySchemaToDb below writes their rows; the models adopt them once it has run.
|
|
3126
2656
|
const rowsWritten = createRowsWrittenSignal();
|
|
3127
2657
|
const modelDefinitions = await createModelsFromJson(importData, modelFileIds, propertyFileIds, rowsWritten.promise);
|
|
3128
|
-
logger$
|
|
2658
|
+
logger$3('loadSchemaFromFile - modelDefinitions length:', Object.keys(modelDefinitions).length);
|
|
3129
2659
|
// Try to add schema and models to database if database is available
|
|
3130
2660
|
try {
|
|
3131
2661
|
const db = BaseDb.getAppDb();
|
|
@@ -3137,134 +2667,12 @@ const loadSchemaFromFile = async (schemaFilePath) => {
|
|
|
3137
2667
|
modelName,
|
|
3138
2668
|
jsonPropertiesToSchemaProperties(modelName, modelDef, propertyFileIds.get(modelName)),
|
|
3139
2669
|
]));
|
|
3140
|
-
|
|
3141
|
-
// Query the database to get model IDs that were just created
|
|
3142
|
-
const _mod_11 = await import('./index-C0SetTd1.js');
|
|
3143
|
-
const _ns_11 = _mod_11.bm;
|
|
3144
|
-
const modelSchemaSchemaMod = _ns_11;
|
|
3145
|
-
const { modelSchemas } = modelSchemaSchemaMod;
|
|
3146
|
-
const _mod_12 = await import('./index-C0SetTd1.js');
|
|
3147
|
-
const _ns_12 = _mod_12.bj;
|
|
3148
|
-
const modelSchemaMod = _ns_12;
|
|
3149
|
-
const { models: modelsTable } = modelSchemaMod;
|
|
3150
|
-
const drizzleMod = await import('drizzle-orm');
|
|
3151
|
-
const { eq } = drizzleMod;
|
|
3152
|
-
// Try to find models directly by schemaFileId first (more reliable than join table)
|
|
3153
|
-
const seedModelId = modelFileIds.get('Seed');
|
|
3154
|
-
let seedModel = [];
|
|
3155
|
-
if (seedModelId) {
|
|
3156
|
-
// Retry querying for the model until it's visible
|
|
3157
|
-
for (let attempt = 0; attempt < 10; attempt++) {
|
|
3158
|
-
seedModel = await db
|
|
3159
|
-
.select()
|
|
3160
|
-
.from(modelsTable)
|
|
3161
|
-
.where(eq(modelsTable.schemaFileId, seedModelId))
|
|
3162
|
-
.limit(1);
|
|
3163
|
-
if (seedModel.length > 0 && seedModel[0].id) {
|
|
3164
|
-
break;
|
|
3165
|
-
}
|
|
3166
|
-
if (attempt < 9) {
|
|
3167
|
-
await new Promise(resolve => setTimeout(resolve, 100));
|
|
3168
|
-
}
|
|
3169
|
-
}
|
|
3170
|
-
if (seedModel.length > 0 && seedModel[0].id) {
|
|
3171
|
-
await verifyPropertiesPersisted(db, seedModel[0].id, 'Seed', 10, 100);
|
|
3172
|
-
}
|
|
3173
|
-
}
|
|
3174
|
-
// Also verify via join table if schemaRecord.id is available (for completeness)
|
|
3175
|
-
if (schemaRecord.id) {
|
|
3176
|
-
// Retry querying join table until entries are visible
|
|
3177
|
-
let modelLinks = [];
|
|
3178
|
-
for (let attempt = 0; attempt < 10; attempt++) {
|
|
3179
|
-
modelLinks = await db
|
|
3180
|
-
.select({
|
|
3181
|
-
modelId: modelSchemas.modelId,
|
|
3182
|
-
modelName: modelsTable.name,
|
|
3183
|
-
})
|
|
3184
|
-
.from(modelSchemas)
|
|
3185
|
-
.innerJoin(modelsTable, eq(modelSchemas.modelId, modelsTable.id))
|
|
3186
|
-
.where(eq(modelSchemas.schemaId, schemaRecord.id));
|
|
3187
|
-
if (modelLinks.length > 0) {
|
|
3188
|
-
break;
|
|
3189
|
-
}
|
|
3190
|
-
if (attempt < 9) {
|
|
3191
|
-
await new Promise(resolve => setTimeout(resolve, 100));
|
|
3192
|
-
}
|
|
3193
|
-
}
|
|
3194
|
-
logger$7(`Verifying properties: found ${modelLinks.length} model links for schema ${schemaName} (id: ${schemaRecord.id})`);
|
|
3195
|
-
// If we didn't verify via direct lookup, verify via join table
|
|
3196
|
-
if (!seedModelId || (seedModel.length === 0 || !seedModel[0].id)) {
|
|
3197
|
-
const seedModelLink = modelLinks.find((link) => link.modelName === 'Seed');
|
|
3198
|
-
if (seedModelLink && seedModelLink.modelId) {
|
|
3199
|
-
logger$7(`Verifying properties for Seed model via join table (modelId: ${seedModelLink.modelId})`);
|
|
3200
|
-
await verifyPropertiesPersisted(db, seedModelLink.modelId, 'Seed', 10, 100);
|
|
3201
|
-
}
|
|
3202
|
-
else if (modelLinks.length > 0 && modelLinks[0].modelId) {
|
|
3203
|
-
// Fallback to first model if Seed not found
|
|
3204
|
-
logger$7(`Verifying properties for ${modelLinks[0].modelName} model via join table (modelId: ${modelLinks[0].modelId})`);
|
|
3205
|
-
await verifyPropertiesPersisted(db, modelLinks[0].modelId, modelLinks[0].modelName || 'unknown', 10, 100);
|
|
3206
|
-
}
|
|
3207
|
-
}
|
|
3208
|
-
}
|
|
3209
|
-
// After properties are created (file path), ensure schemaFile has the correct IDs from database
|
|
3210
|
-
// Query the database to get the actual schemaFileId values that were used
|
|
3211
|
-
// This ensures schemaData matches what's actually in the database
|
|
3212
|
-
const _mod_13 = await import('./index-C0SetTd1.js');
|
|
3213
|
-
const _ns_13 = _mod_13.bj;
|
|
3214
|
-
const modelSchemaMod2 = _ns_13;
|
|
3215
|
-
const { properties: propertiesTable } = modelSchemaMod2;
|
|
3216
|
-
let schemaFileUpdated = false;
|
|
3217
|
-
for (const [modelName, modelFileId] of modelFileIds.entries()) {
|
|
3218
|
-
// Get model record to find modelId
|
|
3219
|
-
const modelRecords = await db
|
|
3220
|
-
.select()
|
|
3221
|
-
.from(modelsTable)
|
|
3222
|
-
.where(eq(modelsTable.schemaFileId, modelFileId))
|
|
3223
|
-
.limit(1);
|
|
3224
|
-
if (modelRecords.length > 0) {
|
|
3225
|
-
const modelId = modelRecords[0].id;
|
|
3226
|
-
// Get all properties for this model from database
|
|
3227
|
-
const propertyRecords = await db
|
|
3228
|
-
.select()
|
|
3229
|
-
.from(propertiesTable)
|
|
3230
|
-
.where(eq(propertiesTable.modelId, modelId));
|
|
3231
|
-
// Update schemaFile with actual database IDs (only if they differ)
|
|
3232
|
-
for (const propRecord of propertyRecords) {
|
|
3233
|
-
if (propRecord.schemaFileId && schemaFile.models[modelName]?.properties[propRecord.name]) {
|
|
3234
|
-
const currentId = schemaFile.models[modelName].properties[propRecord.name].id;
|
|
3235
|
-
if (currentId !== propRecord.schemaFileId) {
|
|
3236
|
-
schemaFile.models[modelName].properties[propRecord.name].id = propRecord.schemaFileId;
|
|
3237
|
-
logger$7(`Updated schemaFile property ID for ${modelName}.${propRecord.name} from ${currentId} to ${propRecord.schemaFileId}`);
|
|
3238
|
-
schemaFileUpdated = true;
|
|
3239
|
-
}
|
|
3240
|
-
}
|
|
3241
|
-
}
|
|
3242
|
-
}
|
|
3243
|
-
}
|
|
3244
|
-
// Always update schemaData to ensure it matches the current schemaFile state
|
|
3245
|
-
// This is important even if nothing changed, to ensure consistency
|
|
3246
|
-
const updatedSchemaData = JSON.stringify(schemaFile, null, 2);
|
|
3247
|
-
// Update the schema record in the database with current schemaData
|
|
3248
|
-
const _mod_14 = await import('./index-C0SetTd1.js');
|
|
3249
|
-
const _ns_14 = _mod_14.bl;
|
|
3250
|
-
const schemaSchemaMod = _ns_14;
|
|
3251
|
-
const { schemas: schemasTable } = schemaSchemaMod;
|
|
3252
|
-
await db
|
|
3253
|
-
.update(schemasTable)
|
|
3254
|
-
.set({ schemaData: updatedSchemaData })
|
|
3255
|
-
.where(eq(schemasTable.id, schemaRecord.id));
|
|
3256
|
-
clearNameMatchLevels();
|
|
3257
|
-
if (schemaFileUpdated) {
|
|
3258
|
-
logger$7(`Updated schemaData in database with actual property IDs for schema "${schemaName}"`);
|
|
3259
|
-
}
|
|
3260
|
-
else {
|
|
3261
|
-
logger$7(`Verified schemaData in database matches schemaFile for schema "${schemaName}"`);
|
|
3262
|
-
}
|
|
2670
|
+
await applySchemaToDb(schemaFile, modelDefinitions, modelFileIds, propertyFileIds, propertyDefinitions).finally(rowsWritten.settle);
|
|
3263
2671
|
}
|
|
3264
2672
|
}
|
|
3265
2673
|
catch (dbError) {
|
|
3266
2674
|
// Database not available - log warning but continue
|
|
3267
|
-
logger$
|
|
2675
|
+
logger$3('Database not available, skipping database operations:', dbError instanceof Error ? dbError.message : String(dbError));
|
|
3268
2676
|
}
|
|
3269
2677
|
finally {
|
|
3270
2678
|
rowsWritten.settle();
|
|
@@ -3272,7 +2680,7 @@ const loadSchemaFromFile = async (schemaFilePath) => {
|
|
|
3272
2680
|
// Models are now Model instances, no registration needed
|
|
3273
2681
|
// They should be created via Model.create() and are accessible via Model static methods
|
|
3274
2682
|
for (const [modelName] of Object.entries(modelDefinitions)) {
|
|
3275
|
-
logger$
|
|
2683
|
+
logger$3('loadSchemaFromFile - model available:', modelName);
|
|
3276
2684
|
}
|
|
3277
2685
|
return schemaFilePath;
|
|
3278
2686
|
}
|
|
@@ -3372,19 +2780,19 @@ const createRowsWrittenSignal = () => {
|
|
|
3372
2780
|
const createModelFromJson = async (modelName, modelDef, schemaName, modelFileId, // Optional modelFileId from JSON file
|
|
3373
2781
|
propertyFileIds, // Optional map of property names to their file IDs from the JSON file
|
|
3374
2782
|
persistedBy) => {
|
|
3375
|
-
const
|
|
3376
|
-
const
|
|
3377
|
-
const modelMod =
|
|
2783
|
+
const _mod_9 = await import('./errors-D1zHAqjr.js');
|
|
2784
|
+
const _ns_9 = _mod_9.i;
|
|
2785
|
+
const modelMod = _ns_9;
|
|
3378
2786
|
const { Model } = modelMod;
|
|
3379
2787
|
const convertedProperties = jsonPropertiesToSchemaProperties(modelName, modelDef, propertyFileIds);
|
|
3380
2788
|
// Create Model instance with the definition
|
|
3381
2789
|
// Pass id (schemaFileId) if provided to ensure Model instance uses correct ID
|
|
3382
2790
|
// Note: indexes and description are ignored - they remain in JSON for schema file format compliance but are not used by Model instances
|
|
3383
2791
|
if (modelFileId) {
|
|
3384
|
-
logger$
|
|
2792
|
+
logger$3(`Creating schema model "${modelName}" with modelFileId: ${modelFileId}`);
|
|
3385
2793
|
}
|
|
3386
2794
|
else {
|
|
3387
|
-
logger$
|
|
2795
|
+
logger$3(`Warning: Creating schema model "${modelName}" without modelFileId - it will be renamed if duplicates exist`);
|
|
3388
2796
|
}
|
|
3389
2797
|
// The schema holds its models once (Model.takeSchemaHold); a model it already holds takes no more.
|
|
3390
2798
|
const schemaHold = Model.takeSchemaHold(modelFileId);
|
|
@@ -3416,7 +2824,7 @@ const createModelsFromJson = async (importData, modelFileIds, propertyFileIds, p
|
|
|
3416
2824
|
// Use modelFileId from map (no fallback to modelDef.id as JsonImportSchema doesn't have id property)
|
|
3417
2825
|
const finalModelFileId = modelFileId;
|
|
3418
2826
|
if (!finalModelFileId) {
|
|
3419
|
-
logger$
|
|
2827
|
+
logger$3(`Warning: No modelFileId found for model "${modelName}" - model will be created without ID`);
|
|
3420
2828
|
}
|
|
3421
2829
|
// Get propertyFileIds for this model if available
|
|
3422
2830
|
const modelPropertyFileIds = propertyFileIds?.get(modelName);
|
|
@@ -3431,9 +2839,10 @@ const createModelsFromJson = async (importData, modelFileIds, propertyFileIds, p
|
|
|
3431
2839
|
* use correct schemaFileIds - preventing duplicate models (Publication 1, etc.) when
|
|
3432
2840
|
* processSchemaFiles runs multiple times.
|
|
3433
2841
|
* @param filePath - Path to the JSON import file
|
|
2842
|
+
* @param persistedBy - See createModelsFromJson
|
|
3434
2843
|
* @returns ModelDefinitions with Model classes created from the JSON schema
|
|
3435
2844
|
*/
|
|
3436
|
-
const createModelsFromJsonFile = async (filePath) => {
|
|
2845
|
+
const createModelsFromJsonFile = async (filePath, persistedBy) => {
|
|
3437
2846
|
const workingDir = BaseFileManager.getWorkingDir();
|
|
3438
2847
|
const internalFilePath = filePath.startsWith(workingDir) ? filePath : `${workingDir}/${filePath}`;
|
|
3439
2848
|
const content = await BaseFileManager.readFileAsString(internalFilePath);
|
|
@@ -3462,7 +2871,7 @@ const createModelsFromJsonFile = async (filePath) => {
|
|
|
3462
2871
|
}
|
|
3463
2872
|
}
|
|
3464
2873
|
}
|
|
3465
|
-
return createModelsFromJson(importData, modelFileIds, propertyFileIds);
|
|
2874
|
+
return createModelsFromJson(importData, modelFileIds, propertyFileIds, persistedBy);
|
|
3466
2875
|
};
|
|
3467
2876
|
|
|
3468
2877
|
var $schema = "https://seedprotocol.org/schemas/data-model/v1";
|
|
@@ -3606,7 +3015,7 @@ var SEEDPROTOCOL_Seed_Protocol_v1 = /*#__PURE__*/Object.freeze({
|
|
|
3606
3015
|
version: version
|
|
3607
3016
|
});
|
|
3608
3017
|
|
|
3609
|
-
const logger$
|
|
3018
|
+
const logger$2 = debug('seedSdk:client:actors:processSchemaFiles');
|
|
3610
3019
|
let processSchemaFilesChain = Promise.resolve();
|
|
3611
3020
|
function resolveSchemaFilePath(schemaFile) {
|
|
3612
3021
|
const path = BaseFileManager.getPathModule();
|
|
@@ -3634,7 +3043,7 @@ async function resolveSchemaNameFromSource(source) {
|
|
|
3634
3043
|
}
|
|
3635
3044
|
}
|
|
3636
3045
|
catch (error) {
|
|
3637
|
-
logger$
|
|
3046
|
+
logger$2('Could not resolve schema name from path:', source, error);
|
|
3638
3047
|
}
|
|
3639
3048
|
}
|
|
3640
3049
|
return null;
|
|
@@ -3649,7 +3058,7 @@ function userSchemaLoadError(option, source, error) {
|
|
|
3649
3058
|
// Schema processing can be slow with syncSchemaFromSource, loadAllSchemasFromDb, and OPFS file I/O
|
|
3650
3059
|
const PROCESS_SCHEMA_FILES_TIMEOUT_MS = 120000;
|
|
3651
3060
|
const processSchemaFiles = fromCallback(({ sendBack, input: { context } }) => {
|
|
3652
|
-
logger$
|
|
3061
|
+
logger$2('processSchemaFiles started');
|
|
3653
3062
|
let hasResponded = false;
|
|
3654
3063
|
let timeoutId = null;
|
|
3655
3064
|
const reportError = (error) => {
|
|
@@ -3659,7 +3068,7 @@ const processSchemaFiles = fromCallback(({ sendBack, input: { context } }) => {
|
|
|
3659
3068
|
clearTimeout(timeoutId);
|
|
3660
3069
|
timeoutId = null;
|
|
3661
3070
|
}
|
|
3662
|
-
logger$
|
|
3071
|
+
logger$2('processSchemaFiles error:', error);
|
|
3663
3072
|
sendBack({
|
|
3664
3073
|
type: 'error',
|
|
3665
3074
|
error: error instanceof Error ? error : new Error(String(error))
|
|
@@ -3673,7 +3082,7 @@ const processSchemaFiles = fromCallback(({ sendBack, input: { context } }) => {
|
|
|
3673
3082
|
clearTimeout(timeoutId);
|
|
3674
3083
|
timeoutId = null;
|
|
3675
3084
|
}
|
|
3676
|
-
logger$
|
|
3085
|
+
logger$2('processSchemaFiles completed');
|
|
3677
3086
|
sendBack({ type: ClientManagerEvents.PROCESS_SCHEMA_FILES_SUCCESS });
|
|
3678
3087
|
}
|
|
3679
3088
|
};
|
|
@@ -3685,7 +3094,7 @@ const processSchemaFiles = fromCallback(({ sendBack, input: { context } }) => {
|
|
|
3685
3094
|
// Schemas written (or confirmed present) this run — skip redundant loadSchemaFromFile later
|
|
3686
3095
|
const schemasWrittenThisRun = new Set();
|
|
3687
3096
|
// First, load the internal seed-protocol schema
|
|
3688
|
-
logger$
|
|
3097
|
+
logger$2('Loading internal seed-protocol schema');
|
|
3689
3098
|
const internalSchemaData = internalSchema;
|
|
3690
3099
|
const db = BaseDb.getAppDb();
|
|
3691
3100
|
const internalSchemaExists = db
|
|
@@ -3694,21 +3103,21 @@ const processSchemaFiles = fromCallback(({ sendBack, input: { context } }) => {
|
|
|
3694
3103
|
// Always mark internal schema as written so the DB/file loop does not re-apply it
|
|
3695
3104
|
schemasWrittenThisRun.add(SEED_PROTOCOL_SCHEMA_NAME);
|
|
3696
3105
|
if (internalSchemaExists) {
|
|
3697
|
-
logger$
|
|
3106
|
+
logger$2('Internal seed-protocol schema already in DB, skipping import');
|
|
3698
3107
|
}
|
|
3699
3108
|
else {
|
|
3700
3109
|
try {
|
|
3701
3110
|
// Import the internal schema to database (will create models and add to store)
|
|
3702
3111
|
await importJsonSchema({ contents: JSON.stringify(internalSchemaData) }, internalSchemaData.version);
|
|
3703
|
-
logger$
|
|
3112
|
+
logger$2(`Loaded internal seed-protocol schema v${internalSchemaData.version}`);
|
|
3704
3113
|
}
|
|
3705
3114
|
catch (error) {
|
|
3706
3115
|
// If schema already exists, that's fine - it means it was already loaded
|
|
3707
3116
|
if (error?.message?.includes('already exists')) {
|
|
3708
|
-
logger$
|
|
3117
|
+
logger$2('Internal seed-protocol schema already loaded');
|
|
3709
3118
|
}
|
|
3710
3119
|
else {
|
|
3711
|
-
logger$
|
|
3120
|
+
logger$2('Error loading internal seed-protocol schema:', error);
|
|
3712
3121
|
// Don't fail if internal schema can't be loaded - it might already be in DB
|
|
3713
3122
|
}
|
|
3714
3123
|
}
|
|
@@ -3721,7 +3130,7 @@ const processSchemaFiles = fromCallback(({ sendBack, input: { context } }) => {
|
|
|
3721
3130
|
: '';
|
|
3722
3131
|
const schemaId = typeof context.schema === 'object' && context.schema?.id ? String(context.schema.id) : undefined;
|
|
3723
3132
|
if (isInternalSchema(schemaName, schemaId)) {
|
|
3724
|
-
logger$
|
|
3133
|
+
logger$2('Schema is internal (Seed Protocol), already loaded - skipping syncSchemaFromSource');
|
|
3725
3134
|
}
|
|
3726
3135
|
else {
|
|
3727
3136
|
try {
|
|
@@ -3730,7 +3139,7 @@ const processSchemaFiles = fromCallback(({ sendBack, input: { context } }) => {
|
|
|
3730
3139
|
if (syncedName) {
|
|
3731
3140
|
schemasWrittenThisRun.add(syncedName);
|
|
3732
3141
|
}
|
|
3733
|
-
logger$
|
|
3142
|
+
logger$2(`Synced canonical schema from ${typeof context.schema === 'string' ? context.schema : 'object'}`);
|
|
3734
3143
|
}
|
|
3735
3144
|
catch (error) {
|
|
3736
3145
|
// A schema the app passed in failed (missing file, bad JSON, DB write). Re-running an
|
|
@@ -3749,7 +3158,7 @@ const processSchemaFiles = fromCallback(({ sendBack, input: { context } }) => {
|
|
|
3749
3158
|
if (parsed?.metadata?.name) {
|
|
3750
3159
|
schemasWrittenThisRun.add(String(parsed.metadata.name));
|
|
3751
3160
|
}
|
|
3752
|
-
logger$
|
|
3161
|
+
logger$2(`Loaded schema from ${resolvedPath}`);
|
|
3753
3162
|
}
|
|
3754
3163
|
catch (error) {
|
|
3755
3164
|
throw userSchemaLoadError('schemaFile', context.schemaFile, error);
|
|
@@ -3757,14 +3166,14 @@ const processSchemaFiles = fromCallback(({ sendBack, input: { context } }) => {
|
|
|
3757
3166
|
}
|
|
3758
3167
|
// Process minimal import files (files without $schema) - skip when canonical schema is set
|
|
3759
3168
|
if (!context.schema) {
|
|
3760
|
-
logger$
|
|
3169
|
+
logger$2('Listing schema files');
|
|
3761
3170
|
let schemaFiles = [];
|
|
3762
3171
|
try {
|
|
3763
3172
|
schemaFiles = await listSchemaFiles();
|
|
3764
|
-
logger$
|
|
3173
|
+
logger$2(`Found ${schemaFiles.length} schema files to process`);
|
|
3765
3174
|
}
|
|
3766
3175
|
catch (error) {
|
|
3767
|
-
logger$
|
|
3176
|
+
logger$2('Error listing schema files (continuing anyway):', error);
|
|
3768
3177
|
schemaFiles = [];
|
|
3769
3178
|
}
|
|
3770
3179
|
for (const schemaFile of schemaFiles) {
|
|
@@ -3775,25 +3184,29 @@ const processSchemaFiles = fromCallback(({ sendBack, input: { context } }) => {
|
|
|
3775
3184
|
}
|
|
3776
3185
|
}
|
|
3777
3186
|
catch (error) {
|
|
3778
|
-
logger$
|
|
3187
|
+
logger$2(`Error importing schema file ${schemaFile.filePath}:`, error);
|
|
3779
3188
|
}
|
|
3780
3189
|
}
|
|
3781
3190
|
}
|
|
3782
3191
|
// Then, load all schemas using the unified database-first approach
|
|
3783
|
-
logger$
|
|
3192
|
+
logger$2('Loading schemas from database and files');
|
|
3784
3193
|
let allSchemasData = [];
|
|
3785
3194
|
try {
|
|
3786
3195
|
allSchemasData = await loadAllSchemasFromDb();
|
|
3787
|
-
logger$
|
|
3196
|
+
logger$2(`Loaded ${allSchemasData.length} schemas (${allSchemasData.filter(s => s.isDraft).length} drafts, ${allSchemasData.filter(s => !s.isDraft).length} published)`);
|
|
3788
3197
|
}
|
|
3789
3198
|
catch (error) {
|
|
3790
|
-
logger$
|
|
3199
|
+
logger$2('Error loading schemas from database (continuing anyway):', error);
|
|
3791
3200
|
// Continue with empty array - this is not critical for initialization
|
|
3792
3201
|
// Schemas can be loaded on-demand later
|
|
3793
3202
|
allSchemasData = [];
|
|
3794
3203
|
}
|
|
3795
3204
|
// Collect models to add to context (schemas are now loaded on-demand via database queries)
|
|
3796
3205
|
const allModels = { ...(context.models || {}) };
|
|
3206
|
+
// The models built below describe rows that loadSchemaFromFile or an earlier init already wrote:
|
|
3207
|
+
// they adopt those rows, and only a model with no row writes one. Without it every init rewrote
|
|
3208
|
+
// each property row and cleared is_edited.
|
|
3209
|
+
const rowsWritten = Promise.resolve();
|
|
3797
3210
|
// Linked model count per schema row, to tell whether an earlier load already applied a file's models
|
|
3798
3211
|
const linkedModelCounts = new Map();
|
|
3799
3212
|
if (db) {
|
|
@@ -3808,13 +3221,13 @@ const processSchemaFiles = fromCallback(({ sendBack, input: { context } }) => {
|
|
|
3808
3221
|
}
|
|
3809
3222
|
}
|
|
3810
3223
|
catch (error) {
|
|
3811
|
-
logger$
|
|
3224
|
+
logger$2('Error counting linked models (re-applying all schema files):', error);
|
|
3812
3225
|
}
|
|
3813
3226
|
}
|
|
3814
3227
|
for (const schemaData of allSchemasData) {
|
|
3815
3228
|
const schema = schemaData.schema;
|
|
3816
3229
|
const schemaName = schema.metadata?.name || 'unknown';
|
|
3817
|
-
logger$
|
|
3230
|
+
logger$2(`Processing schema: ${schemaName} v${schema.version} (${schemaData.isDraft ? 'draft' : 'published'}, source: ${schemaData.source})`);
|
|
3818
3231
|
// For published schemas (not drafts), load models from file if available
|
|
3819
3232
|
if (!schemaData.isDraft && schema.id) {
|
|
3820
3233
|
// loadAllSchemasFromDb already picked the latest file for this schema (and read it)
|
|
@@ -3834,17 +3247,17 @@ const processSchemaFiles = fromCallback(({ sendBack, input: { context } }) => {
|
|
|
3834
3247
|
schemaData.schemaRecordId != null &&
|
|
3835
3248
|
(linkedModelCounts.get(schemaData.schemaRecordId) ?? 0) >= expectedModelCount;
|
|
3836
3249
|
if (alreadyWritten || alreadyApplied) {
|
|
3837
|
-
const modelDefinitions = await createModelsFromJsonFile(latestFilePath);
|
|
3250
|
+
const modelDefinitions = await createModelsFromJsonFile(latestFilePath, rowsWritten);
|
|
3838
3251
|
Object.assign(allModels, modelDefinitions);
|
|
3839
3252
|
}
|
|
3840
3253
|
else {
|
|
3841
3254
|
await loadSchemaFromFile(latestFilePath);
|
|
3842
|
-
const modelDefinitions = await createModelsFromJsonFile(latestFilePath);
|
|
3255
|
+
const modelDefinitions = await createModelsFromJsonFile(latestFilePath, rowsWritten);
|
|
3843
3256
|
Object.assign(allModels, modelDefinitions);
|
|
3844
3257
|
}
|
|
3845
3258
|
}
|
|
3846
3259
|
catch (error) {
|
|
3847
|
-
logger$
|
|
3260
|
+
logger$2(`Error loading schema file for ${schemaName}:`, error);
|
|
3848
3261
|
}
|
|
3849
3262
|
}
|
|
3850
3263
|
else {
|
|
@@ -3891,13 +3304,13 @@ const processSchemaFiles = fromCallback(({ sendBack, input: { context } }) => {
|
|
|
3891
3304
|
},
|
|
3892
3305
|
])),
|
|
3893
3306
|
};
|
|
3894
|
-
const modelDefinitions = await createModelsFromJson(importData, modelFileIds, propertyFileIds);
|
|
3307
|
+
const modelDefinitions = await createModelsFromJson(importData, modelFileIds, propertyFileIds, rowsWritten);
|
|
3895
3308
|
Object.assign(allModels, modelDefinitions);
|
|
3896
|
-
logger$
|
|
3309
|
+
logger$2(`Loaded ${Object.keys(modelDefinitions).length} models from schema data for ${schemaName}`);
|
|
3897
3310
|
}
|
|
3898
3311
|
}
|
|
3899
3312
|
catch (error) {
|
|
3900
|
-
logger$
|
|
3313
|
+
logger$2(`Error creating models from schema data for ${schemaName}:`, error);
|
|
3901
3314
|
}
|
|
3902
3315
|
}
|
|
3903
3316
|
}
|
|
@@ -3945,13 +3358,13 @@ const processSchemaFiles = fromCallback(({ sendBack, input: { context } }) => {
|
|
|
3945
3358
|
},
|
|
3946
3359
|
])),
|
|
3947
3360
|
};
|
|
3948
|
-
const modelDefinitions = await createModelsFromJson(importData, modelFileIds, propertyFileIds);
|
|
3361
|
+
const modelDefinitions = await createModelsFromJson(importData, modelFileIds, propertyFileIds, rowsWritten);
|
|
3949
3362
|
Object.assign(allModels, modelDefinitions);
|
|
3950
|
-
logger$
|
|
3363
|
+
logger$2(`Loaded ${Object.keys(modelDefinitions).length} models from draft schema ${schemaName}`);
|
|
3951
3364
|
}
|
|
3952
3365
|
}
|
|
3953
3366
|
catch (error) {
|
|
3954
|
-
logger$
|
|
3367
|
+
logger$2(`Error creating models from draft schema ${schemaName}:`, error);
|
|
3955
3368
|
}
|
|
3956
3369
|
}
|
|
3957
3370
|
// Schemas are now loaded on-demand via database queries (useSchemas hook uses loadAllSchemasFromDb)
|
|
@@ -3982,651 +3395,6 @@ const processSchemaFiles = fromCallback(({ sendBack, input: { context } }) => {
|
|
|
3982
3395
|
};
|
|
3983
3396
|
});
|
|
3984
3397
|
|
|
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
|
-
|
|
4069
|
-
/**
|
|
4070
|
-
* A legacy ItemStorage draft row: a local edit (no attestation uid, not derived from one) that holds
|
|
4071
|
-
* the content itself in property_value, with no file reference. Item.create / createNewItem stored
|
|
4072
|
-
* ItemStorage values like this before they went through the save pipeline.
|
|
4073
|
-
*/
|
|
4074
|
-
const isVerbatimItemStorageDraftRow = (row) => !row.uid &&
|
|
4075
|
-
row.derivedFromUid == null &&
|
|
4076
|
-
!row.refResolvedValue &&
|
|
4077
|
-
typeof row.propertyValue === 'string' &&
|
|
4078
|
-
row.propertyValue !== '';
|
|
4079
|
-
/**
|
|
4080
|
-
* Convert one legacy ItemStorage draft row (see {@link isVerbatimItemStorageDraftRow}) into the
|
|
4081
|
-
* shape saveItemStorage gives a row: the content goes to the file a save would write
|
|
4082
|
-
* (`<seedUid or seedLocalId><extension>` in the property's storage directory), and the row records
|
|
4083
|
-
* `refResolvedValue`, `localStorageDir` and `refValueType: 'file'` with property_value cleared.
|
|
4084
|
-
* Used by publish (resolveItemStorageChildFile) and the one-time migration (migrateLegacyItemStorageRows).
|
|
4085
|
-
*
|
|
4086
|
-
* Reading the row, writing the file and updating the row happen under the file's lock
|
|
4087
|
-
* ({@link withItemStorageFileLock}), which saveItemStorage holds too: a save in this or another tab
|
|
4088
|
-
* either finishes before (the row, read again once the lock is held, is no longer legacy and is
|
|
4089
|
-
* left alone) or starts after (and overwrites the file and row with its content). Without the lock
|
|
4090
|
-
* a save landing between the read and the file write would have its file overwritten with the old
|
|
4091
|
-
* content. The row update also stays conditional on the row being unchanged, for writers that
|
|
4092
|
-
* don't take the lock (a tab still running an older SDK).
|
|
4093
|
-
*
|
|
4094
|
-
* Returns undefined when there was nothing to convert. Throws when the file can't be written; the
|
|
4095
|
-
* row is then unchanged.
|
|
4096
|
-
*/
|
|
4097
|
-
const convertVerbatimItemStorageRow = async (localId, storage = {}) => {
|
|
4098
|
-
const appDb = BaseDb.getAppDb();
|
|
4099
|
-
if (!appDb || !localId)
|
|
4100
|
-
return undefined;
|
|
4101
|
-
const targetOf = (row) => {
|
|
4102
|
-
if (!isVerbatimItemStorageDraftRow(row))
|
|
4103
|
-
return undefined;
|
|
4104
|
-
const seedId = storage.seedId || row.seedUid || row.seedLocalId;
|
|
4105
|
-
if (!seedId)
|
|
4106
|
-
return undefined;
|
|
4107
|
-
return {
|
|
4108
|
-
seedId,
|
|
4109
|
-
localStorageDir: storage.localStorageDir || row.localStorageDir,
|
|
4110
|
-
filenameSuffix: storage.filenameSuffix,
|
|
4111
|
-
};
|
|
4112
|
-
};
|
|
4113
|
-
return withLockedItemStorageRow(localId, (row) => {
|
|
4114
|
-
const target = targetOf(row);
|
|
4115
|
-
return target && getItemStorageFilePath(target);
|
|
4116
|
-
}, async (row) => {
|
|
4117
|
-
const content = row.propertyValue;
|
|
4118
|
-
const { fileName, filePath, localStorageDir } = await writeItemStorageFile(targetOf(row), content);
|
|
4119
|
-
await appDb
|
|
4120
|
-
.update(metadata$1)
|
|
4121
|
-
.set({ refResolvedValue: fileName, localStorageDir, refValueType: 'file', propertyValue: null })
|
|
4122
|
-
.where(and(eq(metadata$1.localId, localId), isNull(metadata$1.refResolvedValue), eq(metadata$1.propertyValue, content)));
|
|
4123
|
-
// Changed between the read and the update by a writer outside the lock: that change stands.
|
|
4124
|
-
const after = await appDb
|
|
4125
|
-
.select({ refResolvedValue: metadata$1.refResolvedValue, propertyValue: metadata$1.propertyValue })
|
|
4126
|
-
.from(metadata$1)
|
|
4127
|
-
.where(eq(metadata$1.localId, localId))
|
|
4128
|
-
.limit(1);
|
|
4129
|
-
if (after[0]?.refResolvedValue !== fileName || after[0]?.propertyValue != null)
|
|
4130
|
-
return undefined;
|
|
4131
|
-
return { fileName, filePath, localStorageDir, content };
|
|
4132
|
-
});
|
|
4133
|
-
};
|
|
4134
|
-
|
|
4135
|
-
const logger$5 = debug('seedSdk:db:migrateLegacyItemStorageRows');
|
|
4136
|
-
/** appState key recording that legacy ItemStorage rows have been written to their files. */
|
|
4137
|
-
const LEGACY_ITEM_STORAGE_MIGRATION_KEY = 'legacyItemStorageFiles:v1';
|
|
4138
|
-
/** Runs in a row that left rows unconverted because a file write failed, before giving up. */
|
|
4139
|
-
const LEGACY_ITEM_STORAGE_MIGRATION_MAX_ATTEMPTS = 3;
|
|
4140
|
-
const readMarker = async () => {
|
|
4141
|
-
const db = BaseDb.getAppDb();
|
|
4142
|
-
const rows = await db
|
|
4143
|
-
.select({ value: appState.value })
|
|
4144
|
-
.from(appState)
|
|
4145
|
-
.where(eq(appState.key, LEGACY_ITEM_STORAGE_MIGRATION_KEY))
|
|
4146
|
-
.limit(1);
|
|
4147
|
-
if (!rows.length)
|
|
4148
|
-
return undefined;
|
|
4149
|
-
try {
|
|
4150
|
-
return JSON.parse(rows[0].value ?? '');
|
|
4151
|
-
}
|
|
4152
|
-
catch {
|
|
4153
|
-
return null;
|
|
4154
|
-
}
|
|
4155
|
-
};
|
|
4156
|
-
const writeMarker = async (marker) => {
|
|
4157
|
-
const db = BaseDb.getAppDb();
|
|
4158
|
-
const now = Date.now();
|
|
4159
|
-
const value = JSON.stringify(marker);
|
|
4160
|
-
await db
|
|
4161
|
-
.insert(appState)
|
|
4162
|
-
.values({ key: LEGACY_ITEM_STORAGE_MIGRATION_KEY, value, createdAt: now, updatedAt: now })
|
|
4163
|
-
.onConflictDoUpdate({ target: appState.key, set: { value, updatedAt: now } });
|
|
4164
|
-
};
|
|
4165
|
-
/**
|
|
4166
|
-
* The storage settings of a metadata row's property: by its property_id, else by name in the
|
|
4167
|
-
* seed's own model (model names are only unique per schema). Undefined when it can't be told.
|
|
4168
|
-
*/
|
|
4169
|
-
const createStorageResolver = () => {
|
|
4170
|
-
const db = BaseDb.getAppDb();
|
|
4171
|
-
const byPropertyId = new Map();
|
|
4172
|
-
const byModelAndName = new Map();
|
|
4173
|
-
return async (row) => {
|
|
4174
|
-
if (row.propertyId != null) {
|
|
4175
|
-
if (!byPropertyId.has(row.propertyId)) {
|
|
4176
|
-
const found = await db
|
|
4177
|
-
.select({
|
|
4178
|
-
storageType: properties.storageType,
|
|
4179
|
-
localStorageDir: properties.localStorageDir,
|
|
4180
|
-
filenameSuffix: properties.filenameSuffix,
|
|
4181
|
-
})
|
|
4182
|
-
.from(properties)
|
|
4183
|
-
.where(eq(properties.id, row.propertyId))
|
|
4184
|
-
.limit(1);
|
|
4185
|
-
byPropertyId.set(row.propertyId, found[0]);
|
|
4186
|
-
}
|
|
4187
|
-
const fromId = byPropertyId.get(row.propertyId);
|
|
4188
|
-
if (fromId)
|
|
4189
|
-
return fromId;
|
|
4190
|
-
}
|
|
4191
|
-
const modelFileId = await resolveItemModelFileId({ seedLocalId: row.seedLocalId, seedUid: row.seedUid });
|
|
4192
|
-
if (!modelFileId || !row.propertyName)
|
|
4193
|
-
return undefined;
|
|
4194
|
-
const key = `${modelFileId}\u0000${row.propertyName}`;
|
|
4195
|
-
if (!byModelAndName.has(key)) {
|
|
4196
|
-
const found = await db
|
|
4197
|
-
.select({
|
|
4198
|
-
storageType: properties.storageType,
|
|
4199
|
-
localStorageDir: properties.localStorageDir,
|
|
4200
|
-
filenameSuffix: properties.filenameSuffix,
|
|
4201
|
-
})
|
|
4202
|
-
.from(properties)
|
|
4203
|
-
.innerJoin(models$1, eq(properties.modelId, models$1.id))
|
|
4204
|
-
.where(and(eq(models$1.schemaFileId, modelFileId), eq(properties.name, row.propertyName)))
|
|
4205
|
-
.limit(1);
|
|
4206
|
-
byModelAndName.set(key, found[0]);
|
|
4207
|
-
}
|
|
4208
|
-
return byModelAndName.get(key);
|
|
4209
|
-
};
|
|
4210
|
-
};
|
|
4211
|
-
/** True if `row` is the row readers show for its property: the newest of its seed's rows by that name. */
|
|
4212
|
-
const isNewestRowOfProperty = async (row) => {
|
|
4213
|
-
if (!row.seedLocalId || !row.propertyName)
|
|
4214
|
-
return false;
|
|
4215
|
-
const db = BaseDb.getAppDb();
|
|
4216
|
-
const siblings = await db
|
|
4217
|
-
.select()
|
|
4218
|
-
.from(metadata$1)
|
|
4219
|
-
.where(and(eq(metadata$1.seedLocalId, row.seedLocalId), eq(metadata$1.propertyName, row.propertyName)));
|
|
4220
|
-
return [...siblings].sort(compareMetadataRowsLatestFirst)[0]?.localId === row.localId;
|
|
4221
|
-
};
|
|
4222
|
-
/**
|
|
4223
|
-
* One-time data migration: writes the content of legacy ItemStorage draft rows to their files.
|
|
4224
|
-
*
|
|
4225
|
-
* Before Item.create / createNewItem saved ItemStorage values through the save pipeline, a value
|
|
4226
|
-
* given at creation was stored verbatim in metadata.property_value with no file. Publish converts
|
|
4227
|
-
* such a row lazily (resolveItemStorageChildFile); this converts them all up front, with the same
|
|
4228
|
-
* code ({@link convertVerbatimItemStorageRow}), so every ItemStorage draft has the shape a save
|
|
4229
|
-
* gives it: the content in `<seedUid or seedLocalId><extension>`, the row holding
|
|
4230
|
-
* refResolvedValue / localStorageDir / refValueType 'file' and no property_value.
|
|
4231
|
-
*
|
|
4232
|
-
* Only local drafts (no uid, not derived from an attestation) of properties whose properties row
|
|
4233
|
-
* says `storage_type = 'ItemStorage'` are touched, and of those only the newest row of each
|
|
4234
|
-
* seed's property: that is the row reads show and saves write to, and older rows sharing the one
|
|
4235
|
-
* file name would overwrite it with older content. Published and synced rows are never changed.
|
|
4236
|
-
*
|
|
4237
|
-
* A row that fails is logged and left as it was (publish still converts it). The run is recorded
|
|
4238
|
-
* in appState under {@link LEGACY_ITEM_STORAGE_MIGRATION_KEY}; a run with failed rows is retried
|
|
4239
|
-
* on the next start, up to {@link LEGACY_ITEM_STORAGE_MIGRATION_MAX_ATTEMPTS} runs. Safe to run
|
|
4240
|
-
* again regardless: a converted row no longer matches.
|
|
4241
|
-
*
|
|
4242
|
-
* @param options.force run even when the marker says it is done
|
|
4243
|
-
*/
|
|
4244
|
-
async function migrateLegacyItemStorageRows(options = {}) {
|
|
4245
|
-
const result = {
|
|
4246
|
-
alreadyDone: false,
|
|
4247
|
-
candidates: 0,
|
|
4248
|
-
converted: 0,
|
|
4249
|
-
failed: 0,
|
|
4250
|
-
skipped: 0,
|
|
4251
|
-
};
|
|
4252
|
-
const db = BaseDb.getAppDb();
|
|
4253
|
-
if (!db)
|
|
4254
|
-
return { ...result, alreadyDone: true };
|
|
4255
|
-
const marker = await readMarker();
|
|
4256
|
-
const previousAttempts = marker?.status === 'retry' ? marker.attempts : 0;
|
|
4257
|
-
if (!options.force && marker && marker.status === 'done') {
|
|
4258
|
-
return { ...result, alreadyDone: true };
|
|
4259
|
-
}
|
|
4260
|
-
const itemStorageNames = (await db
|
|
4261
|
-
.selectDistinct({ name: properties.name })
|
|
4262
|
-
.from(properties)
|
|
4263
|
-
.where(eq(properties.storageType, 'ItemStorage'))).map((r) => r.name);
|
|
4264
|
-
const candidates = itemStorageNames.length
|
|
4265
|
-
? await db
|
|
4266
|
-
.select()
|
|
4267
|
-
.from(metadata$1)
|
|
4268
|
-
.where(and(inArray(metadata$1.propertyName, itemStorageNames), or(isNull(metadata$1.uid), eq(metadata$1.uid, '')), isNull(metadata$1.derivedFromUid), isNull(metadata$1.refResolvedValue), isNotNull(metadata$1.propertyValue), ne(metadata$1.propertyValue, '')))
|
|
4269
|
-
: [];
|
|
4270
|
-
const resolveStorage = createStorageResolver();
|
|
4271
|
-
for (const row of candidates) {
|
|
4272
|
-
if (!row.localId || !isVerbatimItemStorageDraftRow(row))
|
|
4273
|
-
continue;
|
|
4274
|
-
try {
|
|
4275
|
-
const storage = await resolveStorage(row);
|
|
4276
|
-
if (storage?.storageType !== 'ItemStorage')
|
|
4277
|
-
continue;
|
|
4278
|
-
result.candidates++;
|
|
4279
|
-
if (!(await isNewestRowOfProperty(row))) {
|
|
4280
|
-
result.skipped++;
|
|
4281
|
-
continue;
|
|
4282
|
-
}
|
|
4283
|
-
const converted = await convertVerbatimItemStorageRow(row.localId, {
|
|
4284
|
-
localStorageDir: storage.localStorageDir,
|
|
4285
|
-
filenameSuffix: storage.filenameSuffix,
|
|
4286
|
-
});
|
|
4287
|
-
if (converted) {
|
|
4288
|
-
result.converted++;
|
|
4289
|
-
logger$5(`wrote ${row.propertyName} of ${row.seedLocalId} to ${converted.filePath}`);
|
|
4290
|
-
}
|
|
4291
|
-
else {
|
|
4292
|
-
result.skipped++;
|
|
4293
|
-
}
|
|
4294
|
-
}
|
|
4295
|
-
catch (error) {
|
|
4296
|
-
result.failed++;
|
|
4297
|
-
logger$5(`converting ${row.propertyName} of ${row.seedLocalId} (${row.localId}) failed; left as is`, error);
|
|
4298
|
-
}
|
|
4299
|
-
}
|
|
4300
|
-
const attempts = previousAttempts + 1;
|
|
4301
|
-
await writeMarker({
|
|
4302
|
-
status: result.failed > 0 && attempts < LEGACY_ITEM_STORAGE_MIGRATION_MAX_ATTEMPTS ? 'retry' : 'done',
|
|
4303
|
-
attempts,
|
|
4304
|
-
converted: result.converted,
|
|
4305
|
-
failed: result.failed,
|
|
4306
|
-
at: Date.now(),
|
|
4307
|
-
});
|
|
4308
|
-
if (result.candidates > 0) {
|
|
4309
|
-
logger$5(`legacy ItemStorage rows: ${result.converted} converted, ${result.failed} failed, ` +
|
|
4310
|
-
`${result.skipped} skipped of ${result.candidates}`);
|
|
4311
|
-
}
|
|
4312
|
-
return result;
|
|
4313
|
-
}
|
|
4314
|
-
let running$4;
|
|
4315
|
-
let deferredUntilLeader$4 = false;
|
|
4316
|
-
const runInBackground$4 = () => {
|
|
4317
|
-
running$4 ?? (running$4 = withDbTabLock('item-storage-migration', () => migrateLegacyItemStorageRows())
|
|
4318
|
-
.then(() => undefined)
|
|
4319
|
-
.catch((error) => {
|
|
4320
|
-
// Never fails init: rows stay as they were and publish converts them lazily.
|
|
4321
|
-
logger$5('legacy ItemStorage migration failed', error);
|
|
4322
|
-
})
|
|
4323
|
-
.finally(() => {
|
|
4324
|
-
running$4 = undefined;
|
|
4325
|
-
}));
|
|
4326
|
-
return running$4;
|
|
4327
|
-
};
|
|
4328
|
-
/**
|
|
4329
|
-
* Starts {@link migrateLegacyItemStorageRows} in the background once client init has finished
|
|
4330
|
-
* (the properties table then holds the current storage settings). It runs in the leader tab only
|
|
4331
|
-
* (docs/MULTI_TAB.md), under a `seed:item-storage-migration:<db>` lock in case several tabs lead
|
|
4332
|
-
* (`multiTab: 'off'`); a tab that isn't leader runs it if it takes over. Never throws.
|
|
4333
|
-
*/
|
|
4334
|
-
function startLegacyItemStorageMigration() {
|
|
4335
|
-
if (isLeaderTab()) {
|
|
4336
|
-
void runInBackground$4();
|
|
4337
|
-
return;
|
|
4338
|
-
}
|
|
4339
|
-
if (deferredUntilLeader$4)
|
|
4340
|
-
return;
|
|
4341
|
-
deferredUntilLeader$4 = true;
|
|
4342
|
-
void whenLeaderTab().then(() => {
|
|
4343
|
-
deferredUntilLeader$4 = false;
|
|
4344
|
-
void runInBackground$4();
|
|
4345
|
-
});
|
|
4346
|
-
}
|
|
4347
|
-
|
|
4348
|
-
const logger$4 = debug('seedSdk:db:removeForeignAttestationRows');
|
|
4349
|
-
/** appState key recording that the cleanup below has run on this database. */
|
|
4350
|
-
const FOREIGN_ATTESTATION_CLEANUP_KEY = 'foreignAttestationRowsRemoved';
|
|
4351
|
-
/** Lowercased `attester` of a stored attestation JSON; NULL when the JSON is invalid or has none. */
|
|
4352
|
-
const attesterOf = (raw) => sql `(CASE WHEN json_valid(${raw}) THEN lower(json_extract(${raw}, '$.attester')) END)`;
|
|
4353
|
-
/**
|
|
4354
|
-
* Deletes rows that an SDK without the attester check (partitionByRefAttester) synced from other
|
|
4355
|
-
* accounts' attestations: versions whose attester isn't their seed's, and
|
|
4356
|
-
* properties whose attester isn't their version's, plus the properties of those versions. Sync
|
|
4357
|
-
* removes them too, but only for the seeds it reaches, and only online; this needs no network.
|
|
4358
|
-
*
|
|
4359
|
-
* Only rows synced from EAS on both sides are compared, by the `attester` in their stored
|
|
4360
|
-
* attestation, as sync compares them: local drafts and rows without a stored attestation are
|
|
4361
|
-
* kept, like partitionByRefAttester keeps children whose attesters aren't both known.
|
|
4362
|
-
*/
|
|
4363
|
-
async function removeForeignAttestationRows() {
|
|
4364
|
-
const appDb = BaseDb.getAppDb();
|
|
4365
|
-
const foreignVersions = await appDb
|
|
4366
|
-
.select({ uid: versions.uid })
|
|
4367
|
-
.from(versions)
|
|
4368
|
-
.innerJoin(seeds, eq(seeds.localId, versions.seedLocalId))
|
|
4369
|
-
.where(and(isNotNull(versions.uid), sql `${attesterOf(versions.attestationRaw)} <> ${attesterOf(seeds.attestationRaw)}`));
|
|
4370
|
-
const foreignVersionUids = foreignVersions.map((row) => row.uid).filter(Boolean);
|
|
4371
|
-
const foreignProperties = await appDb
|
|
4372
|
-
.select({ localId: metadata$1.localId })
|
|
4373
|
-
.from(metadata$1)
|
|
4374
|
-
.innerJoin(versions, eq(versions.uid, metadata$1.versionUid))
|
|
4375
|
-
.where(and(isNotNull(metadata$1.uid), sql `${attesterOf(metadata$1.attestationRaw)} <> ${attesterOf(versions.attestationRaw)}`));
|
|
4376
|
-
const foreignPropertyLocalIds = foreignProperties.map((row) => row.localId).filter(Boolean);
|
|
4377
|
-
let propertyRows = foreignPropertyLocalIds.length;
|
|
4378
|
-
await writeInBatches(foreignPropertyLocalIds, (chunk) => appDb.delete(metadata$1).where(inArray(metadata$1.localId, chunk)));
|
|
4379
|
-
await writeInBatches(foreignVersionUids, async (chunk) => {
|
|
4380
|
-
const removed = await appDb
|
|
4381
|
-
.delete(metadata$1)
|
|
4382
|
-
.where(inArray(metadata$1.versionUid, chunk))
|
|
4383
|
-
.returning({ localId: metadata$1.localId });
|
|
4384
|
-
propertyRows += removed.length;
|
|
4385
|
-
});
|
|
4386
|
-
await writeInBatches(foreignVersionUids, (chunk) => appDb.delete(versions).where(inArray(versions.uid, chunk)));
|
|
4387
|
-
return { versionRows: foreignVersionUids.length, propertyRows };
|
|
4388
|
-
}
|
|
4389
|
-
/** Runs the cleanup unless this database has had it, and records that it has. */
|
|
4390
|
-
async function runOnce$2() {
|
|
4391
|
-
const appDb = BaseDb.getAppDb();
|
|
4392
|
-
const marker = await appDb
|
|
4393
|
-
.select()
|
|
4394
|
-
.from(appState)
|
|
4395
|
-
.where(eq(appState.key, FOREIGN_ATTESTATION_CLEANUP_KEY))
|
|
4396
|
-
.limit(1);
|
|
4397
|
-
if (marker.length > 0)
|
|
4398
|
-
return;
|
|
4399
|
-
const result = await removeForeignAttestationRows();
|
|
4400
|
-
const value = JSON.stringify({ ...result, at: Date.now() });
|
|
4401
|
-
await appDb
|
|
4402
|
-
.insert(appState)
|
|
4403
|
-
.values({ key: FOREIGN_ATTESTATION_CLEANUP_KEY, value })
|
|
4404
|
-
.onConflictDoUpdate({ target: appState.key, set: { value } });
|
|
4405
|
-
if (result.versionRows > 0 || result.propertyRows > 0) {
|
|
4406
|
-
logger$4(`removed ${result.versionRows} version and ${result.propertyRows} property rows from other attesters`);
|
|
4407
|
-
}
|
|
4408
|
-
}
|
|
4409
|
-
let running$3;
|
|
4410
|
-
let deferredUntilLeader$3 = false;
|
|
4411
|
-
const runInBackground$3 = () => {
|
|
4412
|
-
// Under the sync's lock, so it can't interleave with a sync writing the same rows.
|
|
4413
|
-
running$3 ?? (running$3 = withDbTabLock('eas-sync', runOnce$2, { timeoutMs: Infinity })
|
|
4414
|
-
.catch((error) => {
|
|
4415
|
-
// Never fails init: the rows stay until the next sync of their seeds removes them.
|
|
4416
|
-
logger$4('foreign attestation cleanup failed', error);
|
|
4417
|
-
})
|
|
4418
|
-
.finally(() => {
|
|
4419
|
-
running$3 = undefined;
|
|
4420
|
-
}));
|
|
4421
|
-
return running$3;
|
|
4422
|
-
};
|
|
4423
|
-
/**
|
|
4424
|
-
* Starts {@link removeForeignAttestationRows} in the background after client init, once per
|
|
4425
|
-
* database: a one-time data fix, so an init step rather than a SQL migration (it needs the
|
|
4426
|
-
* attester out of stored JSON, the same rule as sync, and must never block or fail init). Leader
|
|
4427
|
-
* tab only (docs/MULTI_TAB.md); a tab that isn't leader runs it if it takes over. Never throws.
|
|
4428
|
-
*/
|
|
4429
|
-
function startForeignAttestationCleanup() {
|
|
4430
|
-
if (isLeaderTab()) {
|
|
4431
|
-
void runInBackground$3();
|
|
4432
|
-
return;
|
|
4433
|
-
}
|
|
4434
|
-
if (deferredUntilLeader$3)
|
|
4435
|
-
return;
|
|
4436
|
-
deferredUntilLeader$3 = true;
|
|
4437
|
-
void whenLeaderTab().then(() => {
|
|
4438
|
-
deferredUntilLeader$3 = false;
|
|
4439
|
-
void runInBackground$3();
|
|
4440
|
-
});
|
|
4441
|
-
}
|
|
4442
|
-
|
|
4443
|
-
const logger$3 = debug('seedSdk:db:alignRowPublishers');
|
|
4444
|
-
/** appState key recording that the fix below has run on this database. */
|
|
4445
|
-
const ROW_PUBLISHERS_ALIGNED_KEY = 'rowPublishersAligned';
|
|
4446
|
-
/**
|
|
4447
|
-
* Gives version and property rows their seed's publisher. Before, edits wrote property rows with no
|
|
4448
|
-
* publisher, and versions and property rows took the session's publisher rather than the seed's,
|
|
4449
|
-
* so connecting another wallet could claim rows of a seed that already had one. Local query reads
|
|
4450
|
-
* report a row's publisher as its attester and leave out rows whose attester isn't their parent's.
|
|
4451
|
-
*
|
|
4452
|
-
* Only rows without a stored attestation are changed: synced rows carry their attester in
|
|
4453
|
-
* `attestation_raw`. When the seed belongs to no wallet yet, its unsealed rows lose any publisher,
|
|
4454
|
-
* so they're claimed with it.
|
|
4455
|
-
*/
|
|
4456
|
-
async function alignRowPublishers() {
|
|
4457
|
-
const appDb = BaseDb.getAppDb();
|
|
4458
|
-
const align = async (table) => {
|
|
4459
|
-
const rows = (await appDb
|
|
4460
|
-
.select({
|
|
4461
|
-
localId: table.localId,
|
|
4462
|
-
uid: table.uid,
|
|
4463
|
-
publisher: table.publisher,
|
|
4464
|
-
seedPublisher: seeds.publisher,
|
|
4465
|
-
seedAttestationRaw: seeds.attestationRaw,
|
|
4466
|
-
seedUid: seeds.uid,
|
|
4467
|
-
attestationRaw: table.attestationRaw,
|
|
4468
|
-
})
|
|
4469
|
-
.from(table)
|
|
4470
|
-
.innerJoin(seeds, eq(seeds.localId, table.seedLocalId)));
|
|
4471
|
-
const byTarget = new Map();
|
|
4472
|
-
for (const row of rows) {
|
|
4473
|
-
if (!row.localId || (row.attestationRaw != null && row.attestationRaw !== ''))
|
|
4474
|
-
continue;
|
|
4475
|
-
const seedPublisher = normalizePublisher(resolvePublisherFromSeedRow({
|
|
4476
|
-
publisher: row.seedPublisher,
|
|
4477
|
-
attestationRaw: row.seedAttestationRaw,
|
|
4478
|
-
uid: row.seedUid,
|
|
4479
|
-
}));
|
|
4480
|
-
const current = normalizePublisher(row.publisher);
|
|
4481
|
-
let target;
|
|
4482
|
-
if (seedPublisher) {
|
|
4483
|
-
if (current === seedPublisher)
|
|
4484
|
-
continue;
|
|
4485
|
-
target = seedPublisher;
|
|
4486
|
-
}
|
|
4487
|
-
else {
|
|
4488
|
-
// A seed with no wallet yet: its unsealed rows go with it when it's claimed.
|
|
4489
|
-
if (!current || !isPlaceholderUid(row.uid))
|
|
4490
|
-
continue;
|
|
4491
|
-
target = null;
|
|
4492
|
-
}
|
|
4493
|
-
const ids = byTarget.get(target) ?? [];
|
|
4494
|
-
ids.push(row.localId);
|
|
4495
|
-
byTarget.set(target, ids);
|
|
4496
|
-
}
|
|
4497
|
-
let changed = 0;
|
|
4498
|
-
for (const [target, ids] of byTarget) {
|
|
4499
|
-
await writeInBatches(ids, (chunk) => appDb.update(table).set({ publisher: target }).where(inArray(table.localId, chunk)));
|
|
4500
|
-
changed += ids.length;
|
|
4501
|
-
}
|
|
4502
|
-
return changed;
|
|
4503
|
-
};
|
|
4504
|
-
const versionRows = await align(versions);
|
|
4505
|
-
const propertyRows = await align(metadata$1);
|
|
4506
|
-
return { versionRows, propertyRows };
|
|
4507
|
-
}
|
|
4508
|
-
/** Runs the fix unless this database has had it, and records that it has. */
|
|
4509
|
-
async function runOnce$1() {
|
|
4510
|
-
const appDb = BaseDb.getAppDb();
|
|
4511
|
-
const marker = await appDb
|
|
4512
|
-
.select()
|
|
4513
|
-
.from(appState)
|
|
4514
|
-
.where(eq(appState.key, ROW_PUBLISHERS_ALIGNED_KEY))
|
|
4515
|
-
.limit(1);
|
|
4516
|
-
if (marker.length > 0)
|
|
4517
|
-
return;
|
|
4518
|
-
const result = await alignRowPublishers();
|
|
4519
|
-
const value = JSON.stringify({ ...result, at: Date.now() });
|
|
4520
|
-
await appDb
|
|
4521
|
-
.insert(appState)
|
|
4522
|
-
.values({ key: ROW_PUBLISHERS_ALIGNED_KEY, value })
|
|
4523
|
-
.onConflictDoUpdate({ target: appState.key, set: { value } });
|
|
4524
|
-
if (result.versionRows > 0 || result.propertyRows > 0) {
|
|
4525
|
-
logger$3(`gave ${result.versionRows} version and ${result.propertyRows} property rows their seed's publisher`);
|
|
4526
|
-
}
|
|
4527
|
-
}
|
|
4528
|
-
let running$2;
|
|
4529
|
-
let deferredUntilLeader$2 = false;
|
|
4530
|
-
const runInBackground$2 = () => {
|
|
4531
|
-
// Under the sync's lock: sync writes these rows too.
|
|
4532
|
-
running$2 ?? (running$2 = withDbTabLock('eas-sync', runOnce$1, { timeoutMs: Infinity })
|
|
4533
|
-
.catch((error) => {
|
|
4534
|
-
// Never fails init: the rows keep their old publisher.
|
|
4535
|
-
logger$3('row publisher fix failed', error);
|
|
4536
|
-
})
|
|
4537
|
-
.finally(() => {
|
|
4538
|
-
running$2 = undefined;
|
|
4539
|
-
}));
|
|
4540
|
-
return running$2;
|
|
4541
|
-
};
|
|
4542
|
-
/**
|
|
4543
|
-
* Starts {@link alignRowPublishers} in the background after client init, once per database, like
|
|
4544
|
-
* the foreign-attestation cleanup. Leader tab only (docs/MULTI_TAB.md). Never throws.
|
|
4545
|
-
*/
|
|
4546
|
-
function startAlignRowPublishers() {
|
|
4547
|
-
if (isLeaderTab()) {
|
|
4548
|
-
void runInBackground$2();
|
|
4549
|
-
return;
|
|
4550
|
-
}
|
|
4551
|
-
if (deferredUntilLeader$2)
|
|
4552
|
-
return;
|
|
4553
|
-
deferredUntilLeader$2 = true;
|
|
4554
|
-
void whenLeaderTab().then(() => {
|
|
4555
|
-
deferredUntilLeader$2 = false;
|
|
4556
|
-
void runInBackground$2();
|
|
4557
|
-
});
|
|
4558
|
-
}
|
|
4559
|
-
|
|
4560
|
-
const logger$2 = debug('seedSdk:db:clearStoredDisplayUrls');
|
|
4561
|
-
/** appState key recording that the fix below has run on this database. */
|
|
4562
|
-
const STORED_DISPLAY_URLS_CLEARED_KEY = 'storedDisplayUrlsCleared';
|
|
4563
|
-
/**
|
|
4564
|
-
* Nulls `ref_resolved_display_value` on File and Image rows that hold a session URL. SDK 0.7.5 and
|
|
4565
|
-
* 0.7.6 stored a File's content URL there: a `blob:` URL that is dead after a reload, or a
|
|
4566
|
-
* `file://` URL that breaks when filesDir moves. Readers now mint the URL from the file on disk and
|
|
4567
|
-
* ignore the column for these types; clearing it keeps older readers and direct DB queries from
|
|
4568
|
-
* picking the dead URL up. Returns the number of rows changed.
|
|
4569
|
-
*/
|
|
4570
|
-
async function clearStoredDisplayUrls() {
|
|
4571
|
-
const appDb = BaseDb.getAppDb();
|
|
4572
|
-
const where = and(inArray(metadata$1.refSeedType, ['file', 'image']), or(like(metadata$1.refResolvedDisplayValue, 'blob:%'), like(metadata$1.refResolvedDisplayValue, 'file:%')));
|
|
4573
|
-
const rows = (await appDb.select({ localId: metadata$1.localId }).from(metadata$1).where(where));
|
|
4574
|
-
if (rows.length === 0)
|
|
4575
|
-
return 0;
|
|
4576
|
-
await appDb.update(metadata$1).set({ refResolvedDisplayValue: null }).where(where);
|
|
4577
|
-
return rows.length;
|
|
4578
|
-
}
|
|
4579
|
-
/** Runs the fix unless this database has had it, and records that it has. */
|
|
4580
|
-
async function runOnce() {
|
|
4581
|
-
const appDb = BaseDb.getAppDb();
|
|
4582
|
-
const marker = await appDb
|
|
4583
|
-
.select()
|
|
4584
|
-
.from(appState)
|
|
4585
|
-
.where(eq(appState.key, STORED_DISPLAY_URLS_CLEARED_KEY))
|
|
4586
|
-
.limit(1);
|
|
4587
|
-
if (marker.length > 0)
|
|
4588
|
-
return;
|
|
4589
|
-
const rows = await clearStoredDisplayUrls();
|
|
4590
|
-
const value = JSON.stringify({ rows, at: Date.now() });
|
|
4591
|
-
await appDb
|
|
4592
|
-
.insert(appState)
|
|
4593
|
-
.values({ key: STORED_DISPLAY_URLS_CLEARED_KEY, value })
|
|
4594
|
-
.onConflictDoUpdate({ target: appState.key, set: { value } });
|
|
4595
|
-
if (rows > 0) {
|
|
4596
|
-
logger$2(`cleared stored display URLs on ${rows} File/Image rows`);
|
|
4597
|
-
}
|
|
4598
|
-
}
|
|
4599
|
-
let running$1;
|
|
4600
|
-
let deferredUntilLeader$1 = false;
|
|
4601
|
-
const runInBackground$1 = () => {
|
|
4602
|
-
running$1 ?? (running$1 = runOnce()
|
|
4603
|
-
.catch((error) => {
|
|
4604
|
-
// Never fails init: readers ignore the column for File and Image anyway.
|
|
4605
|
-
logger$2('clearing stored display URLs failed', error);
|
|
4606
|
-
})
|
|
4607
|
-
.finally(() => {
|
|
4608
|
-
running$1 = undefined;
|
|
4609
|
-
}));
|
|
4610
|
-
return running$1;
|
|
4611
|
-
};
|
|
4612
|
-
/**
|
|
4613
|
-
* Starts {@link clearStoredDisplayUrls} in the background after client init, once per database.
|
|
4614
|
-
* Leader tab only (docs/MULTI_TAB.md). Never throws.
|
|
4615
|
-
*/
|
|
4616
|
-
function startClearStoredDisplayUrls() {
|
|
4617
|
-
if (isLeaderTab()) {
|
|
4618
|
-
void runInBackground$1();
|
|
4619
|
-
return;
|
|
4620
|
-
}
|
|
4621
|
-
if (deferredUntilLeader$1)
|
|
4622
|
-
return;
|
|
4623
|
-
deferredUntilLeader$1 = true;
|
|
4624
|
-
void whenLeaderTab().then(() => {
|
|
4625
|
-
deferredUntilLeader$1 = false;
|
|
4626
|
-
void runInBackground$1();
|
|
4627
|
-
});
|
|
4628
|
-
}
|
|
4629
|
-
|
|
4630
3398
|
const logger$1 = debug('seedSdk:db:canonicalizeModelTypes');
|
|
4631
3399
|
/**
|
|
4632
3400
|
* Model types in the local DB (`seeds.type`, `versions.seed_type`, `metadata.model_type`) are the
|
|
@@ -4720,6 +3488,19 @@ const createVersion = async ({ seedLocalId, seedUid, seedType, uid, }, options =
|
|
|
4720
3488
|
return newVersionLocalId;
|
|
4721
3489
|
};
|
|
4722
3490
|
|
|
3491
|
+
/** Absolute path of the file {@link writeItemStorageFile} writes for `target`. */
|
|
3492
|
+
const getItemStorageFilePath = (target) => BaseFileManager.getFilesPath(getItemStorageSubdir(target.localStorageDir), target.fileName || getItemStorageLocalFileName(target.seedId, target.filenameSuffix));
|
|
3493
|
+
/**
|
|
3494
|
+
* Lock name for one ItemStorage file: `seed:item-storage:<absolute file path>`. The path starts
|
|
3495
|
+
* with the files root, which also names the database (`<filesDir>/db/seed.db`), so the name is
|
|
3496
|
+
* per database as well as per file.
|
|
3497
|
+
*/
|
|
3498
|
+
const itemStorageFileLockName = (filePath) => `seed:item-storage:${filePath}`;
|
|
3499
|
+
/** {@link withItemStorageFileLock} only if the lock is free now (see `tryWithTabLock`). */
|
|
3500
|
+
function tryWithItemStorageFileLock(filePath, fn) {
|
|
3501
|
+
return tryWithTabLock(itemStorageFileLockName(filePath), fn);
|
|
3502
|
+
}
|
|
3503
|
+
|
|
4723
3504
|
/**
|
|
4724
3505
|
* Conflicts between a local edit and a value sync wrote after it (ADR 0019). The local edit wins:
|
|
4725
3506
|
* a pending edit applies over the synced row as a new draft, and a draft already written stays the
|
|
@@ -5036,7 +3817,6 @@ async function applyItemStorageValue(seedLocalId, propertyName, op, db) {
|
|
|
5036
3817
|
localStorageDir,
|
|
5037
3818
|
// The draft is as new as its content (see updateItemPropertyValue).
|
|
5038
3819
|
createdAt: now,
|
|
5039
|
-
// Same shape as a row the migration or publish converted (convertVerbatimItemStorageRow).
|
|
5040
3820
|
...(clearsVerbatimValue && { propertyValue: null, refValueType: 'file' }),
|
|
5041
3821
|
})
|
|
5042
3822
|
.where(eq(metadata$1.localId, draft.localId));
|
|
@@ -5504,16 +4284,6 @@ const clientManagerMachine = setup({
|
|
|
5504
4284
|
assign({
|
|
5505
4285
|
isInitialized: true,
|
|
5506
4286
|
}),
|
|
5507
|
-
// One-time data migration that writes files, so it can't be a SQL migration in prepareDb.
|
|
5508
|
-
// In the background after init: the app is usable at once, the properties table holds the
|
|
5509
|
-
// current storage settings by now, and a failure never fails init.
|
|
5510
|
-
() => startLegacyItemStorageMigration(),
|
|
5511
|
-
// Also once, in the background: rows an older sync stored from other accounts' attestations.
|
|
5512
|
-
() => startForeignAttestationCleanup(),
|
|
5513
|
-
// Also once: version and property rows get their seed's publisher (rows from older edits had none).
|
|
5514
|
-
() => startAlignRowPublishers(),
|
|
5515
|
-
// Also once: File/Image rows lose the session URLs 0.7.5–0.7.6 stored (dead blob: URLs after reload).
|
|
5516
|
-
() => startClearStoredDisplayUrls(),
|
|
5517
4287
|
// Stored model types to the ADR 0008 form (html_page), so exact type filters find old rows.
|
|
5518
4288
|
() => startCanonicalizeModelTypes(),
|
|
5519
4289
|
// Registers the item appliers and resumes outbox ops left pending (a reload, a closed
|
|
@@ -5656,10 +4426,8 @@ function seedRowToAttestation(row) {
|
|
|
5656
4426
|
return null;
|
|
5657
4427
|
const fromRaw = attestationFromRaw(row.attestationRaw);
|
|
5658
4428
|
if (fromRaw) {
|
|
5659
|
-
|
|
5660
|
-
|
|
5661
|
-
row.type ??
|
|
5662
|
-
'unknown';
|
|
4429
|
+
// The EAS schema name ("post"), which `seeds.type` also holds.
|
|
4430
|
+
const schemaName = fromRaw.schema?.schemaNames?.[0]?.name ?? row.type ?? 'unknown';
|
|
5663
4431
|
return withLocalRevocation({
|
|
5664
4432
|
...fromRaw,
|
|
5665
4433
|
id: row.uid,
|
|
@@ -5672,7 +4440,7 @@ function seedRowToAttestation(row) {
|
|
|
5672
4440
|
schemaId: fromRaw.schemaId || row.schemaUid || '',
|
|
5673
4441
|
}, row.revokedAt);
|
|
5674
4442
|
}
|
|
5675
|
-
const schemaName = row.
|
|
4443
|
+
const schemaName = row.type ?? 'unknown';
|
|
5676
4444
|
return withLocalRevocation({
|
|
5677
4445
|
id: row.uid,
|
|
5678
4446
|
decodedDataJson: '',
|
|
@@ -5739,29 +4507,6 @@ function metadataRowToAttestation(row) {
|
|
|
5739
4507
|
attester: row.publisher ?? undefined,
|
|
5740
4508
|
}, row.revokedAt);
|
|
5741
4509
|
}
|
|
5742
|
-
async function resolveSchemaNameForSeedType(appDb, seedType,
|
|
5743
|
-
/** seeds.model_file_id: the seed's own model (model names are only unique per schema). */
|
|
5744
|
-
modelFileId) {
|
|
5745
|
-
if (!seedType)
|
|
5746
|
-
return null;
|
|
5747
|
-
const normalized = startCase(seedType);
|
|
5748
|
-
try {
|
|
5749
|
-
const schemaRows = await appDb
|
|
5750
|
-
.select({ schemaName: schemas.name })
|
|
5751
|
-
.from(models$1)
|
|
5752
|
-
.innerJoin(modelSchemas, eq(models$1.id, modelSchemas.modelId))
|
|
5753
|
-
.innerJoin(schemas, eq(modelSchemas.schemaId, schemas.id))
|
|
5754
|
-
.where(modelFileId ? eq(models$1.schemaFileId, modelFileId) : eq(models$1.name, normalized))
|
|
5755
|
-
.orderBy(desc(models$1.id))
|
|
5756
|
-
.limit(1);
|
|
5757
|
-
if (schemaRows[0]?.schemaName)
|
|
5758
|
-
return schemaRows[0].schemaName;
|
|
5759
|
-
}
|
|
5760
|
-
catch {
|
|
5761
|
-
// ignore
|
|
5762
|
-
}
|
|
5763
|
-
return seedType;
|
|
5764
|
-
}
|
|
5765
4510
|
function monthBoundsUnix(year, month) {
|
|
5766
4511
|
const startDate = new Date(year, month - 1, 1);
|
|
5767
4512
|
const endDate = new Date(year, month, 0, 23, 59, 59);
|
|
@@ -5783,7 +4528,6 @@ async function listPublishedSeedRows(schemaName, opts) {
|
|
|
5783
4528
|
uid: seeds.uid,
|
|
5784
4529
|
schemaUid: seeds.schemaUid,
|
|
5785
4530
|
type: seeds.type,
|
|
5786
|
-
modelFileId: seeds.modelFileId,
|
|
5787
4531
|
publisher: seeds.publisher,
|
|
5788
4532
|
attestationRaw: seeds.attestationRaw,
|
|
5789
4533
|
attestationCreatedAt: seeds.attestationCreatedAt,
|
|
@@ -5812,11 +4556,7 @@ async function listPublishedSeedRows(schemaName, opts) {
|
|
|
5812
4556
|
const hasPublished = versionRows.some((v) => v.uid && isValidEasAttestationUid(v.uid) && !isRevokedLocally(v.revokedAt));
|
|
5813
4557
|
if (!hasPublished)
|
|
5814
4558
|
continue;
|
|
5815
|
-
const
|
|
5816
|
-
const att = seedRowToAttestation({
|
|
5817
|
-
...row,
|
|
5818
|
-
schemaName: schemaResolved === schemaName ? schemaName : (schemaResolved ?? schemaName),
|
|
5819
|
-
});
|
|
4559
|
+
const att = seedRowToAttestation(row);
|
|
5820
4560
|
if (!att)
|
|
5821
4561
|
continue;
|
|
5822
4562
|
// Force requested schema name so assembleSeeds filters correctly
|
|
@@ -5851,7 +4591,6 @@ function createLocalQueryDataSource() {
|
|
|
5851
4591
|
uid: seeds.uid,
|
|
5852
4592
|
schemaUid: seeds.schemaUid,
|
|
5853
4593
|
type: seeds.type,
|
|
5854
|
-
modelFileId: seeds.modelFileId,
|
|
5855
4594
|
publisher: seeds.publisher,
|
|
5856
4595
|
attestationRaw: seeds.attestationRaw,
|
|
5857
4596
|
attestationCreatedAt: seeds.attestationCreatedAt,
|
|
@@ -5865,8 +4604,7 @@ function createLocalQueryDataSource() {
|
|
|
5865
4604
|
return null;
|
|
5866
4605
|
if (isRevokedLocally(row.revokedAt))
|
|
5867
4606
|
return null;
|
|
5868
|
-
|
|
5869
|
-
return seedRowToAttestation({ ...row, schemaName });
|
|
4607
|
+
return seedRowToAttestation(row);
|
|
5870
4608
|
},
|
|
5871
4609
|
async listSeedsBySchemaName(schemaName, opts) {
|
|
5872
4610
|
const all = await listPublishedSeedRows(schemaName);
|
|
@@ -5950,7 +4688,6 @@ function createLocalQueryDataSource() {
|
|
|
5950
4688
|
uid: seeds.uid,
|
|
5951
4689
|
schemaUid: seeds.schemaUid,
|
|
5952
4690
|
type: seeds.type,
|
|
5953
|
-
modelFileId: seeds.modelFileId,
|
|
5954
4691
|
publisher: seeds.publisher,
|
|
5955
4692
|
attestationRaw: seeds.attestationRaw,
|
|
5956
4693
|
attestationCreatedAt: seeds.attestationCreatedAt,
|
|
@@ -5962,8 +4699,7 @@ function createLocalQueryDataSource() {
|
|
|
5962
4699
|
for (const row of rows) {
|
|
5963
4700
|
if (isRevokedLocally(row.revokedAt))
|
|
5964
4701
|
continue;
|
|
5965
|
-
const
|
|
5966
|
-
const att = seedRowToAttestation({ ...row, schemaName });
|
|
4702
|
+
const att = seedRowToAttestation(row);
|
|
5967
4703
|
if (att)
|
|
5968
4704
|
out.push(att);
|
|
5969
4705
|
}
|
|
@@ -6539,5 +5275,5 @@ var ClientManager$1 = /*#__PURE__*/Object.freeze({
|
|
|
6539
5275
|
getClient: getClient
|
|
6540
5276
|
});
|
|
6541
5277
|
|
|
6542
|
-
export {
|
|
6543
|
-
//# sourceMappingURL=ClientManager-
|
|
5278
|
+
export { listCompleteSchemaFiles as A, loadAllSchemasFromDb as B, ClientManager as C, mergeEasSyncRequestIntents as D, EAS_CHAIN_ID_APP_STATE_KEY as E, registerSeedQueryLocalSource as F, requestEasSyncFromAddressChange as G, requestEasSyncFromModelsInit as H, INIT_CONFIG_CONFLICT_MESSAGE as I, sendEasSyncClientRequest as J, setRetriesWhenOnlineEnabled as K, startEasSyncActor as L, unregisterSeedQueryLocalSource as M, getLatestSchemaVersion as N, createRowsWrittenSignal as O, createModelsFromJson as P, jsonPropertiesToSchemaProperties as Q, RelationTargetError as R, schema as S, SEEDPROTOCOL_Seed_Protocol_v1 as T, conflicts as U, itemAppliers as V, ClientManager$1 as W, 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, assertLocalDbChain as o, claimUnpublishedDrafts as p, createLocalQueryDataSource as q, readJsonImportFile as r, startItemOutbox as s, throwItemWriteError as t, easSyncActor as u, getClient as v, waitForEasReadChain as w, getPublishedSeedRecord as x, getSchemaNameFromId as y, isSeedQueryLocalSourceRegistered as z };
|
|
5279
|
+
//# sourceMappingURL=ClientManager-GZfXErDX.js.map
|