@vibesdotdev/storage 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +75 -0
- package/SPEC.md +60 -0
- package/dist/adapters/index.d.ts +14 -0
- package/dist/adapters/index.d.ts.map +1 -0
- package/dist/adapters/index.js +15 -0
- package/dist/adapters/index.js.map +1 -0
- package/dist/bridge/index.d.ts +3 -0
- package/dist/bridge/index.d.ts.map +1 -0
- package/dist/bridge/index.js +2 -0
- package/dist/bridge/index.js.map +1 -0
- package/dist/bridge/storage-kind-bridge.d.ts +27 -0
- package/dist/bridge/storage-kind-bridge.d.ts.map +1 -0
- package/dist/bridge/storage-kind-bridge.js +110 -0
- package/dist/bridge/storage-kind-bridge.js.map +1 -0
- package/dist/bridge/types.d.ts +45 -0
- package/dist/bridge/types.d.ts.map +1 -0
- package/dist/bridge/types.js +8 -0
- package/dist/bridge/types.js.map +1 -0
- package/dist/cli/commands/list/storage.list.cli-command.descriptor.d.ts +4 -0
- package/dist/cli/commands/list/storage.list.cli-command.descriptor.d.ts.map +1 -0
- package/dist/cli/commands/list/storage.list.cli-command.descriptor.js +18 -0
- package/dist/cli/commands/list/storage.list.cli-command.descriptor.js.map +1 -0
- package/dist/cli/commands/list/storage.list.cli-command.impl.d.ts +11 -0
- package/dist/cli/commands/list/storage.list.cli-command.impl.d.ts.map +1 -0
- package/dist/cli/commands/list/storage.list.cli-command.impl.js +48 -0
- package/dist/cli/commands/list/storage.list.cli-command.impl.js.map +1 -0
- package/dist/cli/commands/sync/pull/storage.sync.pull.cli-command.descriptor.d.ts +4 -0
- package/dist/cli/commands/sync/pull/storage.sync.pull.cli-command.descriptor.d.ts.map +1 -0
- package/dist/cli/commands/sync/pull/storage.sync.pull.cli-command.descriptor.js +26 -0
- package/dist/cli/commands/sync/pull/storage.sync.pull.cli-command.descriptor.js.map +1 -0
- package/dist/cli/commands/sync/pull/storage.sync.pull.cli-command.impl.d.ts +13 -0
- package/dist/cli/commands/sync/pull/storage.sync.pull.cli-command.impl.d.ts.map +1 -0
- package/dist/cli/commands/sync/pull/storage.sync.pull.cli-command.impl.js +136 -0
- package/dist/cli/commands/sync/pull/storage.sync.pull.cli-command.impl.js.map +1 -0
- package/dist/cli/commands/sync/push/storage.sync.push.cli-command.descriptor.d.ts +4 -0
- package/dist/cli/commands/sync/push/storage.sync.push.cli-command.descriptor.d.ts.map +1 -0
- package/dist/cli/commands/sync/push/storage.sync.push.cli-command.descriptor.js +26 -0
- package/dist/cli/commands/sync/push/storage.sync.push.cli-command.descriptor.js.map +1 -0
- package/dist/cli/commands/sync/push/storage.sync.push.cli-command.impl.d.ts +13 -0
- package/dist/cli/commands/sync/push/storage.sync.push.cli-command.impl.d.ts.map +1 -0
- package/dist/cli/commands/sync/push/storage.sync.push.cli-command.impl.js +165 -0
- package/dist/cli/commands/sync/push/storage.sync.push.cli-command.impl.js.map +1 -0
- package/dist/cli/commands/sync/resolve/storage.sync.resolve.cli-command.descriptor.d.ts +4 -0
- package/dist/cli/commands/sync/resolve/storage.sync.resolve.cli-command.descriptor.d.ts.map +1 -0
- package/dist/cli/commands/sync/resolve/storage.sync.resolve.cli-command.descriptor.js +20 -0
- package/dist/cli/commands/sync/resolve/storage.sync.resolve.cli-command.descriptor.js.map +1 -0
- package/dist/cli/commands/sync/resolve/storage.sync.resolve.cli-command.impl.d.ts +12 -0
- package/dist/cli/commands/sync/resolve/storage.sync.resolve.cli-command.impl.d.ts.map +1 -0
- package/dist/cli/commands/sync/resolve/storage.sync.resolve.cli-command.impl.js +95 -0
- package/dist/cli/commands/sync/resolve/storage.sync.resolve.cli-command.impl.js.map +1 -0
- package/dist/cli/commands/sync/status/storage.sync.status.cli-command.descriptor.d.ts +4 -0
- package/dist/cli/commands/sync/status/storage.sync.status.cli-command.descriptor.d.ts.map +1 -0
- package/dist/cli/commands/sync/status/storage.sync.status.cli-command.descriptor.js +15 -0
- package/dist/cli/commands/sync/status/storage.sync.status.cli-command.descriptor.js.map +1 -0
- package/dist/cli/commands/sync/status/storage.sync.status.cli-command.impl.d.ts +13 -0
- package/dist/cli/commands/sync/status/storage.sync.status.cli-command.impl.d.ts.map +1 -0
- package/dist/cli/commands/sync/status/storage.sync.status.cli-command.impl.js +150 -0
- package/dist/cli/commands/sync/status/storage.sync.status.cli-command.impl.js.map +1 -0
- package/dist/cli/context.consumer.d.ts +26 -0
- package/dist/cli/context.consumer.d.ts.map +1 -0
- package/dist/cli/context.consumer.js +164 -0
- package/dist/cli/context.consumer.js.map +1 -0
- package/dist/cli/storage.cli-group.descriptor.d.ts +4 -0
- package/dist/cli/storage.cli-group.descriptor.d.ts.map +1 -0
- package/dist/cli/storage.cli-group.descriptor.js +11 -0
- package/dist/cli/storage.cli-group.descriptor.js.map +1 -0
- package/dist/cli/storage.sync.cli-group.descriptor.d.ts +4 -0
- package/dist/cli/storage.sync.cli-group.descriptor.d.ts.map +1 -0
- package/dist/cli/storage.sync.cli-group.descriptor.js +12 -0
- package/dist/cli/storage.sync.cli-group.descriptor.js.map +1 -0
- package/dist/cli/types.d.ts +26 -0
- package/dist/cli/types.d.ts.map +1 -0
- package/dist/cli/types.js +11 -0
- package/dist/cli/types.js.map +1 -0
- package/dist/client/index.d.ts +10 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +10 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client/list-browsable-adapters.d.ts +31 -0
- package/dist/client/list-browsable-adapters.d.ts.map +1 -0
- package/dist/client/list-browsable-adapters.js +40 -0
- package/dist/client/list-browsable-adapters.js.map +1 -0
- package/dist/daemon/commands/sync.d.ts +23 -0
- package/dist/daemon/commands/sync.d.ts.map +1 -0
- package/dist/daemon/commands/sync.js +169 -0
- package/dist/daemon/commands/sync.js.map +1 -0
- package/dist/docs/adapters.docs.descriptor.d.ts +4 -0
- package/dist/docs/adapters.docs.descriptor.d.ts.map +1 -0
- package/dist/docs/adapters.docs.descriptor.js +223 -0
- package/dist/docs/adapters.docs.descriptor.js.map +1 -0
- package/dist/docs/manifests.docs.descriptor.d.ts +4 -0
- package/dist/docs/manifests.docs.descriptor.d.ts.map +1 -0
- package/dist/docs/manifests.docs.descriptor.js +316 -0
- package/dist/docs/manifests.docs.descriptor.js.map +1 -0
- package/dist/docs/records.docs.descriptor.d.ts +4 -0
- package/dist/docs/records.docs.descriptor.d.ts.map +1 -0
- package/dist/docs/records.docs.descriptor.js +269 -0
- package/dist/docs/records.docs.descriptor.js.map +1 -0
- package/dist/docs/sync.docs.descriptor.d.ts +4 -0
- package/dist/docs/sync.docs.descriptor.d.ts.map +1 -0
- package/dist/docs/sync.docs.descriptor.js +279 -0
- package/dist/docs/sync.docs.descriptor.js.map +1 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +29 -0
- package/dist/index.js.map +1 -0
- package/dist/interfaces/adapter.d.ts +382 -0
- package/dist/interfaces/adapter.d.ts.map +1 -0
- package/dist/interfaces/adapter.js +11 -0
- package/dist/interfaces/adapter.js.map +1 -0
- package/dist/interfaces/document-store.d.ts +62 -0
- package/dist/interfaces/document-store.d.ts.map +1 -0
- package/dist/interfaces/document-store.js +8 -0
- package/dist/interfaces/document-store.js.map +1 -0
- package/dist/interfaces/index.d.ts +17 -0
- package/dist/interfaces/index.d.ts.map +1 -0
- package/dist/interfaces/index.js +24 -0
- package/dist/interfaces/index.js.map +1 -0
- package/dist/interfaces/key-value.d.ts +95 -0
- package/dist/interfaces/key-value.d.ts.map +1 -0
- package/dist/interfaces/key-value.js +8 -0
- package/dist/interfaces/key-value.js.map +1 -0
- package/dist/interfaces/query-builder.d.ts +31 -0
- package/dist/interfaces/query-builder.d.ts.map +1 -0
- package/dist/interfaces/query-builder.js +11 -0
- package/dist/interfaces/query-builder.js.map +1 -0
- package/dist/interfaces/record/index.d.ts +7 -0
- package/dist/interfaces/record/index.d.ts.map +1 -0
- package/dist/interfaces/record/index.js +7 -0
- package/dist/interfaces/record/index.js.map +1 -0
- package/dist/interfaces/record/interface.d.ts +593 -0
- package/dist/interfaces/record/interface.d.ts.map +1 -0
- package/dist/interfaces/record/interface.js +49 -0
- package/dist/interfaces/record/interface.js.map +1 -0
- package/dist/interfaces/repository.d.ts +262 -0
- package/dist/interfaces/repository.d.ts.map +1 -0
- package/dist/interfaces/repository.js +8 -0
- package/dist/interfaces/repository.js.map +1 -0
- package/dist/interfaces/schema/index.d.ts +8 -0
- package/dist/interfaces/schema/index.d.ts.map +1 -0
- package/dist/interfaces/schema/index.js +10 -0
- package/dist/interfaces/schema/index.js.map +1 -0
- package/dist/interfaces/schema/schema-interface.d.ts +516 -0
- package/dist/interfaces/schema/schema-interface.d.ts.map +1 -0
- package/dist/interfaces/schema/schema-interface.js +31 -0
- package/dist/interfaces/schema/schema-interface.js.map +1 -0
- package/dist/interfaces/schema/table-interface.d.ts +250 -0
- package/dist/interfaces/schema/table-interface.d.ts.map +1 -0
- package/dist/interfaces/schema/table-interface.js +31 -0
- package/dist/interfaces/schema/table-interface.js.map +1 -0
- package/dist/interfaces/storage-consumer-fs.d.ts +40 -0
- package/dist/interfaces/storage-consumer-fs.d.ts.map +1 -0
- package/dist/interfaces/storage-consumer-fs.js +42 -0
- package/dist/interfaces/storage-consumer-fs.js.map +1 -0
- package/dist/manifest/base.d.ts +187 -0
- package/dist/manifest/base.d.ts.map +1 -0
- package/dist/manifest/base.js +516 -0
- package/dist/manifest/base.js.map +1 -0
- package/dist/manifest/cloud-sync.consumer.d.ts +7 -0
- package/dist/manifest/cloud-sync.consumer.d.ts.map +1 -0
- package/dist/manifest/cloud-sync.consumer.js +82 -0
- package/dist/manifest/cloud-sync.consumer.js.map +1 -0
- package/dist/manifest/index.d.ts +7 -0
- package/dist/manifest/index.d.ts.map +1 -0
- package/dist/manifest/index.js +7 -0
- package/dist/manifest/index.js.map +1 -0
- package/dist/manifest/source-policy.d.ts +8 -0
- package/dist/manifest/source-policy.d.ts.map +1 -0
- package/dist/manifest/source-policy.js +62 -0
- package/dist/manifest/source-policy.js.map +1 -0
- package/dist/paths.d.ts +6 -0
- package/dist/paths.d.ts.map +1 -0
- package/dist/paths.js +152 -0
- package/dist/paths.js.map +1 -0
- package/dist/policy/context.d.ts +9 -0
- package/dist/policy/context.d.ts.map +1 -0
- package/dist/policy/context.js +29 -0
- package/dist/policy/context.js.map +1 -0
- package/dist/policy/index.d.ts +4 -0
- package/dist/policy/index.d.ts.map +1 -0
- package/dist/policy/index.js +4 -0
- package/dist/policy/index.js.map +1 -0
- package/dist/policy/overrides.d.ts +40 -0
- package/dist/policy/overrides.d.ts.map +1 -0
- package/dist/policy/overrides.js +37 -0
- package/dist/policy/overrides.js.map +1 -0
- package/dist/policy/persistence.d.ts +38 -0
- package/dist/policy/persistence.d.ts.map +1 -0
- package/dist/policy/persistence.js +65 -0
- package/dist/policy/persistence.js.map +1 -0
- package/dist/policy/types.d.ts +21 -0
- package/dist/policy/types.d.ts.map +1 -0
- package/dist/policy/types.js +7 -0
- package/dist/policy/types.js.map +1 -0
- package/dist/record/base.d.ts +186 -0
- package/dist/record/base.d.ts.map +1 -0
- package/dist/record/base.js +1437 -0
- package/dist/record/base.js.map +1 -0
- package/dist/record/events.d.ts +71 -0
- package/dist/record/events.d.ts.map +1 -0
- package/dist/record/events.js +52 -0
- package/dist/record/events.js.map +1 -0
- package/dist/record/extensions.d.ts +51 -0
- package/dist/record/extensions.d.ts.map +1 -0
- package/dist/record/extensions.js +222 -0
- package/dist/record/extensions.js.map +1 -0
- package/dist/record/index.d.ts +7 -0
- package/dist/record/index.d.ts.map +1 -0
- package/dist/record/index.js +7 -0
- package/dist/record/index.js.map +1 -0
- package/dist/resolver/storage-backed-resolver.d.ts +23 -0
- package/dist/resolver/storage-backed-resolver.d.ts.map +1 -0
- package/dist/resolver/storage-backed-resolver.js +187 -0
- package/dist/resolver/storage-backed-resolver.js.map +1 -0
- package/dist/schemas/adapter-descriptor.d.ts +108 -0
- package/dist/schemas/adapter-descriptor.d.ts.map +1 -0
- package/dist/schemas/adapter-descriptor.js +101 -0
- package/dist/schemas/adapter-descriptor.js.map +1 -0
- package/dist/schemas/index.d.ts +14 -0
- package/dist/schemas/index.d.ts.map +1 -0
- package/dist/schemas/index.js +12 -0
- package/dist/schemas/index.js.map +1 -0
- package/dist/schemas/manifest-descriptor.d.ts +110 -0
- package/dist/schemas/manifest-descriptor.d.ts.map +1 -0
- package/dist/schemas/manifest-descriptor.js +114 -0
- package/dist/schemas/manifest-descriptor.js.map +1 -0
- package/dist/schemas/record/descriptor.d.ts +570 -0
- package/dist/schemas/record/descriptor.d.ts.map +1 -0
- package/dist/schemas/record/descriptor.js +389 -0
- package/dist/schemas/record/descriptor.js.map +1 -0
- package/dist/schemas/record/index.d.ts +8 -0
- package/dist/schemas/record/index.d.ts.map +1 -0
- package/dist/schemas/record/index.js +7 -0
- package/dist/schemas/record/index.js.map +1 -0
- package/dist/schemas/record/relation.d.ts +36 -0
- package/dist/schemas/record/relation.d.ts.map +1 -0
- package/dist/schemas/record/relation.js +37 -0
- package/dist/schemas/record/relation.js.map +1 -0
- package/dist/schemas/schema/descriptor.d.ts +231 -0
- package/dist/schemas/schema/descriptor.d.ts.map +1 -0
- package/dist/schemas/schema/descriptor.js +205 -0
- package/dist/schemas/schema/descriptor.js.map +1 -0
- package/dist/schemas/schema/index.d.ts +7 -0
- package/dist/schemas/schema/index.d.ts.map +1 -0
- package/dist/schemas/schema/index.js +7 -0
- package/dist/schemas/schema/index.js.map +1 -0
- package/dist/schemas/sync-bridge-descriptor.d.ts +124 -0
- package/dist/schemas/sync-bridge-descriptor.d.ts.map +1 -0
- package/dist/schemas/sync-bridge-descriptor.js +67 -0
- package/dist/schemas/sync-bridge-descriptor.js.map +1 -0
- package/dist/server/manifest-route.d.ts +92 -0
- package/dist/server/manifest-route.d.ts.map +1 -0
- package/dist/server/manifest-route.js +226 -0
- package/dist/server/manifest-route.js.map +1 -0
- package/dist/storage-policy.context.descriptor.d.ts +16 -0
- package/dist/storage-policy.context.descriptor.d.ts.map +1 -0
- package/dist/storage-policy.context.descriptor.js +16 -0
- package/dist/storage-policy.context.descriptor.js.map +1 -0
- package/dist/storage-policy.context.server.d.ts +14 -0
- package/dist/storage-policy.context.server.d.ts.map +1 -0
- package/dist/storage-policy.context.server.js +27 -0
- package/dist/storage-policy.context.server.js.map +1 -0
- package/dist/storage.plugin.d.ts +38 -0
- package/dist/storage.plugin.d.ts.map +1 -0
- package/dist/storage.plugin.js +204 -0
- package/dist/storage.plugin.js.map +1 -0
- package/dist/sync/cloud-pull.d.ts +15 -0
- package/dist/sync/cloud-pull.d.ts.map +1 -0
- package/dist/sync/cloud-pull.js +130 -0
- package/dist/sync/cloud-pull.js.map +1 -0
- package/dist/sync/cloud-record-crud-config.d.ts +19 -0
- package/dist/sync/cloud-record-crud-config.d.ts.map +1 -0
- package/dist/sync/cloud-record-crud-config.js +22 -0
- package/dist/sync/cloud-record-crud-config.js.map +1 -0
- package/dist/sync/record-sync-bridge.d.ts +5 -0
- package/dist/sync/record-sync-bridge.d.ts.map +1 -0
- package/dist/sync/record-sync-bridge.js +121 -0
- package/dist/sync/record-sync-bridge.js.map +1 -0
- package/dist/sync/resolve-sync-target.d.ts +23 -0
- package/dist/sync/resolve-sync-target.d.ts.map +1 -0
- package/dist/sync/resolve-sync-target.js +45 -0
- package/dist/sync/resolve-sync-target.js.map +1 -0
- package/dist/sync/schemas/cloud-pull.d.ts +25 -0
- package/dist/sync/schemas/cloud-pull.d.ts.map +1 -0
- package/dist/sync/schemas/cloud-pull.js +7 -0
- package/dist/sync/schemas/cloud-pull.js.map +1 -0
- package/dist/sync/schemas/index.d.ts +9 -0
- package/dist/sync/schemas/index.d.ts.map +1 -0
- package/dist/sync/schemas/index.js +9 -0
- package/dist/sync/schemas/index.js.map +1 -0
- package/dist/sync/schemas/sync-helpers.d.ts +17 -0
- package/dist/sync/schemas/sync-helpers.d.ts.map +1 -0
- package/dist/sync/schemas/sync-helpers.js +7 -0
- package/dist/sync/schemas/sync-helpers.js.map +1 -0
- package/dist/sync/schemas/sync-state.d.ts +65 -0
- package/dist/sync/schemas/sync-state.d.ts.map +1 -0
- package/dist/sync/schemas/sync-state.js +32 -0
- package/dist/sync/schemas/sync-state.js.map +1 -0
- package/dist/sync/sync-bridge.d.ts +80 -0
- package/dist/sync/sync-bridge.d.ts.map +1 -0
- package/dist/sync/sync-bridge.js +617 -0
- package/dist/sync/sync-bridge.js.map +1 -0
- package/dist/sync/sync-manifest.d.ts +20 -0
- package/dist/sync/sync-manifest.d.ts.map +1 -0
- package/dist/sync/sync-manifest.js +140 -0
- package/dist/sync/sync-manifest.js.map +1 -0
- package/dist/sync/sync-state.consumer.d.ts +23 -0
- package/dist/sync/sync-state.consumer.d.ts.map +1 -0
- package/dist/sync/sync-state.consumer.js +111 -0
- package/dist/sync/sync-state.consumer.js.map +1 -0
- package/dist/transform/index.d.ts +75 -0
- package/dist/transform/index.d.ts.map +1 -0
- package/dist/transform/index.js +81 -0
- package/dist/transform/index.js.map +1 -0
- package/dist/transform/transform-descriptor.d.ts +51 -0
- package/dist/transform/transform-descriptor.d.ts.map +1 -0
- package/dist/transform/transform-descriptor.js +30 -0
- package/dist/transform/transform-descriptor.js.map +1 -0
- package/dist/tui/storage-explorer.descriptor.d.ts +14 -0
- package/dist/tui/storage-explorer.descriptor.d.ts.map +1 -0
- package/dist/tui/storage-explorer.descriptor.js +29 -0
- package/dist/tui/storage-explorer.descriptor.js.map +1 -0
- package/dist/tui/storage-explorer.impl.consumer.d.ts +11 -0
- package/dist/tui/storage-explorer.impl.consumer.d.ts.map +1 -0
- package/dist/tui/storage-explorer.impl.consumer.js +13 -0
- package/dist/tui/storage-explorer.impl.consumer.js.map +1 -0
- package/dist/tui/storage-open.descriptor.d.ts +14 -0
- package/dist/tui/storage-open.descriptor.d.ts.map +1 -0
- package/dist/tui/storage-open.descriptor.js +28 -0
- package/dist/tui/storage-open.descriptor.js.map +1 -0
- package/dist/tui/storage-open.impl.consumer.d.ts +11 -0
- package/dist/tui/storage-open.impl.consumer.d.ts.map +1 -0
- package/dist/tui/storage-open.impl.consumer.js +13 -0
- package/dist/tui/storage-open.impl.consumer.js.map +1 -0
- package/dist/utils/error-context.d.ts +2 -0
- package/dist/utils/error-context.d.ts.map +1 -0
- package/dist/utils/error-context.js +17 -0
- package/dist/utils/error-context.js.map +1 -0
- package/package.json +241 -0
- package/src/adapters/index.ts +13 -0
- package/src/bridge/index.ts +2 -0
- package/src/bridge/storage-kind-bridge.ts +131 -0
- package/src/bridge/types.ts +46 -0
- package/src/cli/commands/list/storage.list.cli-command.descriptor.ts +20 -0
- package/src/cli/commands/list/storage.list.cli-command.impl.ts +72 -0
- package/src/cli/commands/sync/pull/storage.sync.pull.cli-command.descriptor.ts +28 -0
- package/src/cli/commands/sync/pull/storage.sync.pull.cli-command.impl.ts +171 -0
- package/src/cli/commands/sync/push/storage.sync.push.cli-command.descriptor.ts +28 -0
- package/src/cli/commands/sync/push/storage.sync.push.cli-command.impl.ts +213 -0
- package/src/cli/commands/sync/resolve/storage.sync.resolve.cli-command.descriptor.ts +22 -0
- package/src/cli/commands/sync/resolve/storage.sync.resolve.cli-command.impl.ts +129 -0
- package/src/cli/commands/sync/status/storage.sync.status.cli-command.descriptor.ts +17 -0
- package/src/cli/commands/sync/status/storage.sync.status.cli-command.impl.ts +192 -0
- package/src/cli/context.consumer.ts +195 -0
- package/src/cli/storage.cli-group.descriptor.ts +13 -0
- package/src/cli/storage.sync.cli-group.descriptor.ts +14 -0
- package/src/cli/types.ts +25 -0
- package/src/client/index.ts +10 -0
- package/src/client/list-browsable-adapters.ts +42 -0
- package/src/daemon/commands/sync.ts +225 -0
- package/src/docs/adapters.docs.descriptor.ts +225 -0
- package/src/docs/manifests.docs.descriptor.ts +318 -0
- package/src/docs/records.docs.descriptor.ts +271 -0
- package/src/docs/sync.docs.descriptor.ts +281 -0
- package/src/index.ts +109 -0
- package/src/interfaces/adapter.ts +451 -0
- package/src/interfaces/document-store.ts +74 -0
- package/src/interfaces/index.ts +117 -0
- package/src/interfaces/key-value.ts +112 -0
- package/src/interfaces/query-builder.ts +31 -0
- package/src/interfaces/record/index.ts +58 -0
- package/src/interfaces/record/interface.ts +723 -0
- package/src/interfaces/repository.ts +300 -0
- package/src/interfaces/schema/index.ts +37 -0
- package/src/interfaces/schema/schema-interface.ts +586 -0
- package/src/interfaces/schema/table-interface.ts +314 -0
- package/src/interfaces/storage-consumer-fs.ts +66 -0
- package/src/manifest/base.ts +594 -0
- package/src/manifest/cloud-sync.consumer.ts +120 -0
- package/src/manifest/index.ts +7 -0
- package/src/manifest/source-policy.ts +74 -0
- package/src/paths.ts +171 -0
- package/src/policy/context.ts +30 -0
- package/src/policy/index.ts +20 -0
- package/src/policy/overrides.ts +46 -0
- package/src/policy/persistence.ts +117 -0
- package/src/policy/types.ts +28 -0
- package/src/record/base.ts +1872 -0
- package/src/record/events.ts +56 -0
- package/src/record/extensions.ts +308 -0
- package/src/record/index.ts +7 -0
- package/src/resolver/storage-backed-resolver.ts +255 -0
- package/src/schemas/adapter-descriptor.ts +128 -0
- package/src/schemas/index.ts +104 -0
- package/src/schemas/manifest-descriptor.ts +143 -0
- package/src/schemas/record/descriptor.ts +621 -0
- package/src/schemas/record/index.ts +60 -0
- package/src/schemas/record/relation.ts +49 -0
- package/src/schemas/schema/descriptor.ts +278 -0
- package/src/schemas/schema/index.ts +14 -0
- package/src/schemas/sync-bridge-descriptor.ts +143 -0
- package/src/server/manifest-route.ts +319 -0
- package/src/storage-policy.context.descriptor.ts +17 -0
- package/src/storage-policy.context.server.ts +34 -0
- package/src/storage.plugin.ts +264 -0
- package/src/sync/cloud-pull.ts +202 -0
- package/src/sync/cloud-record-crud-config.ts +41 -0
- package/src/sync/record-sync-bridge.ts +183 -0
- package/src/sync/resolve-sync-target.ts +57 -0
- package/src/sync/schemas/cloud-pull.ts +26 -0
- package/src/sync/schemas/index.ts +18 -0
- package/src/sync/schemas/sync-helpers.ts +18 -0
- package/src/sync/schemas/sync-state.ts +41 -0
- package/src/sync/sync-bridge.ts +763 -0
- package/src/sync/sync-manifest.ts +212 -0
- package/src/sync/sync-state.consumer.ts +144 -0
- package/src/transform/index.ts +130 -0
- package/src/transform/transform-descriptor.ts +53 -0
- package/src/tui/storage-explorer.descriptor.ts +32 -0
- package/src/tui/storage-explorer.impl.consumer.ts +14 -0
- package/src/tui/storage-open.descriptor.ts +31 -0
- package/src/tui/storage-open.impl.consumer.ts +14 -0
- package/src/utils/error-context.ts +19 -0
|
@@ -0,0 +1,594 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Storage Manifest Base Class
|
|
3
|
+
*
|
|
4
|
+
* Base class for working with stored data. Modules can extend this
|
|
5
|
+
* for custom methods while getting load/save for free.
|
|
6
|
+
*
|
|
7
|
+
* Uses runtime query API to resolve the appropriate adapter.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type { z } from 'zod/v4';
|
|
11
|
+
import { getLogger } from '@vibesdotdev/logging';
|
|
12
|
+
import { getVibesRuntime } from '@vibesdotdev/runtime/api/runtime';
|
|
13
|
+
import type { KindContext } from '@vibesdotdev/runtime/schemas/kind';
|
|
14
|
+
import type { StorageAdapterInterface } from '../interfaces/adapter';
|
|
15
|
+
import type { StorageAdapterDescriptor } from '../schemas/adapter-descriptor';
|
|
16
|
+
import type { StorageManifestDescriptor } from '../schemas/manifest-descriptor';
|
|
17
|
+
import type { DocumentChangeCallback, Unsubscribe } from '../interfaces/document-store';
|
|
18
|
+
import { createTracer } from '@vibesdotdev/runtime/debug';
|
|
19
|
+
import { isBuildingEnvironment } from '@vibesdotdev/runtime';
|
|
20
|
+
import { resolveHomePath, resolveScopePathTemplate, resolveWorkspacePath } from '../paths';
|
|
21
|
+
import { toErrorContext } from '../utils/error-context';
|
|
22
|
+
|
|
23
|
+
const logger = getLogger('storage:manifest');
|
|
24
|
+
|
|
25
|
+
type RuntimeLike = ReturnType<typeof getVibesRuntime>;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Base class for storage manifests.
|
|
29
|
+
*
|
|
30
|
+
* Provides document-style operations (load, save, exists, delete) using
|
|
31
|
+
* the runtime to resolve the appropriate adapter based on scope and configuration.
|
|
32
|
+
*
|
|
33
|
+
* Includes caching and subscription support for reactive updates.
|
|
34
|
+
*
|
|
35
|
+
* @template T - The type of data being stored
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* ```ts
|
|
39
|
+
* // Runtime instantiation (via descriptor)
|
|
40
|
+
* // The runtime will instantiate this with the descriptor
|
|
41
|
+
*
|
|
42
|
+
* // Manual instantiation by ID
|
|
43
|
+
* const storage = StorageManifest.fromId<AIProvider[]>('ai.providers');
|
|
44
|
+
* const providers = await storage.load();
|
|
45
|
+
*
|
|
46
|
+
* // Extended class with custom methods
|
|
47
|
+
* class AIProvidersStorage extends StorageManifest<AIProvider[]> {
|
|
48
|
+
* async getEnabled(): Promise<AIProvider[]> {
|
|
49
|
+
* const all = await this.load() ?? [];
|
|
50
|
+
* return all.filter(p => p.enabled);
|
|
51
|
+
* }
|
|
52
|
+
* }
|
|
53
|
+
* ```
|
|
54
|
+
*/
|
|
55
|
+
export class StorageManifest<T> {
|
|
56
|
+
protected descriptor!: StorageManifestDescriptor;
|
|
57
|
+
protected context!: KindContext;
|
|
58
|
+
private adapterCache: StorageAdapterInterface | null = null;
|
|
59
|
+
|
|
60
|
+
// Lazy resolution
|
|
61
|
+
private pendingId: string | null = null;
|
|
62
|
+
private pendingContext: KindContext | undefined;
|
|
63
|
+
private resolved = false;
|
|
64
|
+
|
|
65
|
+
// Caching
|
|
66
|
+
private cachedData: T | null = null;
|
|
67
|
+
private cacheValid = false;
|
|
68
|
+
|
|
69
|
+
// Subscriptions
|
|
70
|
+
private subscribers = new Set<(data: T | null) => void>();
|
|
71
|
+
private storeUnsubscribe: Unsubscribe | null = null;
|
|
72
|
+
private subscriptionStarted = false;
|
|
73
|
+
|
|
74
|
+
private getRuntime(): RuntimeLike {
|
|
75
|
+
return (this.context.runtime as RuntimeLike | undefined) ?? getVibesRuntime();
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Create a storage manifest instance.
|
|
80
|
+
*
|
|
81
|
+
* @param descriptorOrId - Either the full descriptor (for runtime instantiation)
|
|
82
|
+
* or the manifest ID string (for manual instantiation)
|
|
83
|
+
* @param context - Runtime context (optional for manual instantiation, required for runtime)
|
|
84
|
+
*/
|
|
85
|
+
constructor(descriptorOrId: StorageManifestDescriptor | string, context?: KindContext) {
|
|
86
|
+
if (typeof descriptorOrId === 'string') {
|
|
87
|
+
// Defer descriptor resolution so module-level singletons don't crash
|
|
88
|
+
// when imported before the runtime is bootstrapped (e.g. SSR imports).
|
|
89
|
+
this.pendingId = descriptorOrId;
|
|
90
|
+
this.pendingContext = context;
|
|
91
|
+
// Set stub descriptor so property accesses before resolve don't throw
|
|
92
|
+
this.descriptor = {
|
|
93
|
+
id: descriptorOrId,
|
|
94
|
+
kind: 'storage/manifest',
|
|
95
|
+
namespace: descriptorOrId
|
|
96
|
+
} as StorageManifestDescriptor;
|
|
97
|
+
this.context = context ?? { runtime: getVibesRuntime() };
|
|
98
|
+
} else {
|
|
99
|
+
// Direct descriptor (runtime instantiation)
|
|
100
|
+
this.descriptor = descriptorOrId;
|
|
101
|
+
this.context = context ?? { runtime: getVibesRuntime() };
|
|
102
|
+
this.resolved = true;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Resolve the descriptor from the runtime on first data access.
|
|
108
|
+
* No-op if already resolved or constructed with a direct descriptor.
|
|
109
|
+
*/
|
|
110
|
+
private ensureResolved(): void {
|
|
111
|
+
if (this.resolved || !this.pendingId) return;
|
|
112
|
+
|
|
113
|
+
const runtime =
|
|
114
|
+
(this.pendingContext?.runtime as RuntimeLike | undefined) ??
|
|
115
|
+
(this.context.runtime as RuntimeLike | undefined) ??
|
|
116
|
+
getVibesRuntime();
|
|
117
|
+
const hasKind = runtime.hasKind('storage/manifest');
|
|
118
|
+
|
|
119
|
+
if (!hasKind) {
|
|
120
|
+
// Runtime not yet bootstrapped — keep the stub descriptor.
|
|
121
|
+
// It will be re-resolved on next access after bootstrap.
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const descriptor = runtime
|
|
126
|
+
.query<StorageManifestDescriptor, unknown>('storage/manifest')
|
|
127
|
+
.filter((d: StorageManifestDescriptor) => d.id === this.pendingId)
|
|
128
|
+
.firstDescriptor();
|
|
129
|
+
|
|
130
|
+
if (!descriptor) {
|
|
131
|
+
if (isBuildingEnvironment()) return;
|
|
132
|
+
throw new Error(`Storage manifest '${this.pendingId}' not found. Is it registered?`);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
this.descriptor = descriptor;
|
|
136
|
+
this.context = this.pendingContext ?? { runtime };
|
|
137
|
+
this.resolved = true;
|
|
138
|
+
this.pendingId = null;
|
|
139
|
+
this.pendingContext = undefined;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Create a storage manifest by looking up its ID.
|
|
144
|
+
* Convenience static method for manual instantiation.
|
|
145
|
+
*/
|
|
146
|
+
static fromId<T>(manifestId: string): StorageManifest<T> {
|
|
147
|
+
return new StorageManifest<T>(manifestId);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Get the schema for this manifest.
|
|
152
|
+
*/
|
|
153
|
+
get schema(): z.ZodType<T> {
|
|
154
|
+
this.ensureResolved();
|
|
155
|
+
return this.descriptor.schema as z.ZodType<T>;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Get the namespace for this manifest.
|
|
160
|
+
*/
|
|
161
|
+
get namespace(): string {
|
|
162
|
+
this.ensureResolved();
|
|
163
|
+
return this.descriptor.namespace;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Resolve the adapter for this manifest using runtime query API.
|
|
168
|
+
*
|
|
169
|
+
* Uses the manifest's allowed adapters list and current scope to
|
|
170
|
+
* select the best available adapter.
|
|
171
|
+
*/
|
|
172
|
+
protected async getAdapter(): Promise<StorageAdapterInterface> {
|
|
173
|
+
this.ensureResolved();
|
|
174
|
+
|
|
175
|
+
if (!this.resolved) {
|
|
176
|
+
throw new Error(
|
|
177
|
+
`Storage manifest '${this.descriptor.id}' is not yet resolved. ` +
|
|
178
|
+
`The runtime may not be bootstrapped. Ensure 'storage/manifest' kind is registered before accessing storage.`
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// Adapters are runtime singletons, so manifest-specific configuration
|
|
183
|
+
// must be re-applied on every access before reuse.
|
|
184
|
+
if (this.adapterCache) {
|
|
185
|
+
this.adapterCache.configure(this.getAdapterConfig());
|
|
186
|
+
return this.adapterCache;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const adapterTracer = createTracer(`adapter:${this.descriptor.id}`);
|
|
190
|
+
adapterTracer.start();
|
|
191
|
+
|
|
192
|
+
const runtime = this.getRuntime();
|
|
193
|
+
let adapter: StorageAdapterInterface | null = null;
|
|
194
|
+
let adapterId: string = '';
|
|
195
|
+
|
|
196
|
+
// Prefer explicit default adapter when available for current hardware.
|
|
197
|
+
if (
|
|
198
|
+
this.descriptor.defaultAdapter &&
|
|
199
|
+
this.descriptor.allowedAdapters.includes(this.descriptor.defaultAdapter)
|
|
200
|
+
) {
|
|
201
|
+
adapterId = this.descriptor.defaultAdapter;
|
|
202
|
+
try {
|
|
203
|
+
adapter = await runtime
|
|
204
|
+
.query<StorageAdapterDescriptor, StorageAdapterInterface>('storage/adapter')
|
|
205
|
+
.withId(adapterId)
|
|
206
|
+
.enabled()
|
|
207
|
+
.resolve();
|
|
208
|
+
} catch {
|
|
209
|
+
// Default adapter not registered or unavailable — fall through to allowed adapters
|
|
210
|
+
adapter = null;
|
|
211
|
+
adapterId = '';
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// Fallback to first available adapter
|
|
216
|
+
if (!adapter) {
|
|
217
|
+
for (const allowedId of this.descriptor.allowedAdapters) {
|
|
218
|
+
try {
|
|
219
|
+
adapter = await runtime
|
|
220
|
+
.query<StorageAdapterDescriptor, StorageAdapterInterface>('storage/adapter')
|
|
221
|
+
.withId(allowedId)
|
|
222
|
+
.enabled()
|
|
223
|
+
.resolve();
|
|
224
|
+
adapterId = allowedId;
|
|
225
|
+
break;
|
|
226
|
+
} catch {
|
|
227
|
+
continue;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
if (!adapter || !adapterId) {
|
|
233
|
+
throw new Error(
|
|
234
|
+
`No available adapter for manifest '${this.descriptor.id}'. Checked: ${this.descriptor.allowedAdapters.join(', ')}`
|
|
235
|
+
);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// Adapters are shared across manifests. Always apply this manifest's
|
|
239
|
+
// configuration before use so filename/basePath overrides stay isolated.
|
|
240
|
+
const config = this.getAdapterConfig(adapterId);
|
|
241
|
+
adapter.configure(config);
|
|
242
|
+
|
|
243
|
+
// Register per-manifest cloud endpoint overrides so cloud-api uses
|
|
244
|
+
// descriptor endpoints (e.g. /api/storage/chat/rooms) instead of the
|
|
245
|
+
// namespace fallback (/api/storage/chat.rooms).
|
|
246
|
+
if (adapterId === 'storage.cloud-api') {
|
|
247
|
+
const cloudEndpoint = this.getCloudApiEndpoint();
|
|
248
|
+
if (cloudEndpoint && this.hasCloudEndpointRegistrar(adapter)) {
|
|
249
|
+
adapter.registerEndpoint(this.descriptor.namespace, cloudEndpoint);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// Cache adapter but don't initialize yet
|
|
254
|
+
// Initialization will happen on first data access
|
|
255
|
+
this.adapterCache = adapter;
|
|
256
|
+
adapterTracer.end('resolved');
|
|
257
|
+
return adapter;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Get adapter configuration based on manifest scope.
|
|
262
|
+
* Override in subclasses for custom configuration.
|
|
263
|
+
*/
|
|
264
|
+
protected getAdapterConfig(adapterId?: string): Record<string, unknown> {
|
|
265
|
+
const workspacePath = resolveWorkspacePath(this.context);
|
|
266
|
+
const config: Record<string, unknown> = {
|
|
267
|
+
basePath: this.getBasePath(workspacePath),
|
|
268
|
+
workspacePath
|
|
269
|
+
};
|
|
270
|
+
|
|
271
|
+
// Pass through descriptor-level flags that adapters need
|
|
272
|
+
if (this.descriptor.customTables) {
|
|
273
|
+
config.customTables = true;
|
|
274
|
+
}
|
|
275
|
+
if (this.descriptor.migrationKey) {
|
|
276
|
+
config.migrationKey = this.descriptor.migrationKey;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// Pass through adapter-specific config from descriptor
|
|
280
|
+
if (this.descriptor.adapterConfig) {
|
|
281
|
+
const selectedAdapterId =
|
|
282
|
+
adapterId || this.descriptor.defaultAdapter || this.descriptor.allowedAdapters[0];
|
|
283
|
+
const adapterSpecificConfig = this.descriptor.adapterConfig[selectedAdapterId];
|
|
284
|
+
if (adapterSpecificConfig && typeof adapterSpecificConfig === 'object') {
|
|
285
|
+
Object.assign(config, adapterSpecificConfig);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
// Backward-compatible normalization for cloud adapter manifests.
|
|
289
|
+
// Only promote endpoint -> apiEndpoint when endpoint is a full URL.
|
|
290
|
+
if (
|
|
291
|
+
selectedAdapterId === 'storage.cloud-api' &&
|
|
292
|
+
typeof config.endpoint === 'string' &&
|
|
293
|
+
typeof config.apiEndpoint !== 'string' &&
|
|
294
|
+
config.endpoint.startsWith('http')
|
|
295
|
+
) {
|
|
296
|
+
config.apiEndpoint = config.endpoint;
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
return config;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
private getCloudApiEndpoint(): string | null {
|
|
304
|
+
const raw = this.descriptor.adapterConfig?.['storage.cloud-api'];
|
|
305
|
+
if (!raw || typeof raw !== 'object') return null;
|
|
306
|
+
const endpoint = (raw as Record<string, unknown>).endpoint;
|
|
307
|
+
return typeof endpoint === 'string' && endpoint.length > 0 ? endpoint : null;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
private hasCloudEndpointRegistrar(
|
|
311
|
+
adapter: StorageAdapterInterface
|
|
312
|
+
): adapter is StorageAdapterInterface & {
|
|
313
|
+
registerEndpoint(namespace: string, endpoint: string): void;
|
|
314
|
+
} {
|
|
315
|
+
return typeof (adapter as unknown as Record<string, unknown>).registerEndpoint === 'function';
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* Get base path for storage based on scope.
|
|
320
|
+
* Uses descriptor's scopePaths if provided, otherwise defaults.
|
|
321
|
+
*/
|
|
322
|
+
protected getBasePath(workspacePath = resolveWorkspacePath(this.context)): string {
|
|
323
|
+
const home = resolveHomePath();
|
|
324
|
+
const scope = this.descriptor.scope;
|
|
325
|
+
|
|
326
|
+
// Use custom scope paths if provided
|
|
327
|
+
if (this.descriptor.scopePaths) {
|
|
328
|
+
const customPath = this.descriptor.scopePaths[scope as 'global' | 'project' | 'local'];
|
|
329
|
+
if (customPath) {
|
|
330
|
+
return resolveScopePathTemplate(customPath, workspacePath);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
// Default path resolution
|
|
335
|
+
switch (scope) {
|
|
336
|
+
case 'global':
|
|
337
|
+
return `${home}/.vibes/storage`;
|
|
338
|
+
case 'project':
|
|
339
|
+
case 'local':
|
|
340
|
+
return `${workspacePath}/.vibes/storage`;
|
|
341
|
+
case 'auto':
|
|
342
|
+
default:
|
|
343
|
+
return `${workspacePath}/.vibes/storage`;
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
// Caching
|
|
348
|
+
|
|
349
|
+
/**
|
|
350
|
+
* Invalidate the cache, forcing the next load to hit storage.
|
|
351
|
+
*/
|
|
352
|
+
invalidateCache(): void {
|
|
353
|
+
this.cacheValid = false;
|
|
354
|
+
this.cachedData = null;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* Get cached data if available.
|
|
359
|
+
* @returns Cached data or undefined if not cached
|
|
360
|
+
*/
|
|
361
|
+
getCachedData(): T | undefined {
|
|
362
|
+
if (this.cacheValid) {
|
|
363
|
+
return this.cachedData ?? undefined;
|
|
364
|
+
}
|
|
365
|
+
return undefined;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
/**
|
|
369
|
+
* Check if data is currently cached.
|
|
370
|
+
*/
|
|
371
|
+
isCached(): boolean {
|
|
372
|
+
return this.cacheValid;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
// Document Operations
|
|
376
|
+
|
|
377
|
+
/**
|
|
378
|
+
* Load data from storage.
|
|
379
|
+
*
|
|
380
|
+
* @returns The stored data, or null if not found
|
|
381
|
+
*/
|
|
382
|
+
async load(): Promise<T | null> {
|
|
383
|
+
// Return cached data if valid
|
|
384
|
+
if (this.cacheValid) {
|
|
385
|
+
return this.cachedData;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
const adapter = await this.getAdapter();
|
|
389
|
+
const store = adapter.documentStore(this.descriptor.namespace, this.schema, this.descriptor);
|
|
390
|
+
const data = await store.load();
|
|
391
|
+
|
|
392
|
+
// Update cache
|
|
393
|
+
this.cachedData = data;
|
|
394
|
+
this.cacheValid = true;
|
|
395
|
+
|
|
396
|
+
// Start subscription if adapter supports it and not already started
|
|
397
|
+
if (!this.subscriptionStarted && store.subscribe) {
|
|
398
|
+
this.startSubscription(store.subscribe.bind(store));
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
return data;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
/**
|
|
405
|
+
* Save data to storage.
|
|
406
|
+
*
|
|
407
|
+
* @param data - The data to save
|
|
408
|
+
*/
|
|
409
|
+
async save(data: T): Promise<void> {
|
|
410
|
+
const adapter = await this.getAdapter();
|
|
411
|
+
const store = adapter.documentStore(this.descriptor.namespace, this.schema, this.descriptor);
|
|
412
|
+
await store.save(data);
|
|
413
|
+
|
|
414
|
+
// Update cache
|
|
415
|
+
this.cachedData = data;
|
|
416
|
+
this.cacheValid = true;
|
|
417
|
+
|
|
418
|
+
// Notify subscribers
|
|
419
|
+
this.notifySubscribers(data);
|
|
420
|
+
|
|
421
|
+
// Non-blocking cloud push when a consumer-local save needs to mirror to cloud.
|
|
422
|
+
this.triggerCloudSync(adapter.id, data);
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
/**
|
|
426
|
+
* Trigger a non-blocking cloud push after save.
|
|
427
|
+
* Only fires if the manifest has cloud-api in allowedAdapters.
|
|
428
|
+
*
|
|
429
|
+
* Consumer modules are loaded via opaque dynamic import to prevent Vite
|
|
430
|
+
* from tracing them into the client bundle — they contain Node.js APIs
|
|
431
|
+
* and must only run server-side.
|
|
432
|
+
*/
|
|
433
|
+
private triggerCloudSync(activeAdapterId: string, data: T): void {
|
|
434
|
+
if (!this.descriptor.allowedAdapters.includes('storage.cloud-api')) return;
|
|
435
|
+
if (activeAdapterId === 'storage.cloud-api') return;
|
|
436
|
+
if (this.getRuntime().scope.hardware === 'cloud') return;
|
|
437
|
+
|
|
438
|
+
const consumerSyncModule = './cloud-sync.consumer';
|
|
439
|
+
|
|
440
|
+
void import(/* @vite-ignore */ consumerSyncModule)
|
|
441
|
+
.then(({ pushManifestToCloudAfterLocalSave }) =>
|
|
442
|
+
pushManifestToCloudAfterLocalSave({
|
|
443
|
+
descriptor: this.descriptor,
|
|
444
|
+
data,
|
|
445
|
+
activeAdapterId
|
|
446
|
+
})
|
|
447
|
+
)
|
|
448
|
+
.catch(() => {
|
|
449
|
+
// Non-blocking: don't fail the save operation on sync errors.
|
|
450
|
+
});
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
/**
|
|
454
|
+
* Check if data exists in storage.
|
|
455
|
+
*/
|
|
456
|
+
async exists(): Promise<boolean> {
|
|
457
|
+
const adapter = await this.getAdapter();
|
|
458
|
+
const store = adapter.documentStore(this.descriptor.namespace, this.schema, this.descriptor);
|
|
459
|
+
return store.exists();
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
/**
|
|
463
|
+
* Delete data from storage.
|
|
464
|
+
*/
|
|
465
|
+
async delete(): Promise<void> {
|
|
466
|
+
const adapter = await this.getAdapter();
|
|
467
|
+
const store = adapter.documentStore(this.descriptor.namespace, this.schema, this.descriptor);
|
|
468
|
+
await store.delete();
|
|
469
|
+
|
|
470
|
+
// Clear cache
|
|
471
|
+
this.cachedData = null;
|
|
472
|
+
this.cacheValid = false;
|
|
473
|
+
|
|
474
|
+
// Notify subscribers
|
|
475
|
+
this.notifySubscribers(null);
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
/**
|
|
479
|
+
* Load data or return default value.
|
|
480
|
+
*
|
|
481
|
+
* @param defaultValue - Value to return if no data exists
|
|
482
|
+
*/
|
|
483
|
+
async loadOrDefault(defaultValue: T): Promise<T> {
|
|
484
|
+
const data = await this.load();
|
|
485
|
+
return data ?? defaultValue;
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
/**
|
|
489
|
+
* Update data using a transform function.
|
|
490
|
+
*
|
|
491
|
+
* @param transform - Function that receives current data and returns updated data
|
|
492
|
+
*/
|
|
493
|
+
async update(transform: (current: T | null) => T): Promise<void> {
|
|
494
|
+
const current = await this.load();
|
|
495
|
+
const updated = transform(current);
|
|
496
|
+
await this.save(updated);
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
/**
|
|
500
|
+
* Validate data against the manifest's schema.
|
|
501
|
+
*/
|
|
502
|
+
validate(data: unknown): z.ZodSafeParseResult<T> {
|
|
503
|
+
return this.schema.safeParse(data) as z.ZodSafeParseResult<T>;
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
// Subscriptions
|
|
507
|
+
|
|
508
|
+
/**
|
|
509
|
+
* Subscribe to changes for this manifest.
|
|
510
|
+
* Returns an unsubscribe function.
|
|
511
|
+
*
|
|
512
|
+
* @param callback - Function called when data changes
|
|
513
|
+
* @returns Unsubscribe function
|
|
514
|
+
*/
|
|
515
|
+
subscribe(callback: (data: T | null) => void): Unsubscribe {
|
|
516
|
+
this.subscribers.add(callback);
|
|
517
|
+
|
|
518
|
+
// Start storage-level subscription if not already started
|
|
519
|
+
if (!this.subscriptionStarted) {
|
|
520
|
+
this.initSubscription();
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
// Return unsubscribe function
|
|
524
|
+
return () => {
|
|
525
|
+
this.subscribers.delete(callback);
|
|
526
|
+
// Clean up storage subscription if no more subscribers
|
|
527
|
+
if (this.subscribers.size === 0) {
|
|
528
|
+
this.stopSubscription();
|
|
529
|
+
}
|
|
530
|
+
};
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
/**
|
|
534
|
+
* Initialize subscription to storage adapter.
|
|
535
|
+
*/
|
|
536
|
+
private async initSubscription(): Promise<void> {
|
|
537
|
+
if (this.subscriptionStarted) return;
|
|
538
|
+
|
|
539
|
+
const adapter = await this.getAdapter();
|
|
540
|
+
const store = adapter.documentStore(this.descriptor.namespace, this.schema, this.descriptor);
|
|
541
|
+
|
|
542
|
+
if (store.subscribe) {
|
|
543
|
+
this.startSubscription(store.subscribe.bind(store));
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
/**
|
|
548
|
+
* Start subscription with the given subscribe function.
|
|
549
|
+
*/
|
|
550
|
+
private startSubscription(subscribeFn: (cb: DocumentChangeCallback<T>) => Unsubscribe): void {
|
|
551
|
+
if (this.storeUnsubscribe) return;
|
|
552
|
+
|
|
553
|
+
this.storeUnsubscribe = subscribeFn((data) => {
|
|
554
|
+
// Update cache from external change
|
|
555
|
+
this.cachedData = data;
|
|
556
|
+
this.cacheValid = true;
|
|
557
|
+
// Notify our subscribers
|
|
558
|
+
this.notifySubscribers(data);
|
|
559
|
+
});
|
|
560
|
+
|
|
561
|
+
this.subscriptionStarted = true;
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
/**
|
|
565
|
+
* Stop storage-level subscription.
|
|
566
|
+
*/
|
|
567
|
+
private stopSubscription(): void {
|
|
568
|
+
if (this.storeUnsubscribe) {
|
|
569
|
+
this.storeUnsubscribe();
|
|
570
|
+
this.storeUnsubscribe = null;
|
|
571
|
+
}
|
|
572
|
+
this.subscriptionStarted = false;
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
/**
|
|
576
|
+
* Notify all subscribers of a change.
|
|
577
|
+
*/
|
|
578
|
+
protected notifySubscribers(data: T | null): void {
|
|
579
|
+
for (const callback of this.subscribers) {
|
|
580
|
+
try {
|
|
581
|
+
callback(data);
|
|
582
|
+
} catch (error) {
|
|
583
|
+
logger.error('Error in manifest subscriber:', toErrorContext(error));
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
/**
|
|
589
|
+
* Get the number of active subscribers.
|
|
590
|
+
*/
|
|
591
|
+
getSubscriberCount(): number {
|
|
592
|
+
return this.subscribers.size;
|
|
593
|
+
}
|
|
594
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { getVibesRuntime } from '@vibesdotdev/runtime/api/runtime';
|
|
2
|
+
import type { z } from 'zod/v4';
|
|
3
|
+
import type { StorageAdapterInterface } from '../interfaces/adapter';
|
|
4
|
+
import type { StorageAdapterDescriptor } from '../schemas/adapter-descriptor';
|
|
5
|
+
import type { StorageManifestDescriptor } from '../schemas/manifest-descriptor';
|
|
6
|
+
import {
|
|
7
|
+
computeHash,
|
|
8
|
+
loadSyncState,
|
|
9
|
+
markError,
|
|
10
|
+
markLocalAhead,
|
|
11
|
+
markSynced,
|
|
12
|
+
saveSyncState
|
|
13
|
+
} from '../sync/sync-state.consumer';
|
|
14
|
+
|
|
15
|
+
const REMOTE_ADAPTER_IDS = new Set(['storage.cloud-api', 'storage.drizzle']);
|
|
16
|
+
|
|
17
|
+
function getCloudEndpoint(descriptor: StorageManifestDescriptor): string | null {
|
|
18
|
+
const raw = descriptor.adapterConfig?.['storage.cloud-api'];
|
|
19
|
+
if (!raw || typeof raw !== 'object') return null;
|
|
20
|
+
const endpoint = (raw as Record<string, unknown>).endpoint;
|
|
21
|
+
return typeof endpoint === 'string' && endpoint.length > 0 ? endpoint : null;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function hasEndpointRegistrar(
|
|
25
|
+
adapter: StorageAdapterInterface
|
|
26
|
+
): adapter is StorageAdapterInterface & {
|
|
27
|
+
registerEndpoint(namespace: string, endpoint: string): void;
|
|
28
|
+
} {
|
|
29
|
+
return 'registerEndpoint' in adapter && typeof adapter.registerEndpoint === 'function';
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function isZodSchema<T>(schema: object | null): schema is z.ZodType<T> {
|
|
33
|
+
return schema !== null && '_zod' in schema;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async function isCloudSyncEnabled(): Promise<boolean> {
|
|
37
|
+
const runtime = getVibesRuntime();
|
|
38
|
+
if (!runtime.hasKind('config/manifest')) {
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
try {
|
|
43
|
+
const manifest = (await runtime
|
|
44
|
+
.query('config/manifest')
|
|
45
|
+
.withId('ai.core')
|
|
46
|
+
.enabled()
|
|
47
|
+
.resolve()) as { load(): Promise<Record<string, unknown> | null> } | null;
|
|
48
|
+
if (!manifest) {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const config = await manifest.load();
|
|
53
|
+
return config?.syncToCloud === true;
|
|
54
|
+
} catch {
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export async function pushManifestToCloudAfterLocalSave<T>({
|
|
60
|
+
descriptor,
|
|
61
|
+
data,
|
|
62
|
+
activeAdapterId
|
|
63
|
+
}: {
|
|
64
|
+
descriptor: StorageManifestDescriptor;
|
|
65
|
+
data: T;
|
|
66
|
+
activeAdapterId: string;
|
|
67
|
+
}): Promise<void> {
|
|
68
|
+
if (!descriptor.allowedAdapters.includes('storage.cloud-api')) {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (REMOTE_ADAPTER_IDS.has(activeAdapterId)) {
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const runtime = getVibesRuntime();
|
|
77
|
+
if (runtime.scope?.surface === 'worker' || runtime.scope?.purpose === 'worker') {
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (!(await isCloudSyncEnabled())) {
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const localHash = computeHash(data);
|
|
86
|
+
const syncState = await loadSyncState();
|
|
87
|
+
|
|
88
|
+
try {
|
|
89
|
+
const cloudAdapter = await runtime
|
|
90
|
+
.query<StorageAdapterDescriptor, StorageAdapterInterface>('storage/adapter')
|
|
91
|
+
.withId('storage.cloud-api')
|
|
92
|
+
.enabled()
|
|
93
|
+
.resolve();
|
|
94
|
+
|
|
95
|
+
const endpoint = getCloudEndpoint(descriptor);
|
|
96
|
+
if (endpoint && hasEndpointRegistrar(cloudAdapter)) {
|
|
97
|
+
cloudAdapter.registerEndpoint(descriptor.namespace, endpoint);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
await cloudAdapter.ensureReady();
|
|
101
|
+
const schema =
|
|
102
|
+
typeof descriptor.schema === 'object' && isZodSchema<T>(descriptor.schema)
|
|
103
|
+
? descriptor.schema
|
|
104
|
+
: null;
|
|
105
|
+
if (!schema) {
|
|
106
|
+
throw new Error(`Storage manifest '${descriptor.id}' is missing a valid schema`);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const store = cloudAdapter.documentStore(descriptor.namespace, schema, descriptor);
|
|
110
|
+
await store.save(data);
|
|
111
|
+
|
|
112
|
+
markSynced(syncState, descriptor.id, localHash, 'push');
|
|
113
|
+
} catch (error) {
|
|
114
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
115
|
+
markLocalAhead(syncState, descriptor.id, localHash);
|
|
116
|
+
markError(syncState, descriptor.id, message);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
await saveSyncState(syncState);
|
|
120
|
+
}
|