@seedprotocol/sdk 0.7.9-next.1189.g5e63267 → 0.7.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/BaseFileManager-BAlySv8w.js +650 -0
- package/dist/BaseFileManager-BAlySv8w.js.map +1 -0
- package/dist/{Item-CG5IhPtL.js → Item-Bf4kWKpH.js} +5576 -6649
- package/dist/Item-Bf4kWKpH.js.map +1 -0
- package/dist/{ModelProperty-DDD47KVm.js → ModelProperty-BlaEgb_U.js} +345 -709
- package/dist/ModelProperty-BlaEgb_U.js.map +1 -0
- package/dist/Schema-J_1f6p0c.js +1456 -0
- package/dist/Schema-J_1f6p0c.js.map +1 -0
- package/dist/{SchemaValidationService-CZzKNL04.js → SchemaValidationService-CnmKyzR-.js} +6 -9
- package/dist/{SchemaValidationService-CZzKNL04.js.map → SchemaValidationService-CnmKyzR-.js.map} +1 -1
- package/dist/{configurePlatform-Dukm2QwO.js → configurePlatform-CiOJ1R3q.js} +3 -12
- package/dist/configurePlatform-CiOJ1R3q.js.map +1 -0
- package/dist/db/drizzle/0026_add_content_hash_to_schemas.sql +1 -0
- package/dist/db/drizzle/0027_link_metadata_property_ids.sql +74 -0
- package/dist/db/drizzle/0028_add_definition_to_properties.sql +17 -0
- package/dist/db/drizzle/0029_dedupe_chain_uids_add_unique_indexes.sql +120 -0
- package/dist/db/drizzle/meta/0026_snapshot.json +1659 -0
- package/dist/db/drizzle/meta/0027_snapshot.json +1659 -0
- package/dist/db/drizzle/meta/0028_snapshot.json +1666 -0
- package/dist/db/drizzle/meta/0029_snapshot.json +1691 -0
- package/dist/db/drizzle/meta/_journal.json +29 -1
- package/dist/{detachRowsBeforeDelete-Di1enVUF.js → detachRowsBeforeDelete-sEaUwlOU.js} +2 -13
- package/dist/{detachRowsBeforeDelete-Di1enVUF.js.map → detachRowsBeforeDelete-sEaUwlOU.js.map} +1 -1
- package/dist/dist/{index-rOTW-2QZ.d.ts → BaseFileManager-BAlySv8w.d.ts} +1407 -2700
- package/dist/dist/BaseFileManager-BAlySv8w.d.ts.map +1 -0
- package/dist/dist/{configurePlatform-Dukm2QwO.d.ts → configurePlatform-CiOJ1R3q.d.ts} +1 -1
- package/dist/dist/configurePlatform-CiOJ1R3q.d.ts.map +1 -0
- package/dist/dist/{index-DxHpPNfn.d.ts → index-D0V-mjCV.d.ts} +39 -1
- package/dist/dist/{index-DxHpPNfn.d.ts.map → index-D0V-mjCV.d.ts.map} +1 -1
- package/dist/dist/{index.node-WsEJCOwC.d.ts → index.node-CYPemH-t.d.ts} +157 -5
- package/dist/dist/{index.node-WsEJCOwC.d.ts.map → index.node-CYPemH-t.d.ts.map} +1 -1
- package/dist/dist/platform.node.d.ts +2 -2
- package/dist/eas-wB_fQ8Tc.js +32 -0
- package/dist/eas-wB_fQ8Tc.js.map +1 -0
- package/dist/errors-DLSoqSHG.js +6550 -0
- package/dist/errors-DLSoqSHG.js.map +1 -0
- package/dist/getPublishPayload-BnIwpwz1.js +760 -0
- package/dist/getPublishPayload-BnIwpwz1.js.map +1 -0
- package/dist/getPublishPendingDiff-D6_-A5ns.js +125 -0
- package/dist/getPublishPendingDiff-D6_-A5ns.js.map +1 -0
- package/dist/getPublishUploads-sS6JfPgz.js +783 -0
- package/dist/getPublishUploads-sS6JfPgz.js.map +1 -0
- package/dist/{index-DQoyhp2c.js → index-BVBmz_cc.js} +11 -14
- package/dist/index-BVBmz_cc.js.map +1 -0
- package/dist/index-CYGWPoOx.js +27 -0
- package/dist/index-CYGWPoOx.js.map +1 -0
- package/dist/{index-DxHpPNfn.js → index-D0V-mjCV.js} +2 -2
- package/dist/index-D0V-mjCV.js.map +1 -0
- package/dist/index-DmTtj1nk.js +817 -0
- package/dist/index-DmTtj1nk.js.map +1 -0
- package/dist/{index.browser-QPWBkLJA.js → index.browser-CUmBVYen.js} +397 -356
- package/dist/index.browser-CUmBVYen.js.map +1 -0
- package/dist/{index.node-WsEJCOwC.js → index.node-CYPemH-t.js} +10 -10
- package/dist/index.node-CYPemH-t.js.map +1 -0
- package/dist/main.js +23 -1075
- package/dist/main.js.map +1 -1
- package/dist/modelPropertyRecordSchemas-C7UgA5TH.js +48 -0
- package/dist/modelPropertyRecordSchemas-C7UgA5TH.js.map +1 -0
- package/dist/node.js +14 -18
- package/dist/node.js.map +1 -1
- package/dist/platform.browser.js +8 -13
- package/dist/platform.browser.js.map +1 -1
- package/dist/platform.node.js +6 -16
- package/dist/platform.node.js.map +1 -1
- package/dist/property-BxUYznH0.js +87 -0
- package/dist/property-BxUYznH0.js.map +1 -0
- package/dist/publishGraph-EcB40Uii.js +311 -0
- package/dist/publishGraph-EcB40Uii.js.map +1 -0
- package/dist/readHtmlBodyForStorageSeed-D6KPtWoR.js +110 -0
- package/dist/readHtmlBodyForStorageSeed-D6KPtWoR.js.map +1 -0
- package/dist/seedSchema/ModelSchema.ts +4 -0
- package/dist/seedSchema/ModelSchemaSchema.ts +5 -2
- package/dist/seedSchema/PendingWriteSchema.ts +4 -1
- package/dist/seedSchema/SchemaSchema.ts +3 -0
- package/dist/seedSchema/SeedSchema.ts +8 -2
- package/dist/seedSchema/VersionSchema.ts +7 -2
- package/dist/seedSchema/attestedUid.ts +10 -0
- package/dist/src/Item/Item.d.ts +32 -30
- package/dist/src/Item/Item.d.ts.map +1 -1
- package/dist/src/Item/loadItem.d.ts +12 -0
- package/dist/src/Item/loadItem.d.ts.map +1 -0
- package/dist/src/Item/service/itemMachineSingle.d.ts +2 -13
- package/dist/src/Item/service/itemMachineSingle.d.ts.map +1 -1
- package/dist/src/ItemProperty/ItemProperty.d.ts +77 -46
- package/dist/src/ItemProperty/ItemProperty.d.ts.map +1 -1
- package/dist/src/ItemProperty/loadProperty.d.ts +11 -0
- package/dist/src/ItemProperty/loadProperty.d.ts.map +1 -0
- package/dist/src/ItemProperty/propertyWrite.d.ts +54 -0
- package/dist/src/ItemProperty/propertyWrite.d.ts.map +1 -0
- package/dist/src/ItemProperty/{service/actors/saveValueToDb/rowContext.d.ts → rowContext.d.ts} +1 -1
- package/dist/src/ItemProperty/rowContext.d.ts.map +1 -0
- package/dist/src/ItemProperty/service/actors/hydrateFromDb.d.ts +6 -0
- package/dist/src/ItemProperty/service/actors/hydrateFromDb.d.ts.map +1 -1
- package/dist/src/ItemProperty/service/actors/modelPropertyRecordSchemas.d.ts +5 -15
- package/dist/src/ItemProperty/service/actors/modelPropertyRecordSchemas.d.ts.map +1 -1
- package/dist/src/ItemProperty/service/propertyMachine.d.ts +4 -50
- package/dist/src/ItemProperty/service/propertyMachine.d.ts.map +1 -1
- package/dist/src/Model/Model.d.ts +26 -56
- package/dist/src/Model/Model.d.ts.map +1 -1
- package/dist/src/Model/createModelProperties.d.ts +10 -0
- package/dist/src/Model/createModelProperties.d.ts.map +1 -0
- package/dist/src/Model/loadModel.d.ts +13 -0
- package/dist/src/Model/loadModel.d.ts.map +1 -0
- package/dist/src/Model/service/actors/validateModel.d.ts.map +1 -1
- package/dist/src/Model/service/modelMachine.d.ts +5 -114
- package/dist/src/Model/service/modelMachine.d.ts.map +1 -1
- package/dist/src/ModelProperty/ModelProperty.d.ts +44 -37
- package/dist/src/ModelProperty/ModelProperty.d.ts.map +1 -1
- package/dist/src/ModelProperty/service/actors/compareAndMarkDraft.d.ts.map +1 -1
- package/dist/src/ModelProperty/service/actors/validateProperty.d.ts.map +1 -1
- package/dist/src/ModelProperty/service/modelPropertyMachine.d.ts +6 -77
- package/dist/src/ModelProperty/service/modelPropertyMachine.d.ts.map +1 -1
- package/dist/src/Schema/Schema.d.ts +36 -37
- package/dist/src/Schema/Schema.d.ts.map +1 -1
- package/dist/src/Schema/loadOrCreateSchema.d.ts +21 -0
- package/dist/src/Schema/loadOrCreateSchema.d.ts.map +1 -0
- package/dist/src/Schema/service/schemaMachine.d.ts +7 -125
- package/dist/src/Schema/service/schemaMachine.d.ts.map +1 -1
- package/dist/src/browser/db/Db.d.ts.map +1 -1
- package/dist/src/browser/db/changeFeed.d.ts +2 -18
- package/dist/src/browser/db/changeFeed.d.ts.map +1 -1
- package/dist/src/browser/db/drizzleFiles.d.ts +6 -2
- package/dist/src/browser/db/drizzleFiles.d.ts.map +1 -1
- package/dist/src/browser/workers/filesDownload.d.ts.map +1 -1
- package/dist/src/browser/workers/imageResize.d.ts.map +1 -1
- package/dist/src/client/ClientManager.d.ts +90 -57
- package/dist/src/client/ClientManager.d.ts.map +1 -1
- package/dist/src/client/actors/addModelsToDb.d.ts +9 -7
- package/dist/src/client/actors/addModelsToDb.d.ts.map +1 -1
- package/dist/src/client/actors/dbInit.d.ts +3 -3
- package/dist/src/client/actors/dbInit.d.ts.map +1 -1
- package/dist/src/client/actors/fileSystemInit.d.ts +3 -3
- package/dist/src/client/actors/fileSystemInit.d.ts.map +1 -1
- package/dist/src/client/actors/platformClassesInit.d.ts +10 -5
- package/dist/src/client/actors/platformClassesInit.d.ts.map +1 -1
- package/dist/src/client/actors/processSchemaFiles.d.ts +18 -3
- package/dist/src/client/actors/processSchemaFiles.d.ts.map +1 -1
- package/dist/src/client/actors/saveConfig.d.ts +6 -3
- package/dist/src/client/actors/saveConfig.d.ts.map +1 -1
- package/dist/src/client/clientManagerMachine.d.ts +22 -20
- package/dist/src/client/clientManagerMachine.d.ts.map +1 -1
- package/dist/src/client/constants.d.ts +1 -9
- package/dist/src/client/constants.d.ts.map +1 -1
- package/dist/src/client/readiness.d.ts +26 -0
- package/dist/src/client/readiness.d.ts.map +1 -0
- package/dist/src/db/read/currentPropertyRow.d.ts +61 -0
- package/dist/src/db/read/currentPropertyRow.d.ts.map +1 -0
- package/dist/src/db/read/findSeedRow.d.ts +20 -0
- package/dist/src/db/read/findSeedRow.d.ts.map +1 -0
- package/dist/src/db/read/findSeedRowsByUid.d.ts +4 -1
- package/dist/src/db/read/findSeedRowsByUid.d.ts.map +1 -1
- package/dist/src/db/read/getAttesterForSeed.d.ts +1 -1
- package/dist/src/db/read/getAttesterForSeed.d.ts.map +1 -1
- package/dist/src/db/read/getItemData.d.ts.map +1 -1
- package/dist/src/db/read/getItemProperties.d.ts +5 -0
- package/dist/src/db/read/getItemProperties.d.ts.map +1 -1
- package/dist/src/db/read/getMetadataAttestationUidsForSeedUid.d.ts.map +1 -1
- package/dist/src/db/read/getModelSchemas.d.ts +0 -7
- package/dist/src/db/read/getModelSchemas.d.ts.map +1 -1
- package/dist/src/db/read/getModelsData.d.ts.map +1 -1
- package/dist/src/db/read/getPropertyClear.d.ts +5 -1
- package/dist/src/db/read/getPropertyClear.d.ts.map +1 -1
- package/dist/src/db/read/getPublishPayload.d.ts +35 -40
- package/dist/src/db/read/getPublishPayload.d.ts.map +1 -1
- package/dist/src/db/read/getPublishPendingDiff.d.ts +2 -2
- package/dist/src/db/read/getPublishPendingDiff.d.ts.map +1 -1
- package/dist/src/db/read/getPublishUploads.d.ts +59 -28
- package/dist/src/db/read/getPublishUploads.d.ts.map +1 -1
- package/dist/src/db/read/getSchemaUidForModel.d.ts.map +1 -1
- package/dist/src/db/read/getSeedPublishState.d.ts.map +1 -1
- package/dist/src/db/read/getSeedPublisher.d.ts.map +1 -1
- package/dist/src/db/read/getVersionsForSeedUid.d.ts.map +1 -1
- package/dist/src/db/read/isSeedRevoked.d.ts.map +1 -1
- package/dist/src/db/read/localModelSchemaLookups.d.ts +8 -0
- package/dist/src/db/read/localModelSchemaLookups.d.ts.map +1 -0
- package/dist/src/db/read/metadataProperty.d.ts +104 -0
- package/dist/src/db/read/metadataProperty.d.ts.map +1 -0
- package/dist/src/db/read/publishGraph.d.ts +148 -0
- package/dist/src/db/read/publishGraph.d.ts.map +1 -0
- package/dist/src/db/read/resolveModelRecord.d.ts +26 -2
- package/dist/src/db/read/resolveModelRecord.d.ts.map +1 -1
- package/dist/src/db/read/resolveRelatedSeedRef.d.ts +1 -7
- package/dist/src/db/read/resolveRelatedSeedRef.d.ts.map +1 -1
- package/dist/src/db/read/subqueries/metadataLatest.d.ts +3 -1
- package/dist/src/db/read/subqueries/metadataLatest.d.ts.map +1 -1
- package/dist/src/db/read/summarizePublishWork.d.ts +13 -5
- package/dist/src/db/read/summarizePublishWork.d.ts.map +1 -1
- package/dist/src/db/write/applyPropertyAttestationUidsFromPublish.d.ts +20 -21
- package/dist/src/db/write/applyPropertyAttestationUidsFromPublish.d.ts.map +1 -1
- package/dist/src/db/write/createMetadata.d.ts.map +1 -1
- package/dist/src/db/write/createNewItem.d.ts.map +1 -1
- package/dist/src/db/write/createSeeds.d.ts +5 -1
- package/dist/src/db/write/createSeeds.d.ts.map +1 -1
- package/dist/src/db/write/definitions.d.ts +127 -0
- package/dist/src/db/write/definitions.d.ts.map +1 -0
- package/dist/src/db/write/mergeChainRows.d.ts +22 -0
- package/dist/src/db/write/mergeChainRows.d.ts.map +1 -0
- package/dist/src/db/write/saveDefinition.d.ts +29 -0
- package/dist/src/db/write/saveDefinition.d.ts.map +1 -0
- package/dist/src/db/write/updateSeedUid.d.ts +4 -2
- package/dist/src/db/write/updateSeedUid.d.ts.map +1 -1
- package/dist/src/db/write/updateVersionUid.d.ts +12 -4
- package/dist/src/db/write/updateVersionUid.d.ts.map +1 -1
- package/dist/src/db/write/writeModelUids.d.ts +10 -0
- package/dist/src/db/write/writeModelUids.d.ts.map +1 -0
- package/dist/src/eas.d.ts +8 -6
- package/dist/src/eas.d.ts.map +1 -1
- package/dist/src/events/files/download.d.ts.map +1 -1
- package/dist/src/events/item/syncDbWithEas.d.ts.map +1 -1
- package/dist/src/helpers/arweaveContentTags.d.ts +1 -1
- package/dist/src/helpers/arweaveContentTags.d.ts.map +1 -1
- package/dist/src/helpers/compareMetadataRowsLatestFirst.d.ts +18 -3
- package/dist/src/helpers/compareMetadataRowsLatestFirst.d.ts.map +1 -1
- package/dist/src/helpers/constants.d.ts +5 -2
- package/dist/src/helpers/constants.d.ts.map +1 -1
- package/dist/src/helpers/dataUrl.d.ts +10 -0
- package/dist/src/helpers/dataUrl.d.ts.map +1 -0
- package/dist/src/helpers/db.d.ts +54 -105
- package/dist/src/helpers/db.d.ts.map +1 -1
- package/dist/src/helpers/ensureImageLocal.d.ts.map +1 -1
- package/dist/src/helpers/entity/contextUpdate.d.ts +20 -0
- package/dist/src/helpers/entity/contextUpdate.d.ts.map +1 -0
- package/dist/src/helpers/entity/draftSaveErrors.d.ts +5 -0
- package/dist/src/helpers/entity/draftSaveErrors.d.ts.map +1 -1
- package/dist/src/helpers/entity/entityCache.d.ts +65 -3
- package/dist/src/helpers/entity/entityCache.d.ts.map +1 -1
- package/dist/src/helpers/entity/entityCommon.d.ts +0 -22
- package/dist/src/helpers/entity/entityCommon.d.ts.map +1 -1
- package/dist/src/helpers/entity/entityLifecycle.d.ts +75 -0
- package/dist/src/helpers/entity/entityLifecycle.d.ts.map +1 -0
- package/dist/src/helpers/entity/entityLiveQuery.d.ts +1 -23
- package/dist/src/helpers/entity/entityLiveQuery.d.ts.map +1 -1
- package/dist/src/helpers/htmlEmbeddedDataUriPublish.d.ts +4 -9
- package/dist/src/helpers/htmlEmbeddedDataUriPublish.d.ts.map +1 -1
- package/dist/src/helpers/index.d.ts +2 -24
- package/dist/src/helpers/index.d.ts.map +1 -1
- package/dist/src/helpers/localImageBlobUrl.d.ts +7 -0
- package/dist/src/helpers/localImageBlobUrl.d.ts.map +1 -0
- package/dist/src/helpers/mediaRef.d.ts +3 -70
- package/dist/src/helpers/mediaRef.d.ts.map +1 -1
- package/dist/src/helpers/metadataPropertyNames.d.ts +34 -26
- package/dist/src/helpers/metadataPropertyNames.d.ts.map +1 -1
- package/dist/src/helpers/mimeTypes.d.ts +2 -1
- package/dist/src/helpers/mimeTypes.d.ts.map +1 -1
- package/dist/src/helpers/model.d.ts.map +1 -1
- package/dist/src/helpers/ownership.d.ts.map +1 -1
- package/dist/src/helpers/property.d.ts +21 -26
- package/dist/src/helpers/property.d.ts.map +1 -1
- package/dist/src/helpers/propertyDefinition.d.ts +59 -0
- package/dist/src/helpers/propertyDefinition.d.ts.map +1 -0
- package/dist/src/helpers/readHtmlBodyForStorageSeed.d.ts.map +1 -1
- package/dist/src/helpers/relationSeedRef.d.ts +0 -7
- package/dist/src/helpers/relationSeedRef.d.ts.map +1 -1
- package/dist/src/helpers/schema.d.ts +24 -38
- package/dist/src/helpers/schema.d.ts.map +1 -1
- package/dist/src/helpers/schemaApply.d.ts +135 -0
- package/dist/src/helpers/schemaApply.d.ts.map +1 -0
- package/dist/src/helpers/tabEvents.d.ts.map +1 -1
- package/dist/src/helpers/updateSchema.d.ts +2 -18
- package/dist/src/helpers/updateSchema.d.ts.map +1 -1
- package/dist/src/imports/index.d.ts +1 -1
- package/dist/src/imports/index.d.ts.map +1 -1
- package/dist/src/imports/json.d.ts +8 -78
- package/dist/src/imports/json.d.ts.map +1 -1
- package/dist/src/index.d.ts +13 -13
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/interfaces/IItem.d.ts +5 -0
- package/dist/src/interfaces/IItem.d.ts.map +1 -1
- package/dist/src/interfaces/IItemProperty.d.ts +9 -7
- package/dist/src/interfaces/IItemProperty.d.ts.map +1 -1
- package/dist/src/node/db/Db.d.ts.map +1 -1
- package/dist/src/node/index.d.ts +2 -1
- package/dist/src/node/index.d.ts.map +1 -1
- package/dist/src/outbox/conflicts.d.ts +2 -0
- package/dist/src/outbox/conflicts.d.ts.map +1 -1
- package/dist/src/outbox/itemAppliers.d.ts +63 -14
- package/dist/src/outbox/itemAppliers.d.ts.map +1 -1
- package/dist/src/outbox/outbox.d.ts +14 -3
- package/dist/src/outbox/outbox.d.ts.map +1 -1
- package/dist/src/outbox/pendingValues.d.ts +3 -1
- package/dist/src/outbox/pendingValues.d.ts.map +1 -1
- package/dist/src/outbox/storageValueRow.d.ts +7 -0
- package/dist/src/outbox/storageValueRow.d.ts.map +1 -0
- 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/seedSchema/ModelSchema.d.ts +19 -0
- package/dist/src/seedSchema/ModelSchema.d.ts.map +1 -1
- package/dist/src/seedSchema/ModelSchemaSchema.d.ts.map +1 -1
- package/dist/src/seedSchema/PendingWriteSchema.d.ts.map +1 -1
- package/dist/src/seedSchema/SchemaSchema.d.ts +19 -0
- package/dist/src/seedSchema/SchemaSchema.d.ts.map +1 -1
- package/dist/src/seedSchema/SeedSchema.d.ts.map +1 -1
- package/dist/src/seedSchema/VersionSchema.d.ts.map +1 -1
- package/dist/src/seedSchema/attestedUid.d.ts +9 -0
- package/dist/src/seedSchema/attestedUid.d.ts.map +1 -0
- package/dist/src/storageValue/content.d.ts +45 -0
- package/dist/src/storageValue/content.d.ts.map +1 -0
- package/dist/src/storageValue/findFile.d.ts +7 -0
- package/dist/src/storageValue/findFile.d.ts.map +1 -0
- package/dist/src/storageValue/resolve.d.ts +71 -0
- package/dist/src/storageValue/resolve.d.ts.map +1 -0
- package/dist/src/storageValue/save.d.ts +24 -0
- package/dist/src/storageValue/save.d.ts.map +1 -0
- package/dist/src/storageValue/stage.d.ts +22 -0
- package/dist/src/storageValue/stage.d.ts.map +1 -0
- package/dist/src/types/db.d.ts +0 -14
- package/dist/src/types/db.d.ts.map +1 -1
- package/dist/src/types/index.d.ts +3 -3
- package/dist/src/types/index.d.ts.map +1 -1
- package/dist/src/types/machines.d.ts +1 -1
- package/dist/src/types/machines.d.ts.map +1 -1
- package/dist/src/types/property.d.ts +9 -24
- package/dist/src/types/property.d.ts.map +1 -1
- package/dist/src/types/publish.d.ts +1 -1
- package/dist/src/types/publish.d.ts.map +1 -1
- package/dist/{syncDbWithEas-BMHoou6X.js → syncDbWithEas-CA7PvBgu.js} +112 -162
- package/dist/syncDbWithEas-CA7PvBgu.js.map +1 -0
- package/dist/tabEvents-CaVmngqr.js +3804 -0
- package/dist/tabEvents-CaVmngqr.js.map +1 -0
- package/dist/{tolerantWebAccess-BHndShch.js → tolerantWebAccess-BJqViq08.js} +10 -15
- package/dist/{tolerantWebAccess-BHndShch.js.map → tolerantWebAccess-BJqViq08.js.map} +1 -1
- package/dist/{resolveModelForSyncedSeed-fIURvYRV.js → updateSeedRevokedAt-BL9Bg-G7.js} +30 -4
- package/dist/updateSeedRevokedAt-BL9Bg-G7.js.map +1 -0
- package/package.json +6 -6
- package/dist/ClientManager-DqL0q_eu.js +0 -5292
- package/dist/ClientManager-DqL0q_eu.js.map +0 -1
- package/dist/Item-CG5IhPtL.js.map +0 -1
- package/dist/ModelProperty-DDD47KVm.js.map +0 -1
- package/dist/Schema-BS8oR7QV.js +0 -4370
- package/dist/Schema-BS8oR7QV.js.map +0 -1
- package/dist/backfillMetadataPropertyIds-C7P7FL6F.js +0 -72
- package/dist/backfillMetadataPropertyIds-C7P7FL6F.js.map +0 -1
- package/dist/changeFeed-M8sGbOrW.js +0 -726
- package/dist/changeFeed-M8sGbOrW.js.map +0 -1
- package/dist/configurePlatform-Dukm2QwO.js.map +0 -1
- package/dist/dist/ClientManager-DqL0q_eu.d.ts +0 -952
- package/dist/dist/ClientManager-DqL0q_eu.d.ts.map +0 -1
- package/dist/dist/Item-CG5IhPtL.d.ts +0 -1115
- package/dist/dist/Item-CG5IhPtL.d.ts.map +0 -1
- package/dist/dist/ModelProperty-DDD47KVm.d.ts +0 -315
- package/dist/dist/ModelProperty-DDD47KVm.d.ts.map +0 -1
- package/dist/dist/Schema-BS8oR7QV.d.ts +0 -432
- package/dist/dist/Schema-BS8oR7QV.d.ts.map +0 -1
- package/dist/dist/SchemaValidationService-CZzKNL04.d.ts +0 -118
- package/dist/dist/SchemaValidationService-CZzKNL04.d.ts.map +0 -1
- package/dist/dist/backfillMetadataPropertyIds-C7P7FL6F.d.ts +0 -7
- package/dist/dist/backfillMetadataPropertyIds-C7P7FL6F.d.ts.map +0 -1
- package/dist/dist/changeFeed-M8sGbOrW.d.ts +0 -160
- package/dist/dist/changeFeed-M8sGbOrW.d.ts.map +0 -1
- package/dist/dist/configurePlatform-Dukm2QwO.d.ts.map +0 -1
- package/dist/dist/detachRowsBeforeDelete-Di1enVUF.d.ts +0 -13
- package/dist/dist/detachRowsBeforeDelete-Di1enVUF.d.ts.map +0 -1
- package/dist/dist/eas-B5VJolSj.d.ts +0 -12
- package/dist/dist/eas-B5VJolSj.d.ts.map +0 -1
- package/dist/dist/errors-C1qUEZ7A.d.ts +0 -25
- package/dist/dist/errors-C1qUEZ7A.d.ts.map +0 -1
- package/dist/dist/errors-CS3nDpUU.d.ts +0 -515
- package/dist/dist/errors-CS3nDpUU.d.ts.map +0 -1
- package/dist/dist/eventBus-7vxTCc3a.d.ts +0 -18
- package/dist/dist/eventBus-7vxTCc3a.d.ts.map +0 -1
- package/dist/dist/findSeedRowsByUid-CuQmK7An.d.ts +0 -13
- package/dist/dist/findSeedRowsByUid-CuQmK7An.d.ts.map +0 -1
- package/dist/dist/getItem-Uha3_H0t.d.ts +0 -6
- package/dist/dist/getItem-Uha3_H0t.d.ts.map +0 -1
- package/dist/dist/getPublishPayload-pbin4lk8.d.ts +0 -65
- package/dist/dist/getPublishPayload-pbin4lk8.d.ts.map +0 -1
- package/dist/dist/getPublishPendingDiff-ByIaPvCn.d.ts +0 -18
- package/dist/dist/getPublishPendingDiff-ByIaPvCn.d.ts.map +0 -1
- package/dist/dist/getPublishUploads-BBqiowVc.d.ts +0 -89
- package/dist/dist/getPublishUploads-BBqiowVc.d.ts.map +0 -1
- package/dist/dist/index-DQoyhp2c.d.ts +0 -6
- package/dist/dist/index-DQoyhp2c.d.ts.map +0 -1
- package/dist/dist/index-njjjo74v.d.ts +0 -14
- package/dist/dist/index-njjjo74v.d.ts.map +0 -1
- package/dist/dist/index-rOTW-2QZ.d.ts.map +0 -1
- package/dist/dist/index.browser-QPWBkLJA.d.ts +0 -9959
- package/dist/dist/index.browser-QPWBkLJA.d.ts.map +0 -1
- package/dist/dist/mimeTypes-C9r76DCH.d.ts +0 -30
- package/dist/dist/mimeTypes-C9r76DCH.d.ts.map +0 -1
- package/dist/dist/model-oHA3YhOd.d.ts +0 -6
- package/dist/dist/model-oHA3YhOd.d.ts.map +0 -1
- package/dist/dist/modelPropertyRecordSchemas-onFOG2x6.d.ts +0 -7
- package/dist/dist/modelPropertyRecordSchemas-onFOG2x6.d.ts.map +0 -1
- package/dist/dist/platform.browser.d.ts +0 -3
- package/dist/dist/platform.browser.d.ts.map +0 -1
- package/dist/dist/property-C85DCD7K.d.ts +0 -37
- package/dist/dist/property-C85DCD7K.d.ts.map +0 -1
- package/dist/dist/propertyValidationRules-CjUPOFeu.d.ts +0 -13
- package/dist/dist/propertyValidationRules-CjUPOFeu.d.ts.map +0 -1
- package/dist/dist/publishDraftGraph-DBWAN72w.d.ts +0 -93
- package/dist/dist/publishDraftGraph-DBWAN72w.d.ts.map +0 -1
- package/dist/dist/resolveModelForSyncedSeed-fIURvYRV.d.ts +0 -21
- package/dist/dist/resolveModelForSyncedSeed-fIURvYRV.d.ts.map +0 -1
- package/dist/dist/syncDbWithEas-BMHoou6X.d.ts +0 -13
- package/dist/dist/syncDbWithEas-BMHoou6X.d.ts.map +0 -1
- package/dist/dist/tolerantWebAccess-BHndShch.d.ts +0 -113
- package/dist/dist/tolerantWebAccess-BHndShch.d.ts.map +0 -1
- package/dist/dist/updateSeedRevokedAt-DpfG6ztE.d.ts +0 -11
- package/dist/dist/updateSeedRevokedAt-DpfG6ztE.d.ts.map +0 -1
- package/dist/eas-B5VJolSj.js +0 -67
- package/dist/eas-B5VJolSj.js.map +0 -1
- package/dist/errors-CS3nDpUU.js +0 -4006
- package/dist/errors-CS3nDpUU.js.map +0 -1
- package/dist/eventBus-7vxTCc3a.js +0 -64
- package/dist/eventBus-7vxTCc3a.js.map +0 -1
- package/dist/findSeedRowsByUid-CuQmK7An.js +0 -47
- package/dist/findSeedRowsByUid-CuQmK7An.js.map +0 -1
- package/dist/getItem-Uha3_H0t.js +0 -45
- package/dist/getItem-Uha3_H0t.js.map +0 -1
- package/dist/getPublishPayload-pbin4lk8.js +0 -1736
- package/dist/getPublishPayload-pbin4lk8.js.map +0 -1
- package/dist/getPublishPendingDiff-ByIaPvCn.js +0 -118
- package/dist/getPublishPendingDiff-ByIaPvCn.js.map +0 -1
- package/dist/getPublishUploads-BBqiowVc.js +0 -1080
- package/dist/getPublishUploads-BBqiowVc.js.map +0 -1
- package/dist/index-DQoyhp2c.js.map +0 -1
- package/dist/index-DxHpPNfn.js.map +0 -1
- package/dist/index-njjjo74v.js +0 -29
- package/dist/index-njjjo74v.js.map +0 -1
- package/dist/index-rOTW-2QZ.js +0 -4760
- package/dist/index-rOTW-2QZ.js.map +0 -1
- package/dist/index.browser-QPWBkLJA.js.map +0 -1
- package/dist/index.node-WsEJCOwC.js.map +0 -1
- package/dist/mimeTypes-C9r76DCH.js +0 -209
- package/dist/mimeTypes-C9r76DCH.js.map +0 -1
- package/dist/model-oHA3YhOd.js +0 -29
- package/dist/model-oHA3YhOd.js.map +0 -1
- package/dist/modelPropertyRecordSchemas-onFOG2x6.js +0 -94
- package/dist/modelPropertyRecordSchemas-onFOG2x6.js.map +0 -1
- package/dist/property-C85DCD7K.js +0 -289
- package/dist/property-C85DCD7K.js.map +0 -1
- package/dist/propertyValidationRules-CjUPOFeu.js +0 -73
- package/dist/propertyValidationRules-CjUPOFeu.js.map +0 -1
- package/dist/publishDraftGraph-DBWAN72w.js +0 -505
- package/dist/publishDraftGraph-DBWAN72w.js.map +0 -1
- package/dist/resolveModelForSyncedSeed-fIURvYRV.js.map +0 -1
- package/dist/src/Item/service/actors/loadOrCreateItem.d.ts +0 -5
- package/dist/src/Item/service/actors/loadOrCreateItem.d.ts.map +0 -1
- package/dist/src/Item/service/actors/waitForDb.d.ts +0 -4
- package/dist/src/Item/service/actors/waitForDb.d.ts.map +0 -1
- package/dist/src/ItemProperty/service/actors/loadOrCreateProperty.d.ts +0 -5
- package/dist/src/ItemProperty/service/actors/loadOrCreateProperty.d.ts.map +0 -1
- package/dist/src/ItemProperty/service/actors/saveValueToDb/analyzeInput.d.ts +0 -5
- package/dist/src/ItemProperty/service/actors/saveValueToDb/analyzeInput.d.ts.map +0 -1
- package/dist/src/ItemProperty/service/actors/saveValueToDb/index.d.ts +0 -6
- package/dist/src/ItemProperty/service/actors/saveValueToDb/index.d.ts.map +0 -1
- package/dist/src/ItemProperty/service/actors/saveValueToDb/rowContext.d.ts.map +0 -1
- package/dist/src/ItemProperty/service/actors/saveValueToDb/saveFile.d.ts +0 -24
- package/dist/src/ItemProperty/service/actors/saveValueToDb/saveFile.d.ts.map +0 -1
- package/dist/src/ItemProperty/service/actors/saveValueToDb/saveHtml.d.ts +0 -5
- package/dist/src/ItemProperty/service/actors/saveValueToDb/saveHtml.d.ts.map +0 -1
- package/dist/src/ItemProperty/service/actors/saveValueToDb/saveImage.d.ts +0 -5
- package/dist/src/ItemProperty/service/actors/saveValueToDb/saveImage.d.ts.map +0 -1
- package/dist/src/ItemProperty/service/actors/saveValueToDb/saveItemStorage.d.ts +0 -10
- package/dist/src/ItemProperty/service/actors/saveValueToDb/saveItemStorage.d.ts.map +0 -1
- package/dist/src/ItemProperty/service/actors/saveValueToDb/storageValue.d.ts +0 -22
- package/dist/src/ItemProperty/service/actors/saveValueToDb/storageValue.d.ts.map +0 -1
- package/dist/src/ItemProperty/service/actors/waitForDb.d.ts +0 -4
- package/dist/src/ItemProperty/service/actors/waitForDb.d.ts.map +0 -1
- package/dist/src/Model/service/actors/createModelProperties.d.ts +0 -9
- package/dist/src/Model/service/actors/createModelProperties.d.ts.map +0 -1
- package/dist/src/Model/service/actors/loadOrCreateModel.d.ts +0 -5
- package/dist/src/Model/service/actors/loadOrCreateModel.d.ts.map +0 -1
- package/dist/src/Schema/service/actors/checkExistingSchema.d.ts +0 -5
- package/dist/src/Schema/service/actors/checkExistingSchema.d.ts.map +0 -1
- package/dist/src/Schema/service/actors/createModelInstances.d.ts +0 -11
- package/dist/src/Schema/service/actors/createModelInstances.d.ts.map +0 -1
- package/dist/src/Schema/service/actors/createPropertyInstances.d.ts +0 -12
- package/dist/src/Schema/service/actors/createPropertyInstances.d.ts.map +0 -1
- package/dist/src/Schema/service/actors/validateSchema.d.ts +0 -5
- package/dist/src/Schema/service/actors/validateSchema.d.ts.map +0 -1
- package/dist/src/Schema/service/actors/verifyModelInstancesInCache.d.ts +0 -6
- package/dist/src/Schema/service/actors/verifyModelInstancesInCache.d.ts.map +0 -1
- package/dist/src/Schema/service/actors/verifyModelsInDb.d.ts +0 -7
- package/dist/src/Schema/service/actors/verifyModelsInDb.d.ts.map +0 -1
- package/dist/src/Schema/service/actors/verifyPropertiesInDb.d.ts +0 -8
- package/dist/src/Schema/service/actors/verifyPropertiesInDb.d.ts.map +0 -1
- package/dist/src/Schema/service/actors/verifyPropertyInstancesInCache.d.ts +0 -6
- package/dist/src/Schema/service/actors/verifyPropertyInstancesInCache.d.ts.map +0 -1
- package/dist/src/Schema/service/actors/verifySchemaInDb.d.ts +0 -7
- package/dist/src/Schema/service/actors/verifySchemaInDb.d.ts.map +0 -1
- package/dist/src/Schema/service/actors/writeModelsToDb.d.ts +0 -9
- package/dist/src/Schema/service/actors/writeModelsToDb.d.ts.map +0 -1
- package/dist/src/Schema/service/actors/writePropertiesToDb.d.ts +0 -10
- package/dist/src/Schema/service/actors/writePropertiesToDb.d.ts.map +0 -1
- package/dist/src/Schema/service/actors/writeSchemaToDb.d.ts +0 -11
- package/dist/src/Schema/service/actors/writeSchemaToDb.d.ts.map +0 -1
- package/dist/src/browser/helpers/ArweaveClient.d.ts +0 -14
- package/dist/src/browser/helpers/ArweaveClient.d.ts.map +0 -1
- package/dist/src/browser/helpers/EasClient.d.ts +0 -10
- package/dist/src/browser/helpers/EasClient.d.ts.map +0 -1
- package/dist/src/browser/helpers/QueryClient.d.ts +0 -9
- package/dist/src/browser/helpers/QueryClient.d.ts.map +0 -1
- package/dist/src/client/actors/addModelsToStore.d.ts +0 -4
- package/dist/src/client/actors/addModelsToStore.d.ts.map +0 -1
- package/dist/src/db/backfillMetadataPropertyIds.d.ts +0 -7
- package/dist/src/db/backfillMetadataPropertyIds.d.ts.map +0 -1
- package/dist/src/db/read/getItem.d.ts +0 -3
- package/dist/src/db/read/getItem.d.ts.map +0 -1
- package/dist/src/db/read/getPropertyData.d.ts +0 -4
- package/dist/src/db/read/getPropertyData.d.ts.map +0 -1
- package/dist/src/db/read/getRelatedItemsForPublish.d.ts +0 -10
- package/dist/src/db/read/getRelatedItemsForPublish.d.ts.map +0 -1
- package/dist/src/db/read/getSeedData.d.ts +0 -12
- package/dist/src/db/read/getSeedData.d.ts.map +0 -1
- package/dist/src/db/read/itemLoads.d.ts +0 -20
- package/dist/src/db/read/itemLoads.d.ts.map +0 -1
- package/dist/src/db/read/publishDraftGraph.d.ts +0 -64
- package/dist/src/db/read/publishDraftGraph.d.ts.map +0 -1
- package/dist/src/db/write/linkModelToSchema.d.ts +0 -12
- package/dist/src/db/write/linkModelToSchema.d.ts.map +0 -1
- package/dist/src/helpers/ArweaveClient/BaseArweaveClient.d.ts +0 -2
- package/dist/src/helpers/ArweaveClient/BaseArweaveClient.d.ts.map +0 -1
- package/dist/src/helpers/ArweaveClient/arweaveL1UploadApi.d.ts +0 -2
- package/dist/src/helpers/ArweaveClient/arweaveL1UploadApi.d.ts.map +0 -1
- package/dist/src/helpers/ArweaveClient/selectReadGateway.d.ts +0 -2
- package/dist/src/helpers/ArweaveClient/selectReadGateway.d.ts.map +0 -1
- package/dist/src/helpers/ArweaveClient/uploadApiVerification.d.ts +0 -2
- package/dist/src/helpers/ArweaveClient/uploadApiVerification.d.ts.map +0 -1
- package/dist/src/helpers/EasClient/BaseEasClient.d.ts +0 -2
- package/dist/src/helpers/EasClient/BaseEasClient.d.ts.map +0 -1
- package/dist/src/helpers/QueryClient/BaseQueryClient.d.ts +0 -2
- package/dist/src/helpers/QueryClient/BaseQueryClient.d.ts.map +0 -1
- package/dist/src/helpers/easUid.d.ts +0 -2
- package/dist/src/helpers/easUid.d.ts.map +0 -1
- package/dist/src/helpers/entity/entityDestroy.d.ts +0 -49
- package/dist/src/helpers/entity/entityDestroy.d.ts.map +0 -1
- package/dist/src/helpers/entity/entityFind.d.ts +0 -52
- package/dist/src/helpers/entity/entityFind.d.ts.map +0 -1
- package/dist/src/helpers/entity/entityState.d.ts +0 -28
- package/dist/src/helpers/entity/entityState.d.ts.map +0 -1
- package/dist/src/helpers/entity/entityUnload.d.ts +0 -56
- package/dist/src/helpers/entity/entityUnload.d.ts.map +0 -1
- package/dist/src/helpers/entity/evictionEpoch.d.ts +0 -43
- package/dist/src/helpers/entity/evictionEpoch.d.ts.map +0 -1
- package/dist/src/helpers/entity/index.d.ts +0 -12
- package/dist/src/helpers/entity/index.d.ts.map +0 -1
- package/dist/src/helpers/gateway/gatewayState.d.ts +0 -2
- package/dist/src/helpers/gateway/gatewayState.d.ts.map +0 -1
- package/dist/src/helpers/gateway/resolveSeedGatewayEndpoints.d.ts +0 -2
- package/dist/src/helpers/gateway/resolveSeedGatewayEndpoints.d.ts.map +0 -1
- package/dist/src/helpers/gateway/seedGatewayConfig.d.ts +0 -2
- package/dist/src/helpers/gateway/seedGatewayConfig.d.ts.map +0 -1
- package/dist/src/helpers/getSchemaForItemProperty.d.ts +0 -15
- package/dist/src/helpers/getSchemaForItemProperty.d.ts.map +0 -1
- package/dist/src/helpers/getSegmentedItemProperties.d.ts +0 -10
- package/dist/src/helpers/getSegmentedItemProperties.d.ts.map +0 -1
- package/dist/src/helpers/isSqliteUniqueConstraintError.d.ts +0 -7
- package/dist/src/helpers/isSqliteUniqueConstraintError.d.ts.map +0 -1
- package/dist/src/helpers/propertyValidationRules.d.ts +0 -20
- package/dist/src/helpers/propertyValidationRules.d.ts.map +0 -1
- package/dist/src/helpers/propertyWriteTickets.d.ts +0 -11
- package/dist/src/helpers/propertyWriteTickets.d.ts.map +0 -1
- package/dist/src/helpers/reconcilePropertyDraftRows.d.ts +0 -10
- package/dist/src/helpers/reconcilePropertyDraftRows.d.ts.map +0 -1
- package/dist/src/helpers/waitForEntityIdle.d.ts +0 -21
- package/dist/src/helpers/waitForEntityIdle.d.ts.map +0 -1
- package/dist/src/interfaces/IQueryClient.d.ts +0 -15
- package/dist/src/interfaces/IQueryClient.d.ts.map +0 -1
- package/dist/src/node/helpers/ArweaveClient.d.ts +0 -5
- package/dist/src/node/helpers/ArweaveClient.d.ts.map +0 -1
- package/dist/src/node/helpers/EasClient.d.ts +0 -5
- package/dist/src/node/helpers/EasClient.d.ts.map +0 -1
- package/dist/src/node/helpers/QueryClient.d.ts +0 -5
- package/dist/src/node/helpers/QueryClient.d.ts.map +0 -1
- package/dist/src/services/write/actors/validateEntity.d.ts +0 -6
- package/dist/src/services/write/actors/validateEntity.d.ts.map +0 -1
- package/dist/src/services/write/actors/writeToDatabase.d.ts +0 -14
- package/dist/src/services/write/actors/writeToDatabase.d.ts.map +0 -1
- package/dist/src/services/write/writeProcessMachine.d.ts +0 -56
- package/dist/src/services/write/writeProcessMachine.d.ts.map +0 -1
- package/dist/src/stores/eas.d.ts +0 -2
- package/dist/src/stores/eas.d.ts.map +0 -1
- package/dist/src/types/arweave.d.ts +0 -57
- package/dist/src/types/arweave.d.ts.map +0 -1
- package/dist/src/types/gateway.d.ts +0 -2
- package/dist/src/types/gateway.d.ts.map +0 -1
- package/dist/syncDbWithEas-BMHoou6X.js.map +0 -1
- package/dist/updateSeedRevokedAt-DpfG6ztE.js +0 -31
- package/dist/updateSeedRevokedAt-DpfG6ztE.js.map +0 -1
|
@@ -0,0 +1,1456 @@
|
|
|
1
|
+
import { setup, assign, createActor } from 'xstate';
|
|
2
|
+
import { T as applyContextUpdate, U as isInternalUpdate, V as evictionLog, W as holdChild, X as isEntityTornDown, Y as sameEntity, Z as DEFAULT_READY_TIMEOUT_MS, _ as waitForEntityReady, $ as createReactiveProxy, a0 as runEntityLoad, a1 as evictEntities, a2 as entityStatus, a3 as releaseEntity, a4 as destroyEntity, a5 as EntityCache } from './Item-Bf4kWKpH.js';
|
|
3
|
+
import { SchemaValidationService } from './SchemaValidationService-CnmKyzR-.js';
|
|
4
|
+
import { m as listLatestSchemaFiles, n as readSchemaFile, o as applySchemaFile, p as resolveSchemaRow, S as SCHEMA_FILE_FORMAT, q as loadAllSchemasFromDb, M as Model, u as getDraftSaveError, C as ConflictError, w as writeNextSchemaVersion, v as queueDraftSave, x as setupEntityLiveQuery, y as mergeSchemaFiles, z as trackDraftSave } from './errors-DLSoqSHG.js';
|
|
5
|
+
import { B as BaseDb, t as schemas, d as models, j as modelSchemas, l as properties, w as BaseFileManager } from './BaseFileManager-BAlySv8w.js';
|
|
6
|
+
import { eq, desc, and, inArray } from 'drizzle-orm';
|
|
7
|
+
import { S as SEED_PROTOCOL_SCHEMA_NAME, I as INTERNAL_SCHEMA_IDS, m as generateId, o as addSchemaToDb, p as isInternalSchema, q as inDefinitionsTransaction, s as isClientReady, u as upsertSchemaRow, t as broadcastSchemasInvalidate } from './tabEvents-CaVmngqr.js';
|
|
8
|
+
import '@seedprotocol/arweave';
|
|
9
|
+
import 'pluralize';
|
|
10
|
+
import '@seedprotocol/eas';
|
|
11
|
+
import debug from 'debug';
|
|
12
|
+
|
|
13
|
+
const validationService = new SchemaValidationService();
|
|
14
|
+
const schemaMachine = setup({
|
|
15
|
+
types: {
|
|
16
|
+
context: {},
|
|
17
|
+
input: {},
|
|
18
|
+
events: {},
|
|
19
|
+
},
|
|
20
|
+
actions: {
|
|
21
|
+
// Validation is synchronous: the result is in the context as soon as the event is handled
|
|
22
|
+
validate: assign(({ context }) => {
|
|
23
|
+
try {
|
|
24
|
+
return { _validationErrors: validationService.validateSchema(context).errors };
|
|
25
|
+
}
|
|
26
|
+
catch (error) {
|
|
27
|
+
return {
|
|
28
|
+
_validationErrors: [{
|
|
29
|
+
field: 'schema',
|
|
30
|
+
message: error instanceof Error ? error.message : 'Unknown validation error',
|
|
31
|
+
code: 'validation_exception',
|
|
32
|
+
severity: 'error',
|
|
33
|
+
}],
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
}),
|
|
37
|
+
},
|
|
38
|
+
}).createMachine({
|
|
39
|
+
id: 'schema',
|
|
40
|
+
initial: 'idle',
|
|
41
|
+
context: ({ input }) => ({
|
|
42
|
+
schemaName: input.schemaName,
|
|
43
|
+
_isDraft: false,
|
|
44
|
+
_editedProperties: new Set(),
|
|
45
|
+
_validationErrors: undefined,
|
|
46
|
+
_liveQueryModelIds: [],
|
|
47
|
+
}),
|
|
48
|
+
on: {
|
|
49
|
+
// Every key is applied, including ones the context doesn't have yet (id, version, metadata
|
|
50
|
+
// sent before the load sets them). Internal-only updates (`_dbUpdatedAt` after a draft save)
|
|
51
|
+
// don't revalidate.
|
|
52
|
+
updateContext: [
|
|
53
|
+
{
|
|
54
|
+
guard: ({ event }) => !isInternalUpdate(event),
|
|
55
|
+
actions: [assign(({ context, event }) => applyContextUpdate(context, event)), 'validate'],
|
|
56
|
+
},
|
|
57
|
+
{ actions: assign(({ context, event }) => applyContextUpdate(context, event)) },
|
|
58
|
+
],
|
|
59
|
+
validateSchema: {
|
|
60
|
+
actions: 'validate',
|
|
61
|
+
},
|
|
62
|
+
markAsDraft: {
|
|
63
|
+
actions: assign(({ context, event }) => ({
|
|
64
|
+
...context,
|
|
65
|
+
_isDraft: true,
|
|
66
|
+
_isEdited: true,
|
|
67
|
+
_editedProperties: new Set([
|
|
68
|
+
...(context._editedProperties || []),
|
|
69
|
+
event.propertyKey,
|
|
70
|
+
]),
|
|
71
|
+
})),
|
|
72
|
+
},
|
|
73
|
+
clearDraft: {
|
|
74
|
+
actions: assign(({ context, event }) => {
|
|
75
|
+
const newContext = { ...context };
|
|
76
|
+
newContext._isDraft = false;
|
|
77
|
+
newContext._isEdited = false;
|
|
78
|
+
newContext._editedProperties = new Set();
|
|
79
|
+
// Update conflict detection metadata if provided
|
|
80
|
+
if (event._dbUpdatedAt !== undefined) {
|
|
81
|
+
newContext._dbUpdatedAt = event._dbUpdatedAt;
|
|
82
|
+
}
|
|
83
|
+
if (event._dbVersion !== undefined) {
|
|
84
|
+
newContext._dbVersion = event._dbVersion;
|
|
85
|
+
}
|
|
86
|
+
// saveNewVersion passes the schema it just wrote: the instance now is that version.
|
|
87
|
+
const saved = event.savedSchema;
|
|
88
|
+
if (saved) {
|
|
89
|
+
newContext.version = saved.version;
|
|
90
|
+
newContext.metadata = saved.metadata;
|
|
91
|
+
newContext.migrations = saved.migrations;
|
|
92
|
+
}
|
|
93
|
+
return newContext;
|
|
94
|
+
}),
|
|
95
|
+
},
|
|
96
|
+
// The load runs outside the machine (Schema.load); its result arrives here
|
|
97
|
+
loaded: [
|
|
98
|
+
{
|
|
99
|
+
// Created at runtime: what code already set wins over the new record's defaults
|
|
100
|
+
guard: ({ event }) => event.output.created,
|
|
101
|
+
actions: assign(({ context, event }) => {
|
|
102
|
+
const { schema, schemaRecord, modelIds } = event.output;
|
|
103
|
+
return {
|
|
104
|
+
_schemaRecord: schemaRecord,
|
|
105
|
+
id: schema.id, // schemaFileId (string)
|
|
106
|
+
_dbId: schemaRecord?.id, // Database integer ID
|
|
107
|
+
$schema: context.$schema ?? schema.$schema,
|
|
108
|
+
version: context.version ?? schema.version,
|
|
109
|
+
metadata: context.metadata ?? schema.metadata,
|
|
110
|
+
enums: context.enums ?? schema.enums,
|
|
111
|
+
migrations: context.migrations ?? schema.migrations,
|
|
112
|
+
nameMatch: context.nameMatch ?? schema.nameMatch,
|
|
113
|
+
models: context.models ?? schema.models,
|
|
114
|
+
_liveQueryModelIds: modelIds,
|
|
115
|
+
};
|
|
116
|
+
}),
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
actions: assign(({ event }) => {
|
|
120
|
+
const { schema, schemaRecord, modelIds, loadedAt, dbVersion, dbUpdatedAt } = event.output;
|
|
121
|
+
return {
|
|
122
|
+
schemaName: schema.metadata.name,
|
|
123
|
+
$schema: schema.$schema,
|
|
124
|
+
version: schema.version,
|
|
125
|
+
metadata: schema.metadata,
|
|
126
|
+
models: schema.models,
|
|
127
|
+
enums: schema.enums,
|
|
128
|
+
migrations: schema.migrations,
|
|
129
|
+
nameMatch: schema.nameMatch,
|
|
130
|
+
_isDraft: false,
|
|
131
|
+
_isEdited: schemaRecord?.isEdited ?? false,
|
|
132
|
+
_editedProperties: new Set(),
|
|
133
|
+
_validationErrors: undefined,
|
|
134
|
+
id: schema.id, // schemaFileId (string)
|
|
135
|
+
_dbId: schemaRecord?.id, // Database integer ID
|
|
136
|
+
_loadedAt: loadedAt,
|
|
137
|
+
_dbVersion: dbVersion,
|
|
138
|
+
_dbUpdatedAt: dbUpdatedAt,
|
|
139
|
+
_liveQueryModelIds: modelIds,
|
|
140
|
+
_schemaRecord: schemaRecord,
|
|
141
|
+
};
|
|
142
|
+
}),
|
|
143
|
+
},
|
|
144
|
+
],
|
|
145
|
+
destroyStarted: {
|
|
146
|
+
actions: assign({ _destroyError: null }),
|
|
147
|
+
},
|
|
148
|
+
destroyError: {
|
|
149
|
+
actions: assign(({ event }) => ({
|
|
150
|
+
_destroyError: event.error instanceof Error
|
|
151
|
+
? { message: event.error.message, name: event.error.name }
|
|
152
|
+
: { message: String(event.error) },
|
|
153
|
+
})),
|
|
154
|
+
},
|
|
155
|
+
},
|
|
156
|
+
states: {
|
|
157
|
+
idle: {},
|
|
158
|
+
},
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
const logger$1 = debug('seedSdk:schema:loadOrCreateSchema');
|
|
162
|
+
/**
|
|
163
|
+
* Query model IDs (schemaFileId) from database for a given schema
|
|
164
|
+
*/
|
|
165
|
+
const getModelIdsForSchema = async (schemaId) => {
|
|
166
|
+
const db = BaseDb.getAppDb();
|
|
167
|
+
if (!db) {
|
|
168
|
+
logger$1('Database not available, cannot query model IDs');
|
|
169
|
+
return [];
|
|
170
|
+
}
|
|
171
|
+
try {
|
|
172
|
+
const modelRecords = await db
|
|
173
|
+
.select({
|
|
174
|
+
modelFileId: models.schemaFileId,
|
|
175
|
+
})
|
|
176
|
+
.from(modelSchemas)
|
|
177
|
+
.innerJoin(models, eq(modelSchemas.modelId, models.id))
|
|
178
|
+
.where(eq(modelSchemas.schemaId, schemaId));
|
|
179
|
+
const modelIds = modelRecords
|
|
180
|
+
.map((row) => row.modelFileId)
|
|
181
|
+
.filter((id) => id !== null && id !== undefined);
|
|
182
|
+
logger$1(`Found ${modelIds.length} model IDs for schema (id: ${schemaId}): ${modelIds.join(', ')}`);
|
|
183
|
+
return modelIds;
|
|
184
|
+
}
|
|
185
|
+
catch (error) {
|
|
186
|
+
logger$1(`Error querying model IDs for schema ${schemaId}:`, error);
|
|
187
|
+
return [];
|
|
188
|
+
}
|
|
189
|
+
};
|
|
190
|
+
/**
|
|
191
|
+
* Load the schema's Model instances, held by `owner` (the loading Schema) so an app's unload of a
|
|
192
|
+
* model doesn't drop it from `schema.models` while the schema is loaded.
|
|
193
|
+
*/
|
|
194
|
+
const createModelInstances = async (modelIds, since, owner) => {
|
|
195
|
+
if (modelIds.length === 0) {
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
try {
|
|
199
|
+
const _mod_0 = await import('./errors-DLSoqSHG.js');
|
|
200
|
+
const _ns_0 = _mod_0.a4;
|
|
201
|
+
const mod = _ns_0;
|
|
202
|
+
const Model = mod?.Model ?? mod?.default;
|
|
203
|
+
if (!Model) {
|
|
204
|
+
logger$1('Model not available from dynamic import');
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
const createPromises = modelIds.map(async (modelFileId) => {
|
|
208
|
+
try {
|
|
209
|
+
// Not if the schema was evicted (Schema.destroy, test cleanup) since this check started
|
|
210
|
+
const model = await Model.createById(modelFileId, { since, hold: false });
|
|
211
|
+
if (model && owner)
|
|
212
|
+
holdChild(owner, model, Model.cache);
|
|
213
|
+
if (model) {
|
|
214
|
+
logger$1(`Created/cached Model instance for modelFileId "${modelFileId}"`);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
catch (error) {
|
|
218
|
+
logger$1(`Error creating Model instance for modelFileId "${modelFileId}": ${error}`);
|
|
219
|
+
}
|
|
220
|
+
});
|
|
221
|
+
await Promise.all(createPromises);
|
|
222
|
+
logger$1(`Finished creating/caching ${modelIds.length} Model instances`);
|
|
223
|
+
}
|
|
224
|
+
catch (error) {
|
|
225
|
+
logger$1(`Error in createModelInstances: ${error}`);
|
|
226
|
+
}
|
|
227
|
+
};
|
|
228
|
+
const findSchemaRow = async (db, schemaName) => {
|
|
229
|
+
if (schemaName === SEED_PROTOCOL_SCHEMA_NAME) {
|
|
230
|
+
const [internal] = await db.select().from(schemas).where(eq(schemas.schemaFileId, INTERNAL_SCHEMA_IDS[0])).limit(1);
|
|
231
|
+
if (internal)
|
|
232
|
+
return internal;
|
|
233
|
+
}
|
|
234
|
+
const [byName] = await db
|
|
235
|
+
.select()
|
|
236
|
+
.from(schemas)
|
|
237
|
+
.where(eq(schemas.name, schemaName))
|
|
238
|
+
.orderBy(desc(schemas.isDraft), desc(schemas.version))
|
|
239
|
+
.limit(1);
|
|
240
|
+
if (byName)
|
|
241
|
+
return byName;
|
|
242
|
+
const [byFileId] = await db.select().from(schemas).where(eq(schemas.schemaFileId, schemaName)).limit(1);
|
|
243
|
+
return byFileId;
|
|
244
|
+
};
|
|
245
|
+
/**
|
|
246
|
+
* Creates the schema that has no row or file: the bundled Seed Protocol schema, or an empty draft
|
|
247
|
+
* (version 1, new id, no models).
|
|
248
|
+
*/
|
|
249
|
+
const createSchema = async (schemaName) => {
|
|
250
|
+
if (schemaName === SEED_PROTOCOL_SCHEMA_NAME) {
|
|
251
|
+
const _mod_1 = await import('./errors-DLSoqSHG.js');
|
|
252
|
+
const _ns_1 = _mod_1.a6;
|
|
253
|
+
const internalSchema = _ns_1;
|
|
254
|
+
const { schemaFile, schemaRecord } = await applySchemaFile(internalSchema.default, {
|
|
255
|
+
store: false,
|
|
256
|
+
});
|
|
257
|
+
return { schema: schemaFile, schemaRecord };
|
|
258
|
+
}
|
|
259
|
+
const now = new Date().toISOString();
|
|
260
|
+
const schema = {
|
|
261
|
+
$schema: SCHEMA_FILE_FORMAT,
|
|
262
|
+
version: 1,
|
|
263
|
+
id: generateId(),
|
|
264
|
+
metadata: { name: schemaName, createdAt: now, updatedAt: now },
|
|
265
|
+
models: {},
|
|
266
|
+
enums: {},
|
|
267
|
+
migrations: [{ version: 1, timestamp: now, description: 'Initial schema', changes: [] }],
|
|
268
|
+
};
|
|
269
|
+
const schemaRecord = await addSchemaToDb({
|
|
270
|
+
name: schemaName,
|
|
271
|
+
version: schema.version,
|
|
272
|
+
createdAt: new Date(now).getTime(),
|
|
273
|
+
updatedAt: new Date(now).getTime(),
|
|
274
|
+
}, schema.id, JSON.stringify(schema, null, 2), true, // isDraft
|
|
275
|
+
true);
|
|
276
|
+
logger$1(`Created new draft schema ${schemaName} in database`);
|
|
277
|
+
return { schema, schemaRecord };
|
|
278
|
+
};
|
|
279
|
+
/**
|
|
280
|
+
* Loads the schema named `schemaName` (or with that file id): its row, drafts first, resolved by
|
|
281
|
+
* resolveSchemaRow, with its models' instances cached. With no row, a version file of that name is
|
|
282
|
+
* applied first; with neither, the schema is created. A failed read throws rather than creating
|
|
283
|
+
* over the existing row.
|
|
284
|
+
*/
|
|
285
|
+
async function loadOrCreateSchema(schemaName, owner) {
|
|
286
|
+
const since = evictionLog.now();
|
|
287
|
+
const db = BaseDb.getAppDb();
|
|
288
|
+
if (!db)
|
|
289
|
+
throw new Error('Database not available');
|
|
290
|
+
if (!schemaName)
|
|
291
|
+
throw new Error('Schema name is required');
|
|
292
|
+
let row = await findSchemaRow(db, schemaName);
|
|
293
|
+
let created;
|
|
294
|
+
if (!row) {
|
|
295
|
+
// A version file with no row yet (written by another tool, or before this database)
|
|
296
|
+
const file = (await listLatestSchemaFiles()).find((info) => info.name === schemaName);
|
|
297
|
+
if (file) {
|
|
298
|
+
const schemaFile = await readSchemaFile(file.filePath);
|
|
299
|
+
if (!schemaFile)
|
|
300
|
+
throw new Error(`Could not read schema file ${file.filePath}`);
|
|
301
|
+
await applySchemaFile({ ...schemaFile, id: schemaFile.id ?? file.schemaFileId }, { store: false });
|
|
302
|
+
row = await findSchemaRow(db, schemaName);
|
|
303
|
+
if (!row)
|
|
304
|
+
throw new Error(`Schema "${schemaName}" has no row after applying ${file.filePath}`);
|
|
305
|
+
}
|
|
306
|
+
else {
|
|
307
|
+
created = await createSchema(schemaName);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
const loadedAt = Date.now();
|
|
311
|
+
if (created) {
|
|
312
|
+
const modelIds = Object.values(created.schema.models ?? {}).map((model) => model.id).filter(Boolean);
|
|
313
|
+
return {
|
|
314
|
+
...created,
|
|
315
|
+
modelIds,
|
|
316
|
+
loadedAt,
|
|
317
|
+
dbVersion: created.schema.version,
|
|
318
|
+
dbUpdatedAt: loadedAt,
|
|
319
|
+
created: true,
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
logger$1(`Found schema record: name="${row.name}", isDraft=${row.isDraft}`);
|
|
323
|
+
const { schema } = await resolveSchemaRow(row, db);
|
|
324
|
+
const modelIds = row.id ? await getModelIdsForSchema(row.id) : [];
|
|
325
|
+
await createModelInstances(modelIds, since, owner);
|
|
326
|
+
return {
|
|
327
|
+
schema,
|
|
328
|
+
schemaRecord: row,
|
|
329
|
+
modelIds,
|
|
330
|
+
loadedAt,
|
|
331
|
+
dbVersion: row.version || schema.version,
|
|
332
|
+
dbUpdatedAt: row.updatedAt || loadedAt,
|
|
333
|
+
created: false,
|
|
334
|
+
};
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
const logger = debug('seedSdk:schema:saveNewVersion');
|
|
338
|
+
const saveDraftLogger = debug('seedSdk:schema:saveDraftToDb');
|
|
339
|
+
// Define tracked properties for the Proxy
|
|
340
|
+
// These properties will be read from/written to the actor context
|
|
341
|
+
const TRACKED_PROPERTIES = [
|
|
342
|
+
'id', // schemaFileId (string) - public ID
|
|
343
|
+
'$schema',
|
|
344
|
+
'version',
|
|
345
|
+
'metadata',
|
|
346
|
+
'enums',
|
|
347
|
+
'migrations',
|
|
348
|
+
'name', // metadata.name (flattened)
|
|
349
|
+
'createdAt', // metadata.createdAt (flattened)
|
|
350
|
+
'updatedAt', // metadata.updatedAt (flattened)
|
|
351
|
+
];
|
|
352
|
+
class Schema {
|
|
353
|
+
constructor(schemaName) {
|
|
354
|
+
const serviceInput = {
|
|
355
|
+
schemaName,
|
|
356
|
+
};
|
|
357
|
+
this._service = createActor(schemaMachine, {
|
|
358
|
+
input: serviceInput,
|
|
359
|
+
});
|
|
360
|
+
this._service.start();
|
|
361
|
+
// Follows the schema's model links once it has loaded
|
|
362
|
+
this._setupLiveQuerySubscription();
|
|
363
|
+
}
|
|
364
|
+
/**
|
|
365
|
+
* Load the schema (creating a draft for an unknown name), hold its models, and cache it under
|
|
366
|
+
* its file id and name. Another cached instance that already has the loaded id keeps it.
|
|
367
|
+
*/
|
|
368
|
+
static async load(instance) {
|
|
369
|
+
let output;
|
|
370
|
+
try {
|
|
371
|
+
output = await loadOrCreateSchema(instance._getSnapshotContext().schemaName, instance);
|
|
372
|
+
}
|
|
373
|
+
catch (error) {
|
|
374
|
+
// Why it failed, for useSchema
|
|
375
|
+
if (!isEntityTornDown(instance)) {
|
|
376
|
+
const loadingError = { stage: 'loading', error: error instanceof Error ? error : new Error(String(error)) };
|
|
377
|
+
instance._service.send({ type: 'updateContext', _loadingError: loadingError });
|
|
378
|
+
}
|
|
379
|
+
throw error;
|
|
380
|
+
}
|
|
381
|
+
if (isEntityTornDown(instance))
|
|
382
|
+
return;
|
|
383
|
+
instance._service.send({ type: 'loaded', output });
|
|
384
|
+
const { id, metadata, schemaName } = instance._getSnapshotContext();
|
|
385
|
+
const other = id ? Schema.cache.peek(id) : undefined;
|
|
386
|
+
if (other && !sameEntity(other, instance))
|
|
387
|
+
return;
|
|
388
|
+
Schema.cache.setKeys(instance, [id, metadata?.name ?? schemaName]);
|
|
389
|
+
}
|
|
390
|
+
static create(schemaName, options) {
|
|
391
|
+
if (!schemaName) {
|
|
392
|
+
throw new Error('Schema name is required');
|
|
393
|
+
}
|
|
394
|
+
const waitForReady = options?.waitForReady !== false;
|
|
395
|
+
const readyTimeout = options?.readyTimeout ?? DEFAULT_READY_TIMEOUT_MS;
|
|
396
|
+
const holds = options?.hold === false ? 0 : 1;
|
|
397
|
+
// Cached under this name (or file id)
|
|
398
|
+
const cached = this.cache.peek(schemaName);
|
|
399
|
+
if (cached) {
|
|
400
|
+
if (holds)
|
|
401
|
+
this.cache.holdInstance(cached);
|
|
402
|
+
if (!waitForReady)
|
|
403
|
+
return cached;
|
|
404
|
+
return waitForEntityReady(cached, { timeout: readyTimeout }).then(() => cached);
|
|
405
|
+
}
|
|
406
|
+
// Create new instance
|
|
407
|
+
const newInstance = new this(schemaName);
|
|
408
|
+
// Wrap instance in Proxy for reactive property access
|
|
409
|
+
const proxiedInstance = createReactiveProxy({
|
|
410
|
+
instance: newInstance,
|
|
411
|
+
service: newInstance._service,
|
|
412
|
+
trackedProperties: TRACKED_PROPERTIES,
|
|
413
|
+
getContext: (instance) => {
|
|
414
|
+
// Handle special cases like metadata.name, models array conversion
|
|
415
|
+
const context = instance._getSnapshotContext();
|
|
416
|
+
// Get the schema name, ensuring it's never the ID
|
|
417
|
+
// Prefer metadata.name, then schemaName (but only if it's not the ID)
|
|
418
|
+
const schemaFileId = context.id; // id is now the schemaFileId (string)
|
|
419
|
+
let name = context.metadata?.name;
|
|
420
|
+
// If metadata.name is not available, use schemaName but only if it's not the ID
|
|
421
|
+
// This prevents returning the ID when the schema is still loading
|
|
422
|
+
if (!name) {
|
|
423
|
+
name = (context.schemaName && context.schemaName !== schemaFileId)
|
|
424
|
+
? context.schemaName
|
|
425
|
+
: undefined;
|
|
426
|
+
}
|
|
427
|
+
// Final fallback - if we still don't have a name, use schemaName (even if it might be the ID)
|
|
428
|
+
// This handles edge cases during loading
|
|
429
|
+
if (!name) {
|
|
430
|
+
name = context.schemaName;
|
|
431
|
+
}
|
|
432
|
+
// CRITICAL: Always create a new metadata object to ensure React detects changes
|
|
433
|
+
// Even if the metadata content is the same, we need a new reference so React re-renders
|
|
434
|
+
const metadata = context.metadata ? {
|
|
435
|
+
...context.metadata,
|
|
436
|
+
} : undefined;
|
|
437
|
+
return {
|
|
438
|
+
...context,
|
|
439
|
+
// Always return a new metadata object reference so React detects changes
|
|
440
|
+
metadata,
|
|
441
|
+
// Flatten metadata properties to top level for convenience
|
|
442
|
+
// Fall back to schemaName if metadata.name is not available (handles loading states)
|
|
443
|
+
name,
|
|
444
|
+
createdAt: context.metadata?.createdAt,
|
|
445
|
+
updatedAt: context.metadata?.updatedAt,
|
|
446
|
+
};
|
|
447
|
+
},
|
|
448
|
+
sendUpdate: (instance, prop, value) => {
|
|
449
|
+
// Handle special property updates
|
|
450
|
+
if (prop === 'name') {
|
|
451
|
+
// Update both metadata.name and schemaName
|
|
452
|
+
const context = instance._getSnapshotContext();
|
|
453
|
+
const currentMetadata = context.metadata || {
|
|
454
|
+
name: schemaName,
|
|
455
|
+
createdAt: new Date().toISOString(),
|
|
456
|
+
updatedAt: new Date().toISOString(),
|
|
457
|
+
};
|
|
458
|
+
const oldName = currentMetadata.name || context.schemaName;
|
|
459
|
+
const newName = value;
|
|
460
|
+
// Only update if the name actually changed
|
|
461
|
+
if (oldName !== newName) {
|
|
462
|
+
logger(`Updating schema name from "${oldName}" to "${newName}"`);
|
|
463
|
+
Schema.cache.setKeys(instance, [context.id, newName]);
|
|
464
|
+
const updateEvent = {
|
|
465
|
+
type: 'updateContext',
|
|
466
|
+
schemaName: newName,
|
|
467
|
+
metadata: {
|
|
468
|
+
...currentMetadata,
|
|
469
|
+
name: newName,
|
|
470
|
+
updatedAt: new Date().toISOString(),
|
|
471
|
+
},
|
|
472
|
+
};
|
|
473
|
+
// A schema still loading would overwrite the update with what it loads: send it once ready
|
|
474
|
+
if (entityStatus(instance) === 'loading') {
|
|
475
|
+
waitForEntityReady(instance).then(() => instance._service.send(updateEvent), () => logger(`Schema failed to load, cannot rename it to "${newName}"`));
|
|
476
|
+
}
|
|
477
|
+
else {
|
|
478
|
+
instance._service.send(updateEvent);
|
|
479
|
+
}
|
|
480
|
+
// Mark schema as draft when name changes
|
|
481
|
+
instance._service.send({
|
|
482
|
+
type: 'markAsDraft',
|
|
483
|
+
propertyKey: 'schema:name', // Special key for schema name changes
|
|
484
|
+
});
|
|
485
|
+
// Save draft to database immediately so changes persist
|
|
486
|
+
saveDraftLogger(`Name change detected, calling _saveDraftToDb (oldName: "${oldName}", newName: "${newName}")`);
|
|
487
|
+
trackDraftSave(instance._service, instance._saveDraftToDb(oldName, newName), `Schema "${newName}"`);
|
|
488
|
+
}
|
|
489
|
+
else {
|
|
490
|
+
logger(`Schema name unchanged: "${oldName}"`);
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
else if (prop === 'models') {
|
|
494
|
+
// Models are read-only, computed from Model instances. Array assignment was removed because
|
|
495
|
+
// the draft save could run before the new Model instances existed, losing them.
|
|
496
|
+
throw new Error('Cannot set schema.models directly. Models are computed from Model instances; ' +
|
|
497
|
+
'use Model.create(modelName, schema, { properties }) to add one.');
|
|
498
|
+
}
|
|
499
|
+
else if (prop === 'createdAt' || prop === 'updatedAt') {
|
|
500
|
+
// Update metadata object
|
|
501
|
+
const metadataContext = newInstance._getSnapshotContext();
|
|
502
|
+
const currentMetadata = metadataContext.metadata || {
|
|
503
|
+
name: schemaName,
|
|
504
|
+
createdAt: new Date().toISOString(),
|
|
505
|
+
updatedAt: new Date().toISOString(),
|
|
506
|
+
};
|
|
507
|
+
newInstance._service.send({
|
|
508
|
+
type: 'updateContext',
|
|
509
|
+
metadata: {
|
|
510
|
+
...currentMetadata,
|
|
511
|
+
[prop]: value,
|
|
512
|
+
updatedAt: new Date().toISOString(),
|
|
513
|
+
},
|
|
514
|
+
});
|
|
515
|
+
}
|
|
516
|
+
else {
|
|
517
|
+
// Standard property update
|
|
518
|
+
newInstance._service.send({
|
|
519
|
+
type: 'updateContext',
|
|
520
|
+
[prop]: value,
|
|
521
|
+
});
|
|
522
|
+
// Mark schema as draft for other property changes
|
|
523
|
+
newInstance._service.send({
|
|
524
|
+
type: 'markAsDraft',
|
|
525
|
+
propertyKey: prop,
|
|
526
|
+
});
|
|
527
|
+
// Save draft to database for tracked properties
|
|
528
|
+
if (TRACKED_PROPERTIES.includes(prop)) {
|
|
529
|
+
const trackedPropContext = newInstance._getSnapshotContext();
|
|
530
|
+
const schemaName = trackedPropContext.metadata?.name || trackedPropContext.schemaName;
|
|
531
|
+
trackDraftSave(newInstance._service, newInstance._saveDraftToDb(schemaName, schemaName), `Schema "${schemaName}"`);
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
},
|
|
535
|
+
});
|
|
536
|
+
this.cache.add(proxiedInstance, [schemaName], { hold: holds === 1 });
|
|
537
|
+
void runEntityLoad(proxiedInstance, () => Schema.load(proxiedInstance));
|
|
538
|
+
if (!waitForReady)
|
|
539
|
+
return proxiedInstance;
|
|
540
|
+
return waitForEntityReady(proxiedInstance, { timeout: readyTimeout }).then(() => proxiedInstance);
|
|
541
|
+
}
|
|
542
|
+
/**
|
|
543
|
+
* Get schema instance by schemaFileId (preferred method)
|
|
544
|
+
* Returns null if not found in cache
|
|
545
|
+
*/
|
|
546
|
+
static getById(schemaFileId) {
|
|
547
|
+
return this.cache.hold(schemaFileId) ?? null;
|
|
548
|
+
}
|
|
549
|
+
/**
|
|
550
|
+
* The cached schema with this file id or name, without taking a hold. For SDK code that reads
|
|
551
|
+
* the schema and doesn't hand it to a caller; callers that keep it use `create` or `find`.
|
|
552
|
+
*/
|
|
553
|
+
static peek(schemaFileIdOrName) {
|
|
554
|
+
return this.cache.peek(schemaFileIdOrName);
|
|
555
|
+
}
|
|
556
|
+
/** Stop and drop every cached Schema, whoever holds it (test cleanup). */
|
|
557
|
+
static clearCache() {
|
|
558
|
+
evictEntities(this.cache, () => true);
|
|
559
|
+
}
|
|
560
|
+
/**
|
|
561
|
+
* Create or get schema instance by schemaFileId
|
|
562
|
+
* Queries the database to find the schema name if not cached
|
|
563
|
+
* @param schemaFileId - The schema file ID
|
|
564
|
+
* @returns Schema instance, with a hold taken (unless `hold: false`)
|
|
565
|
+
*/
|
|
566
|
+
static async createById(schemaFileId,
|
|
567
|
+
/** @internal `hold: false` as for `create` */
|
|
568
|
+
options) {
|
|
569
|
+
if (!schemaFileId) {
|
|
570
|
+
throw new Error('Schema file ID is required');
|
|
571
|
+
}
|
|
572
|
+
// First, check if we have an instance cached by ID
|
|
573
|
+
const cachedInstance = options?.hold === false ? this.peek(schemaFileId) : this.getById(schemaFileId);
|
|
574
|
+
if (cachedInstance) {
|
|
575
|
+
return cachedInstance;
|
|
576
|
+
}
|
|
577
|
+
// Query database to get schema name from ID
|
|
578
|
+
const db = BaseDb.getAppDb();
|
|
579
|
+
if (!db) {
|
|
580
|
+
throw new Error('Database not available');
|
|
581
|
+
}
|
|
582
|
+
const dbSchemas = await db
|
|
583
|
+
.select()
|
|
584
|
+
.from(schemas)
|
|
585
|
+
.where(eq(schemas.schemaFileId, schemaFileId))
|
|
586
|
+
.orderBy(desc(schemas.version))
|
|
587
|
+
.limit(1);
|
|
588
|
+
if (dbSchemas.length === 0) {
|
|
589
|
+
throw new Error(`Schema with ID "${schemaFileId}" not found in database`);
|
|
590
|
+
}
|
|
591
|
+
const dbSchema = dbSchemas[0];
|
|
592
|
+
const schemaName = dbSchema.name;
|
|
593
|
+
if (!schemaName) {
|
|
594
|
+
throw new Error(`Schema with ID "${schemaFileId}" has no name in database`);
|
|
595
|
+
}
|
|
596
|
+
// Create schema using the name (this will load from database/file)
|
|
597
|
+
return this.create(schemaName, options?.hold === false ? { hold: false } : undefined);
|
|
598
|
+
}
|
|
599
|
+
/**
|
|
600
|
+
* Find a schema by schemaFileId or by name. Read-only: a name with no schema row gives undefined
|
|
601
|
+
* and creates nothing (`Schema.create` creates a draft for an unknown name). By name, the cached
|
|
602
|
+
* instance is used, else the stored schema is loaded. Waits for the schema to be fully loaded
|
|
603
|
+
* (idle state) by default. Takes a hold unless `hold: false`.
|
|
604
|
+
* @returns Schema instance if found, undefined otherwise
|
|
605
|
+
*/
|
|
606
|
+
static async find({ schemaFileId, schemaName, waitForReady = true, readyTimeout = DEFAULT_READY_TIMEOUT_MS, hold, }) {
|
|
607
|
+
if (schemaName) {
|
|
608
|
+
return this.findByName(schemaName, { waitForReady, readyTimeout, hold });
|
|
609
|
+
}
|
|
610
|
+
if (!schemaFileId) {
|
|
611
|
+
return undefined;
|
|
612
|
+
}
|
|
613
|
+
try {
|
|
614
|
+
const schema = (hold === false ? Schema.peek(schemaFileId) : (Schema.getById(schemaFileId) ?? undefined)) ??
|
|
615
|
+
(await Schema.createById(schemaFileId, hold === false ? { hold: false } : undefined));
|
|
616
|
+
if (waitForReady)
|
|
617
|
+
await waitForEntityReady(schema, { timeout: readyTimeout });
|
|
618
|
+
return schema;
|
|
619
|
+
}
|
|
620
|
+
catch {
|
|
621
|
+
return undefined;
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
static async findByName(schemaName, options) {
|
|
625
|
+
const createOptions = { readyTimeout: options.readyTimeout, ...(options.hold === false && { hold: false }) };
|
|
626
|
+
const loadOrCached = () => options.waitForReady
|
|
627
|
+
? this.create(schemaName, { ...createOptions, waitForReady: true })
|
|
628
|
+
: this.create(schemaName, { ...createOptions, waitForReady: false });
|
|
629
|
+
if (this.cache.peek(schemaName))
|
|
630
|
+
return loadOrCached();
|
|
631
|
+
const db = BaseDb.getAppDb();
|
|
632
|
+
if (!db)
|
|
633
|
+
return undefined;
|
|
634
|
+
const rows = await db
|
|
635
|
+
.select({ id: schemas.id })
|
|
636
|
+
.from(schemas)
|
|
637
|
+
.where(eq(schemas.name, schemaName))
|
|
638
|
+
.limit(1);
|
|
639
|
+
if (rows.length === 0)
|
|
640
|
+
return undefined;
|
|
641
|
+
return loadOrCached();
|
|
642
|
+
}
|
|
643
|
+
/**
|
|
644
|
+
* Get instantiated Schema objects for all schemas (from database and files)
|
|
645
|
+
* By default, returns only the latest version of each schema and excludes the internal Seed Protocol schema.
|
|
646
|
+
* Uses loadAllSchemasFromDb() as the single source of truth, which intelligently merges database and file data.
|
|
647
|
+
* Takes no holds on the instances it returns: a caller that keeps one uses `Schema.create` or `Schema.find`.
|
|
648
|
+
*
|
|
649
|
+
* @param options - Configuration options
|
|
650
|
+
* @param options.includeAllVersions - If true, returns all versions of each schema. Default: false
|
|
651
|
+
* @param options.includeInternal - If true, includes the internal Seed Protocol schema. Default: false
|
|
652
|
+
* @returns Array of Schema instances
|
|
653
|
+
*/
|
|
654
|
+
static async all(options = {}) {
|
|
655
|
+
const { includeAllVersions = false, includeInternal = false, waitForReady = false, readyTimeout = DEFAULT_READY_TIMEOUT_MS, } = options;
|
|
656
|
+
// Use loadAllSchemasFromDb as single source of truth
|
|
657
|
+
// This intelligently merges database and file data, including drafts
|
|
658
|
+
const allSchemasData = await loadAllSchemasFromDb();
|
|
659
|
+
// Filter internal schemas unless explicitly included
|
|
660
|
+
let filteredSchemas = includeInternal
|
|
661
|
+
? allSchemasData
|
|
662
|
+
: allSchemasData.filter(schemaData => {
|
|
663
|
+
const schema = schemaData.schema;
|
|
664
|
+
// Check if this is an internal schema by name or ID
|
|
665
|
+
return !isInternalSchema(schema.metadata?.name || '', schema.id);
|
|
666
|
+
});
|
|
667
|
+
// Filter to latest versions if needed
|
|
668
|
+
if (!includeAllVersions) {
|
|
669
|
+
// Group by schema name and keep only the latest version of each
|
|
670
|
+
const schemaMap = new Map();
|
|
671
|
+
for (const schemaData of filteredSchemas) {
|
|
672
|
+
const schemaName = schemaData.schema.metadata?.name || '';
|
|
673
|
+
if (!schemaName)
|
|
674
|
+
continue;
|
|
675
|
+
const existing = schemaMap.get(schemaName);
|
|
676
|
+
if (!existing || schemaData.schema.version > existing.schema.version) {
|
|
677
|
+
schemaMap.set(schemaName, schemaData);
|
|
678
|
+
}
|
|
679
|
+
else if (schemaData.schema.version === existing.schema.version) {
|
|
680
|
+
// If versions are equal, use updatedAt as tiebreaker
|
|
681
|
+
const currentUpdatedAt = new Date(schemaData.schema.metadata?.updatedAt || 0).getTime();
|
|
682
|
+
const existingUpdatedAt = new Date(existing.schema.metadata?.updatedAt || 0).getTime();
|
|
683
|
+
if (currentUpdatedAt > existingUpdatedAt) {
|
|
684
|
+
schemaMap.set(schemaName, schemaData);
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
filteredSchemas = Array.from(schemaMap.values());
|
|
689
|
+
}
|
|
690
|
+
// Create Schema instances using the schemaFileId from filtered data to ensure correct version
|
|
691
|
+
const schemaInstances = [];
|
|
692
|
+
const processedSchemaNames = new Set();
|
|
693
|
+
for (const schemaData of filteredSchemas) {
|
|
694
|
+
const schemaName = schemaData.schema.metadata?.name;
|
|
695
|
+
const schemaFileId = schemaData.schema.id;
|
|
696
|
+
const expectedVersion = schemaData.schema.version;
|
|
697
|
+
if (!schemaName)
|
|
698
|
+
continue;
|
|
699
|
+
// Skip if we've already processed this schema name (to avoid duplicates)
|
|
700
|
+
if (processedSchemaNames.has(schemaName)) {
|
|
701
|
+
continue;
|
|
702
|
+
}
|
|
703
|
+
processedSchemaNames.add(schemaName);
|
|
704
|
+
// Try to use schemaFileId to ensure we load the correct version
|
|
705
|
+
// First check if we have a cached instance by schemaFileId. Schema.all takes no holds: it
|
|
706
|
+
// lists schemas (useSchemas caches the list and never unloads it).
|
|
707
|
+
if (schemaFileId) {
|
|
708
|
+
const cachedById = this.peek(schemaFileId);
|
|
709
|
+
if (cachedById) {
|
|
710
|
+
// Verify the cached instance has the correct version
|
|
711
|
+
const cachedContext = cachedById.getService().getSnapshot().context;
|
|
712
|
+
if (cachedContext.version === expectedVersion) {
|
|
713
|
+
schemaInstances.push(cachedById);
|
|
714
|
+
continue;
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
// If no cached instance by ID, check by name but verify version
|
|
719
|
+
const cachedByName = this.cache.peek(schemaName);
|
|
720
|
+
if (cachedByName) {
|
|
721
|
+
const cachedContext = cachedByName.getService().getSnapshot().context;
|
|
722
|
+
// Only use cached instance if it has the correct version
|
|
723
|
+
if (cachedContext.version === expectedVersion && (!schemaFileId || cachedContext.id === schemaFileId)) {
|
|
724
|
+
schemaInstances.push(cachedByName);
|
|
725
|
+
continue;
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
// Create new instance - it will load from database
|
|
729
|
+
// The loadOrCreateSchema actor should query by name and get the latest version
|
|
730
|
+
// But to ensure we get the correct version, we'll use createById if we have the schemaFileId
|
|
731
|
+
if (schemaFileId) {
|
|
732
|
+
try {
|
|
733
|
+
const instance = await this.createById(schemaFileId, { hold: false });
|
|
734
|
+
schemaInstances.push(instance);
|
|
735
|
+
}
|
|
736
|
+
catch {
|
|
737
|
+
// Fallback to creating by name if createById fails
|
|
738
|
+
schemaInstances.push(this.create(schemaName, { waitForReady: false, hold: false }));
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
else {
|
|
742
|
+
schemaInstances.push(this.create(schemaName, { waitForReady: false, hold: false }));
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
if (waitForReady && schemaInstances.length > 0) {
|
|
746
|
+
await Promise.all(schemaInstances.map((schema) => waitForEntityReady(schema, { timeout: readyTimeout })));
|
|
747
|
+
}
|
|
748
|
+
return schemaInstances;
|
|
749
|
+
}
|
|
750
|
+
getService() {
|
|
751
|
+
return this._service;
|
|
752
|
+
}
|
|
753
|
+
_getSnapshot() {
|
|
754
|
+
return this._service.getSnapshot();
|
|
755
|
+
}
|
|
756
|
+
_getSnapshotContext() {
|
|
757
|
+
return this._getSnapshot().context;
|
|
758
|
+
}
|
|
759
|
+
get schemaName() {
|
|
760
|
+
const context = this._getSnapshotContext();
|
|
761
|
+
const schemaFileId = context.id; // id is now the schemaFileId (string)
|
|
762
|
+
// Prefer metadata.name if available (most reliable)
|
|
763
|
+
if (context.metadata?.name) {
|
|
764
|
+
return context.metadata.name;
|
|
765
|
+
}
|
|
766
|
+
// If metadata.name is not available, use schemaName but only if it's not the ID
|
|
767
|
+
// This prevents returning the ID when the schema is still loading or if an ID was mistakenly passed
|
|
768
|
+
if (context.schemaName && context.schemaName !== schemaFileId) {
|
|
769
|
+
return context.schemaName;
|
|
770
|
+
}
|
|
771
|
+
// Final fallback - return schemaName even if it might be the ID
|
|
772
|
+
// This handles edge cases during loading, but should be rare
|
|
773
|
+
return context.schemaName || '';
|
|
774
|
+
}
|
|
775
|
+
get schemaFileId() {
|
|
776
|
+
return this._getSnapshotContext().id; // id is now the schemaFileId (string)
|
|
777
|
+
}
|
|
778
|
+
get id() {
|
|
779
|
+
return this._getSnapshotContext().id; // id is now the schemaFileId (string)
|
|
780
|
+
}
|
|
781
|
+
/**
|
|
782
|
+
* Returns Model instances for this schema
|
|
783
|
+
* This is a computed property that reads from the service context
|
|
784
|
+
* Note: This is NOT reactive - use useModels() hook for reactivity
|
|
785
|
+
*/
|
|
786
|
+
get models() {
|
|
787
|
+
const context = this._getSnapshotContext();
|
|
788
|
+
const schemaName = context.schemaName;
|
|
789
|
+
// Get model IDs from service context (reactive state)
|
|
790
|
+
const liveQueryIds = context._liveQueryModelIds || [];
|
|
791
|
+
// Get pending model IDs (not yet in DB)
|
|
792
|
+
// Note: schemaId lookup is async, so we skip pending IDs here
|
|
793
|
+
// They will be included when schemaId is available asynchronously
|
|
794
|
+
const pendingIds = [];
|
|
795
|
+
// Combine and deduplicate
|
|
796
|
+
const allModelIds = [...new Set([...liveQueryIds, ...pendingIds])];
|
|
797
|
+
// Get Model instances from static cache (from schema load)
|
|
798
|
+
const seen = new Set();
|
|
799
|
+
const modelInstances = [];
|
|
800
|
+
for (const modelFileId of allModelIds) {
|
|
801
|
+
const model = Model.peek(modelFileId);
|
|
802
|
+
if (model && modelFileId && !seen.has(modelFileId)) {
|
|
803
|
+
modelInstances.push(model);
|
|
804
|
+
seen.add(modelFileId);
|
|
805
|
+
}
|
|
806
|
+
}
|
|
807
|
+
// Include models created at runtime via Model.create() that belong to this schema
|
|
808
|
+
// (they may not be in _liveQueryModelIds until schema context is updated)
|
|
809
|
+
if (schemaName) {
|
|
810
|
+
const cachedForSchema = Model.getCachedInstancesForSchema(schemaName);
|
|
811
|
+
for (const model of cachedForSchema) {
|
|
812
|
+
const id = model.id;
|
|
813
|
+
if (id && !seen.has(id)) {
|
|
814
|
+
modelInstances.push(model);
|
|
815
|
+
seen.add(id);
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
// Return a new array reference (snapshot at time of access)
|
|
820
|
+
return [...modelInstances];
|
|
821
|
+
}
|
|
822
|
+
/** `loading` until the schema and its models are loaded, then `ready` or `error`. */
|
|
823
|
+
get status() {
|
|
824
|
+
return entityStatus(this);
|
|
825
|
+
}
|
|
826
|
+
/** Resolves once `status` is `ready`; rejects when the load failed or `timeout` ms pass. */
|
|
827
|
+
waitForReady(options) {
|
|
828
|
+
return waitForEntityReady(this, options);
|
|
829
|
+
}
|
|
830
|
+
get isEdited() {
|
|
831
|
+
const context = this._getSnapshotContext();
|
|
832
|
+
// First check in-memory state
|
|
833
|
+
if (context._isEdited !== undefined) {
|
|
834
|
+
return context._isEdited;
|
|
835
|
+
}
|
|
836
|
+
// Fall back to reading from database if we have _dbId
|
|
837
|
+
if (context._dbId) {
|
|
838
|
+
// Load from database asynchronously (fire-and-forget for now)
|
|
839
|
+
// For synchronous getter, we'll need to cache it or make it async
|
|
840
|
+
// For now, return false if not in context
|
|
841
|
+
return false;
|
|
842
|
+
}
|
|
843
|
+
return false;
|
|
844
|
+
}
|
|
845
|
+
get validationErrors() {
|
|
846
|
+
return this._getSnapshotContext()._validationErrors || [];
|
|
847
|
+
}
|
|
848
|
+
/**
|
|
849
|
+
* The error from the last draft save that an assignment started (e.g. `schema.name = ...`),
|
|
850
|
+
* such as a ConflictError; undefined once a later one succeeds.
|
|
851
|
+
*/
|
|
852
|
+
get lastSaveError() {
|
|
853
|
+
return getDraftSaveError(this._service);
|
|
854
|
+
}
|
|
855
|
+
get isValid() {
|
|
856
|
+
const errors = this.validationErrors;
|
|
857
|
+
return errors.length === 0;
|
|
858
|
+
}
|
|
859
|
+
/**
|
|
860
|
+
* Validate the schema
|
|
861
|
+
* @returns Validation result
|
|
862
|
+
*/
|
|
863
|
+
async validate() {
|
|
864
|
+
// Validate the loaded schema, not the empty context of one still loading
|
|
865
|
+
await waitForEntityReady(this, { throwOnError: false });
|
|
866
|
+
this._service.send({ type: 'validateSchema' });
|
|
867
|
+
const errors = this._getSnapshotContext()._validationErrors || [];
|
|
868
|
+
return { isValid: errors.length === 0, errors };
|
|
869
|
+
}
|
|
870
|
+
/**
|
|
871
|
+
* Build the file-format `models` object from this schema's Model instances: every model
|
|
872
|
+
* (those created at runtime too), each property as its file definition ({ id, type, model,
|
|
873
|
+
* ref, refValueType, required, storage, validation, ... }).
|
|
874
|
+
*/
|
|
875
|
+
async _buildModelsFromInstances() {
|
|
876
|
+
const context = this._getSnapshotContext();
|
|
877
|
+
const _mod_2 = await import('./index-DmTtj1nk.js');
|
|
878
|
+
const _ns_2 = _mod_2.j;
|
|
879
|
+
const { convertPropertyToSchemaUpdate } = _ns_2;
|
|
880
|
+
const models = {};
|
|
881
|
+
for (const modelInstance of this.models) {
|
|
882
|
+
try {
|
|
883
|
+
const modelName = modelInstance.modelName;
|
|
884
|
+
if (!modelName)
|
|
885
|
+
continue;
|
|
886
|
+
const properties$1 = {};
|
|
887
|
+
let propertyContexts = (modelInstance.properties ?? []).map((property) => property.getService().getSnapshot().context);
|
|
888
|
+
// model.properties can still be empty for a model created at runtime (the browser fills
|
|
889
|
+
// it from a live query): read the rows, preferring each row's cached instance.
|
|
890
|
+
const modelDbId = modelInstance.getService().getSnapshot().context._dbId;
|
|
891
|
+
const db = BaseDb.getAppDb();
|
|
892
|
+
if (propertyContexts.length === 0 && modelDbId && db) {
|
|
893
|
+
const { ModelProperty } = await import('./ModelProperty-BlaEgb_U.js');
|
|
894
|
+
const rows = await db.select().from(properties).where(eq(properties.modelId, modelDbId));
|
|
895
|
+
propertyContexts = rows.map((row) => {
|
|
896
|
+
const cached = row.schemaFileId ? ModelProperty.getById(row.schemaFileId) : undefined;
|
|
897
|
+
return cached
|
|
898
|
+
? cached.getService().getSnapshot().context
|
|
899
|
+
: {
|
|
900
|
+
...row,
|
|
901
|
+
id: row.schemaFileId ?? undefined,
|
|
902
|
+
refModelId: row.refModelId ?? undefined,
|
|
903
|
+
refValueType: row.refValueType ?? undefined,
|
|
904
|
+
storageType: row.storageType ?? undefined,
|
|
905
|
+
localStorageDir: row.localStorageDir ?? undefined,
|
|
906
|
+
filenameSuffix: row.filenameSuffix ?? undefined,
|
|
907
|
+
};
|
|
908
|
+
});
|
|
909
|
+
}
|
|
910
|
+
const contextModel = context.models?.[modelName];
|
|
911
|
+
const fromContext = contextModel?.properties;
|
|
912
|
+
// nameMatch lives only in the schema file (ADR 0009): keep each property's, found by id
|
|
913
|
+
// first so a renamed property keeps it.
|
|
914
|
+
const contextNameMatch = (ctx) => {
|
|
915
|
+
const defs = Object.values(fromContext ?? {});
|
|
916
|
+
const def = (ctx.id ? defs.find((d) => d?.id === ctx.id) : undefined) ?? fromContext?.[ctx.name];
|
|
917
|
+
return def?.nameMatch;
|
|
918
|
+
};
|
|
919
|
+
for (const ctx of propertyContexts) {
|
|
920
|
+
if (!ctx.name)
|
|
921
|
+
continue;
|
|
922
|
+
const { updates } = await convertPropertyToSchemaUpdate(ctx, modelName, ctx.name);
|
|
923
|
+
const nameMatch = contextNameMatch(ctx);
|
|
924
|
+
properties$1[ctx.name] = {
|
|
925
|
+
...(ctx.id ? { id: ctx.id } : {}),
|
|
926
|
+
...updates,
|
|
927
|
+
...(ctx.validation ? { validation: ctx.validation } : {}),
|
|
928
|
+
...(ctx.htmlEmbeddedDataUriPolicy ? { htmlEmbeddedDataUriPolicy: ctx.htmlEmbeddedDataUriPolicy } : {}),
|
|
929
|
+
...(nameMatch !== undefined ? { nameMatch } : {}),
|
|
930
|
+
};
|
|
931
|
+
}
|
|
932
|
+
// No property instances loaded for this model: keep the definitions the schema has.
|
|
933
|
+
models[modelName] = {
|
|
934
|
+
...(modelInstance.id ? { id: modelInstance.id } : {}),
|
|
935
|
+
...(contextModel?.nameMatch !== undefined ? { nameMatch: contextModel.nameMatch } : {}),
|
|
936
|
+
properties: Object.keys(properties$1).length > 0 || !fromContext ? properties$1 : fromContext,
|
|
937
|
+
};
|
|
938
|
+
}
|
|
939
|
+
catch (error) {
|
|
940
|
+
logger(`Error building model from instance: ${error instanceof Error ? error.message : String(error)}`);
|
|
941
|
+
}
|
|
942
|
+
}
|
|
943
|
+
logger(`Built ${Object.keys(models).length} models from Model instances`);
|
|
944
|
+
return models;
|
|
945
|
+
}
|
|
946
|
+
/**
|
|
947
|
+
* Saves all edited properties to a new schema version.
|
|
948
|
+
* This writes the changes to a new JSON file and clears the draft flags.
|
|
949
|
+
* Validates the schema before saving.
|
|
950
|
+
* Transitions schema from draft (DB-only) to published (file + DB).
|
|
951
|
+
* @returns The file path of the new schema version
|
|
952
|
+
*/
|
|
953
|
+
async saveNewVersion() {
|
|
954
|
+
// Check for conflicts before saving
|
|
955
|
+
const conflictCheck = await this._checkForConflicts();
|
|
956
|
+
if (conflictCheck.hasConflict) {
|
|
957
|
+
const errorMessage = conflictCheck.message || 'Database was updated externally. Please reload the schema and try again.';
|
|
958
|
+
logger(`CONFLICT DETECTED: ${errorMessage}`);
|
|
959
|
+
throw new ConflictError(errorMessage, conflictCheck);
|
|
960
|
+
}
|
|
961
|
+
const context = this._getSnapshotContext();
|
|
962
|
+
if (!context._isDraft || !context._editedProperties || context._editedProperties.size === 0) {
|
|
963
|
+
logger('No changes to save');
|
|
964
|
+
return '';
|
|
965
|
+
}
|
|
966
|
+
// Validate schema before saving
|
|
967
|
+
const validationResult = await this.validate();
|
|
968
|
+
if (!validationResult.isValid) {
|
|
969
|
+
logger(`Schema validation failed with ${validationResult.errors.length} errors`);
|
|
970
|
+
throw new Error(`Cannot save schema: validation failed. Errors: ${validationResult.errors.map(e => e.message).join(', ')}`);
|
|
971
|
+
}
|
|
972
|
+
logger(`Saving new version for schema ${this.schemaName} with ${context._editedProperties.size} edited properties`);
|
|
973
|
+
// STEP 1: Ensure draft exists in database and update it with current state
|
|
974
|
+
const db = BaseDb.getAppDb();
|
|
975
|
+
if (!db) {
|
|
976
|
+
throw new Error('Database not found');
|
|
977
|
+
}
|
|
978
|
+
// Build current schema state from context
|
|
979
|
+
// CRITICAL: Read models from Model instances, not from Schema context
|
|
980
|
+
// Model instances are the source of truth for model data
|
|
981
|
+
const modelsFromInstances = await this._buildModelsFromInstances();
|
|
982
|
+
const currentSchema = {
|
|
983
|
+
id: context.id,
|
|
984
|
+
$schema: context.$schema || 'https://seedprotocol.org/schemas/data-model/v1',
|
|
985
|
+
version: context.version || 1,
|
|
986
|
+
metadata: context.metadata || {
|
|
987
|
+
name: this.schemaName,
|
|
988
|
+
createdAt: new Date().toISOString(),
|
|
989
|
+
updatedAt: new Date().toISOString(),
|
|
990
|
+
},
|
|
991
|
+
models: modelsFromInstances, // Read from Model instances, not context.models
|
|
992
|
+
enums: context.enums || {},
|
|
993
|
+
migrations: context.migrations || [],
|
|
994
|
+
...(context.nameMatch !== undefined && { nameMatch: context.nameMatch }),
|
|
995
|
+
};
|
|
996
|
+
// Check we have something to save: schema:models (new models) or modelName:propertyName (property edits)
|
|
997
|
+
const hasSchemaModels = context._editedProperties.has('schema:models');
|
|
998
|
+
const hasPropertyEdits = [...context._editedProperties].some((key) => {
|
|
999
|
+
const [modelName, propertyName] = key.split(':');
|
|
1000
|
+
return modelName && propertyName && key !== 'schema:name';
|
|
1001
|
+
});
|
|
1002
|
+
if (!hasSchemaModels && !hasPropertyEdits) {
|
|
1003
|
+
logger('No valid property updates to save');
|
|
1004
|
+
return '';
|
|
1005
|
+
}
|
|
1006
|
+
// The draft row holds the current state until the version file is written
|
|
1007
|
+
await addSchemaToDb({
|
|
1008
|
+
name: this.schemaName,
|
|
1009
|
+
version: currentSchema.version,
|
|
1010
|
+
createdAt: new Date(currentSchema.metadata.createdAt).getTime(),
|
|
1011
|
+
updatedAt: new Date(currentSchema.metadata.updatedAt).getTime(),
|
|
1012
|
+
}, currentSchema.id, JSON.stringify(currentSchema, null, 2), true);
|
|
1013
|
+
// The next version file: the previous one with the instances' models merged in by id, so
|
|
1014
|
+
// fields the instances don't carry (validation, descriptions, ...) stay. Applying it publishes
|
|
1015
|
+
// the row.
|
|
1016
|
+
const { schemaFile: publishedSchema, filePath: newFilePath } = await writeNextSchemaVersion(currentSchema.id ?? this.schemaName, (previous) => mergeSchemaFiles(previous, currentSchema), {
|
|
1017
|
+
description: 'New schema version (e.g. new models added)',
|
|
1018
|
+
changes: [{ type: 'full_schema_write' }],
|
|
1019
|
+
});
|
|
1020
|
+
// Clear edited flags on the cached ModelProperty instances of the edited keys, then on the rows
|
|
1021
|
+
// (schema, those properties, the schema's models) in one transaction.
|
|
1022
|
+
const { ModelProperty } = await import('./ModelProperty-BlaEgb_U.js');
|
|
1023
|
+
const thisSchemaName = this.schemaName;
|
|
1024
|
+
const clearedKeys = [];
|
|
1025
|
+
for (const propertyKey of context._editedProperties) {
|
|
1026
|
+
const [modelName, propertyName] = propertyKey.split(':');
|
|
1027
|
+
if (!modelName || !propertyName)
|
|
1028
|
+
continue;
|
|
1029
|
+
// Model names are only unique per schema: pick this schema's instance
|
|
1030
|
+
const [cachedInstance] = ModelProperty.cache.instances((instance) => {
|
|
1031
|
+
const ctx = instance.getService().getSnapshot().context;
|
|
1032
|
+
return (ctx.modelName === modelName &&
|
|
1033
|
+
ctx.name === propertyName &&
|
|
1034
|
+
(!ctx._schemaName || ctx._schemaName === thisSchemaName));
|
|
1035
|
+
});
|
|
1036
|
+
if (!cachedInstance)
|
|
1037
|
+
continue;
|
|
1038
|
+
cachedInstance.getService().send({ type: 'clearEdited' });
|
|
1039
|
+
clearedKeys.push({ modelName, propertyName });
|
|
1040
|
+
}
|
|
1041
|
+
const _mod_3 = await import('./tabEvents-CaVmngqr.js');
|
|
1042
|
+
const _ns_3 = _mod_3.be;
|
|
1043
|
+
const { resolveModelRecord } = _ns_3;
|
|
1044
|
+
await inDefinitionsTransaction(async (tx) => {
|
|
1045
|
+
await tx
|
|
1046
|
+
.update(schemas)
|
|
1047
|
+
.set({ isEdited: false })
|
|
1048
|
+
.where(eq(schemas.schemaFileId, publishedSchema.id));
|
|
1049
|
+
for (const { modelName, propertyName } of clearedKeys) {
|
|
1050
|
+
const modelRecord = await resolveModelRecord(modelName, { schemaName: thisSchemaName }, tx);
|
|
1051
|
+
if (!modelRecord)
|
|
1052
|
+
continue;
|
|
1053
|
+
await tx
|
|
1054
|
+
.update(properties)
|
|
1055
|
+
.set({ isEdited: false })
|
|
1056
|
+
.where(and(eq(properties.name, propertyName), eq(properties.modelId, modelRecord.id)));
|
|
1057
|
+
}
|
|
1058
|
+
if (context._dbId) {
|
|
1059
|
+
const linked = tx
|
|
1060
|
+
.select({ id: modelSchemas.modelId })
|
|
1061
|
+
.from(modelSchemas)
|
|
1062
|
+
.where(eq(modelSchemas.schemaId, context._dbId));
|
|
1063
|
+
await tx.update(models).set({ isEdited: false }).where(inArray(models.id, linked));
|
|
1064
|
+
}
|
|
1065
|
+
});
|
|
1066
|
+
// Clear draft flags on Schema and update conflict detection metadata
|
|
1067
|
+
this._service.send({
|
|
1068
|
+
type: 'clearDraft',
|
|
1069
|
+
_dbUpdatedAt: new Date(publishedSchema.metadata.updatedAt).getTime(),
|
|
1070
|
+
_dbVersion: publishedSchema.version,
|
|
1071
|
+
savedSchema: publishedSchema,
|
|
1072
|
+
});
|
|
1073
|
+
logger(`Successfully saved new version for schema ${this.schemaName} and published to file`);
|
|
1074
|
+
return newFilePath;
|
|
1075
|
+
}
|
|
1076
|
+
/**
|
|
1077
|
+
* Check for conflicts between actor context and database
|
|
1078
|
+
* @returns ConflictResult indicating if a conflict exists
|
|
1079
|
+
*/
|
|
1080
|
+
async _checkForConflicts() {
|
|
1081
|
+
const context = this._getSnapshotContext();
|
|
1082
|
+
// If we don't have load metadata, can't check for conflicts
|
|
1083
|
+
if (!context._dbUpdatedAt || !context.id) {
|
|
1084
|
+
return { hasConflict: false };
|
|
1085
|
+
}
|
|
1086
|
+
try {
|
|
1087
|
+
const db = BaseDb.getAppDb();
|
|
1088
|
+
if (!db) {
|
|
1089
|
+
return { hasConflict: false }; // Can't check without DB
|
|
1090
|
+
}
|
|
1091
|
+
// Get current DB record
|
|
1092
|
+
const dbSchemas = await db
|
|
1093
|
+
.select()
|
|
1094
|
+
.from(schemas)
|
|
1095
|
+
.where(eq(schemas.schemaFileId, context.id)) // id is now the schemaFileId (string)
|
|
1096
|
+
.orderBy(desc(schemas.version))
|
|
1097
|
+
.limit(1);
|
|
1098
|
+
if (dbSchemas.length === 0) {
|
|
1099
|
+
return { hasConflict: false }; // No DB record, no conflict
|
|
1100
|
+
}
|
|
1101
|
+
const dbRecord = dbSchemas[0];
|
|
1102
|
+
// Check if DB was updated after we loaded
|
|
1103
|
+
const dbUpdatedAt = dbRecord.updatedAt || 0;
|
|
1104
|
+
const localUpdatedAt = context._dbUpdatedAt;
|
|
1105
|
+
if (dbUpdatedAt > localUpdatedAt) {
|
|
1106
|
+
return {
|
|
1107
|
+
hasConflict: true,
|
|
1108
|
+
localVersion: context.version,
|
|
1109
|
+
dbVersion: dbRecord.version,
|
|
1110
|
+
localUpdatedAt: context.metadata?.updatedAt,
|
|
1111
|
+
dbUpdatedAt: new Date(dbUpdatedAt).toISOString(),
|
|
1112
|
+
message: `Database was updated externally. Local version: ${context.version}, DB version: ${dbRecord.version}`,
|
|
1113
|
+
};
|
|
1114
|
+
}
|
|
1115
|
+
return { hasConflict: false };
|
|
1116
|
+
}
|
|
1117
|
+
catch (error) {
|
|
1118
|
+
logger(`Error checking for conflicts: ${error instanceof Error ? error.message : String(error)}`);
|
|
1119
|
+
return { hasConflict: false }; // On error, assume no conflict to allow save
|
|
1120
|
+
}
|
|
1121
|
+
}
|
|
1122
|
+
/**
|
|
1123
|
+
* Reload schema from database
|
|
1124
|
+
* This refreshes the actor context with the latest data from the database
|
|
1125
|
+
*/
|
|
1126
|
+
async reload() {
|
|
1127
|
+
logger(`Reloading schema ${this.schemaName} from database`);
|
|
1128
|
+
await runEntityLoad(this, () => Schema.load(this));
|
|
1129
|
+
if (this.status === 'error')
|
|
1130
|
+
throw new Error('Failed to reload schema from database');
|
|
1131
|
+
}
|
|
1132
|
+
/**
|
|
1133
|
+
* Save the current schema state to the database as a draft
|
|
1134
|
+
* This persists changes immediately without creating a new file version
|
|
1135
|
+
* @param oldName - Optional old name to look up existing record before name change
|
|
1136
|
+
* @param newName - Optional new name to use (if not provided, uses this.schemaName)
|
|
1137
|
+
*/
|
|
1138
|
+
async _saveDraftToDb(oldName, newName) {
|
|
1139
|
+
saveDraftLogger(`_saveDraftToDb called for schema (oldName: "${oldName}", newName: "${newName}")`);
|
|
1140
|
+
// Not during client init in the browser: schemas are being loaded from files then, not edited
|
|
1141
|
+
if (typeof window !== 'undefined' && !isClientReady()) {
|
|
1142
|
+
saveDraftLogger(`Client not ready, skipping save (oldName: "${oldName}", newName: "${newName}")`);
|
|
1143
|
+
return;
|
|
1144
|
+
}
|
|
1145
|
+
saveDraftLogger(`Client is initialized, proceeding with save (oldName: "${oldName}", newName: "${newName}")`);
|
|
1146
|
+
const initialContext = this._getSnapshotContext();
|
|
1147
|
+
// schemaFileId when known, else the name
|
|
1148
|
+
const saveKey = initialContext.id || newName || initialContext.schemaName || oldName || '';
|
|
1149
|
+
// A save started while another for this schema runs waits for it, so renames land in order.
|
|
1150
|
+
await queueDraftSave(saveKey, async () => {
|
|
1151
|
+
const conflictCheck = await this._checkForConflicts();
|
|
1152
|
+
if (conflictCheck.hasConflict) {
|
|
1153
|
+
const errorMessage = conflictCheck.message || 'Database was updated externally. Please reload the schema and try again.';
|
|
1154
|
+
saveDraftLogger(`CONFLICT DETECTED: ${errorMessage}`);
|
|
1155
|
+
throw new ConflictError(errorMessage, conflictCheck);
|
|
1156
|
+
}
|
|
1157
|
+
// Get context - if service is stopped, build it from what we know
|
|
1158
|
+
let context;
|
|
1159
|
+
try {
|
|
1160
|
+
context = this._getSnapshotContext();
|
|
1161
|
+
}
|
|
1162
|
+
catch {
|
|
1163
|
+
logger(`Service stopped, building context from available data`);
|
|
1164
|
+
context = {
|
|
1165
|
+
schemaName: newName || oldName || '',
|
|
1166
|
+
metadata: {
|
|
1167
|
+
name: newName || oldName || '',
|
|
1168
|
+
createdAt: new Date().toISOString(),
|
|
1169
|
+
updatedAt: new Date().toISOString(),
|
|
1170
|
+
},
|
|
1171
|
+
version: 1,
|
|
1172
|
+
_isDraft: true,
|
|
1173
|
+
_editedProperties: new Set(),
|
|
1174
|
+
};
|
|
1175
|
+
}
|
|
1176
|
+
const db = BaseDb.getAppDb();
|
|
1177
|
+
if (!db) {
|
|
1178
|
+
throw new Error('Database not found');
|
|
1179
|
+
}
|
|
1180
|
+
const finalNewName = newName || context.schemaName || this.schemaName;
|
|
1181
|
+
const isRename = !!oldName && oldName !== finalNewName;
|
|
1182
|
+
// The row: by schemaFileId, else by name (the old name for a rename, preferring a draft).
|
|
1183
|
+
let existingSchemaRecord;
|
|
1184
|
+
if (context.id) {
|
|
1185
|
+
[existingSchemaRecord] = await db
|
|
1186
|
+
.select()
|
|
1187
|
+
.from(schemas)
|
|
1188
|
+
.where(eq(schemas.schemaFileId, context.id))
|
|
1189
|
+
.limit(1);
|
|
1190
|
+
}
|
|
1191
|
+
if (!existingSchemaRecord) {
|
|
1192
|
+
const byName = await db
|
|
1193
|
+
.select()
|
|
1194
|
+
.from(schemas)
|
|
1195
|
+
.where(eq(schemas.name, isRename ? oldName : finalNewName))
|
|
1196
|
+
.limit(10);
|
|
1197
|
+
existingSchemaRecord =
|
|
1198
|
+
(isRename ? byName.find((row) => row.isDraft === true) : undefined) ?? byName[0];
|
|
1199
|
+
}
|
|
1200
|
+
// A published schema's rename is its next version file, under the new name (ADR 0016).
|
|
1201
|
+
// A row-only rename was undone at the next init, which matched the files by their old name.
|
|
1202
|
+
if (isRename && existingSchemaRecord?.schemaFileId && existingSchemaRecord.isDraft !== true) {
|
|
1203
|
+
const { schemaFile } = await writeNextSchemaVersion(existingSchemaRecord.schemaFileId, (previous) => ({ ...previous, metadata: { ...previous.metadata, name: finalNewName } }), {
|
|
1204
|
+
description: `Renamed schema ${oldName} to ${finalNewName}`,
|
|
1205
|
+
changes: [{ type: 'schema_rename', oldName: oldName, newName: finalNewName }],
|
|
1206
|
+
});
|
|
1207
|
+
const savedAt = new Date(schemaFile.metadata.updatedAt).getTime();
|
|
1208
|
+
this._service.send({
|
|
1209
|
+
type: 'updateContext',
|
|
1210
|
+
id: schemaFile.id,
|
|
1211
|
+
version: schemaFile.version,
|
|
1212
|
+
_dbUpdatedAt: savedAt,
|
|
1213
|
+
_dbVersion: schemaFile.version,
|
|
1214
|
+
});
|
|
1215
|
+
const otherEdits = [...(context._editedProperties ?? [])].some((key) => key !== 'schema:name');
|
|
1216
|
+
if (!otherEdits) {
|
|
1217
|
+
saveDraftLogger(`Renamed schema "${oldName}" to "${finalNewName}" in v${schemaFile.version}`);
|
|
1218
|
+
return;
|
|
1219
|
+
}
|
|
1220
|
+
// Other edits stay a draft of the new version
|
|
1221
|
+
context = this._getSnapshotContext();
|
|
1222
|
+
[existingSchemaRecord] = await db
|
|
1223
|
+
.select()
|
|
1224
|
+
.from(schemas)
|
|
1225
|
+
.where(eq(schemas.schemaFileId, existingSchemaRecord.schemaFileId))
|
|
1226
|
+
.limit(1);
|
|
1227
|
+
}
|
|
1228
|
+
if (isRename && !existingSchemaRecord) {
|
|
1229
|
+
throw new Error(`Cannot update schema name: existing schema with name "${oldName}" not found in database`);
|
|
1230
|
+
}
|
|
1231
|
+
// The database's schemaFileId is the schema's id
|
|
1232
|
+
const finalSchemaFileId = existingSchemaRecord?.schemaFileId || context.id || generateId();
|
|
1233
|
+
const currentMetadata = context.metadata
|
|
1234
|
+
? { ...context.metadata, name: finalNewName, updatedAt: new Date().toISOString() }
|
|
1235
|
+
: { name: finalNewName, createdAt: new Date().toISOString(), updatedAt: new Date().toISOString() };
|
|
1236
|
+
// Model instances are the source of truth for model data
|
|
1237
|
+
const modelsFromInstances = await this._buildModelsFromInstances();
|
|
1238
|
+
const currentSchema = {
|
|
1239
|
+
$schema: context.$schema || 'https://seedprotocol.org/schemas/data-model/v1',
|
|
1240
|
+
version: context.version || 1,
|
|
1241
|
+
id: finalSchemaFileId,
|
|
1242
|
+
metadata: currentMetadata,
|
|
1243
|
+
models: modelsFromInstances,
|
|
1244
|
+
enums: context.enums || {},
|
|
1245
|
+
migrations: context.migrations || [],
|
|
1246
|
+
...(context.nameMatch !== undefined && { nameMatch: context.nameMatch }),
|
|
1247
|
+
};
|
|
1248
|
+
// A rename writes the row it found under the old name; other saves find the row by id or name.
|
|
1249
|
+
const { inserted } = await inDefinitionsTransaction((tx) => upsertSchemaRow(tx, {
|
|
1250
|
+
name: finalNewName,
|
|
1251
|
+
version: currentSchema.version,
|
|
1252
|
+
createdAt: new Date(currentSchema.metadata.createdAt).getTime(),
|
|
1253
|
+
updatedAt: new Date(currentSchema.metadata.updatedAt).getTime(),
|
|
1254
|
+
schemaFileId: finalSchemaFileId,
|
|
1255
|
+
schemaData: JSON.stringify(currentSchema, null, 2),
|
|
1256
|
+
isDraft: true,
|
|
1257
|
+
}, isRename ? { rowId: existingSchemaRecord.id } : {}));
|
|
1258
|
+
if (inserted)
|
|
1259
|
+
broadcastSchemasInvalidate();
|
|
1260
|
+
try {
|
|
1261
|
+
if (this._service.getSnapshot().status !== 'stopped') {
|
|
1262
|
+
this._service.send({
|
|
1263
|
+
type: 'updateContext',
|
|
1264
|
+
...(isRename && { id: finalSchemaFileId }),
|
|
1265
|
+
_dbUpdatedAt: new Date(currentSchema.metadata.updatedAt).getTime(),
|
|
1266
|
+
_dbVersion: currentSchema.version,
|
|
1267
|
+
});
|
|
1268
|
+
}
|
|
1269
|
+
}
|
|
1270
|
+
catch {
|
|
1271
|
+
// Service might be stopped, ignore
|
|
1272
|
+
}
|
|
1273
|
+
saveDraftLogger(`Saved draft schema "${finalNewName}" (key: ${saveKey})`);
|
|
1274
|
+
});
|
|
1275
|
+
}
|
|
1276
|
+
/**
|
|
1277
|
+
* Force-evict the cached Schema instance(s) named `schemaName`, ignoring refCounts: stop their live
|
|
1278
|
+
* query and service. Schema.destroy does the same for itself. For code that deletes a schema's rows
|
|
1279
|
+
* without destroying it (test cleanup): a live Schema keeps re-creating its models from its live
|
|
1280
|
+
* query while their rows are being deleted.
|
|
1281
|
+
*/
|
|
1282
|
+
static evict(schemaName) {
|
|
1283
|
+
evictEntities(this.cache, (schema) => schema._getSnapshotContext().schemaName === schemaName);
|
|
1284
|
+
}
|
|
1285
|
+
/**
|
|
1286
|
+
* Release this caller's hold. With the last one the schema is stopped, leaves the cache, and
|
|
1287
|
+
* releases its hold on each of its models.
|
|
1288
|
+
*/
|
|
1289
|
+
unload() {
|
|
1290
|
+
releaseEntity(this, Schema.cache);
|
|
1291
|
+
}
|
|
1292
|
+
/**
|
|
1293
|
+
* Destroy the schema: delete its rows (schema, models, properties, links) and its files, and stop
|
|
1294
|
+
* it and its cached models and properties, whoever holds them.
|
|
1295
|
+
*/
|
|
1296
|
+
async destroy() {
|
|
1297
|
+
const context = this._getSnapshotContext();
|
|
1298
|
+
const schemaFileId = context.id;
|
|
1299
|
+
const schemaName = context.schemaName;
|
|
1300
|
+
// Lookups stop finding it now, not once its models are evicted and their writes drained
|
|
1301
|
+
Schema.cache.remove(this);
|
|
1302
|
+
// Until its rows are gone, nothing may re-create this schema's models. Its own actor stays live
|
|
1303
|
+
// till then, and its live query reacting to destroyStarted could read a model row the drained
|
|
1304
|
+
// write had just landed and re-create (and re-write) that model after the delete below.
|
|
1305
|
+
const finishEviction = evictionLog.evict(schemaName ? [`schema:${schemaName}`] : []);
|
|
1306
|
+
try {
|
|
1307
|
+
await this._destroyRows(schemaFileId, schemaName, context.metadata?.name);
|
|
1308
|
+
}
|
|
1309
|
+
finally {
|
|
1310
|
+
finishEviction();
|
|
1311
|
+
}
|
|
1312
|
+
}
|
|
1313
|
+
async _destroyRows(schemaFileId, schemaName, metadataName) {
|
|
1314
|
+
// The rows for this schema's models and properties are deleted below; evict their cached
|
|
1315
|
+
// instances too, or a re-import would get them back with dangling _dbIds.
|
|
1316
|
+
if (schemaName) {
|
|
1317
|
+
const evictedModelNames = Model.evictForSchema(schemaName);
|
|
1318
|
+
const { ModelProperty } = await import('./ModelProperty-BlaEgb_U.js');
|
|
1319
|
+
ModelProperty.evictForModels(evictedModelNames, schemaName);
|
|
1320
|
+
// Evicting stops new writes but not ones already running; let those land before deleting their rows
|
|
1321
|
+
const _mod_4 = await import('./errors-DLSoqSHG.js');
|
|
1322
|
+
const _ns_4 = _mod_4.a3;
|
|
1323
|
+
const { waitForInFlightWrites } = _ns_4;
|
|
1324
|
+
await waitForInFlightWrites();
|
|
1325
|
+
}
|
|
1326
|
+
await destroyEntity(this, Schema.cache, async () => {
|
|
1327
|
+
const db = BaseDb.getAppDb();
|
|
1328
|
+
if (!db || !schemaFileId)
|
|
1329
|
+
return;
|
|
1330
|
+
const { detachModelRows } = await import('./detachRowsBeforeDelete-sEaUwlOU.js');
|
|
1331
|
+
// The schema's rows go together or not at all
|
|
1332
|
+
const deleted = await inDefinitionsTransaction(async (tx) => {
|
|
1333
|
+
const schemaRecords = await tx
|
|
1334
|
+
.select({ id: schemas.id })
|
|
1335
|
+
.from(schemas)
|
|
1336
|
+
.where(eq(schemas.schemaFileId, schemaFileId));
|
|
1337
|
+
if (schemaRecords.length === 0)
|
|
1338
|
+
return false;
|
|
1339
|
+
const schemaIds = schemaRecords
|
|
1340
|
+
.map((r) => r.id)
|
|
1341
|
+
.filter((id) => id != null);
|
|
1342
|
+
if (schemaIds.length === 0)
|
|
1343
|
+
return false;
|
|
1344
|
+
const joinRows = await tx
|
|
1345
|
+
.select({ modelId: modelSchemas.modelId })
|
|
1346
|
+
.from(modelSchemas)
|
|
1347
|
+
.where(inArray(modelSchemas.schemaId, schemaIds));
|
|
1348
|
+
const modelIds = [
|
|
1349
|
+
...new Set(joinRows
|
|
1350
|
+
.map((r) => r.modelId)
|
|
1351
|
+
.filter((id) => id != null)),
|
|
1352
|
+
];
|
|
1353
|
+
await detachModelRows(tx, modelIds);
|
|
1354
|
+
await tx.delete(modelSchemas).where(inArray(modelSchemas.schemaId, schemaIds));
|
|
1355
|
+
for (const modelId of modelIds) {
|
|
1356
|
+
await tx.delete(properties).where(eq(properties.modelId, modelId));
|
|
1357
|
+
}
|
|
1358
|
+
for (const modelId of modelIds) {
|
|
1359
|
+
await tx.delete(models).where(eq(models.id, modelId));
|
|
1360
|
+
}
|
|
1361
|
+
await tx.delete(schemas).where(eq(schemas.schemaFileId, schemaFileId));
|
|
1362
|
+
return true;
|
|
1363
|
+
});
|
|
1364
|
+
if (!deleted)
|
|
1365
|
+
return;
|
|
1366
|
+
// Delete the SDK's own copies of this schema's files (all versions) in the working dir.
|
|
1367
|
+
// loadAllSchemasFromDb imports any schema file without a DB row, so leaving them brought
|
|
1368
|
+
// the destroyed schema back on the next Schema.all().
|
|
1369
|
+
// Match on name as well as id: versions imported from complete schema files can each
|
|
1370
|
+
// have their own id, and any version left behind would bring the schema back.
|
|
1371
|
+
const _mod_5 = await import('./errors-DLSoqSHG.js');
|
|
1372
|
+
const _ns_5 = _mod_5.a5;
|
|
1373
|
+
const { listCompleteSchemaFiles } = _ns_5;
|
|
1374
|
+
const files = await listCompleteSchemaFiles().catch(() => []);
|
|
1375
|
+
const fs = await BaseFileManager.getFs();
|
|
1376
|
+
const names = new Set([schemaName, metadataName].filter(Boolean));
|
|
1377
|
+
for (const file of files) {
|
|
1378
|
+
if (file.schemaFileId === schemaFileId || names.has(file.name)) {
|
|
1379
|
+
await fs.promises.unlink(file.filePath).catch(() => { });
|
|
1380
|
+
}
|
|
1381
|
+
}
|
|
1382
|
+
});
|
|
1383
|
+
}
|
|
1384
|
+
/**
|
|
1385
|
+
* Set up liveQuery subscription to watch for model changes in the database
|
|
1386
|
+
* This enables cross-instance synchronization (e.g., changes in other tabs/windows)
|
|
1387
|
+
*/
|
|
1388
|
+
_setupLiveQuerySubscription() {
|
|
1389
|
+
// Only set up in browser environment where liveQuery is available
|
|
1390
|
+
if (typeof window === 'undefined') {
|
|
1391
|
+
return;
|
|
1392
|
+
}
|
|
1393
|
+
setupEntityLiveQuery(this, {
|
|
1394
|
+
// Its row, once loaded
|
|
1395
|
+
getEntityId: async (schema) => entityStatus(schema) === 'ready' ? schema._getSnapshotContext()._dbId : undefined,
|
|
1396
|
+
buildQuery: async (schemaId) => {
|
|
1397
|
+
const db = BaseDb.getAppDb();
|
|
1398
|
+
if (!db) {
|
|
1399
|
+
throw new Error('Database not available');
|
|
1400
|
+
}
|
|
1401
|
+
return BaseDb.liveQuery(db
|
|
1402
|
+
.select({
|
|
1403
|
+
modelId: modelSchemas.modelId,
|
|
1404
|
+
modelName: models.name,
|
|
1405
|
+
modelFileId: models.schemaFileId,
|
|
1406
|
+
})
|
|
1407
|
+
.from(modelSchemas)
|
|
1408
|
+
.innerJoin(models, eq(modelSchemas.modelId, models.id))
|
|
1409
|
+
.where(eq(modelSchemas.schemaId, typeof schemaId === 'string' ? parseInt(schemaId, 10) : schemaId)));
|
|
1410
|
+
},
|
|
1411
|
+
extractEntityIds: (rows) => rows.map(row => row.modelFileId).filter(Boolean),
|
|
1412
|
+
updateContext: (schema, ids) => {
|
|
1413
|
+
schema._service.send({ type: 'updateContext', _liveQueryModelIds: ids, _modelsUpdated: Date.now() });
|
|
1414
|
+
},
|
|
1415
|
+
createChildInstances: async (ids) => {
|
|
1416
|
+
// One at a time: an eviction of this schema part way through stops the rest
|
|
1417
|
+
const since = evictionLog.now();
|
|
1418
|
+
for (const id of ids) {
|
|
1419
|
+
await Model.createById(id, { since, hold: false });
|
|
1420
|
+
}
|
|
1421
|
+
},
|
|
1422
|
+
queryInitialData: async (schemaId) => {
|
|
1423
|
+
const db = BaseDb.getAppDb();
|
|
1424
|
+
if (!db) {
|
|
1425
|
+
return [];
|
|
1426
|
+
}
|
|
1427
|
+
// The schema is idle, so its load (and any import it waited for) wrote these rows already
|
|
1428
|
+
const initialModels = await db
|
|
1429
|
+
.select({
|
|
1430
|
+
modelId: modelSchemas.modelId,
|
|
1431
|
+
modelName: models.name,
|
|
1432
|
+
modelFileId: models.schemaFileId,
|
|
1433
|
+
})
|
|
1434
|
+
.from(modelSchemas)
|
|
1435
|
+
.innerJoin(models, eq(modelSchemas.modelId, models.id))
|
|
1436
|
+
.where(eq(modelSchemas.schemaId, typeof schemaId === 'string' ? parseInt(schemaId, 10) : schemaId));
|
|
1437
|
+
return initialModels.map((row) => ({
|
|
1438
|
+
modelId: row.modelId,
|
|
1439
|
+
modelName: row.modelName,
|
|
1440
|
+
modelFileId: row.modelFileId || '',
|
|
1441
|
+
}));
|
|
1442
|
+
},
|
|
1443
|
+
loggerName: 'seedSdk:schema:liveQuery',
|
|
1444
|
+
});
|
|
1445
|
+
}
|
|
1446
|
+
}
|
|
1447
|
+
/** Cached under its file id and its name (ADR 0014). */
|
|
1448
|
+
Schema.cache = new EntityCache();
|
|
1449
|
+
|
|
1450
|
+
var Schema$1 = /*#__PURE__*/Object.freeze({
|
|
1451
|
+
__proto__: null,
|
|
1452
|
+
Schema: Schema
|
|
1453
|
+
});
|
|
1454
|
+
|
|
1455
|
+
export { Schema as S, Schema$1 as a, schemaMachine as s };
|
|
1456
|
+
//# sourceMappingURL=Schema-J_1f6p0c.js.map
|