@jini-ai/cms 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +84 -0
- package/dist/content-types/agent-tools.d.ts +65 -0
- package/dist/content-types/agent-tools.d.ts.map +1 -0
- package/dist/content-types/agent-tools.js +172 -0
- package/dist/content-types/agent-tools.js.map +1 -0
- package/dist/content-types/cleanup.d.ts +118 -0
- package/dist/content-types/cleanup.d.ts.map +1 -0
- package/dist/content-types/cleanup.js +65 -0
- package/dist/content-types/cleanup.js.map +1 -0
- package/dist/content-types/errors.d.ts +90 -0
- package/dist/content-types/errors.d.ts.map +1 -0
- package/dist/content-types/errors.js +119 -0
- package/dist/content-types/errors.js.map +1 -0
- package/dist/content-types/field-defs.d.ts +25 -0
- package/dist/content-types/field-defs.d.ts.map +1 -0
- package/dist/content-types/field-defs.js +155 -0
- package/dist/content-types/field-defs.js.map +1 -0
- package/dist/content-types/index-provisioning.d.ts +94 -0
- package/dist/content-types/index-provisioning.d.ts.map +1 -0
- package/dist/content-types/index-provisioning.js +133 -0
- package/dist/content-types/index-provisioning.js.map +1 -0
- package/dist/content-types/index.d.ts +63 -0
- package/dist/content-types/index.d.ts.map +1 -0
- package/dist/content-types/index.js +36 -0
- package/dist/content-types/index.js.map +1 -0
- package/dist/content-types/lifecycle-dispatch.d.ts +38 -0
- package/dist/content-types/lifecycle-dispatch.d.ts.map +1 -0
- package/dist/content-types/lifecycle-dispatch.js +28 -0
- package/dist/content-types/lifecycle-dispatch.js.map +1 -0
- package/dist/content-types/lifecycle.d.ts +104 -0
- package/dist/content-types/lifecycle.d.ts.map +1 -0
- package/dist/content-types/lifecycle.js +143 -0
- package/dist/content-types/lifecycle.js.map +1 -0
- package/dist/content-types/list.d.ts +44 -0
- package/dist/content-types/list.d.ts.map +1 -0
- package/dist/content-types/list.js +13 -0
- package/dist/content-types/list.js.map +1 -0
- package/dist/content-types/repo.memory.d.ts +72 -0
- package/dist/content-types/repo.memory.d.ts.map +1 -0
- package/dist/content-types/repo.memory.js +71 -0
- package/dist/content-types/repo.memory.js.map +1 -0
- package/dist/content-types/tool-registrations.d.ts +65 -0
- package/dist/content-types/tool-registrations.d.ts.map +1 -0
- package/dist/content-types/tool-registrations.js +180 -0
- package/dist/content-types/tool-registrations.js.map +1 -0
- package/dist/content-types/types.d.ts +78 -0
- package/dist/content-types/types.d.ts.map +1 -0
- package/dist/content-types/types.js +32 -0
- package/dist/content-types/types.js.map +1 -0
- package/dist/content-types/write-service.d.ts +141 -0
- package/dist/content-types/write-service.d.ts.map +1 -0
- package/dist/content-types/write-service.js +180 -0
- package/dist/content-types/write-service.js.map +1 -0
- package/dist/core/commands/change-set.d.ts +98 -0
- package/dist/core/commands/change-set.d.ts.map +1 -0
- package/dist/core/commands/change-set.js +2 -0
- package/dist/core/commands/change-set.js.map +1 -0
- package/dist/core/commands/command.d.ts +168 -0
- package/dist/core/commands/command.d.ts.map +1 -0
- package/dist/core/commands/command.js +173 -0
- package/dist/core/commands/command.js.map +1 -0
- package/dist/core/index.d.ts +45 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +43 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/ports.d.ts +139 -0
- package/dist/core/ports.d.ts.map +1 -0
- package/dist/core/ports.js +2 -0
- package/dist/core/ports.js.map +1 -0
- package/dist/core/tools/registration-kit.d.ts +308 -0
- package/dist/core/tools/registration-kit.d.ts.map +1 -0
- package/dist/core/tools/registration-kit.js +381 -0
- package/dist/core/tools/registration-kit.js.map +1 -0
- package/dist/entries/agent-tools.d.ts +78 -0
- package/dist/entries/agent-tools.d.ts.map +1 -0
- package/dist/entries/agent-tools.js +158 -0
- package/dist/entries/agent-tools.js.map +1 -0
- package/dist/entries/errors.d.ts +43 -0
- package/dist/entries/errors.d.ts.map +1 -0
- package/dist/entries/errors.js +59 -0
- package/dist/entries/errors.js.map +1 -0
- package/dist/entries/field-validation.d.ts +70 -0
- package/dist/entries/field-validation.d.ts.map +1 -0
- package/dist/entries/field-validation.js +87 -0
- package/dist/entries/field-validation.js.map +1 -0
- package/dist/entries/index.d.ts +55 -0
- package/dist/entries/index.d.ts.map +1 -0
- package/dist/entries/index.js +38 -0
- package/dist/entries/index.js.map +1 -0
- package/dist/entries/lifecycle-dispatch.d.ts +15 -0
- package/dist/entries/lifecycle-dispatch.d.ts.map +1 -0
- package/dist/entries/lifecycle-dispatch.js +16 -0
- package/dist/entries/lifecycle-dispatch.js.map +1 -0
- package/dist/entries/list.d.ts +47 -0
- package/dist/entries/list.d.ts.map +1 -0
- package/dist/entries/list.js +12 -0
- package/dist/entries/list.js.map +1 -0
- package/dist/entries/repo.memory.d.ts +64 -0
- package/dist/entries/repo.memory.d.ts.map +1 -0
- package/dist/entries/repo.memory.js +73 -0
- package/dist/entries/repo.memory.js.map +1 -0
- package/dist/entries/tool-registrations.d.ts +52 -0
- package/dist/entries/tool-registrations.d.ts.map +1 -0
- package/dist/entries/tool-registrations.js +141 -0
- package/dist/entries/tool-registrations.js.map +1 -0
- package/dist/entries/types.d.ts +55 -0
- package/dist/entries/types.d.ts.map +1 -0
- package/dist/entries/types.js +2 -0
- package/dist/entries/types.js.map +1 -0
- package/dist/entries/write-service.d.ts +202 -0
- package/dist/entries/write-service.d.ts.map +1 -0
- package/dist/entries/write-service.js +204 -0
- package/dist/entries/write-service.js.map +1 -0
- package/dist/identity/admin-crud-service.d.ts +252 -0
- package/dist/identity/admin-crud-service.d.ts.map +1 -0
- package/dist/identity/admin-crud-service.js +437 -0
- package/dist/identity/admin-crud-service.js.map +1 -0
- package/dist/identity/agent-tool-input.d.ts +58 -0
- package/dist/identity/agent-tool-input.d.ts.map +1 -0
- package/dist/identity/agent-tool-input.js +126 -0
- package/dist/identity/agent-tool-input.js.map +1 -0
- package/dist/identity/agent-tools.d.ts +101 -0
- package/dist/identity/agent-tools.d.ts.map +1 -0
- package/dist/identity/agent-tools.js +290 -0
- package/dist/identity/agent-tools.js.map +1 -0
- package/dist/identity/auth-service.d.ts +87 -0
- package/dist/identity/auth-service.d.ts.map +1 -0
- package/dist/identity/auth-service.js +141 -0
- package/dist/identity/auth-service.js.map +1 -0
- package/dist/identity/authorize.d.ts +90 -0
- package/dist/identity/authorize.d.ts.map +1 -0
- package/dist/identity/authorize.js +94 -0
- package/dist/identity/authorize.js.map +1 -0
- package/dist/identity/grant-service.d.ts +198 -0
- package/dist/identity/grant-service.d.ts.map +1 -0
- package/dist/identity/grant-service.js +361 -0
- package/dist/identity/grant-service.js.map +1 -0
- package/dist/identity/hasher.d.ts +39 -0
- package/dist/identity/hasher.d.ts.map +1 -0
- package/dist/identity/hasher.js +39 -0
- package/dist/identity/hasher.js.map +1 -0
- package/dist/identity/index.d.ts +59 -0
- package/dist/identity/index.d.ts.map +1 -0
- package/dist/identity/index.js +51 -0
- package/dist/identity/index.js.map +1 -0
- package/dist/identity/password-policy.d.ts +58 -0
- package/dist/identity/password-policy.d.ts.map +1 -0
- package/dist/identity/password-policy.js +67 -0
- package/dist/identity/password-policy.js.map +1 -0
- package/dist/identity/permission-migrations.d.ts +86 -0
- package/dist/identity/permission-migrations.d.ts.map +1 -0
- package/dist/identity/permission-migrations.js +67 -0
- package/dist/identity/permission-migrations.js.map +1 -0
- package/dist/identity/permissions.d.ts +35 -0
- package/dist/identity/permissions.d.ts.map +1 -0
- package/dist/identity/permissions.js +603 -0
- package/dist/identity/permissions.js.map +1 -0
- package/dist/identity/ports.d.ts +201 -0
- package/dist/identity/ports.d.ts.map +1 -0
- package/dist/identity/ports.js +2 -0
- package/dist/identity/ports.js.map +1 -0
- package/dist/identity/repo.memory.d.ts +164 -0
- package/dist/identity/repo.memory.d.ts.map +1 -0
- package/dist/identity/repo.memory.js +224 -0
- package/dist/identity/repo.memory.js.map +1 -0
- package/dist/identity/seed.d.ts +42 -0
- package/dist/identity/seed.d.ts.map +1 -0
- package/dist/identity/seed.js +277 -0
- package/dist/identity/seed.js.map +1 -0
- package/dist/identity/tool-registrations.d.ts +50 -0
- package/dist/identity/tool-registrations.d.ts.map +1 -0
- package/dist/identity/tool-registrations.js +419 -0
- package/dist/identity/tool-registrations.js.map +1 -0
- package/dist/identity/types.d.ts +185 -0
- package/dist/identity/types.d.ts.map +1 -0
- package/dist/identity/types.js +64 -0
- package/dist/identity/types.js.map +1 -0
- package/dist/identity/username.d.ts +12 -0
- package/dist/identity/username.d.ts.map +1 -0
- package/dist/identity/username.js +14 -0
- package/dist/identity/username.js.map +1 -0
- package/dist/media/agent-tools.d.ts +66 -0
- package/dist/media/agent-tools.d.ts.map +1 -0
- package/dist/media/agent-tools.js +131 -0
- package/dist/media/agent-tools.js.map +1 -0
- package/dist/media/blob-gc-lock.d.ts +37 -0
- package/dist/media/blob-gc-lock.d.ts.map +1 -0
- package/dist/media/blob-gc-lock.js +55 -0
- package/dist/media/blob-gc-lock.js.map +1 -0
- package/dist/media/blob-gc.d.ts +246 -0
- package/dist/media/blob-gc.d.ts.map +1 -0
- package/dist/media/blob-gc.js +254 -0
- package/dist/media/blob-gc.js.map +1 -0
- package/dist/media/blob-key.d.ts +28 -0
- package/dist/media/blob-key.d.ts.map +1 -0
- package/dist/media/blob-key.js +11 -0
- package/dist/media/blob-key.js.map +1 -0
- package/dist/media/blob-store.fs.d.ts +23 -0
- package/dist/media/blob-store.fs.d.ts.map +1 -0
- package/dist/media/blob-store.fs.js +48 -0
- package/dist/media/blob-store.fs.js.map +1 -0
- package/dist/media/blob-store.memory.d.ts +22 -0
- package/dist/media/blob-store.memory.d.ts.map +1 -0
- package/dist/media/blob-store.memory.js +23 -0
- package/dist/media/blob-store.memory.js.map +1 -0
- package/dist/media/content-type-sniffer.d.ts +49 -0
- package/dist/media/content-type-sniffer.d.ts.map +1 -0
- package/dist/media/content-type-sniffer.js +141 -0
- package/dist/media/content-type-sniffer.js.map +1 -0
- package/dist/media/image-transformer.d.ts +45 -0
- package/dist/media/image-transformer.d.ts.map +1 -0
- package/dist/media/image-transformer.js +23 -0
- package/dist/media/image-transformer.js.map +1 -0
- package/dist/media/image-transformer.sharp.d.ts +26 -0
- package/dist/media/image-transformer.sharp.d.ts.map +1 -0
- package/dist/media/image-transformer.sharp.js +91 -0
- package/dist/media/image-transformer.sharp.js.map +1 -0
- package/dist/media/index.d.ts +43 -0
- package/dist/media/index.d.ts.map +1 -0
- package/dist/media/index.js +31 -0
- package/dist/media/index.js.map +1 -0
- package/dist/media/media-service.d.ts +244 -0
- package/dist/media/media-service.d.ts.map +1 -0
- package/dist/media/media-service.js +345 -0
- package/dist/media/media-service.js.map +1 -0
- package/dist/media/ports.d.ts +142 -0
- package/dist/media/ports.d.ts.map +1 -0
- package/dist/media/ports.js +2 -0
- package/dist/media/ports.js.map +1 -0
- package/dist/media/rendition-service.d.ts +66 -0
- package/dist/media/rendition-service.d.ts.map +1 -0
- package/dist/media/rendition-service.js +135 -0
- package/dist/media/rendition-service.js.map +1 -0
- package/dist/media/repo.memory.d.ts +107 -0
- package/dist/media/repo.memory.d.ts.map +1 -0
- package/dist/media/repo.memory.js +131 -0
- package/dist/media/repo.memory.js.map +1 -0
- package/dist/media/tool-registrations.d.ts +42 -0
- package/dist/media/tool-registrations.d.ts.map +1 -0
- package/dist/media/tool-registrations.js +121 -0
- package/dist/media/tool-registrations.js.map +1 -0
- package/dist/media/transform-lock.d.ts +36 -0
- package/dist/media/transform-lock.d.ts.map +1 -0
- package/dist/media/transform-lock.js +50 -0
- package/dist/media/transform-lock.js.map +1 -0
- package/dist/media/transform-registry.d.ts +103 -0
- package/dist/media/transform-registry.d.ts.map +1 -0
- package/dist/media/transform-registry.js +87 -0
- package/dist/media/transform-registry.js.map +1 -0
- package/dist/media/transform-types.d.ts +82 -0
- package/dist/media/transform-types.d.ts.map +1 -0
- package/dist/media/transform-types.js +47 -0
- package/dist/media/transform-types.js.map +1 -0
- package/dist/media/types.d.ts +150 -0
- package/dist/media/types.d.ts.map +1 -0
- package/dist/media/types.js +26 -0
- package/dist/media/types.js.map +1 -0
- package/dist/navigation/agent-tools.d.ts +90 -0
- package/dist/navigation/agent-tools.d.ts.map +1 -0
- package/dist/navigation/agent-tools.js +225 -0
- package/dist/navigation/agent-tools.js.map +1 -0
- package/dist/navigation/contracts.d.ts +98 -0
- package/dist/navigation/contracts.d.ts.map +1 -0
- package/dist/navigation/contracts.js +70 -0
- package/dist/navigation/contracts.js.map +1 -0
- package/dist/navigation/index.d.ts +39 -0
- package/dist/navigation/index.d.ts.map +1 -0
- package/dist/navigation/index.js +30 -0
- package/dist/navigation/index.js.map +1 -0
- package/dist/navigation/menu-service.d.ts +256 -0
- package/dist/navigation/menu-service.d.ts.map +1 -0
- package/dist/navigation/menu-service.js +382 -0
- package/dist/navigation/menu-service.js.map +1 -0
- package/dist/navigation/ports.d.ts +147 -0
- package/dist/navigation/ports.d.ts.map +1 -0
- package/dist/navigation/ports.js +2 -0
- package/dist/navigation/ports.js.map +1 -0
- package/dist/navigation/read-model.d.ts +11 -0
- package/dist/navigation/read-model.d.ts.map +1 -0
- package/dist/navigation/read-model.js +27 -0
- package/dist/navigation/read-model.js.map +1 -0
- package/dist/navigation/reconcile.d.ts +57 -0
- package/dist/navigation/reconcile.d.ts.map +1 -0
- package/dist/navigation/reconcile.js +33 -0
- package/dist/navigation/reconcile.js.map +1 -0
- package/dist/navigation/repo.memory.d.ts +137 -0
- package/dist/navigation/repo.memory.d.ts.map +1 -0
- package/dist/navigation/repo.memory.js +95 -0
- package/dist/navigation/repo.memory.js.map +1 -0
- package/dist/navigation/resolver.d.ts +110 -0
- package/dist/navigation/resolver.d.ts.map +1 -0
- package/dist/navigation/resolver.js +131 -0
- package/dist/navigation/resolver.js.map +1 -0
- package/dist/navigation/tool-registrations.d.ts +43 -0
- package/dist/navigation/tool-registrations.d.ts.map +1 -0
- package/dist/navigation/tool-registrations.js +126 -0
- package/dist/navigation/tool-registrations.js.map +1 -0
- package/dist/navigation/types.d.ts +207 -0
- package/dist/navigation/types.d.ts.map +1 -0
- package/dist/navigation/types.js +14 -0
- package/dist/navigation/types.js.map +1 -0
- package/dist/presentation/index.d.ts +15 -0
- package/dist/presentation/index.d.ts.map +1 -0
- package/dist/presentation/index.js +15 -0
- package/dist/presentation/index.js.map +1 -0
- package/dist/presentation/presentation.d.ts +72 -0
- package/dist/presentation/presentation.d.ts.map +1 -0
- package/dist/presentation/presentation.js +51 -0
- package/dist/presentation/presentation.js.map +1 -0
- package/dist/presentation/repo.memory.d.ts +9 -0
- package/dist/presentation/repo.memory.d.ts.map +1 -0
- package/dist/presentation/repo.memory.js +21 -0
- package/dist/presentation/repo.memory.js.map +1 -0
- package/dist/server/index.d.ts +28 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +28 -0
- package/dist/server/index.js.map +1 -0
- package/dist/settings/agent-tools.d.ts +83 -0
- package/dist/settings/agent-tools.d.ts.map +1 -0
- package/dist/settings/agent-tools.js +200 -0
- package/dist/settings/agent-tools.js.map +1 -0
- package/dist/settings/agent-writable-preferences.d.ts +67 -0
- package/dist/settings/agent-writable-preferences.d.ts.map +1 -0
- package/dist/settings/agent-writable-preferences.js +144 -0
- package/dist/settings/agent-writable-preferences.js.map +1 -0
- package/dist/settings/change-feed.d.ts +74 -0
- package/dist/settings/change-feed.d.ts.map +1 -0
- package/dist/settings/change-feed.js +61 -0
- package/dist/settings/change-feed.js.map +1 -0
- package/dist/settings/definitions-dispatch.d.ts +51 -0
- package/dist/settings/definitions-dispatch.d.ts.map +1 -0
- package/dist/settings/definitions-dispatch.js +86 -0
- package/dist/settings/definitions-dispatch.js.map +1 -0
- package/dist/settings/dictionaries/index.d.ts +45 -0
- package/dist/settings/dictionaries/index.d.ts.map +1 -0
- package/dist/settings/dictionaries/index.js +69 -0
- package/dist/settings/dictionaries/index.js.map +1 -0
- package/dist/settings/dictionaries/settings-dialog.ar.d.ts +3 -0
- package/dist/settings/dictionaries/settings-dialog.ar.d.ts.map +1 -0
- package/dist/settings/dictionaries/settings-dialog.ar.js +28 -0
- package/dist/settings/dictionaries/settings-dialog.ar.js.map +1 -0
- package/dist/settings/dictionaries/settings-dialog.bn.d.ts +3 -0
- package/dist/settings/dictionaries/settings-dialog.bn.d.ts.map +1 -0
- package/dist/settings/dictionaries/settings-dialog.bn.js +28 -0
- package/dist/settings/dictionaries/settings-dialog.bn.js.map +1 -0
- package/dist/settings/dictionaries/settings-dialog.de.d.ts +3 -0
- package/dist/settings/dictionaries/settings-dialog.de.d.ts.map +1 -0
- package/dist/settings/dictionaries/settings-dialog.de.js +28 -0
- package/dist/settings/dictionaries/settings-dialog.de.js.map +1 -0
- package/dist/settings/dictionaries/settings-dialog.es.d.ts +3 -0
- package/dist/settings/dictionaries/settings-dialog.es.d.ts.map +1 -0
- package/dist/settings/dictionaries/settings-dialog.es.js +28 -0
- package/dist/settings/dictionaries/settings-dialog.es.js.map +1 -0
- package/dist/settings/dictionaries/settings-dialog.fa.d.ts +3 -0
- package/dist/settings/dictionaries/settings-dialog.fa.d.ts.map +1 -0
- package/dist/settings/dictionaries/settings-dialog.fa.js +28 -0
- package/dist/settings/dictionaries/settings-dialog.fa.js.map +1 -0
- package/dist/settings/dictionaries/settings-dialog.fr.d.ts +3 -0
- package/dist/settings/dictionaries/settings-dialog.fr.d.ts.map +1 -0
- package/dist/settings/dictionaries/settings-dialog.fr.js +28 -0
- package/dist/settings/dictionaries/settings-dialog.fr.js.map +1 -0
- package/dist/settings/dictionaries/settings-dialog.hi.d.ts +3 -0
- package/dist/settings/dictionaries/settings-dialog.hi.d.ts.map +1 -0
- package/dist/settings/dictionaries/settings-dialog.hi.js +28 -0
- package/dist/settings/dictionaries/settings-dialog.hi.js.map +1 -0
- package/dist/settings/dictionaries/settings-dialog.hu.d.ts +3 -0
- package/dist/settings/dictionaries/settings-dialog.hu.d.ts.map +1 -0
- package/dist/settings/dictionaries/settings-dialog.hu.js +28 -0
- package/dist/settings/dictionaries/settings-dialog.hu.js.map +1 -0
- package/dist/settings/dictionaries/settings-dialog.id.d.ts +3 -0
- package/dist/settings/dictionaries/settings-dialog.id.d.ts.map +1 -0
- package/dist/settings/dictionaries/settings-dialog.id.js +28 -0
- package/dist/settings/dictionaries/settings-dialog.id.js.map +1 -0
- package/dist/settings/dictionaries/settings-dialog.it.d.ts +3 -0
- package/dist/settings/dictionaries/settings-dialog.it.d.ts.map +1 -0
- package/dist/settings/dictionaries/settings-dialog.it.js +28 -0
- package/dist/settings/dictionaries/settings-dialog.it.js.map +1 -0
- package/dist/settings/dictionaries/settings-dialog.ja.d.ts +3 -0
- package/dist/settings/dictionaries/settings-dialog.ja.d.ts.map +1 -0
- package/dist/settings/dictionaries/settings-dialog.ja.js +28 -0
- package/dist/settings/dictionaries/settings-dialog.ja.js.map +1 -0
- package/dist/settings/dictionaries/settings-dialog.ko.d.ts +3 -0
- package/dist/settings/dictionaries/settings-dialog.ko.d.ts.map +1 -0
- package/dist/settings/dictionaries/settings-dialog.ko.js +28 -0
- package/dist/settings/dictionaries/settings-dialog.ko.js.map +1 -0
- package/dist/settings/dictionaries/settings-dialog.pl.d.ts +3 -0
- package/dist/settings/dictionaries/settings-dialog.pl.d.ts.map +1 -0
- package/dist/settings/dictionaries/settings-dialog.pl.js +28 -0
- package/dist/settings/dictionaries/settings-dialog.pl.js.map +1 -0
- package/dist/settings/dictionaries/settings-dialog.pt-BR.d.ts +3 -0
- package/dist/settings/dictionaries/settings-dialog.pt-BR.d.ts.map +1 -0
- package/dist/settings/dictionaries/settings-dialog.pt-BR.js +28 -0
- package/dist/settings/dictionaries/settings-dialog.pt-BR.js.map +1 -0
- package/dist/settings/dictionaries/settings-dialog.ru.d.ts +3 -0
- package/dist/settings/dictionaries/settings-dialog.ru.d.ts.map +1 -0
- package/dist/settings/dictionaries/settings-dialog.ru.js +28 -0
- package/dist/settings/dictionaries/settings-dialog.ru.js.map +1 -0
- package/dist/settings/dictionaries/settings-dialog.th.d.ts +3 -0
- package/dist/settings/dictionaries/settings-dialog.th.d.ts.map +1 -0
- package/dist/settings/dictionaries/settings-dialog.th.js +28 -0
- package/dist/settings/dictionaries/settings-dialog.th.js.map +1 -0
- package/dist/settings/dictionaries/settings-dialog.tr.d.ts +3 -0
- package/dist/settings/dictionaries/settings-dialog.tr.d.ts.map +1 -0
- package/dist/settings/dictionaries/settings-dialog.tr.js +28 -0
- package/dist/settings/dictionaries/settings-dialog.tr.js.map +1 -0
- package/dist/settings/dictionaries/settings-dialog.uk.d.ts +3 -0
- package/dist/settings/dictionaries/settings-dialog.uk.d.ts.map +1 -0
- package/dist/settings/dictionaries/settings-dialog.uk.js +28 -0
- package/dist/settings/dictionaries/settings-dialog.uk.js.map +1 -0
- package/dist/settings/dictionaries/settings-dialog.ur.d.ts +3 -0
- package/dist/settings/dictionaries/settings-dialog.ur.d.ts.map +1 -0
- package/dist/settings/dictionaries/settings-dialog.ur.js +28 -0
- package/dist/settings/dictionaries/settings-dialog.ur.js.map +1 -0
- package/dist/settings/dictionaries/settings-dialog.zh-CN.d.ts +3 -0
- package/dist/settings/dictionaries/settings-dialog.zh-CN.d.ts.map +1 -0
- package/dist/settings/dictionaries/settings-dialog.zh-CN.js +28 -0
- package/dist/settings/dictionaries/settings-dialog.zh-CN.js.map +1 -0
- package/dist/settings/dictionaries/settings-dialog.zh-TW.d.ts +3 -0
- package/dist/settings/dictionaries/settings-dialog.zh-TW.d.ts.map +1 -0
- package/dist/settings/dictionaries/settings-dialog.zh-TW.js +28 -0
- package/dist/settings/dictionaries/settings-dialog.zh-TW.js.map +1 -0
- package/dist/settings/ensure-definitions.d.ts +88 -0
- package/dist/settings/ensure-definitions.d.ts.map +1 -0
- package/dist/settings/ensure-definitions.js +91 -0
- package/dist/settings/ensure-definitions.js.map +1 -0
- package/dist/settings/errors.d.ts +36 -0
- package/dist/settings/errors.d.ts.map +1 -0
- package/dist/settings/errors.js +40 -0
- package/dist/settings/errors.js.map +1 -0
- package/dist/settings/index.d.ts +37 -0
- package/dist/settings/index.d.ts.map +1 -0
- package/dist/settings/index.js +36 -0
- package/dist/settings/index.js.map +1 -0
- package/dist/settings/ports.d.ts +117 -0
- package/dist/settings/ports.d.ts.map +1 -0
- package/dist/settings/ports.js +2 -0
- package/dist/settings/ports.js.map +1 -0
- package/dist/settings/purge-service.d.ts +53 -0
- package/dist/settings/purge-service.d.ts.map +1 -0
- package/dist/settings/purge-service.js +105 -0
- package/dist/settings/purge-service.js.map +1 -0
- package/dist/settings/repo.memory.d.ts +119 -0
- package/dist/settings/repo.memory.d.ts.map +1 -0
- package/dist/settings/repo.memory.js +199 -0
- package/dist/settings/repo.memory.js.map +1 -0
- package/dist/settings/settings.d.ts +124 -0
- package/dist/settings/settings.d.ts.map +1 -0
- package/dist/settings/settings.js +238 -0
- package/dist/settings/settings.js.map +1 -0
- package/dist/settings/tool-registrations.d.ts +56 -0
- package/dist/settings/tool-registrations.d.ts.map +1 -0
- package/dist/settings/tool-registrations.js +240 -0
- package/dist/settings/tool-registrations.js.map +1 -0
- package/dist/settings/types.d.ts +125 -0
- package/dist/settings/types.d.ts.map +1 -0
- package/dist/settings/types.js +3 -0
- package/dist/settings/types.js.map +1 -0
- package/dist/settings/ui-tab-definitions.d.ts +41 -0
- package/dist/settings/ui-tab-definitions.d.ts.map +1 -0
- package/dist/settings/ui-tab-definitions.js +148 -0
- package/dist/settings/ui-tab-definitions.js.map +1 -0
- package/dist/settings/write-service.d.ts +314 -0
- package/dist/settings/write-service.d.ts.map +1 -0
- package/dist/settings/write-service.js +677 -0
- package/dist/settings/write-service.js.map +1 -0
- package/dist/taxonomy/agent-tools.d.ts +76 -0
- package/dist/taxonomy/agent-tools.d.ts.map +1 -0
- package/dist/taxonomy/agent-tools.js +178 -0
- package/dist/taxonomy/agent-tools.js.map +1 -0
- package/dist/taxonomy/content-lookup.d.ts +45 -0
- package/dist/taxonomy/content-lookup.d.ts.map +1 -0
- package/dist/taxonomy/content-lookup.js +9 -0
- package/dist/taxonomy/content-lookup.js.map +1 -0
- package/dist/taxonomy/index.d.ts +38 -0
- package/dist/taxonomy/index.d.ts.map +1 -0
- package/dist/taxonomy/index.js +38 -0
- package/dist/taxonomy/index.js.map +1 -0
- package/dist/taxonomy/list.d.ts +39 -0
- package/dist/taxonomy/list.d.ts.map +1 -0
- package/dist/taxonomy/list.js +19 -0
- package/dist/taxonomy/list.js.map +1 -0
- package/dist/taxonomy/merge-term.d.ts +94 -0
- package/dist/taxonomy/merge-term.d.ts.map +1 -0
- package/dist/taxonomy/merge-term.js +65 -0
- package/dist/taxonomy/merge-term.js.map +1 -0
- package/dist/taxonomy/repo.memory.d.ts +160 -0
- package/dist/taxonomy/repo.memory.d.ts.map +1 -0
- package/dist/taxonomy/repo.memory.js +171 -0
- package/dist/taxonomy/repo.memory.js.map +1 -0
- package/dist/taxonomy/validation-chain.d.ts +114 -0
- package/dist/taxonomy/validation-chain.d.ts.map +1 -0
- package/dist/taxonomy/validation-chain.js +152 -0
- package/dist/taxonomy/validation-chain.js.map +1 -0
- package/dist/taxonomy/write-service.d.ts +387 -0
- package/dist/taxonomy/write-service.d.ts.map +1 -0
- package/dist/taxonomy/write-service.js +350 -0
- package/dist/taxonomy/write-service.js.map +1 -0
- package/dist/workspace/agent-tools.d.ts +67 -0
- package/dist/workspace/agent-tools.d.ts.map +1 -0
- package/dist/workspace/agent-tools.js +103 -0
- package/dist/workspace/agent-tools.js.map +1 -0
- package/dist/workspace/create.d.ts +116 -0
- package/dist/workspace/create.d.ts.map +1 -0
- package/dist/workspace/create.js +69 -0
- package/dist/workspace/create.js.map +1 -0
- package/dist/workspace/delete.d.ts +50 -0
- package/dist/workspace/delete.d.ts.map +1 -0
- package/dist/workspace/delete.js +24 -0
- package/dist/workspace/delete.js.map +1 -0
- package/dist/workspace/index.d.ts +27 -0
- package/dist/workspace/index.d.ts.map +1 -0
- package/dist/workspace/index.js +27 -0
- package/dist/workspace/index.js.map +1 -0
- package/dist/workspace/repo.memory.d.ts +34 -0
- package/dist/workspace/repo.memory.d.ts.map +1 -0
- package/dist/workspace/repo.memory.js +50 -0
- package/dist/workspace/repo.memory.js.map +1 -0
- package/dist/workspace/tool-registrations.d.ts +38 -0
- package/dist/workspace/tool-registrations.d.ts.map +1 -0
- package/dist/workspace/tool-registrations.js +71 -0
- package/dist/workspace/tool-registrations.js.map +1 -0
- package/dist/workspace/update.d.ts +52 -0
- package/dist/workspace/update.d.ts.map +1 -0
- package/dist/workspace/update.js +41 -0
- package/dist/workspace/update.js.map +1 -0
- package/package.json +149 -0
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Blob-GC protocol ("References, deletion, and GC
|
|
3
|
+
* (never-brick)", INV-1) — the audited tombstone -> delete-pass -> unlink-pass
|
|
4
|
+
* design, scoped to what an in-memory-repo build can actually run today.
|
|
5
|
+
*
|
|
6
|
+
* Built in this pass:
|
|
7
|
+
* - The real "unreferenced" predicate's sha256-uniqueness-across-non-purged-
|
|
8
|
+
* media-entries conjunct ({@link isBlobUnreferenced}), backed by the actual
|
|
9
|
+
* `mediaRepo` data `purgeMedia` already has.
|
|
10
|
+
* - Ordering (INV-1a): {@link runBlobGcDeletePass} deletes the `asset_blobs`
|
|
11
|
+
* row and writes the `blob_gc_journal` entry together, before any bytes are
|
|
12
|
+
* touched; {@link runBlobGcUnlinkPass} only ever unlinks bytes for a row
|
|
13
|
+
* whose deletion has already happened. `uploadMedia` (see
|
|
14
|
+
* `media-service.ts`) already writes bytes before the row.
|
|
15
|
+
* - Serialization: every transition below runs inside {@link withSha256Lock}
|
|
16
|
+
* (`blob-gc-lock.ts`) — this build's substitute for `BEGIN IMMEDIATE`
|
|
17
|
+
* against an in-memory table (see that file's header for why).
|
|
18
|
+
* - The two-phase, journaled shape: {@link tombstoneBlobIfUnreferenced} ->
|
|
19
|
+
* {@link runBlobGcDeletePass} (re-checks the predicate + `gc_grace`,
|
|
20
|
+
* journals, deletes the row) -> {@link runBlobGcUnlinkPass} (drains the
|
|
21
|
+
* journal, removes bytes). {@link runBlobGcCycle} is a convenience batch
|
|
22
|
+
* wrapper around the last two for tests/manual operation; nothing calls it
|
|
23
|
+
* on a schedule.
|
|
24
|
+
* - `gc_grace = max(30d default, retained-snapshot age)`, with the snapshot
|
|
25
|
+
* input wired as a stub (see below) so a real value slots in later without
|
|
26
|
+
* reworking callers.
|
|
27
|
+
*
|
|
28
|
+
* Deliberately NOT built (disclosed, matches this task's explicit scope):
|
|
29
|
+
* - **`entry_refs` where-used index** ({@link hasLiveEntryRefs}) — belongs to
|
|
30
|
+
* the generic entries model, which is accepted design only, not
|
|
31
|
+
* running code yet (see `types.ts`'s file header on `MediaRecord` being a
|
|
32
|
+
* bespoke table for the same reason). Stubbed to always return `false`
|
|
33
|
+
* ("no live refs found").
|
|
34
|
+
* - **Retained-snapshot conjunct** ({@link getOldestRetainedSnapshotAgeMs}) —
|
|
35
|
+
* owned by a pending Storage/Backups snapshot primitive, which doesn't
|
|
36
|
+
* exist yet either. Stubbed to always
|
|
37
|
+
* return `undefined` ("no retained snapshot").
|
|
38
|
+
* - **Monthly orphan sweep** ({@link runMonthlyOrphanSweepStub}) — the fourth
|
|
39
|
+
* protocol phase, reconciling bytes on disk with no `asset_blobs` row at
|
|
40
|
+
* all (e.g. a crash before any GC protocol existed). Needs a scheduler
|
|
41
|
+
* this library doesn't provide. Named so the seam exists; performs no work
|
|
42
|
+
* and is never called.
|
|
43
|
+
* - **Cross-process safety** — `withSha256Lock` only serializes within one
|
|
44
|
+
* Node process. A real multi-instance deployment needs the real DB
|
|
45
|
+
* transaction the original design specifies, which a host's own persistence adapter
|
|
46
|
+
* would supply; this build has no multi-writer story for media at all yet
|
|
47
|
+
* (in-memory repo), so that gap is inherited, not new.
|
|
48
|
+
*/
|
|
49
|
+
import type { ClockPort, IdGeneratorPort, UUID } from "../core/ports.js";
|
|
50
|
+
import type { AssetBlobRepoPort, BlobGcJournalRepoPort, BlobStorePort, MediaRepoPort } from "./ports.js";
|
|
51
|
+
/** Default retention window before a tombstoned blob's delete-pass may run. */
|
|
52
|
+
export declare const DEFAULT_GC_GRACE_MS: number;
|
|
53
|
+
/**
|
|
54
|
+
* `gc_grace = max(configured default, age of the oldest retained snapshot at
|
|
55
|
+
* delete-pass time)`. The snapshot half is always `0` in this
|
|
56
|
+
* build (see {@link getOldestRetainedSnapshotAgeMs}), so this currently
|
|
57
|
+
* always resolves to {@link DEFAULT_GC_GRACE_MS} — structured so a real
|
|
58
|
+
* snapshot-age input replaces that `?? 0` later without touching callers.
|
|
59
|
+
*
|
|
60
|
+
* @complexity O(1).
|
|
61
|
+
* @overallScore 100
|
|
62
|
+
*/
|
|
63
|
+
export declare function resolveGcGraceMs(input: {
|
|
64
|
+
workspaceId: UUID;
|
|
65
|
+
sha256: string;
|
|
66
|
+
}): number;
|
|
67
|
+
export interface IsBlobUnreferencedRequired {
|
|
68
|
+
deps: {
|
|
69
|
+
mediaRepo: MediaRepoPort;
|
|
70
|
+
};
|
|
71
|
+
input: {
|
|
72
|
+
workspaceId: UUID;
|
|
73
|
+
sha256: string;
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* The real "unreferenced" check this file replaces `purgeMedia`'s old
|
|
78
|
+
* sibling-scan-and-immediately-delete shortcut with. Normative definition:
|
|
79
|
+
* no media entry in the workspace in any non-purged state
|
|
80
|
+
* (active or trashed — purged rows are physically removed by `purgeMedia`,
|
|
81
|
+
* so `mediaRepo.list` already excludes them by construction) references this
|
|
82
|
+
* sha256, AND no live `entry_refs` targets it, AND no retained snapshot
|
|
83
|
+
* references it. The last two conjuncts are evaluated by the disclosed stubs
|
|
84
|
+
* above.
|
|
85
|
+
*
|
|
86
|
+
* Callers MUST invoke this from inside {@link withSha256Lock} for the same
|
|
87
|
+
* sha256 — this function only reads, it does not lock itself, so its result
|
|
88
|
+
* is only trustworthy for as long as the caller's own lock is held.
|
|
89
|
+
*
|
|
90
|
+
* @complexity O(n) in the workspace's media row count (same disclosed
|
|
91
|
+
* tradeoff `purgeMedia`'s prior sibling-scan already carried — see
|
|
92
|
+
* `media-service.ts`'s findings note on that function).
|
|
93
|
+
* @overallScore 90
|
|
94
|
+
* @findings Medium: O(n) `mediaRepo.list` + `.some` scan per call, same
|
|
95
|
+
* known tradeoff as the code this replaces. A real `asset_blobs` reference
|
|
96
|
+
* count column would make this O(1); not worth adding for an in-memory
|
|
97
|
+
* walking-skeleton repo.
|
|
98
|
+
*/
|
|
99
|
+
export declare function isBlobUnreferenced(required: IsBlobUnreferencedRequired): Promise<boolean>;
|
|
100
|
+
export interface TombstoneBlobDeps {
|
|
101
|
+
mediaRepo: MediaRepoPort;
|
|
102
|
+
blobRepo: AssetBlobRepoPort;
|
|
103
|
+
clock: ClockPort;
|
|
104
|
+
}
|
|
105
|
+
export interface TombstoneBlobRequired {
|
|
106
|
+
deps: TombstoneBlobDeps;
|
|
107
|
+
input: {
|
|
108
|
+
workspaceId: UUID;
|
|
109
|
+
sha256: string;
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Tombstone-pass. Marks an `active` blob row `tombstoned` (starting its
|
|
114
|
+
* `gc_grace` clock) if-and-only-if {@link isBlobUnreferenced} holds, all
|
|
115
|
+
* inside one {@link withSha256Lock} section so a concurrent dedup upload for
|
|
116
|
+
* the same sha256 can't observe a half-updated row. Idempotent: re-tombstoning
|
|
117
|
+
* an already-tombstoned row is a no-op success, not an error (mirrors
|
|
118
|
+
* `trashMedia`'s idempotency).
|
|
119
|
+
*
|
|
120
|
+
* @complexity O(n) — dominated by {@link isBlobUnreferenced}'s scan.
|
|
121
|
+
* @overallScore 100
|
|
122
|
+
*/
|
|
123
|
+
export declare function tombstoneBlobIfUnreferenced(required: TombstoneBlobRequired): Promise<{
|
|
124
|
+
tombstoned: boolean;
|
|
125
|
+
reason: string;
|
|
126
|
+
}>;
|
|
127
|
+
export interface RunBlobGcDeletePassDeps {
|
|
128
|
+
mediaRepo: MediaRepoPort;
|
|
129
|
+
blobRepo: AssetBlobRepoPort;
|
|
130
|
+
journalRepo: BlobGcJournalRepoPort;
|
|
131
|
+
clock: ClockPort;
|
|
132
|
+
idGen: IdGeneratorPort;
|
|
133
|
+
}
|
|
134
|
+
export interface RunBlobGcDeletePassRequired {
|
|
135
|
+
deps: RunBlobGcDeletePassDeps;
|
|
136
|
+
input: {
|
|
137
|
+
workspaceId: UUID;
|
|
138
|
+
sha256: string;
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Delete-pass. Gated on the row being `tombstoned` AND `gc_grace` having
|
|
143
|
+
* elapsed since `tombstonedAt` ({@link resolveGcGraceMs}); re-checks the full
|
|
144
|
+
* {@link isBlobUnreferenced} predicate one more time before acting (a
|
|
145
|
+
* resurrect between tombstone-pass and delete-pass already flips status back
|
|
146
|
+
* to `active`, which the tombstoned-status check below catches first, but the
|
|
147
|
+
* re-check is what the protocol calls for and is what future non-stub
|
|
148
|
+
* entry_refs/snapshot conjuncts would need). On success: writes the
|
|
149
|
+
* `blob_gc_journal` entry and removes the `asset_blobs` row, in that order,
|
|
150
|
+
* inside the same locked section — INV-1a's "unlinked only after the row
|
|
151
|
+
* deletion commits" half depends on nothing touching bytes here at all.
|
|
152
|
+
*
|
|
153
|
+
* @complexity O(n) — dominated by the re-check's `isBlobUnreferenced` scan.
|
|
154
|
+
* @overallScore 100
|
|
155
|
+
*/
|
|
156
|
+
export declare function runBlobGcDeletePass(required: RunBlobGcDeletePassRequired): Promise<{
|
|
157
|
+
deleted: boolean;
|
|
158
|
+
reason: string;
|
|
159
|
+
}>;
|
|
160
|
+
export interface RunBlobGcUnlinkPassDeps {
|
|
161
|
+
blobRepo: AssetBlobRepoPort;
|
|
162
|
+
journalRepo: BlobGcJournalRepoPort;
|
|
163
|
+
blobStore: BlobStorePort;
|
|
164
|
+
}
|
|
165
|
+
export interface RunBlobGcUnlinkPassRequired {
|
|
166
|
+
deps: RunBlobGcUnlinkPassDeps;
|
|
167
|
+
input: {
|
|
168
|
+
workspaceId: UUID;
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Unlink-pass. Drains every journal entry for the workspace; for each, under
|
|
173
|
+
* that entry's sha256 lock, re-checks whether a **live** `asset_blobs` row now
|
|
174
|
+
* exists for the same sha256 (a dedup upload can legitimately recreate one
|
|
175
|
+
* after the delete-pass ran but before this pass drained the entry). If one
|
|
176
|
+
* exists, the entry is stale — its bytes are now owned by the live row, so
|
|
177
|
+
* this pass must NOT unlink them; the journal entry is still removed (its
|
|
178
|
+
* job — reconciling the row this ADR's crash-safety story cares about — is
|
|
179
|
+
* done either way). If no row exists, the bytes are genuinely orphaned and
|
|
180
|
+
* are removed.
|
|
181
|
+
*
|
|
182
|
+
* This re-check-under-lock is this build's substitute for the design's
|
|
183
|
+
* per-generation storage-key epochs (deferred — see `blob-key.ts`'s file
|
|
184
|
+
* header): instead of tagging storage keys with a generation suffix so a
|
|
185
|
+
* stale unlink physically cannot address live bytes, the sha256 lock plus
|
|
186
|
+
* this re-check gives the same guarantee for a single-process, in-memory
|
|
187
|
+
* build (see `blob-gc-lock.ts`'s file header for the serialization story this
|
|
188
|
+
* relies on).
|
|
189
|
+
*
|
|
190
|
+
* @complexity O(j) in the number of pending journal entries for the
|
|
191
|
+
* workspace, each doing O(1) repo/store work.
|
|
192
|
+
* @overallScore 100
|
|
193
|
+
*/
|
|
194
|
+
export declare function runBlobGcUnlinkPass(required: RunBlobGcUnlinkPassRequired): Promise<{
|
|
195
|
+
unlinked: string[];
|
|
196
|
+
skipped: string[];
|
|
197
|
+
}>;
|
|
198
|
+
export interface RunBlobGcCycleDeps extends RunBlobGcDeletePassDeps, Pick<RunBlobGcUnlinkPassDeps, "blobStore"> {
|
|
199
|
+
}
|
|
200
|
+
export interface RunBlobGcCycleRequired {
|
|
201
|
+
deps: RunBlobGcCycleDeps;
|
|
202
|
+
input: {
|
|
203
|
+
workspaceId: UUID;
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Convenience wrapper: runs the delete-pass over every currently-tombstoned
|
|
208
|
+
* blob in the workspace (each still individually grace-gated —
|
|
209
|
+
* `runBlobGcDeletePass` may no-op per row), then drains the unlink-pass once.
|
|
210
|
+
* This is NOT the ADR's periodic/monthly orphan sweep (a different,
|
|
211
|
+
* out-of-scope reconciliation against bytes with no row at all — see
|
|
212
|
+
* {@link runMonthlyOrphanSweepStub}); it is just a batch shape over the two
|
|
213
|
+
* in-scope phases above, for tests and any future manual/operator trigger.
|
|
214
|
+
* Nothing calls it on a schedule.
|
|
215
|
+
*
|
|
216
|
+
* @complexity O(t * n + j) — t tombstoned rows each doing an O(n)
|
|
217
|
+
* `isBlobUnreferenced` re-check, plus O(j) journal drain.
|
|
218
|
+
* @overallScore 100
|
|
219
|
+
*/
|
|
220
|
+
export declare function runBlobGcCycle(required: RunBlobGcCycleRequired): Promise<{
|
|
221
|
+
deletedShas: string[];
|
|
222
|
+
unlinked: string[];
|
|
223
|
+
skipped: string[];
|
|
224
|
+
}>;
|
|
225
|
+
/**
|
|
226
|
+
* STUB — the protocol's fourth GC phase, a periodic/monthly orphan sweep that
|
|
227
|
+
* reconciles bytes physically present in the blob store with no
|
|
228
|
+
* corresponding `asset_blobs` row at all (e.g. bytes from a crash before any
|
|
229
|
+
* GC protocol existed, or before this build's ordering guarantee was in
|
|
230
|
+
* place). Out of scope for this task ("needs a scheduler this build doesn't
|
|
231
|
+
* have yet" — see this file's header). Performs no work; exists only so the
|
|
232
|
+
* seam a future scheduler would call has a name and signature. Never invoked
|
|
233
|
+
* anywhere in this build.
|
|
234
|
+
*
|
|
235
|
+
* @complexity O(1) (stub — does nothing).
|
|
236
|
+
* @overallScore 100
|
|
237
|
+
*/
|
|
238
|
+
export declare function runMonthlyOrphanSweepStub(_deps: {
|
|
239
|
+
blobStore: BlobStorePort;
|
|
240
|
+
blobRepo: AssetBlobRepoPort;
|
|
241
|
+
}, _input: {
|
|
242
|
+
workspaceId: UUID;
|
|
243
|
+
}): Promise<{
|
|
244
|
+
implemented: false;
|
|
245
|
+
}>;
|
|
246
|
+
//# sourceMappingURL=blob-gc.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"blob-gc.d.ts","sourceRoot":"","sources":["../../src/media/blob-gc.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
import { withSha256Lock } from "./blob-gc-lock.js";
|
|
2
|
+
/** Default retention window before a tombstoned blob's delete-pass may run. */
|
|
3
|
+
export const DEFAULT_GC_GRACE_MS = 30 * 24 * 60 * 60 * 1000; // 30 days
|
|
4
|
+
// ---------------------------------------------------------------------------
|
|
5
|
+
// Disclosed stubs — conjuncts this build cannot evaluate for real
|
|
6
|
+
// yet. Both are named, not silently folded into `true`/`false` inline, so a
|
|
7
|
+
// future implementation has an obvious seam to replace.
|
|
8
|
+
// ---------------------------------------------------------------------------
|
|
9
|
+
/**
|
|
10
|
+
* STUB — the derived `entry_refs` where-used index (TipTap image nodes
|
|
11
|
+
* + registry `ref` fields) does not exist as running code yet (see this
|
|
12
|
+
* file's header). Always reports no live references, which is what lets
|
|
13
|
+
* {@link isBlobUnreferenced} degrade to the sha256-uniqueness check alone.
|
|
14
|
+
*
|
|
15
|
+
* @complexity O(1) (stub).
|
|
16
|
+
* @overallScore 100
|
|
17
|
+
*/
|
|
18
|
+
function hasLiveEntryRefs(_input) {
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* STUB — snapshot-retention is owned by a pending Storage/Backups snapshot
|
|
23
|
+
* primitive (not built yet at all — see this file's header). Always reports
|
|
24
|
+
* no retained snapshot.
|
|
25
|
+
*
|
|
26
|
+
* @complexity O(1) (stub).
|
|
27
|
+
* @overallScore 100
|
|
28
|
+
*/
|
|
29
|
+
function hasRetainedSnapshot(_input) {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* STUB — age (ms) of the oldest snapshot that still retains this blob, at
|
|
34
|
+
* delete-pass time. Always `undefined` in this build (no snapshot primitive
|
|
35
|
+
* exists), which is what makes {@link resolveGcGraceMs} fall back to the
|
|
36
|
+
* 30-day default alone. A real implementation would return a number here;
|
|
37
|
+
* `resolveGcGraceMs`'s `Math.max` already accepts that without change.
|
|
38
|
+
*
|
|
39
|
+
* @complexity O(1) (stub).
|
|
40
|
+
* @overallScore 100
|
|
41
|
+
*/
|
|
42
|
+
function getOldestRetainedSnapshotAgeMs(_input) {
|
|
43
|
+
return undefined;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* `gc_grace = max(configured default, age of the oldest retained snapshot at
|
|
47
|
+
* delete-pass time)`. The snapshot half is always `0` in this
|
|
48
|
+
* build (see {@link getOldestRetainedSnapshotAgeMs}), so this currently
|
|
49
|
+
* always resolves to {@link DEFAULT_GC_GRACE_MS} — structured so a real
|
|
50
|
+
* snapshot-age input replaces that `?? 0` later without touching callers.
|
|
51
|
+
*
|
|
52
|
+
* @complexity O(1).
|
|
53
|
+
* @overallScore 100
|
|
54
|
+
*/
|
|
55
|
+
export function resolveGcGraceMs(input) {
|
|
56
|
+
const snapshotAgeMs = getOldestRetainedSnapshotAgeMs(input) ?? 0;
|
|
57
|
+
return Math.max(DEFAULT_GC_GRACE_MS, snapshotAgeMs);
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* The real "unreferenced" check this file replaces `purgeMedia`'s old
|
|
61
|
+
* sibling-scan-and-immediately-delete shortcut with. Normative definition:
|
|
62
|
+
* no media entry in the workspace in any non-purged state
|
|
63
|
+
* (active or trashed — purged rows are physically removed by `purgeMedia`,
|
|
64
|
+
* so `mediaRepo.list` already excludes them by construction) references this
|
|
65
|
+
* sha256, AND no live `entry_refs` targets it, AND no retained snapshot
|
|
66
|
+
* references it. The last two conjuncts are evaluated by the disclosed stubs
|
|
67
|
+
* above.
|
|
68
|
+
*
|
|
69
|
+
* Callers MUST invoke this from inside {@link withSha256Lock} for the same
|
|
70
|
+
* sha256 — this function only reads, it does not lock itself, so its result
|
|
71
|
+
* is only trustworthy for as long as the caller's own lock is held.
|
|
72
|
+
*
|
|
73
|
+
* @complexity O(n) in the workspace's media row count (same disclosed
|
|
74
|
+
* tradeoff `purgeMedia`'s prior sibling-scan already carried — see
|
|
75
|
+
* `media-service.ts`'s findings note on that function).
|
|
76
|
+
* @overallScore 90
|
|
77
|
+
* @findings Medium: O(n) `mediaRepo.list` + `.some` scan per call, same
|
|
78
|
+
* known tradeoff as the code this replaces. A real `asset_blobs` reference
|
|
79
|
+
* count column would make this O(1); not worth adding for an in-memory
|
|
80
|
+
* walking-skeleton repo.
|
|
81
|
+
*/
|
|
82
|
+
export async function isBlobUnreferenced(required) {
|
|
83
|
+
const { deps, input } = required;
|
|
84
|
+
const rows = await deps.mediaRepo.list({ workspaceId: input.workspaceId });
|
|
85
|
+
const hasMediaReference = rows.some((row) => row.source.sha256 === input.sha256);
|
|
86
|
+
if (hasMediaReference)
|
|
87
|
+
return false;
|
|
88
|
+
if (hasLiveEntryRefs(input))
|
|
89
|
+
return false;
|
|
90
|
+
if (hasRetainedSnapshot(input))
|
|
91
|
+
return false;
|
|
92
|
+
return true;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Tombstone-pass. Marks an `active` blob row `tombstoned` (starting its
|
|
96
|
+
* `gc_grace` clock) if-and-only-if {@link isBlobUnreferenced} holds, all
|
|
97
|
+
* inside one {@link withSha256Lock} section so a concurrent dedup upload for
|
|
98
|
+
* the same sha256 can't observe a half-updated row. Idempotent: re-tombstoning
|
|
99
|
+
* an already-tombstoned row is a no-op success, not an error (mirrors
|
|
100
|
+
* `trashMedia`'s idempotency).
|
|
101
|
+
*
|
|
102
|
+
* @complexity O(n) — dominated by {@link isBlobUnreferenced}'s scan.
|
|
103
|
+
* @overallScore 100
|
|
104
|
+
*/
|
|
105
|
+
export async function tombstoneBlobIfUnreferenced(required) {
|
|
106
|
+
const { deps, input } = required;
|
|
107
|
+
return withSha256Lock(input.sha256, async () => {
|
|
108
|
+
const row = await deps.blobRepo.findByHash(input);
|
|
109
|
+
if (!row)
|
|
110
|
+
return { tombstoned: false, reason: "no-blob-row" };
|
|
111
|
+
if (row.status === "tombstoned")
|
|
112
|
+
return { tombstoned: true, reason: "already-tombstoned" };
|
|
113
|
+
const unreferenced = await isBlobUnreferenced({ deps, input });
|
|
114
|
+
if (!unreferenced)
|
|
115
|
+
return { tombstoned: false, reason: "still-referenced" };
|
|
116
|
+
await deps.blobRepo.save({ ...row, status: "tombstoned", tombstonedAt: deps.clock.nowIso() });
|
|
117
|
+
return { tombstoned: true, reason: "tombstoned" };
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Delete-pass. Gated on the row being `tombstoned` AND `gc_grace` having
|
|
122
|
+
* elapsed since `tombstonedAt` ({@link resolveGcGraceMs}); re-checks the full
|
|
123
|
+
* {@link isBlobUnreferenced} predicate one more time before acting (a
|
|
124
|
+
* resurrect between tombstone-pass and delete-pass already flips status back
|
|
125
|
+
* to `active`, which the tombstoned-status check below catches first, but the
|
|
126
|
+
* re-check is what the protocol calls for and is what future non-stub
|
|
127
|
+
* entry_refs/snapshot conjuncts would need). On success: writes the
|
|
128
|
+
* `blob_gc_journal` entry and removes the `asset_blobs` row, in that order,
|
|
129
|
+
* inside the same locked section — INV-1a's "unlinked only after the row
|
|
130
|
+
* deletion commits" half depends on nothing touching bytes here at all.
|
|
131
|
+
*
|
|
132
|
+
* @complexity O(n) — dominated by the re-check's `isBlobUnreferenced` scan.
|
|
133
|
+
* @overallScore 100
|
|
134
|
+
*/
|
|
135
|
+
export async function runBlobGcDeletePass(required) {
|
|
136
|
+
const { deps, input } = required;
|
|
137
|
+
return withSha256Lock(input.sha256, async () => {
|
|
138
|
+
const row = await deps.blobRepo.findByHash(input);
|
|
139
|
+
if (!row)
|
|
140
|
+
return { deleted: false, reason: "no-blob-row" };
|
|
141
|
+
if (row.status !== "tombstoned" || !row.tombstonedAt) {
|
|
142
|
+
return { deleted: false, reason: "not-tombstoned" };
|
|
143
|
+
}
|
|
144
|
+
const graceMs = resolveGcGraceMs(input);
|
|
145
|
+
const elapsedMs = new Date(deps.clock.nowIso()).getTime() - new Date(row.tombstonedAt).getTime();
|
|
146
|
+
if (elapsedMs < graceMs)
|
|
147
|
+
return { deleted: false, reason: "grace-period-not-elapsed" };
|
|
148
|
+
const stillUnreferenced = await isBlobUnreferenced({ deps, input });
|
|
149
|
+
if (!stillUnreferenced)
|
|
150
|
+
return { deleted: false, reason: "resurrected" };
|
|
151
|
+
await deps.journalRepo.save({
|
|
152
|
+
id: deps.idGen.newId(),
|
|
153
|
+
workspaceId: input.workspaceId,
|
|
154
|
+
sha256: input.sha256,
|
|
155
|
+
storageKey: row.storageKey,
|
|
156
|
+
journaledAt: deps.clock.nowIso(),
|
|
157
|
+
});
|
|
158
|
+
await deps.blobRepo.remove(input);
|
|
159
|
+
return { deleted: true, reason: "deleted" };
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Unlink-pass. Drains every journal entry for the workspace; for each, under
|
|
164
|
+
* that entry's sha256 lock, re-checks whether a **live** `asset_blobs` row now
|
|
165
|
+
* exists for the same sha256 (a dedup upload can legitimately recreate one
|
|
166
|
+
* after the delete-pass ran but before this pass drained the entry). If one
|
|
167
|
+
* exists, the entry is stale — its bytes are now owned by the live row, so
|
|
168
|
+
* this pass must NOT unlink them; the journal entry is still removed (its
|
|
169
|
+
* job — reconciling the row this ADR's crash-safety story cares about — is
|
|
170
|
+
* done either way). If no row exists, the bytes are genuinely orphaned and
|
|
171
|
+
* are removed.
|
|
172
|
+
*
|
|
173
|
+
* This re-check-under-lock is this build's substitute for the design's
|
|
174
|
+
* per-generation storage-key epochs (deferred — see `blob-key.ts`'s file
|
|
175
|
+
* header): instead of tagging storage keys with a generation suffix so a
|
|
176
|
+
* stale unlink physically cannot address live bytes, the sha256 lock plus
|
|
177
|
+
* this re-check gives the same guarantee for a single-process, in-memory
|
|
178
|
+
* build (see `blob-gc-lock.ts`'s file header for the serialization story this
|
|
179
|
+
* relies on).
|
|
180
|
+
*
|
|
181
|
+
* @complexity O(j) in the number of pending journal entries for the
|
|
182
|
+
* workspace, each doing O(1) repo/store work.
|
|
183
|
+
* @overallScore 100
|
|
184
|
+
*/
|
|
185
|
+
export async function runBlobGcUnlinkPass(required) {
|
|
186
|
+
const { deps, input } = required;
|
|
187
|
+
const entries = await deps.journalRepo.list(input);
|
|
188
|
+
const unlinked = [];
|
|
189
|
+
const skipped = [];
|
|
190
|
+
for (const entry of entries) {
|
|
191
|
+
await withSha256Lock(entry.sha256, async () => {
|
|
192
|
+
const liveRow = await deps.blobRepo.findByHash({
|
|
193
|
+
workspaceId: entry.workspaceId,
|
|
194
|
+
sha256: entry.sha256,
|
|
195
|
+
});
|
|
196
|
+
if (liveRow) {
|
|
197
|
+
skipped.push(entry.sha256);
|
|
198
|
+
}
|
|
199
|
+
else {
|
|
200
|
+
await deps.blobStore.remove({ storageKey: entry.storageKey });
|
|
201
|
+
unlinked.push(entry.sha256);
|
|
202
|
+
}
|
|
203
|
+
await deps.journalRepo.remove({ workspaceId: entry.workspaceId, id: entry.id });
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
return { unlinked, skipped };
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Convenience wrapper: runs the delete-pass over every currently-tombstoned
|
|
210
|
+
* blob in the workspace (each still individually grace-gated —
|
|
211
|
+
* `runBlobGcDeletePass` may no-op per row), then drains the unlink-pass once.
|
|
212
|
+
* This is NOT the ADR's periodic/monthly orphan sweep (a different,
|
|
213
|
+
* out-of-scope reconciliation against bytes with no row at all — see
|
|
214
|
+
* {@link runMonthlyOrphanSweepStub}); it is just a batch shape over the two
|
|
215
|
+
* in-scope phases above, for tests and any future manual/operator trigger.
|
|
216
|
+
* Nothing calls it on a schedule.
|
|
217
|
+
*
|
|
218
|
+
* @complexity O(t * n + j) — t tombstoned rows each doing an O(n)
|
|
219
|
+
* `isBlobUnreferenced` re-check, plus O(j) journal drain.
|
|
220
|
+
* @overallScore 100
|
|
221
|
+
*/
|
|
222
|
+
export async function runBlobGcCycle(required) {
|
|
223
|
+
const { deps, input } = required;
|
|
224
|
+
const rows = await deps.blobRepo.list(input);
|
|
225
|
+
const tombstonedRows = rows.filter((row) => row.status === "tombstoned");
|
|
226
|
+
const deletedShas = [];
|
|
227
|
+
for (const row of tombstonedRows) {
|
|
228
|
+
const result = await runBlobGcDeletePass({ deps, input: { workspaceId: input.workspaceId, sha256: row.sha256 } });
|
|
229
|
+
if (result.deleted)
|
|
230
|
+
deletedShas.push(row.sha256);
|
|
231
|
+
}
|
|
232
|
+
const { unlinked, skipped } = await runBlobGcUnlinkPass({ deps, input });
|
|
233
|
+
return { deletedShas, unlinked, skipped };
|
|
234
|
+
}
|
|
235
|
+
// ---------------------------------------------------------------------------
|
|
236
|
+
// Explicitly out of scope — named stub only (see file header)
|
|
237
|
+
// ---------------------------------------------------------------------------
|
|
238
|
+
/**
|
|
239
|
+
* STUB — the protocol's fourth GC phase, a periodic/monthly orphan sweep that
|
|
240
|
+
* reconciles bytes physically present in the blob store with no
|
|
241
|
+
* corresponding `asset_blobs` row at all (e.g. bytes from a crash before any
|
|
242
|
+
* GC protocol existed, or before this build's ordering guarantee was in
|
|
243
|
+
* place). Out of scope for this task ("needs a scheduler this build doesn't
|
|
244
|
+
* have yet" — see this file's header). Performs no work; exists only so the
|
|
245
|
+
* seam a future scheduler would call has a name and signature. Never invoked
|
|
246
|
+
* anywhere in this build.
|
|
247
|
+
*
|
|
248
|
+
* @complexity O(1) (stub — does nothing).
|
|
249
|
+
* @overallScore 100
|
|
250
|
+
*/
|
|
251
|
+
export async function runMonthlyOrphanSweepStub(_deps, _input) {
|
|
252
|
+
return { implemented: false };
|
|
253
|
+
}
|
|
254
|
+
//# sourceMappingURL=blob-gc.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"blob-gc.js","sourceRoot":"","sources":["../../src/media/blob-gc.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Shared storage-key derivation for `BlobStorePort` adapters
|
|
3
|
+
* (workspace-prefixed keys).
|
|
4
|
+
*
|
|
5
|
+
* Purpose:
|
|
6
|
+
* Both `blob-store.fs.ts` and `blob-store.memory.ts` must derive the same key
|
|
7
|
+
* shape from `(workspaceId, sha256)` so switching adapters never changes what a
|
|
8
|
+
* stored key looks like. Kept as one small pure function rather than
|
|
9
|
+
* duplicated inline in each adapter.
|
|
10
|
+
*
|
|
11
|
+
* No per-generation epoch suffix (contrast the original design's
|
|
12
|
+
* `{sha256}-{storage_epoch}`) — epochs exist to make the journaled 2-phase GC
|
|
13
|
+
* race-proof, and that protocol is explicitly deferred in this build (see
|
|
14
|
+
* `media-service.ts` file header). A future epoch-aware rewrite would change
|
|
15
|
+
* this function's output shape, not its callers' contract.
|
|
16
|
+
*/
|
|
17
|
+
import type { UUID } from "../core/ports.js";
|
|
18
|
+
/**
|
|
19
|
+
* Derives `ws/{workspaceId}/blobs/{sha256[0..1]}/{sha256}`.
|
|
20
|
+
*
|
|
21
|
+
* @complexity O(1).
|
|
22
|
+
* @overallScore 100
|
|
23
|
+
*/
|
|
24
|
+
export declare function computeBlobStorageKey(input: {
|
|
25
|
+
workspaceId: UUID;
|
|
26
|
+
sha256: string;
|
|
27
|
+
}): string;
|
|
28
|
+
//# sourceMappingURL=blob-key.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"blob-key.d.ts","sourceRoot":"","sources":["../../src/media/blob-key.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAE7C;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE;IAAE,WAAW,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAG1F"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Derives `ws/{workspaceId}/blobs/{sha256[0..1]}/{sha256}`.
|
|
3
|
+
*
|
|
4
|
+
* @complexity O(1).
|
|
5
|
+
* @overallScore 100
|
|
6
|
+
*/
|
|
7
|
+
export function computeBlobStorageKey(input) {
|
|
8
|
+
const shard = input.sha256.slice(0, 2);
|
|
9
|
+
return `ws/${input.workspaceId}/blobs/${shard}/${input.sha256}`;
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=blob-key.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"blob-key.js","sourceRoot":"","sources":["../../src/media/blob-key.ts"],"names":[],"mappings":"AAkBA;;;;;GAKG;AACH,MAAM,UAAU,qBAAqB,CAAC,KAA4C;IAChF,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACvC,OAAO,MAAM,KAAK,CAAC,WAAW,UAAU,KAAK,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;AAClE,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { BlobStorePort, PutBlobInput } from "./ports.js";
|
|
2
|
+
export interface LocalFsBlobStoreDeps {
|
|
3
|
+
/** Root directory blob storage keys are resolved relative to. */
|
|
4
|
+
rootDir: string;
|
|
5
|
+
}
|
|
6
|
+
export declare class LocalFsBlobStore implements BlobStorePort {
|
|
7
|
+
private readonly rootDir;
|
|
8
|
+
constructor(deps: LocalFsBlobStoreDeps);
|
|
9
|
+
private resolvePath;
|
|
10
|
+
put(input: PutBlobInput): Promise<{
|
|
11
|
+
storageKey: string;
|
|
12
|
+
}>;
|
|
13
|
+
get(input: {
|
|
14
|
+
storageKey: string;
|
|
15
|
+
}): Promise<Uint8Array>;
|
|
16
|
+
exists(input: {
|
|
17
|
+
storageKey: string;
|
|
18
|
+
}): Promise<boolean>;
|
|
19
|
+
remove(input: {
|
|
20
|
+
storageKey: string;
|
|
21
|
+
}): Promise<void>;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=blob-store.fs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"blob-store.fs.d.ts","sourceRoot":"","sources":["../../src/media/blob-store.fs.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAG9D,MAAM,WAAW,oBAAoB;IACnC,iEAAiE;IACjE,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,qBAAa,gBAAiB,YAAW,aAAa;IACpD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;gBAErB,IAAI,EAAE,oBAAoB;IAItC,OAAO,CAAC,WAAW;IAIb,GAAG,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC;QAAE,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC;IAQzD,GAAG,CAAC,KAAK,EAAE;QAAE,UAAU,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,UAAU,CAAC;IAIvD,MAAM,CAAC,KAAK,EAAE;QAAE,UAAU,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,OAAO,CAAC;IASvD,MAAM,CAAC,KAAK,EAAE;QAAE,UAAU,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;CAG3D"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Local-filesystem `BlobStorePort` adapter (port/adapter rule-of-two "one
|
|
3
|
+
* being built now" half; the `uploads/` convention).
|
|
4
|
+
*
|
|
5
|
+
* Purpose:
|
|
6
|
+
* Writes/reads blob bytes under a configurable root directory, keyed by
|
|
7
|
+
* `computeBlobStorageKey` (`blob-key.ts`). A host wires this in for its real
|
|
8
|
+
* running server; the in-memory adapter (`blob-store.memory.ts`) is what
|
|
9
|
+
* hermetic tests and a default dev composition use instead.
|
|
10
|
+
*
|
|
11
|
+
* Deliberately NOT built: the S3 adapter (deferred), the presign
|
|
12
|
+
* surface, per-generation storage epochs (see `blob-key.ts` file header).
|
|
13
|
+
*/
|
|
14
|
+
import { mkdir, readFile, rm, stat, writeFile } from "node:fs/promises";
|
|
15
|
+
import { dirname, join } from "node:path";
|
|
16
|
+
import { computeBlobStorageKey } from "./blob-key.js";
|
|
17
|
+
export class LocalFsBlobStore {
|
|
18
|
+
rootDir;
|
|
19
|
+
constructor(deps) {
|
|
20
|
+
this.rootDir = deps.rootDir;
|
|
21
|
+
}
|
|
22
|
+
resolvePath(storageKey) {
|
|
23
|
+
return join(this.rootDir, storageKey);
|
|
24
|
+
}
|
|
25
|
+
async put(input) {
|
|
26
|
+
const storageKey = computeBlobStorageKey(input);
|
|
27
|
+
const path = this.resolvePath(storageKey);
|
|
28
|
+
await mkdir(dirname(path), { recursive: true });
|
|
29
|
+
await writeFile(path, input.bytes);
|
|
30
|
+
return { storageKey };
|
|
31
|
+
}
|
|
32
|
+
async get(input) {
|
|
33
|
+
return readFile(this.resolvePath(input.storageKey));
|
|
34
|
+
}
|
|
35
|
+
async exists(input) {
|
|
36
|
+
try {
|
|
37
|
+
await stat(this.resolvePath(input.storageKey));
|
|
38
|
+
return true;
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
async remove(input) {
|
|
45
|
+
await rm(this.resolvePath(input.storageKey), { force: true });
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=blob-store.fs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"blob-store.fs.js","sourceRoot":"","sources":["../../src/media/blob-store.fs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACxE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAG1C,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAOtD,MAAM,OAAO,gBAAgB;IACV,OAAO,CAAS;IAEjC,YAAY,IAA0B;QACpC,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;IAC9B,CAAC;IAEO,WAAW,CAAC,UAAkB;QACpC,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;IACxC,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,KAAmB;QAC3B,MAAM,UAAU,GAAG,qBAAqB,CAAC,KAAK,CAAC,CAAC;QAChD,MAAM,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC;QAC1C,MAAM,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAChD,MAAM,SAAS,CAAC,IAAI,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;QACnC,OAAO,EAAE,UAAU,EAAE,CAAC;IACxB,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,KAA6B;QACrC,OAAO,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC;IACtD,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,KAA6B;QACxC,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC;YAC/C,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,KAA6B;QACxC,MAAM,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAChE,CAAC;CACF"}
|