aimeat 3.2.0 → 3.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.env.example +58 -1
- package/dist/build-stamp.json +4 -4
- package/dist/locales/en.json +41 -1
- package/dist/locales/es.json +41 -1
- package/dist/locales/fi.json +43 -3
- package/dist/public/changelog.json +12 -0
- package/dist/public/css/views/chat.css +388 -0
- package/dist/public/js/services/chat.js +190 -0
- package/dist/public/js/services/speech-reader.js +26 -0
- package/dist/public/lib/VENDORED.md +1 -0
- package/dist/public/lib/duckdb-wasm@1.32.0/duckdb-browser-eh.worker.js +14 -0
- package/dist/public/lib/duckdb-wasm@1.32.0/duckdb-browser.js +23 -0
- package/dist/public/lib/duckdb-wasm@1.32.0/duckdb-eh.wasm +0 -0
- package/dist/public/lib/duckdb-wasm@1.32.0/extensions/v1.4.3/wasm_eh/parquet.duckdb_extension.wasm +0 -0
- package/dist/public/lib/vendored-assets.json +19 -0
- package/dist/public/llms-full-template.txt +2706 -0
- package/dist/public/llms-index-template.txt +60 -0
- package/dist/public/robots.node.txt +64 -23
- package/dist/public/spa.html +8 -1
- package/dist/public/views/chat/parts.js +257 -0
- package/dist/public/views/chat.js +327 -0
- package/dist/public/views/landing.js +24 -1
- package/dist/public/views/profile/agents/scope-model.js +320 -315
- package/dist/scripts/audit-mcp-schemas.js +41 -0
- package/dist/scripts/audit-mcp-schemas.js.map +1 -1
- package/dist/scripts/build-sdk-libs.d.ts.map +1 -1
- package/dist/scripts/build-sdk-libs.js +1 -0
- package/dist/scripts/build-sdk-libs.js.map +1 -1
- package/dist/scripts/check-ai-disclosure.js +11 -0
- package/dist/scripts/check-ai-disclosure.js.map +1 -1
- package/dist/scripts/check-denial-coverage.d.ts +29 -0
- package/dist/scripts/check-denial-coverage.d.ts.map +1 -0
- package/dist/scripts/check-denial-coverage.js +237 -0
- package/dist/scripts/check-denial-coverage.js.map +1 -0
- package/dist/scripts/check-ext-entrypoints.js +14 -2
- package/dist/scripts/check-ext-entrypoints.js.map +1 -1
- package/dist/scripts/check-outbound-fetch.d.ts.map +1 -1
- package/dist/scripts/check-outbound-fetch.js +16 -2
- package/dist/scripts/check-outbound-fetch.js.map +1 -1
- package/dist/scripts/check-sse-parity.js +14 -0
- package/dist/scripts/check-sse-parity.js.map +1 -1
- package/dist/scripts/indexnow.js +9 -7
- package/dist/scripts/indexnow.js.map +1 -1
- package/dist/src/auth/middleware.d.ts +7 -0
- package/dist/src/auth/middleware.d.ts.map +1 -1
- package/dist/src/auth/middleware.js +15 -21
- package/dist/src/auth/middleware.js.map +1 -1
- package/dist/src/cli/connect/mcp/tools/agent-tasks.d.ts +4 -0
- package/dist/src/cli/connect/mcp/tools/agent-tasks.d.ts.map +1 -1
- package/dist/src/cli/connect/mcp/tools/agent-tasks.js +11 -1
- package/dist/src/cli/connect/mcp/tools/agent-tasks.js.map +1 -1
- package/dist/src/cli/connect/mcp/tools/apps.d.ts.map +1 -1
- package/dist/src/cli/connect/mcp/tools/apps.js +88 -0
- package/dist/src/cli/connect/mcp/tools/apps.js.map +1 -1
- package/dist/src/cli/connect/mcp/tools/core.d.ts +7 -0
- package/dist/src/cli/connect/mcp/tools/core.d.ts.map +1 -1
- package/dist/src/cli/connect/mcp/tools/core.js +83 -4
- package/dist/src/cli/connect/mcp/tools/core.js.map +1 -1
- package/dist/src/cli/connect/onboarding-prompt.js +1 -1
- package/dist/src/cli/connect/skill-bundle.js +1 -1
- package/dist/src/cli/connect/tool-call-defs-app-draft-edit.d.ts +21 -0
- package/dist/src/cli/connect/tool-call-defs-app-draft-edit.d.ts.map +1 -0
- package/dist/src/cli/connect/tool-call-defs-app-draft-edit.js +137 -0
- package/dist/src/cli/connect/tool-call-defs-app-draft-edit.js.map +1 -0
- package/dist/src/cli/connect/tool-call-defs-core.d.ts +1 -0
- package/dist/src/cli/connect/tool-call-defs-core.d.ts.map +1 -1
- package/dist/src/cli/connect/tool-call-defs-core.js +30 -0
- package/dist/src/cli/connect/tool-call-defs-core.js.map +1 -1
- package/dist/src/cli/connect/tool-call.d.ts.map +1 -1
- package/dist/src/cli/connect/tool-call.js +2 -0
- package/dist/src/cli/connect/tool-call.js.map +1 -1
- package/dist/src/config-types-ai.d.ts +76 -0
- package/dist/src/config-types-ai.d.ts.map +1 -0
- package/dist/src/config-types-ai.js +15 -0
- package/dist/src/config-types-ai.js.map +1 -0
- package/dist/src/config-types.d.ts +11 -2
- package/dist/src/config-types.d.ts.map +1 -1
- package/dist/src/config.d.ts.map +1 -1
- package/dist/src/config.js +25 -4
- package/dist/src/config.js.map +1 -1
- package/dist/src/data/builtin-skills.d.ts.map +1 -1
- package/dist/src/data/builtin-skills.js +3 -2
- package/dist/src/data/builtin-skills.js.map +1 -1
- package/dist/src/data/digital-signage-package.js +1 -1
- package/dist/src/data/library-packs/sdk.d.ts.map +1 -1
- package/dist/src/data/library-packs/sdk.js +76 -0
- package/dist/src/data/library-packs/sdk.js.map +1 -1
- package/dist/src/data/library-packs/vendored.d.ts.map +1 -1
- package/dist/src/data/library-packs/vendored.js +81 -0
- package/dist/src/data/library-packs/vendored.js.map +1 -1
- package/dist/src/data/library-packs.d.ts +2 -2
- package/dist/src/data/library-packs.js +2 -2
- package/dist/src/data/public-pages.d.ts +13 -0
- package/dist/src/data/public-pages.d.ts.map +1 -1
- package/dist/src/data/public-pages.js +153 -113
- package/dist/src/data/public-pages.js.map +1 -1
- package/dist/src/generated/api-types.d.ts +1652 -36
- package/dist/src/generated/api-types.d.ts.map +1 -1
- package/dist/src/index-start.d.ts.map +1 -1
- package/dist/src/index-start.js +3 -0
- package/dist/src/index-start.js.map +1 -1
- package/dist/src/mcp/agent-tasks.d.ts.map +1 -1
- package/dist/src/mcp/agent-tasks.js +5 -0
- package/dist/src/mcp/agent-tasks.js.map +1 -1
- package/dist/src/mcp/ai-image.d.ts +22 -0
- package/dist/src/mcp/ai-image.d.ts.map +1 -0
- package/dist/src/mcp/ai-image.js +60 -0
- package/dist/src/mcp/ai-image.js.map +1 -0
- package/dist/src/mcp/annotations.d.ts +5 -0
- package/dist/src/mcp/annotations.d.ts.map +1 -1
- package/dist/src/mcp/annotations.js +18 -0
- package/dist/src/mcp/annotations.js.map +1 -1
- package/dist/src/mcp/apps-draft-edit.d.ts +28 -0
- package/dist/src/mcp/apps-draft-edit.d.ts.map +1 -0
- package/dist/src/mcp/apps-draft-edit.js +164 -0
- package/dist/src/mcp/apps-draft-edit.js.map +1 -0
- package/dist/src/mcp/apps-screenshot.d.ts +26 -0
- package/dist/src/mcp/apps-screenshot.d.ts.map +1 -0
- package/dist/src/mcp/apps-screenshot.js +39 -0
- package/dist/src/mcp/apps-screenshot.js.map +1 -0
- package/dist/src/mcp/catalog/definitions/discovery-work-boards.d.ts +1 -0
- package/dist/src/mcp/catalog/definitions/discovery-work-boards.d.ts.map +1 -1
- package/dist/src/mcp/catalog/definitions/discovery-work-boards.js +40 -0
- package/dist/src/mcp/catalog/definitions/discovery-work-boards.js.map +1 -1
- package/dist/src/mcp/catalog/definitions/organisms-workspaces-apps.d.ts +3 -0
- package/dist/src/mcp/catalog/definitions/organisms-workspaces-apps.d.ts.map +1 -1
- package/dist/src/mcp/catalog/definitions/organisms-workspaces-apps.js +74 -0
- package/dist/src/mcp/catalog/definitions/organisms-workspaces-apps.js.map +1 -1
- package/dist/src/mcp/catalog/definitions/schedules-tasks-memory.d.ts.map +1 -1
- package/dist/src/mcp/catalog/definitions/schedules-tasks-memory.js +1 -0
- package/dist/src/mcp/catalog/definitions/schedules-tasks-memory.js.map +1 -1
- package/dist/src/mcp/catalog/scopes.d.ts.map +1 -1
- package/dist/src/mcp/catalog/scopes.js +19 -1
- package/dist/src/mcp/catalog/scopes.js.map +1 -1
- package/dist/src/mcp/catalog/surfaces.d.ts.map +1 -1
- package/dist/src/mcp/catalog/surfaces.js +18 -4
- package/dist/src/mcp/catalog/surfaces.js.map +1 -1
- package/dist/src/mcp/core-datapackage.d.ts +32 -0
- package/dist/src/mcp/core-datapackage.d.ts.map +1 -0
- package/dist/src/mcp/core-datapackage.js +188 -0
- package/dist/src/mcp/core-datapackage.js.map +1 -0
- package/dist/src/mcp/core-storage.d.ts +7 -3
- package/dist/src/mcp/core-storage.d.ts.map +1 -1
- package/dist/src/mcp/core-storage.js +27 -4
- package/dist/src/mcp/core-storage.js.map +1 -1
- package/dist/src/mcp/core.d.ts.map +1 -1
- package/dist/src/mcp/core.js +3 -0
- package/dist/src/mcp/core.js.map +1 -1
- package/dist/src/mcp/extensions.d.ts.map +1 -1
- package/dist/src/mcp/extensions.js +11 -1
- package/dist/src/mcp/extensions.js.map +1 -1
- package/dist/src/mcp/index.d.ts +9 -0
- package/dist/src/mcp/index.d.ts.map +1 -1
- package/dist/src/mcp/index.js +34 -0
- package/dist/src/mcp/index.js.map +1 -1
- package/dist/src/models/agent-task-schemas.d.ts.map +1 -1
- package/dist/src/models/agent-task-schemas.js +12 -1
- package/dist/src/models/agent-task-schemas.js.map +1 -1
- package/dist/src/models/workflow-schemas.d.ts +178 -1
- package/dist/src/models/workflow-schemas.d.ts.map +1 -1
- package/dist/src/models/workflow-schemas.js +75 -0
- package/dist/src/models/workflow-schemas.js.map +1 -1
- package/dist/src/routes/admin-extensions.d.ts +4 -0
- package/dist/src/routes/admin-extensions.d.ts.map +1 -1
- package/dist/src/routes/admin-extensions.js +135 -142
- package/dist/src/routes/admin-extensions.js.map +1 -1
- package/dist/src/routes/agent-conventions.d.ts.map +1 -1
- package/dist/src/routes/agent-conventions.js +4 -2
- package/dist/src/routes/agent-conventions.js.map +1 -1
- package/dist/src/routes/agent-docs.d.ts +4 -4
- package/dist/src/routes/agent-docs.js +145 -145
- package/dist/src/routes/agent-docs.js.map +1 -1
- package/dist/src/routes/agent-messages.d.ts +6 -0
- package/dist/src/routes/agent-messages.d.ts.map +1 -1
- package/dist/src/routes/agent-messages.js +23 -1
- package/dist/src/routes/agent-messages.js.map +1 -1
- package/dist/src/routes/agent-tasks/create-read.d.ts.map +1 -1
- package/dist/src/routes/agent-tasks/create-read.js +8 -1
- package/dist/src/routes/agent-tasks/create-read.js.map +1 -1
- package/dist/src/routes/agent-tasks/lifecycle.d.ts +4 -1
- package/dist/src/routes/agent-tasks/lifecycle.d.ts.map +1 -1
- package/dist/src/routes/agent-tasks/lifecycle.js +80 -2
- package/dist/src/routes/agent-tasks/lifecycle.js.map +1 -1
- package/dist/src/routes/ai.d.ts +5 -0
- package/dist/src/routes/ai.d.ts.map +1 -1
- package/dist/src/routes/ai.js +51 -1
- package/dist/src/routes/ai.js.map +1 -1
- package/dist/src/routes/app-grants.d.ts.map +1 -1
- package/dist/src/routes/app-grants.js +5 -0
- package/dist/src/routes/app-grants.js.map +1 -1
- package/dist/src/routes/apps/drafts.d.ts +6 -0
- package/dist/src/routes/apps/drafts.d.ts.map +1 -1
- package/dist/src/routes/apps/drafts.js +133 -1
- package/dist/src/routes/apps/drafts.js.map +1 -1
- package/dist/src/routes/apps/read.d.ts.map +1 -1
- package/dist/src/routes/apps/read.js +38 -1
- package/dist/src/routes/apps/read.js.map +1 -1
- package/dist/src/routes/auth-otk.d.ts +28 -0
- package/dist/src/routes/auth-otk.d.ts.map +1 -0
- package/dist/src/routes/auth-otk.js +190 -0
- package/dist/src/routes/auth-otk.js.map +1 -0
- package/dist/src/routes/auth.d.ts +17 -0
- package/dist/src/routes/auth.d.ts.map +1 -1
- package/dist/src/routes/auth.js +44 -153
- package/dist/src/routes/auth.js.map +1 -1
- package/dist/src/routes/bootstrap.d.ts +6 -0
- package/dist/src/routes/bootstrap.d.ts.map +1 -1
- package/dist/src/routes/bootstrap.js +47 -20
- package/dist/src/routes/bootstrap.js.map +1 -1
- package/dist/src/routes/chat.d.ts +23 -0
- package/dist/src/routes/chat.d.ts.map +1 -0
- package/dist/src/routes/chat.js +165 -0
- package/dist/src/routes/chat.js.map +1 -0
- package/dist/src/routes/commerce.js +4 -4
- package/dist/src/routes/commerce.js.map +1 -1
- package/dist/src/routes/datapackages.d.ts +35 -0
- package/dist/src/routes/datapackages.d.ts.map +1 -0
- package/dist/src/routes/datapackages.js +217 -0
- package/dist/src/routes/datapackages.js.map +1 -0
- package/dist/src/routes/disputes.d.ts +8 -0
- package/dist/src/routes/disputes.d.ts.map +1 -1
- package/dist/src/routes/disputes.js +52 -1
- package/dist/src/routes/disputes.js.map +1 -1
- package/dist/src/routes/ecosystem-apps-advisories.d.ts +16 -0
- package/dist/src/routes/ecosystem-apps-advisories.d.ts.map +1 -0
- package/dist/src/routes/ecosystem-apps-advisories.js +104 -0
- package/dist/src/routes/ecosystem-apps-advisories.js.map +1 -0
- package/dist/src/routes/ecosystem-apps.d.ts +6 -0
- package/dist/src/routes/ecosystem-apps.d.ts.map +1 -1
- package/dist/src/routes/ecosystem-apps.js +31 -99
- package/dist/src/routes/ecosystem-apps.js.map +1 -1
- package/dist/src/routes/extensions/actions.d.ts.map +1 -1
- package/dist/src/routes/extensions/actions.js +29 -1
- package/dist/src/routes/extensions/actions.js.map +1 -1
- package/dist/src/routes/federation-sync/routing.d.ts.map +1 -1
- package/dist/src/routes/federation-sync/routing.js +12 -3
- package/dist/src/routes/federation-sync/routing.js.map +1 -1
- package/dist/src/routes/glossary.js +1 -1
- package/dist/src/routes/glossary.js.map +1 -1
- package/dist/src/routes/home/track.d.ts +5 -1
- package/dist/src/routes/home/track.d.ts.map +1 -1
- package/dist/src/routes/home/track.js +20 -6
- package/dist/src/routes/home/track.js.map +1 -1
- package/dist/src/routes/instances/install.d.ts +3 -0
- package/dist/src/routes/instances/install.d.ts.map +1 -1
- package/dist/src/routes/instances/install.js +17 -24
- package/dist/src/routes/instances/install.js.map +1 -1
- package/dist/src/routes/libs.js +1 -1
- package/dist/src/routes/libs.js.map +1 -1
- package/dist/src/routes/markdown-mirrors.js +1 -1
- package/dist/src/routes/markdown-mirrors.js.map +1 -1
- package/dist/src/routes/odata.d.ts +36 -0
- package/dist/src/routes/odata.d.ts.map +1 -0
- package/dist/src/routes/odata.js +143 -0
- package/dist/src/routes/odata.js.map +1 -0
- package/dist/src/routes/openrouter.d.ts +4 -0
- package/dist/src/routes/openrouter.d.ts.map +1 -1
- package/dist/src/routes/openrouter.js +10 -1
- package/dist/src/routes/openrouter.js.map +1 -1
- package/dist/src/routes/organisms/gates.d.ts.map +1 -1
- package/dist/src/routes/organisms/gates.js +9 -2
- package/dist/src/routes/organisms/gates.js.map +1 -1
- package/dist/src/routes/portal.d.ts +1 -0
- package/dist/src/routes/portal.d.ts.map +1 -1
- package/dist/src/routes/portal.js +13 -0
- package/dist/src/routes/portal.js.map +1 -1
- package/dist/src/routes/schedules.d.ts +4 -0
- package/dist/src/routes/schedules.d.ts.map +1 -1
- package/dist/src/routes/schedules.js +9 -1
- package/dist/src/routes/schedules.js.map +1 -1
- package/dist/src/routes/storage-files.d.ts +23 -0
- package/dist/src/routes/storage-files.d.ts.map +1 -1
- package/dist/src/routes/storage-files.js +103 -82
- package/dist/src/routes/storage-files.js.map +1 -1
- package/dist/src/routes/workflows.d.ts.map +1 -1
- package/dist/src/routes/workflows.js +9 -1
- package/dist/src/routes/workflows.js.map +1 -1
- package/dist/src/server-bootstrap/routes-loader.d.ts +2 -0
- package/dist/src/server-bootstrap/routes-loader.d.ts.map +1 -1
- package/dist/src/server-bootstrap/routes-loader.js +20 -2
- package/dist/src/server-bootstrap/routes-loader.js.map +1 -1
- package/dist/src/server-bootstrap/service-init.d.ts.map +1 -1
- package/dist/src/server-bootstrap/service-init.js +12 -7
- package/dist/src/server-bootstrap/service-init.js.map +1 -1
- package/dist/src/server-bootstrap/static-files.d.ts.map +1 -1
- package/dist/src/server-bootstrap/static-files.js +44 -10
- package/dist/src/server-bootstrap/static-files.js.map +1 -1
- package/dist/src/services/ai-allowance.d.ts +82 -0
- package/dist/src/services/ai-allowance.d.ts.map +1 -0
- package/dist/src/services/ai-allowance.js +117 -0
- package/dist/src/services/ai-allowance.js.map +1 -0
- package/dist/src/services/ai-completion.d.ts +26 -0
- package/dist/src/services/ai-completion.d.ts.map +1 -1
- package/dist/src/services/ai-completion.js +41 -13
- package/dist/src/services/ai-completion.js.map +1 -1
- package/dist/src/services/ai-image.d.ts +70 -0
- package/dist/src/services/ai-image.d.ts.map +1 -0
- package/dist/src/services/ai-image.js +104 -0
- package/dist/src/services/ai-image.js.map +1 -0
- package/dist/src/services/ai-model-defaults.d.ts +45 -0
- package/dist/src/services/ai-model-defaults.d.ts.map +1 -0
- package/dist/src/services/ai-model-defaults.js +42 -0
- package/dist/src/services/ai-model-defaults.js.map +1 -0
- package/dist/src/services/ai-tool-setup.d.ts +5 -1
- package/dist/src/services/ai-tool-setup.d.ts.map +1 -1
- package/dist/src/services/ai-tool-setup.js +36 -0
- package/dist/src/services/ai-tool-setup.js.map +1 -1
- package/dist/src/services/ai-transcription.d.ts +5 -0
- package/dist/src/services/ai-transcription.d.ts.map +1 -1
- package/dist/src/services/ai-transcription.js +5 -2
- package/dist/src/services/ai-transcription.js.map +1 -1
- package/dist/src/services/app-agent-surfaces.js +4 -4
- package/dist/src/services/app-agent-surfaces.js.map +1 -1
- package/dist/src/services/app-draft-edit.d.ts +144 -0
- package/dist/src/services/app-draft-edit.d.ts.map +1 -0
- package/dist/src/services/app-draft-edit.js +203 -0
- package/dist/src/services/app-draft-edit.js.map +1 -0
- package/dist/src/services/auth-md.js +2 -2
- package/dist/src/services/auth-md.js.map +1 -1
- package/dist/src/services/board-write.d.ts +11 -3
- package/dist/src/services/board-write.d.ts.map +1 -1
- package/dist/src/services/board-write.js +24 -3
- package/dist/src/services/board-write.js.map +1 -1
- package/dist/src/services/chat-agent.d.ts +36 -0
- package/dist/src/services/chat-agent.d.ts.map +1 -0
- package/dist/src/services/chat-agent.js +123 -0
- package/dist/src/services/chat-agent.js.map +1 -0
- package/dist/src/services/chat-session.d.ts +58 -0
- package/dist/src/services/chat-session.d.ts.map +1 -0
- package/dist/src/services/chat-session.js +151 -0
- package/dist/src/services/chat-session.js.map +1 -0
- package/dist/src/services/chat-threads.d.ts +61 -0
- package/dist/src/services/chat-threads.d.ts.map +1 -0
- package/dist/src/services/chat-threads.js +137 -0
- package/dist/src/services/chat-threads.js.map +1 -0
- package/dist/src/services/config-schema.d.ts.map +1 -1
- package/dist/src/services/config-schema.js +2 -1
- package/dist/src/services/config-schema.js.map +1 -1
- package/dist/src/services/datapackage/contract.d.ts +198 -0
- package/dist/src/services/datapackage/contract.d.ts.map +1 -0
- package/dist/src/services/datapackage/contract.js +140 -0
- package/dist/src/services/datapackage/contract.js.map +1 -0
- package/dist/src/services/datapackage/ext-capability.d.ts +85 -0
- package/dist/src/services/datapackage/ext-capability.d.ts.map +1 -0
- package/dist/src/services/datapackage/ext-capability.js +72 -0
- package/dist/src/services/datapackage/ext-capability.js.map +1 -0
- package/dist/src/services/datapackage/odata.d.ts +92 -0
- package/dist/src/services/datapackage/odata.d.ts.map +1 -0
- package/dist/src/services/datapackage/odata.js +256 -0
- package/dist/src/services/datapackage/odata.js.map +1 -0
- package/dist/src/services/datapackage/odps.d.ts +24 -0
- package/dist/src/services/datapackage/odps.d.ts.map +1 -0
- package/dist/src/services/datapackage/odps.js +183 -0
- package/dist/src/services/datapackage/odps.js.map +1 -0
- package/dist/src/services/datapackage/store.d.ts +143 -0
- package/dist/src/services/datapackage/store.d.ts.map +1 -0
- package/dist/src/services/datapackage/store.js +533 -0
- package/dist/src/services/datapackage/store.js.map +1 -0
- package/dist/src/services/datapackage/table.d.ts +67 -0
- package/dist/src/services/datapackage/table.d.ts.map +1 -0
- package/dist/src/services/datapackage/table.js +0 -0
- package/dist/src/services/datapackage/table.js.map +1 -0
- package/dist/src/services/extension-ctx.d.ts +1 -0
- package/dist/src/services/extension-ctx.d.ts.map +1 -1
- package/dist/src/services/extension-ctx.js +31 -6
- package/dist/src/services/extension-ctx.js.map +1 -1
- package/dist/src/services/extension-files.d.ts +20 -0
- package/dist/src/services/extension-files.d.ts.map +1 -1
- package/dist/src/services/extension-files.js +9 -2
- package/dist/src/services/extension-files.js.map +1 -1
- package/dist/src/services/extension-lifecycle.d.ts +3 -0
- package/dist/src/services/extension-lifecycle.d.ts.map +1 -1
- package/dist/src/services/extension-lifecycle.js +2 -26
- package/dist/src/services/extension-lifecycle.js.map +1 -1
- package/dist/src/services/extension-runtime.d.ts +28 -2
- package/dist/src/services/extension-runtime.d.ts.map +1 -1
- package/dist/src/services/extension-runtime.js +22 -0
- package/dist/src/services/extension-runtime.js.map +1 -1
- package/dist/src/services/extension-schedules.d.ts +90 -0
- package/dist/src/services/extension-schedules.d.ts.map +1 -0
- package/dist/src/services/extension-schedules.js +123 -0
- package/dist/src/services/extension-schedules.js.map +1 -0
- package/dist/src/services/extension-system-run.d.ts +91 -0
- package/dist/src/services/extension-system-run.d.ts.map +1 -0
- package/dist/src/services/extension-system-run.js +100 -0
- package/dist/src/services/extension-system-run.js.map +1 -0
- package/dist/src/services/extension-upsert.d.ts +2 -0
- package/dist/src/services/extension-upsert.d.ts.map +1 -1
- package/dist/src/services/extension-upsert.js +6 -24
- package/dist/src/services/extension-upsert.js.map +1 -1
- package/dist/src/services/goose-acp.d.ts +84 -0
- package/dist/src/services/goose-acp.d.ts.map +1 -0
- package/dist/src/services/goose-acp.js +304 -0
- package/dist/src/services/goose-acp.js.map +1 -0
- package/dist/src/services/markdown-negotiation.js +1 -1
- package/dist/src/services/markdown-negotiation.js.map +1 -1
- package/dist/src/services/openrouter.d.ts +20 -1
- package/dist/src/services/openrouter.d.ts.map +1 -1
- package/dist/src/services/openrouter.js +66 -0
- package/dist/src/services/openrouter.js.map +1 -1
- package/dist/src/services/prompt-defaults/tiers-core.js +4 -4
- package/dist/src/services/scheduler-extension-job.d.ts +29 -6
- package/dist/src/services/scheduler-extension-job.d.ts.map +1 -1
- package/dist/src/services/scheduler-extension-job.js +29 -75
- package/dist/src/services/scheduler-extension-job.js.map +1 -1
- package/dist/src/services/scope-vocabulary-migration.d.ts +34 -1
- package/dist/src/services/scope-vocabulary-migration.d.ts.map +1 -1
- package/dist/src/services/scope-vocabulary-migration.js +60 -0
- package/dist/src/services/scope-vocabulary-migration.js.map +1 -1
- package/dist/src/services/screenshot-capture.d.ts +40 -1
- package/dist/src/services/screenshot-capture.d.ts.map +1 -1
- package/dist/src/services/screenshot-capture.js +142 -60
- package/dist/src/services/screenshot-capture.js.map +1 -1
- package/dist/src/services/skill-bundle/generator.js +1 -1
- package/dist/src/services/skill-bundle/generic-adapter.js +1 -1
- package/dist/src/services/skill-bundle/hermes-adapter.js +1 -1
- package/dist/src/services/storage-file-write.d.ts +36 -1
- package/dist/src/services/storage-file-write.d.ts.map +1 -1
- package/dist/src/services/storage-file-write.js +49 -3
- package/dist/src/services/storage-file-write.js.map +1 -1
- package/dist/src/services/task-outcome.d.ts +53 -0
- package/dist/src/services/task-outcome.d.ts.map +1 -0
- package/dist/src/services/task-outcome.js +28 -0
- package/dist/src/services/task-outcome.js.map +1 -0
- package/dist/src/services/workflow/engine-human.d.ts +15 -0
- package/dist/src/services/workflow/engine-human.d.ts.map +1 -1
- package/dist/src/services/workflow/engine-human.js +10 -1
- package/dist/src/services/workflow/engine-human.js.map +1 -1
- package/dist/src/services/workflow/engine-steps.d.ts +48 -3
- package/dist/src/services/workflow/engine-steps.d.ts.map +1 -1
- package/dist/src/services/workflow/engine-steps.js +361 -0
- package/dist/src/services/workflow/engine-steps.js.map +1 -1
- package/dist/src/services/workflow/engine.d.ts +1 -0
- package/dist/src/services/workflow/engine.d.ts.map +1 -1
- package/dist/src/services/workflow/engine.js +2 -1
- package/dist/src/services/workflow/engine.js.map +1 -1
- package/dist/src/services/workflow/store.d.ts.map +1 -1
- package/dist/src/services/workflow/store.js +60 -4
- package/dist/src/services/workflow/store.js.map +1 -1
- package/dist/src/services/write-guards.d.ts +27 -1
- package/dist/src/services/write-guards.d.ts.map +1 -1
- package/dist/src/services/write-guards.js +39 -9
- package/dist/src/services/write-guards.js.map +1 -1
- package/dist/src/storage/providers/postgres-kysely/db-types.d.ts +1 -0
- package/dist/src/storage/providers/postgres-kysely/db-types.d.ts.map +1 -1
- package/dist/src/storage/providers/postgres-kysely/methods/app-grants.d.ts +1 -0
- package/dist/src/storage/providers/postgres-kysely/methods/app-grants.d.ts.map +1 -1
- package/dist/src/storage/providers/postgres-kysely/methods/app-grants.js +3 -0
- package/dist/src/storage/providers/postgres-kysely/methods/app-grants.js.map +1 -1
- package/dist/src/storage/providers/postgres-kysely/methods/files.d.ts +2 -0
- package/dist/src/storage/providers/postgres-kysely/methods/files.d.ts.map +1 -1
- package/dist/src/storage/providers/postgres-kysely/methods/files.js +34 -2
- package/dist/src/storage/providers/postgres-kysely/methods/files.js.map +1 -1
- package/dist/src/storage/providers/postgres-kysely/migrations/0039_storage_file_utf8_verified.sql +19 -0
- package/dist/src/storage/providers/sqlite/index.d.ts.map +1 -1
- package/dist/src/storage/providers/sqlite/index.js +2 -1
- package/dist/src/storage/providers/sqlite/index.js.map +1 -1
- package/dist/src/storage/providers/sqlite/methods/apps.d.ts +1 -0
- package/dist/src/storage/providers/sqlite/methods/apps.d.ts.map +1 -1
- package/dist/src/storage/providers/sqlite/methods/apps.js +33 -28
- package/dist/src/storage/providers/sqlite/methods/apps.js.map +1 -1
- package/dist/src/storage/providers/sqlite/methods/identity-nodes.d.ts +1 -12
- package/dist/src/storage/providers/sqlite/methods/identity-nodes.d.ts.map +1 -1
- package/dist/src/storage/providers/sqlite/methods/identity-nodes.js +28 -135
- package/dist/src/storage/providers/sqlite/methods/identity-nodes.js.map +1 -1
- package/dist/src/storage/providers/sqlite/methods/storage-files.d.ts +38 -0
- package/dist/src/storage/providers/sqlite/methods/storage-files.d.ts.map +1 -0
- package/dist/src/storage/providers/sqlite/methods/storage-files.js +109 -0
- package/dist/src/storage/providers/sqlite/methods/storage-files.js.map +1 -0
- package/dist/src/storage/providers/sqlite/schema.d.ts.map +1 -1
- package/dist/src/storage/providers/sqlite/schema.js +134 -130
- package/dist/src/storage/providers/sqlite/schema.js.map +1 -1
- package/dist/src/storage/repositories/app-grant.repository.d.ts +11 -0
- package/dist/src/storage/repositories/app-grant.repository.d.ts.map +1 -1
- package/dist/src/storage/repositories/file.repository.d.ts +13 -0
- package/dist/src/storage/repositories/file.repository.d.ts.map +1 -1
- package/dist/src/storage/types/commerce.d.ts +6 -0
- package/dist/src/storage/types/commerce.d.ts.map +1 -1
- package/dist/src/utils/agent-footer.d.ts.map +1 -1
- package/dist/src/utils/agent-footer.js +1 -0
- package/dist/src/utils/agent-footer.js.map +1 -1
- package/dist/src/utils/app-content-type.d.ts +57 -3
- package/dist/src/utils/app-content-type.d.ts.map +1 -1
- package/dist/src/utils/app-content-type.js +81 -12
- package/dist/src/utils/app-content-type.js.map +1 -1
- package/dist/src/utils/env-config/sections-features.d.ts.map +1 -1
- package/dist/src/utils/env-config/sections-features.js +9 -3
- package/dist/src/utils/env-config/sections-features.js.map +1 -1
- package/dist/src/utils/file-download-headers.d.ts +5 -3
- package/dist/src/utils/file-download-headers.d.ts.map +1 -1
- package/dist/src/utils/file-download-headers.js +18 -5
- package/dist/src/utils/file-download-headers.js.map +1 -1
- package/dist/src/utils/http-range.d.ts +151 -0
- package/dist/src/utils/http-range.d.ts.map +1 -0
- package/dist/src/utils/http-range.js +190 -0
- package/dist/src/utils/http-range.js.map +1 -0
- package/dist/src/utils/page-head.d.ts +5 -0
- package/dist/src/utils/page-head.d.ts.map +1 -1
- package/dist/src/utils/page-head.js +10 -1
- package/dist/src/utils/page-head.js.map +1 -1
- package/dist/src/utils/reserved-keys.d.ts +4 -1
- package/dist/src/utils/reserved-keys.d.ts.map +1 -1
- package/dist/src/utils/reserved-keys.js +4 -1
- package/dist/src/utils/reserved-keys.js.map +1 -1
- package/dist/static/sdk-libs/datapackage/index.js +336 -0
- package/dist/static/sdk-libs/dist/aimeat-datapackage.js +305 -0
- package/package.json +10 -2
|
@@ -1,85 +1,39 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { buildExtensionCtx, buildExtensionNotify, buildExtensionEmail } from './extension-ctx.js';
|
|
3
|
-
import { getEncryptionKey } from './encryption.js';
|
|
4
|
-
import { getExtSecretKeys, getInstanceSecretKeys, decryptSecretFields } from './extension-secrets.js';
|
|
1
|
+
import { runExtensionActionAsSystem } from './extension-system-run.js';
|
|
5
2
|
/**
|
|
6
|
-
* Execute a scheduled `extension` job
|
|
7
|
-
*
|
|
8
|
-
*
|
|
3
|
+
* Execute a scheduled `extension` job and return the tracked memory reads/writes for the run log.
|
|
4
|
+
*
|
|
5
|
+
* Every refusal throws: the scheduler records a thrown error as `lastRunResult: 'error'`, leaves the
|
|
6
|
+
* run count alone and notifies the owner, while any normal return is recorded as a successful run.
|
|
9
7
|
*/
|
|
10
8
|
export async function runExtensionJob(storage, config, emailService, job) {
|
|
11
9
|
if (!job.extensionName || !job.actionId) {
|
|
12
10
|
throw new Error(`Extension job "${job.id}" missing extensionName or actionId`);
|
|
13
11
|
}
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
12
|
+
// A schedule's `ownerScope` is the owner GHII; an extension record carries the BARE installer name
|
|
13
|
+
// (routes/extensions/crud.ts writes `req.auth!.owner` into it). Both forms are needed: the owner
|
|
14
|
+
// fence compares bare names, storage is addressed by GHII. Falling back to the extension record's
|
|
15
|
+
// own installer would make the fence compare a value against itself, so it is not done.
|
|
16
|
+
const ownerScope = job.ownerScope ?? '';
|
|
17
|
+
const ownerName = ownerScope.split('@')[0];
|
|
18
|
+
if (!ownerName) {
|
|
19
|
+
throw new Error(`Extension job "${job.id}" has no owner scope — reinstall or reactivate extension "${job.extensionName}" to re-register it`);
|
|
17
20
|
}
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
:
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
let instanceCtx;
|
|
34
|
-
if (job.instanceId) {
|
|
35
|
-
const inst = await storage.getExtensionInstance(ext.name, job.instanceId);
|
|
36
|
-
instanceCtx = {
|
|
37
|
-
id: job.instanceId,
|
|
38
|
-
config: inst
|
|
39
|
-
? decryptSecretFields(inst.config, getInstanceSecretKeys(ext), encKey)
|
|
40
|
-
: (job.input ?? {}),
|
|
41
|
-
};
|
|
42
|
-
}
|
|
43
|
-
// One builder, so this road cannot be the one that forgets a guard again. It was: until
|
|
44
|
-
// 2026-08-10 the scheduled path wrote memory without the size and key-count limits, and fetched
|
|
45
|
-
// with a bare fetch rather than safeFetch, so an extension running on a clock had neither the
|
|
46
|
-
// storage ceiling nor the SSRF check that the same extension had when a person invoked it.
|
|
47
|
-
const baseCtx = buildExtensionCtx({
|
|
48
|
-
config,
|
|
49
|
-
storage,
|
|
50
|
-
extMemoryOwner,
|
|
51
|
-
// Scheduled runs have no human present. The installer is the responsible party, and the
|
|
52
|
-
// 'operator' role is what the sandbox reads to decide it is a system run.
|
|
53
|
-
caller: {
|
|
54
|
-
gaii: `scheduler@${config.nodeId}`,
|
|
55
|
-
owner: ext.installedBy,
|
|
56
|
-
roles: ['operator'],
|
|
57
|
-
},
|
|
58
|
-
extConfig: decryptSecretFields(ext.config, getExtSecretKeys(ext), encKey),
|
|
59
|
-
instance: instanceCtx,
|
|
60
|
-
logPrefix: `[ext:${ext.name}:scheduler]`,
|
|
61
|
-
// No wallet: nobody's balance is available to spend on a schedule.
|
|
62
|
-
notify: buildExtensionNotify({
|
|
63
|
-
storage, config, extName: ext.name,
|
|
64
|
-
recipientGaii: ext.installedBy, recipientOwner: ext.installedBy,
|
|
65
|
-
}),
|
|
66
|
-
email: buildExtensionEmail({
|
|
67
|
-
storage, config, extName: ext.name, extConfig: ext.config,
|
|
68
|
-
ownerName: ext.installedBy, emailService,
|
|
69
|
-
}),
|
|
21
|
+
const ownerGhii = ownerScope.includes('@') ? ownerScope : `${ownerName}@${config.nodeId}`;
|
|
22
|
+
const out = await runExtensionActionAsSystem({ storage, config, emailService }, {
|
|
23
|
+
extensionName: job.extensionName,
|
|
24
|
+
actionId: job.actionId,
|
|
25
|
+
instanceId: job.instanceId,
|
|
26
|
+
input: job.input,
|
|
27
|
+
// Nobody is present, and the scheduler says so rather than borrowing the owner's name for it.
|
|
28
|
+
callerGaii: `scheduler@${config.nodeId}`,
|
|
29
|
+
ownerName,
|
|
30
|
+
storageOwnerGhii: ownerGhii,
|
|
31
|
+
logLabel: 'scheduler',
|
|
32
|
+
producerKind: 'extension',
|
|
33
|
+
producerRef: job.id,
|
|
34
|
+
producerSchedule: job.cron,
|
|
35
|
+
trackMemory: true,
|
|
70
36
|
});
|
|
71
|
-
|
|
72
|
-
const { ctx, accessLog } = trackMemoryAccess(baseCtx);
|
|
73
|
-
// Validate input is a plain object — reject non-serializable values
|
|
74
|
-
const rawInput = job.input ?? {};
|
|
75
|
-
let input;
|
|
76
|
-
try {
|
|
77
|
-
input = JSON.parse(JSON.stringify(rawInput));
|
|
78
|
-
}
|
|
79
|
-
catch {
|
|
80
|
-
throw new Error(`Scheduled job "${job.id}" has non-serializable input`);
|
|
81
|
-
}
|
|
82
|
-
await executeExtensionAction(action.scriptContent, ctx, input, ext.limits);
|
|
83
|
-
return { reads: accessLog.reads, writes: accessLog.writes };
|
|
37
|
+
return { reads: out.reads, writes: out.writes };
|
|
84
38
|
}
|
|
85
39
|
//# sourceMappingURL=scheduler-extension-job.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scheduler-extension-job.js","sourceRoot":"","sources":["../../../src/services/scheduler-extension-job.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"scheduler-extension-job.js","sourceRoot":"","sources":["../../../src/services/scheduler-extension-job.ts"],"names":[],"mappings":"AAmCA,OAAO,EAAE,0BAA0B,EAAE,MAAM,2BAA2B,CAAC;AAGvE;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,OAAgB,EAChB,MAAoB,EACpB,YAAsC,EACtC,GAAuB;IAEvB,IAAI,CAAC,GAAG,CAAC,aAAa,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC;QACxC,MAAM,IAAI,KAAK,CAAC,kBAAkB,GAAG,CAAC,EAAE,qCAAqC,CAAC,CAAC;IACjF,CAAC;IAED,mGAAmG;IACnG,iGAAiG;IACjG,kGAAkG;IAClG,wFAAwF;IACxF,MAAM,UAAU,GAAG,GAAG,CAAC,UAAU,IAAI,EAAE,CAAC;IACxC,MAAM,SAAS,GAAG,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IAC3C,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,kBAAkB,GAAG,CAAC,EAAE,6DAA6D,GAAG,CAAC,aAAa,qBAAqB,CAAC,CAAC;IAC/I,CAAC;IACD,MAAM,SAAS,GAAG,UAAU,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,SAAS,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;IAE1F,MAAM,GAAG,GAAG,MAAM,0BAA0B,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,EAAE;QAC9E,aAAa,EAAE,GAAG,CAAC,aAAa;QAChC,QAAQ,EAAE,GAAG,CAAC,QAAQ;QACtB,UAAU,EAAE,GAAG,CAAC,UAAU;QAC1B,KAAK,EAAE,GAAG,CAAC,KAAK;QAChB,8FAA8F;QAC9F,UAAU,EAAE,aAAa,MAAM,CAAC,MAAM,EAAE;QACxC,SAAS;QACT,gBAAgB,EAAE,SAAS;QAC3B,QAAQ,EAAE,WAAW;QACrB,YAAY,EAAE,WAAW;QACzB,WAAW,EAAE,GAAG,CAAC,EAAE;QACnB,gBAAgB,EAAE,GAAG,CAAC,IAAI;QAC1B,WAAW,EAAE,IAAI;KAClB,CAAC,CAAC;IACH,OAAO,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,CAAC;AAClD,CAAC"}
|
|
@@ -72,7 +72,7 @@ import type { Storage } from '../storage/interface.js';
|
|
|
72
72
|
* NO conditional entry for it below — a conditional grant would be dead code here, because this list
|
|
73
73
|
* hands the word to every agent with a recorded scope list and `*` covers it at the door.
|
|
74
74
|
*/
|
|
75
|
-
export declare const GRANDFATHERED_SCOPES: readonly ["agent:write", "app:write", "app:manage", "capability:write", "ext:invoke", "organism:write", "organism:invite"];
|
|
75
|
+
export declare const GRANDFATHERED_SCOPES: readonly ["agent:write", "app:write", "app:manage", "capability:write", "ext:invoke", "organism:write", "organism:invite", "packages:write"];
|
|
76
76
|
/**
|
|
77
77
|
* Words granted only to agents that ALREADY hold the word they are replacing.
|
|
78
78
|
*
|
|
@@ -94,4 +94,37 @@ export declare const CONDITIONAL_SCOPES: ReadonlyArray<{
|
|
|
94
94
|
* nothing to do. Returns the number of agents actually updated, for the boot log.
|
|
95
95
|
*/
|
|
96
96
|
export declare function migrateAgentScopeVocabulary(storage: Storage): Promise<number>;
|
|
97
|
+
/**
|
|
98
|
+
* The same grandfathering, for the OTHER principal family a new permission word can refuse.
|
|
99
|
+
*
|
|
100
|
+
* `requireScope` waves an owner session through and deliberately does NOT wave an app grant through
|
|
101
|
+
* — it is the only middleware that stops one, which is exactly why tightening a route to a new word
|
|
102
|
+
* is the shape that broke a live app in changelog 1.33.1 and is why H-20 was reverted. Everything
|
|
103
|
+
* above was written for agents and stopped there, so for five days the node had a mechanism that
|
|
104
|
+
* made a new word safe for one family and left the family the word actually bites uncovered.
|
|
105
|
+
*
|
|
106
|
+
* A grant carries what its owner approved on the consent screen at the time it was made, and an app
|
|
107
|
+
* gains nothing from being updated. So a word added to the vocabulary today would refuse every grant
|
|
108
|
+
* approved before it existed — for an act the app was already performing, through a door that asked
|
|
109
|
+
* nothing. Writing the word onto those grants preserves the reach they have; it does not hand an app
|
|
110
|
+
* a permission it never had, because the door it names was open to them a moment ago.
|
|
111
|
+
*
|
|
112
|
+
* The rule for a NEW grant is unchanged and is where the word does its work: the consent screen
|
|
113
|
+
* lists it, the owner sees it, and they can uncheck it.
|
|
114
|
+
*
|
|
115
|
+
* Conditional words are not applied here. Their `when` is a question about what an owner granted a
|
|
116
|
+
* particular agent, and an app grant's scope list is a different conversation with a different
|
|
117
|
+
* screen; the two should not be reasoned about with one table until someone decides they mean the
|
|
118
|
+
* same thing.
|
|
119
|
+
*/
|
|
120
|
+
export declare function migrateAppGrantScopeVocabulary(storage: Storage): Promise<number>;
|
|
121
|
+
/**
|
|
122
|
+
* Both families, one call. The boot path takes this rather than either half, so a word added to
|
|
123
|
+
* GRANDFATHERED_SCOPES cannot reach one principal family and miss the other — which is the failure
|
|
124
|
+
* this pair exists to prevent, and which it had itself.
|
|
125
|
+
*/
|
|
126
|
+
export declare function migrateScopeVocabulary(storage: Storage): Promise<{
|
|
127
|
+
agents: number;
|
|
128
|
+
appGrants: number;
|
|
129
|
+
}>;
|
|
97
130
|
//# sourceMappingURL=scope-vocabulary-migration.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scope-vocabulary-migration.d.ts","sourceRoot":"","sources":["../../../src/services/scope-vocabulary-migration.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmDG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAIvD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,oBAAoB,
|
|
1
|
+
{"version":3,"file":"scope-vocabulary-migration.d.ts","sourceRoot":"","sources":["../../../src/services/scope-vocabulary-migration.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmDG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAIvD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,oBAAoB,8IAavB,CAAC;AAEX;;;;;;;;;;GAUG;AACH,eAAO,MAAM,kBAAkB,EAAE,aAAa,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAc1F,CAAC;AAEF;;;GAGG;AACH,wBAAsB,2BAA2B,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CA0DnF;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAsB,8BAA8B,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAoBtF;AAED;;;;GAIG;AACH,wBAAsB,sBAAsB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC,CAK7G"}
|
|
@@ -29,6 +29,11 @@ export const GRANDFATHERED_SCOPES = [
|
|
|
29
29
|
'ext:invoke',
|
|
30
30
|
'organism:write',
|
|
31
31
|
'organism:invite',
|
|
32
|
+
// Added 2026-08-15 with the door that now demands it (routes/instances/install.ts). Installing a
|
|
33
|
+
// package asked for nothing before, so every principal that could reach the route could install;
|
|
34
|
+
// the word describes what was already happening rather than granting anything new, which is the
|
|
35
|
+
// only condition under which a word belongs on this list.
|
|
36
|
+
'packages:write',
|
|
32
37
|
];
|
|
33
38
|
/**
|
|
34
39
|
* Words granted only to agents that ALREADY hold the word they are replacing.
|
|
@@ -119,4 +124,59 @@ export async function migrateAgentScopeVocabulary(storage) {
|
|
|
119
124
|
}
|
|
120
125
|
return changed;
|
|
121
126
|
}
|
|
127
|
+
/**
|
|
128
|
+
* The same grandfathering, for the OTHER principal family a new permission word can refuse.
|
|
129
|
+
*
|
|
130
|
+
* `requireScope` waves an owner session through and deliberately does NOT wave an app grant through
|
|
131
|
+
* — it is the only middleware that stops one, which is exactly why tightening a route to a new word
|
|
132
|
+
* is the shape that broke a live app in changelog 1.33.1 and is why H-20 was reverted. Everything
|
|
133
|
+
* above was written for agents and stopped there, so for five days the node had a mechanism that
|
|
134
|
+
* made a new word safe for one family and left the family the word actually bites uncovered.
|
|
135
|
+
*
|
|
136
|
+
* A grant carries what its owner approved on the consent screen at the time it was made, and an app
|
|
137
|
+
* gains nothing from being updated. So a word added to the vocabulary today would refuse every grant
|
|
138
|
+
* approved before it existed — for an act the app was already performing, through a door that asked
|
|
139
|
+
* nothing. Writing the word onto those grants preserves the reach they have; it does not hand an app
|
|
140
|
+
* a permission it never had, because the door it names was open to them a moment ago.
|
|
141
|
+
*
|
|
142
|
+
* The rule for a NEW grant is unchanged and is where the word does its work: the consent screen
|
|
143
|
+
* lists it, the owner sees it, and they can uncheck it.
|
|
144
|
+
*
|
|
145
|
+
* Conditional words are not applied here. Their `when` is a question about what an owner granted a
|
|
146
|
+
* particular agent, and an app grant's scope list is a different conversation with a different
|
|
147
|
+
* screen; the two should not be reasoned about with one table until someone decides they mean the
|
|
148
|
+
* same thing.
|
|
149
|
+
*/
|
|
150
|
+
export async function migrateAppGrantScopeVocabulary(storage) {
|
|
151
|
+
const grants = await storage.listAppGrants();
|
|
152
|
+
let changed = 0;
|
|
153
|
+
for (const grant of grants) {
|
|
154
|
+
const held = grant.scopes;
|
|
155
|
+
if (!Array.isArray(held) || held.includes('*'))
|
|
156
|
+
continue;
|
|
157
|
+
const missing = GRANDFATHERED_SCOPES.filter(s => !held.includes(s));
|
|
158
|
+
if (!missing.length)
|
|
159
|
+
continue;
|
|
160
|
+
await storage.updateAppGrant(grant.grantId, { scopes: [...held, ...missing] });
|
|
161
|
+
changed++;
|
|
162
|
+
}
|
|
163
|
+
if (changed) {
|
|
164
|
+
logger.info('Scope vocabulary migration: live app grants grandfathered onto the new words', {
|
|
165
|
+
grantsUpdated: changed,
|
|
166
|
+
scopes: GRANDFATHERED_SCOPES.join(', '),
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
return changed;
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Both families, one call. The boot path takes this rather than either half, so a word added to
|
|
173
|
+
* GRANDFATHERED_SCOPES cannot reach one principal family and miss the other — which is the failure
|
|
174
|
+
* this pair exists to prevent, and which it had itself.
|
|
175
|
+
*/
|
|
176
|
+
export async function migrateScopeVocabulary(storage) {
|
|
177
|
+
return {
|
|
178
|
+
agents: await migrateAgentScopeVocabulary(storage),
|
|
179
|
+
appGrants: await migrateAppGrantScopeVocabulary(storage),
|
|
180
|
+
};
|
|
181
|
+
}
|
|
122
182
|
//# sourceMappingURL=scope-vocabulary-migration.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scope-vocabulary-migration.js","sourceRoot":"","sources":["../../../src/services/scope-vocabulary-migration.ts"],"names":[],"mappings":"AAqDA,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAC5C,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAE5D;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG;IAChC,aAAa;IACb,WAAW;IACX,YAAY;IACZ,kBAAkB;IAClB,YAAY;IACZ,gBAAgB;IAChB,iBAAiB;
|
|
1
|
+
{"version":3,"file":"scope-vocabulary-migration.js","sourceRoot":"","sources":["../../../src/services/scope-vocabulary-migration.ts"],"names":[],"mappings":"AAqDA,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAC5C,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAE5D;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG;IAChC,aAAa;IACb,WAAW;IACX,YAAY;IACZ,kBAAkB;IAClB,YAAY;IACZ,gBAAgB;IAChB,iBAAiB;IACjB,iGAAiG;IACjG,iGAAiG;IACjG,gGAAgG;IAChG,0DAA0D;IAC1D,gBAAgB;CACV,CAAC;AAEX;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAgE;IAC3F;QACI,KAAK,EAAE,sBAAsB;QAC7B,IAAI,EAAE,eAAe;QACrB,GAAG,EAAE,uFAAuF;KAC/F;IACD,8FAA8F;IAC9F,6FAA6F;IAC7F,4FAA4F;IAC5F,EAAE,KAAK,EAAE,cAAc,EAAE,IAAI,EAAE,eAAe,EAAE,GAAG,EAAE,mCAAmC,EAAE;IAC1F,EAAE,KAAK,EAAE,6BAA6B,EAAE,IAAI,EAAE,aAAa,EAAE,GAAG,EAAE,qCAAqC,EAAE;IACzG,EAAE,KAAK,EAAE,mBAAmB,EAAE,IAAI,EAAE,aAAa,EAAE,GAAG,EAAE,iCAAiC,EAAE;IAC3F,EAAE,KAAK,EAAE,gBAAgB,EAAE,IAAI,EAAE,gBAAgB,EAAE,GAAG,EAAE,oDAAoD,EAAE;IAC9G,EAAE,KAAK,EAAE,gBAAgB,EAAE,IAAI,EAAE,cAAc,EAAE,GAAG,EAAE,sBAAsB,EAAE;CACjF,CAAC;AAEF;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,2BAA2B,CAAC,OAAgB;IAC9D,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,UAAU,EAAE,CAAC;IAC1C,IAAI,OAAO,GAAG,CAAC,CAAC;IAChB,IAAI,WAAW,GAAG,CAAC,CAAC;IAEpB,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QACzB,MAAM,IAAI,GAAG,KAAK,CAAC,aAAa,CAAC;QACjC,uFAAuF;QACvF,0FAA0F;QAC1F,yFAAyF;QACzF,4FAA4F;QAC5F,2DAA2D;QAC3D,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;YAAC,WAAW,EAAE,CAAC;YAAC,SAAS;QAAC,CAAC;QAEtD,6FAA6F;QAC7F,MAAM,OAAO,GAAa,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC;YACxC,CAAC,CAAC,EAAE;YACJ,CAAC,CAAC,oBAAoB,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;QAE1D,4FAA4F;QAC5F,4FAA4F;QAC5F,sFAAsF;QACtF,0FAA0F;QAC1F,4FAA4F;QAC5F,yFAAyF;QACzF,yFAAyF;QACzF,4FAA4F;QAC5F,6FAA6F;QAC7F,2FAA2F;QAC3F,8FAA8F;QAC9F,kCAAkC;QAClC,MAAM,YAAY,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAE,oBAA0C,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;QAChG,KAAK,MAAM,CAAC,IAAI,kBAAkB,EAAE,CAAC;YACjC,IAAI,cAAc,CAAC,YAAY,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC;gBAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;QAC/F,CAAC;QACD,IAAI,CAAC,OAAO,CAAC,MAAM;YAAE,SAAS;QAE9B,MAAM,OAAO,CAAC,WAAW,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,aAAa,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,OAAO,CAAC,EAAE,CAAC,CAAC;QAChF,OAAO,EAAE,CAAC;IACd,CAAC;IAED,IAAI,OAAO,EAAE,CAAC;QACV,MAAM,CAAC,IAAI,CAAC,8EAA8E,EAAE;YACxF,aAAa,EAAE,OAAO;YACtB,MAAM,EAAE,oBAAoB,CAAC,IAAI,CAAC,IAAI,CAAC;SAC1C,CAAC,CAAC;IACP,CAAC;IACD,IAAI,WAAW,EAAE,CAAC;QACd,2FAA2F;QAC3F,2FAA2F;QAC3F,uFAAuF;QACvF,+DAA+D;QAC/D,MAAM,CAAC,IAAI,CAAC,gFAAgF,EAAE;YAC1F,MAAM,EAAE,WAAW;YACnB,MAAM,EAAE,gFAAgF;SAC3F,CAAC,CAAC;IACP,CAAC;IACD,OAAO,OAAO,CAAC;AACnB,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,CAAC,KAAK,UAAU,8BAA8B,CAAC,OAAgB;IACjE,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,aAAa,EAAE,CAAC;IAC7C,IAAI,OAAO,GAAG,CAAC,CAAC;IAEhB,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QACzB,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,CAAC;QAC1B,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC;YAAE,SAAS;QACzD,MAAM,OAAO,GAAG,oBAAoB,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;QACpE,IAAI,CAAC,OAAO,CAAC,MAAM;YAAE,SAAS;QAC9B,MAAM,OAAO,CAAC,cAAc,CAAC,KAAK,CAAC,OAAO,EAAE,EAAE,MAAM,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,OAAO,CAAC,EAAE,CAAC,CAAC;QAC/E,OAAO,EAAE,CAAC;IACd,CAAC;IAED,IAAI,OAAO,EAAE,CAAC;QACV,MAAM,CAAC,IAAI,CAAC,8EAA8E,EAAE;YACxF,aAAa,EAAE,OAAO;YACtB,MAAM,EAAE,oBAAoB,CAAC,IAAI,CAAC,IAAI,CAAC;SAC1C,CAAC,CAAC;IACP,CAAC;IACD,OAAO,OAAO,CAAC;AACnB,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAAC,OAAgB;IACzD,OAAO;QACH,MAAM,EAAE,MAAM,2BAA2B,CAAC,OAAO,CAAC;QAClD,SAAS,EAAE,MAAM,8BAA8B,CAAC,OAAO,CAAC;KAC3D,CAAC;AACN,CAAC"}
|
|
@@ -6,8 +6,22 @@
|
|
|
6
6
|
* storage. No HTTP, no token, no operator action: it self-authenticates by virtue of running
|
|
7
7
|
* inside the node. Disables itself gracefully (one log line, no crash) if no browser is available.
|
|
8
8
|
* Opt-in via config.screenshotAutoCapture so nodes without a browser never try.
|
|
9
|
-
*
|
|
9
|
+
*
|
|
10
|
+
* It also serves ONE app on demand (captureAppScreenshot), which is a different job wearing the
|
|
11
|
+
* same machinery. The batch exists so a catalogue is not full of blank cards; the on-demand call
|
|
12
|
+
* exists because an agent that has just published an app cannot otherwise see what it made. A
|
|
13
|
+
* hosted agent has no browser and no shell, so without this it ships blind and says "done" on the
|
|
14
|
+
* strength of a 200.
|
|
15
|
+
* @structure startScreenshotAutoCapture() entry; launchBrowser() channel fallback;
|
|
16
|
+
* runScreenshotCapturePass() one batch scan; captureAppScreenshot() one app, with its own
|
|
17
|
+
* per-owner throttle; renderAndStore() the shared render both paths use.
|
|
10
18
|
* @version-history
|
|
19
|
+
* v1.3.0 — 2026-08-16 — captureAppScreenshot(): one named app, on demand, answering with a reason
|
|
20
|
+
* instead of a number. The render moved into renderAndStore() so the batch and the request run
|
|
21
|
+
* the same code. The module-level `running` flag stays a BATCH guard only — it used to make any
|
|
22
|
+
* second caller return 0 silently, which is the wrong answer to give someone who asked a
|
|
23
|
+
* question. Rendering is expensive and unauthenticated rendering is a denial-of-service shape,
|
|
24
|
+
* so the on-demand path carries a per-owner throttle of its own.
|
|
11
25
|
* v1.0.0 — 2026-06-20 — initial: interval backfill writing straight to storage; channel-fallback
|
|
12
26
|
* browser via lazy playwright-core; graceful self-disable when no browser is present.
|
|
13
27
|
* v1.1.0 — 2026-06-20 — render the app's STORED HTML directly (fulfill the main document) instead of
|
|
@@ -18,11 +32,36 @@
|
|
|
18
32
|
*/
|
|
19
33
|
import type { AimeatConfig } from '../config.js';
|
|
20
34
|
import type { Storage } from '../storage/interface.js';
|
|
35
|
+
/** What one on-demand capture can answer. Every failure names itself, because the caller is an agent
|
|
36
|
+
* deciding what to do next rather than a log nobody reads. */
|
|
37
|
+
export type CaptureResult = {
|
|
38
|
+
ok: true;
|
|
39
|
+
sizeBytes: number;
|
|
40
|
+
} | {
|
|
41
|
+
ok: false;
|
|
42
|
+
status: number;
|
|
43
|
+
code: string;
|
|
44
|
+
message: string;
|
|
45
|
+
};
|
|
21
46
|
/**
|
|
22
47
|
* One scan: capture + store a thumbnail for every published app that still has none. Returns the
|
|
23
48
|
* number captured. Exported so a manual trigger / test can run a single pass on demand.
|
|
24
49
|
*/
|
|
25
50
|
export declare function runScreenshotCapturePass(config: AimeatConfig, storage: Storage): Promise<number>;
|
|
51
|
+
/**
|
|
52
|
+
* Capture ONE app now, for a caller who asked.
|
|
53
|
+
*
|
|
54
|
+
* Separate from the batch on purpose. The batch may skip, retry next interval and answer with a
|
|
55
|
+
* count; someone who just published an app and wants to look at it needs either a picture or a
|
|
56
|
+
* reason. The batch's `running` flag is deliberately NOT consulted here: a scan in progress is no
|
|
57
|
+
* reason to refuse a person, and the two writing the same key is an upsert either way.
|
|
58
|
+
*
|
|
59
|
+
* Rendering is the most expensive thing this node does per request, so it is throttled per owner.
|
|
60
|
+
*/
|
|
61
|
+
export declare function captureAppScreenshot(config: AimeatConfig, storage: Storage, app: {
|
|
62
|
+
ownerName: string;
|
|
63
|
+
filename: string;
|
|
64
|
+
}): Promise<CaptureResult>;
|
|
26
65
|
/** Start the interval-driven auto-capture job (no-op unless config.screenshotAutoCapture is on). */
|
|
27
66
|
export declare function startScreenshotAutoCapture(config: AimeatConfig, storage: Storage): void;
|
|
28
67
|
//# sourceMappingURL=screenshot-capture.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"screenshot-capture.d.ts","sourceRoot":"","sources":["../../../src/services/screenshot-capture.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"screenshot-capture.d.ts","sourceRoot":"","sources":["../../../src/services/screenshot-capture.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AACjD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAmBvD;+DAC+D;AAC/D,MAAM,MAAM,aAAa,GACrB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GAC/B;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAoHjE;;;GAGG;AACH,wBAAsB,wBAAwB,CAAC,MAAM,EAAE,YAAY,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAiCtG;AAED;;;;;;;;;GASG;AACH,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,YAAY,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GACnF,OAAO,CAAC,aAAa,CAAC,CAqDxB;AAED,oGAAoG;AACpG,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,YAAY,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI,CAOvF"}
|
|
@@ -6,6 +6,12 @@ const FIRST_PASS_DELAY_MS = 30_000; // let the server settle (and be reachable a
|
|
|
6
6
|
let running = false;
|
|
7
7
|
let disabled = false;
|
|
8
8
|
let timer = null;
|
|
9
|
+
/**
|
|
10
|
+
* Owner GHII -> the moments they asked for an on-demand capture, newest last. In-process on purpose:
|
|
11
|
+
* this is throttling, not accounting, and a node restart handing out a fresh allowance costs a few
|
|
12
|
+
* seconds of rendering rather than money.
|
|
13
|
+
*/
|
|
14
|
+
const onDemandHistory = new Map();
|
|
9
15
|
/**
|
|
10
16
|
* Launch a headless browser WITHOUT a Playwright browser download: prefer the machine's installed
|
|
11
17
|
* Edge/Chrome via `channel`, then a Playwright-installed Chromium. Returns null (and the caller
|
|
@@ -43,6 +49,75 @@ async function launchBrowser() {
|
|
|
43
49
|
+ '`npx playwright install --with-deps chromium`. Last error: ' + (lastErr?.message ?? 'unknown'));
|
|
44
50
|
return null;
|
|
45
51
|
}
|
|
52
|
+
/**
|
|
53
|
+
* Render one app and store its thumbnail. The bytes come from storage and are served to the page by
|
|
54
|
+
* intercepting the main document, rather than navigating to the public URL: that URL 301-redirects
|
|
55
|
+
* to the app origin under H-2, which 404s on a node with no separate app host and would capture an
|
|
56
|
+
* error page. Sub-resources still load against the node and the page URL stays the node URL, so
|
|
57
|
+
* relative paths and API calls resolve.
|
|
58
|
+
*
|
|
59
|
+
* Throws on failure; each caller words its own answer.
|
|
60
|
+
*/
|
|
61
|
+
async function renderAndStore(ctx, config, storage, app) {
|
|
62
|
+
const base = config.baseUrl.replace(/\/+$/, '');
|
|
63
|
+
const page = await ctx.newPage();
|
|
64
|
+
try {
|
|
65
|
+
const full = await storage.getAppByOwnerName(app.ownerName, app.filename);
|
|
66
|
+
// storage returns `data` as a Uint8Array; a plain Uint8Array's .toString('utf8') comma-joins the
|
|
67
|
+
// byte values instead of decoding — wrap in Buffer.
|
|
68
|
+
const html = full?.data ? Buffer.from(full.data).toString('utf8') : null;
|
|
69
|
+
const url = `${base}/v1/apps/${encodeURIComponent(app.ownerName)}/${encodeURIComponent(app.filename)}?mode=inline`;
|
|
70
|
+
if (html) {
|
|
71
|
+
let fulfilled = false;
|
|
72
|
+
await page.route('**/*', (route) => {
|
|
73
|
+
if (!fulfilled && route.request().resourceType() === 'document') {
|
|
74
|
+
fulfilled = true;
|
|
75
|
+
route.fulfill({ status: 200, contentType: 'text/html', body: html });
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
route.continue();
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
// 'load' rather than networkidle: polling and SSE apps never go idle. The settle wait after it is
|
|
83
|
+
// what stops an app that fetches its data post-load from being captured blank.
|
|
84
|
+
await page.goto(url, { waitUntil: 'load', timeout: PAGE_TIMEOUT });
|
|
85
|
+
await page.waitForTimeout(Math.max(0, config.screenshotSettleMs));
|
|
86
|
+
const jpeg = await page.screenshot({ type: 'jpeg', quality: 80 });
|
|
87
|
+
await storage.createStorageFile({
|
|
88
|
+
key: `apps/screenshots/${app.filename}`,
|
|
89
|
+
ownerGaii: app.ownerGaii, // match the app row's bucket so the GET route finds it
|
|
90
|
+
visibility: 'public',
|
|
91
|
+
mimeType: 'image/jpeg',
|
|
92
|
+
size: jpeg.length,
|
|
93
|
+
data: jpeg,
|
|
94
|
+
createdAt: new Date().toISOString(),
|
|
95
|
+
});
|
|
96
|
+
return jpeg.length;
|
|
97
|
+
}
|
|
98
|
+
finally {
|
|
99
|
+
await page.close();
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
/** Launch, hand over a context, and always close. */
|
|
103
|
+
async function withBrowser(fn) {
|
|
104
|
+
const browser = await launchBrowser();
|
|
105
|
+
if (!browser) {
|
|
106
|
+
disabled = true;
|
|
107
|
+
if (timer) {
|
|
108
|
+
clearInterval(timer);
|
|
109
|
+
timer = null;
|
|
110
|
+
}
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
try {
|
|
114
|
+
const ctx = await browser.newContext({ viewport: VIEWPORT, deviceScaleFactor: 1 });
|
|
115
|
+
return await fn(ctx);
|
|
116
|
+
}
|
|
117
|
+
finally {
|
|
118
|
+
await browser.close();
|
|
119
|
+
}
|
|
120
|
+
}
|
|
46
121
|
/**
|
|
47
122
|
* One scan: capture + store a thumbnail for every published app that still has none. Returns the
|
|
48
123
|
* number captured. Exported so a manual trigger / test can run a single pass on demand.
|
|
@@ -62,74 +137,20 @@ export async function runScreenshotCapturePass(config, storage) {
|
|
|
62
137
|
}
|
|
63
138
|
if (missing.length === 0)
|
|
64
139
|
return 0;
|
|
65
|
-
|
|
66
|
-
if (!browser) {
|
|
67
|
-
disabled = true;
|
|
68
|
-
if (timer) {
|
|
69
|
-
clearInterval(timer);
|
|
70
|
-
timer = null;
|
|
71
|
-
}
|
|
72
|
-
return 0;
|
|
73
|
-
}
|
|
74
|
-
try {
|
|
75
|
-
const ctx = await browser.newContext({ viewport: VIEWPORT, deviceScaleFactor: 1 });
|
|
76
|
-
const base = config.baseUrl.replace(/\/+$/, '');
|
|
140
|
+
await withBrowser(async (ctx) => {
|
|
77
141
|
for (const app of missing) {
|
|
78
|
-
const page = await ctx.newPage();
|
|
79
142
|
try {
|
|
80
|
-
|
|
81
|
-
// to the public inline URL: that URL 301-redirects to the app origin under H-2, which 404s
|
|
82
|
-
// on a node with no separate app host (e.g. local dev) and would capture an error page.
|
|
83
|
-
// Sub-resources (libs, images, API) still load against the node and the page URL stays the
|
|
84
|
-
// node URL so relative paths resolve. Opened anonymously; 'load' (not networkidle) since
|
|
85
|
-
// polling/SSE apps never go idle.
|
|
86
|
-
const full = await storage.getAppByOwnerName(app.ownerName, app.filename);
|
|
87
|
-
// storage returns `data` as a Uint8Array (Prisma 6 Bytes); a plain Uint8Array's
|
|
88
|
-
// .toString('utf8') comma-joins the byte values instead of decoding — wrap in Buffer.
|
|
89
|
-
const html = full?.data ? Buffer.from(full.data).toString('utf8') : null;
|
|
90
|
-
const url = `${base}/v1/apps/${encodeURIComponent(app.ownerName)}/${encodeURIComponent(app.filename)}?mode=inline`;
|
|
91
|
-
if (html) {
|
|
92
|
-
let fulfilled = false;
|
|
93
|
-
await page.route('**/*', (route) => {
|
|
94
|
-
if (!fulfilled && route.request().resourceType() === 'document') {
|
|
95
|
-
fulfilled = true;
|
|
96
|
-
route.fulfill({ status: 200, contentType: 'text/html', body: html });
|
|
97
|
-
}
|
|
98
|
-
else {
|
|
99
|
-
route.continue();
|
|
100
|
-
}
|
|
101
|
-
});
|
|
102
|
-
}
|
|
103
|
-
await page.goto(url, { waitUntil: 'load', timeout: PAGE_TIMEOUT });
|
|
104
|
-
// Settle wait: many apps fetch data / render after 'load', so capturing immediately yields a
|
|
105
|
-
// blank page. Default 6s; tune with AIMEAT_SCREENSHOT_SETTLE_MS.
|
|
106
|
-
await page.waitForTimeout(Math.max(0, config.screenshotSettleMs));
|
|
107
|
-
const jpeg = await page.screenshot({ type: 'jpeg', quality: 80 });
|
|
108
|
-
await storage.createStorageFile({
|
|
109
|
-
key: `apps/screenshots/${app.filename}`,
|
|
110
|
-
ownerGaii: app.ownerGaii, // match the app row's bucket so the GET route finds it
|
|
111
|
-
visibility: 'public',
|
|
112
|
-
mimeType: 'image/jpeg',
|
|
113
|
-
size: jpeg.length,
|
|
114
|
-
data: jpeg,
|
|
115
|
-
createdAt: new Date().toISOString(),
|
|
116
|
-
});
|
|
143
|
+
await renderAndStore(ctx, config, storage, app);
|
|
117
144
|
captured++;
|
|
118
145
|
}
|
|
119
146
|
catch (e) {
|
|
120
147
|
logger.warn(`Screenshot auto-capture failed for ${app.ownerName}/${app.filename}: ${e.message}`);
|
|
121
148
|
}
|
|
122
|
-
finally {
|
|
123
|
-
await page.close();
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
if (captured > 0) {
|
|
127
|
-
logger.info(`Screenshot auto-capture: ${captured}/${missing.length} app thumbnail(s) generated.`);
|
|
128
|
-
emitChange('apps');
|
|
129
149
|
}
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
|
|
150
|
+
});
|
|
151
|
+
if (captured > 0) {
|
|
152
|
+
logger.info(`Screenshot auto-capture: ${captured}/${missing.length} app thumbnail(s) generated.`);
|
|
153
|
+
emitChange('apps');
|
|
133
154
|
}
|
|
134
155
|
}
|
|
135
156
|
catch (e) {
|
|
@@ -140,6 +161,67 @@ export async function runScreenshotCapturePass(config, storage) {
|
|
|
140
161
|
}
|
|
141
162
|
return captured;
|
|
142
163
|
}
|
|
164
|
+
/**
|
|
165
|
+
* Capture ONE app now, for a caller who asked.
|
|
166
|
+
*
|
|
167
|
+
* Separate from the batch on purpose. The batch may skip, retry next interval and answer with a
|
|
168
|
+
* count; someone who just published an app and wants to look at it needs either a picture or a
|
|
169
|
+
* reason. The batch's `running` flag is deliberately NOT consulted here: a scan in progress is no
|
|
170
|
+
* reason to refuse a person, and the two writing the same key is an upsert either way.
|
|
171
|
+
*
|
|
172
|
+
* Rendering is the most expensive thing this node does per request, so it is throttled per owner.
|
|
173
|
+
*/
|
|
174
|
+
export async function captureAppScreenshot(config, storage, app) {
|
|
175
|
+
if (disabled) {
|
|
176
|
+
return {
|
|
177
|
+
ok: false, status: 503, code: 'NO_BROWSER',
|
|
178
|
+
message: 'This node has no usable browser, so it cannot render app screenshots. An operator can '
|
|
179
|
+
+ 'install one with `npx playwright install --with-deps chromium`.',
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
// The lookup lives here rather than at each door: it decides both "is there anything to render"
|
|
183
|
+
// and WHICH storage bucket the thumbnail belongs in, and a door that answered the first half for
|
|
184
|
+
// itself would be the second implementation of the same decision.
|
|
185
|
+
const live = await storage.getAppByOwnerName(app.ownerName, app.filename);
|
|
186
|
+
if (!live) {
|
|
187
|
+
return {
|
|
188
|
+
ok: false, status: 404, code: 'NOT_FOUND',
|
|
189
|
+
message: `No published app "${app.filename}" to render. Publish it first; a draft has no public `
|
|
190
|
+
+ 'page to photograph.',
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
const ownerGaii = live.ownerGaii;
|
|
194
|
+
const perHour = Math.max(1, config.screenshotOnDemandPerHour);
|
|
195
|
+
const now = Date.now();
|
|
196
|
+
const recent = (onDemandHistory.get(ownerGaii) ?? []).filter((t) => now - t < 3_600_000);
|
|
197
|
+
if (recent.length >= perHour) {
|
|
198
|
+
const waitMin = Math.ceil((3_600_000 - (now - recent[0])) / 60_000);
|
|
199
|
+
return {
|
|
200
|
+
ok: false, status: 429, code: 'RATE_LIMITED',
|
|
201
|
+
message: `Screenshot limit reached (${perHour} per hour). Try again in about ${waitMin} minute(s).`,
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
recent.push(now);
|
|
205
|
+
onDemandHistory.set(ownerGaii, recent);
|
|
206
|
+
try {
|
|
207
|
+
const bytes = await withBrowser((ctx) => renderAndStore(ctx, config, storage, { ownerName: app.ownerName, ownerGaii, filename: app.filename }));
|
|
208
|
+
if (bytes === null) {
|
|
209
|
+
return {
|
|
210
|
+
ok: false, status: 503, code: 'NO_BROWSER',
|
|
211
|
+
message: 'This node has no usable browser, so it cannot render app screenshots.',
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
emitChange('apps');
|
|
215
|
+
logger.info(`Screenshot captured on demand: ${app.ownerName}/${app.filename} (${bytes} bytes)`);
|
|
216
|
+
return { ok: true, sizeBytes: bytes };
|
|
217
|
+
}
|
|
218
|
+
catch (e) {
|
|
219
|
+
return {
|
|
220
|
+
ok: false, status: 502, code: 'RENDER_FAILED',
|
|
221
|
+
message: `The page did not render: ${e.message}`,
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
}
|
|
143
225
|
/** Start the interval-driven auto-capture job (no-op unless config.screenshotAutoCapture is on). */
|
|
144
226
|
export function startScreenshotAutoCapture(config, storage) {
|
|
145
227
|
if (!config.screenshotAutoCapture)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"screenshot-capture.js","sourceRoot":"","sources":["../../../src/services/screenshot-capture.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"screenshot-capture.js","sourceRoot":"","sources":["../../../src/services/screenshot-capture.ts"],"names":[],"mappings":"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"}
|