@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 @@
|
|
|
1
|
+
{"version":3,"file":"remote-afs.mjs","names":["body","res"],"sources":["../src/remote-afs.ts"],"sourcesContent":["/**\n * RemoteUserSpaceAFS — HTTP adapter for the /api/space/{path} REST API.\n *\n * @deprecated since 2026-04. This class is the wrong abstraction:\n * - Treats REST as the canonical DID Space interface (it should be one\n * transport among many: WS, HTTP, static-readonly, in-process).\n * - Does not extend `AFSBaseProvider` and cannot be `afs.mount()`'d.\n *\n * Replacement: transport-pluggable `DIDSpaceProvider` + `RpcUserSpaceAFS`\n * (afs-rpc). See `planning/did-integration/did-space-mobile-transport/`.\n *\n * Until Phase 3 lands, this class is still used by `arc space\n * export/import/diff` and by the SyncEngine push/pull/fullResync path.\n *\n * Provides a minimal AFS-compatible interface (list, read, write, delete)\n * that maps to the remote ARC Computer's DID Space REST API. Sync-specific\n * metadata (deviceId / contentCid / ifMatch / mtime) flows through\n * `AFSWriteEntryPayload.meta.extra` and `AFSDeleteOptions.meta`; incremental\n * changelog and content-addressed reads flow through the virtual paths\n * `.changelog/{seq}` (cursor) and `.objects/{cid}` (raw bytes) — both\n * consumed by the SyncEngine as plain AFS `list` / `read` calls.\n *\n * The remote API uses user-root semantics: paths map directly to the\n * authenticated user's DID Space.\n */\n\nimport type {\n AFSBatchDeleteEntry,\n AFSBatchWriteEntry,\n AFSDeleteOptions,\n AFSDeleteResult,\n AFSListOptions,\n AFSListResult,\n AFSReadResult,\n AFSWriteEntryPayload,\n AFSWriteResult,\n} from \"@aigne/afs\";\nimport {\n AFSCompactedError,\n AFSConflictError,\n AFSNotFoundError,\n AFSValidationError,\n} from \"@aigne/afs\";\nimport { encodePath, joinURL } from \"ufo\";\nimport { computeCID } from \"./cid.js\";\nimport { isTextMime } from \"./mime-utils.js\";\n\n/**\n * Loopback hosts that may be served over plain http (no HTTPS requirement).\n * Covers `localhost`, the reserved `*.localhost` subdomains (RFC 6761 — always\n * loopback, e.g. `aside.localhost:8787` for local multi-app dev where the\n * subdomain selects the blocklet), and the IPv4/IPv6 loopback literals.\n */\nfunction isLoopbackHost(hostname: string): boolean {\n const h = hostname.toLowerCase().replace(/^\\[|\\]$/g, \"\");\n return h === \"localhost\" || h.endsWith(\".localhost\") || h === \"127.0.0.1\" || h === \"::1\";\n}\n\nexport interface RemoteUserSpaceAFSOptions {\n /** Base URL of the ARC Computer (e.g. \"https://computer.afsd.dev\") */\n baseUrl: string;\n /** Bearer token for authentication */\n token: string;\n}\n\nexport class RemoteUserSpaceAFS {\n readonly name = \"remote-user-space\";\n private baseUrl: string;\n private token: string;\n\n constructor(options: RemoteUserSpaceAFSOptions) {\n // Enforce HTTPS for non-localhost URLs (security requirement)\n const url = new URL(options.baseUrl);\n if (url.protocol !== \"https:\" && !isLoopbackHost(url.hostname)) {\n throw new Error(\n `HTTPS required for remote connections (got ${url.protocol}//${url.hostname})`,\n );\n }\n this.baseUrl = options.baseUrl;\n this.token = options.token;\n }\n\n private apiUrl(path: string, params?: Record<string, string>): string {\n // joinURL strips trailing slash, but the server requires /api/space/ prefix.\n // Ensure the path segment always has a trailing slash for root (\"/\").\n const url = joinURL(this.baseUrl, \"/api/space/\", encodePath(path));\n if (!params) return url;\n const search = new URLSearchParams(params);\n return `${url}?${search.toString()}`;\n }\n\n private headers(): HeadersInit {\n return { Authorization: `Bearer ${this.token}` };\n }\n\n private async handleResponse<T>(res: Response, path: string): Promise<T> {\n if (res.ok) return res.json() as Promise<T>;\n\n if (res.status === 404) {\n throw new AFSNotFoundError(path);\n }\n if (res.status === 401) {\n throw new Error(\"Authentication failed: check your access token\");\n }\n if (res.status === 409) {\n await this.handle409(res, path);\n }\n\n // Parse error body for non-standard status codes\n const errorMsg = await this.parseErrorBody(res);\n throw new Error(`Remote AFS error at ${path}: ${errorMsg}`);\n }\n\n /**\n * Parse a 409 response body and throw the appropriate AFS error:\n * - `{ error: \"if_match_failed\", currentCid, currentMtime, currentDeviceId }` → AFSConflictError\n * - `{ requireFullResync: true, compactedBelowSeq }` → AFSCompactedError\n * - Otherwise → generic error\n */\n private async handle409(res: Response, path: string): Promise<never> {\n let body: Record<string, unknown>;\n try {\n body = (await res.json()) as Record<string, unknown>;\n } catch {\n throw new Error(`Remote AFS 409 at ${path}`);\n }\n\n if (body.requireFullResync === true) {\n const seq = typeof body.compactedBelowSeq === \"number\" ? body.compactedBelowSeq : 0;\n throw new AFSCompactedError(path, String(seq));\n }\n\n // T4.1 存量 bug fix: the live servers send the stable wire code\n // `code: \"AFS_CONFLICT\"` (afs-rpc-wire.ts WIRE_ERROR_CODES.conflict) —\n // the old `error === \"if_match_failed\"` string never matched, so the TS\n // single-op path could not produce AFSConflictError. Key on the code OR\n // triple-field presence (Swift's throwConflict convention); keep the\n // legacy string as a back-compat alias.\n if (body.code === \"AFS_CONFLICT\" || body.error === \"if_match_failed\" || \"currentCid\" in body) {\n throw new AFSConflictError(path, {\n cid: typeof body.currentCid === \"string\" ? body.currentCid : null,\n mtime: typeof body.currentMtime === \"number\" ? body.currentMtime : null,\n deviceId: typeof body.currentDeviceId === \"string\" ? body.currentDeviceId : null,\n });\n }\n\n throw new Error(`Remote AFS 409 at ${path}: ${JSON.stringify(body)}`);\n }\n\n private async parseErrorBody(res: Response): Promise<string> {\n try {\n const body = (await res.json()) as { error?: string };\n return body.error || `HTTP ${res.status}`;\n } catch {\n return `HTTP ${res.status}`;\n }\n }\n\n async list(path: string, options?: AFSListOptions): Promise<AFSListResult> {\n const params: Record<string, string> = { op: \"list\" };\n const normPath = path.startsWith(\"/\") ? path.slice(1) : path;\n const isChangelog = normPath === \".changelog\" || normPath.startsWith(\".changelog/\");\n\n if (options?.maxDepth === -1) {\n // §0.5 Decision #3: .changelog does not support maxDepth=-1\n if (isChangelog) {\n throw new AFSValidationError(\n \".changelog path does not support maxDepth=-1 (changelog uses cursor-based incremental access)\",\n );\n }\n // Mutex: maxDepth=-1 cannot be combined with cursor/limit/offset.\n // The server returns the full snapshot in one response (G5.b CTE);\n // pagination params are meaningless and would break the consistency\n // guarantee.\n if (\n (options.limit !== undefined && Number.isFinite(options.limit)) ||\n (options.offset !== undefined && Number.isFinite(options.offset)) ||\n options.cursor !== undefined\n ) {\n throw new AFSValidationError(\n \"list with maxDepth=-1 cannot be combined with cursor, limit, or offset\",\n );\n }\n // Fall through: pass maxDepth=-1 to the server. DIDSpaceProvider.list()\n // handles the snapshot natively and returns meta.cursor = manifestSeq.\n }\n\n if (options?.maxDepth !== undefined) {\n params.maxDepth = String(options.maxDepth);\n }\n\n // .changelog path with cursor → changelog listing\n if (isChangelog && options?.cursor !== undefined) {\n params.cursor = String(options.cursor);\n }\n\n if (!isChangelog) {\n if (options?.limit !== undefined && Number.isFinite(options.limit)) {\n params.limit = String(options.limit);\n }\n if (options?.offset !== undefined && Number.isFinite(options.offset)) {\n params.offset = String(options.offset);\n }\n }\n\n const res = await fetch(this.apiUrl(path, params), {\n headers: this.headers(),\n });\n return this.handleResponse<AFSListResult>(res, path);\n }\n\n async read(path: string): Promise<AFSReadResult> {\n // Task 1.3: .objects/{cid} path → raw GET with CID verification\n const normPath = path.startsWith(\"/\") ? path.slice(1) : path;\n if (normPath.startsWith(\".objects/\")) {\n return this.readObject(path, normPath);\n }\n\n const res = await fetch(this.apiUrl(path), {\n headers: this.headers(),\n });\n\n // Error responses are still JSON\n if (!res.ok) {\n return this.handleResponse<AFSReadResult>(res, path);\n }\n\n const contentType = res.headers.get(\"Content-Type\") || \"\";\n\n // Distinguish raw file content from JSON-wrapped API responses:\n // afsToReadResponse always sets X-AFS-Kind header for file/directory content.\n // If absent, the response is a legacy JSON-wrapped AFSReadResult (directories, etc.).\n const hasAfsHeaders = res.headers.has(\"X-AFS-Kind\");\n if (!hasAfsHeaders && contentType.includes(\"application/json\")) {\n return res.json() as Promise<AFSReadResult>;\n }\n\n // Extract metadata from X-AFS-* headers\n const meta: Record<string, unknown> = {};\n const kind = res.headers.get(\"X-AFS-Kind\");\n const cid = res.headers.get(\"X-AFS-CID\");\n const size = res.headers.get(\"X-AFS-Size\");\n const mimeType = res.headers.get(\"X-AFS-MimeType\");\n const childrenCount = res.headers.get(\"X-AFS-ChildrenCount\");\n\n meta.kind = kind || \"did-space:file\";\n if (cid) meta.cid = cid;\n if (size) meta.size = Number(size);\n if (mimeType) meta.mimeType = mimeType;\n if (childrenCount != null) meta.childrenCount = Number(childrenCount);\n\n // Determine content type: use X-AFS-MimeType (exact mime) for classification,\n // fall back to Content-Type header (may include charset suffix)\n const mimeForClassification = mimeType || (contentType.split(\";\")[0] ?? \"\").trim() || undefined;\n const content = isTextMime(mimeForClassification) ? await res.text() : await res.arrayBuffer();\n\n const createdAt = res.headers.get(\"X-AFS-CreatedAt\");\n const updatedAt = res.headers.get(\"X-AFS-UpdatedAt\");\n\n return {\n data: {\n id: path,\n path,\n content,\n meta,\n createdAt: createdAt ? new Date(createdAt) : undefined,\n updatedAt: updatedAt ? new Date(updatedAt) : undefined,\n },\n };\n }\n\n /**\n * Task 1.3: read a content-addressed object by path `.objects/{cid}`.\n * Calls `GET /api/space/.objects/{cid}`, reads raw bytes, then recomputes\n * the CID to verify integrity before returning.\n */\n private async readObject(path: string, normPath: string): Promise<AFSReadResult> {\n const requestedCid = normPath.slice(\".objects/\".length);\n const res = await fetch(this.apiUrl(path), {\n headers: this.headers(),\n });\n if (!res.ok) {\n return this.handleResponse<AFSReadResult>(res, path);\n }\n const ab = await res.arrayBuffer();\n const bytes = new Uint8Array(ab);\n // CID integrity check — defends against MITM and server bugs\n const actualCid = await computeCID(bytes);\n if (actualCid !== requestedCid) {\n throw new Error(`read .objects: CID mismatch (requested ${requestedCid}, got ${actualCid})`);\n }\n return {\n data: {\n id: path,\n path,\n content: bytes,\n meta: { kind: \"did-space:object\", cid: requestedCid, size: bytes.length },\n },\n };\n }\n\n async write(path: string, payload: AFSWriteEntryPayload): Promise<AFSWriteResult> {\n const content = payload.content;\n\n // Task 1.1: extract sync metadata from meta.extra\n const extra = payload.meta?.extra as Record<string, unknown> | undefined;\n const extraHeaders: Record<string, string> = {};\n if (extra) {\n if (typeof extra.contentCid === \"string\") extraHeaders[\"X-Content-CID\"] = extra.contentCid;\n if (typeof extra.deviceId === \"string\") extraHeaders[\"X-Device-Id\"] = extra.deviceId;\n if (typeof extra.mtime === \"number\") extraHeaders[\"X-Mtime\"] = String(extra.mtime);\n if (typeof extra.ifMatch === \"string\") extraHeaders[\"If-Match\"] = extra.ifMatch;\n }\n\n // Binary upload — raw body, server's getWritePayload() handles octet-stream\n if (content instanceof ArrayBuffer || content instanceof Uint8Array) {\n const body =\n content instanceof Uint8Array\n ? (content.buffer as ArrayBuffer).slice(\n content.byteOffset,\n content.byteOffset + content.byteLength,\n )\n : content;\n const res = await fetch(this.apiUrl(path), {\n method: \"PUT\",\n headers: { ...this.headers(), \"Content-Type\": \"application/octet-stream\", ...extraHeaders },\n body,\n });\n return this.handleResponse<AFSWriteResult>(res, path);\n }\n\n // Text/object content — send raw content with appropriate Content-Type.\n // Server's getWritePayload expects the body to be the file content itself\n // (same convention as publish.ts), not a JSON-wrapped payload.\n const isString = typeof content === \"string\";\n const body = isString ? content : JSON.stringify(content);\n const mimeType = isString ? \"text/plain\" : \"application/json\";\n const res = await fetch(this.apiUrl(path), {\n method: \"PUT\",\n headers: { ...this.headers(), \"Content-Type\": mimeType, ...extraHeaders },\n body,\n });\n return this.handleResponse<AFSWriteResult>(res, path);\n }\n\n async delete(path: string, opts?: AFSDeleteOptions): Promise<AFSDeleteResult> {\n // Task 1.2: extract sync metadata from opts.meta\n const meta = opts?.meta as Record<string, unknown> | undefined;\n const extraHeaders: Record<string, string> = {};\n if (meta) {\n if (typeof meta.deviceId === \"string\") extraHeaders[\"X-Device-Id\"] = meta.deviceId;\n if (typeof meta.mtime === \"number\") extraHeaders[\"X-Mtime\"] = String(meta.mtime);\n if (typeof meta.ifMatch === \"string\") extraHeaders[\"If-Match\"] = meta.ifMatch;\n }\n\n const res = await fetch(this.apiUrl(path), {\n method: \"DELETE\",\n headers: { ...this.headers(), ...extraHeaders },\n });\n return this.handleResponse<AFSDeleteResult>(res, path);\n }\n}\n\n// ═══════════════════════════════════════════════════════════════════════\n// RpcUserSpaceAFS — afs-rpc wire transport (afs-rpc-batch P4)\n// ═══════════════════════════════════════════════════════════════════════\n\n/** Per-entry batch result restored from a wire `results[i]` (single-op iso). */\nexport interface RpcBatchEntryResult {\n path: string;\n success: boolean;\n /** Wire `status` verbatim (200/404/409/503/…). */\n status: number;\n data?: Record<string, unknown>;\n error?: string;\n code?: string;\n /** Soft miss for `optional: true` batchRead entries. */\n missing?: boolean;\n /** Conflict triple — same fields `AFSConflictError` carries. */\n conflict?: {\n currentCid: string | null;\n currentMtime: number | null;\n currentDeviceId: string | null;\n };\n}\n\nexport interface RpcBatchResult {\n results: RpcBatchEntryResult[];\n succeeded: number;\n failed: number;\n}\n\n/** Thrown when the server does not support the batch wire ops (old daemon). */\nexport class BatchUnsupportedError extends Error {\n constructor() {\n super(\"server does not support batch wire ops\");\n this.name = \"BatchUnsupportedError\";\n }\n}\n\n/**\n * Envelope-level BATCH_OVER_BUDGET / PAYLOAD_TOO_LARGE — zero entries\n * executed; the engine halves the chunk and retries (design §7.3). MUST NOT\n * trip the capability-fallback memory.\n */\nexport class BatchOverBudgetError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"BatchOverBudgetError\";\n }\n}\n\nexport interface RpcUserSpaceAFSOptions {\n /** Base URL of the arc daemon / worker (e.g. \"http://127.0.0.1:4900\"). */\n baseUrl: string;\n /** Bearer token. */\n token: string;\n /** Envelope blocklet (the app whose /user fragment is the sync target). */\n blocklet: string;\n /** Optional envelope sessionId. */\n sessionId?: string;\n /** Extra headers (test seams, tracing). Never logged. */\n extraHeaders?: Record<string, string>;\n}\n\n/**\n * SyncCloudAFS over the afs-rpc wire (`POST /api/afs/rpc`) — the transport\n * the production daemon/worker actually serve (the legacy `/api/space` REST\n * server is gone; `RemoteUserSpaceAFS` above survives only for the\n * export/import CLI against legacy hosts).\n *\n * Sync paths are fragment-root-relative; the wire allowlist admits only\n * `/user/**` mutations, so every path is mapped through `/user` on the way\n * out and stripped on the way back.\n *\n * Batch (P4): `batchWrite`/`batchDelete`/`batchRead` send one wire envelope\n * each (wire-contract §9) and restore per-entry results to the single-op\n * error types (`AFSConflictError` with the triple, `BATCH_TAIL_SKIPPED`\n * passthrough). Capability fallback: the FIRST envelope answered with the\n * old server's exact `Unsupported op 'batch…'` 400 marks this INSTANCE as\n * batch-unsupported (`supportsBatch === false`) and throws\n * {@link BatchUnsupportedError}; the engine then stays on the single-op\n * path for the rest of the instance's life. Any other 400 (e.g.\n * BATCH_OVER_BUDGET) does NOT trip the memory.\n */\nexport class RpcUserSpaceAFS {\n readonly name = \"rpc-user-space\";\n private baseUrl: string;\n private token: string;\n private blocklet: string;\n private sessionId?: string;\n private extraHeaders: Record<string, string>;\n /** null = unknown (no batch envelope sent yet); set on first evidence. */\n private batchSupported: boolean | null = null;\n\n constructor(options: RpcUserSpaceAFSOptions) {\n const url = new URL(options.baseUrl);\n if (url.protocol !== \"https:\" && !isLoopbackHost(url.hostname)) {\n throw new Error(\n `HTTPS required for remote connections (got ${url.protocol}//${url.hostname})`,\n );\n }\n this.baseUrl = options.baseUrl;\n this.token = options.token;\n this.blocklet = options.blocklet;\n this.sessionId = options.sessionId;\n this.extraHeaders = options.extraHeaders ?? {};\n }\n\n /** Instance-scoped capability memory (per-server, design §7.1). */\n get supportsBatch(): boolean | null {\n return this.batchSupported;\n }\n\n private wirePath(path: string): string {\n const p = path.startsWith(\"/\") ? path : `/${path}`;\n return `/user${p === \"/\" ? \"\" : p}`;\n }\n\n private stripUser(path: string): string {\n return path.startsWith(\"/user/\") ? path.slice(\"/user\".length) : path;\n }\n\n private async rpc(\n body: Record<string, unknown>,\n ): Promise<{ status: number; json: Record<string, unknown> }> {\n const res = await fetch(joinURL(this.baseUrl, \"/api/afs/rpc\"), {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/json\",\n Authorization: `Bearer ${this.token}`,\n ...this.extraHeaders,\n },\n body: JSON.stringify({\n blocklet: this.blocklet,\n ...(this.sessionId ? { sessionId: this.sessionId } : {}),\n ...body,\n }),\n });\n let json: Record<string, unknown>;\n try {\n json = (await res.json()) as Record<string, unknown>;\n } catch {\n json = { ok: false, error: `non-JSON response (HTTP ${res.status})` };\n }\n return { status: res.status, json };\n }\n\n /** Map a non-OK single-op wire response onto the AFS error types. */\n private throwWireError(status: number, json: Record<string, unknown>, path: string): never {\n if (status === 404) throw new AFSNotFoundError(path);\n if (status === 401) throw new Error(\"Authentication failed: check your access token\");\n if (status === 409) this.throwConflict(json, path);\n if (json.requireFullResync === true) {\n throw new AFSCompactedError(path, String(json.compactedBelowSeq ?? 0));\n }\n throw new Error(`afs-rpc error at ${path}: ${String(json.error ?? `HTTP ${status}`)}`);\n }\n\n /**\n * 409 → AFSConflictError with the triple. Keyed on `code: \"AFS_CONFLICT\"`\n * OR triple-field presence — NEVER the legacy `error === \"if_match_failed\"`\n * string (the T4.1 存量 bug: the wire sends the stable code, see\n * afs-rpc-wire.ts WIRE_ERROR_CODES.conflict; Swift's throwConflict already\n * keys on the code).\n */\n private throwConflict(json: Record<string, unknown>, path: string): never {\n if (json.code === \"AFS_CONFLICT\" || \"currentCid\" in json) {\n throw new AFSConflictError(path, {\n cid: typeof json.currentCid === \"string\" ? json.currentCid : null,\n mtime: typeof json.currentMtime === \"number\" ? json.currentMtime : null,\n deviceId: typeof json.currentDeviceId === \"string\" ? json.currentDeviceId : null,\n });\n }\n if (json.requireFullResync === true) {\n throw new AFSCompactedError(path, String(json.compactedBelowSeq ?? 0));\n }\n throw new Error(`afs-rpc 409 at ${path}: ${JSON.stringify(json)}`);\n }\n\n async list(path: string, options?: AFSListOptions): Promise<AFSListResult> {\n const opts: Record<string, unknown> = {};\n if (options?.cursor !== undefined) opts.cursor = options.cursor;\n if (options?.limit !== undefined && Number.isFinite(options.limit)) opts.limit = options.limit;\n if (options?.maxDepth !== undefined) opts.maxDepth = options.maxDepth;\n const { status, json } = await this.rpc({\n type: \"list\",\n path: this.wirePath(path),\n ...(Object.keys(opts).length ? { options: opts } : {}),\n });\n if (status !== 200 || json.ok !== true) this.throwWireError(status, json, path);\n const data = (json.data ?? []) as Array<Record<string, unknown>>;\n return {\n data: data.map((e) => ({ ...e, path: this.stripUser(String(e.path ?? \"\")) })) as never,\n total: typeof json.total === \"number\" ? json.total : data.length,\n meta: json.meta as AFSListResult[\"meta\"],\n liveSeq: json.liveSeq as never,\n } as AFSListResult;\n }\n\n async read(path: string): Promise<AFSReadResult> {\n const normPath = path.startsWith(\"/\") ? path.slice(1) : path;\n const isObject = normPath.startsWith(\".objects/\");\n const { status, json } = await this.rpc({ type: \"read\", path: this.wirePath(path) });\n if (status !== 200 || json.ok !== true) this.throwWireError(status, json, path);\n const data = (json.data ?? {}) as Record<string, unknown>;\n let content = data.content as unknown;\n if (data.encoding === \"base64\" && typeof content === \"string\") {\n content = decodeBase64ToBytes(content);\n }\n if (isObject) {\n const requestedCid = normPath.slice(\".objects/\".length);\n const bytes =\n content instanceof Uint8Array ? content : new TextEncoder().encode(String(content ?? \"\"));\n const actualCid = await computeCID(bytes);\n if (actualCid !== requestedCid) {\n throw new Error(\n `read .objects: CID mismatch (requested ${requestedCid}, got ${actualCid})`,\n );\n }\n content = bytes;\n }\n return {\n data: { ...data, path: this.stripUser(String(data.path ?? path)), content } as never,\n } as AFSReadResult;\n }\n\n async write(path: string, payload: AFSWriteEntryPayload): Promise<AFSWriteResult> {\n const extra = payload.meta?.extra as Record<string, unknown> | undefined;\n const content = payload.content;\n const bytes =\n content instanceof Uint8Array\n ? content\n : content instanceof ArrayBuffer\n ? new Uint8Array(content)\n : new TextEncoder().encode(\n typeof content === \"string\" ? content : JSON.stringify(content),\n );\n const options: Record<string, unknown> = {};\n const meta: Record<string, unknown> = {};\n if (typeof extra?.deviceId === \"string\") meta.deviceId = extra.deviceId;\n if (typeof extra?.mtime === \"number\") meta.mtime = extra.mtime;\n if (Object.keys(meta).length) options.meta = meta;\n if (typeof extra?.ifMatch === \"string\") options.ifMatch = extra.ifMatch;\n // Application metadata (feed-sort §5.1 / §5.5): everything in payload.meta\n // EXCEPT the `extra` sync-provenance sub-field is application data\n // (createdAt etc.). It rides the wire body's TOP-LEVEL `meta`, which the\n // afs-rpc write handler lifts via `wireMeta` onto payload.meta — distinct\n // from `options.meta` provenance, and mirroring batchWrite. This is JSON\n // body, NOT the raw content bytes, so the CID is untouched.\n const { extra: _extra, ...appMeta } = payload.meta ?? {};\n const { status, json } = await this.rpc({\n type: \"write\",\n path: this.wirePath(path),\n content: encodeBytesToBase64(bytes),\n encoding: \"base64\",\n ...(appMeta && Object.keys(appMeta).length ? { meta: appMeta } : {}),\n ...(Object.keys(options).length ? { options } : {}),\n });\n if (status !== 200 || json.ok !== true) this.throwWireError(status, json, path);\n return { data: json.data } as AFSWriteResult;\n }\n\n async delete(path: string, opts?: AFSDeleteOptions): Promise<AFSDeleteResult> {\n const meta = opts?.meta as Record<string, unknown> | undefined;\n const wireMeta: Record<string, unknown> = {};\n if (typeof meta?.deviceId === \"string\") wireMeta.deviceId = meta.deviceId;\n if (typeof meta?.mtime === \"number\") wireMeta.mtime = meta.mtime;\n if (typeof meta?.ifMatch === \"string\") wireMeta.ifMatch = meta.ifMatch;\n const { status, json } = await this.rpc({\n type: \"delete\",\n path: this.wirePath(path),\n ...(Object.keys(wireMeta).length ? { options: { meta: wireMeta } } : {}),\n });\n if (status !== 200 || json.ok !== true) this.throwWireError(status, json, path);\n return json.data as AFSDeleteResult;\n }\n\n // ── batch wire ops (P4) ────────────────────────────────────────────────\n\n /** Detect the old server's exact \"unsupported batch op\" 400 (design T4.2):\n * ONLY this text trips the per-instance fallback memory. */\n private checkBatchUnsupported(status: number, json: Record<string, unknown>): void {\n if (\n status === 400 &&\n typeof json.error === \"string\" &&\n /Unsupported op 'batch/.test(json.error)\n ) {\n this.batchSupported = false;\n throw new BatchUnsupportedError();\n }\n // Over-budget is a RETRYABLE envelope rejection (halve + retry), never a\n // capability signal.\n if (json.code === \"BATCH_OVER_BUDGET\" || json.code === \"PAYLOAD_TOO_LARGE\") {\n throw new BatchOverBudgetError(String(json.error ?? json.code));\n }\n }\n\n private restoreBatchResults(rawResults: unknown, entryPaths: string[]): RpcBatchEntryResult[] {\n if (!Array.isArray(rawResults) || rawResults.length !== entryPaths.length) {\n // Protocol violation — never consume a misaligned results array.\n throw new Error(\n `afs-rpc batch: results length ${Array.isArray(rawResults) ? rawResults.length : \"?\"} != entries length ${entryPaths.length}`,\n );\n }\n return rawResults.map((raw, i) => {\n const r = (raw ?? {}) as Record<string, unknown>;\n const status = typeof r.status === \"number\" ? r.status : 500;\n const ok = r.ok === true;\n const out: RpcBatchEntryResult = { path: entryPaths[i]!, success: ok, status };\n if (ok) {\n out.data = r.data as Record<string, unknown>;\n return out;\n }\n out.error = typeof r.error === \"string\" ? r.error : undefined;\n out.code = typeof r.code === \"string\" ? r.code : undefined;\n if (r.missing === true) out.missing = true;\n if (status === 409 || out.code === \"AFS_CONFLICT\") {\n out.conflict = {\n currentCid: typeof r.currentCid === \"string\" ? r.currentCid : null,\n currentMtime: typeof r.currentMtime === \"number\" ? r.currentMtime : null,\n currentDeviceId: typeof r.currentDeviceId === \"string\" ? r.currentDeviceId : null,\n };\n }\n return out;\n });\n }\n\n /**\n * One wire envelope per call — entries in the CORE batch shape\n * (`AFSBatchWriteEntry`: `content.content` bytes + `options.ifMatch` /\n * `options.meta` provenance), paths fragment-relative.\n */\n async batchWrite(entries: AFSBatchWriteEntry[]): Promise<RpcBatchResult> {\n const wireEntries = entries.map((e) => {\n const payload = e.content?.content;\n const bytes =\n payload instanceof Uint8Array\n ? payload\n : payload instanceof ArrayBuffer\n ? new Uint8Array(payload)\n : new TextEncoder().encode(\n typeof payload === \"string\" ? payload : JSON.stringify(payload ?? \"\"),\n );\n const options = e.options as\n | { ifMatch?: string; meta?: { deviceId?: string; mtime?: number } }\n | undefined;\n const meta: Record<string, unknown> = {};\n if (typeof options?.meta?.deviceId === \"string\") meta.deviceId = options.meta.deviceId;\n if (typeof options?.meta?.mtime === \"number\") meta.mtime = options.meta.mtime;\n const wireOptions: Record<string, unknown> = {};\n if (Object.keys(meta).length) wireOptions.meta = meta;\n if (typeof options?.ifMatch === \"string\") wireOptions.ifMatch = options.ifMatch;\n // Application metadata (did-space-metadata G3): the payload's `meta`\n // (createdAt etc.) rides the wire entry's TOP-LEVEL `meta`, which the\n // afs-rpc batchWrite handler lifts via `wireMeta` onto `payload.meta` —\n // distinct from `options.meta` provenance. Previously dropped entirely.\n const appMeta = (e.content as { meta?: Record<string, unknown> } | undefined)?.meta;\n return {\n path: this.wirePath(e.path),\n content: encodeBytesToBase64(bytes),\n encoding: \"base64\",\n ...(appMeta && Object.keys(appMeta).length ? { meta: appMeta } : {}),\n ...(Object.keys(wireOptions).length ? { options: wireOptions } : {}),\n };\n });\n const { status, json } = await this.rpc({ type: \"batchWrite\", entries: wireEntries });\n this.checkBatchUnsupported(status, json);\n if (status !== 200 || json.ok !== true) this.throwWireError(status, json, \"batchWrite\");\n this.batchSupported = true;\n return {\n results: this.restoreBatchResults(\n json.results,\n entries.map((e) => e.path),\n ),\n succeeded: Number(json.succeeded ?? 0),\n failed: Number(json.failed ?? 0),\n };\n }\n\n /** Core-shaped delete entries (`options.meta.{ifMatch,deviceId,mtime}`). */\n async batchDelete(entries: AFSBatchDeleteEntry[]): Promise<RpcBatchResult> {\n const wireEntries = entries.map((e) => {\n const m = (e.options as { meta?: Record<string, unknown> } | undefined)?.meta;\n const meta: Record<string, unknown> = {};\n if (typeof m?.deviceId === \"string\") meta.deviceId = m.deviceId;\n if (typeof m?.mtime === \"number\") meta.mtime = m.mtime;\n if (typeof m?.ifMatch === \"string\") meta.ifMatch = m.ifMatch;\n return {\n path: this.wirePath(e.path),\n ...(Object.keys(meta).length ? { options: { meta } } : {}),\n };\n });\n const { status, json } = await this.rpc({ type: \"batchDelete\", entries: wireEntries });\n this.checkBatchUnsupported(status, json);\n if (status !== 200 || json.ok !== true) this.throwWireError(status, json, \"batchDelete\");\n this.batchSupported = true;\n return {\n results: this.restoreBatchResults(\n json.results,\n entries.map((e) => e.path),\n ),\n succeeded: Number(json.succeeded ?? 0),\n failed: Number(json.failed ?? 0),\n };\n }\n\n /** Entries are absolute wire paths already (e.g. \"/.objects/{cid}\" reads). */\n async batchRead(entries: Array<{ path: string; optional?: boolean }>): Promise<RpcBatchResult> {\n const wireEntries = entries.map((e) => ({\n path: this.wirePath(e.path),\n ...(e.optional ? { optional: true } : {}),\n }));\n const { status, json } = await this.rpc({ type: \"batchRead\", entries: wireEntries });\n this.checkBatchUnsupported(status, json);\n if (status !== 200 || json.ok !== true) this.throwWireError(status, json, \"batchRead\");\n this.batchSupported = true;\n const results = this.restoreBatchResults(\n json.results,\n entries.map((e) => e.path),\n );\n // Decode base64 content in place (single-op read parity).\n for (const r of results) {\n const content = r.data?.content;\n if (r.data?.encoding === \"base64\" && typeof content === \"string\") {\n r.data.content = decodeBase64ToBytes(content);\n }\n }\n return { results, succeeded: Number(json.succeeded ?? 0), failed: Number(json.failed ?? 0) };\n }\n\n // ── upload plane (design §6.1 / §7.2) ──────────────────────────────────────\n\n /**\n * Probe whether the server's `/user` space advertises grant capability\n * (P2 T2.5). Reads the `.actions` catalogue and checks the prepare-upload\n * entry's `meta.grantCapability`. `false` on Node (fallback-only) or an old\n * server with no upload actions → the engine stays on batchWrite.\n */\n async uploadGrantCapability(): Promise<boolean> {\n const { status, json } = await this.rpc({ type: \"list\", path: this.wirePath(\"/.actions\") });\n if (status !== 200 || json.ok !== true) return false;\n const data = (json.data ?? []) as Array<{ id?: string; meta?: { grantCapability?: unknown } }>;\n const prep = data.find((e) => e.id === \"prepare-upload\");\n return prep?.meta?.grantCapability === true;\n }\n\n /** Run a `/user/.actions/<name>` exec. Throws `BatchUnsupportedError` when the\n * server lacks the action (old server) so the engine falls back. */\n private async execAction(\n name: string,\n args: Record<string, unknown>,\n ): Promise<Record<string, unknown>> {\n const { status, json } = await this.rpc({\n type: \"exec\",\n path: this.wirePath(`/.actions/${name}`),\n args,\n });\n if (status === 404 || status === 501) throw new BatchUnsupportedError();\n if (status !== 200 || json.ok !== true) {\n throw new Error(\n `afs-rpc exec ${name} failed: ${String(json.error ?? json.message ?? status)}`,\n );\n }\n return (json.data ?? {}) as Record<string, unknown>;\n }\n\n async prepareUpload(entries: PrepareUploadEntryInput[]): Promise<PrepareUploadResult> {\n const data = await this.execAction(\"prepare-upload\", { entries, strategy: \"auto\" });\n return data as unknown as PrepareUploadResult;\n }\n\n async commitUpload(\n sessionId: string,\n entries: CommitUploadEntryInput[],\n ): Promise<RpcBatchResult> {\n const data = await this.execAction(\"commit-upload\", { sessionId, entries });\n const results = ((data.results as Array<Record<string, unknown>>) ?? []).map((r) =>\n commitResultToBatchEntry(r),\n );\n let okCount = 0;\n for (const r of results) if (r.success) okCount++;\n return {\n results,\n succeeded: Number(data.succeeded ?? okCount),\n failed: Number(data.failed ?? results.length - okCount),\n };\n }\n\n /** Abort a prepared session (staged objects → GC). No TS engine call site yet\n * — the engine bails via BatchUnsupportedError on grant loss; exposed for\n * protocol parity (Swift mirror) + a future P4 abort-on-timeout path. */\n async abortUpload(sessionId: string): Promise<void> {\n await this.execAction(\"abort-upload\", { sessionId });\n }\n\n /** Out-of-band PUT of object bytes via a presigned grant. Returns the HTTP\n * status (commit-after-200: the engine only commits entries that got 200). */\n async uploadObject(grant: UploadGrant, bytes: Uint8Array): Promise<number> {\n const res = await fetch(grant.url, {\n method: grant.method,\n headers: grant.signedHeaders,\n // Uint8Array is a valid fetch BodyInit at runtime; the cast bridges the\n // cross-runtime lib types (this package targets Node/bun/Workers).\n body: bytes as BodyInit,\n });\n if (!res.ok) await res.text().catch(() => undefined); // drain (never logged)\n return res.status;\n }\n\n // ── download plane (design §6.3 / §7.2) ────────────────────────────────────\n\n /**\n * Probe whether the server's `/user` space advertises GET-grant capability\n * (P2 T2.4). Reads the `.actions` catalogue and checks the prepare-download\n * entry's INDEPENDENT `meta.downloadGrantCapability` (NOT the upload\n * `grantCapability`). `false` on Node (fallback-only) or an old server → the\n * engine stays on batchRead.\n */\n async downloadGrantCapability(): Promise<boolean> {\n const { status, json } = await this.rpc({ type: \"list\", path: this.wirePath(\"/.actions\") });\n if (status !== 200 || json.ok !== true) return false;\n const data = (json.data ?? []) as Array<{\n id?: string;\n meta?: { downloadGrantCapability?: unknown };\n }>;\n const prep = data.find((e) => e.id === \"prepare-download\");\n return prep?.meta?.downloadGrantCapability === true;\n }\n\n /** Run `prepare-download` — mints GET grants for the referenced cids. Throws\n * `BatchUnsupportedError` when the server lacks the action (old server). */\n async prepareDownload(entries: PrepareDownloadEntryInput[]): Promise<PrepareDownloadResult> {\n const data = await this.execAction(\"prepare-download\", { entries });\n return data as unknown as PrepareDownloadResult;\n }\n\n /**\n * Out-of-band GET of object bytes via a presigned grant (content leaves R2\n * directly — never through the Worker / base64). Returns the raw bytes on\n * 200. A 401/403 means the grant was rejected (token lacks GetObject / bad\n * signature) → throws {@link DownloadForbiddenError} so the engine flips the\n * whole session to batchRead (runtime fallback-on-403, §7.3). Any other\n * non-2xx (404 dangling / 5xx) throws a generic Error — the engine leaves the\n * cid unfilled so the existing missing-object path handles it.\n */\n async downloadObject(grant: DownloadGrant): Promise<Uint8Array> {\n const res = await fetch(grant.url, { method: grant.method });\n if (res.status === 401 || res.status === 403) {\n await res.body?.cancel().catch(() => undefined); // drain, never logged\n throw new DownloadForbiddenError(res.status);\n }\n if (!res.ok) {\n await res.body?.cancel().catch(() => undefined);\n throw new Error(`downloadObject ${grant.method} failed: ${res.status}`);\n }\n return new Uint8Array(await res.arrayBuffer());\n }\n}\n\n/**\n * A presigned GET directly rejected the bearer (401/403) — the R2 token likely\n * lacks GetObject or the signature is bad. Signals the engine to flip the whole\n * sync session to batchRead and not keep hitting the same wall (§7.3).\n */\nexport class DownloadForbiddenError extends Error {\n constructor(readonly status: number) {\n super(`download grant rejected by object store: ${status}`);\n this.name = \"DownloadForbiddenError\";\n }\n}\n\n/** A minted presigned-PUT grant (mirrors the provider's PresignedPut). */\nexport interface UploadGrant {\n kind: \"presigned-put\";\n url: string;\n method: \"PUT\";\n signedHeaders: Record<string, string>;\n expiresAt: string;\n}\n\nexport interface PrepareUploadEntryInput {\n path: string;\n cid: string;\n size: number;\n /**\n * Path-detected mime (the changelog carries none): drives the server's\n * `treeEntry.mimeType` AND the text-mime gate for the inline copy a matching\n * commit entry carries (inline-content-commit §5.3). Belongs on prepare so\n * the session persists it before commit.\n */\n mimeType?: string;\n ifMatch?: string;\n deviceId?: string;\n mtime?: number;\n}\n\n/**\n * Commit entries are prepare entries PLUS an optional cid-verified inline text\n * copy of the bytes (inline-content-commit §5.1/§5.3). Split from\n * `PrepareUploadEntryInput` so the 2KB×N content rides ONLY the commit leg, not\n * prepare (the grant-signing step has no use for it). The server text-mime-gates\n * + digest-pre-verifies the copy before storing it.\n */\nexport interface CommitUploadEntryInput extends PrepareUploadEntryInput {\n content?: string;\n /**\n * Application metadata (did-space-metadata G2): app fields (e.g. createdAt)\n * the commit persists to `entries.metadata`. The server strips\n * provider-reserved keys + caps the size; not part of the digest (it is\n * application data, not bytes).\n */\n metadata?: Record<string, unknown>;\n}\n\nexport interface PreparedUploadEntry {\n path: string;\n cid: string;\n status: string;\n objectKey: string;\n checksumSha256: string;\n grant: UploadGrant | null;\n}\n\nexport interface PrepareUploadResult {\n sessionId: string;\n expiresAt: string;\n entries: PreparedUploadEntry[];\n}\n\n/** A minted presigned-GET grant (mirrors the provider's PresignedGet). */\nexport interface DownloadGrant {\n kind: \"presigned-get\";\n url: string;\n method: \"GET\";\n signedHeaders: Record<string, string>;\n expiresAt: string;\n}\n\nexport interface PrepareDownloadEntryInput {\n cid: string;\n /** Error/log context only — never participates in authorization (§7.2). */\n path?: string;\n}\n\nexport interface PreparedDownloadEntry {\n cid: string;\n /** \"ok\" | \"forbidden\" | \"invalid\" (partial-success, §7.2). */\n status: string;\n objectKey?: string;\n grant?: DownloadGrant | null;\n}\n\nexport interface PrepareDownloadResult {\n entries: PreparedDownloadEntry[];\n}\n\n/** Map a commit-upload per-entry result (P2 shape) → the engine's RpcBatchEntryResult. */\nfunction commitResultToBatchEntry(r: Record<string, unknown>): RpcBatchEntryResult {\n // success: { status:200, ok:true, data:{ path, meta:{cid,liveSeq} } }\n if (r.ok === true || (typeof r.status === \"number\" && r.status === 200 && !r.code)) {\n const data = r.data as { path?: string } | undefined;\n return {\n path: String(data?.path ?? \"\"),\n success: true,\n status: 200,\n data: r.data as Record<string, unknown>,\n };\n }\n // conflict / failure: { path, success:false, code, conflict?, error? }\n return {\n path: String(r.path ?? \"\"),\n success: false,\n status: typeof r.status === \"number\" ? r.status : r.code === \"AFS_CONFLICT\" ? 409 : 500,\n code: typeof r.code === \"string\" ? r.code : undefined,\n error: typeof r.error === \"string\" ? r.error : undefined,\n conflict: r.conflict as RpcBatchEntryResult[\"conflict\"],\n };\n}\n\nfunction encodeBytesToBase64(bytes: Uint8Array): string {\n let binary = \"\";\n const CHUNK = 0x8000;\n for (let i = 0; i < bytes.length; i += CHUNK) {\n binary += String.fromCharCode(...bytes.subarray(i, i + CHUNK));\n }\n return btoa(binary);\n}\n\nfunction decodeBase64ToBytes(b64: string): Uint8Array {\n const binary = atob(b64);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);\n return bytes;\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
|
|
2
|
+
//#region src/rename-guard.ts
|
|
3
|
+
async function renameLegacyTable(client, oldName, newName) {
|
|
4
|
+
const { rows } = await client.execute({
|
|
5
|
+
sql: "SELECT name FROM sqlite_master WHERE type = 'table' AND name IN (?, ?)",
|
|
6
|
+
args: [oldName, newName]
|
|
7
|
+
});
|
|
8
|
+
const names = new Set(rows.map((r) => String(r.name)));
|
|
9
|
+
if (names.has(oldName) && !names.has(newName)) try {
|
|
10
|
+
await client.execute(`ALTER TABLE "${oldName}" RENAME TO "${newName}"`);
|
|
11
|
+
} catch (err) {
|
|
12
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
13
|
+
if (!msg.includes("no such table") && !msg.includes("already exists") && !msg.includes("already another table")) throw err;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
//#endregion
|
|
18
|
+
exports.renameLegacyTable = renameLegacyTable;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
//#region src/rename-guard.ts
|
|
2
|
+
async function renameLegacyTable(client, oldName, newName) {
|
|
3
|
+
const { rows } = await client.execute({
|
|
4
|
+
sql: "SELECT name FROM sqlite_master WHERE type = 'table' AND name IN (?, ?)",
|
|
5
|
+
args: [oldName, newName]
|
|
6
|
+
});
|
|
7
|
+
const names = new Set(rows.map((r) => String(r.name)));
|
|
8
|
+
if (names.has(oldName) && !names.has(newName)) try {
|
|
9
|
+
await client.execute(`ALTER TABLE "${oldName}" RENAME TO "${newName}"`);
|
|
10
|
+
} catch (err) {
|
|
11
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
12
|
+
if (!msg.includes("no such table") && !msg.includes("already exists") && !msg.includes("already another table")) throw err;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
//#endregion
|
|
17
|
+
export { renameLegacyTable };
|
|
18
|
+
//# sourceMappingURL=rename-guard.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rename-guard.mjs","names":[],"sources":["../src/rename-guard.ts"],"sourcesContent":["/**\n * ds_ prefix migration — legacy-table rename guard (d1-table-naming).\n *\n * State-checked via sqlite_master instead of sniffing ALTER error strings.\n * When BOTH the legacy and the prefixed table exist (seen in the wild: a\n * leftover unprefixed `shares` beside a fresh `ds_shares`), SQLite raises\n * \"there is already another table or index with this name: <new>\" — a message\n * the previous sniff (\"no such table\" / \"already exists\") did not tolerate,\n * so ensureTable() rethrew and daemon boot / `afs ls` died with SQLITE_ERROR.\n *\n * The prefixed table is authoritative; a stray legacy table is left untouched\n * for manual inspection — boot is never destructive.\n */\n\nimport type { Client as LibsqlClient } from \"@libsql/client\";\n\nexport async function renameLegacyTable(\n client: LibsqlClient,\n oldName: string,\n newName: string,\n): Promise<void> {\n const { rows } = await client.execute({\n sql: \"SELECT name FROM sqlite_master WHERE type = 'table' AND name IN (?, ?)\",\n args: [oldName, newName],\n });\n const names = new Set(rows.map((r) => String((r as { name?: unknown }).name)));\n if (names.has(oldName) && !names.has(newName)) {\n try {\n await client.execute(`ALTER TABLE \"${oldName}\" RENAME TO \"${newName}\"`);\n } catch (err) {\n // The state check above decided intent; any failure here can only be a\n // concurrent opener winning the same rename between check and ALTER\n // (\"no such table\" — legacy already gone; \"already another table or\n // index\" / \"already exists\" — target already created). All safe.\n const msg = err instanceof Error ? err.message : String(err);\n if (\n !msg.includes(\"no such table\") &&\n !msg.includes(\"already exists\") &&\n !msg.includes(\"already another table\")\n ) {\n throw err;\n }\n }\n }\n}\n"],"mappings":";AAgBA,eAAsB,kBACpB,QACA,SACA,SACe;CACf,MAAM,EAAE,SAAS,MAAM,OAAO,QAAQ;EACpC,KAAK;EACL,MAAM,CAAC,SAAS,QAAQ;EACzB,CAAC;CACF,MAAM,QAAQ,IAAI,IAAI,KAAK,KAAK,MAAM,OAAQ,EAAyB,KAAK,CAAC,CAAC;AAC9E,KAAI,MAAM,IAAI,QAAQ,IAAI,CAAC,MAAM,IAAI,QAAQ,CAC3C,KAAI;AACF,QAAM,OAAO,QAAQ,gBAAgB,QAAQ,eAAe,QAAQ,GAAG;UAChE,KAAK;EAKZ,MAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI;AAC5D,MACE,CAAC,IAAI,SAAS,gBAAgB,IAC9B,CAAC,IAAI,SAAS,iBAAiB,IAC/B,CAAC,IAAI,SAAS,wBAAwB,CAEtC,OAAM"}
|
package/dist/resolve.cjs
ADDED
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
const require_rolldown_runtime = require('./_virtual/rolldown_runtime.cjs');
|
|
2
|
+
const require_did_utils = require('./did-utils.cjs');
|
|
3
|
+
let _aigne_afs = require("@aigne/afs");
|
|
4
|
+
|
|
5
|
+
//#region src/resolve.ts
|
|
6
|
+
var DIDSpaceResolver = class {
|
|
7
|
+
constructor(store) {
|
|
8
|
+
this.store = store;
|
|
9
|
+
}
|
|
10
|
+
async resolve(did) {
|
|
11
|
+
const raw = await this.store.get(`resolve/${did}`);
|
|
12
|
+
return raw ? JSON.parse(raw) : null;
|
|
13
|
+
}
|
|
14
|
+
async register(did, entry) {
|
|
15
|
+
require_did_utils.validateId(did);
|
|
16
|
+
await this.store.put(`resolve/${did}`, JSON.stringify(entry));
|
|
17
|
+
}
|
|
18
|
+
async unregister(did) {
|
|
19
|
+
require_did_utils.validateId(did);
|
|
20
|
+
await this.store.delete(`resolve/${did}`);
|
|
21
|
+
}
|
|
22
|
+
async resolveBlocklet(id) {
|
|
23
|
+
require_did_utils.validateId(id);
|
|
24
|
+
const raw = await this.store.get(`resolve/blocklet/${id}`);
|
|
25
|
+
return raw ? JSON.parse(raw) : null;
|
|
26
|
+
}
|
|
27
|
+
async registerBlocklet(id, entry) {
|
|
28
|
+
require_did_utils.validateId(id);
|
|
29
|
+
const existing = await this.resolveBlocklet(id);
|
|
30
|
+
if (existing && existing.owner !== entry.owner) throw new _aigne_afs.AFSAlreadyExistsError(id, `blocklet "${id}" is already registered to a different owner`);
|
|
31
|
+
await this.store.put(`resolve/blocklet/${id}`, JSON.stringify(entry));
|
|
32
|
+
}
|
|
33
|
+
async unregisterBlocklet(id) {
|
|
34
|
+
require_did_utils.validateId(id);
|
|
35
|
+
await this.store.delete(`resolve/blocklet/${id}`);
|
|
36
|
+
}
|
|
37
|
+
/** List all registered blocklets (`resolve/blocklet/*`). */
|
|
38
|
+
async listBlocklets() {
|
|
39
|
+
const out = [];
|
|
40
|
+
if (this.store.listWithValues) {
|
|
41
|
+
const result$1 = await this.store.listWithValues({ prefix: "resolve/blocklet/" });
|
|
42
|
+
for (const { key, value } of result$1.entries) {
|
|
43
|
+
let entry;
|
|
44
|
+
try {
|
|
45
|
+
entry = JSON.parse(value);
|
|
46
|
+
} catch {
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
out.push({
|
|
50
|
+
id: key.slice(17),
|
|
51
|
+
entry
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
return out;
|
|
55
|
+
}
|
|
56
|
+
const result = await this.store.list({ prefix: "resolve/blocklet/" });
|
|
57
|
+
for (const { name } of result.keys) {
|
|
58
|
+
const raw = await this.store.get(name);
|
|
59
|
+
if (!raw) continue;
|
|
60
|
+
let entry;
|
|
61
|
+
try {
|
|
62
|
+
entry = JSON.parse(raw);
|
|
63
|
+
} catch {
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
out.push({
|
|
67
|
+
id: name.slice(17),
|
|
68
|
+
entry
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
return out;
|
|
72
|
+
}
|
|
73
|
+
async list(options) {
|
|
74
|
+
if ("listWithTimestamps" in this.store && typeof this.store.listWithTimestamps === "function") return this._listWithTimestamps(options);
|
|
75
|
+
if (this.store.listWithValues) return this._listOptimized(options);
|
|
76
|
+
return this._listFallback(options);
|
|
77
|
+
}
|
|
78
|
+
/** Optimized: single query with timestamps via D1ResolveStore.listWithTimestamps */
|
|
79
|
+
async _listWithTimestamps(options) {
|
|
80
|
+
const result = await this.store.listWithTimestamps({ prefix: "resolve/" });
|
|
81
|
+
const entries = [];
|
|
82
|
+
for (const { key, value, created_at, updated_at } of result.entries) {
|
|
83
|
+
if (key.startsWith("resolve/domain/") || key.startsWith("resolve/blocklet/")) continue;
|
|
84
|
+
let entry;
|
|
85
|
+
try {
|
|
86
|
+
entry = JSON.parse(value);
|
|
87
|
+
} catch {
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
if (options?.type !== void 0 && entry.type !== options.type) continue;
|
|
91
|
+
const did = key.slice(8);
|
|
92
|
+
entries.push({
|
|
93
|
+
did,
|
|
94
|
+
entry,
|
|
95
|
+
createdAt: created_at ?? void 0,
|
|
96
|
+
updatedAt: updated_at ?? void 0
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
return entries;
|
|
100
|
+
}
|
|
101
|
+
/** Optimized: single query via listWithValues (no N+1) */
|
|
102
|
+
async _listOptimized(options) {
|
|
103
|
+
const result = await this.store.listWithValues({ prefix: "resolve/" });
|
|
104
|
+
const entries = [];
|
|
105
|
+
for (const { key, value } of result.entries) {
|
|
106
|
+
if (key.startsWith("resolve/domain/") || key.startsWith("resolve/blocklet/")) continue;
|
|
107
|
+
let entry;
|
|
108
|
+
try {
|
|
109
|
+
entry = JSON.parse(value);
|
|
110
|
+
} catch {
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
if (options?.type !== void 0 && entry.type !== options.type) continue;
|
|
114
|
+
const did = key.slice(8);
|
|
115
|
+
entries.push({
|
|
116
|
+
did,
|
|
117
|
+
entry
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
return entries;
|
|
121
|
+
}
|
|
122
|
+
/** Fallback: N+1 queries (list keys, then get each value) */
|
|
123
|
+
async _listFallback(options) {
|
|
124
|
+
const result = await this.store.list({ prefix: "resolve/" });
|
|
125
|
+
const entries = [];
|
|
126
|
+
for (const { name } of result.keys) {
|
|
127
|
+
if (name.startsWith("resolve/domain/") || name.startsWith("resolve/blocklet/")) continue;
|
|
128
|
+
const raw = await this.store.get(name);
|
|
129
|
+
if (!raw) continue;
|
|
130
|
+
let entry;
|
|
131
|
+
try {
|
|
132
|
+
entry = JSON.parse(raw);
|
|
133
|
+
} catch {
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
if (options?.type !== void 0 && entry.type !== options.type) continue;
|
|
137
|
+
const did = name.slice(8);
|
|
138
|
+
entries.push({
|
|
139
|
+
did,
|
|
140
|
+
entry
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
return entries;
|
|
144
|
+
}
|
|
145
|
+
async listDomains() {
|
|
146
|
+
if (this.store.listWithValues) return this._listDomainsOptimized();
|
|
147
|
+
return this._listDomainsFallback();
|
|
148
|
+
}
|
|
149
|
+
/** Optimized: single query via listWithValues */
|
|
150
|
+
async _listDomainsOptimized() {
|
|
151
|
+
const result = await this.store.listWithValues({ prefix: "resolve/domain/" });
|
|
152
|
+
const entries = [];
|
|
153
|
+
for (const { key, value } of result.entries) {
|
|
154
|
+
let entry;
|
|
155
|
+
try {
|
|
156
|
+
entry = JSON.parse(value);
|
|
157
|
+
} catch {
|
|
158
|
+
continue;
|
|
159
|
+
}
|
|
160
|
+
const domain = key.slice(15);
|
|
161
|
+
entries.push({
|
|
162
|
+
domain,
|
|
163
|
+
entry
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
return entries;
|
|
167
|
+
}
|
|
168
|
+
/** Fallback: N+1 queries */
|
|
169
|
+
async _listDomainsFallback() {
|
|
170
|
+
const result = await this.store.list({ prefix: "resolve/domain/" });
|
|
171
|
+
const entries = [];
|
|
172
|
+
for (const { name } of result.keys) {
|
|
173
|
+
const raw = await this.store.get(name);
|
|
174
|
+
if (!raw) continue;
|
|
175
|
+
let entry;
|
|
176
|
+
try {
|
|
177
|
+
entry = JSON.parse(raw);
|
|
178
|
+
} catch {
|
|
179
|
+
continue;
|
|
180
|
+
}
|
|
181
|
+
const domain = name.slice(15);
|
|
182
|
+
entries.push({
|
|
183
|
+
domain,
|
|
184
|
+
entry
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
return entries;
|
|
188
|
+
}
|
|
189
|
+
async resolveDomain(domain) {
|
|
190
|
+
const raw = await this.store.get(`resolve/domain/${domain}`);
|
|
191
|
+
return raw ? JSON.parse(raw) : null;
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Serve-path host resolution (issue #808): fetch `resolve/blocklet/<name>` and
|
|
195
|
+
* `resolve/domain/<name>` in ONE store round trip (D1 `IN(...)`) instead of the
|
|
196
|
+
* sequential `resolveBlocklet` → `resolveDomain` ladder. Blocklet wins (id
|
|
197
|
+
* key), falling back to the domain entry — identical priority, one fewer round
|
|
198
|
+
* trip. For a brand-domain host (the prod model), the id key always misses and
|
|
199
|
+
* the domain key hits, so this saves the domain lookup's whole round trip on
|
|
200
|
+
* EVERY request. Degrades to two concurrent `get()`s when the store can't
|
|
201
|
+
* batch. `validateId` mirrors `resolveBlocklet` (the sequential ladder runs it
|
|
202
|
+
* first, so an invalid id resolves to null there too — never reaching domain).
|
|
203
|
+
*/
|
|
204
|
+
async resolveBlockletOrDomain(name) {
|
|
205
|
+
try {
|
|
206
|
+
require_did_utils.validateId(name);
|
|
207
|
+
} catch {
|
|
208
|
+
return null;
|
|
209
|
+
}
|
|
210
|
+
const blockletKey = `resolve/blocklet/${name}`;
|
|
211
|
+
const domainKey = `resolve/domain/${name}`;
|
|
212
|
+
let blockletRaw;
|
|
213
|
+
let domainRaw;
|
|
214
|
+
if (this.store.getMany) {
|
|
215
|
+
const map = await this.store.getMany([blockletKey, domainKey]);
|
|
216
|
+
blockletRaw = map.get(blockletKey) ?? null;
|
|
217
|
+
domainRaw = map.get(domainKey) ?? null;
|
|
218
|
+
} else [blockletRaw, domainRaw] = await Promise.all([this.store.get(blockletKey), this.store.get(domainKey)]);
|
|
219
|
+
if (blockletRaw) {
|
|
220
|
+
const entry = JSON.parse(blockletRaw);
|
|
221
|
+
if (entry?.owner) return {
|
|
222
|
+
source: "blocklet",
|
|
223
|
+
owner: entry.owner,
|
|
224
|
+
path: entry.path ?? ""
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
if (domainRaw) {
|
|
228
|
+
const entry = JSON.parse(domainRaw);
|
|
229
|
+
if (entry?.owner) return {
|
|
230
|
+
source: "domain",
|
|
231
|
+
owner: entry.owner,
|
|
232
|
+
path: entry.path ?? "",
|
|
233
|
+
did: entry.did
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
return null;
|
|
237
|
+
}
|
|
238
|
+
async registerDomain(domain, entry) {
|
|
239
|
+
require_did_utils.validateId(domain);
|
|
240
|
+
await this.store.put(`resolve/domain/${domain}`, JSON.stringify(entry));
|
|
241
|
+
}
|
|
242
|
+
async unregisterDomain(domain) {
|
|
243
|
+
require_did_utils.validateId(domain);
|
|
244
|
+
await this.store.delete(`resolve/domain/${domain}`);
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Domains currently registered to this exact (owner, path) pair (#764 Phase
|
|
248
|
+
* 4a). Shared by the write hook's reconcile step (drop domains no longer in
|
|
249
|
+
* a redeploy's manifest) and the delete hook (drop all domains on unpublish)
|
|
250
|
+
* — same `listDomains()` + filter pattern `applyBlockletDeleteHook` already
|
|
251
|
+
* used inline for `resolve/blocklet/*`, factored out here since Phase 4
|
|
252
|
+
* needs it twice.
|
|
253
|
+
*/
|
|
254
|
+
async domainsForBlocklet(owner, path) {
|
|
255
|
+
return (await this.listDomains()).filter(({ entry }) => entry.owner === owner && entry.path === path).map(({ domain }) => domain);
|
|
256
|
+
}
|
|
257
|
+
};
|
|
258
|
+
|
|
259
|
+
//#endregion
|
|
260
|
+
exports.DIDSpaceResolver = DIDSpaceResolver;
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { KeyValueStore } from "@aigne/afs-kv";
|
|
2
|
+
|
|
3
|
+
//#region src/resolve.d.ts
|
|
4
|
+
interface ResolveEntry {
|
|
5
|
+
owner: string;
|
|
6
|
+
path: string;
|
|
7
|
+
type?: string;
|
|
8
|
+
name?: string;
|
|
9
|
+
routes?: Array<{
|
|
10
|
+
name: string;
|
|
11
|
+
site: string;
|
|
12
|
+
path: string;
|
|
13
|
+
source: string;
|
|
14
|
+
handler: string;
|
|
15
|
+
}>;
|
|
16
|
+
/** Whether this blocklet has pre-rendered .web-cache/ content. Set at publish time. */
|
|
17
|
+
hasWebCache?: boolean;
|
|
18
|
+
/** Monotonic timestamp (Date.now()) set by CLI at publish time. Used by DO cache invalidation. */
|
|
19
|
+
publishVersion?: number;
|
|
20
|
+
}
|
|
21
|
+
interface DomainResolveEntry {
|
|
22
|
+
did: string;
|
|
23
|
+
owner: string;
|
|
24
|
+
path: string;
|
|
25
|
+
blockletDid?: string;
|
|
26
|
+
blockletOwner?: string;
|
|
27
|
+
blockletPath?: string;
|
|
28
|
+
/** Materialized from blocklet ResolveEntry at publish/bind time. */
|
|
29
|
+
routes?: Array<{
|
|
30
|
+
name: string;
|
|
31
|
+
site: string;
|
|
32
|
+
path: string;
|
|
33
|
+
source: string;
|
|
34
|
+
handler: string;
|
|
35
|
+
}>;
|
|
36
|
+
/** Materialized from blocklet ResolveEntry at publish/bind time. */
|
|
37
|
+
hasWebCache?: boolean;
|
|
38
|
+
/** Materialized from blocklet ResolveEntry at publish/bind time. Used by DO cache invalidation. */
|
|
39
|
+
publishVersion?: number;
|
|
40
|
+
}
|
|
41
|
+
declare class DIDSpaceResolver {
|
|
42
|
+
private store;
|
|
43
|
+
constructor(store: KeyValueStore);
|
|
44
|
+
resolve(did: string): Promise<ResolveEntry | null>;
|
|
45
|
+
register(did: string, entry: ResolveEntry): Promise<void>;
|
|
46
|
+
unregister(did: string): Promise<void>;
|
|
47
|
+
resolveBlocklet(id: string): Promise<ResolveEntry | null>;
|
|
48
|
+
registerBlocklet(id: string, entry: ResolveEntry): Promise<void>;
|
|
49
|
+
unregisterBlocklet(id: string): Promise<void>;
|
|
50
|
+
/** List all registered blocklets (`resolve/blocklet/*`). */
|
|
51
|
+
listBlocklets(): Promise<Array<{
|
|
52
|
+
id: string;
|
|
53
|
+
entry: ResolveEntry;
|
|
54
|
+
}>>;
|
|
55
|
+
list(options?: {
|
|
56
|
+
type?: string;
|
|
57
|
+
}): Promise<Array<{
|
|
58
|
+
did: string;
|
|
59
|
+
entry: ResolveEntry;
|
|
60
|
+
createdAt?: number;
|
|
61
|
+
updatedAt?: number;
|
|
62
|
+
}>>;
|
|
63
|
+
/** Optimized: single query with timestamps via D1ResolveStore.listWithTimestamps */
|
|
64
|
+
private _listWithTimestamps;
|
|
65
|
+
/** Optimized: single query via listWithValues (no N+1) */
|
|
66
|
+
private _listOptimized;
|
|
67
|
+
/** Fallback: N+1 queries (list keys, then get each value) */
|
|
68
|
+
private _listFallback;
|
|
69
|
+
listDomains(): Promise<Array<{
|
|
70
|
+
domain: string;
|
|
71
|
+
entry: DomainResolveEntry;
|
|
72
|
+
}>>;
|
|
73
|
+
/** Optimized: single query via listWithValues */
|
|
74
|
+
private _listDomainsOptimized;
|
|
75
|
+
/** Fallback: N+1 queries */
|
|
76
|
+
private _listDomainsFallback;
|
|
77
|
+
resolveDomain(domain: string): Promise<DomainResolveEntry | null>;
|
|
78
|
+
/**
|
|
79
|
+
* Serve-path host resolution (issue #808): fetch `resolve/blocklet/<name>` and
|
|
80
|
+
* `resolve/domain/<name>` in ONE store round trip (D1 `IN(...)`) instead of the
|
|
81
|
+
* sequential `resolveBlocklet` → `resolveDomain` ladder. Blocklet wins (id
|
|
82
|
+
* key), falling back to the domain entry — identical priority, one fewer round
|
|
83
|
+
* trip. For a brand-domain host (the prod model), the id key always misses and
|
|
84
|
+
* the domain key hits, so this saves the domain lookup's whole round trip on
|
|
85
|
+
* EVERY request. Degrades to two concurrent `get()`s when the store can't
|
|
86
|
+
* batch. `validateId` mirrors `resolveBlocklet` (the sequential ladder runs it
|
|
87
|
+
* first, so an invalid id resolves to null there too — never reaching domain).
|
|
88
|
+
*/
|
|
89
|
+
resolveBlockletOrDomain(name: string): Promise<{
|
|
90
|
+
source: "blocklet";
|
|
91
|
+
owner: string;
|
|
92
|
+
path: string;
|
|
93
|
+
} | {
|
|
94
|
+
source: "domain";
|
|
95
|
+
owner: string;
|
|
96
|
+
path: string;
|
|
97
|
+
did: string;
|
|
98
|
+
} | null>;
|
|
99
|
+
registerDomain(domain: string, entry: DomainResolveEntry): Promise<void>;
|
|
100
|
+
unregisterDomain(domain: string): Promise<void>;
|
|
101
|
+
/**
|
|
102
|
+
* Domains currently registered to this exact (owner, path) pair (#764 Phase
|
|
103
|
+
* 4a). Shared by the write hook's reconcile step (drop domains no longer in
|
|
104
|
+
* a redeploy's manifest) and the delete hook (drop all domains on unpublish)
|
|
105
|
+
* — same `listDomains()` + filter pattern `applyBlockletDeleteHook` already
|
|
106
|
+
* used inline for `resolve/blocklet/*`, factored out here since Phase 4
|
|
107
|
+
* needs it twice.
|
|
108
|
+
*/
|
|
109
|
+
domainsForBlocklet(owner: string, path: string): Promise<string[]>;
|
|
110
|
+
}
|
|
111
|
+
//#endregion
|
|
112
|
+
export { DIDSpaceResolver, DomainResolveEntry, ResolveEntry };
|
|
113
|
+
//# sourceMappingURL=resolve.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve.d.cts","names":[],"sources":["../src/resolve.ts"],"mappings":";;;UAIiB,YAAA;EACf,KAAA;EACA,IAAA;EACA,IAAA;EACA,IAAA;EACA,MAAA,GAAS,KAAA;IAAQ,IAAA;IAAc,IAAA;IAAc,IAAA;IAAc,MAAA;IAAgB,OAAA;EAAA;EAA1D;EAEjB,WAAA;EAF6C;EAI7C,cAAA;AAAA;AAAA,UAGe,kBAAA;EACf,GAAA;EACA,KAAA;EACA,IAAA;EACA,WAAA;EACA,aAAA;EACA,YAAA;EAEc;EAAd,MAAA,GAAS,KAAA;IAAQ,IAAA;IAAc,IAAA;IAAc,IAAA;IAAc,MAAA;IAAgB,OAAA;EAAA;EAAlE;EAET,WAAA;EAF+B;EAI/B,cAAA;AAAA;AAAA,cAGW,gBAAA;EAAA,QACS,KAAA;cAAA,KAAA,EAAO,aAAA;EAIrB,OAAA,CAAQ,GAAA,WAAc,OAAA,CAAQ,YAAA;EAK9B,QAAA,CAAS,GAAA,UAAa,KAAA,EAAO,YAAA,GAAe,OAAA;EAK5C,UAAA,CAAW,GAAA,WAAc,OAAA;EAkBzB,eAAA,CAAgB,EAAA,WAAa,OAAA,CAAQ,YAAA;EAMrC,gBAAA,CAAiB,EAAA,UAAY,KAAA,EAAO,YAAA,GAAe,OAAA;EAYnD,kBAAA,CAAmB,EAAA,WAAa,OAAA;EA9CF;EAoD9B,aAAA,CAAA,GAAiB,OAAA,CAAQ,KAAA;IAAQ,EAAA;IAAY,KAAA,EAAO,YAAA;EAAA;EAgCpD,IAAA,CAAK,OAAA;IACT,IAAA;EAAA,IACE,OAAA,CAAQ,KAAA;IAAQ,GAAA;IAAa,KAAA,EAAO,YAAA;IAAc,SAAA;IAAoB,SAAA;EAAA;EAAlC;EAAA,QAc1B,mBAAA;EAdV;EAAA,QA6CU,cAAA;EA6Ce;EAAA,QAxBf,aAAA;EAwBR,WAAA,CAAA,GAAe,OAAA,CAAQ,KAAA;IAAQ,MAAA;IAAgB,KAAA,EAAO,kBAAA;EAAA;EAwGK;EAAA,QAhGnD,qBAAA;EAkHyC;EAAA,QA/FzC,oBAAA;EAsBR,aAAA,CAAc,MAAA,WAAiB,OAAA,CAAQ,kBAAA;EArOzB;;;;;;;;;;;EAqPd,uBAAA,CACJ,IAAA,WACC,OAAA;IACG,MAAA;IAAoB,KAAA;IAAe,IAAA;EAAA;IACnC,MAAA;IAAkB,KAAA;IAAe,IAAA;IAAc,GAAA;EAAA;EAmC/C,cAAA,CAAe,MAAA,UAAgB,KAAA,EAAO,kBAAA,GAAqB,OAAA;EAK3D,gBAAA,CAAiB,MAAA,WAAiB,OAAA;EA3PL;;;;;;;;EAwQ7B,kBAAA,CAAmB,KAAA,UAAe,IAAA,WAAe,OAAA;AAAA"}
|