@aigne/aos 0.2.0-beta
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/CHANGELOG.md +49 -0
- package/LICENSE.md +26 -0
- package/dist/agent-dsl.cjs +116 -0
- package/dist/agent-dsl.d.cts +31 -0
- package/dist/agent-dsl.d.cts.map +1 -0
- package/dist/agent-dsl.d.mts +31 -0
- package/dist/agent-dsl.d.mts.map +1 -0
- package/dist/agent-dsl.mjs +115 -0
- package/dist/agent-dsl.mjs.map +1 -0
- package/dist/arc-compat.cjs +125 -0
- package/dist/arc-compat.d.cts +17 -0
- package/dist/arc-compat.d.cts.map +1 -0
- package/dist/arc-compat.d.mts +17 -0
- package/dist/arc-compat.d.mts.map +1 -0
- package/dist/arc-compat.mjs +123 -0
- package/dist/arc-compat.mjs.map +1 -0
- package/dist/auto-surface/compiler.cjs +36 -0
- package/dist/auto-surface/compiler.d.cts +7 -0
- package/dist/auto-surface/compiler.d.cts.map +1 -0
- package/dist/auto-surface/compiler.d.mts +7 -0
- package/dist/auto-surface/compiler.d.mts.map +1 -0
- package/dist/auto-surface/compiler.mjs +37 -0
- package/dist/auto-surface/compiler.mjs.map +1 -0
- package/dist/auto-surface/definition-dsl.cjs +333 -0
- package/dist/auto-surface/definition-dsl.d.cts +41 -0
- package/dist/auto-surface/definition-dsl.d.cts.map +1 -0
- package/dist/auto-surface/definition-dsl.d.mts +41 -0
- package/dist/auto-surface/definition-dsl.d.mts.map +1 -0
- package/dist/auto-surface/definition-dsl.mjs +332 -0
- package/dist/auto-surface/definition-dsl.mjs.map +1 -0
- package/dist/auto-surface/fragments.cjs +177 -0
- package/dist/auto-surface/fragments.d.cts +23 -0
- package/dist/auto-surface/fragments.d.cts.map +1 -0
- package/dist/auto-surface/fragments.d.mts +23 -0
- package/dist/auto-surface/fragments.d.mts.map +1 -0
- package/dist/auto-surface/fragments.mjs +175 -0
- package/dist/auto-surface/fragments.mjs.map +1 -0
- package/dist/auto-surface/index.d.mts +9 -0
- package/dist/auto-surface/layering.cjs +43 -0
- package/dist/auto-surface/layering.d.cts +7 -0
- package/dist/auto-surface/layering.d.cts.map +1 -0
- package/dist/auto-surface/layering.d.mts +7 -0
- package/dist/auto-surface/layering.d.mts.map +1 -0
- package/dist/auto-surface/layering.mjs +43 -0
- package/dist/auto-surface/layering.mjs.map +1 -0
- package/dist/auto-surface/projection.cjs +11 -0
- package/dist/auto-surface/projection.d.cts +11 -0
- package/dist/auto-surface/projection.d.cts.map +1 -0
- package/dist/auto-surface/projection.d.mts +11 -0
- package/dist/auto-surface/projection.d.mts.map +1 -0
- package/dist/auto-surface/projection.mjs +12 -0
- package/dist/auto-surface/projection.mjs.map +1 -0
- package/dist/auto-surface/projectors/settings-shell.cjs +114 -0
- package/dist/auto-surface/projectors/settings-shell.d.cts +10 -0
- package/dist/auto-surface/projectors/settings-shell.d.cts.map +1 -0
- package/dist/auto-surface/projectors/settings-shell.d.mts +10 -0
- package/dist/auto-surface/projectors/settings-shell.d.mts.map +1 -0
- package/dist/auto-surface/projectors/settings-shell.mjs +114 -0
- package/dist/auto-surface/projectors/settings-shell.mjs.map +1 -0
- package/dist/auto-surface/scenario.cjs +38 -0
- package/dist/auto-surface/scenario.d.cts +31 -0
- package/dist/auto-surface/scenario.d.cts.map +1 -0
- package/dist/auto-surface/scenario.d.mts +31 -0
- package/dist/auto-surface/scenario.d.mts.map +1 -0
- package/dist/auto-surface/scenario.mjs +37 -0
- package/dist/auto-surface/scenario.mjs.map +1 -0
- package/dist/auto-surface/types.cjs +9 -0
- package/dist/auto-surface/types.d.cts +153 -0
- package/dist/auto-surface/types.d.cts.map +1 -0
- package/dist/auto-surface/types.d.mts +153 -0
- package/dist/auto-surface/types.d.mts.map +1 -0
- package/dist/auto-surface/types.mjs +9 -0
- package/dist/auto-surface/types.mjs.map +1 -0
- package/dist/auto-surface/value-dsl.cjs +80 -0
- package/dist/auto-surface/value-dsl.d.cts +24 -0
- package/dist/auto-surface/value-dsl.d.cts.map +1 -0
- package/dist/auto-surface/value-dsl.d.mts +24 -0
- package/dist/auto-surface/value-dsl.d.mts.map +1 -0
- package/dist/auto-surface/value-dsl.mjs +79 -0
- package/dist/auto-surface/value-dsl.mjs.map +1 -0
- package/dist/blocklet/activation.cjs +94 -0
- package/dist/blocklet/activation.d.cts +30 -0
- package/dist/blocklet/activation.d.cts.map +1 -0
- package/dist/blocklet/activation.d.mts +30 -0
- package/dist/blocklet/activation.d.mts.map +1 -0
- package/dist/blocklet/activation.mjs +94 -0
- package/dist/blocklet/activation.mjs.map +1 -0
- package/dist/blocklet/did-space-registry.cjs +282 -0
- package/dist/blocklet/did-space-registry.d.cts +82 -0
- package/dist/blocklet/did-space-registry.d.cts.map +1 -0
- package/dist/blocklet/did-space-registry.d.mts +82 -0
- package/dist/blocklet/did-space-registry.d.mts.map +1 -0
- package/dist/blocklet/did-space-registry.mjs +281 -0
- package/dist/blocklet/did-space-registry.mjs.map +1 -0
- package/dist/blocklet/handlers.cjs +66 -0
- package/dist/blocklet/handlers.d.cts +16 -0
- package/dist/blocklet/handlers.d.cts.map +1 -0
- package/dist/blocklet/handlers.d.mts +16 -0
- package/dist/blocklet/handlers.d.mts.map +1 -0
- package/dist/blocklet/handlers.mjs +65 -0
- package/dist/blocklet/handlers.mjs.map +1 -0
- package/dist/blocklet/index.d.mts +7 -0
- package/dist/blocklet/manifest.d.cts +2 -0
- package/dist/blocklet/manifest.d.mts +2 -0
- package/dist/blocklet/manifest.mjs +3 -0
- package/dist/blocklet/registry.cjs +447 -0
- package/dist/blocklet/registry.d.cts +197 -0
- package/dist/blocklet/registry.d.cts.map +1 -0
- package/dist/blocklet/registry.d.mts +197 -0
- package/dist/blocklet/registry.d.mts.map +1 -0
- package/dist/blocklet/registry.mjs +441 -0
- package/dist/blocklet/registry.mjs.map +1 -0
- package/dist/blocklet/static-render.cjs +183 -0
- package/dist/blocklet/static-render.d.cts +55 -0
- package/dist/blocklet/static-render.d.cts.map +1 -0
- package/dist/blocklet/static-render.d.mts +55 -0
- package/dist/blocklet/static-render.d.mts.map +1 -0
- package/dist/blocklet/static-render.mjs +181 -0
- package/dist/blocklet/static-render.mjs.map +1 -0
- package/dist/blocklet/types.d.cts +70 -0
- package/dist/blocklet/types.d.cts.map +1 -0
- package/dist/blocklet/types.d.mts +70 -0
- package/dist/blocklet/types.d.mts.map +1 -0
- package/dist/devices/chain.cjs +127 -0
- package/dist/devices/chain.d.cts +48 -0
- package/dist/devices/chain.d.cts.map +1 -0
- package/dist/devices/chain.d.mts +48 -0
- package/dist/devices/chain.d.mts.map +1 -0
- package/dist/devices/chain.mjs +125 -0
- package/dist/devices/chain.mjs.map +1 -0
- package/dist/dsl-shared.cjs +290 -0
- package/dist/dsl-shared.d.cts +54 -0
- package/dist/dsl-shared.d.cts.map +1 -0
- package/dist/dsl-shared.d.mts +54 -0
- package/dist/dsl-shared.d.mts.map +1 -0
- package/dist/dsl-shared.mjs +287 -0
- package/dist/dsl-shared.mjs.map +1 -0
- package/dist/http/afs-mcp.cjs +85 -0
- package/dist/http/afs-mcp.d.cts +14 -0
- package/dist/http/afs-mcp.d.cts.map +1 -0
- package/dist/http/afs-mcp.d.mts +14 -0
- package/dist/http/afs-mcp.d.mts.map +1 -0
- package/dist/http/afs-mcp.mjs +86 -0
- package/dist/http/afs-mcp.mjs.map +1 -0
- package/dist/http/afs-raw.cjs +264 -0
- package/dist/http/afs-raw.d.cts +31 -0
- package/dist/http/afs-raw.d.cts.map +1 -0
- package/dist/http/afs-raw.d.mts +31 -0
- package/dist/http/afs-raw.d.mts.map +1 -0
- package/dist/http/afs-raw.mjs +264 -0
- package/dist/http/afs-raw.mjs.map +1 -0
- package/dist/http/afs-rest.cjs +30 -0
- package/dist/http/afs-rest.d.cts +21 -0
- package/dist/http/afs-rest.d.cts.map +1 -0
- package/dist/http/afs-rest.d.mts +21 -0
- package/dist/http/afs-rest.d.mts.map +1 -0
- package/dist/http/afs-rest.mjs +31 -0
- package/dist/http/afs-rest.mjs.map +1 -0
- package/dist/http/afs-rpc-wire.cjs +271 -0
- package/dist/http/afs-rpc-wire.d.cts +195 -0
- package/dist/http/afs-rpc-wire.d.cts.map +1 -0
- package/dist/http/afs-rpc-wire.d.mts +195 -0
- package/dist/http/afs-rpc-wire.d.mts.map +1 -0
- package/dist/http/afs-rpc-wire.mjs +262 -0
- package/dist/http/afs-rpc-wire.mjs.map +1 -0
- package/dist/http/afs-rpc.cjs +729 -0
- package/dist/http/afs-rpc.d.cts +103 -0
- package/dist/http/afs-rpc.d.cts.map +1 -0
- package/dist/http/afs-rpc.d.mts +103 -0
- package/dist/http/afs-rpc.d.mts.map +1 -0
- package/dist/http/afs-rpc.mjs +729 -0
- package/dist/http/afs-rpc.mjs.map +1 -0
- package/dist/http/afs-upload.cjs +116 -0
- package/dist/http/afs-upload.d.cts +40 -0
- package/dist/http/afs-upload.d.cts.map +1 -0
- package/dist/http/afs-upload.d.mts +40 -0
- package/dist/http/afs-upload.d.mts.map +1 -0
- package/dist/http/afs-upload.mjs +116 -0
- package/dist/http/afs-upload.mjs.map +1 -0
- package/dist/http/aup-client.cjs +60 -0
- package/dist/http/aup-client.d.cts +22 -0
- package/dist/http/aup-client.d.cts.map +1 -0
- package/dist/http/aup-client.d.mts +22 -0
- package/dist/http/aup-client.d.mts.map +1 -0
- package/dist/http/aup-client.mjs +59 -0
- package/dist/http/aup-client.mjs.map +1 -0
- package/dist/http/aup-event.cjs +100 -0
- package/dist/http/aup-event.d.cts +38 -0
- package/dist/http/aup-event.d.cts.map +1 -0
- package/dist/http/aup-event.d.mts +38 -0
- package/dist/http/aup-event.d.mts.map +1 -0
- package/dist/http/aup-event.mjs +101 -0
- package/dist/http/aup-event.mjs.map +1 -0
- package/dist/http/auth-context.cjs +66 -0
- package/dist/http/auth-context.d.cts +64 -0
- package/dist/http/auth-context.d.cts.map +1 -0
- package/dist/http/auth-context.d.mts +64 -0
- package/dist/http/auth-context.d.mts.map +1 -0
- package/dist/http/auth-context.mjs +66 -0
- package/dist/http/auth-context.mjs.map +1 -0
- package/dist/http/csrf.cjs +50 -0
- package/dist/http/csrf.d.cts +8 -0
- package/dist/http/csrf.d.cts.map +1 -0
- package/dist/http/csrf.d.mts +8 -0
- package/dist/http/csrf.d.mts.map +1 -0
- package/dist/http/csrf.mjs +49 -0
- package/dist/http/csrf.mjs.map +1 -0
- package/dist/http/handlers.cjs +106 -0
- package/dist/http/handlers.d.cts +39 -0
- package/dist/http/handlers.d.cts.map +1 -0
- package/dist/http/handlers.d.mts +39 -0
- package/dist/http/handlers.d.mts.map +1 -0
- package/dist/http/handlers.mjs +104 -0
- package/dist/http/handlers.mjs.map +1 -0
- package/dist/http/index.d.mts +1 -0
- package/dist/http/ingest-facade.cjs +315 -0
- package/dist/http/ingest-facade.mjs +314 -0
- package/dist/http/ingest-facade.mjs.map +1 -0
- package/dist/http/raw-url.cjs +136 -0
- package/dist/http/raw-url.d.cts +54 -0
- package/dist/http/raw-url.d.cts.map +1 -0
- package/dist/http/raw-url.d.mts +54 -0
- package/dist/http/raw-url.d.mts.map +1 -0
- package/dist/http/raw-url.mjs +136 -0
- package/dist/http/raw-url.mjs.map +1 -0
- package/dist/http/request-context.cjs +178 -0
- package/dist/http/request-context.d.cts +76 -0
- package/dist/http/request-context.d.cts.map +1 -0
- package/dist/http/request-context.d.mts +76 -0
- package/dist/http/request-context.d.mts.map +1 -0
- package/dist/http/request-context.mjs +179 -0
- package/dist/http/request-context.mjs.map +1 -0
- package/dist/index.cjs +197 -0
- package/dist/index.d.cts +63 -0
- package/dist/index.d.mts +68 -0
- package/dist/index.mjs +61 -0
- package/dist/mcp/index.cjs +9 -0
- package/dist/mcp/index.d.cts +5 -0
- package/dist/mcp/index.d.mts +5 -0
- package/dist/mcp/index.mjs +6 -0
- package/dist/mcp/prompts.cjs +17 -0
- package/dist/mcp/prompts.d.cts +8 -0
- package/dist/mcp/prompts.d.cts.map +1 -0
- package/dist/mcp/prompts.d.mts +8 -0
- package/dist/mcp/prompts.d.mts.map +1 -0
- package/dist/mcp/prompts.mjs +17 -0
- package/dist/mcp/prompts.mjs.map +1 -0
- package/dist/mcp/resources.cjs +22 -0
- package/dist/mcp/resources.d.cts +8 -0
- package/dist/mcp/resources.d.cts.map +1 -0
- package/dist/mcp/resources.d.mts +8 -0
- package/dist/mcp/resources.d.mts.map +1 -0
- package/dist/mcp/resources.mjs +22 -0
- package/dist/mcp/resources.mjs.map +1 -0
- package/dist/mcp/server.cjs +51 -0
- package/dist/mcp/server.d.cts +20 -0
- package/dist/mcp/server.d.cts.map +1 -0
- package/dist/mcp/server.d.mts +20 -0
- package/dist/mcp/server.d.mts.map +1 -0
- package/dist/mcp/server.mjs +52 -0
- package/dist/mcp/server.mjs.map +1 -0
- package/dist/mcp/tools.cjs +218 -0
- package/dist/mcp/tools.d.cts +8 -0
- package/dist/mcp/tools.d.cts.map +1 -0
- package/dist/mcp/tools.d.mts +8 -0
- package/dist/mcp/tools.d.mts.map +1 -0
- package/dist/mcp/tools.mjs +219 -0
- package/dist/mcp/tools.mjs.map +1 -0
- package/dist/mcp/utils.cjs +75 -0
- package/dist/mcp/utils.mjs +69 -0
- package/dist/mcp/utils.mjs.map +1 -0
- package/dist/mount/index.cjs +4 -0
- package/dist/mount/index.d.cts +3 -0
- package/dist/mount/index.d.mts +3 -0
- package/dist/mount/index.mjs +3 -0
- package/dist/mount/materializer.cjs +167 -0
- package/dist/mount/materializer.d.cts +97 -0
- package/dist/mount/materializer.d.cts.map +1 -0
- package/dist/mount/materializer.d.mts +97 -0
- package/dist/mount/materializer.d.mts.map +1 -0
- package/dist/mount/materializer.mjs +167 -0
- package/dist/mount/materializer.mjs.map +1 -0
- package/dist/mount/types.d.cts +90 -0
- package/dist/mount/types.d.cts.map +1 -0
- package/dist/mount/types.d.mts +90 -0
- package/dist/mount/types.d.mts.map +1 -0
- package/dist/mount-config.cjs +61 -0
- package/dist/mount-config.d.cts +19 -0
- package/dist/mount-config.d.cts.map +1 -0
- package/dist/mount-config.d.mts +19 -0
- package/dist/mount-config.d.mts.map +1 -0
- package/dist/mount-config.mjs +61 -0
- package/dist/mount-config.mjs.map +1 -0
- package/dist/projectors/aup-projector.cjs +190 -0
- package/dist/projectors/aup-projector.d.cts +59 -0
- package/dist/projectors/aup-projector.d.cts.map +1 -0
- package/dist/projectors/aup-projector.d.mts +59 -0
- package/dist/projectors/aup-projector.d.mts.map +1 -0
- package/dist/projectors/aup-projector.mjs +188 -0
- package/dist/projectors/aup-projector.mjs.map +1 -0
- package/dist/projectors/index.cjs +6 -0
- package/dist/projectors/index.d.cts +2 -0
- package/dist/projectors/index.d.mts +2 -0
- package/dist/projectors/index.mjs +3 -0
- package/dist/scaffold/afs.cjs +195 -0
- package/dist/scaffold/afs.d.cts +16 -0
- package/dist/scaffold/afs.d.cts.map +1 -0
- package/dist/scaffold/afs.d.mts +16 -0
- package/dist/scaffold/afs.d.mts.map +1 -0
- package/dist/scaffold/afs.mjs +195 -0
- package/dist/scaffold/afs.mjs.map +1 -0
- package/dist/scaffold/composition.cjs +92 -0
- package/dist/scaffold/composition.d.cts +10 -0
- package/dist/scaffold/composition.d.cts.map +1 -0
- package/dist/scaffold/composition.d.mts +10 -0
- package/dist/scaffold/composition.d.mts.map +1 -0
- package/dist/scaffold/composition.mjs +92 -0
- package/dist/scaffold/composition.mjs.map +1 -0
- package/dist/scaffold/dsl-error.cjs +21 -0
- package/dist/scaffold/dsl-error.d.cts +11 -0
- package/dist/scaffold/dsl-error.d.cts.map +1 -0
- package/dist/scaffold/dsl-error.d.mts +11 -0
- package/dist/scaffold/dsl-error.d.mts.map +1 -0
- package/dist/scaffold/dsl-error.mjs +20 -0
- package/dist/scaffold/dsl-error.mjs.map +1 -0
- package/dist/scaffold/index.d.mts +12 -0
- package/dist/scaffold/manifest-dsl.cjs +188 -0
- package/dist/scaffold/manifest-dsl.d.cts +8 -0
- package/dist/scaffold/manifest-dsl.d.cts.map +1 -0
- package/dist/scaffold/manifest-dsl.d.mts +8 -0
- package/dist/scaffold/manifest-dsl.d.mts.map +1 -0
- package/dist/scaffold/manifest-dsl.mjs +188 -0
- package/dist/scaffold/manifest-dsl.mjs.map +1 -0
- package/dist/scaffold/module-dsl.cjs +284 -0
- package/dist/scaffold/module-dsl.d.cts +8 -0
- package/dist/scaffold/module-dsl.d.cts.map +1 -0
- package/dist/scaffold/module-dsl.d.mts +8 -0
- package/dist/scaffold/module-dsl.d.mts.map +1 -0
- package/dist/scaffold/module-dsl.mjs +284 -0
- package/dist/scaffold/module-dsl.mjs.map +1 -0
- package/dist/scaffold/resolver.cjs +156 -0
- package/dist/scaffold/resolver.d.cts +7 -0
- package/dist/scaffold/resolver.d.cts.map +1 -0
- package/dist/scaffold/resolver.d.mts +7 -0
- package/dist/scaffold/resolver.d.mts.map +1 -0
- package/dist/scaffold/resolver.mjs +156 -0
- package/dist/scaffold/resolver.mjs.map +1 -0
- package/dist/scaffold/runtime.cjs +24 -0
- package/dist/scaffold/runtime.d.cts +19 -0
- package/dist/scaffold/runtime.d.cts.map +1 -0
- package/dist/scaffold/runtime.d.mts +19 -0
- package/dist/scaffold/runtime.d.mts.map +1 -0
- package/dist/scaffold/runtime.mjs +25 -0
- package/dist/scaffold/runtime.mjs.map +1 -0
- package/dist/scaffold/shell-dsl.cjs +279 -0
- package/dist/scaffold/shell-dsl.d.cts +8 -0
- package/dist/scaffold/shell-dsl.d.cts.map +1 -0
- package/dist/scaffold/shell-dsl.d.mts +8 -0
- package/dist/scaffold/shell-dsl.d.mts.map +1 -0
- package/dist/scaffold/shell-dsl.mjs +279 -0
- package/dist/scaffold/shell-dsl.mjs.map +1 -0
- package/dist/scaffold/surface-dsl.cjs +182 -0
- package/dist/scaffold/surface-dsl.d.cts +8 -0
- package/dist/scaffold/surface-dsl.d.cts.map +1 -0
- package/dist/scaffold/surface-dsl.d.mts +8 -0
- package/dist/scaffold/surface-dsl.d.mts.map +1 -0
- package/dist/scaffold/surface-dsl.mjs +182 -0
- package/dist/scaffold/surface-dsl.mjs.map +1 -0
- package/dist/scaffold/surfaces.cjs +84 -0
- package/dist/scaffold/surfaces.d.cts +23 -0
- package/dist/scaffold/surfaces.d.cts.map +1 -0
- package/dist/scaffold/surfaces.d.mts +24 -0
- package/dist/scaffold/surfaces.d.mts.map +1 -0
- package/dist/scaffold/surfaces.mjs +84 -0
- package/dist/scaffold/surfaces.mjs.map +1 -0
- package/dist/scaffold/types.d.cts +264 -0
- package/dist/scaffold/types.d.cts.map +1 -0
- package/dist/scaffold/types.d.mts +265 -0
- package/dist/scaffold/types.d.mts.map +1 -0
- package/dist/scaffold/workspace-dsl.cjs +339 -0
- package/dist/scaffold/workspace-dsl.d.cts +49 -0
- package/dist/scaffold/workspace-dsl.d.cts.map +1 -0
- package/dist/scaffold/workspace-dsl.d.mts +49 -0
- package/dist/scaffold/workspace-dsl.d.mts.map +1 -0
- package/dist/scaffold/workspace-dsl.mjs +337 -0
- package/dist/scaffold/workspace-dsl.mjs.map +1 -0
- package/dist/scope/index.d.mts +3 -0
- package/dist/scope/read-blocklet-scope.cjs +29 -0
- package/dist/scope/read-blocklet-scope.d.cts +8 -0
- package/dist/scope/read-blocklet-scope.d.cts.map +1 -0
- package/dist/scope/read-blocklet-scope.d.mts +8 -0
- package/dist/scope/read-blocklet-scope.d.mts.map +1 -0
- package/dist/scope/read-blocklet-scope.mjs +30 -0
- package/dist/scope/read-blocklet-scope.mjs.map +1 -0
- package/dist/scope/resolve-scoped-afs.cjs +87 -0
- package/dist/scope/resolve-scoped-afs.d.cts +7 -0
- package/dist/scope/resolve-scoped-afs.d.cts.map +1 -0
- package/dist/scope/resolve-scoped-afs.d.mts +7 -0
- package/dist/scope/resolve-scoped-afs.d.mts.map +1 -0
- package/dist/scope/resolve-scoped-afs.mjs +88 -0
- package/dist/scope/resolve-scoped-afs.mjs.map +1 -0
- package/dist/scope/types.d.cts +25 -0
- package/dist/scope/types.d.cts.map +1 -0
- package/dist/scope/types.d.mts +25 -0
- package/dist/scope/types.d.mts.map +1 -0
- package/dist/session/backends.cjs +90 -0
- package/dist/session/backends.d.cts +35 -0
- package/dist/session/backends.d.cts.map +1 -0
- package/dist/session/backends.d.mts +35 -0
- package/dist/session/backends.d.mts.map +1 -0
- package/dist/session/backends.mjs +89 -0
- package/dist/session/backends.mjs.map +1 -0
- package/dist/session/replication-resolver.cjs +323 -0
- package/dist/session/replication-resolver.d.cts +71 -0
- package/dist/session/replication-resolver.d.cts.map +1 -0
- package/dist/session/replication-resolver.d.mts +71 -0
- package/dist/session/replication-resolver.d.mts.map +1 -0
- package/dist/session/replication-resolver.mjs +323 -0
- package/dist/session/replication-resolver.mjs.map +1 -0
- package/dist/session/role-level.cjs +36 -0
- package/dist/session/role-level.d.cts +24 -0
- package/dist/session/role-level.d.cts.map +1 -0
- package/dist/session/role-level.d.mts +24 -0
- package/dist/session/role-level.d.mts.map +1 -0
- package/dist/session/role-level.mjs +35 -0
- package/dist/session/role-level.mjs.map +1 -0
- package/dist/session/session-dir-providers.cjs +254 -0
- package/dist/session/session-dir-providers.d.cts +32 -0
- package/dist/session/session-dir-providers.d.cts.map +1 -0
- package/dist/session/session-dir-providers.d.mts +32 -0
- package/dist/session/session-dir-providers.d.mts.map +1 -0
- package/dist/session/session-dir-providers.mjs +252 -0
- package/dist/session/session-dir-providers.mjs.map +1 -0
- package/dist/session/session-id.cjs +20 -0
- package/dist/session/session-id.d.cts +15 -0
- package/dist/session/session-id.d.cts.map +1 -0
- package/dist/session/session-id.d.mts +15 -0
- package/dist/session/session-id.d.mts.map +1 -0
- package/dist/session/session-id.mjs +20 -0
- package/dist/session/session-id.mjs.map +1 -0
- package/dist/session/session-user-afs.cjs +899 -0
- package/dist/session/session-user-afs.d.cts +296 -0
- package/dist/session/session-user-afs.d.cts.map +1 -0
- package/dist/session/session-user-afs.d.mts +296 -0
- package/dist/session/session-user-afs.d.mts.map +1 -0
- package/dist/session/session-user-afs.mjs +896 -0
- package/dist/session/session-user-afs.mjs.map +1 -0
- package/dist/session/settings-cascade.cjs +69 -0
- package/dist/session/settings-cascade.d.cts +81 -0
- package/dist/session/settings-cascade.d.cts.map +1 -0
- package/dist/session/settings-cascade.d.mts +81 -0
- package/dist/session/settings-cascade.d.mts.map +1 -0
- package/dist/session/settings-cascade.mjs +69 -0
- package/dist/session/settings-cascade.mjs.map +1 -0
- package/dist/session/settings-resolver.cjs +770 -0
- package/dist/session/settings-resolver.d.cts +177 -0
- package/dist/session/settings-resolver.d.cts.map +1 -0
- package/dist/session/settings-resolver.d.mts +177 -0
- package/dist/session/settings-resolver.d.mts.map +1 -0
- package/dist/session/settings-resolver.mjs +771 -0
- package/dist/session/settings-resolver.mjs.map +1 -0
- package/dist/session/settings-schema-store.cjs +0 -0
- package/dist/session/settings-schema-store.d.cts +72 -0
- package/dist/session/settings-schema-store.d.cts.map +1 -0
- package/dist/session/settings-schema-store.d.mts +72 -0
- package/dist/session/settings-schema-store.d.mts.map +1 -0
- package/dist/session/settings-schema-store.mjs +0 -0
- package/dist/session/settings-schema-store.mjs.map +1 -0
- package/dist/system-mounts/index.cjs +14 -0
- package/dist/system-mounts/index.d.cts +6 -0
- package/dist/system-mounts/index.d.mts +6 -0
- package/dist/system-mounts/index.mjs +6 -0
- package/dist/system-mounts/install.cjs +101 -0
- package/dist/system-mounts/install.d.cts +36 -0
- package/dist/system-mounts/install.d.cts.map +1 -0
- package/dist/system-mounts/install.d.mts +37 -0
- package/dist/system-mounts/install.d.mts.map +1 -0
- package/dist/system-mounts/install.mjs +102 -0
- package/dist/system-mounts/install.mjs.map +1 -0
- package/dist/system-mounts/installers.cjs +247 -0
- package/dist/system-mounts/installers.d.cts +13 -0
- package/dist/system-mounts/installers.d.cts.map +1 -0
- package/dist/system-mounts/installers.d.mts +14 -0
- package/dist/system-mounts/installers.d.mts.map +1 -0
- package/dist/system-mounts/installers.mjs +244 -0
- package/dist/system-mounts/installers.mjs.map +1 -0
- package/dist/system-mounts/lists.cjs +122 -0
- package/dist/system-mounts/lists.d.cts +34 -0
- package/dist/system-mounts/lists.d.cts.map +1 -0
- package/dist/system-mounts/lists.d.mts +34 -0
- package/dist/system-mounts/lists.d.mts.map +1 -0
- package/dist/system-mounts/lists.mjs +122 -0
- package/dist/system-mounts/lists.mjs.map +1 -0
- package/dist/system-mounts/types.d.cts +124 -0
- package/dist/system-mounts/types.d.cts.map +1 -0
- package/dist/system-mounts/types.d.mts +125 -0
- package/dist/system-mounts/types.d.mts.map +1 -0
- package/dist/system-mounts/validate.cjs +56 -0
- package/dist/system-mounts/validate.d.cts +34 -0
- package/dist/system-mounts/validate.d.cts.map +1 -0
- package/dist/system-mounts/validate.d.mts +34 -0
- package/dist/system-mounts/validate.d.mts.map +1 -0
- package/dist/system-mounts/validate.mjs +56 -0
- package/dist/system-mounts/validate.mjs.map +1 -0
- package/dist/terminal-llm.cjs +90 -0
- package/dist/terminal-llm.d.cts +50 -0
- package/dist/terminal-llm.d.cts.map +1 -0
- package/dist/terminal-llm.d.mts +50 -0
- package/dist/terminal-llm.d.mts.map +1 -0
- package/dist/terminal-llm.mjs +90 -0
- package/dist/terminal-llm.mjs.map +1 -0
- package/dist/terminal-repl.cjs +371 -0
- package/dist/terminal-repl.d.cts +69 -0
- package/dist/terminal-repl.d.cts.map +1 -0
- package/dist/terminal-repl.d.mts +69 -0
- package/dist/terminal-repl.d.mts.map +1 -0
- package/dist/terminal-repl.mjs +370 -0
- package/dist/terminal-repl.mjs.map +1 -0
- package/dist/transport/idle-timer.cjs +136 -0
- package/dist/transport/idle-timer.d.cts +92 -0
- package/dist/transport/idle-timer.d.cts.map +1 -0
- package/dist/transport/idle-timer.d.mts +92 -0
- package/dist/transport/idle-timer.d.mts.map +1 -0
- package/dist/transport/idle-timer.mjs +132 -0
- package/dist/transport/idle-timer.mjs.map +1 -0
- package/dist/web-component-dsl.cjs +153 -0
- package/dist/web-component-dsl.d.cts +27 -0
- package/dist/web-component-dsl.d.cts.map +1 -0
- package/dist/web-component-dsl.d.mts +27 -0
- package/dist/web-component-dsl.d.mts.map +1 -0
- package/dist/web-component-dsl.mjs +152 -0
- package/dist/web-component-dsl.mjs.map +1 -0
- package/package.json +81 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.mjs","names":[],"sources":["../../src/blocklet/registry.ts"],"sourcesContent":["/**\n * Blocklet Registry — portable, runtime-agnostic discovery and reading.\n *\n * The registry unifies how Node and Cloudflare Worker runtimes discover and\n * read blocklets. Same detector logic runs against both filesystem-backed\n * readers (Node) and static-map-backed readers (CF bundle).\n *\n * Zero platform imports: everything here works unchanged in Node, Bun, Deno,\n * browsers, and Cloudflare Workers.\n */\n\nimport { makeNsLog } from \"@aigne/afs\";\nimport { time } from \"@aigne/afs-timing\";\nimport { joinURL } from \"ufo\";\n\nconst log = makeNsLog(\"aos\");\n\nconst UTF8_DECODER = new TextDecoder(\"utf-8\");\nconst UTF8_ENCODER = new TextEncoder();\nconst ALIASES_PATH = \".afs/aliases.json\";\n\n// ---------------------------------------------------------------------------\n// BlockletReader — narrow file-access interface for a single blocklet\n// ---------------------------------------------------------------------------\n\n/**\n * Read-only view of a single blocklet's files.\n *\n * Paths are relative to the blocklet root (e.g. \"index.html\", \".aup/app.json\").\n * Implementations should normalize leading slashes and `./` prefixes.\n */\nexport interface BlockletReader {\n /** Return true if a file exists at the given relative path. */\n exists(relPath: string): Promise<boolean>;\n /** Read file contents as UTF-8 text, or undefined if missing. */\n readText(relPath: string): Promise<string | undefined>;\n /**\n * Read file contents as raw bytes, or undefined if missing. Required for\n * binary assets (png / ico / jpg) — using `readText` for those bytes\n * round-trips through UTF-8 and corrupts the file.\n */\n readBytes(relPath: string): Promise<Uint8Array | undefined>;\n /** Return true if any file exists under the given directory path. */\n hasDir(relDir: string): Promise<boolean>;\n /** List relative paths of files directly under `relDir` (non-recursive). */\n listDir(relDir: string): Promise<string[]>;\n /**\n * List entries directly under `relDir` with each one's name + dir/file kind,\n * in ONE backend round-trip. Optional: when present, `detectBlockletPattern`\n * probes blocklet.yaml / .aup / index.* from a single `list` instead of 3-4\n * sequential `exists`/`hasDir` stats — the dominant cold-start cost on CF\n * DID-Space (issue #808: `resolve.pattern` ~665ms → ~150ms). Readers whose\n * per-entry stat is already cheap (fs, in-memory map) may omit it;\n * `detectBlockletPattern` falls back to the sequential probes.\n */\n listEntries?(relDir: string): Promise<Array<{ name: string; isDir: boolean }>>;\n}\n\n/** Normalize a relative path: strip leading `/` and `./`, collapse `//`. */\nexport function normalizeRel(p: string): string {\n let s = p.replace(/^\\.\\//, \"\").replace(/^\\/+/, \"\").replace(/\\/+/g, \"/\");\n if (s.endsWith(\"/\")) s = s.slice(0, -1);\n return s;\n}\n\n/**\n * Create a reader backed by an in-memory map of relative paths → file content.\n */\nexport function createMapBlockletReader(files: Record<string, string>): BlockletReader {\n const normalized: Record<string, string> = {};\n for (const [k, v] of Object.entries(files)) {\n normalized[normalizeRel(k)] = v;\n }\n const keys = Object.keys(normalized);\n\n return {\n async exists(relPath) {\n return Object.hasOwn(normalized, normalizeRel(relPath));\n },\n async readText(relPath) {\n return normalized[normalizeRel(relPath)];\n },\n async readBytes(relPath) {\n const text = normalized[normalizeRel(relPath)];\n return text === undefined ? undefined : UTF8_ENCODER.encode(text);\n },\n async hasDir(relDir) {\n const prefix = `${normalizeRel(relDir)}/`;\n return keys.some((k) => k.startsWith(prefix));\n },\n async listDir(relDir) {\n const prefix = normalizeRel(relDir) === \"\" ? \"\" : `${normalizeRel(relDir)}/`;\n const seen = new Set<string>();\n for (const k of keys) {\n if (!k.startsWith(prefix)) continue;\n const rest = k.slice(prefix.length);\n const firstSlash = rest.indexOf(\"/\");\n seen.add(firstSlash < 0 ? rest : rest.slice(0, firstSlash));\n }\n return [...seen];\n },\n // A key with a slash after the prefix is a nested path → its first segment\n // is a dir (mirrors `hasDir`); a slash-less key is a file (mirrors\n // `exists`). Dir wins if a name appears as both, matching precedence.\n async listEntries(relDir) {\n const prefix = normalizeRel(relDir) === \"\" ? \"\" : `${normalizeRel(relDir)}/`;\n const seen = new Map<string, boolean>();\n for (const k of keys) {\n if (!k.startsWith(prefix)) continue;\n const rest = k.slice(prefix.length);\n const firstSlash = rest.indexOf(\"/\");\n const name = firstSlash < 0 ? rest : rest.slice(0, firstSlash);\n if (name === \"\") continue;\n const isDir = firstSlash >= 0;\n if (isDir || !seen.has(name)) seen.set(name, isDir);\n }\n return [...seen].map(([name, isDir]) => ({ name, isDir }));\n },\n };\n}\n\n// ---------------------------------------------------------------------------\n// detectBlockletPattern — reader-based detection (replaces fs-based version)\n// ---------------------------------------------------------------------------\n\nexport type BlockletPatternKind =\n /** Directory has an explicit blocklet.yaml — use it as the source of truth. */\n | \"manifest\"\n /** Zero-config Pattern A — directory has a .aup/ subdirectory. */\n | \"zero-aup\"\n /** Zero-config Pattern S — directory has index.html at root. */\n | \"zero-web\"\n /** Zero-config Pattern B — directory has index.txt / index.md / index.ans at root. */\n | \"zero-terminal\";\n\nexport interface BlockletPattern {\n kind: BlockletPatternKind;\n /** For Pattern B — which index file was found. */\n terminalIndexFile?: string;\n /** For Pattern B — MIME type of the index file. */\n terminalIndexContentType?: string;\n}\n\n/** Terminal entry filename + MIME type recognised by Pattern B zero-config. */\nexport const TERMINAL_INDEX_FILES: ReadonlyArray<{ file: string; contentType: string }> = [\n { file: \"index.txt\", contentType: \"text/plain; charset=utf-8\" },\n { file: \"index.md\", contentType: \"text/markdown; charset=utf-8\" },\n { file: \"index.ans\", contentType: \"text/plain; charset=utf-8\" },\n];\n\n/**\n * Inspect a blocklet reader and return its pattern.\n *\n * Precedence (same as the fs-based version):\n * 1. blocklet.yaml → \"manifest\"\n * 2. .aup/ → \"zero-aup\"\n * 3. index.html → \"zero-web\"\n * 4. index.{txt,md,ans} → \"zero-terminal\"\n * 5. otherwise → null\n */\nexport async function detectBlockletPattern(\n reader: BlockletReader,\n): Promise<BlockletPattern | null> {\n // Fast path: one directory listing instead of 3-4 sequential stats. On CF\n // DID-Space each `exists`/`hasDir` is a cold D1/R2 round-trip (~150ms), so a\n // zero-web blocklet paid ~665ms probing blocklet.yaml → .aup → index.html\n // serially (issue #808 `resolve.pattern`). A single `list` collapses that to\n // ONE query; the precedence checks below become in-memory. `isFile` mirrors\n // `reader.exists` (file-only) and the `.aup` check mirrors `reader.hasDir`\n // (dir-only), so this path yields the SAME pattern as the fallback.\n if (reader.listEntries) {\n // `resolve.pattern.list` proves the fast path fired + times the single list\n // (vs the fallback's per-entry stats) — visible in Server-Timing.\n const entries = await time(\"resolve.pattern.list\", () => reader.listEntries!(\"\"));\n const isFile = (name: string): boolean => entries.some((e) => e.name === name && !e.isDir);\n if (isFile(\"blocklet.yaml\")) return { kind: \"manifest\" };\n if (entries.some((e) => e.name === \".aup\" && e.isDir)) return { kind: \"zero-aup\" };\n if (isFile(\"index.html\")) return { kind: \"zero-web\" };\n for (const { file, contentType } of TERMINAL_INDEX_FILES) {\n if (isFile(file)) {\n return {\n kind: \"zero-terminal\",\n terminalIndexFile: file,\n terminalIndexContentType: contentType,\n };\n }\n }\n return null;\n }\n\n // Fallback: sequential probes for readers that don't expose `listEntries`\n // (fs / in-memory map), where a per-entry stat is already cheap.\n if (await reader.exists(\"blocklet.yaml\")) return { kind: \"manifest\" };\n if (await reader.hasDir(\".aup\")) return { kind: \"zero-aup\" };\n if (await reader.exists(\"index.html\")) return { kind: \"zero-web\" };\n for (const { file, contentType } of TERMINAL_INDEX_FILES) {\n if (await reader.exists(file)) {\n return {\n kind: \"zero-terminal\",\n terminalIndexFile: file,\n terminalIndexContentType: contentType,\n };\n }\n }\n return null;\n}\n\n// ---------------------------------------------------------------------------\n// BlockletRegistry — lookup blocklets by name\n// ---------------------------------------------------------------------------\n\n/**\n * Registry of available blocklets. Runtime-specific implementations:\n * - Node: scans a filesystem directory (see runtimes/node/.../fs-blocklet-registry.ts)\n * - CF Worker: reads from a bundled static map (createStaticBlockletRegistry)\n * - Future: resolves via DID document\n */\nexport interface BlockletRegistry {\n /** Source label for logging (\"local\", \"embedded\", \"remote\"). */\n readonly source: \"local\" | \"embedded\" | \"remote\";\n /** List all known blocklet names. */\n list(): Promise<string[]>;\n /** Return the canonical blocklet name for a lookup key or alias, if found. */\n resolveName?(name: string): Promise<string | null>;\n /** Return a reader for the named blocklet, or null if not found. */\n reader(name: string): Promise<BlockletReader | null>;\n /**\n * Resolve the raw `(afs, rootPath)` pair backing this blocklet, for\n * consumers that need list/read/stat against a stable AFS path rather than\n * the narrower `BlockletReader` surface (e.g. the Web Device SiteServer,\n * which walks its own sub-paths directly). Optional — registries backed by\n * a non-path-addressable store (e.g. an embedded static map) omit it.\n * Returns null when the blocklet is unknown or has no raw AFS root.\n */\n afsRoot?(name: string): Promise<{ afs: BlockletAfsReader; rootPath: string } | null>;\n}\n\n/**\n * Create a registry backed by a static `{ name → { relPath → content } }` map.\n * Used by CF Worker to serve blocklets embedded at build time.\n */\nexport function createStaticBlockletRegistry(\n blocklets: Record<string, Record<string, string>>,\n): BlockletRegistry {\n const readers = new Map<string, BlockletReader>();\n for (const [name, files] of Object.entries(blocklets)) {\n readers.set(name, createMapBlockletReader(files));\n }\n return {\n source: \"embedded\",\n async list() {\n return [...readers.keys()];\n },\n async resolveName(name) {\n return readers.has(name) ? name : null;\n },\n async reader(name) {\n return readers.get(name) ?? null;\n },\n };\n}\n\n// ---------------------------------------------------------------------------\n// AFS-backed registry — works on top of any mounted provider (AFSFS,\n// AFSHttpMount, in-memory, etc). The reader proxies list/read through AFS so\n// the caller doesn't need to know which provider serves which blocklet.\n// ---------------------------------------------------------------------------\n\n/**\n * Minimal AFS surface this module needs. Typed loosely to avoid dragging the\n * full `@aigne/afs` AFS type into aos's public surface — only `read`, `list`,\n * and `stat` are consumed, and only their happy-path shape.\n */\n/**\n * Read options forwarded to the underlying AFS. Only the fields the blocklet\n * serve path needs are surfaced here — chiefly `includeActions:\"none\"`, which\n * skips the per-read semantic-action probe (`list <path>/.actions`) that pure\n * byte-serving reads never use (issue #808). Simple readers that don't wrap a\n * real AFS ignore it (they have no actions anyway).\n */\nexport interface BlockletAfsReadOptions {\n includeActions?: \"none\" | \"refs\" | \"schemas\";\n /**\n * For `stat` only: skip the `read()` fallback when the provider's stat handler\n * reports the path absent (issue #808). The bundle-cid probe sets it — a stat\n * miss means \"no bundle\", so the read fallback would only miss again. Mirrors\n * {@link AFSStatOptions.noReadFallback}; a real AFS forwards it, simple readers\n * ignore it.\n */\n noReadFallback?: boolean;\n}\n\nexport interface BlockletAfsReader {\n read(\n path: string,\n options?: BlockletAfsReadOptions,\n ): Promise<{ data?: { content?: unknown } | null | undefined } | null | undefined>;\n // `list` intentionally does NOT take BlockletAfsReadOptions: the core `list`\n // path doesn't thread `includeActions`, and its own option type (AFSListOptions:\n // pagination/orderBy) is disjoint — widening it here would break assignment\n // from a real AFS. The `.actions` probe on the serve path rides file READS.\n list(path: string): Promise<{\n data?:\n | ReadonlyArray<{\n path: string;\n meta?: { kind?: string; childrenCount?: number } | null | undefined;\n }>\n | null\n | undefined;\n }>;\n stat(\n path: string,\n options?: BlockletAfsReadOptions,\n ): Promise<{\n data?:\n | { meta?: { kind?: string; childrenCount?: number } | null | undefined }\n | null\n | undefined;\n } | null>;\n /**\n * Optional batch read — fetch many file paths in one shot (issue #808\n * follow-up). A real AFS pushes this to the DID-Space provider's `getMany`\n * (one `IN(…)` D1 query, inline content → zero R2). `ReadonlyMap` (not `Map`)\n * so a concrete `Map<string, AFSEntry | null>` stays assignable here despite\n * `Map`'s invariance. Absent → callers fall back to per-path `read`.\n */\n readMany?(paths: string[]): Promise<ReadonlyMap<string, { content?: unknown } | null>>;\n}\n\n/**\n * Directories in AFS always carry `childrenCount` in their meta. Leaves (files,\n * actions) do not. This matches the predicate used by `convention-scanner` in\n * @aigne/afs. Avoids stringly-typed kind matching that would drift as providers\n * add new kinds.\n */\nfunction isDirEntry(meta?: { childrenCount?: number } | null): boolean {\n return meta?.childrenCount !== undefined && meta.childrenCount !== null;\n}\n\nfunction lastSegment(p: string): string {\n const i = p.lastIndexOf(\"/\");\n return i < 0 ? p : p.slice(i + 1);\n}\n\n/** Create a BlockletReader that serves one blocklet rooted at `blockletRoot` in AFS. */\nexport function createAfsBlockletReader(\n afs: BlockletAfsReader,\n blockletRoot: string,\n): BlockletReader {\n // A blocklet reader serves file bytes + directory metadata for serve/registry\n // paths — it NEVER surfaces semantic actions. So every stat/read skips\n // enrichData's `list <path>/.actions` probe (issue #808). Thorough by\n // construction: no caller of this reader can accidentally pay for it.\n const NO_ACTIONS = { includeActions: \"none\" } as const;\n return {\n async exists(relPath) {\n const p = joinURL(blockletRoot, normalizeRel(relPath));\n try {\n const res = await afs.stat(p, NO_ACTIONS);\n const meta = res?.data?.meta;\n if (!meta) return false;\n return !isDirEntry(meta);\n } catch {\n return false;\n }\n },\n async readText(relPath) {\n const p = joinURL(blockletRoot, normalizeRel(relPath));\n try {\n const res = await afs.read(p, NO_ACTIONS);\n const content = res?.data?.content;\n if (typeof content === \"string\") return content;\n if (content instanceof Uint8Array) return UTF8_DECODER.decode(content);\n // The DID-Space provider returns binary reads as an ArrayBuffer.\n if (content instanceof ArrayBuffer) return UTF8_DECODER.decode(new Uint8Array(content));\n return undefined;\n } catch {\n return undefined;\n }\n },\n async readBytes(relPath) {\n const p = joinURL(blockletRoot, normalizeRel(relPath));\n try {\n const res = await afs.read(p, NO_ACTIONS);\n const content = res?.data?.content;\n if (content instanceof Uint8Array) return content;\n // The DID-Space provider returns binary reads (png/font/…) as an\n // ArrayBuffer; without this an image asset falls through to undefined and\n // the zero-web serve wrongly SPA-fallbacks to index.html.\n if (content instanceof ArrayBuffer) return new Uint8Array(content);\n if (typeof content === \"string\") return UTF8_ENCODER.encode(content);\n return undefined;\n } catch {\n return undefined;\n }\n },\n async hasDir(relDir) {\n const p = joinURL(blockletRoot, normalizeRel(relDir));\n try {\n const res = await afs.stat(p, NO_ACTIONS);\n return isDirEntry(res?.data?.meta);\n } catch {\n return false;\n }\n },\n async listDir(relDir) {\n const p = joinURL(blockletRoot, normalizeRel(relDir));\n try {\n const res = await afs.list(p);\n return (res?.data ?? []).map((e) => lastSegment(e.path));\n } catch {\n return [];\n }\n },\n // One `list` returns every child's name + kind (dir carries `childrenCount`,\n // same signal `computeList` already keys on) — no per-entry `.actions` probe\n // (`_list` doesn't enrich), so detectBlockletPattern pays ONE D1 query, not\n // one per precedence probe (issue #808).\n async listEntries(relDir) {\n const p = joinURL(blockletRoot, normalizeRel(relDir));\n try {\n const res = await afs.list(p);\n return (res?.data ?? []).map((e) => ({\n name: lastSegment(e.path),\n isDir: isDirEntry(e.meta),\n }));\n } catch {\n return [];\n }\n },\n };\n}\n\n/** Options for `createAfsBlockletRegistry`. */\nexport interface AfsBlockletRegistryOptions {\n afs: BlockletAfsReader;\n /** AFS paths to search for blocklet directories, e.g. `[\"/blocklets\"]`. */\n searchPaths: string[];\n /** Source label (default `\"local\"`). */\n source?: BlockletRegistry[\"source\"];\n}\n\n/**\n * Create a registry that discovers blocklets under one or more AFS paths.\n *\n * Each search path is listed; every immediate child directory is treated as a\n * candidate blocklet and probed via `detectBlockletPattern`. First match wins\n * when the same blocklet name appears in multiple search paths.\n */\nexport function createAfsBlockletRegistry(opts: AfsBlockletRegistryOptions): BlockletRegistry {\n const { afs, searchPaths, source = \"local\" } = opts;\n const readerCache = new Map<string, BlockletReader>();\n // Only positive results are cached — misses are NOT cached so that newly\n // deployed blocklets are discovered on the next probe (the underlying\n // http-mount refresh-on-miss handles rate-limiting).\n const dirCache = new Map<string, string>();\n const canonicalNameCache = new Map<string, string>();\n const aliasCache = new Map<string, string>();\n const aliasesLoaded = new Set<string>();\n const aliasLoadPromises = new Map<string, Promise<void>>();\n let listPromise: Promise<string[]> | undefined;\n\n function isSafeRegistryName(value: string): boolean {\n return (\n value.length > 0 &&\n value.length <= 253 &&\n !value.includes(\"/\") &&\n !value.includes(\"\\\\\") &&\n !value.includes(\"..\") &&\n !value.includes(\"@\")\n );\n }\n\n function isNotFoundError(err: unknown): boolean {\n if (!err || typeof err !== \"object\") return false;\n const maybe = err as { code?: unknown; name?: unknown; message?: unknown };\n if (maybe.name === \"AFSNotFoundError\" || maybe.code === \"AFS_NOT_FOUND\") return true;\n return typeof maybe.message === \"string\" && /not found/i.test(maybe.message);\n }\n\n async function loadAliases(base: string): Promise<void> {\n if (aliasesLoaded.has(base)) return;\n const existing = aliasLoadPromises.get(base);\n if (existing) return existing;\n\n let cacheableResult = false;\n const promise = (async () => {\n try {\n const res = await afs.read(joinURL(base, ALIASES_PATH));\n cacheableResult = true;\n const raw = decodeAfsContent(res?.data);\n if (!raw) return;\n const parsed = JSON.parse(raw) as unknown;\n if (!parsed || typeof parsed !== \"object\" || Array.isArray(parsed)) return;\n for (const [alias, target] of Object.entries(parsed)) {\n if (typeof target !== \"string\") continue;\n const key = alias.trim().toLowerCase();\n const value = target.trim();\n if (!isSafeRegistryName(key) || !isSafeRegistryName(value)) continue;\n aliasCache.set(key, value);\n }\n } catch (err) {\n // Alias metadata is optional. Cache definite absence/malformed content,\n // but let genuine provider/network failures retry on the next lookup.\n cacheableResult = cacheableResult || isNotFoundError(err);\n } finally {\n if (cacheableResult) aliasesLoaded.add(base);\n aliasLoadPromises.delete(base);\n }\n })();\n aliasLoadPromises.set(base, promise);\n return promise;\n }\n\n async function resolveAlias(name: string): Promise<string | null> {\n const key = name.trim().toLowerCase();\n const cached = aliasCache.get(key);\n if (cached !== undefined) return cached;\n for (const base of searchPaths) {\n await loadAliases(base);\n const target = aliasCache.get(key);\n if (target !== undefined) return target;\n }\n return null;\n }\n\n async function resolveLocation(\n name: string,\n ): Promise<{ canonicalName: string; dir: string } | null> {\n const cached = dirCache.get(name);\n const cachedName = canonicalNameCache.get(name);\n if (cached !== undefined && cachedName !== undefined) {\n return { canonicalName: cachedName, dir: cached };\n }\n // The direct-name dir lookup has NO dependency on the alias table, so probe\n // it concurrently with the (cold, HTTP-mount) aliases read instead of after\n // it. On a cold isolate the alias read and the direct stat each cost a full\n // round-trip; serializing them (the prior `await resolveAlias` then stat)\n // doubled the latency of the page-GET `resolve` segment. Overlapping them\n // collapses the two into ~one round-trip. Alias precedence is unchanged:\n // an explicit alias for `name` still wins over a same-named direct dir\n // (the alias branch is checked first below), matching the old\n // `[aliasTarget, name]` candidate order.\n const directProbe = resolveDirectDir(name);\n const aliasTarget = await resolveAlias(name);\n if (aliasTarget && aliasTarget !== name) {\n const aliasDir = await resolveDirectDir(aliasTarget);\n if (aliasDir) {\n dirCache.set(name, aliasDir);\n canonicalNameCache.set(name, aliasTarget);\n dirCache.set(aliasTarget, aliasDir);\n canonicalNameCache.set(aliasTarget, aliasTarget);\n return { canonicalName: aliasTarget, dir: aliasDir };\n }\n }\n const directDir = await directProbe;\n if (directDir) {\n dirCache.set(name, directDir);\n canonicalNameCache.set(name, name);\n return { canonicalName: name, dir: directDir };\n }\n // Do NOT cache null — let the next request retry so newly deployed\n // blocklets are picked up without a Worker restart.\n return null;\n }\n\n async function resolveDir(name: string): Promise<string | null> {\n return (await resolveLocation(name))?.dir ?? null;\n }\n\n function decodeAfsContent(raw: unknown): string {\n const content = (raw as { content?: unknown } | null | undefined)?.content;\n if (typeof content === \"string\") return content;\n if (content instanceof Uint8Array) return UTF8_DECODER.decode(content);\n if (content instanceof ArrayBuffer) return UTF8_DECODER.decode(new Uint8Array(content));\n return \"\";\n }\n\n async function resolveDirectDir(name: string): Promise<string | null> {\n for (const base of searchPaths) {\n const full = joinURL(base, name);\n try {\n const res = await afs.stat(full);\n if (isDirEntry(res?.data?.meta)) {\n return full;\n }\n } catch {\n // try next search path\n }\n }\n return null;\n }\n\n async function computeList(): Promise<string[]> {\n const found = new Set<string>();\n for (const base of searchPaths) {\n let entries: ReadonlyArray<{\n path: string;\n meta?: { kind?: string; childrenCount?: number } | null | undefined;\n }> = [];\n try {\n entries = (await afs.list(base))?.data ?? [];\n } catch (err) {\n log.warn(`[aos] blocklet-registry: list(\"${base}\") failed:`, err);\n continue;\n }\n const checks = await Promise.all(\n entries.map(async (e) => {\n if (!isDirEntry(e.meta)) return null;\n const name = lastSegment(e.path);\n if (found.has(name)) return null;\n const reader = createAfsBlockletReader(afs, joinURL(base, name));\n return (await detectBlockletPattern(reader)) ? name : null;\n }),\n );\n for (const n of checks) if (n) found.add(n);\n\n await loadAliases(base);\n for (const [alias, target] of aliasCache) {\n if (found.has(alias)) continue;\n const targetDir = await resolveDirectDir(target);\n if (!targetDir) continue;\n const reader = createAfsBlockletReader(afs, targetDir);\n if (await detectBlockletPattern(reader)) found.add(alias);\n }\n }\n return [...found];\n }\n\n return {\n source,\n async list() {\n if (!listPromise) {\n listPromise = computeList();\n listPromise.catch(() => {\n listPromise = undefined;\n });\n }\n return listPromise;\n },\n async resolveName(name) {\n return (await resolveLocation(name))?.canonicalName ?? null;\n },\n async reader(name) {\n if (readerCache.has(name)) return readerCache.get(name) ?? null;\n const dir = await resolveDir(name);\n if (!dir) return null;\n const reader = createAfsBlockletReader(afs, dir);\n readerCache.set(name, reader);\n return reader;\n },\n async afsRoot(name) {\n const dir = await resolveDir(name);\n if (!dir) return null;\n return { afs, rootPath: dir };\n },\n };\n}\n\n// ---------------------------------------------------------------------------\n// Pattern cache — memoise detectBlockletPattern + reader per name. Used by\n// domain routers that receive each subdomain as a fresh string and want to\n// round-trip to the registry at most once per unique name.\n// ---------------------------------------------------------------------------\n\nexport interface BlockletPatternCache {\n resolve(name: string): Promise<BlockletPattern | null>;\n resolveName(name: string): Promise<string | null>;\n readerFor(name: string): Promise<BlockletReader | null>;\n}\n\n/**\n * `null` as a tombstone for \"name is known but has no valid pattern\" keeps\n * repeated negative lookups cheap.\n */\nexport function createPatternCache(registry: BlockletRegistry): BlockletPatternCache {\n // Only positive results are cached. Misses are NOT stored so that newly\n // deployed blocklets are picked up on the next request without a restart.\n const patterns = new Map<string, BlockletPattern>();\n const readers = new Map<string, BlockletReader>();\n\n async function readerFor(name: string): Promise<BlockletReader | null> {\n const cached = readers.get(name);\n if (cached !== undefined) return cached;\n const r = await registry.reader(name);\n if (r) readers.set(name, r);\n return r;\n }\n\n async function resolve(name: string): Promise<BlockletPattern | null> {\n const cached = patterns.get(name);\n if (cached !== undefined) return cached;\n const reader = await readerFor(name);\n if (!reader) return null;\n // `resolve.pattern` attributes the cold-start file probes (blocklet.yaml /\n // .aup / index.html) detectBlockletPattern runs, separate from the reader\n // lookup — so `resolve`'s cost is split reader-lookup vs pattern-detect.\n const pattern = await time(\"resolve.pattern\", () => detectBlockletPattern(reader));\n if (pattern) patterns.set(name, pattern);\n return pattern;\n }\n\n async function resolveName(name: string): Promise<string | null> {\n const canonical = registry.resolveName ? await registry.resolveName(name) : null;\n const lookupName = canonical ?? name;\n const pattern = await resolve(lookupName);\n if (!pattern) return null;\n return lookupName;\n }\n\n return { resolve, resolveName, readerFor };\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
const require_registry = require('./registry.cjs');
|
|
2
|
+
|
|
3
|
+
//#region src/blocklet/static-render.ts
|
|
4
|
+
/**
|
|
5
|
+
* Serve a request against a blocklet reader.
|
|
6
|
+
*
|
|
7
|
+
* @param reader File reader for the blocklet
|
|
8
|
+
* @param pattern Pattern info from `detectBlockletPattern`
|
|
9
|
+
* @param subPath Request path within the blocklet (e.g. "/" or "/assets/app.js")
|
|
10
|
+
*/
|
|
11
|
+
async function renderStaticBlocklet(reader, pattern, subPath) {
|
|
12
|
+
if (subPath.includes("..")) return {
|
|
13
|
+
body: "Bad Request",
|
|
14
|
+
contentType: "text/plain",
|
|
15
|
+
status: 400
|
|
16
|
+
};
|
|
17
|
+
const normalized = normalizeSubPath(subPath);
|
|
18
|
+
if (pattern.kind === "zero-terminal") {
|
|
19
|
+
const indexFile = pattern.terminalIndexFile ?? "index.txt";
|
|
20
|
+
const contentType = pattern.terminalIndexContentType ?? "text/plain; charset=utf-8";
|
|
21
|
+
const body = await reader.readText(indexFile);
|
|
22
|
+
if (body === void 0) return {
|
|
23
|
+
body: "Not Found",
|
|
24
|
+
contentType: "text/plain",
|
|
25
|
+
status: 404
|
|
26
|
+
};
|
|
27
|
+
return {
|
|
28
|
+
body,
|
|
29
|
+
contentType,
|
|
30
|
+
status: 200
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
if (pattern.kind === "zero-web") {
|
|
34
|
+
const target = normalized === "/" ? "index.html" : stripLeadingSlash(normalized);
|
|
35
|
+
const contentType = guessContentType(target);
|
|
36
|
+
const body = BINARY_CONTENT_TYPES.has(contentType) ? await reader.readBytes(target) : await reader.readText(target);
|
|
37
|
+
if (body !== void 0) return {
|
|
38
|
+
body,
|
|
39
|
+
contentType,
|
|
40
|
+
status: 200
|
|
41
|
+
};
|
|
42
|
+
const fallback = await reader.readText("index.html");
|
|
43
|
+
if (fallback !== void 0) return {
|
|
44
|
+
body: fallback,
|
|
45
|
+
contentType: "text/html; charset=utf-8",
|
|
46
|
+
status: 200
|
|
47
|
+
};
|
|
48
|
+
return {
|
|
49
|
+
body: "Not Found",
|
|
50
|
+
contentType: "text/plain",
|
|
51
|
+
status: 404
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
return {
|
|
55
|
+
body: "Unsupported zero-config pattern",
|
|
56
|
+
contentType: "text/plain",
|
|
57
|
+
status: 500
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Conventional manifest asset filenames. Manager UIs and other consumers may
|
|
62
|
+
* request these paths against any blocklet; we serve them straight from the
|
|
63
|
+
* blocklet's directory regardless of pattern (manifest / zero-aup / etc.).
|
|
64
|
+
* Keep in lockstep with `LOGO_CANDIDATES` in `fs-blocklet-registry.ts` so the
|
|
65
|
+
* server side accepts whatever the registry advertised as `iconPath`.
|
|
66
|
+
*/
|
|
67
|
+
const CONVENTIONAL_ASSETS = new Set([
|
|
68
|
+
"logo.png",
|
|
69
|
+
"logo.svg",
|
|
70
|
+
"icon.png",
|
|
71
|
+
"icon.svg",
|
|
72
|
+
"favicon.png",
|
|
73
|
+
"favicon.svg",
|
|
74
|
+
"favicon.ico"
|
|
75
|
+
]);
|
|
76
|
+
/**
|
|
77
|
+
* Content types that must be read as raw bytes — UTF-8 round-tripping these
|
|
78
|
+
* corrupts the file. The text-vs-binary split is by content type, not by
|
|
79
|
+
* filename, so `guessContentType` is the single source of truth.
|
|
80
|
+
*/
|
|
81
|
+
const BINARY_CONTENT_TYPES = new Set([
|
|
82
|
+
"image/png",
|
|
83
|
+
"image/jpeg",
|
|
84
|
+
"image/gif",
|
|
85
|
+
"image/webp",
|
|
86
|
+
"image/x-icon",
|
|
87
|
+
"application/wasm",
|
|
88
|
+
"application/octet-stream"
|
|
89
|
+
]);
|
|
90
|
+
/**
|
|
91
|
+
* Quick check used by callers to gate the manifest-asset lookup before paying
|
|
92
|
+
* for filesystem access. Returns true for paths that look like an asset
|
|
93
|
+
* request: conventional filenames (`/logo.svg`, `/favicon.ico`, …) or a path
|
|
94
|
+
* that matches a manifest-declared logo. `declaredLogo` is optional — if the
|
|
95
|
+
* caller doesn't know it yet, the conventional-list check still gates ~95%
|
|
96
|
+
* of real traffic.
|
|
97
|
+
*/
|
|
98
|
+
function isConventionalAssetPath(subPath, declaredLogo) {
|
|
99
|
+
if (subPath.includes("..")) return false;
|
|
100
|
+
const normalized = subPath.startsWith("/") ? subPath.slice(1) : subPath;
|
|
101
|
+
if (!normalized) return false;
|
|
102
|
+
if (CONVENTIONAL_ASSETS.has(normalized)) return true;
|
|
103
|
+
const declared = declaredLogo?.replace(/^\/+/, "") ?? "";
|
|
104
|
+
return declared !== "" && normalized === declared;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Serve a conventional manifest asset (logo / icon / favicon) — or a
|
|
108
|
+
* manifest-declared logo path — from a blocklet reader. Returns `null` for
|
|
109
|
+
* paths outside the allowlist so the caller can fall through to its normal
|
|
110
|
+
* routing (AUP page, SiteServer, etc.); refuses to serve arbitrary files just
|
|
111
|
+
* because they happen to live next to `blocklet.yaml`.
|
|
112
|
+
*
|
|
113
|
+
* Reads binary content types (png / ico / jpg / …) through `readBytes` so the
|
|
114
|
+
* bytes round-trip correctly; text content types (svg / html / css / …) keep
|
|
115
|
+
* going through `readText`.
|
|
116
|
+
*
|
|
117
|
+
* The allowlist exists for two reasons:
|
|
118
|
+
* 1. Avoid surprising readers that didn't declare a static surface.
|
|
119
|
+
* 2. Keep behaviour identical across patterns so a manifest blocklet can
|
|
120
|
+
* show its logo in the manager UI without setting up routes.
|
|
121
|
+
*/
|
|
122
|
+
async function serveBlockletAsset(reader, subPath, opts = {}) {
|
|
123
|
+
if (subPath.includes("..")) return {
|
|
124
|
+
body: "Bad Request",
|
|
125
|
+
contentType: "text/plain",
|
|
126
|
+
status: 400
|
|
127
|
+
};
|
|
128
|
+
const normalized = subPath.startsWith("/") ? subPath.slice(1) : subPath;
|
|
129
|
+
if (!normalized) return null;
|
|
130
|
+
const declared = opts.declaredLogo?.replace(/^\/+/, "") ?? "";
|
|
131
|
+
if (!(CONVENTIONAL_ASSETS.has(normalized) || normalized === declared)) return null;
|
|
132
|
+
const contentType = guessContentType(normalized);
|
|
133
|
+
const body = BINARY_CONTENT_TYPES.has(contentType) ? await reader.readBytes(normalized) : await reader.readText(normalized);
|
|
134
|
+
if (body === void 0) return {
|
|
135
|
+
body: "Not Found",
|
|
136
|
+
contentType: "text/plain",
|
|
137
|
+
status: 404
|
|
138
|
+
};
|
|
139
|
+
return {
|
|
140
|
+
body,
|
|
141
|
+
contentType,
|
|
142
|
+
status: 200
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
function normalizeSubPath(sub) {
|
|
146
|
+
if (!sub || sub === "") return "/";
|
|
147
|
+
return sub.startsWith("/") ? sub : `/${sub}`;
|
|
148
|
+
}
|
|
149
|
+
function stripLeadingSlash(p) {
|
|
150
|
+
return p.startsWith("/") ? p.slice(1) : p;
|
|
151
|
+
}
|
|
152
|
+
const CONTENT_TYPES = {
|
|
153
|
+
html: "text/html; charset=utf-8",
|
|
154
|
+
htm: "text/html; charset=utf-8",
|
|
155
|
+
css: "text/css; charset=utf-8",
|
|
156
|
+
js: "application/javascript; charset=utf-8",
|
|
157
|
+
mjs: "application/javascript; charset=utf-8",
|
|
158
|
+
json: "application/json; charset=utf-8",
|
|
159
|
+
svg: "image/svg+xml",
|
|
160
|
+
png: "image/png",
|
|
161
|
+
jpg: "image/jpeg",
|
|
162
|
+
jpeg: "image/jpeg",
|
|
163
|
+
gif: "image/gif",
|
|
164
|
+
webp: "image/webp",
|
|
165
|
+
ico: "image/x-icon",
|
|
166
|
+
txt: "text/plain; charset=utf-8",
|
|
167
|
+
md: "text/markdown; charset=utf-8",
|
|
168
|
+
ans: "text/plain; charset=utf-8",
|
|
169
|
+
xml: "application/xml; charset=utf-8",
|
|
170
|
+
wasm: "application/wasm"
|
|
171
|
+
};
|
|
172
|
+
/** Guess a content type from a path suffix. Deliberately minimal. */
|
|
173
|
+
function guessContentType(path) {
|
|
174
|
+
const dot = path.lastIndexOf(".");
|
|
175
|
+
if (dot < 0) return "application/octet-stream";
|
|
176
|
+
return CONTENT_TYPES[path.slice(dot + 1).toLowerCase()] ?? "application/octet-stream";
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
//#endregion
|
|
180
|
+
exports.guessContentType = guessContentType;
|
|
181
|
+
exports.isConventionalAssetPath = isConventionalAssetPath;
|
|
182
|
+
exports.renderStaticBlocklet = renderStaticBlocklet;
|
|
183
|
+
exports.serveBlockletAsset = serveBlockletAsset;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { BlockletPattern, BlockletReader, createMapBlockletReader, detectBlockletPattern } from "./registry.cjs";
|
|
2
|
+
|
|
3
|
+
//#region src/blocklet/static-render.d.ts
|
|
4
|
+
interface StaticRenderResult {
|
|
5
|
+
/**
|
|
6
|
+
* Response body. `string` for text content (svg, html, css, js, json…);
|
|
7
|
+
* `Uint8Array` for binary content (png, jpg, ico, webp, wasm…). The
|
|
8
|
+
* content type tells the caller which one to expect; the writer side
|
|
9
|
+
* (`new Response(body, …)`) accepts both shapes.
|
|
10
|
+
*/
|
|
11
|
+
body: string | Uint8Array;
|
|
12
|
+
contentType: string;
|
|
13
|
+
status: number;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Serve a request against a blocklet reader.
|
|
17
|
+
*
|
|
18
|
+
* @param reader File reader for the blocklet
|
|
19
|
+
* @param pattern Pattern info from `detectBlockletPattern`
|
|
20
|
+
* @param subPath Request path within the blocklet (e.g. "/" or "/assets/app.js")
|
|
21
|
+
*/
|
|
22
|
+
declare function renderStaticBlocklet(reader: BlockletReader, pattern: BlockletPattern, subPath: string): Promise<StaticRenderResult>;
|
|
23
|
+
/**
|
|
24
|
+
* Quick check used by callers to gate the manifest-asset lookup before paying
|
|
25
|
+
* for filesystem access. Returns true for paths that look like an asset
|
|
26
|
+
* request: conventional filenames (`/logo.svg`, `/favicon.ico`, …) or a path
|
|
27
|
+
* that matches a manifest-declared logo. `declaredLogo` is optional — if the
|
|
28
|
+
* caller doesn't know it yet, the conventional-list check still gates ~95%
|
|
29
|
+
* of real traffic.
|
|
30
|
+
*/
|
|
31
|
+
declare function isConventionalAssetPath(subPath: string, declaredLogo?: string): boolean;
|
|
32
|
+
/**
|
|
33
|
+
* Serve a conventional manifest asset (logo / icon / favicon) — or a
|
|
34
|
+
* manifest-declared logo path — from a blocklet reader. Returns `null` for
|
|
35
|
+
* paths outside the allowlist so the caller can fall through to its normal
|
|
36
|
+
* routing (AUP page, SiteServer, etc.); refuses to serve arbitrary files just
|
|
37
|
+
* because they happen to live next to `blocklet.yaml`.
|
|
38
|
+
*
|
|
39
|
+
* Reads binary content types (png / ico / jpg / …) through `readBytes` so the
|
|
40
|
+
* bytes round-trip correctly; text content types (svg / html / css / …) keep
|
|
41
|
+
* going through `readText`.
|
|
42
|
+
*
|
|
43
|
+
* The allowlist exists for two reasons:
|
|
44
|
+
* 1. Avoid surprising readers that didn't declare a static surface.
|
|
45
|
+
* 2. Keep behaviour identical across patterns so a manifest blocklet can
|
|
46
|
+
* show its logo in the manager UI without setting up routes.
|
|
47
|
+
*/
|
|
48
|
+
declare function serveBlockletAsset(reader: BlockletReader, subPath: string, opts?: {
|
|
49
|
+
declaredLogo?: string;
|
|
50
|
+
}): Promise<StaticRenderResult | null>;
|
|
51
|
+
/** Guess a content type from a path suffix. Deliberately minimal. */
|
|
52
|
+
declare function guessContentType(path: string): string;
|
|
53
|
+
//#endregion
|
|
54
|
+
export { StaticRenderResult, guessContentType, isConventionalAssetPath, renderStaticBlocklet, serveBlockletAsset };
|
|
55
|
+
//# sourceMappingURL=static-render.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"static-render.d.cts","names":[],"sources":["../../src/blocklet/static-render.ts"],"mappings":";;;UAciB,kBAAA;EAST;AAUR;;;;;EAZE,IAAA,WAAe,UAAA;EACf,WAAA;EACA,MAAA;AAAA;;;;;;;;iBAUoB,oBAAA,CACpB,MAAA,EAAQ,cAAA,EACR,OAAA,EAAS,eAAA,EACT,OAAA,WACC,OAAA,CAAQ,kBAAA;;AA8EX;;;;;AAyBA;;iBAzBgB,uBAAA,CAAwB,OAAA,UAAiB,YAAA;;;;;;;;;;;;;;;AAkFzD;;iBAzDsB,kBAAA,CACpB,MAAA,EAAQ,cAAA,EACR,OAAA,UACA,IAAA;EAAQ,YAAA;AAAA,IACP,OAAA,CAAQ,kBAAA;;iBAqDK,gBAAA,CAAiB,IAAA"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { BlockletPattern, BlockletReader, createMapBlockletReader, detectBlockletPattern } from "./registry.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/blocklet/static-render.d.ts
|
|
4
|
+
interface StaticRenderResult {
|
|
5
|
+
/**
|
|
6
|
+
* Response body. `string` for text content (svg, html, css, js, json…);
|
|
7
|
+
* `Uint8Array` for binary content (png, jpg, ico, webp, wasm…). The
|
|
8
|
+
* content type tells the caller which one to expect; the writer side
|
|
9
|
+
* (`new Response(body, …)`) accepts both shapes.
|
|
10
|
+
*/
|
|
11
|
+
body: string | Uint8Array;
|
|
12
|
+
contentType: string;
|
|
13
|
+
status: number;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Serve a request against a blocklet reader.
|
|
17
|
+
*
|
|
18
|
+
* @param reader File reader for the blocklet
|
|
19
|
+
* @param pattern Pattern info from `detectBlockletPattern`
|
|
20
|
+
* @param subPath Request path within the blocklet (e.g. "/" or "/assets/app.js")
|
|
21
|
+
*/
|
|
22
|
+
declare function renderStaticBlocklet(reader: BlockletReader, pattern: BlockletPattern, subPath: string): Promise<StaticRenderResult>;
|
|
23
|
+
/**
|
|
24
|
+
* Quick check used by callers to gate the manifest-asset lookup before paying
|
|
25
|
+
* for filesystem access. Returns true for paths that look like an asset
|
|
26
|
+
* request: conventional filenames (`/logo.svg`, `/favicon.ico`, …) or a path
|
|
27
|
+
* that matches a manifest-declared logo. `declaredLogo` is optional — if the
|
|
28
|
+
* caller doesn't know it yet, the conventional-list check still gates ~95%
|
|
29
|
+
* of real traffic.
|
|
30
|
+
*/
|
|
31
|
+
declare function isConventionalAssetPath(subPath: string, declaredLogo?: string): boolean;
|
|
32
|
+
/**
|
|
33
|
+
* Serve a conventional manifest asset (logo / icon / favicon) — or a
|
|
34
|
+
* manifest-declared logo path — from a blocklet reader. Returns `null` for
|
|
35
|
+
* paths outside the allowlist so the caller can fall through to its normal
|
|
36
|
+
* routing (AUP page, SiteServer, etc.); refuses to serve arbitrary files just
|
|
37
|
+
* because they happen to live next to `blocklet.yaml`.
|
|
38
|
+
*
|
|
39
|
+
* Reads binary content types (png / ico / jpg / …) through `readBytes` so the
|
|
40
|
+
* bytes round-trip correctly; text content types (svg / html / css / …) keep
|
|
41
|
+
* going through `readText`.
|
|
42
|
+
*
|
|
43
|
+
* The allowlist exists for two reasons:
|
|
44
|
+
* 1. Avoid surprising readers that didn't declare a static surface.
|
|
45
|
+
* 2. Keep behaviour identical across patterns so a manifest blocklet can
|
|
46
|
+
* show its logo in the manager UI without setting up routes.
|
|
47
|
+
*/
|
|
48
|
+
declare function serveBlockletAsset(reader: BlockletReader, subPath: string, opts?: {
|
|
49
|
+
declaredLogo?: string;
|
|
50
|
+
}): Promise<StaticRenderResult | null>;
|
|
51
|
+
/** Guess a content type from a path suffix. Deliberately minimal. */
|
|
52
|
+
declare function guessContentType(path: string): string;
|
|
53
|
+
//#endregion
|
|
54
|
+
export { StaticRenderResult, guessContentType, isConventionalAssetPath, renderStaticBlocklet, serveBlockletAsset };
|
|
55
|
+
//# sourceMappingURL=static-render.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"static-render.d.mts","names":[],"sources":["../../src/blocklet/static-render.ts"],"mappings":";;;UAciB,kBAAA;EAST;AAUR;;;;;EAZE,IAAA,WAAe,UAAA;EACf,WAAA;EACA,MAAA;AAAA;;;;;;;;iBAUoB,oBAAA,CACpB,MAAA,EAAQ,cAAA,EACR,OAAA,EAAS,eAAA,EACT,OAAA,WACC,OAAA,CAAQ,kBAAA;;AA8EX;;;;;AAyBA;;iBAzBgB,uBAAA,CAAwB,OAAA,UAAiB,YAAA;;;;;;;;;;;;;;;AAkFzD;;iBAzDsB,kBAAA,CACpB,MAAA,EAAQ,cAAA,EACR,OAAA,UACA,IAAA;EAAQ,YAAA;AAAA,IACP,OAAA,CAAQ,kBAAA;;iBAqDK,gBAAA,CAAiB,IAAA"}
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import { createMapBlockletReader, detectBlockletPattern } from "./registry.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/blocklet/static-render.ts
|
|
4
|
+
/**
|
|
5
|
+
* Serve a request against a blocklet reader.
|
|
6
|
+
*
|
|
7
|
+
* @param reader File reader for the blocklet
|
|
8
|
+
* @param pattern Pattern info from `detectBlockletPattern`
|
|
9
|
+
* @param subPath Request path within the blocklet (e.g. "/" or "/assets/app.js")
|
|
10
|
+
*/
|
|
11
|
+
async function renderStaticBlocklet(reader, pattern, subPath) {
|
|
12
|
+
if (subPath.includes("..")) return {
|
|
13
|
+
body: "Bad Request",
|
|
14
|
+
contentType: "text/plain",
|
|
15
|
+
status: 400
|
|
16
|
+
};
|
|
17
|
+
const normalized = normalizeSubPath(subPath);
|
|
18
|
+
if (pattern.kind === "zero-terminal") {
|
|
19
|
+
const indexFile = pattern.terminalIndexFile ?? "index.txt";
|
|
20
|
+
const contentType = pattern.terminalIndexContentType ?? "text/plain; charset=utf-8";
|
|
21
|
+
const body = await reader.readText(indexFile);
|
|
22
|
+
if (body === void 0) return {
|
|
23
|
+
body: "Not Found",
|
|
24
|
+
contentType: "text/plain",
|
|
25
|
+
status: 404
|
|
26
|
+
};
|
|
27
|
+
return {
|
|
28
|
+
body,
|
|
29
|
+
contentType,
|
|
30
|
+
status: 200
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
if (pattern.kind === "zero-web") {
|
|
34
|
+
const target = normalized === "/" ? "index.html" : stripLeadingSlash(normalized);
|
|
35
|
+
const contentType = guessContentType(target);
|
|
36
|
+
const body = BINARY_CONTENT_TYPES.has(contentType) ? await reader.readBytes(target) : await reader.readText(target);
|
|
37
|
+
if (body !== void 0) return {
|
|
38
|
+
body,
|
|
39
|
+
contentType,
|
|
40
|
+
status: 200
|
|
41
|
+
};
|
|
42
|
+
const fallback = await reader.readText("index.html");
|
|
43
|
+
if (fallback !== void 0) return {
|
|
44
|
+
body: fallback,
|
|
45
|
+
contentType: "text/html; charset=utf-8",
|
|
46
|
+
status: 200
|
|
47
|
+
};
|
|
48
|
+
return {
|
|
49
|
+
body: "Not Found",
|
|
50
|
+
contentType: "text/plain",
|
|
51
|
+
status: 404
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
return {
|
|
55
|
+
body: "Unsupported zero-config pattern",
|
|
56
|
+
contentType: "text/plain",
|
|
57
|
+
status: 500
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Conventional manifest asset filenames. Manager UIs and other consumers may
|
|
62
|
+
* request these paths against any blocklet; we serve them straight from the
|
|
63
|
+
* blocklet's directory regardless of pattern (manifest / zero-aup / etc.).
|
|
64
|
+
* Keep in lockstep with `LOGO_CANDIDATES` in `fs-blocklet-registry.ts` so the
|
|
65
|
+
* server side accepts whatever the registry advertised as `iconPath`.
|
|
66
|
+
*/
|
|
67
|
+
const CONVENTIONAL_ASSETS = new Set([
|
|
68
|
+
"logo.png",
|
|
69
|
+
"logo.svg",
|
|
70
|
+
"icon.png",
|
|
71
|
+
"icon.svg",
|
|
72
|
+
"favicon.png",
|
|
73
|
+
"favicon.svg",
|
|
74
|
+
"favicon.ico"
|
|
75
|
+
]);
|
|
76
|
+
/**
|
|
77
|
+
* Content types that must be read as raw bytes — UTF-8 round-tripping these
|
|
78
|
+
* corrupts the file. The text-vs-binary split is by content type, not by
|
|
79
|
+
* filename, so `guessContentType` is the single source of truth.
|
|
80
|
+
*/
|
|
81
|
+
const BINARY_CONTENT_TYPES = new Set([
|
|
82
|
+
"image/png",
|
|
83
|
+
"image/jpeg",
|
|
84
|
+
"image/gif",
|
|
85
|
+
"image/webp",
|
|
86
|
+
"image/x-icon",
|
|
87
|
+
"application/wasm",
|
|
88
|
+
"application/octet-stream"
|
|
89
|
+
]);
|
|
90
|
+
/**
|
|
91
|
+
* Quick check used by callers to gate the manifest-asset lookup before paying
|
|
92
|
+
* for filesystem access. Returns true for paths that look like an asset
|
|
93
|
+
* request: conventional filenames (`/logo.svg`, `/favicon.ico`, …) or a path
|
|
94
|
+
* that matches a manifest-declared logo. `declaredLogo` is optional — if the
|
|
95
|
+
* caller doesn't know it yet, the conventional-list check still gates ~95%
|
|
96
|
+
* of real traffic.
|
|
97
|
+
*/
|
|
98
|
+
function isConventionalAssetPath(subPath, declaredLogo) {
|
|
99
|
+
if (subPath.includes("..")) return false;
|
|
100
|
+
const normalized = subPath.startsWith("/") ? subPath.slice(1) : subPath;
|
|
101
|
+
if (!normalized) return false;
|
|
102
|
+
if (CONVENTIONAL_ASSETS.has(normalized)) return true;
|
|
103
|
+
const declared = declaredLogo?.replace(/^\/+/, "") ?? "";
|
|
104
|
+
return declared !== "" && normalized === declared;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Serve a conventional manifest asset (logo / icon / favicon) — or a
|
|
108
|
+
* manifest-declared logo path — from a blocklet reader. Returns `null` for
|
|
109
|
+
* paths outside the allowlist so the caller can fall through to its normal
|
|
110
|
+
* routing (AUP page, SiteServer, etc.); refuses to serve arbitrary files just
|
|
111
|
+
* because they happen to live next to `blocklet.yaml`.
|
|
112
|
+
*
|
|
113
|
+
* Reads binary content types (png / ico / jpg / …) through `readBytes` so the
|
|
114
|
+
* bytes round-trip correctly; text content types (svg / html / css / …) keep
|
|
115
|
+
* going through `readText`.
|
|
116
|
+
*
|
|
117
|
+
* The allowlist exists for two reasons:
|
|
118
|
+
* 1. Avoid surprising readers that didn't declare a static surface.
|
|
119
|
+
* 2. Keep behaviour identical across patterns so a manifest blocklet can
|
|
120
|
+
* show its logo in the manager UI without setting up routes.
|
|
121
|
+
*/
|
|
122
|
+
async function serveBlockletAsset(reader, subPath, opts = {}) {
|
|
123
|
+
if (subPath.includes("..")) return {
|
|
124
|
+
body: "Bad Request",
|
|
125
|
+
contentType: "text/plain",
|
|
126
|
+
status: 400
|
|
127
|
+
};
|
|
128
|
+
const normalized = subPath.startsWith("/") ? subPath.slice(1) : subPath;
|
|
129
|
+
if (!normalized) return null;
|
|
130
|
+
const declared = opts.declaredLogo?.replace(/^\/+/, "") ?? "";
|
|
131
|
+
if (!(CONVENTIONAL_ASSETS.has(normalized) || normalized === declared)) return null;
|
|
132
|
+
const contentType = guessContentType(normalized);
|
|
133
|
+
const body = BINARY_CONTENT_TYPES.has(contentType) ? await reader.readBytes(normalized) : await reader.readText(normalized);
|
|
134
|
+
if (body === void 0) return {
|
|
135
|
+
body: "Not Found",
|
|
136
|
+
contentType: "text/plain",
|
|
137
|
+
status: 404
|
|
138
|
+
};
|
|
139
|
+
return {
|
|
140
|
+
body,
|
|
141
|
+
contentType,
|
|
142
|
+
status: 200
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
function normalizeSubPath(sub) {
|
|
146
|
+
if (!sub || sub === "") return "/";
|
|
147
|
+
return sub.startsWith("/") ? sub : `/${sub}`;
|
|
148
|
+
}
|
|
149
|
+
function stripLeadingSlash(p) {
|
|
150
|
+
return p.startsWith("/") ? p.slice(1) : p;
|
|
151
|
+
}
|
|
152
|
+
const CONTENT_TYPES = {
|
|
153
|
+
html: "text/html; charset=utf-8",
|
|
154
|
+
htm: "text/html; charset=utf-8",
|
|
155
|
+
css: "text/css; charset=utf-8",
|
|
156
|
+
js: "application/javascript; charset=utf-8",
|
|
157
|
+
mjs: "application/javascript; charset=utf-8",
|
|
158
|
+
json: "application/json; charset=utf-8",
|
|
159
|
+
svg: "image/svg+xml",
|
|
160
|
+
png: "image/png",
|
|
161
|
+
jpg: "image/jpeg",
|
|
162
|
+
jpeg: "image/jpeg",
|
|
163
|
+
gif: "image/gif",
|
|
164
|
+
webp: "image/webp",
|
|
165
|
+
ico: "image/x-icon",
|
|
166
|
+
txt: "text/plain; charset=utf-8",
|
|
167
|
+
md: "text/markdown; charset=utf-8",
|
|
168
|
+
ans: "text/plain; charset=utf-8",
|
|
169
|
+
xml: "application/xml; charset=utf-8",
|
|
170
|
+
wasm: "application/wasm"
|
|
171
|
+
};
|
|
172
|
+
/** Guess a content type from a path suffix. Deliberately minimal. */
|
|
173
|
+
function guessContentType(path) {
|
|
174
|
+
const dot = path.lastIndexOf(".");
|
|
175
|
+
if (dot < 0) return "application/octet-stream";
|
|
176
|
+
return CONTENT_TYPES[path.slice(dot + 1).toLowerCase()] ?? "application/octet-stream";
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
//#endregion
|
|
180
|
+
export { guessContentType, isConventionalAssetPath, renderStaticBlocklet, serveBlockletAsset };
|
|
181
|
+
//# sourceMappingURL=static-render.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"static-render.mjs","names":[],"sources":["../../src/blocklet/static-render.ts"],"sourcesContent":["/**\n * Static blocklet renderer — serves files from a BlockletReader.\n *\n * Replaces the AFS-based zero-config renderer that used to live in\n * runtimes/node. Works identically on Node, Bun, and Cloudflare Workers.\n *\n * Pattern S (zero-web): serves files with SPA fallback to index.html.\n * Pattern B (zero-terminal): returns the index file for every request.\n */\n\nimport type { BlockletPattern, BlockletReader } from \"./registry.js\";\n\nexport { createMapBlockletReader, detectBlockletPattern } from \"./registry.js\";\n\nexport interface StaticRenderResult {\n /**\n * Response body. `string` for text content (svg, html, css, js, json…);\n * `Uint8Array` for binary content (png, jpg, ico, webp, wasm…). The\n * content type tells the caller which one to expect; the writer side\n * (`new Response(body, …)`) accepts both shapes.\n */\n body: string | Uint8Array;\n contentType: string;\n status: number;\n}\n\n/**\n * Serve a request against a blocklet reader.\n *\n * @param reader File reader for the blocklet\n * @param pattern Pattern info from `detectBlockletPattern`\n * @param subPath Request path within the blocklet (e.g. \"/\" or \"/assets/app.js\")\n */\nexport async function renderStaticBlocklet(\n reader: BlockletReader,\n pattern: BlockletPattern,\n subPath: string,\n): Promise<StaticRenderResult> {\n if (subPath.includes(\"..\")) {\n return { body: \"Bad Request\", contentType: \"text/plain\", status: 400 };\n }\n\n const normalized = normalizeSubPath(subPath);\n\n if (pattern.kind === \"zero-terminal\") {\n const indexFile = pattern.terminalIndexFile ?? \"index.txt\";\n const contentType = pattern.terminalIndexContentType ?? \"text/plain; charset=utf-8\";\n const body = await reader.readText(indexFile);\n if (body === undefined) {\n return { body: \"Not Found\", contentType: \"text/plain\", status: 404 };\n }\n return { body, contentType, status: 200 };\n }\n\n if (pattern.kind === \"zero-web\") {\n const target = normalized === \"/\" ? \"index.html\" : stripLeadingSlash(normalized);\n const contentType = guessContentType(target);\n const body = BINARY_CONTENT_TYPES.has(contentType)\n ? await reader.readBytes(target)\n : await reader.readText(target);\n if (body !== undefined) {\n return { body, contentType, status: 200 };\n }\n // SPA fallback\n const fallback = await reader.readText(\"index.html\");\n if (fallback !== undefined) {\n return { body: fallback, contentType: \"text/html; charset=utf-8\", status: 200 };\n }\n return { body: \"Not Found\", contentType: \"text/plain\", status: 404 };\n }\n\n // zero-aup / manifest cases are handled by higher-level routers.\n return { body: \"Unsupported zero-config pattern\", contentType: \"text/plain\", status: 500 };\n}\n\n/**\n * Conventional manifest asset filenames. Manager UIs and other consumers may\n * request these paths against any blocklet; we serve them straight from the\n * blocklet's directory regardless of pattern (manifest / zero-aup / etc.).\n * Keep in lockstep with `LOGO_CANDIDATES` in `fs-blocklet-registry.ts` so the\n * server side accepts whatever the registry advertised as `iconPath`.\n */\nconst CONVENTIONAL_ASSETS: ReadonlySet<string> = new Set([\n \"logo.png\",\n \"logo.svg\",\n \"icon.png\",\n \"icon.svg\",\n \"favicon.png\",\n \"favicon.svg\",\n \"favicon.ico\",\n]);\n\n/**\n * Content types that must be read as raw bytes — UTF-8 round-tripping these\n * corrupts the file. The text-vs-binary split is by content type, not by\n * filename, so `guessContentType` is the single source of truth.\n */\nconst BINARY_CONTENT_TYPES: ReadonlySet<string> = new Set([\n \"image/png\",\n \"image/jpeg\",\n \"image/gif\",\n \"image/webp\",\n \"image/x-icon\",\n \"application/wasm\",\n \"application/octet-stream\",\n]);\n\n/**\n * Quick check used by callers to gate the manifest-asset lookup before paying\n * for filesystem access. Returns true for paths that look like an asset\n * request: conventional filenames (`/logo.svg`, `/favicon.ico`, …) or a path\n * that matches a manifest-declared logo. `declaredLogo` is optional — if the\n * caller doesn't know it yet, the conventional-list check still gates ~95%\n * of real traffic.\n */\nexport function isConventionalAssetPath(subPath: string, declaredLogo?: string): boolean {\n if (subPath.includes(\"..\")) return false;\n const normalized = subPath.startsWith(\"/\") ? subPath.slice(1) : subPath;\n if (!normalized) return false;\n if (CONVENTIONAL_ASSETS.has(normalized)) return true;\n const declared = declaredLogo?.replace(/^\\/+/, \"\") ?? \"\";\n return declared !== \"\" && normalized === declared;\n}\n\n/**\n * Serve a conventional manifest asset (logo / icon / favicon) — or a\n * manifest-declared logo path — from a blocklet reader. Returns `null` for\n * paths outside the allowlist so the caller can fall through to its normal\n * routing (AUP page, SiteServer, etc.); refuses to serve arbitrary files just\n * because they happen to live next to `blocklet.yaml`.\n *\n * Reads binary content types (png / ico / jpg / …) through `readBytes` so the\n * bytes round-trip correctly; text content types (svg / html / css / …) keep\n * going through `readText`.\n *\n * The allowlist exists for two reasons:\n * 1. Avoid surprising readers that didn't declare a static surface.\n * 2. Keep behaviour identical across patterns so a manifest blocklet can\n * show its logo in the manager UI without setting up routes.\n */\nexport async function serveBlockletAsset(\n reader: BlockletReader,\n subPath: string,\n opts: { declaredLogo?: string } = {},\n): Promise<StaticRenderResult | null> {\n if (subPath.includes(\"..\")) {\n return { body: \"Bad Request\", contentType: \"text/plain\", status: 400 };\n }\n const normalized = subPath.startsWith(\"/\") ? subPath.slice(1) : subPath;\n if (!normalized) return null;\n\n const declared = opts.declaredLogo?.replace(/^\\/+/, \"\") ?? \"\";\n const isAllowed = CONVENTIONAL_ASSETS.has(normalized) || normalized === declared;\n if (!isAllowed) return null;\n\n const contentType = guessContentType(normalized);\n const body = BINARY_CONTENT_TYPES.has(contentType)\n ? await reader.readBytes(normalized)\n : await reader.readText(normalized);\n if (body === undefined) {\n return { body: \"Not Found\", contentType: \"text/plain\", status: 404 };\n }\n return { body, contentType, status: 200 };\n}\n\nfunction normalizeSubPath(sub: string): string {\n if (!sub || sub === \"\") return \"/\";\n return sub.startsWith(\"/\") ? sub : `/${sub}`;\n}\n\nfunction stripLeadingSlash(p: string): string {\n return p.startsWith(\"/\") ? p.slice(1) : p;\n}\n\n// biome-ignore format: readable as a table\nconst CONTENT_TYPES: Readonly<Record<string, string>> = {\n html: \"text/html; charset=utf-8\",\n htm: \"text/html; charset=utf-8\",\n css: \"text/css; charset=utf-8\",\n js: \"application/javascript; charset=utf-8\",\n mjs: \"application/javascript; charset=utf-8\",\n json: \"application/json; charset=utf-8\",\n svg: \"image/svg+xml\",\n png: \"image/png\",\n jpg: \"image/jpeg\",\n jpeg: \"image/jpeg\",\n gif: \"image/gif\",\n webp: \"image/webp\",\n ico: \"image/x-icon\",\n txt: \"text/plain; charset=utf-8\",\n md: \"text/markdown; charset=utf-8\",\n ans: \"text/plain; charset=utf-8\",\n xml: \"application/xml; charset=utf-8\",\n wasm: \"application/wasm\",\n};\n\n/** Guess a content type from a path suffix. Deliberately minimal. */\nexport function guessContentType(path: string): string {\n const dot = path.lastIndexOf(\".\");\n if (dot < 0) return \"application/octet-stream\";\n const ext = path.slice(dot + 1).toLowerCase();\n return CONTENT_TYPES[ext] ?? \"application/octet-stream\";\n}\n"],"mappings":"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"}
|