@aigne/afs-did-space 1.12.0-beta.5
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.md +26 -0
- package/README.md +129 -0
- package/dist/_virtual/_@oxc-project_runtime@0.108.0/helpers/decorate.cjs +11 -0
- package/dist/_virtual/_@oxc-project_runtime@0.108.0/helpers/decorate.mjs +10 -0
- package/dist/_virtual/rolldown_runtime.cjs +29 -0
- package/dist/afs-metadata-context.cjs +20 -0
- package/dist/afs-metadata-context.d.cts +21 -0
- package/dist/afs-metadata-context.d.cts.map +1 -0
- package/dist/afs-metadata-context.d.mts +21 -0
- package/dist/afs-metadata-context.d.mts.map +1 -0
- package/dist/afs-metadata-context.mjs +18 -0
- package/dist/afs-metadata-context.mjs.map +1 -0
- package/dist/blocklet-hook.cjs +180 -0
- package/dist/blocklet-hook.d.cts +29 -0
- package/dist/blocklet-hook.d.cts.map +1 -0
- package/dist/blocklet-hook.d.mts +29 -0
- package/dist/blocklet-hook.d.mts.map +1 -0
- package/dist/blocklet-hook.mjs +178 -0
- package/dist/blocklet-hook.mjs.map +1 -0
- package/dist/changelog-schema.cjs +603 -0
- package/dist/changelog-schema.d.cts +395 -0
- package/dist/changelog-schema.d.cts.map +1 -0
- package/dist/changelog-schema.d.mts +395 -0
- package/dist/changelog-schema.d.mts.map +1 -0
- package/dist/changelog-schema.mjs +570 -0
- package/dist/changelog-schema.mjs.map +1 -0
- package/dist/changelog-write.cjs +80 -0
- package/dist/changelog-write.d.cts +70 -0
- package/dist/changelog-write.d.cts.map +1 -0
- package/dist/changelog-write.d.mts +70 -0
- package/dist/changelog-write.d.mts.map +1 -0
- package/dist/changelog-write.mjs +77 -0
- package/dist/changelog-write.mjs.map +1 -0
- package/dist/cid-byte-cache.cjs +126 -0
- package/dist/cid-byte-cache.d.cts +46 -0
- package/dist/cid-byte-cache.d.cts.map +1 -0
- package/dist/cid-byte-cache.d.mts +47 -0
- package/dist/cid-byte-cache.d.mts.map +1 -0
- package/dist/cid-byte-cache.mjs +125 -0
- package/dist/cid-byte-cache.mjs.map +1 -0
- package/dist/cid.cjs +68 -0
- package/dist/cid.d.cts +22 -0
- package/dist/cid.d.cts.map +1 -0
- package/dist/cid.d.mts +22 -0
- package/dist/cid.d.mts.map +1 -0
- package/dist/cid.mjs +65 -0
- package/dist/cid.mjs.map +1 -0
- package/dist/client.cjs +221 -0
- package/dist/client.d.cts +72 -0
- package/dist/client.d.cts.map +1 -0
- package/dist/client.d.mts +72 -0
- package/dist/client.d.mts.map +1 -0
- package/dist/client.mjs +220 -0
- package/dist/client.mjs.map +1 -0
- package/dist/cloudflare.cjs +510 -0
- package/dist/cloudflare.d.cts +307 -0
- package/dist/cloudflare.d.cts.map +1 -0
- package/dist/cloudflare.d.mts +308 -0
- package/dist/cloudflare.d.mts.map +1 -0
- package/dist/cloudflare.mjs +507 -0
- package/dist/cloudflare.mjs.map +1 -0
- package/dist/ctime-backfill.cjs +272 -0
- package/dist/ctime-backfill.d.cts +169 -0
- package/dist/ctime-backfill.d.cts.map +1 -0
- package/dist/ctime-backfill.d.mts +169 -0
- package/dist/ctime-backfill.d.mts.map +1 -0
- package/dist/ctime-backfill.mjs +267 -0
- package/dist/ctime-backfill.mjs.map +1 -0
- package/dist/d1-gc-queue.cjs +80 -0
- package/dist/d1-gc-queue.d.cts +59 -0
- package/dist/d1-gc-queue.d.cts.map +1 -0
- package/dist/d1-gc-queue.d.mts +59 -0
- package/dist/d1-gc-queue.d.mts.map +1 -0
- package/dist/d1-gc-queue.mjs +81 -0
- package/dist/d1-gc-queue.mjs.map +1 -0
- package/dist/d1-resolve-store.cjs +189 -0
- package/dist/d1-resolve-store.d.cts +93 -0
- package/dist/d1-resolve-store.d.cts.map +1 -0
- package/dist/d1-resolve-store.d.mts +93 -0
- package/dist/d1-resolve-store.d.mts.map +1 -0
- package/dist/d1-resolve-store.mjs +190 -0
- package/dist/d1-resolve-store.mjs.map +1 -0
- package/dist/d1-schema.cjs +361 -0
- package/dist/d1-schema.d.cts +237 -0
- package/dist/d1-schema.d.cts.map +1 -0
- package/dist/d1-schema.d.mts +237 -0
- package/dist/d1-schema.d.mts.map +1 -0
- package/dist/d1-schema.mjs +341 -0
- package/dist/d1-schema.mjs.map +1 -0
- package/dist/d1-share-store.cjs +0 -0
- package/dist/d1-share-store.d.cts +53 -0
- package/dist/d1-share-store.d.cts.map +1 -0
- package/dist/d1-share-store.d.mts +53 -0
- package/dist/d1-share-store.d.mts.map +1 -0
- package/dist/d1-share-store.mjs +0 -0
- package/dist/d1-share-store.mjs.map +1 -0
- package/dist/d1-tree-index.cjs +1098 -0
- package/dist/d1-tree-index.d.cts +203 -0
- package/dist/d1-tree-index.d.cts.map +1 -0
- package/dist/d1-tree-index.d.mts +203 -0
- package/dist/d1-tree-index.d.mts.map +1 -0
- package/dist/d1-tree-index.mjs +1094 -0
- package/dist/d1-tree-index.mjs.map +1 -0
- package/dist/data-backend.cjs +147 -0
- package/dist/data-backend.d.cts +30 -0
- package/dist/data-backend.d.cts.map +1 -0
- package/dist/data-backend.d.mts +30 -0
- package/dist/data-backend.d.mts.map +1 -0
- package/dist/data-backend.mjs +148 -0
- package/dist/data-backend.mjs.map +1 -0
- package/dist/dedup-backfill.cjs +278 -0
- package/dist/dedup-backfill.d.cts +165 -0
- package/dist/dedup-backfill.d.cts.map +1 -0
- package/dist/dedup-backfill.d.mts +165 -0
- package/dist/dedup-backfill.d.mts.map +1 -0
- package/dist/dedup-backfill.mjs +273 -0
- package/dist/dedup-backfill.mjs.map +1 -0
- package/dist/did-space-like.d.cts +2 -0
- package/dist/did-space-like.d.mts +2 -0
- package/dist/did-utils.cjs +44 -0
- package/dist/did-utils.d.cts +25 -0
- package/dist/did-utils.d.cts.map +1 -0
- package/dist/did-utils.d.mts +25 -0
- package/dist/did-utils.d.mts.map +1 -0
- package/dist/did-utils.mjs +43 -0
- package/dist/did-utils.mjs.map +1 -0
- package/dist/dirty-path-queue.cjs +31 -0
- package/dist/dirty-path-queue.d.cts +104 -0
- package/dist/dirty-path-queue.d.cts.map +1 -0
- package/dist/dirty-path-queue.d.mts +104 -0
- package/dist/dirty-path-queue.d.mts.map +1 -0
- package/dist/dirty-path-queue.mjs +31 -0
- package/dist/dirty-path-queue.mjs.map +1 -0
- package/dist/dirty-path-schema.cjs +142 -0
- package/dist/dirty-path-schema.d.cts +90 -0
- package/dist/dirty-path-schema.d.cts.map +1 -0
- package/dist/dirty-path-schema.d.mts +90 -0
- package/dist/dirty-path-schema.d.mts.map +1 -0
- package/dist/dirty-path-schema.mjs +136 -0
- package/dist/dirty-path-schema.mjs.map +1 -0
- package/dist/download-actions.cjs +43 -0
- package/dist/download-actions.mjs +40 -0
- package/dist/download-actions.mjs.map +1 -0
- package/dist/fs-object-store.cjs +153 -0
- package/dist/fs-object-store.d.cts +21 -0
- package/dist/fs-object-store.d.cts.map +1 -0
- package/dist/fs-object-store.d.mts +22 -0
- package/dist/fs-object-store.d.mts.map +1 -0
- package/dist/fs-object-store.mjs +153 -0
- package/dist/fs-object-store.mjs.map +1 -0
- package/dist/gc-queue.d.cts +43 -0
- package/dist/gc-queue.d.cts.map +1 -0
- package/dist/gc-queue.d.mts +43 -0
- package/dist/gc-queue.d.mts.map +1 -0
- package/dist/index.cjs +2712 -0
- package/dist/index.d.cts +504 -0
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.mts +505 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +2537 -0
- package/dist/index.mjs.map +1 -0
- package/dist/inline-content-migration.cjs +212 -0
- package/dist/inline-content-migration.d.cts +110 -0
- package/dist/inline-content-migration.d.cts.map +1 -0
- package/dist/inline-content-migration.d.mts +111 -0
- package/dist/inline-content-migration.d.mts.map +1 -0
- package/dist/inline-content-migration.mjs +207 -0
- package/dist/inline-content-migration.mjs.map +1 -0
- package/dist/inline-content.cjs +145 -0
- package/dist/inline-content.d.cts +98 -0
- package/dist/inline-content.d.cts.map +1 -0
- package/dist/inline-content.d.mts +98 -0
- package/dist/inline-content.d.mts.map +1 -0
- package/dist/inline-content.mjs +137 -0
- package/dist/inline-content.mjs.map +1 -0
- package/dist/local-changelog.cjs +241 -0
- package/dist/local-changelog.d.cts +119 -0
- package/dist/local-changelog.d.cts.map +1 -0
- package/dist/local-changelog.d.mts +119 -0
- package/dist/local-changelog.d.mts.map +1 -0
- package/dist/local-changelog.mjs +240 -0
- package/dist/local-changelog.mjs.map +1 -0
- package/dist/local.cjs +435 -0
- package/dist/local.d.cts +254 -0
- package/dist/local.d.cts.map +1 -0
- package/dist/local.d.mts +254 -0
- package/dist/local.d.mts.map +1 -0
- package/dist/local.mjs +427 -0
- package/dist/local.mjs.map +1 -0
- package/dist/memory-gc-queue.cjs +36 -0
- package/dist/memory-gc-queue.d.cts +22 -0
- package/dist/memory-gc-queue.d.cts.map +1 -0
- package/dist/memory-gc-queue.d.mts +22 -0
- package/dist/memory-gc-queue.d.mts.map +1 -0
- package/dist/memory-gc-queue.mjs +36 -0
- package/dist/memory-gc-queue.mjs.map +1 -0
- package/dist/memory-tree-index.cjs +734 -0
- package/dist/memory-tree-index.d.cts +159 -0
- package/dist/memory-tree-index.d.cts.map +1 -0
- package/dist/memory-tree-index.d.mts +159 -0
- package/dist/memory-tree-index.d.mts.map +1 -0
- package/dist/memory-tree-index.mjs +735 -0
- package/dist/memory-tree-index.mjs.map +1 -0
- package/dist/metadata-db.cjs +562 -0
- package/dist/metadata-db.d.cts +102 -0
- package/dist/metadata-db.d.cts.map +1 -0
- package/dist/metadata-db.d.mts +102 -0
- package/dist/metadata-db.d.mts.map +1 -0
- package/dist/metadata-db.mjs +562 -0
- package/dist/metadata-db.mjs.map +1 -0
- package/dist/mime-utils.cjs +2 -0
- package/dist/mime-utils.d.cts +2 -0
- package/dist/mime-utils.d.mts +2 -0
- package/dist/mime-utils.mjs +3 -0
- package/dist/object-key.cjs +41 -0
- package/dist/object-key.d.cts +25 -0
- package/dist/object-key.d.cts.map +1 -0
- package/dist/object-key.d.mts +25 -0
- package/dist/object-key.d.mts.map +1 -0
- package/dist/object-key.mjs +40 -0
- package/dist/object-key.mjs.map +1 -0
- package/dist/packages/session/dist/index.cjs +788 -0
- package/dist/packages/session/dist/index.mjs +782 -0
- package/dist/packages/session/dist/index.mjs.map +1 -0
- package/dist/platform/r2/dist/types.d.cts +49 -0
- package/dist/platform/r2/dist/types.d.cts.map +1 -0
- package/dist/prefix-range.cjs +33 -0
- package/dist/prefix-range.d.cts +29 -0
- package/dist/prefix-range.d.cts.map +1 -0
- package/dist/prefix-range.d.mts +29 -0
- package/dist/prefix-range.d.mts.map +1 -0
- package/dist/prefix-range.mjs +33 -0
- package/dist/prefix-range.mjs.map +1 -0
- package/dist/prefixed-tree-index.cjs +238 -0
- package/dist/prefixed-tree-index.d.cts +85 -0
- package/dist/prefixed-tree-index.d.cts.map +1 -0
- package/dist/prefixed-tree-index.d.mts +85 -0
- package/dist/prefixed-tree-index.d.mts.map +1 -0
- package/dist/prefixed-tree-index.mjs +239 -0
- package/dist/prefixed-tree-index.mjs.map +1 -0
- package/dist/presign-signer.cjs +7 -0
- package/dist/presign-signer.d.cts +99 -0
- package/dist/presign-signer.d.cts.map +1 -0
- package/dist/presign-signer.d.mts +99 -0
- package/dist/presign-signer.d.mts.map +1 -0
- package/dist/presign-signer.mjs +7 -0
- package/dist/presign-signer.mjs.map +1 -0
- package/dist/providers/platform/r2/dist/index.d.mts +3 -0
- package/dist/providers/platform/r2/dist/types.d.mts +49 -0
- package/dist/providers/platform/r2/dist/types.d.mts.map +1 -0
- package/dist/reconcile.cjs +184 -0
- package/dist/reconcile.d.cts +26 -0
- package/dist/reconcile.d.cts.map +1 -0
- package/dist/reconcile.d.mts +26 -0
- package/dist/reconcile.d.mts.map +1 -0
- package/dist/reconcile.mjs +184 -0
- package/dist/reconcile.mjs.map +1 -0
- package/dist/reference-check.cjs +49 -0
- package/dist/reference-check.d.cts +10 -0
- package/dist/reference-check.d.cts.map +1 -0
- package/dist/reference-check.d.mts +10 -0
- package/dist/reference-check.d.mts.map +1 -0
- package/dist/reference-check.mjs +48 -0
- package/dist/reference-check.mjs.map +1 -0
- package/dist/remote-afs.cjs +681 -0
- package/dist/remote-afs.d.cts +236 -0
- package/dist/remote-afs.d.cts.map +1 -0
- package/dist/remote-afs.d.mts +236 -0
- package/dist/remote-afs.d.mts.map +1 -0
- package/dist/remote-afs.mjs +676 -0
- package/dist/remote-afs.mjs.map +1 -0
- package/dist/rename-guard.cjs +18 -0
- package/dist/rename-guard.mjs +18 -0
- package/dist/rename-guard.mjs.map +1 -0
- package/dist/resolve.cjs +260 -0
- package/dist/resolve.d.cts +113 -0
- package/dist/resolve.d.cts.map +1 -0
- package/dist/resolve.d.mts +113 -0
- package/dist/resolve.d.mts.map +1 -0
- package/dist/resolve.mjs +260 -0
- package/dist/resolve.mjs.map +1 -0
- package/dist/rsync-content.cjs +33 -0
- package/dist/rsync-content.mjs +33 -0
- package/dist/rsync-content.mjs.map +1 -0
- package/dist/rsync.cjs +400 -0
- package/dist/rsync.d.cts +157 -0
- package/dist/rsync.d.cts.map +1 -0
- package/dist/rsync.d.mts +157 -0
- package/dist/rsync.d.mts.map +1 -0
- package/dist/rsync.mjs +397 -0
- package/dist/rsync.mjs.map +1 -0
- package/dist/run-gc.cjs +57 -0
- package/dist/run-gc.d.cts +40 -0
- package/dist/run-gc.d.cts.map +1 -0
- package/dist/run-gc.d.mts +41 -0
- package/dist/run-gc.d.mts.map +1 -0
- package/dist/run-gc.mjs +57 -0
- package/dist/run-gc.mjs.map +1 -0
- package/dist/scope-id.cjs +70 -0
- package/dist/scope-id.d.cts +35 -0
- package/dist/scope-id.d.cts.map +1 -0
- package/dist/scope-id.d.mts +35 -0
- package/dist/scope-id.d.mts.map +1 -0
- package/dist/scope-id.mjs +68 -0
- package/dist/scope-id.mjs.map +1 -0
- package/dist/scope-migration-node.cjs +172 -0
- package/dist/scope-migration-node.d.cts +44 -0
- package/dist/scope-migration-node.d.cts.map +1 -0
- package/dist/scope-migration-node.d.mts +44 -0
- package/dist/scope-migration-node.d.mts.map +1 -0
- package/dist/scope-migration-node.mjs +171 -0
- package/dist/scope-migration-node.mjs.map +1 -0
- package/dist/scope-migration.cjs +155 -0
- package/dist/scope-migration.d.cts +65 -0
- package/dist/scope-migration.d.cts.map +1 -0
- package/dist/scope-migration.d.mts +65 -0
- package/dist/scope-migration.d.mts.map +1 -0
- package/dist/scope-migration.mjs +154 -0
- package/dist/scope-migration.mjs.map +1 -0
- package/dist/share-declaration.cjs +225 -0
- package/dist/share-declaration.d.cts +30 -0
- package/dist/share-declaration.d.cts.map +1 -0
- package/dist/share-declaration.d.mts +32 -0
- package/dist/share-declaration.d.mts.map +1 -0
- package/dist/share-declaration.mjs +221 -0
- package/dist/share-declaration.mjs.map +1 -0
- package/dist/share-hook.cjs +63 -0
- package/dist/share-hook.mjs +62 -0
- package/dist/share-hook.mjs.map +1 -0
- package/dist/share-resolve.cjs +176 -0
- package/dist/share-resolve.d.cts +36 -0
- package/dist/share-resolve.d.cts.map +1 -0
- package/dist/share-resolve.d.mts +36 -0
- package/dist/share-resolve.d.mts.map +1 -0
- package/dist/share-resolve.mjs +177 -0
- package/dist/share-resolve.mjs.map +1 -0
- package/dist/share-serve.cjs +145 -0
- package/dist/share-serve.d.cts +30 -0
- package/dist/share-serve.d.cts.map +1 -0
- package/dist/share-serve.d.mts +30 -0
- package/dist/share-serve.d.mts.map +1 -0
- package/dist/share-serve.mjs +144 -0
- package/dist/share-serve.mjs.map +1 -0
- package/dist/share-store.cjs +25 -0
- package/dist/share-store.d.cts +65 -0
- package/dist/share-store.d.cts.map +1 -0
- package/dist/share-store.d.mts +65 -0
- package/dist/share-store.d.mts.map +1 -0
- package/dist/share-store.mjs +25 -0
- package/dist/share-store.mjs.map +1 -0
- package/dist/share-virtual-path.cjs +102 -0
- package/dist/share-virtual-path.mjs +101 -0
- package/dist/share-virtual-path.mjs.map +1 -0
- package/dist/space-resolver.cjs +54 -0
- package/dist/space-resolver.d.cts +34 -0
- package/dist/space-resolver.d.cts.map +1 -0
- package/dist/space-resolver.d.mts +34 -0
- package/dist/space-resolver.d.mts.map +1 -0
- package/dist/space-resolver.mjs +55 -0
- package/dist/space-resolver.mjs.map +1 -0
- package/dist/sqlite-gc-queue.cjs +51 -0
- package/dist/sqlite-gc-queue.d.cts +22 -0
- package/dist/sqlite-gc-queue.d.cts.map +1 -0
- package/dist/sqlite-gc-queue.d.mts +22 -0
- package/dist/sqlite-gc-queue.d.mts.map +1 -0
- package/dist/sqlite-gc-queue.mjs +52 -0
- package/dist/sqlite-gc-queue.mjs.map +1 -0
- package/dist/sqlite-resolve-store.cjs +163 -0
- package/dist/sqlite-resolve-store.d.cts +50 -0
- package/dist/sqlite-resolve-store.d.cts.map +1 -0
- package/dist/sqlite-resolve-store.d.mts +50 -0
- package/dist/sqlite-resolve-store.d.mts.map +1 -0
- package/dist/sqlite-resolve-store.mjs +164 -0
- package/dist/sqlite-resolve-store.mjs.map +1 -0
- package/dist/sqlite-share-store.cjs +157 -0
- package/dist/sqlite-share-store.d.cts +31 -0
- package/dist/sqlite-share-store.d.cts.map +1 -0
- package/dist/sqlite-share-store.d.mts +31 -0
- package/dist/sqlite-share-store.d.mts.map +1 -0
- package/dist/sqlite-share-store.mjs +157 -0
- package/dist/sqlite-share-store.mjs.map +1 -0
- package/dist/sqlite-tree-index.cjs +901 -0
- package/dist/sqlite-tree-index.d.cts +107 -0
- package/dist/sqlite-tree-index.d.cts.map +1 -0
- package/dist/sqlite-tree-index.d.mts +107 -0
- package/dist/sqlite-tree-index.d.mts.map +1 -0
- package/dist/sqlite-tree-index.mjs +902 -0
- package/dist/sqlite-tree-index.mjs.map +1 -0
- package/dist/sync-engine.cjs +1324 -0
- package/dist/sync-engine.d.cts +473 -0
- package/dist/sync-engine.d.cts.map +1 -0
- package/dist/sync-engine.d.mts +473 -0
- package/dist/sync-engine.d.mts.map +1 -0
- package/dist/sync-engine.mjs +1315 -0
- package/dist/sync-engine.mjs.map +1 -0
- package/dist/sync-state.cjs +303 -0
- package/dist/sync-state.d.cts +224 -0
- package/dist/sync-state.d.cts.map +1 -0
- package/dist/sync-state.d.mts +224 -0
- package/dist/sync-state.d.mts.map +1 -0
- package/dist/sync-state.mjs +297 -0
- package/dist/sync-state.mjs.map +1 -0
- package/dist/timestamp.cjs +92 -0
- package/dist/timestamp.mjs +91 -0
- package/dist/timestamp.mjs.map +1 -0
- package/dist/transports/http.cjs +54 -0
- package/dist/transports/http.d.cts +26 -0
- package/dist/transports/http.d.cts.map +1 -0
- package/dist/transports/http.d.mts +26 -0
- package/dist/transports/http.d.mts.map +1 -0
- package/dist/transports/http.mjs +54 -0
- package/dist/transports/http.mjs.map +1 -0
- package/dist/transports/static.cjs +55 -0
- package/dist/transports/static.d.cts +28 -0
- package/dist/transports/static.d.cts.map +1 -0
- package/dist/transports/static.d.mts +28 -0
- package/dist/transports/static.d.mts.map +1 -0
- package/dist/transports/static.mjs +55 -0
- package/dist/transports/static.mjs.map +1 -0
- package/dist/transports/types.cjs +13 -0
- package/dist/transports/types.d.cts +72 -0
- package/dist/transports/types.d.cts.map +1 -0
- package/dist/transports/types.d.mts +72 -0
- package/dist/transports/types.d.mts.map +1 -0
- package/dist/transports/types.mjs +13 -0
- package/dist/transports/types.mjs.map +1 -0
- package/dist/transports/ws.cjs +207 -0
- package/dist/transports/ws.d.cts +47 -0
- package/dist/transports/ws.d.cts.map +1 -0
- package/dist/transports/ws.d.mts +47 -0
- package/dist/transports/ws.d.mts.map +1 -0
- package/dist/transports/ws.mjs +206 -0
- package/dist/transports/ws.mjs.map +1 -0
- package/dist/tree-index.cjs +333 -0
- package/dist/tree-index.d.cts +524 -0
- package/dist/tree-index.d.cts.map +1 -0
- package/dist/tree-index.d.mts +524 -0
- package/dist/tree-index.d.mts.map +1 -0
- package/dist/tree-index.mjs +322 -0
- package/dist/tree-index.mjs.map +1 -0
- package/dist/tree-query.cjs +655 -0
- package/dist/tree-query.d.cts +70 -0
- package/dist/tree-query.d.cts.map +1 -0
- package/dist/tree-query.d.mts +70 -0
- package/dist/tree-query.d.mts.map +1 -0
- package/dist/tree-query.mjs +648 -0
- package/dist/tree-query.mjs.map +1 -0
- package/dist/upload-actions.cjs +97 -0
- package/dist/upload-actions.d.cts +19 -0
- package/dist/upload-actions.d.cts.map +1 -0
- package/dist/upload-actions.d.mts +21 -0
- package/dist/upload-actions.d.mts.map +1 -0
- package/dist/upload-actions.mjs +90 -0
- package/dist/upload-actions.mjs.map +1 -0
- package/dist/upload-session-store.cjs +185 -0
- package/dist/upload-session-store.d.cts +99 -0
- package/dist/upload-session-store.d.cts.map +1 -0
- package/dist/upload-session-store.d.mts +99 -0
- package/dist/upload-session-store.d.mts.map +1 -0
- package/dist/upload-session-store.mjs +184 -0
- package/dist/upload-session-store.mjs.map +1 -0
- package/dist/url-normalize.cjs +61 -0
- package/dist/url-normalize.d.cts +33 -0
- package/dist/url-normalize.d.cts.map +1 -0
- package/dist/url-normalize.d.mts +33 -0
- package/dist/url-normalize.d.mts.map +1 -0
- package/dist/url-normalize.mjs +61 -0
- package/dist/url-normalize.mjs.map +1 -0
- package/dist/versioned-content-backends.cjs +155 -0
- package/dist/versioned-content-backends.d.cts +49 -0
- package/dist/versioned-content-backends.d.cts.map +1 -0
- package/dist/versioned-content-backends.d.mts +49 -0
- package/dist/versioned-content-backends.d.mts.map +1 -0
- package/dist/versioned-content-backends.mjs +154 -0
- package/dist/versioned-content-backends.mjs.map +1 -0
- package/dist/versioned-content-index.cjs +102 -0
- package/dist/versioned-content-index.d.cts +46 -0
- package/dist/versioned-content-index.d.cts.map +1 -0
- package/dist/versioned-content-index.d.mts +46 -0
- package/dist/versioned-content-index.d.mts.map +1 -0
- package/dist/versioned-content-index.mjs +103 -0
- package/dist/versioned-content-index.mjs.map +1 -0
- package/dist/versioned-content-store.cjs +121 -0
- package/dist/versioned-content-store.d.cts +90 -0
- package/dist/versioned-content-store.d.cts.map +1 -0
- package/dist/versioned-content-store.d.mts +90 -0
- package/dist/versioned-content-store.d.mts.map +1 -0
- package/dist/versioned-content-store.mjs +122 -0
- package/dist/versioned-content-store.mjs.map +1 -0
- package/dist/versioned-scope.cjs +39 -0
- package/dist/versioned-scope.d.cts +57 -0
- package/dist/versioned-scope.d.cts.map +1 -0
- package/dist/versioned-scope.d.mts +57 -0
- package/dist/versioned-scope.d.mts.map +1 -0
- package/dist/versioned-scope.mjs +37 -0
- package/dist/versioned-scope.mjs.map +1 -0
- package/migrations/0001_tree_entries.sql +17 -0
- package/migrations/0002_resolve_entries.sql +7 -0
- package/migrations/0003_entries_v2.sql +38 -0
- package/migrations/0004_gc_queue.sql +5 -0
- package/migrations/0006_resolve_enhance.sql +14 -0
- package/migrations/0007_resolve_created_at.sql +10 -0
- package/migrations/0008_changelog.sql +34 -0
- package/migrations/0009_device_sync_state.sql +29 -0
- package/migrations/0010_scope_meta.sql +33 -0
- package/migrations/0011_shares.sql +25 -0
- package/migrations/0012_scope_meta_file_count.sql +41 -0
- package/migrations/0013_scope_meta_total_bytes.sql +47 -0
- package/migrations/0014_rename_tables.sql +62 -0
- package/package.json +102 -0
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
import { SYNC_STATE_INDEX_SQL, SYNC_STATE_TABLE_SQL } from "./changelog-schema.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/sync-state.ts
|
|
4
|
+
/**
|
|
5
|
+
* SyncStateStore — Phase 3 Task 3.5 (G7)
|
|
6
|
+
*
|
|
7
|
+
* Typed key-value façade over the `sync_state` table introduced by
|
|
8
|
+
* Task 3.4. Where {@link LocalChangelog} owns the bare minimum of the
|
|
9
|
+
* `{scope}:local_seq` and `{scope}:cloud_seq` keys for changelog GC,
|
|
10
|
+
* SyncStateStore exposes the FULL set of progress fields the local
|
|
11
|
+
* SyncEngine needs:
|
|
12
|
+
*
|
|
13
|
+
* - device_id (per-user, NOT scope-prefixed)
|
|
14
|
+
* - {scope}:local_seq
|
|
15
|
+
* - {scope}:cloud_seq
|
|
16
|
+
* - {scope}:last_sync_at
|
|
17
|
+
* - {scope}:sync_status
|
|
18
|
+
*
|
|
19
|
+
* The class is intentionally a sibling of LocalChangelog rather than a
|
|
20
|
+
* refactor of it. Both operate on the same SQLite `sync_state` table and
|
|
21
|
+
* share monotonic semantics for `local_seq` / `cloud_seq`; cross-class
|
|
22
|
+
* parity is asserted by tests so the SyncEngine can mix the two without
|
|
23
|
+
* surprises. Refactoring LocalChangelog into a thin wrapper around
|
|
24
|
+
* SyncStateStore is a future optimisation that Task 3.6 (SyncEngine) can
|
|
25
|
+
* decide to make if it becomes ergonomic.
|
|
26
|
+
*
|
|
27
|
+
* Platform notes:
|
|
28
|
+
* - TypeScript / desktop: device_id is stored ONLY in this SQLite table.
|
|
29
|
+
* There is no Keychain equivalent on desktop, so the file IS the SoT.
|
|
30
|
+
* - Swift / iOS: Keychain is the SoT; this SQLite cache is rebuilt
|
|
31
|
+
* on startup.
|
|
32
|
+
* - Kotlin / Android: AndroidKeystore + EncryptedSharedPreferences is
|
|
33
|
+
* the SoT; SQLite is again the cache.
|
|
34
|
+
*
|
|
35
|
+
* The two mobile runtimes implement their own SyncStateStore + DeviceIDStore
|
|
36
|
+
* pair under `swift/Sources/AFSDIDSpace/` and
|
|
37
|
+
* `kotlin/afs-didspace/.../io/aigne/afs/didspace/`. The TypeScript class
|
|
38
|
+
* here matches their public surface as closely as the language allows.
|
|
39
|
+
*/
|
|
40
|
+
/** Default `AppState` returned by load() when nothing is persisted yet. */
|
|
41
|
+
function defaultAppState() {
|
|
42
|
+
return {
|
|
43
|
+
deviceId: "",
|
|
44
|
+
cloudSeq: 0,
|
|
45
|
+
localSeq: 0,
|
|
46
|
+
lastSyncAt: 0,
|
|
47
|
+
syncStatus: { kind: "idle" }
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Registry of the raw `sync_state` keys this class manages. Exported so
|
|
52
|
+
* tests and the eventual SyncEngine can introspect the wire format without
|
|
53
|
+
* hard-coding strings.
|
|
54
|
+
*
|
|
55
|
+
* Keys marked `scoped` are written as `{scope}:{name}`. The `device_id`
|
|
56
|
+
* key is unique among the registry — it is per-user and intentionally NOT
|
|
57
|
+
* scope-prefixed so a single device sharing two DID Space scopes still
|
|
58
|
+
* presents the same identity to both.
|
|
59
|
+
*/
|
|
60
|
+
const SYNC_STATE_KEYS = {
|
|
61
|
+
deviceId: {
|
|
62
|
+
name: "device_id",
|
|
63
|
+
scoped: false
|
|
64
|
+
},
|
|
65
|
+
localSeq: {
|
|
66
|
+
name: "local_seq",
|
|
67
|
+
scoped: true
|
|
68
|
+
},
|
|
69
|
+
cloudSeq: {
|
|
70
|
+
name: "cloud_seq",
|
|
71
|
+
scoped: true
|
|
72
|
+
},
|
|
73
|
+
lastSyncAt: {
|
|
74
|
+
name: "last_sync_at",
|
|
75
|
+
scoped: true
|
|
76
|
+
},
|
|
77
|
+
syncStatus: {
|
|
78
|
+
name: "sync_status",
|
|
79
|
+
scoped: true
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
/**
|
|
83
|
+
* Serialise a {@link SyncStatus} to its on-disk string form.
|
|
84
|
+
*
|
|
85
|
+
* Format (matches the spec acceptance criteria):
|
|
86
|
+
* - `idle` → `"idle"`
|
|
87
|
+
* - `syncing` → `"syncing"`
|
|
88
|
+
* - `active` → `"active"`
|
|
89
|
+
* - `error:{message}` → `"error:{message}"`
|
|
90
|
+
*
|
|
91
|
+
* The `error` branch preserves the full message verbatim. Newlines and
|
|
92
|
+
* colons inside the message are tolerated; parsing is greedy on the prefix
|
|
93
|
+
* `error:` so the remainder of the string is the message regardless of
|
|
94
|
+
* what punctuation it contains.
|
|
95
|
+
*/
|
|
96
|
+
function serializeSyncStatus(status) {
|
|
97
|
+
switch (status.kind) {
|
|
98
|
+
case "idle": return "idle";
|
|
99
|
+
case "syncing": return "syncing";
|
|
100
|
+
case "active": return "active";
|
|
101
|
+
case "error": return `error:${status.message}`;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Parse a `sync_status` string back into a {@link SyncStatus}. Throws on
|
|
106
|
+
* unrecognised forms — this matches LocalChangelog's "corrupt value =
|
|
107
|
+
* surface the bug" stance from Task 3.4.
|
|
108
|
+
*/
|
|
109
|
+
function parseSyncStatus(raw) {
|
|
110
|
+
if (raw === "idle") return { kind: "idle" };
|
|
111
|
+
if (raw === "syncing") return { kind: "syncing" };
|
|
112
|
+
if (raw === "active") return { kind: "active" };
|
|
113
|
+
if (raw.startsWith("error:")) return {
|
|
114
|
+
kind: "error",
|
|
115
|
+
message: raw.slice(6)
|
|
116
|
+
};
|
|
117
|
+
throw new Error(`SyncStateStore: corrupt sync_status value: ${raw}`);
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Strict device_id format regex. Must match the server-side validator in
|
|
121
|
+
* `services/arc-computer/src/handlers/validate-headers.ts` so locally
|
|
122
|
+
* generated identifiers round-trip through the cloud sync endpoints
|
|
123
|
+
* unchanged. Format: `<class>:<platform>:<suffix>`.
|
|
124
|
+
*
|
|
125
|
+
* Duplicated locally so this module has zero cross-package imports — the
|
|
126
|
+
* source of truth lives in `validate-headers.ts` and any change there must
|
|
127
|
+
* be mirrored here AND in the Swift/Kotlin equivalents.
|
|
128
|
+
*/
|
|
129
|
+
const DEVICE_ID_FORMAT_RE = /^(aside|desktop|server):[a-z0-9-]+:[a-z0-9-]+$/;
|
|
130
|
+
/** Validate a device_id string. Returns true on match. */
|
|
131
|
+
function isValidDeviceId(deviceId) {
|
|
132
|
+
return DEVICE_ID_FORMAT_RE.test(deviceId);
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Generate a fresh device_id for the current TypeScript desktop runtime.
|
|
136
|
+
* Format: `desktop:ts:<uuid v4>`. Tests can pass an injected UUID to
|
|
137
|
+
* keep generation deterministic.
|
|
138
|
+
*/
|
|
139
|
+
function generateDesktopDeviceId(uuid) {
|
|
140
|
+
return `desktop:ts:${uuid ?? crypto.randomUUID()}`;
|
|
141
|
+
}
|
|
142
|
+
var SyncStateStore = class {
|
|
143
|
+
client;
|
|
144
|
+
scope;
|
|
145
|
+
constructor(opts) {
|
|
146
|
+
if (typeof opts.scope !== "string" || opts.scope.length === 0) throw new Error("SyncStateStore: scope must be a non-empty string");
|
|
147
|
+
this.client = opts.client;
|
|
148
|
+
this.scope = opts.scope;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Idempotently create the `sync_state` table. MetadataDB.open() and the
|
|
152
|
+
* Swift/Kotlin SQLiteTreeIndex.migrate() already create it; this static
|
|
153
|
+
* helper exists for test fixtures that build a SyncStateStore on a raw
|
|
154
|
+
* libsql client. Reuses the canonical DDL from `changelog-schema.ts` so
|
|
155
|
+
* three-runtime parity is preserved.
|
|
156
|
+
*/
|
|
157
|
+
static async ensureTable(client) {
|
|
158
|
+
await client.execute(SYNC_STATE_TABLE_SQL);
|
|
159
|
+
for (const sql of SYNC_STATE_INDEX_SQL) await client.execute(sql);
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Build the on-disk key for a given AppState field. Per-scope fields
|
|
163
|
+
* are prefixed with `{scope}:`; the per-user `device_id` field is the
|
|
164
|
+
* raw bare name. Exposed as a private helper (rather than inlined) so
|
|
165
|
+
* the parity tests can introspect the rule via SYNC_STATE_KEYS.
|
|
166
|
+
*/
|
|
167
|
+
keyFor(field) {
|
|
168
|
+
const meta = SYNC_STATE_KEYS[field];
|
|
169
|
+
return meta.scoped ? `${this.scope}:${meta.name}` : meta.name;
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Read the full {@link AppState} for this scope. Missing fields fall
|
|
173
|
+
* back to the defaults from {@link defaultAppState}.
|
|
174
|
+
*
|
|
175
|
+
* If `device_id` is absent, this method generates a fresh one using
|
|
176
|
+
* {@link generateDesktopDeviceId} and persists it back to the same
|
|
177
|
+
* SQLite cache before returning. Subsequent loads will see the same
|
|
178
|
+
* value (this is the "TS desktop has no Keychain — file IS the SoT"
|
|
179
|
+
* branch from the spec).
|
|
180
|
+
*
|
|
181
|
+
* Corrupt values throw — corrupt `cloud_seq` / `local_seq` / `last_sync_at`
|
|
182
|
+
* non-numeric, corrupt `sync_status` not in the recognised set, corrupt
|
|
183
|
+
* `device_id` failing the strict regex.
|
|
184
|
+
*/
|
|
185
|
+
async load() {
|
|
186
|
+
const state = defaultAppState();
|
|
187
|
+
const result = await this.client.execute({
|
|
188
|
+
sql: `SELECT key, value FROM ds_sync_state WHERE key IN (?, ?, ?, ?, ?)`,
|
|
189
|
+
args: [
|
|
190
|
+
this.keyFor("deviceId"),
|
|
191
|
+
this.keyFor("cloudSeq"),
|
|
192
|
+
this.keyFor("localSeq"),
|
|
193
|
+
this.keyFor("lastSyncAt"),
|
|
194
|
+
this.keyFor("syncStatus")
|
|
195
|
+
]
|
|
196
|
+
});
|
|
197
|
+
const rows = /* @__PURE__ */ new Map();
|
|
198
|
+
for (const row of result.rows) {
|
|
199
|
+
const k = row[0];
|
|
200
|
+
const v = row[1];
|
|
201
|
+
if (typeof k === "string" && (typeof v === "string" || typeof v === "number")) rows.set(k, String(v));
|
|
202
|
+
}
|
|
203
|
+
const rawDeviceId = rows.get(this.keyFor("deviceId"));
|
|
204
|
+
if (rawDeviceId !== void 0) {
|
|
205
|
+
if (!isValidDeviceId(rawDeviceId)) throw new Error(`SyncStateStore: corrupt device_id value: ${rawDeviceId}`);
|
|
206
|
+
state.deviceId = rawDeviceId;
|
|
207
|
+
} else {
|
|
208
|
+
const fresh = generateDesktopDeviceId();
|
|
209
|
+
await this.writeKey(this.keyFor("deviceId"), fresh);
|
|
210
|
+
state.deviceId = fresh;
|
|
211
|
+
}
|
|
212
|
+
state.cloudSeq = parseSeqValue(rows.get(this.keyFor("cloudSeq")), "cloud_seq");
|
|
213
|
+
state.localSeq = parseSeqValue(rows.get(this.keyFor("localSeq")), "local_seq");
|
|
214
|
+
state.lastSyncAt = parseSeqValue(rows.get(this.keyFor("lastSyncAt")), "last_sync_at");
|
|
215
|
+
const rawStatus = rows.get(this.keyFor("syncStatus"));
|
|
216
|
+
if (rawStatus !== void 0) state.syncStatus = parseSyncStatus(rawStatus);
|
|
217
|
+
return state;
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Persist a partial update to the {@link AppState}. Each field is
|
|
221
|
+
* written via INSERT OR REPLACE on its individual key; concurrent
|
|
222
|
+
* save() calls touching disjoint fields cannot lose data.
|
|
223
|
+
*
|
|
224
|
+
* Monotonic fields:
|
|
225
|
+
* - `cloudSeq` and `localSeq` use the same CASE expression as
|
|
226
|
+
* {@link LocalChangelog.markPushed}, so a save() with a lower value
|
|
227
|
+
* than the current watermark is silently ignored. This keeps a
|
|
228
|
+
* SyncEngine + LocalChangelog mixed-write path safe.
|
|
229
|
+
*
|
|
230
|
+
* Non-monotonic fields:
|
|
231
|
+
* - `lastSyncAt`, `syncStatus`, `deviceId` are written as-is. The
|
|
232
|
+
* state machine (`idle → syncing → active → idle` etc.) and the
|
|
233
|
+
* `last_sync_at` clock have valid backwards transitions in some
|
|
234
|
+
* edge cases (test reset, manual rollback) and we must not block
|
|
235
|
+
* them.
|
|
236
|
+
*
|
|
237
|
+
* Unknown fields are caught at compile time by `Partial<AppState>`.
|
|
238
|
+
* Defense-in-depth: at runtime we iterate the explicit list of fields
|
|
239
|
+
* we know how to serialise rather than `Object.keys(update)`.
|
|
240
|
+
*/
|
|
241
|
+
async save(update) {
|
|
242
|
+
if (update.deviceId !== void 0) {
|
|
243
|
+
if (!isValidDeviceId(update.deviceId)) throw new Error(`SyncStateStore: refusing to save invalid device_id: ${update.deviceId}`);
|
|
244
|
+
await this.writeKey(this.keyFor("deviceId"), update.deviceId);
|
|
245
|
+
}
|
|
246
|
+
if (update.cloudSeq !== void 0) await this.writeKeyMonotonic(this.keyFor("cloudSeq"), update.cloudSeq);
|
|
247
|
+
if (update.localSeq !== void 0) await this.writeKeyMonotonic(this.keyFor("localSeq"), update.localSeq);
|
|
248
|
+
if (update.lastSyncAt !== void 0) {
|
|
249
|
+
const safe = Math.max(0, Math.floor(Number.isFinite(update.lastSyncAt) ? update.lastSyncAt : 0));
|
|
250
|
+
await this.writeKey(this.keyFor("lastSyncAt"), String(safe));
|
|
251
|
+
}
|
|
252
|
+
if (update.syncStatus !== void 0) await this.writeKey(this.keyFor("syncStatus"), serializeSyncStatus(update.syncStatus));
|
|
253
|
+
}
|
|
254
|
+
/** Plain INSERT OR REPLACE for non-monotonic keys. */
|
|
255
|
+
async writeKey(key, value) {
|
|
256
|
+
await this.client.execute({
|
|
257
|
+
sql: `INSERT INTO ds_sync_state (key, value) VALUES (?, ?)
|
|
258
|
+
ON CONFLICT(key) DO UPDATE SET value = excluded.value`,
|
|
259
|
+
args: [key, value]
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Monotonic INSERT OR REPLACE for integer keys. Mirror of the helper in
|
|
264
|
+
* {@link LocalChangelog.writeSeqKeyMonotonic} so the two classes converge
|
|
265
|
+
* on the same on-disk representation regardless of which one performs
|
|
266
|
+
* the write.
|
|
267
|
+
*/
|
|
268
|
+
async writeKeyMonotonic(key, seq) {
|
|
269
|
+
const safe = Math.max(0, Math.floor(Number.isFinite(seq) ? seq : 0));
|
|
270
|
+
await this.client.execute({
|
|
271
|
+
sql: `INSERT INTO ds_sync_state (key, value) VALUES (?, ?)
|
|
272
|
+
ON CONFLICT(key) DO UPDATE SET
|
|
273
|
+
value = CASE
|
|
274
|
+
WHEN CAST(excluded.value AS INTEGER) > CAST(ds_sync_state.value AS INTEGER)
|
|
275
|
+
THEN excluded.value
|
|
276
|
+
ELSE ds_sync_state.value
|
|
277
|
+
END`,
|
|
278
|
+
args: [key, String(safe)]
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
};
|
|
282
|
+
/**
|
|
283
|
+
* Parse a stored numeric value (cloud_seq / local_seq / last_sync_at).
|
|
284
|
+
*
|
|
285
|
+
* Missing → 0 (the "nothing recorded yet" sentinel, matches LocalChangelog).
|
|
286
|
+
* Non-integer / non-numeric → throws to surface corruption to the caller.
|
|
287
|
+
*/
|
|
288
|
+
function parseSeqValue(raw, label) {
|
|
289
|
+
if (raw === void 0) return 0;
|
|
290
|
+
const parsed = Number(raw);
|
|
291
|
+
if (!Number.isFinite(parsed) || !Number.isInteger(parsed)) throw new Error(`SyncStateStore: corrupt ${label} value: ${raw}`);
|
|
292
|
+
return parsed;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
//#endregion
|
|
296
|
+
export { DEVICE_ID_FORMAT_RE, SYNC_STATE_KEYS, SyncStateStore, defaultAppState, generateDesktopDeviceId, isValidDeviceId, parseSyncStatus, serializeSyncStatus };
|
|
297
|
+
//# sourceMappingURL=sync-state.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sync-state.mjs","names":[],"sources":["../src/sync-state.ts"],"sourcesContent":["/**\n * SyncStateStore — Phase 3 Task 3.5 (G7)\n *\n * Typed key-value façade over the `sync_state` table introduced by\n * Task 3.4. Where {@link LocalChangelog} owns the bare minimum of the\n * `{scope}:local_seq` and `{scope}:cloud_seq` keys for changelog GC,\n * SyncStateStore exposes the FULL set of progress fields the local\n * SyncEngine needs:\n *\n * - device_id (per-user, NOT scope-prefixed)\n * - {scope}:local_seq\n * - {scope}:cloud_seq\n * - {scope}:last_sync_at\n * - {scope}:sync_status\n *\n * The class is intentionally a sibling of LocalChangelog rather than a\n * refactor of it. Both operate on the same SQLite `sync_state` table and\n * share monotonic semantics for `local_seq` / `cloud_seq`; cross-class\n * parity is asserted by tests so the SyncEngine can mix the two without\n * surprises. Refactoring LocalChangelog into a thin wrapper around\n * SyncStateStore is a future optimisation that Task 3.6 (SyncEngine) can\n * decide to make if it becomes ergonomic.\n *\n * Platform notes:\n * - TypeScript / desktop: device_id is stored ONLY in this SQLite table.\n * There is no Keychain equivalent on desktop, so the file IS the SoT.\n * - Swift / iOS: Keychain is the SoT; this SQLite cache is rebuilt\n * on startup.\n * - Kotlin / Android: AndroidKeystore + EncryptedSharedPreferences is\n * the SoT; SQLite is again the cache.\n *\n * The two mobile runtimes implement their own SyncStateStore + DeviceIDStore\n * pair under `swift/Sources/AFSDIDSpace/` and\n * `kotlin/afs-didspace/.../io/aigne/afs/didspace/`. The TypeScript class\n * here matches their public surface as closely as the language allows.\n */\n\nimport { SYNC_STATE_INDEX_SQL, SYNC_STATE_TABLE_SQL } from \"./changelog-schema.js\";\n\n/** Discriminated union shape of `sync_status`. */\nexport type SyncStatus =\n | { kind: \"idle\" }\n | { kind: \"syncing\" }\n | { kind: \"active\" }\n | { kind: \"error\"; message: string };\n\n/**\n * Full snapshot of the per-scope sync state. Returned by {@link SyncStateStore.load}.\n *\n * `deviceId` is per-USER-DID (stable across all scopes for the same install)\n * and is therefore stored under the bare key `device_id` — NOT scope-prefixed.\n * Every other field is scope-prefixed internally so multiple scopes sharing\n * the same SQLite file stay isolated.\n */\nexport interface AppState {\n /** Stable device identifier. Generated on first load() if missing. */\n deviceId: string;\n /** Highest changelog.seq pulled+applied from other devices. */\n cloudSeq: number;\n /** Highest changelog.seq this device has pushed to cloud. */\n localSeq: number;\n /** Unix millis of the last successful sync round (any leg). */\n lastSyncAt: number;\n /** Current sync state machine value. */\n syncStatus: SyncStatus;\n}\n\n/** Default `AppState` returned by load() when nothing is persisted yet. */\nexport function defaultAppState(): AppState {\n return {\n deviceId: \"\",\n cloudSeq: 0,\n localSeq: 0,\n lastSyncAt: 0,\n syncStatus: { kind: \"idle\" },\n };\n}\n\n/**\n * Registry of the raw `sync_state` keys this class manages. Exported so\n * tests and the eventual SyncEngine can introspect the wire format without\n * hard-coding strings.\n *\n * Keys marked `scoped` are written as `{scope}:{name}`. The `device_id`\n * key is unique among the registry — it is per-user and intentionally NOT\n * scope-prefixed so a single device sharing two DID Space scopes still\n * presents the same identity to both.\n */\nexport const SYNC_STATE_KEYS = {\n deviceId: { name: \"device_id\", scoped: false },\n localSeq: { name: \"local_seq\", scoped: true },\n cloudSeq: { name: \"cloud_seq\", scoped: true },\n lastSyncAt: { name: \"last_sync_at\", scoped: true },\n syncStatus: { name: \"sync_status\", scoped: true },\n} as const;\n\nexport interface SyncStateStoreOptions {\n /**\n * Already-opened libsql client sharing the same DB file as the TreeIndex.\n * SyncStateStore does NOT own the client lifecycle — callers (typically\n * `DIDSpaceProvider` construction) remain responsible for close().\n */\n client: import(\"@libsql/client\").Client;\n /** Scope string used to prefix per-scope keys. Must be non-empty. */\n scope: string;\n}\n\n/**\n * Serialise a {@link SyncStatus} to its on-disk string form.\n *\n * Format (matches the spec acceptance criteria):\n * - `idle` → `\"idle\"`\n * - `syncing` → `\"syncing\"`\n * - `active` → `\"active\"`\n * - `error:{message}` → `\"error:{message}\"`\n *\n * The `error` branch preserves the full message verbatim. Newlines and\n * colons inside the message are tolerated; parsing is greedy on the prefix\n * `error:` so the remainder of the string is the message regardless of\n * what punctuation it contains.\n */\nexport function serializeSyncStatus(status: SyncStatus): string {\n switch (status.kind) {\n case \"idle\":\n return \"idle\";\n case \"syncing\":\n return \"syncing\";\n case \"active\":\n return \"active\";\n case \"error\":\n return `error:${status.message}`;\n }\n}\n\n/**\n * Parse a `sync_status` string back into a {@link SyncStatus}. Throws on\n * unrecognised forms — this matches LocalChangelog's \"corrupt value =\n * surface the bug\" stance from Task 3.4.\n */\nexport function parseSyncStatus(raw: string): SyncStatus {\n if (raw === \"idle\") return { kind: \"idle\" };\n if (raw === \"syncing\") return { kind: \"syncing\" };\n if (raw === \"active\") return { kind: \"active\" };\n if (raw.startsWith(\"error:\")) {\n return { kind: \"error\", message: raw.slice(\"error:\".length) };\n }\n throw new Error(`SyncStateStore: corrupt sync_status value: ${raw}`);\n}\n\n/**\n * Strict device_id format regex. Must match the server-side validator in\n * `services/arc-computer/src/handlers/validate-headers.ts` so locally\n * generated identifiers round-trip through the cloud sync endpoints\n * unchanged. Format: `<class>:<platform>:<suffix>`.\n *\n * Duplicated locally so this module has zero cross-package imports — the\n * source of truth lives in `validate-headers.ts` and any change there must\n * be mirrored here AND in the Swift/Kotlin equivalents.\n */\nexport const DEVICE_ID_FORMAT_RE = /^(aside|desktop|server):[a-z0-9-]+:[a-z0-9-]+$/;\n\n/** Validate a device_id string. Returns true on match. */\nexport function isValidDeviceId(deviceId: string): boolean {\n return DEVICE_ID_FORMAT_RE.test(deviceId);\n}\n\n/**\n * Generate a fresh device_id for the current TypeScript desktop runtime.\n * Format: `desktop:ts:<uuid v4>`. Tests can pass an injected UUID to\n * keep generation deterministic.\n */\nexport function generateDesktopDeviceId(uuid?: string): string {\n const id = uuid ?? crypto.randomUUID();\n return `desktop:ts:${id}`;\n}\n\nexport class SyncStateStore {\n private readonly client: import(\"@libsql/client\").Client;\n private readonly scope: string;\n\n constructor(opts: SyncStateStoreOptions) {\n if (typeof opts.scope !== \"string\" || opts.scope.length === 0) {\n throw new Error(\"SyncStateStore: scope must be a non-empty string\");\n }\n this.client = opts.client;\n this.scope = opts.scope;\n }\n\n /**\n * Idempotently create the `sync_state` table. MetadataDB.open() and the\n * Swift/Kotlin SQLiteTreeIndex.migrate() already create it; this static\n * helper exists for test fixtures that build a SyncStateStore on a raw\n * libsql client. Reuses the canonical DDL from `changelog-schema.ts` so\n * three-runtime parity is preserved.\n */\n static async ensureTable(client: import(\"@libsql/client\").Client): Promise<void> {\n await client.execute(SYNC_STATE_TABLE_SQL);\n for (const sql of SYNC_STATE_INDEX_SQL) {\n await client.execute(sql);\n }\n }\n\n // ── key helpers ───────────────────────────────────────────────\n\n /**\n * Build the on-disk key for a given AppState field. Per-scope fields\n * are prefixed with `{scope}:`; the per-user `device_id` field is the\n * raw bare name. Exposed as a private helper (rather than inlined) so\n * the parity tests can introspect the rule via SYNC_STATE_KEYS.\n */\n private keyFor(field: keyof typeof SYNC_STATE_KEYS): string {\n const meta = SYNC_STATE_KEYS[field];\n return meta.scoped ? `${this.scope}:${meta.name}` : meta.name;\n }\n\n // ── load ──────────────────────────────────────────────────────\n\n /**\n * Read the full {@link AppState} for this scope. Missing fields fall\n * back to the defaults from {@link defaultAppState}.\n *\n * If `device_id` is absent, this method generates a fresh one using\n * {@link generateDesktopDeviceId} and persists it back to the same\n * SQLite cache before returning. Subsequent loads will see the same\n * value (this is the \"TS desktop has no Keychain — file IS the SoT\"\n * branch from the spec).\n *\n * Corrupt values throw — corrupt `cloud_seq` / `local_seq` / `last_sync_at`\n * non-numeric, corrupt `sync_status` not in the recognised set, corrupt\n * `device_id` failing the strict regex.\n */\n async load(): Promise<AppState> {\n const state = defaultAppState();\n\n const result = await this.client.execute({\n sql: `SELECT key, value FROM ds_sync_state WHERE key IN (?, ?, ?, ?, ?)`,\n args: [\n this.keyFor(\"deviceId\"),\n this.keyFor(\"cloudSeq\"),\n this.keyFor(\"localSeq\"),\n this.keyFor(\"lastSyncAt\"),\n this.keyFor(\"syncStatus\"),\n ],\n });\n\n const rows = new Map<string, string>();\n for (const row of result.rows) {\n const k = row[0];\n const v = row[1];\n if (typeof k === \"string\" && (typeof v === \"string\" || typeof v === \"number\")) {\n rows.set(k, String(v));\n }\n }\n\n const rawDeviceId = rows.get(this.keyFor(\"deviceId\"));\n if (rawDeviceId !== undefined) {\n if (!isValidDeviceId(rawDeviceId)) {\n throw new Error(`SyncStateStore: corrupt device_id value: ${rawDeviceId}`);\n }\n state.deviceId = rawDeviceId;\n } else {\n // Bootstrap branch: TS desktop has no Keychain, so we generate the\n // device_id here and persist it. Mobile runtimes use their native\n // store as the SoT and only fall through to this branch if the\n // native store is empty.\n const fresh = generateDesktopDeviceId();\n await this.writeKey(this.keyFor(\"deviceId\"), fresh);\n state.deviceId = fresh;\n }\n\n state.cloudSeq = parseSeqValue(rows.get(this.keyFor(\"cloudSeq\")), \"cloud_seq\");\n state.localSeq = parseSeqValue(rows.get(this.keyFor(\"localSeq\")), \"local_seq\");\n state.lastSyncAt = parseSeqValue(rows.get(this.keyFor(\"lastSyncAt\")), \"last_sync_at\");\n\n const rawStatus = rows.get(this.keyFor(\"syncStatus\"));\n if (rawStatus !== undefined) {\n state.syncStatus = parseSyncStatus(rawStatus);\n }\n\n return state;\n }\n\n // ── save ──────────────────────────────────────────────────────\n\n /**\n * Persist a partial update to the {@link AppState}. Each field is\n * written via INSERT OR REPLACE on its individual key; concurrent\n * save() calls touching disjoint fields cannot lose data.\n *\n * Monotonic fields:\n * - `cloudSeq` and `localSeq` use the same CASE expression as\n * {@link LocalChangelog.markPushed}, so a save() with a lower value\n * than the current watermark is silently ignored. This keeps a\n * SyncEngine + LocalChangelog mixed-write path safe.\n *\n * Non-monotonic fields:\n * - `lastSyncAt`, `syncStatus`, `deviceId` are written as-is. The\n * state machine (`idle → syncing → active → idle` etc.) and the\n * `last_sync_at` clock have valid backwards transitions in some\n * edge cases (test reset, manual rollback) and we must not block\n * them.\n *\n * Unknown fields are caught at compile time by `Partial<AppState>`.\n * Defense-in-depth: at runtime we iterate the explicit list of fields\n * we know how to serialise rather than `Object.keys(update)`.\n */\n async save(update: Partial<AppState>): Promise<void> {\n if (update.deviceId !== undefined) {\n if (!isValidDeviceId(update.deviceId)) {\n throw new Error(`SyncStateStore: refusing to save invalid device_id: ${update.deviceId}`);\n }\n await this.writeKey(this.keyFor(\"deviceId\"), update.deviceId);\n }\n if (update.cloudSeq !== undefined) {\n await this.writeKeyMonotonic(this.keyFor(\"cloudSeq\"), update.cloudSeq);\n }\n if (update.localSeq !== undefined) {\n await this.writeKeyMonotonic(this.keyFor(\"localSeq\"), update.localSeq);\n }\n if (update.lastSyncAt !== undefined) {\n const safe = Math.max(\n 0,\n Math.floor(Number.isFinite(update.lastSyncAt) ? update.lastSyncAt : 0),\n );\n await this.writeKey(this.keyFor(\"lastSyncAt\"), String(safe));\n }\n if (update.syncStatus !== undefined) {\n await this.writeKey(this.keyFor(\"syncStatus\"), serializeSyncStatus(update.syncStatus));\n }\n }\n\n // ── private SQL helpers ───────────────────────────────────────\n\n /** Plain INSERT OR REPLACE for non-monotonic keys. */\n private async writeKey(key: string, value: string): Promise<void> {\n await this.client.execute({\n sql: `INSERT INTO ds_sync_state (key, value) VALUES (?, ?)\n ON CONFLICT(key) DO UPDATE SET value = excluded.value`,\n args: [key, value],\n });\n }\n\n /**\n * Monotonic INSERT OR REPLACE for integer keys. Mirror of the helper in\n * {@link LocalChangelog.writeSeqKeyMonotonic} so the two classes converge\n * on the same on-disk representation regardless of which one performs\n * the write.\n */\n private async writeKeyMonotonic(key: string, seq: number): Promise<void> {\n const safe = Math.max(0, Math.floor(Number.isFinite(seq) ? seq : 0));\n await this.client.execute({\n sql: `INSERT INTO ds_sync_state (key, value) VALUES (?, ?)\n ON CONFLICT(key) DO UPDATE SET\n value = CASE\n WHEN CAST(excluded.value AS INTEGER) > CAST(ds_sync_state.value AS INTEGER)\n THEN excluded.value\n ELSE ds_sync_state.value\n END`,\n args: [key, String(safe)],\n });\n }\n}\n\n/**\n * Parse a stored numeric value (cloud_seq / local_seq / last_sync_at).\n *\n * Missing → 0 (the \"nothing recorded yet\" sentinel, matches LocalChangelog).\n * Non-integer / non-numeric → throws to surface corruption to the caller.\n */\nfunction parseSeqValue(raw: string | undefined, label: string): number {\n if (raw === undefined) return 0;\n const parsed = Number(raw);\n if (!Number.isFinite(parsed) || !Number.isInteger(parsed)) {\n throw new Error(`SyncStateStore: corrupt ${label} value: ${raw}`);\n }\n return parsed;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoEA,SAAgB,kBAA4B;AAC1C,QAAO;EACL,UAAU;EACV,UAAU;EACV,UAAU;EACV,YAAY;EACZ,YAAY,EAAE,MAAM,QAAQ;EAC7B;;;;;;;;;;;;AAaH,MAAa,kBAAkB;CAC7B,UAAU;EAAE,MAAM;EAAa,QAAQ;EAAO;CAC9C,UAAU;EAAE,MAAM;EAAa,QAAQ;EAAM;CAC7C,UAAU;EAAE,MAAM;EAAa,QAAQ;EAAM;CAC7C,YAAY;EAAE,MAAM;EAAgB,QAAQ;EAAM;CAClD,YAAY;EAAE,MAAM;EAAe,QAAQ;EAAM;CAClD;;;;;;;;;;;;;;;AA2BD,SAAgB,oBAAoB,QAA4B;AAC9D,SAAQ,OAAO,MAAf;EACE,KAAK,OACH,QAAO;EACT,KAAK,UACH,QAAO;EACT,KAAK,SACH,QAAO;EACT,KAAK,QACH,QAAO,SAAS,OAAO;;;;;;;;AAS7B,SAAgB,gBAAgB,KAAyB;AACvD,KAAI,QAAQ,OAAQ,QAAO,EAAE,MAAM,QAAQ;AAC3C,KAAI,QAAQ,UAAW,QAAO,EAAE,MAAM,WAAW;AACjD,KAAI,QAAQ,SAAU,QAAO,EAAE,MAAM,UAAU;AAC/C,KAAI,IAAI,WAAW,SAAS,CAC1B,QAAO;EAAE,MAAM;EAAS,SAAS,IAAI,MAAM,EAAgB;EAAE;AAE/D,OAAM,IAAI,MAAM,8CAA8C,MAAM;;;;;;;;;;;;AAatE,MAAa,sBAAsB;;AAGnC,SAAgB,gBAAgB,UAA2B;AACzD,QAAO,oBAAoB,KAAK,SAAS;;;;;;;AAQ3C,SAAgB,wBAAwB,MAAuB;AAE7D,QAAO,cADI,QAAQ,OAAO,YAAY;;AAIxC,IAAa,iBAAb,MAA4B;CAC1B,AAAiB;CACjB,AAAiB;CAEjB,YAAY,MAA6B;AACvC,MAAI,OAAO,KAAK,UAAU,YAAY,KAAK,MAAM,WAAW,EAC1D,OAAM,IAAI,MAAM,mDAAmD;AAErE,OAAK,SAAS,KAAK;AACnB,OAAK,QAAQ,KAAK;;;;;;;;;CAUpB,aAAa,YAAY,QAAwD;AAC/E,QAAM,OAAO,QAAQ,qBAAqB;AAC1C,OAAK,MAAM,OAAO,qBAChB,OAAM,OAAO,QAAQ,IAAI;;;;;;;;CAY7B,AAAQ,OAAO,OAA6C;EAC1D,MAAM,OAAO,gBAAgB;AAC7B,SAAO,KAAK,SAAS,GAAG,KAAK,MAAM,GAAG,KAAK,SAAS,KAAK;;;;;;;;;;;;;;;;CAmB3D,MAAM,OAA0B;EAC9B,MAAM,QAAQ,iBAAiB;EAE/B,MAAM,SAAS,MAAM,KAAK,OAAO,QAAQ;GACvC,KAAK;GACL,MAAM;IACJ,KAAK,OAAO,WAAW;IACvB,KAAK,OAAO,WAAW;IACvB,KAAK,OAAO,WAAW;IACvB,KAAK,OAAO,aAAa;IACzB,KAAK,OAAO,aAAa;IAC1B;GACF,CAAC;EAEF,MAAM,uBAAO,IAAI,KAAqB;AACtC,OAAK,MAAM,OAAO,OAAO,MAAM;GAC7B,MAAM,IAAI,IAAI;GACd,MAAM,IAAI,IAAI;AACd,OAAI,OAAO,MAAM,aAAa,OAAO,MAAM,YAAY,OAAO,MAAM,UAClE,MAAK,IAAI,GAAG,OAAO,EAAE,CAAC;;EAI1B,MAAM,cAAc,KAAK,IAAI,KAAK,OAAO,WAAW,CAAC;AACrD,MAAI,gBAAgB,QAAW;AAC7B,OAAI,CAAC,gBAAgB,YAAY,CAC/B,OAAM,IAAI,MAAM,4CAA4C,cAAc;AAE5E,SAAM,WAAW;SACZ;GAKL,MAAM,QAAQ,yBAAyB;AACvC,SAAM,KAAK,SAAS,KAAK,OAAO,WAAW,EAAE,MAAM;AACnD,SAAM,WAAW;;AAGnB,QAAM,WAAW,cAAc,KAAK,IAAI,KAAK,OAAO,WAAW,CAAC,EAAE,YAAY;AAC9E,QAAM,WAAW,cAAc,KAAK,IAAI,KAAK,OAAO,WAAW,CAAC,EAAE,YAAY;AAC9E,QAAM,aAAa,cAAc,KAAK,IAAI,KAAK,OAAO,aAAa,CAAC,EAAE,eAAe;EAErF,MAAM,YAAY,KAAK,IAAI,KAAK,OAAO,aAAa,CAAC;AACrD,MAAI,cAAc,OAChB,OAAM,aAAa,gBAAgB,UAAU;AAG/C,SAAO;;;;;;;;;;;;;;;;;;;;;;;;CA2BT,MAAM,KAAK,QAA0C;AACnD,MAAI,OAAO,aAAa,QAAW;AACjC,OAAI,CAAC,gBAAgB,OAAO,SAAS,CACnC,OAAM,IAAI,MAAM,uDAAuD,OAAO,WAAW;AAE3F,SAAM,KAAK,SAAS,KAAK,OAAO,WAAW,EAAE,OAAO,SAAS;;AAE/D,MAAI,OAAO,aAAa,OACtB,OAAM,KAAK,kBAAkB,KAAK,OAAO,WAAW,EAAE,OAAO,SAAS;AAExE,MAAI,OAAO,aAAa,OACtB,OAAM,KAAK,kBAAkB,KAAK,OAAO,WAAW,EAAE,OAAO,SAAS;AAExE,MAAI,OAAO,eAAe,QAAW;GACnC,MAAM,OAAO,KAAK,IAChB,GACA,KAAK,MAAM,OAAO,SAAS,OAAO,WAAW,GAAG,OAAO,aAAa,EAAE,CACvE;AACD,SAAM,KAAK,SAAS,KAAK,OAAO,aAAa,EAAE,OAAO,KAAK,CAAC;;AAE9D,MAAI,OAAO,eAAe,OACxB,OAAM,KAAK,SAAS,KAAK,OAAO,aAAa,EAAE,oBAAoB,OAAO,WAAW,CAAC;;;CAO1F,MAAc,SAAS,KAAa,OAA8B;AAChE,QAAM,KAAK,OAAO,QAAQ;GACxB,KAAK;;GAEL,MAAM,CAAC,KAAK,MAAM;GACnB,CAAC;;;;;;;;CASJ,MAAc,kBAAkB,KAAa,KAA4B;EACvE,MAAM,OAAO,KAAK,IAAI,GAAG,KAAK,MAAM,OAAO,SAAS,IAAI,GAAG,MAAM,EAAE,CAAC;AACpE,QAAM,KAAK,OAAO,QAAQ;GACxB,KAAK;;;;;;;GAOL,MAAM,CAAC,KAAK,OAAO,KAAK,CAAC;GAC1B,CAAC;;;;;;;;;AAUN,SAAS,cAAc,KAAyB,OAAuB;AACrE,KAAI,QAAQ,OAAW,QAAO;CAC9B,MAAM,SAAS,OAAO,IAAI;AAC1B,KAAI,CAAC,OAAO,SAAS,OAAO,IAAI,CAAC,OAAO,UAAU,OAAO,CACvD,OAAM,IAAI,MAAM,2BAA2B,MAAM,UAAU,MAAM;AAEnE,QAAO"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
|
|
2
|
+
//#region src/timestamp.ts
|
|
3
|
+
/**
|
|
4
|
+
* Timestamp normalization for the createdAt → ctime feed-sort fix
|
|
5
|
+
* (planning/did-integration/feed-sort-createdat, design §4).
|
|
6
|
+
*
|
|
7
|
+
* The `entries.ctime` / `entries.mtime` columns are INTEGER unix-ms; the
|
|
8
|
+
* application `createdAt` / `updatedAt` are ISO-8601 strings produced by
|
|
9
|
+
* `generate.timeiso` (`YYYY-MM-DDTHH:MM:SS.sssZ`, data-contract §2). These
|
|
10
|
+
* pure helpers bridge the two so a write/backfill can stamp `ctime` from the
|
|
11
|
+
* application timestamp.
|
|
12
|
+
*
|
|
13
|
+
* STRICT INVARIANTS (design §4, tri-runtime contract — TS `Date.parse`,
|
|
14
|
+
* Swift `ISO8601DateFormatter`, Kotlin `Instant.parse` MUST agree on the
|
|
15
|
+
* canonical format AND on the fallback behavior for malformed input):
|
|
16
|
+
* - The functions are PURE: no clock read (except the explicit `fallbackMs`
|
|
17
|
+
* argument), no env, no I/O, no SQL — they never throw and never log the
|
|
18
|
+
* input.
|
|
19
|
+
* - `normalizeTs` returns a finite epoch-ms `number > 0`, or `null`. It NEVER
|
|
20
|
+
* returns `NaN`, `0`, a negative, or a non-finite value, so a caller that
|
|
21
|
+
* does `normalizeTs(x) ?? fallback` can never persist `NaN`/`NULL` into a
|
|
22
|
+
* ctime/mtime column.
|
|
23
|
+
* - `resolveCtime` consumes ONLY explicit `metadata` — it does not touch
|
|
24
|
+
* bytes/path and does not call `readApplicationMetadata` (design §5 intro).
|
|
25
|
+
*/
|
|
26
|
+
/**
|
|
27
|
+
* Parse an application timestamp value into epoch-ms.
|
|
28
|
+
*
|
|
29
|
+
* @param v - candidate value (typically `metadata.createdAt`, an ISO string;
|
|
30
|
+
* a raw epoch-ms number is also accepted for forward-compat).
|
|
31
|
+
* @returns finite epoch-ms `> 0`, or `null` when the input is missing, the
|
|
32
|
+
* wrong type, unparseable, or non-positive (`≤ 0`, which includes the 1970
|
|
33
|
+
* epoch and pre-epoch dates — those fall back rather than sink to ctime 0).
|
|
34
|
+
*
|
|
35
|
+
* Contract (design §4 / tasks 0-1):
|
|
36
|
+
* - string → `Date.parse(v)`; keep only when finite and `> 0`.
|
|
37
|
+
* - number → keep only when finite and `> 0` (already epoch-ms).
|
|
38
|
+
* - other → `null`.
|
|
39
|
+
*/
|
|
40
|
+
function normalizeTs(v) {
|
|
41
|
+
let ms;
|
|
42
|
+
if (typeof v === "number") ms = v;
|
|
43
|
+
else if (typeof v === "string") ms = Date.parse(v);
|
|
44
|
+
else return null;
|
|
45
|
+
return Number.isFinite(ms) && ms > 0 ? ms : null;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Resolve the `ctime` to stamp for a write, from explicit application
|
|
49
|
+
* metadata, falling back to a caller-supplied epoch-ms.
|
|
50
|
+
*
|
|
51
|
+
* `= normalizeTs(metadata?.createdAt) ?? fallbackMs`. Because `fallbackMs` is
|
|
52
|
+
* a `number` (not `number | null`) and `normalizeTs` never returns `0`, the
|
|
53
|
+
* result is ALWAYS a finite `number` — callers can stamp it into a ctime
|
|
54
|
+
* column without a NaN/NULL guard.
|
|
55
|
+
*
|
|
56
|
+
* Only `metadata.createdAt` is read; bytes/path are never touched (design
|
|
57
|
+
* §5 intro). The caller is responsible for having already lifted the
|
|
58
|
+
* application metadata into `metadata` (cloud: `payload.meta`; local-apply:
|
|
59
|
+
* `SyncEngine` via `readAppMeta(bytes)`).
|
|
60
|
+
*/
|
|
61
|
+
function resolveCtime(metadata, fallbackMs) {
|
|
62
|
+
return normalizeTs(metadata?.createdAt) ?? fallbackMs;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Resolve the direct-parent DIR row stamp for Rule R2 (design §3 / §5.2).
|
|
66
|
+
*
|
|
67
|
+
* @returns `{ ctime, mtime }` to UPSERT onto the written entry's DIRECT parent
|
|
68
|
+
* directory row, or `null` when the metadata carries no usable `createdAt`
|
|
69
|
+
* (the caller then keeps `INSERT OR IGNORE` — the dir row is NOT disturbed).
|
|
70
|
+
*
|
|
71
|
+
* - `ctime = normalizeTs(createdAt)` (the gate: null `createdAt` → whole stamp
|
|
72
|
+
* is `null`, so a write without an application createdAt never overwrites a
|
|
73
|
+
* previously stamped DIR ctime).
|
|
74
|
+
* - `mtime = normalizeTs(updatedAt) ?? ctime` (updatedAt falls back to
|
|
75
|
+
* createdAt). DIR rows never enter the changelog (design §1 fact 3) so this
|
|
76
|
+
* mtime carries NO LWW meaning — unlike file-row mtime, which is the LWW
|
|
77
|
+
* arbiter and is NEVER touched by Rule R.
|
|
78
|
+
*
|
|
79
|
+
* Only the direct parent is stamped; ancestors are never propagated to.
|
|
80
|
+
*/
|
|
81
|
+
function resolveParentDirStamp(metadata) {
|
|
82
|
+
const ctime = normalizeTs(metadata?.createdAt);
|
|
83
|
+
if (ctime === null) return null;
|
|
84
|
+
return {
|
|
85
|
+
ctime,
|
|
86
|
+
mtime: normalizeTs(metadata?.updatedAt) ?? ctime
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
//#endregion
|
|
91
|
+
exports.resolveCtime = resolveCtime;
|
|
92
|
+
exports.resolveParentDirStamp = resolveParentDirStamp;
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
//#region src/timestamp.ts
|
|
2
|
+
/**
|
|
3
|
+
* Timestamp normalization for the createdAt → ctime feed-sort fix
|
|
4
|
+
* (planning/did-integration/feed-sort-createdat, design §4).
|
|
5
|
+
*
|
|
6
|
+
* The `entries.ctime` / `entries.mtime` columns are INTEGER unix-ms; the
|
|
7
|
+
* application `createdAt` / `updatedAt` are ISO-8601 strings produced by
|
|
8
|
+
* `generate.timeiso` (`YYYY-MM-DDTHH:MM:SS.sssZ`, data-contract §2). These
|
|
9
|
+
* pure helpers bridge the two so a write/backfill can stamp `ctime` from the
|
|
10
|
+
* application timestamp.
|
|
11
|
+
*
|
|
12
|
+
* STRICT INVARIANTS (design §4, tri-runtime contract — TS `Date.parse`,
|
|
13
|
+
* Swift `ISO8601DateFormatter`, Kotlin `Instant.parse` MUST agree on the
|
|
14
|
+
* canonical format AND on the fallback behavior for malformed input):
|
|
15
|
+
* - The functions are PURE: no clock read (except the explicit `fallbackMs`
|
|
16
|
+
* argument), no env, no I/O, no SQL — they never throw and never log the
|
|
17
|
+
* input.
|
|
18
|
+
* - `normalizeTs` returns a finite epoch-ms `number > 0`, or `null`. It NEVER
|
|
19
|
+
* returns `NaN`, `0`, a negative, or a non-finite value, so a caller that
|
|
20
|
+
* does `normalizeTs(x) ?? fallback` can never persist `NaN`/`NULL` into a
|
|
21
|
+
* ctime/mtime column.
|
|
22
|
+
* - `resolveCtime` consumes ONLY explicit `metadata` — it does not touch
|
|
23
|
+
* bytes/path and does not call `readApplicationMetadata` (design §5 intro).
|
|
24
|
+
*/
|
|
25
|
+
/**
|
|
26
|
+
* Parse an application timestamp value into epoch-ms.
|
|
27
|
+
*
|
|
28
|
+
* @param v - candidate value (typically `metadata.createdAt`, an ISO string;
|
|
29
|
+
* a raw epoch-ms number is also accepted for forward-compat).
|
|
30
|
+
* @returns finite epoch-ms `> 0`, or `null` when the input is missing, the
|
|
31
|
+
* wrong type, unparseable, or non-positive (`≤ 0`, which includes the 1970
|
|
32
|
+
* epoch and pre-epoch dates — those fall back rather than sink to ctime 0).
|
|
33
|
+
*
|
|
34
|
+
* Contract (design §4 / tasks 0-1):
|
|
35
|
+
* - string → `Date.parse(v)`; keep only when finite and `> 0`.
|
|
36
|
+
* - number → keep only when finite and `> 0` (already epoch-ms).
|
|
37
|
+
* - other → `null`.
|
|
38
|
+
*/
|
|
39
|
+
function normalizeTs(v) {
|
|
40
|
+
let ms;
|
|
41
|
+
if (typeof v === "number") ms = v;
|
|
42
|
+
else if (typeof v === "string") ms = Date.parse(v);
|
|
43
|
+
else return null;
|
|
44
|
+
return Number.isFinite(ms) && ms > 0 ? ms : null;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Resolve the `ctime` to stamp for a write, from explicit application
|
|
48
|
+
* metadata, falling back to a caller-supplied epoch-ms.
|
|
49
|
+
*
|
|
50
|
+
* `= normalizeTs(metadata?.createdAt) ?? fallbackMs`. Because `fallbackMs` is
|
|
51
|
+
* a `number` (not `number | null`) and `normalizeTs` never returns `0`, the
|
|
52
|
+
* result is ALWAYS a finite `number` — callers can stamp it into a ctime
|
|
53
|
+
* column without a NaN/NULL guard.
|
|
54
|
+
*
|
|
55
|
+
* Only `metadata.createdAt` is read; bytes/path are never touched (design
|
|
56
|
+
* §5 intro). The caller is responsible for having already lifted the
|
|
57
|
+
* application metadata into `metadata` (cloud: `payload.meta`; local-apply:
|
|
58
|
+
* `SyncEngine` via `readAppMeta(bytes)`).
|
|
59
|
+
*/
|
|
60
|
+
function resolveCtime(metadata, fallbackMs) {
|
|
61
|
+
return normalizeTs(metadata?.createdAt) ?? fallbackMs;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Resolve the direct-parent DIR row stamp for Rule R2 (design §3 / §5.2).
|
|
65
|
+
*
|
|
66
|
+
* @returns `{ ctime, mtime }` to UPSERT onto the written entry's DIRECT parent
|
|
67
|
+
* directory row, or `null` when the metadata carries no usable `createdAt`
|
|
68
|
+
* (the caller then keeps `INSERT OR IGNORE` — the dir row is NOT disturbed).
|
|
69
|
+
*
|
|
70
|
+
* - `ctime = normalizeTs(createdAt)` (the gate: null `createdAt` → whole stamp
|
|
71
|
+
* is `null`, so a write without an application createdAt never overwrites a
|
|
72
|
+
* previously stamped DIR ctime).
|
|
73
|
+
* - `mtime = normalizeTs(updatedAt) ?? ctime` (updatedAt falls back to
|
|
74
|
+
* createdAt). DIR rows never enter the changelog (design §1 fact 3) so this
|
|
75
|
+
* mtime carries NO LWW meaning — unlike file-row mtime, which is the LWW
|
|
76
|
+
* arbiter and is NEVER touched by Rule R.
|
|
77
|
+
*
|
|
78
|
+
* Only the direct parent is stamped; ancestors are never propagated to.
|
|
79
|
+
*/
|
|
80
|
+
function resolveParentDirStamp(metadata) {
|
|
81
|
+
const ctime = normalizeTs(metadata?.createdAt);
|
|
82
|
+
if (ctime === null) return null;
|
|
83
|
+
return {
|
|
84
|
+
ctime,
|
|
85
|
+
mtime: normalizeTs(metadata?.updatedAt) ?? ctime
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
//#endregion
|
|
90
|
+
export { resolveCtime, resolveParentDirStamp };
|
|
91
|
+
//# sourceMappingURL=timestamp.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"timestamp.mjs","names":[],"sources":["../src/timestamp.ts"],"sourcesContent":["/**\n * Timestamp normalization for the createdAt → ctime feed-sort fix\n * (planning/did-integration/feed-sort-createdat, design §4).\n *\n * The `entries.ctime` / `entries.mtime` columns are INTEGER unix-ms; the\n * application `createdAt` / `updatedAt` are ISO-8601 strings produced by\n * `generate.timeiso` (`YYYY-MM-DDTHH:MM:SS.sssZ`, data-contract §2). These\n * pure helpers bridge the two so a write/backfill can stamp `ctime` from the\n * application timestamp.\n *\n * STRICT INVARIANTS (design §4, tri-runtime contract — TS `Date.parse`,\n * Swift `ISO8601DateFormatter`, Kotlin `Instant.parse` MUST agree on the\n * canonical format AND on the fallback behavior for malformed input):\n * - The functions are PURE: no clock read (except the explicit `fallbackMs`\n * argument), no env, no I/O, no SQL — they never throw and never log the\n * input.\n * - `normalizeTs` returns a finite epoch-ms `number > 0`, or `null`. It NEVER\n * returns `NaN`, `0`, a negative, or a non-finite value, so a caller that\n * does `normalizeTs(x) ?? fallback` can never persist `NaN`/`NULL` into a\n * ctime/mtime column.\n * - `resolveCtime` consumes ONLY explicit `metadata` — it does not touch\n * bytes/path and does not call `readApplicationMetadata` (design §5 intro).\n */\n\n/**\n * Parse an application timestamp value into epoch-ms.\n *\n * @param v - candidate value (typically `metadata.createdAt`, an ISO string;\n * a raw epoch-ms number is also accepted for forward-compat).\n * @returns finite epoch-ms `> 0`, or `null` when the input is missing, the\n * wrong type, unparseable, or non-positive (`≤ 0`, which includes the 1970\n * epoch and pre-epoch dates — those fall back rather than sink to ctime 0).\n *\n * Contract (design §4 / tasks 0-1):\n * - string → `Date.parse(v)`; keep only when finite and `> 0`.\n * - number → keep only when finite and `> 0` (already epoch-ms).\n * - other → `null`.\n */\nexport function normalizeTs(v: unknown): number | null {\n let ms: number;\n if (typeof v === \"number\") {\n ms = v;\n } else if (typeof v === \"string\") {\n // Date.parse returns NaN for unparseable input (empty string, garbage,\n // injection payloads) — Number.isFinite then rejects it below.\n ms = Date.parse(v);\n } else {\n return null;\n }\n return Number.isFinite(ms) && ms > 0 ? ms : null;\n}\n\n/**\n * Resolve the `ctime` to stamp for a write, from explicit application\n * metadata, falling back to a caller-supplied epoch-ms.\n *\n * `= normalizeTs(metadata?.createdAt) ?? fallbackMs`. Because `fallbackMs` is\n * a `number` (not `number | null`) and `normalizeTs` never returns `0`, the\n * result is ALWAYS a finite `number` — callers can stamp it into a ctime\n * column without a NaN/NULL guard.\n *\n * Only `metadata.createdAt` is read; bytes/path are never touched (design\n * §5 intro). The caller is responsible for having already lifted the\n * application metadata into `metadata` (cloud: `payload.meta`; local-apply:\n * `SyncEngine` via `readAppMeta(bytes)`).\n */\nexport function resolveCtime(\n metadata: Record<string, unknown> | null | undefined,\n fallbackMs: number,\n): number {\n return normalizeTs(metadata?.createdAt) ?? fallbackMs;\n}\n\n/**\n * Resolve the direct-parent DIR row stamp for Rule R2 (design §3 / §5.2).\n *\n * @returns `{ ctime, mtime }` to UPSERT onto the written entry's DIRECT parent\n * directory row, or `null` when the metadata carries no usable `createdAt`\n * (the caller then keeps `INSERT OR IGNORE` — the dir row is NOT disturbed).\n *\n * - `ctime = normalizeTs(createdAt)` (the gate: null `createdAt` → whole stamp\n * is `null`, so a write without an application createdAt never overwrites a\n * previously stamped DIR ctime).\n * - `mtime = normalizeTs(updatedAt) ?? ctime` (updatedAt falls back to\n * createdAt). DIR rows never enter the changelog (design §1 fact 3) so this\n * mtime carries NO LWW meaning — unlike file-row mtime, which is the LWW\n * arbiter and is NEVER touched by Rule R.\n *\n * Only the direct parent is stamped; ancestors are never propagated to.\n */\nexport function resolveParentDirStamp(\n metadata: Record<string, unknown> | null | undefined,\n): { ctime: number; mtime: number } | null {\n const ctime = normalizeTs(metadata?.createdAt);\n if (ctime === null) return null;\n const mtime = normalizeTs(metadata?.updatedAt) ?? ctime;\n return { ctime, mtime };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAsCA,SAAgB,YAAY,GAA2B;CACrD,IAAI;AACJ,KAAI,OAAO,MAAM,SACf,MAAK;UACI,OAAO,MAAM,SAGtB,MAAK,KAAK,MAAM,EAAE;KAElB,QAAO;AAET,QAAO,OAAO,SAAS,GAAG,IAAI,KAAK,IAAI,KAAK;;;;;;;;;;;;;;;;AAiB9C,SAAgB,aACd,UACA,YACQ;AACR,QAAO,YAAY,UAAU,UAAU,IAAI;;;;;;;;;;;;;;;;;;;AAoB7C,SAAgB,sBACd,UACyC;CACzC,MAAM,QAAQ,YAAY,UAAU,UAAU;AAC9C,KAAI,UAAU,KAAM,QAAO;AAE3B,QAAO;EAAE;EAAO,OADF,YAAY,UAAU,UAAU,IAAI;EAC3B"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
const require_rolldown_runtime = require('../_virtual/rolldown_runtime.cjs');
|
|
2
|
+
const require_remote_afs = require('../remote-afs.cjs');
|
|
3
|
+
let _aigne_afs = require("@aigne/afs");
|
|
4
|
+
|
|
5
|
+
//#region src/transports/http.ts
|
|
6
|
+
const ALLOWED_SCHEMES = new Set(["http:", "https:"]);
|
|
7
|
+
function assertUrlScheme(rawUrl) {
|
|
8
|
+
let parsed;
|
|
9
|
+
try {
|
|
10
|
+
parsed = new URL(rawUrl);
|
|
11
|
+
} catch {
|
|
12
|
+
throw new Error(`HttpTransport: invalid URL: ${rawUrl}`);
|
|
13
|
+
}
|
|
14
|
+
if (!ALLOWED_SCHEMES.has(parsed.protocol)) throw new Error(`HttpTransport: only http(s) is supported, got ${parsed.protocol} (URL: ${rawUrl})`);
|
|
15
|
+
return parsed;
|
|
16
|
+
}
|
|
17
|
+
var HttpTransport = class {
|
|
18
|
+
kind = "http";
|
|
19
|
+
remote;
|
|
20
|
+
constructor(options) {
|
|
21
|
+
assertUrlScheme(options.url);
|
|
22
|
+
this.remote = new require_remote_afs.RemoteUserSpaceAFS({
|
|
23
|
+
baseUrl: options.url,
|
|
24
|
+
token: options.token
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
list(path, options) {
|
|
28
|
+
return this.remote.list(path, options);
|
|
29
|
+
}
|
|
30
|
+
read(path, _options) {
|
|
31
|
+
return this.remote.read(path);
|
|
32
|
+
}
|
|
33
|
+
write(path, payload, _options) {
|
|
34
|
+
return this.remote.write(path, payload);
|
|
35
|
+
}
|
|
36
|
+
delete(path, options) {
|
|
37
|
+
return this.remote.delete(path, options);
|
|
38
|
+
}
|
|
39
|
+
async stat(_path, _options) {
|
|
40
|
+
throw new _aigne_afs.AFSUnsupportedError("stat", "HttpTransport does not expose stat (REST has no /op=stat); use the WS transport for stat.");
|
|
41
|
+
}
|
|
42
|
+
async search(_path, _query, _options) {
|
|
43
|
+
throw new _aigne_afs.AFSUnsupportedError("search", "HttpTransport does not expose search (REST has no /op=search); use the WS transport for search.");
|
|
44
|
+
}
|
|
45
|
+
async exec(_path, _args, _options) {
|
|
46
|
+
throw new _aigne_afs.AFSUnsupportedError("exec", "HttpTransport does not expose exec; use the WS transport for action execution.");
|
|
47
|
+
}
|
|
48
|
+
async explain(_path, _options) {
|
|
49
|
+
throw new _aigne_afs.AFSUnsupportedError("explain", "HttpTransport does not expose explain; use the WS transport for explain.");
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
//#endregion
|
|
54
|
+
exports.HttpTransport = HttpTransport;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Transport } from "./types.cjs";
|
|
2
|
+
import { AFSDeleteOptions, AFSDeleteResult, AFSExecOptions, AFSExecResult, AFSExplainOptions, AFSExplainResult, AFSListOptions, AFSListResult, AFSReadOptions, AFSReadResult, AFSSearchOptions, AFSSearchResult, AFSStatOptions, AFSStatResult, AFSWriteEntryPayload, AFSWriteOptions, AFSWriteResult } from "@aigne/afs";
|
|
3
|
+
|
|
4
|
+
//#region src/transports/http.d.ts
|
|
5
|
+
interface HttpTransportOptions {
|
|
6
|
+
/** Base URL of the DID Space REST server, e.g. `https://computer.afsd.dev`. */
|
|
7
|
+
url: string;
|
|
8
|
+
/** Bearer token for authentication. */
|
|
9
|
+
token: string;
|
|
10
|
+
}
|
|
11
|
+
declare class HttpTransport implements Transport {
|
|
12
|
+
readonly kind: "http";
|
|
13
|
+
private readonly remote;
|
|
14
|
+
constructor(options: HttpTransportOptions);
|
|
15
|
+
list(path: string, options?: AFSListOptions): Promise<AFSListResult>;
|
|
16
|
+
read(path: string, _options?: AFSReadOptions): Promise<AFSReadResult>;
|
|
17
|
+
write(path: string, payload: AFSWriteEntryPayload, _options?: AFSWriteOptions): Promise<AFSWriteResult>;
|
|
18
|
+
delete(path: string, options?: AFSDeleteOptions): Promise<AFSDeleteResult>;
|
|
19
|
+
stat(_path: string, _options?: AFSStatOptions): Promise<AFSStatResult>;
|
|
20
|
+
search(_path: string, _query: string, _options?: AFSSearchOptions): Promise<AFSSearchResult>;
|
|
21
|
+
exec(_path: string, _args: Record<string, unknown>, _options?: AFSExecOptions): Promise<AFSExecResult>;
|
|
22
|
+
explain(_path: string, _options?: AFSExplainOptions): Promise<AFSExplainResult>;
|
|
23
|
+
}
|
|
24
|
+
//#endregion
|
|
25
|
+
export { HttpTransport, HttpTransportOptions };
|
|
26
|
+
//# sourceMappingURL=http.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http.d.cts","names":[],"sources":["../../src/transports/http.ts"],"mappings":";;;;UA4CiB,oBAAA;EAmDgB;EAjD/B,GAAA;EAiDkD;EA/ClD,KAAA;AAAA;AAAA,cAoBW,aAAA,YAAyB,SAAA;EAAA,SAC3B,IAAA;EAAA,iBACQ,MAAA;cAEL,OAAA,EAAS,oBAAA;EAOrB,IAAA,CAAK,IAAA,UAAc,OAAA,GAAU,cAAA,GAAiB,OAAA,CAAQ,aAAA;EAItD,IAAA,CAAK,IAAA,UAAc,QAAA,GAAW,cAAA,GAAiB,OAAA,CAAQ,aAAA;EAIvD,KAAA,CACE,IAAA,UACA,OAAA,EAAS,oBAAA,EACT,QAAA,GAAW,eAAA,GACV,OAAA,CAAQ,cAAA;EAIX,MAAA,CAAO,IAAA,UAAc,OAAA,GAAU,gBAAA,GAAmB,OAAA,CAAQ,eAAA;EAIpD,IAAA,CAAK,KAAA,UAAe,QAAA,GAAW,cAAA,GAAiB,OAAA,CAAQ,aAAA;EAOxD,MAAA,CACJ,KAAA,UACA,MAAA,UACA,QAAA,GAAW,gBAAA,GACV,OAAA,CAAQ,eAAA;EAOL,IAAA,CACJ,KAAA,UACA,KAAA,EAAO,MAAA,mBACP,QAAA,GAAW,cAAA,GACV,OAAA,CAAQ,aAAA;EAOL,OAAA,CAAQ,KAAA,UAAe,QAAA,GAAW,iBAAA,GAAoB,OAAA,CAAQ,gBAAA;AAAA"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Transport } from "./types.mjs";
|
|
2
|
+
import { AFSDeleteOptions, AFSDeleteResult, AFSExecOptions, AFSExecResult, AFSExplainOptions, AFSExplainResult, AFSListOptions, AFSListResult, AFSReadOptions, AFSReadResult, AFSSearchOptions, AFSSearchResult, AFSStatOptions, AFSStatResult, AFSWriteEntryPayload, AFSWriteOptions, AFSWriteResult } from "@aigne/afs";
|
|
3
|
+
|
|
4
|
+
//#region src/transports/http.d.ts
|
|
5
|
+
interface HttpTransportOptions {
|
|
6
|
+
/** Base URL of the DID Space REST server, e.g. `https://computer.afsd.dev`. */
|
|
7
|
+
url: string;
|
|
8
|
+
/** Bearer token for authentication. */
|
|
9
|
+
token: string;
|
|
10
|
+
}
|
|
11
|
+
declare class HttpTransport implements Transport {
|
|
12
|
+
readonly kind: "http";
|
|
13
|
+
private readonly remote;
|
|
14
|
+
constructor(options: HttpTransportOptions);
|
|
15
|
+
list(path: string, options?: AFSListOptions): Promise<AFSListResult>;
|
|
16
|
+
read(path: string, _options?: AFSReadOptions): Promise<AFSReadResult>;
|
|
17
|
+
write(path: string, payload: AFSWriteEntryPayload, _options?: AFSWriteOptions): Promise<AFSWriteResult>;
|
|
18
|
+
delete(path: string, options?: AFSDeleteOptions): Promise<AFSDeleteResult>;
|
|
19
|
+
stat(_path: string, _options?: AFSStatOptions): Promise<AFSStatResult>;
|
|
20
|
+
search(_path: string, _query: string, _options?: AFSSearchOptions): Promise<AFSSearchResult>;
|
|
21
|
+
exec(_path: string, _args: Record<string, unknown>, _options?: AFSExecOptions): Promise<AFSExecResult>;
|
|
22
|
+
explain(_path: string, _options?: AFSExplainOptions): Promise<AFSExplainResult>;
|
|
23
|
+
}
|
|
24
|
+
//#endregion
|
|
25
|
+
export { HttpTransport, HttpTransportOptions };
|
|
26
|
+
//# sourceMappingURL=http.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http.d.mts","names":[],"sources":["../../src/transports/http.ts"],"mappings":";;;;UA4CiB,oBAAA;EAmDgB;EAjD/B,GAAA;EAiDkD;EA/ClD,KAAA;AAAA;AAAA,cAoBW,aAAA,YAAyB,SAAA;EAAA,SAC3B,IAAA;EAAA,iBACQ,MAAA;cAEL,OAAA,EAAS,oBAAA;EAOrB,IAAA,CAAK,IAAA,UAAc,OAAA,GAAU,cAAA,GAAiB,OAAA,CAAQ,aAAA;EAItD,IAAA,CAAK,IAAA,UAAc,QAAA,GAAW,cAAA,GAAiB,OAAA,CAAQ,aAAA;EAIvD,KAAA,CACE,IAAA,UACA,OAAA,EAAS,oBAAA,EACT,QAAA,GAAW,eAAA,GACV,OAAA,CAAQ,cAAA;EAIX,MAAA,CAAO,IAAA,UAAc,OAAA,GAAU,gBAAA,GAAmB,OAAA,CAAQ,eAAA;EAIpD,IAAA,CAAK,KAAA,UAAe,QAAA,GAAW,cAAA,GAAiB,OAAA,CAAQ,aAAA;EAOxD,MAAA,CACJ,KAAA,UACA,MAAA,UACA,QAAA,GAAW,gBAAA,GACV,OAAA,CAAQ,eAAA;EAOL,IAAA,CACJ,KAAA,UACA,KAAA,EAAO,MAAA,mBACP,QAAA,GAAW,cAAA,GACV,OAAA,CAAQ,aAAA;EAOL,OAAA,CAAQ,KAAA,UAAe,QAAA,GAAW,iBAAA,GAAoB,OAAA,CAAQ,gBAAA;AAAA"}
|