@engenty/wizards-runtime 0.0.0-stage → 0.7.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +110 -0
- package/README.md +214 -2
- package/apps/runtime/dist/agents/architect.js +444 -0
- package/apps/runtime/dist/agents/studio-assistant.js +883 -0
- package/apps/runtime/dist/agents/subscription.js +207 -0
- package/apps/runtime/dist/agents/thought.js +21 -0
- package/apps/runtime/dist/agents/website.js +480 -0
- package/apps/runtime/dist/app.js +359 -0
- package/apps/runtime/dist/apple/wizards-apple +0 -0
- package/apps/runtime/dist/assistant/browser.js +26 -0
- package/apps/runtime/dist/assistant/docs.js +158 -0
- package/apps/runtime/dist/assistant/knows.js +353 -0
- package/apps/runtime/dist/assistant/primer.js +26 -0
- package/apps/runtime/dist/assistant/runs.js +24 -0
- package/apps/runtime/dist/auth/account.js +175 -0
- package/apps/runtime/dist/auth/device.js +112 -0
- package/apps/runtime/dist/auth/index.js +358 -0
- package/apps/runtime/dist/auth/keys.js +55 -0
- package/apps/runtime/dist/auth/local-ticket.js +26 -0
- package/apps/runtime/dist/authoring/example.js +74 -0
- package/apps/runtime/dist/authoring/guide.js +433 -0
- package/apps/runtime/dist/authoring/ops.js +117 -0
- package/apps/runtime/dist/browser/fast/action-space.js +160 -0
- package/apps/runtime/dist/browser/fast/classifier.js +91 -0
- package/apps/runtime/dist/browser/fast/decide.js +171 -0
- package/apps/runtime/dist/browser/fast/driver.js +141 -0
- package/apps/runtime/dist/browser/fast/instructions.js +33 -0
- package/apps/runtime/dist/browser/fast/run.js +249 -0
- package/apps/runtime/dist/browser/fast/span-picker.js +153 -0
- package/apps/runtime/dist/browser/fast/text-helper.js +178 -0
- package/apps/runtime/dist/browser/snapshot.js +335 -0
- package/apps/runtime/dist/cli/account.js +385 -0
- package/apps/runtime/dist/cli/autostart.js +182 -0
- package/apps/runtime/dist/cli/autoupdate.js +221 -0
- package/apps/runtime/dist/cli/clients.js +44 -0
- package/apps/runtime/dist/cli/connect.js +540 -0
- package/apps/runtime/dist/cli/environment.js +95 -0
- package/apps/runtime/dist/cli/exec.js +45 -0
- package/apps/runtime/dist/cli/features.js +50 -0
- package/apps/runtime/dist/cli/home.js +88 -0
- package/apps/runtime/dist/cli/install-env.js +33 -0
- package/apps/runtime/dist/cli/machine.js +107 -0
- package/apps/runtime/dist/cli/main.js +231 -0
- package/apps/runtime/dist/cli/mcp.js +136 -0
- package/apps/runtime/dist/cli/menu.js +202 -0
- package/apps/runtime/dist/cli/processes.js +72 -0
- package/apps/runtime/dist/cli/report.js +66 -0
- package/apps/runtime/dist/cli/sandbox.js +77 -0
- package/apps/runtime/dist/cli/setup.js +335 -0
- package/apps/runtime/dist/cli/start.js +276 -0
- package/apps/runtime/dist/cli/status.js +212 -0
- package/apps/runtime/dist/cli/ui.js +59 -0
- package/apps/runtime/dist/cli/uninstall-main.js +20 -0
- package/apps/runtime/dist/cli/uninstall.js +231 -0
- package/apps/runtime/dist/cli/update.js +86 -0
- package/apps/runtime/dist/cli/validate.js +75 -0
- package/apps/runtime/dist/cli/versions.js +123 -0
- package/apps/runtime/dist/connectors/builtin.js +86 -0
- package/apps/runtime/dist/connectors/external.js +409 -0
- package/apps/runtime/dist/connectors/gmail.js +107 -0
- package/apps/runtime/dist/connectors/imap.js +261 -0
- package/apps/runtime/dist/connectors/index.js +325 -0
- package/apps/runtime/dist/connectors/mail.js +72 -0
- package/apps/runtime/dist/connectors/outlook.js +90 -0
- package/apps/runtime/dist/connectors/plugin-connections.js +343 -0
- package/apps/runtime/dist/connectors/via-account.js +65 -0
- package/apps/runtime/dist/credits/credits.js +100 -0
- package/apps/runtime/dist/credits/estimate.js +152 -0
- package/apps/runtime/dist/db/adopt.js +149 -0
- package/apps/runtime/dist/db/client.js +173 -0
- package/apps/runtime/dist/db/control-schema.js +133 -0
- package/apps/runtime/dist/db/migrations/control/0000_last_absorbing_man.sql +47 -0
- package/apps/runtime/dist/db/migrations/control/0001_gorgeous_nicolaos.sql +41 -0
- package/apps/runtime/dist/db/migrations/control/0002_secret_penance.sql +1 -0
- package/apps/runtime/dist/db/migrations/control/0003_nasty_mordo.sql +3 -0
- package/apps/runtime/dist/db/migrations/control/0004_breezy_eddie_brock.sql +6 -0
- package/apps/runtime/dist/db/migrations/control/0005_chilly_oracle.sql +1 -0
- package/apps/runtime/dist/db/migrations/control/0006_sleepy_mojo.sql +1 -0
- package/apps/runtime/dist/db/migrations/control/0007_common_the_hand.sql +15 -0
- package/apps/runtime/dist/db/migrations/control/0008_runner.sql +8 -0
- package/apps/runtime/dist/db/migrations/control/0009_plugin_claim.sql +9 -0
- package/apps/runtime/dist/db/migrations/control/0010_tan_snowbird.sql +6 -0
- package/apps/runtime/dist/db/migrations/control/meta/0000_snapshot.json +311 -0
- package/apps/runtime/dist/db/migrations/control/meta/0001_snapshot.json +599 -0
- package/apps/runtime/dist/db/migrations/control/meta/0002_snapshot.json +607 -0
- package/apps/runtime/dist/db/migrations/control/meta/0003_snapshot.json +311 -0
- package/apps/runtime/dist/db/migrations/control/meta/0004_snapshot.json +350 -0
- package/apps/runtime/dist/db/migrations/control/meta/0005_snapshot.json +358 -0
- package/apps/runtime/dist/db/migrations/control/meta/0006_snapshot.json +365 -0
- package/apps/runtime/dist/db/migrations/control/meta/0007_snapshot.json +460 -0
- package/apps/runtime/dist/db/migrations/control/meta/0008_snapshot.json +505 -0
- package/apps/runtime/dist/db/migrations/control/meta/0009_snapshot.json +561 -0
- package/apps/runtime/dist/db/migrations/control/meta/0010_snapshot.json +600 -0
- package/apps/runtime/dist/db/migrations/control/meta/_journal.json +83 -0
- package/apps/runtime/dist/db/migrations/tenant/0000_eminent_freak.sql +188 -0
- package/apps/runtime/dist/db/migrations/tenant/0001_salty_master_chief.sql +1 -0
- package/apps/runtime/dist/db/migrations/tenant/0002_cloudy_firebird.sql +1 -0
- package/apps/runtime/dist/db/migrations/tenant/0003_brown_warbound.sql +52 -0
- package/apps/runtime/dist/db/migrations/tenant/0004_romantic_nocturne.sql +6 -0
- package/apps/runtime/dist/db/migrations/tenant/0005_reflective_forgotten_one.sql +2 -0
- package/apps/runtime/dist/db/migrations/tenant/0006_hard_war_machine.sql +30 -0
- package/apps/runtime/dist/db/migrations/tenant/0007_space_data.sql +43 -0
- package/apps/runtime/dist/db/migrations/tenant/0008_run_event_note.sql +1 -0
- package/apps/runtime/dist/db/migrations/tenant/0009_knowledge.sql +104 -0
- package/apps/runtime/dist/db/migrations/tenant/0010_plugin_connection.sql +15 -0
- package/apps/runtime/dist/db/migrations/tenant/0011_runners.sql +2 -0
- package/apps/runtime/dist/db/migrations/tenant/0012_assistant_chat.sql +40 -0
- package/apps/runtime/dist/db/migrations/tenant/0013_run_origin.sql +1 -0
- package/apps/runtime/dist/db/migrations/tenant/0014_run_answer.sql +2 -0
- package/apps/runtime/dist/db/migrations/tenant/0015_device_calls.sql +13 -0
- package/apps/runtime/dist/db/migrations/tenant/0016_even_trish_tilby.sql +12 -0
- package/apps/runtime/dist/db/migrations/tenant/meta/0000_snapshot.json +1323 -0
- package/apps/runtime/dist/db/migrations/tenant/meta/0001_snapshot.json +1330 -0
- package/apps/runtime/dist/db/migrations/tenant/meta/0002_snapshot.json +1337 -0
- package/apps/runtime/dist/db/migrations/tenant/meta/0003_snapshot.json +1605 -0
- package/apps/runtime/dist/db/migrations/tenant/meta/0004_snapshot.json +1645 -0
- package/apps/runtime/dist/db/migrations/tenant/meta/0005_snapshot.json +1659 -0
- package/apps/runtime/dist/db/migrations/tenant/meta/0006_snapshot.json +1696 -0
- package/apps/runtime/dist/db/migrations/tenant/meta/0007_snapshot.json +2012 -0
- package/apps/runtime/dist/db/migrations/tenant/meta/0008_snapshot.json +2019 -0
- package/apps/runtime/dist/db/migrations/tenant/meta/0009_snapshot.json +2837 -0
- package/apps/runtime/dist/db/migrations/tenant/meta/0010_snapshot.json +2942 -0
- package/apps/runtime/dist/db/migrations/tenant/meta/0011_snapshot.json +2956 -0
- package/apps/runtime/dist/db/migrations/tenant/meta/0012_snapshot.json +3132 -0
- package/apps/runtime/dist/db/migrations/tenant/meta/0013_snapshot.json +3139 -0
- package/apps/runtime/dist/db/migrations/tenant/meta/0014_snapshot.json +3154 -0
- package/apps/runtime/dist/db/migrations/tenant/meta/0015_snapshot.json +3243 -0
- package/apps/runtime/dist/db/migrations/tenant/meta/0016_snapshot.json +3326 -0
- package/apps/runtime/dist/db/migrations/tenant/meta/_journal.json +125 -0
- package/apps/runtime/dist/db/schema.js +602 -0
- package/apps/runtime/dist/debug.js +197 -0
- package/apps/runtime/dist/docs/dev/index.md +41 -0
- package/apps/runtime/dist/docs/dev/meta.json +7 -0
- package/apps/runtime/dist/docs/dev/plugins/connections.md +74 -0
- package/apps/runtime/dist/docs/dev/plugins/events.md +89 -0
- package/apps/runtime/dist/docs/dev/plugins/examples.md +101 -0
- package/apps/runtime/dist/docs/dev/plugins/index.md +78 -0
- package/apps/runtime/dist/docs/dev/plugins/layout.md +90 -0
- package/apps/runtime/dist/docs/dev/plugins/meta.json +28 -0
- package/apps/runtime/dist/docs/dev/plugins/quick-start.md +94 -0
- package/apps/runtime/dist/docs/dev/plugins/reference.md +348 -0
- package/apps/runtime/dist/docs/dev/plugins/reloading.md +76 -0
- package/apps/runtime/dist/docs/dev/plugins/routes.md +185 -0
- package/apps/runtime/dist/docs/dev/plugins/runners.md +230 -0
- package/apps/runtime/dist/docs/dev/plugins/server.md +281 -0
- package/apps/runtime/dist/docs/dev/plugins/shipping.md +79 -0
- package/apps/runtime/dist/docs/dev/plugins/space.md +297 -0
- package/apps/runtime/dist/docs/dev/plugins/starters.md +70 -0
- package/apps/runtime/dist/docs/dev/plugins/studio.md +363 -0
- package/apps/runtime/dist/docs/dev/plugins/styling.md +129 -0
- package/apps/runtime/dist/docs/dev/plugins/tables.md +104 -0
- package/apps/runtime/dist/docs/dev/plugins/tools.md +139 -0
- package/apps/runtime/dist/docs/dev/wizard-format.md +125 -0
- package/apps/runtime/dist/docs/meta.json +3 -0
- package/apps/runtime/dist/docs/user/ai-apps.md +112 -0
- package/apps/runtime/dist/docs/user/assistant.md +77 -0
- package/apps/runtime/dist/docs/user/build-a-wizard.md +116 -0
- package/apps/runtime/dist/docs/user/command-line.md +86 -0
- package/apps/runtime/dist/docs/user/connectors.md +90 -0
- package/apps/runtime/dist/docs/user/create-account.md +52 -0
- package/apps/runtime/dist/docs/user/data.md +66 -0
- package/apps/runtime/dist/docs/user/first-start.md +60 -0
- package/apps/runtime/dist/docs/user/index.md +49 -0
- package/apps/runtime/dist/docs/user/install.md +123 -0
- package/apps/runtime/dist/docs/user/local-only.md +42 -0
- package/apps/runtime/dist/docs/user/meta.json +32 -0
- package/apps/runtime/dist/docs/user/models.md +156 -0
- package/apps/runtime/dist/docs/user/plugins.md +71 -0
- package/apps/runtime/dist/docs/user/run.md +98 -0
- package/apps/runtime/dist/docs/user/server.md +52 -0
- package/apps/runtime/dist/docs/user/space.md +126 -0
- package/apps/runtime/dist/docs/user/steps.md +220 -0
- package/apps/runtime/dist/docs/user/test-and-share.md +224 -0
- package/apps/runtime/dist/docs/user/troubleshooting.md +67 -0
- package/apps/runtime/dist/docs/user/wordpress.md +121 -0
- package/apps/runtime/dist/documents/parse.js +246 -0
- package/apps/runtime/dist/engenty/connections-external/build-connector.js +193 -0
- package/apps/runtime/dist/engenty/connections-external/errors.js +11 -0
- package/apps/runtime/dist/engenty/connections-external/import-service.js +270 -0
- package/apps/runtime/dist/engenty/connections-external/importer/classify.js +34 -0
- package/apps/runtime/dist/engenty/connections-external/importer/map-auth.js +185 -0
- package/apps/runtime/dist/engenty/connections-external/importer/normalize-mcp.js +63 -0
- package/apps/runtime/dist/engenty/connections-external/importer/normalize-openapi.js +130 -0
- package/apps/runtime/dist/engenty/connections-external/invoke/http-invoker.js +143 -0
- package/apps/runtime/dist/engenty/connections-external/invoke/mcp-client.js +143 -0
- package/apps/runtime/dist/engenty/connections-external/net/guarded-fetch.js +119 -0
- package/apps/runtime/dist/engenty/connections-external/oauth-dcr.js +88 -0
- package/apps/runtime/dist/engenty/connections-external/registry-client.js +336 -0
- package/apps/runtime/dist/engenty/connections-external/registry-source.js +82 -0
- package/apps/runtime/dist/engenty/connections-external/types.js +7 -0
- package/apps/runtime/dist/engenty/connections-github/connector.js +209 -0
- package/apps/runtime/dist/engenty/connections-google/connectors/calendar.js +381 -0
- package/apps/runtime/dist/engenty/connections-google/connectors/contacts.js +94 -0
- package/apps/runtime/dist/engenty/connections-google/connectors/drive.js +290 -0
- package/apps/runtime/dist/engenty/connections-google/connectors/gmail.js +567 -0
- package/apps/runtime/dist/engenty/connections-google/definitions.js +11 -0
- package/apps/runtime/dist/engenty/connections-google/shared.js +73 -0
- package/apps/runtime/dist/engenty/connections-hubspot/connector.js +140 -0
- package/apps/runtime/dist/engenty/connections-microsoft/action.js +17 -0
- package/apps/runtime/dist/engenty/connections-microsoft/graph.js +114 -0
- package/apps/runtime/dist/engenty/connections-microsoft/onedrive.js +286 -0
- package/apps/runtime/dist/engenty/connections-microsoft/outlook.js +492 -0
- package/apps/runtime/dist/engenty/connections-s3/s3.js +328 -0
- package/apps/runtime/dist/engenty/connections-sdk/files-capability.js +86 -0
- package/apps/runtime/dist/engenty/connections-sdk/oauth2.js +150 -0
- package/apps/runtime/dist/engenty/connections-sdk/registry.js +89 -0
- package/apps/runtime/dist/engenty/connections-sdk/storage-capability.js +84 -0
- package/apps/runtime/dist/engenty/connections-sdk/types.js +30 -0
- package/apps/runtime/dist/engenty/connections-slack/connector.js +360 -0
- package/apps/runtime/dist/engenty/csv-import/csv-matrix.js +178 -0
- package/apps/runtime/dist/engenty/csv-import/import-sources.js +87 -0
- package/apps/runtime/dist/engenty/csv-import/parse-csv.js +129 -0
- package/apps/runtime/dist/engenty/csv-import/serialize-csv.js +20 -0
- package/apps/runtime/dist/engenty/csv-import/types.js +1 -0
- package/apps/runtime/dist/engenty/csv-import/xlsx-workbook.js +159 -0
- package/apps/runtime/dist/engenty/doc-converter/interface.js +9 -0
- package/apps/runtime/dist/engenty/doc-converter/page-break.js +92 -0
- package/apps/runtime/dist/engenty/doc-converter/providers/local/index.js +72 -0
- package/apps/runtime/dist/engenty/document-scanner/schemas/classifier.js +30 -0
- package/apps/runtime/dist/engenty/document-scanner/schemas/index.js +4 -0
- package/apps/runtime/dist/engenty/document-scanner/schemas/invoice.js +73 -0
- package/apps/runtime/dist/engenty/document-scanner/schemas/receipt.js +63 -0
- package/apps/runtime/dist/engenty/document-scanner/schemas/shared.js +40 -0
- package/apps/runtime/dist/engenty/search-index/chunks.js +164 -0
- package/apps/runtime/dist/engenty/search-index/contracts.js +9 -0
- package/apps/runtime/dist/engenty/shims/connections-sdk.js +39 -0
- package/apps/runtime/dist/engenty/shims/plugin-sdk.js +1 -0
- package/apps/runtime/dist/engenty/shims/web-ingest.js +19 -0
- package/apps/runtime/dist/engenty/web-ingest/ssrf.js +277 -0
- package/apps/runtime/dist/engine/asks.js +82 -0
- package/apps/runtime/dist/engine/decide.js +82 -0
- package/apps/runtime/dist/engine/device.js +194 -0
- package/apps/runtime/dist/engine/events.js +128 -0
- package/apps/runtime/dist/engine/input.js +208 -0
- package/apps/runtime/dist/engine/owner.js +32 -0
- package/apps/runtime/dist/engine/prepare.js +90 -0
- package/apps/runtime/dist/engine/push.js +58 -0
- package/apps/runtime/dist/engine/requirements.js +355 -0
- package/apps/runtime/dist/engine/resources.js +198 -0
- package/apps/runtime/dist/engine/runner.js +970 -0
- package/apps/runtime/dist/engine/steps.js +1000 -0
- package/apps/runtime/dist/engine/surface.js +91 -0
- package/apps/runtime/dist/engine/template.js +240 -0
- package/apps/runtime/dist/engine/types.js +4 -0
- package/apps/runtime/dist/env.js +279 -0
- package/apps/runtime/dist/features.js +123 -0
- package/apps/runtime/dist/files/blobs.js +22 -0
- package/apps/runtime/dist/files/objects.js +86 -0
- package/apps/runtime/dist/files/storage.js +120 -0
- package/apps/runtime/dist/files/web-images.js +101 -0
- package/apps/runtime/dist/film/project.js +257 -0
- package/apps/runtime/dist/film/skills.js +91 -0
- package/apps/runtime/dist/film/sounds.js +122 -0
- package/apps/runtime/dist/film/step.js +289 -0
- package/apps/runtime/dist/film/tools.js +99 -0
- package/apps/runtime/dist/geocode.js +58 -0
- package/apps/runtime/dist/harness/antigravity.js +129 -0
- package/apps/runtime/dist/harness/apple.js +270 -0
- package/apps/runtime/dist/harness/claude.js +147 -0
- package/apps/runtime/dist/harness/codex.js +229 -0
- package/apps/runtime/dist/harness/cursor.js +93 -0
- package/apps/runtime/dist/harness/env.js +124 -0
- package/apps/runtime/dist/harness/index.js +95 -0
- package/apps/runtime/dist/harness/model.js +279 -0
- package/apps/runtime/dist/harness/prompt.js +121 -0
- package/apps/runtime/dist/harness/terminal.js +194 -0
- package/apps/runtime/dist/harness/types.js +7 -0
- package/apps/runtime/dist/index.js +113 -0
- package/apps/runtime/dist/limits.js +81 -0
- package/apps/runtime/dist/link-preview.js +60 -0
- package/apps/runtime/dist/log.js +106 -0
- package/apps/runtime/dist/manage.js +249 -0
- package/apps/runtime/dist/mcp/auth.js +161 -0
- package/apps/runtime/dist/mcp/bridge.js +59 -0
- package/apps/runtime/dist/mcp/flow-app.js +97 -0
- package/apps/runtime/dist/mcp/handler.js +54 -0
- package/apps/runtime/dist/mcp/scopes.js +14 -0
- package/apps/runtime/dist/mcp/seen.js +65 -0
- package/apps/runtime/dist/mcp/tools.js +572 -0
- package/apps/runtime/dist/media/conversation.js +167 -0
- package/apps/runtime/dist/media/ffmpeg.js +121 -0
- package/apps/runtime/dist/media/generate.js +120 -0
- package/apps/runtime/dist/media/marking.js +121 -0
- package/apps/runtime/dist/media/transcribe.js +198 -0
- package/apps/runtime/dist/model-errors.js +42 -0
- package/apps/runtime/dist/models.js +1164 -0
- package/apps/runtime/dist/plugin.js +61 -0
- package/apps/runtime/dist/plugins/channels.js +78 -0
- package/apps/runtime/dist/plugins/claims.js +56 -0
- package/apps/runtime/dist/plugins/discovery.js +155 -0
- package/apps/runtime/dist/plugins/events.js +63 -0
- package/apps/runtime/dist/plugins/jobs.js +64 -0
- package/apps/runtime/dist/plugins/loader.js +508 -0
- package/apps/runtime/dist/plugins/migrations.js +69 -0
- package/apps/runtime/dist/plugins/pro-keys.js +34 -0
- package/apps/runtime/dist/plugins/pro-state.js +83 -0
- package/apps/runtime/dist/plugins/pro.js +310 -0
- package/apps/runtime/dist/plugins/public.js +44 -0
- package/apps/runtime/dist/plugins/registry.js +122 -0
- package/apps/runtime/dist/plugins/runs.js +210 -0
- package/apps/runtime/dist/render/browser-path.js +54 -0
- package/apps/runtime/dist/render/chromium.js +98 -0
- package/apps/runtime/dist/render/convert.js +158 -0
- package/apps/runtime/dist/render/downloads.js +299 -0
- package/apps/runtime/dist/render/guard.js +25 -0
- package/apps/runtime/dist/render/shaped.js +137 -0
- package/apps/runtime/dist/routes/api.js +440 -0
- package/apps/runtime/dist/routes/debug.js +42 -0
- package/apps/runtime/dist/routes/delivery.js +90 -0
- package/apps/runtime/dist/routes/internal.js +81 -0
- package/apps/runtime/dist/routes/lang.js +25 -0
- package/apps/runtime/dist/routes/marketplace.js +43 -0
- package/apps/runtime/dist/routes/plugin-public.js +113 -0
- package/apps/runtime/dist/routes/plugins.js +212 -0
- package/apps/runtime/dist/routes/runs.js +1422 -0
- package/apps/runtime/dist/routes/studio.js +1629 -0
- package/apps/runtime/dist/routes/wizard-stream.js +30 -0
- package/apps/runtime/dist/running.js +39 -0
- package/apps/runtime/dist/sandbox/agentos-package.js +73 -0
- package/apps/runtime/dist/sandbox/agentos.js +162 -0
- package/apps/runtime/dist/sandbox/docker.js +45 -0
- package/apps/runtime/dist/sandbox/index.js +52 -0
- package/apps/runtime/dist/sandbox/install.js +122 -0
- package/apps/runtime/dist/sandbox/mastra.js +71 -0
- package/apps/runtime/dist/sandbox/types.js +1 -0
- package/apps/runtime/dist/secrets/crypto.js +28 -0
- package/apps/runtime/dist/secrets/signing.js +52 -0
- package/apps/runtime/dist/secrets/vault.js +59 -0
- package/apps/runtime/dist/services/access.js +88 -0
- package/apps/runtime/dist/services/api.js +248 -0
- package/apps/runtime/dist/services/architect.js +95 -0
- package/apps/runtime/dist/services/assistant-chats.js +311 -0
- package/apps/runtime/dist/services/brand.js +85 -0
- package/apps/runtime/dist/services/cloud.js +456 -0
- package/apps/runtime/dist/services/draft-events.js +27 -0
- package/apps/runtime/dist/services/engenty-shapes.js +71 -0
- package/apps/runtime/dist/services/errors.js +29 -0
- package/apps/runtime/dist/services/files.js +178 -0
- package/apps/runtime/dist/services/knowledge-model.js +559 -0
- package/apps/runtime/dist/services/knowledge.js +721 -0
- package/apps/runtime/dist/services/links.js +16 -0
- package/apps/runtime/dist/services/marketplace.js +492 -0
- package/apps/runtime/dist/services/onboarding.js +152 -0
- package/apps/runtime/dist/services/package-file.js +82 -0
- package/apps/runtime/dist/services/package.js +170 -0
- package/apps/runtime/dist/services/profile.js +51 -0
- package/apps/runtime/dist/services/project-files.js +439 -0
- package/apps/runtime/dist/services/project-index.js +707 -0
- package/apps/runtime/dist/services/projects.js +387 -0
- package/apps/runtime/dist/services/relevance.js +58 -0
- package/apps/runtime/dist/services/runners.js +178 -0
- package/apps/runtime/dist/services/runs.js +524 -0
- package/apps/runtime/dist/services/shares.js +130 -0
- package/apps/runtime/dist/services/site.js +270 -0
- package/apps/runtime/dist/services/space-categories.js +861 -0
- package/apps/runtime/dist/services/space-data.js +792 -0
- package/apps/runtime/dist/services/space-origin.js +207 -0
- package/apps/runtime/dist/services/spaces.js +657 -0
- package/apps/runtime/dist/services/translations.js +306 -0
- package/apps/runtime/dist/services/widgets.js +34 -0
- package/apps/runtime/dist/services/wizard-icon.js +157 -0
- package/apps/runtime/dist/services/wizards.js +420 -0
- package/apps/runtime/dist/settings.js +16 -0
- package/apps/runtime/dist/store/errors.js +4 -0
- package/apps/runtime/dist/store/index.js +299 -0
- package/apps/runtime/dist/store/shared-lists.js +123 -0
- package/apps/runtime/dist/tenants/control.js +238 -0
- package/apps/runtime/dist/tenants/tenant.js +26 -0
- package/apps/runtime/dist/texts.js +207 -0
- package/apps/runtime/dist/tools/browser.js +703 -0
- package/apps/runtime/dist/tools/connector.js +204 -0
- package/apps/runtime/dist/tools/index.js +291 -0
- package/apps/runtime/dist/tools/mail.js +104 -0
- package/apps/runtime/dist/tools/net-guard.js +170 -0
- package/apps/runtime/dist/tools/pages.js +81 -0
- package/apps/runtime/dist/tools/plugin.js +180 -0
- package/apps/runtime/dist/tools/project.js +154 -0
- package/apps/runtime/dist/tools/shared.js +69 -0
- package/apps/runtime/dist/tools/store.js +238 -0
- package/apps/runtime/dist/update.js +113 -0
- package/apps/runtime/dist/widgets/bundle.js +99 -0
- package/apps/runtime/dist/widgets/render.js +329 -0
- package/apps/runtime/dist/widgets/runtime.js +108 -0
- package/apps/runtime/dist/widgets/script.js +30 -0
- package/apps/runtime/dist/widgets/step.js +223 -0
- package/apps/web/dist/ai-labels/ai-black.svg +20 -0
- package/apps/web/dist/ai-labels/ai-generated-black.svg +31 -0
- package/apps/web/dist/ai-labels/ai-generated-white.svg +32 -0
- package/apps/web/dist/ai-labels/ai-modified-black.svg +30 -0
- package/apps/web/dist/ai-labels/ai-modified-white.svg +31 -0
- package/apps/web/dist/ai-labels/ai-white.svg +21 -0
- package/apps/web/dist/assets/AboutDialog-DYgXPagX.js +1 -0
- package/apps/web/dist/assets/ChangelogDialog-BXqBW8j3.js +1 -0
- package/apps/web/dist/assets/ChatView-CK2--tsE.js +10 -0
- package/apps/web/dist/assets/EditorPage-jvcwyXbU.js +3 -0
- package/apps/web/dist/assets/FlowPreview-CusP7ci9.js +1 -0
- package/apps/web/dist/assets/Harness-BrP-ENHg.css +1 -0
- package/apps/web/dist/assets/Harness-CV9uYzbv.js +16 -0
- package/apps/web/dist/assets/NewWizardChannels-BakW5q6s.js +1 -0
- package/apps/web/dist/assets/NewWizardPage-BoA-LJuW.js +7 -0
- package/apps/web/dist/assets/OnboardingPage-DaD1XnOe.js +1 -0
- package/apps/web/dist/assets/ProjectPage-BFgk1DEv.js +1 -0
- package/apps/web/dist/assets/PublicRunner-C9MwEvxy.js +1 -0
- package/apps/web/dist/assets/ReadOnly-DC2Kp7l8.js +1 -0
- package/apps/web/dist/assets/RunDrawer-CY6NZSrI.js +4 -0
- package/apps/web/dist/assets/RunnerView-BT26XgcY.js +1 -0
- package/apps/web/dist/assets/SettingsPage-AFt9IDLt.js +1 -0
- package/apps/web/dist/assets/SetupPage-DtFYAbwJ.js +1 -0
- package/apps/web/dist/assets/SharePage-t2xwNS61.js +1 -0
- package/apps/web/dist/assets/changelog-CATQFxCQ.js +1 -0
- package/apps/web/dist/assets/engenty-eXZ-EAwd.js +1 -0
- package/apps/web/dist/assets/esm-DXeMu8Lb.js +7 -0
- package/apps/web/dist/assets/fluffy-engenty-ClRou7yu.js +456 -0
- package/apps/web/dist/assets/index-AfUa8xKD.css +1 -0
- package/apps/web/dist/assets/index-Drw7FMTQ.js +14 -0
- package/apps/web/dist/assets/jsx-runtime-BNakU3Ej.js +1 -0
- package/apps/web/dist/assets/lock-R_CfU0Xo.js +1 -0
- package/apps/web/dist/assets/oss-credits-cZ9NUaLZ.js +1 -0
- package/apps/web/dist/assets/pdfmake-Cx9scTbD.js +228 -0
- package/apps/web/dist/assets/phone-CgrIS4_-.js +1 -0
- package/apps/web/dist/assets/preload-helper-CNEI7N0N.js +1 -0
- package/apps/web/dist/assets/qr-scanner-worker.min-CJaXo3yu.js +98 -0
- package/apps/web/dist/assets/qr-scanner.min-C_UI0gH-.js +1 -0
- package/apps/web/dist/assets/rolldown-runtime-hePW80VL.js +1 -0
- package/apps/web/dist/assets/settings-menu-2IMOOlLl.js +1 -0
- package/apps/web/dist/assets/ui-dzGvc3xk.js +137 -0
- package/apps/web/dist/assets/upload-BSuTilFF.js +1 -0
- package/apps/web/dist/assets/vfs_fonts-DllDSYt1.js +1 -0
- package/apps/web/dist/embed.js +266 -0
- package/apps/web/dist/favicon.svg +1 -0
- package/apps/web/dist/icons/apple-touch-icon.png +0 -0
- package/apps/web/dist/icons/icon-192.png +0 -0
- package/apps/web/dist/icons/icon-512.png +0 -0
- package/apps/web/dist/icons/icon-maskable-512.png +0 -0
- package/apps/web/dist/index.html +48 -0
- package/apps/web/dist/install.sh +577 -0
- package/apps/web/dist/manifest.webmanifest +21 -0
- package/apps/web/dist/mcp/flow.html +980 -0
- package/apps/web/dist/sw.js +15 -0
- package/bin/wizards.mjs +288 -0
- package/modules/README.md +15 -0
- package/node_modules/@engenty/wizards/dist/plugin/index.d.ts +1150 -0
- package/node_modules/@engenty/wizards/dist/plugin/index.js +4 -0
- package/node_modules/@engenty/wizards/dist/plugin/studio.d.ts +322 -0
- package/node_modules/@engenty/wizards/dist/plugin/studio.js +4 -0
- package/node_modules/@engenty/wizards/dist/plugin/thread.d.ts +174 -0
- package/node_modules/@engenty/wizards/dist/plugin/thread.js +821 -0
- package/node_modules/@engenty/wizards/package.json +11 -0
- package/node_modules/@engenty-wizards/shared/dist/assistant.d.ts +174 -0
- package/node_modules/@engenty-wizards/shared/dist/assistant.js +65 -0
- package/node_modules/@engenty-wizards/shared/dist/changes.d.ts +22 -0
- package/node_modules/@engenty-wizards/shared/dist/changes.js +61 -0
- package/node_modules/@engenty-wizards/shared/dist/connectors.d.ts +77 -0
- package/node_modules/@engenty-wizards/shared/dist/connectors.js +2 -0
- package/node_modules/@engenty-wizards/shared/dist/decision.d.ts +76 -0
- package/node_modules/@engenty-wizards/shared/dist/decision.js +147 -0
- package/node_modules/@engenty-wizards/shared/dist/definition.d.ts +2922 -0
- package/node_modules/@engenty-wizards/shared/dist/definition.js +1920 -0
- package/node_modules/@engenty-wizards/shared/dist/engenty/data-tables/columns-format.d.ts +5 -0
- package/node_modules/@engenty-wizards/shared/dist/engenty/data-tables/columns-format.js +132 -0
- package/node_modules/@engenty-wizards/shared/dist/engenty/data-tables/columns-value.d.ts +11 -0
- package/node_modules/@engenty-wizards/shared/dist/engenty/data-tables/columns-value.js +209 -0
- package/node_modules/@engenty-wizards/shared/dist/engenty/data-tables/columns.d.ts +532 -0
- package/node_modules/@engenty-wizards/shared/dist/engenty/data-tables/columns.js +217 -0
- package/node_modules/@engenty-wizards/shared/dist/engenty/data-tables/index.d.ts +3 -0
- package/node_modules/@engenty-wizards/shared/dist/engenty/data-tables/index.js +3 -0
- package/node_modules/@engenty-wizards/shared/dist/engenty/search-index/catalog-lexical.d.ts +14 -0
- package/node_modules/@engenty-wizards/shared/dist/engenty/search-index/catalog-lexical.js +166 -0
- package/node_modules/@engenty-wizards/shared/dist/engenty/search-index/catalog-rank.d.ts +33 -0
- package/node_modules/@engenty-wizards/shared/dist/engenty/search-index/catalog-rank.js +99 -0
- package/node_modules/@engenty-wizards/shared/dist/feature-flags.d.ts +78 -0
- package/node_modules/@engenty-wizards/shared/dist/feature-flags.js +70 -0
- package/node_modules/@engenty-wizards/shared/dist/features.d.ts +41 -0
- package/node_modules/@engenty-wizards/shared/dist/features.js +89 -0
- package/node_modules/@engenty-wizards/shared/dist/fit.d.ts +71 -0
- package/node_modules/@engenty-wizards/shared/dist/fit.js +382 -0
- package/node_modules/@engenty-wizards/shared/dist/json-schema.d.ts +14 -0
- package/node_modules/@engenty-wizards/shared/dist/json-schema.js +66 -0
- package/node_modules/@engenty-wizards/shared/dist/knowledge.d.ts +199 -0
- package/node_modules/@engenty-wizards/shared/dist/knowledge.js +68 -0
- package/node_modules/@engenty-wizards/shared/dist/marketplace-entry.d.ts +35 -0
- package/node_modules/@engenty-wizards/shared/dist/marketplace-entry.js +107 -0
- package/node_modules/@engenty-wizards/shared/dist/marketplace-search.d.ts +20 -0
- package/node_modules/@engenty-wizards/shared/dist/marketplace-search.js +136 -0
- package/node_modules/@engenty-wizards/shared/dist/marketplace.d.ts +227 -0
- package/node_modules/@engenty-wizards/shared/dist/marketplace.js +354 -0
- package/node_modules/@engenty-wizards/shared/dist/merge.d.ts +7 -0
- package/node_modules/@engenty-wizards/shared/dist/merge.js +40 -0
- package/node_modules/@engenty-wizards/shared/dist/numbers.d.ts +24 -0
- package/node_modules/@engenty-wizards/shared/dist/numbers.js +54 -0
- package/node_modules/@engenty-wizards/shared/dist/projects.d.ts +224 -0
- package/node_modules/@engenty-wizards/shared/dist/projects.js +319 -0
- package/node_modules/@engenty-wizards/shared/dist/providers.d.ts +101 -0
- package/node_modules/@engenty-wizards/shared/dist/providers.js +390 -0
- package/node_modules/@engenty-wizards/shared/dist/run.d.ts +680 -0
- package/node_modules/@engenty-wizards/shared/dist/run.js +620 -0
- package/node_modules/@engenty-wizards/shared/dist/runner-texts.d.ts +546 -0
- package/node_modules/@engenty-wizards/shared/dist/runner-texts.js +523 -0
- package/node_modules/@engenty-wizards/shared/dist/runners.d.ts +93 -0
- package/node_modules/@engenty-wizards/shared/dist/runners.js +146 -0
- package/node_modules/@engenty-wizards/shared/dist/shape.d.ts +102 -0
- package/node_modules/@engenty-wizards/shared/dist/shape.js +318 -0
- package/node_modules/@engenty-wizards/shared/dist/space-data.d.ts +89 -0
- package/node_modules/@engenty-wizards/shared/dist/space-data.js +47 -0
- package/node_modules/@engenty-wizards/shared/dist/store.d.ts +117 -0
- package/node_modules/@engenty-wizards/shared/dist/store.js +81 -0
- package/node_modules/@engenty-wizards/shared/dist/surface.d.ts +115 -0
- package/node_modules/@engenty-wizards/shared/dist/surface.js +442 -0
- package/node_modules/@engenty-wizards/shared/dist/texts.d.ts +45 -0
- package/node_modules/@engenty-wizards/shared/dist/texts.js +54 -0
- package/node_modules/@engenty-wizards/shared/dist/translation.d.ts +23 -0
- package/node_modules/@engenty-wizards/shared/dist/translation.js +154 -0
- package/node_modules/@engenty-wizards/shared/dist/wizard-package.d.ts +48 -0
- package/node_modules/@engenty-wizards/shared/dist/wizard-package.js +49 -0
- package/node_modules/@engenty-wizards/shared/dist/workspace.d.ts +16 -0
- package/node_modules/@engenty-wizards/shared/dist/workspace.js +51 -0
- package/node_modules/@engenty-wizards/shared/package.json +10 -0
- package/package.json +77 -4
- package/plugin/.claude-plugin/plugin.json +9 -0
- package/plugin/.mcp.json +8 -0
- package/plugin/commands/wizard.md +8 -0
- package/plugin/skills/build-wizard/SKILL.md +27 -0
- package/plugin/skills/use-wizard/SKILL.md +18 -0
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* Mail as wizards use it: read-only, and the same three actions whichever provider the person
|
|
4
|
+
* connected. Every mail connector is an engenty `ConnectorDefinition` whose actions are these.
|
|
5
|
+
*/
|
|
6
|
+
export const mailSearchInput = z.object({
|
|
7
|
+
terms: z
|
|
8
|
+
.array(z.string().min(1))
|
|
9
|
+
.max(12)
|
|
10
|
+
.optional()
|
|
11
|
+
.describe("Words to look for in subject and body; a mail matches when ANY of them occurs."),
|
|
12
|
+
from: z.string().optional().describe("Sender address or domain, e.g. billing@notion.so"),
|
|
13
|
+
since: z.string().optional().describe("First day, YYYY-MM-DD (inclusive)."),
|
|
14
|
+
until: z.string().optional().describe("Last day, YYYY-MM-DD (inclusive)."),
|
|
15
|
+
has_attachment: z.boolean().optional(),
|
|
16
|
+
limit: z.number().int().min(1).max(100).optional().describe("Newest first; default 40."),
|
|
17
|
+
});
|
|
18
|
+
export const mailReadInput = z.object({ id: z.string() });
|
|
19
|
+
export const mailAttachmentInput = z.object({ id: z.string(), attachment_id: z.string() });
|
|
20
|
+
export function mailActions(backend, providerScopes) {
|
|
21
|
+
return [
|
|
22
|
+
{
|
|
23
|
+
id: "search",
|
|
24
|
+
group: "read",
|
|
25
|
+
summary: "Search the mailbox",
|
|
26
|
+
description: "Search the mailbox, newest first. Returns id, date, sender, subject, a snippet and the attachments of each mail.",
|
|
27
|
+
inputSchema: mailSearchInput,
|
|
28
|
+
providerScopes,
|
|
29
|
+
handler: async (input, ctx) => ({
|
|
30
|
+
mails: await backend.search(mailSearchInput.parse(input), ctx),
|
|
31
|
+
}),
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
id: "read",
|
|
35
|
+
group: "read",
|
|
36
|
+
summary: "Read one mail",
|
|
37
|
+
description: "Read one mail in full: sender, recipients, text and attachments.",
|
|
38
|
+
inputSchema: mailReadInput,
|
|
39
|
+
providerScopes,
|
|
40
|
+
handler: (input, ctx) => backend.read(mailReadInput.parse(input).id, ctx),
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
id: "get_attachment",
|
|
44
|
+
group: "read",
|
|
45
|
+
summary: "Fetch an attachment",
|
|
46
|
+
description: "Fetch one attachment's bytes (base64).",
|
|
47
|
+
inputSchema: mailAttachmentInput,
|
|
48
|
+
providerScopes,
|
|
49
|
+
handler: (input, ctx) => {
|
|
50
|
+
const { id, attachment_id } = mailAttachmentInput.parse(input);
|
|
51
|
+
return backend.attachment(id, attachment_id, ctx);
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
];
|
|
55
|
+
}
|
|
56
|
+
/** Calls one of a mail connector's actions. */
|
|
57
|
+
export async function mailAction(connector, actionId, input, ctx) {
|
|
58
|
+
const action = connector.actions.find((a) => a.id === actionId);
|
|
59
|
+
if (!action) {
|
|
60
|
+
throw new Error(`${connector.name} has no action "${actionId}".`);
|
|
61
|
+
}
|
|
62
|
+
return (await action.handler(input, ctx));
|
|
63
|
+
}
|
|
64
|
+
export function snippetOf(text, length = 240) {
|
|
65
|
+
return text.replace(/\s+/g, " ").trim().slice(0, length);
|
|
66
|
+
}
|
|
67
|
+
/** The day after a YYYY-MM-DD date — for providers whose "before" is exclusive. */
|
|
68
|
+
export function dayAfter(day) {
|
|
69
|
+
const d = new Date(`${day}T00:00:00Z`);
|
|
70
|
+
d.setUTCDate(d.getUTCDate() + 1);
|
|
71
|
+
return d.toISOString().slice(0, 10);
|
|
72
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { bodyToText, graphJson, MICROSOFT_OAUTH2 } from "../engenty/connections-microsoft/graph.js";
|
|
2
|
+
import { mailActions, snippetOf, } from "./mail.js";
|
|
3
|
+
const SCOPE_READ = "Mail.Read";
|
|
4
|
+
const address = (a) => {
|
|
5
|
+
const e = a?.emailAddress;
|
|
6
|
+
return e?.address ? (e.name ? `${e.name} <${e.address}>` : e.address) : null;
|
|
7
|
+
};
|
|
8
|
+
/** KQL, the language of Graph's `$search` on messages. */
|
|
9
|
+
function kql(input) {
|
|
10
|
+
const quote = (t) => `"${t.replace(/["\\]/g, "")}"`;
|
|
11
|
+
const parts = [
|
|
12
|
+
input.terms?.length ? `(${input.terms.map(quote).join(" OR ")})` : "",
|
|
13
|
+
input.from ? `from:${quote(input.from)}` : "",
|
|
14
|
+
input.since || input.until
|
|
15
|
+
? `received:${input.since ?? "1990-01-01"}..${input.until ?? "2999-12-31"}`
|
|
16
|
+
: "",
|
|
17
|
+
input.has_attachment ? "hasAttachments:true" : "",
|
|
18
|
+
].filter(Boolean);
|
|
19
|
+
return parts.join(" AND ");
|
|
20
|
+
}
|
|
21
|
+
async function attachmentsOf(ctx, id) {
|
|
22
|
+
const data = await graphJson(ctx, `/me/messages/${encodeURIComponent(id)}/attachments?$select=id,name,contentType,size,isInline`);
|
|
23
|
+
return (data.value ?? [])
|
|
24
|
+
.filter((a) => !a.isInline)
|
|
25
|
+
.map((a) => ({
|
|
26
|
+
id: a.id,
|
|
27
|
+
name: a.name ?? "attachment",
|
|
28
|
+
mime: a.contentType ?? "application/octet-stream",
|
|
29
|
+
size: a.size ?? null,
|
|
30
|
+
}));
|
|
31
|
+
}
|
|
32
|
+
const SELECT = "id,subject,bodyPreview,receivedDateTime,hasAttachments,from";
|
|
33
|
+
const backend = {
|
|
34
|
+
async search(input, ctx) {
|
|
35
|
+
const params = new URLSearchParams({ $select: SELECT, $top: String(input.limit ?? 40) });
|
|
36
|
+
const search = kql(input);
|
|
37
|
+
if (search) {
|
|
38
|
+
params.set("$search", `"${search.replace(/"/g, '\\"')}"`);
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
params.set("$orderby", "receivedDateTime desc");
|
|
42
|
+
}
|
|
43
|
+
const data = await graphJson(ctx, `/me/messages?${params}`);
|
|
44
|
+
const messages = data.value ?? [];
|
|
45
|
+
return Promise.all(messages.map(async (m) => ({
|
|
46
|
+
id: m.id,
|
|
47
|
+
date: m.receivedDateTime ?? null,
|
|
48
|
+
from: address(m.from),
|
|
49
|
+
subject: m.subject ?? null,
|
|
50
|
+
snippet: snippetOf(m.bodyPreview ?? ""),
|
|
51
|
+
attachments: m.hasAttachments ? await attachmentsOf(ctx, m.id) : [],
|
|
52
|
+
})));
|
|
53
|
+
},
|
|
54
|
+
async read(id, ctx) {
|
|
55
|
+
const m = await graphJson(ctx, `/me/messages/${encodeURIComponent(id)}?$select=${SELECT},toRecipients,body`);
|
|
56
|
+
const text = bodyToText(m.body);
|
|
57
|
+
return {
|
|
58
|
+
id: m.id,
|
|
59
|
+
date: m.receivedDateTime ?? null,
|
|
60
|
+
from: address(m.from),
|
|
61
|
+
to: (m.toRecipients ?? []).map(address).filter((a) => Boolean(a)),
|
|
62
|
+
subject: m.subject ?? null,
|
|
63
|
+
snippet: snippetOf(m.bodyPreview ?? text),
|
|
64
|
+
attachments: m.hasAttachments ? await attachmentsOf(ctx, m.id) : [],
|
|
65
|
+
text,
|
|
66
|
+
html: m.body?.contentType?.toLowerCase() === "html" ? (m.body.content ?? null) : null,
|
|
67
|
+
};
|
|
68
|
+
},
|
|
69
|
+
async attachment(id, attachmentId, ctx) {
|
|
70
|
+
const a = await graphJson(ctx, `/me/messages/${encodeURIComponent(id)}/attachments/${encodeURIComponent(attachmentId)}`);
|
|
71
|
+
if (!a.contentBytes) {
|
|
72
|
+
throw new Error("This attachment is not a file.");
|
|
73
|
+
}
|
|
74
|
+
return {
|
|
75
|
+
name: a.name ?? "attachment",
|
|
76
|
+
mime: a.contentType ?? "application/octet-stream",
|
|
77
|
+
data_base64: a.contentBytes,
|
|
78
|
+
};
|
|
79
|
+
},
|
|
80
|
+
};
|
|
81
|
+
export const outlookConnector = {
|
|
82
|
+
id: "mail-outlook",
|
|
83
|
+
moduleId: "wizards-mail",
|
|
84
|
+
name: "Outlook",
|
|
85
|
+
description: "Read mail in an Outlook or Microsoft 365 account.",
|
|
86
|
+
icon: "logo:outlook",
|
|
87
|
+
toolPrefix: "mail",
|
|
88
|
+
auth: { kind: "oauth2", oauth2: MICROSOFT_OAUTH2 },
|
|
89
|
+
actions: mailActions(backend, [SCOPE_READ]),
|
|
90
|
+
};
|
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
import { and, desc, eq } from "drizzle-orm";
|
|
2
|
+
import { nanoid } from "nanoid";
|
|
3
|
+
import { db, schema } from "../db/client.js";
|
|
4
|
+
import { buildAuthorizationUrl, createOAuth2Pkce, exchangeAuthorizationCode, refreshAccessToken, } from "../engenty/connections-sdk/oauth2.js";
|
|
5
|
+
import { seal, unseal } from "../secrets/crypto.js";
|
|
6
|
+
import { currentTenant } from "../tenants/tenant.js";
|
|
7
|
+
import { builtinConnector, connectorFetch, resolveEnv, usable, viaAccount } from "./builtin.js";
|
|
8
|
+
import { connectRedirectUri as redirectUri } from "./index.js";
|
|
9
|
+
import { AccountConnectError, redeemTicket, refreshThroughAccount, startThroughAccount, } from "./via-account.js";
|
|
10
|
+
function oauthConnector(id) {
|
|
11
|
+
const connector = builtinConnector(id);
|
|
12
|
+
if (connector?.auth.kind !== "oauth2") {
|
|
13
|
+
throw new Error(`"${id}" is not a built-in connector that signs in.`);
|
|
14
|
+
}
|
|
15
|
+
return connector;
|
|
16
|
+
}
|
|
17
|
+
/** A built-in connector a plugin may connect: signed in, or with keys. */
|
|
18
|
+
function connectorOf(id) {
|
|
19
|
+
const connector = builtinConnector(id);
|
|
20
|
+
if (!connector || connector.auth.kind === "browser") {
|
|
21
|
+
throw new Error(`"${id}" is not a built-in connector a plugin can connect.`);
|
|
22
|
+
}
|
|
23
|
+
return connector;
|
|
24
|
+
}
|
|
25
|
+
/** The actions a connection is made for exist on the connector. */
|
|
26
|
+
function knownActions(connector, actions) {
|
|
27
|
+
for (const id of actions) {
|
|
28
|
+
if (!connector.actions.some((a) => a.id === id)) {
|
|
29
|
+
throw new Error(`${connector.name} has no action "${id}".`);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return [...new Set(actions)];
|
|
33
|
+
}
|
|
34
|
+
async function spaceExists(space) {
|
|
35
|
+
const project = await db.query.project.findFirst({
|
|
36
|
+
where: eq(schema.project.id, space),
|
|
37
|
+
columns: { id: true },
|
|
38
|
+
});
|
|
39
|
+
if (!project) {
|
|
40
|
+
throw new Error(`There’s no space “${space}”.`);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
/** Keeps a connection: the same account for the same space again replaces the first one. */
|
|
44
|
+
async function keep(input) {
|
|
45
|
+
const same = await db.query.pluginConnection.findFirst({
|
|
46
|
+
where: and(eq(schema.pluginConnection.plugin, input.plugin), eq(schema.pluginConnection.projectId, input.projectId), eq(schema.pluginConnection.connector, input.connector), eq(schema.pluginConnection.label, input.label)),
|
|
47
|
+
});
|
|
48
|
+
if (same) {
|
|
49
|
+
const [row] = await db
|
|
50
|
+
.update(schema.pluginConnection)
|
|
51
|
+
.set({ actions: input.actions, data: seal(input.stored), updatedAt: new Date() })
|
|
52
|
+
.where(eq(schema.pluginConnection.id, same.id))
|
|
53
|
+
.returning();
|
|
54
|
+
return row;
|
|
55
|
+
}
|
|
56
|
+
const [row] = await db
|
|
57
|
+
.insert(schema.pluginConnection)
|
|
58
|
+
.values({
|
|
59
|
+
id: nanoid(14),
|
|
60
|
+
plugin: input.plugin,
|
|
61
|
+
projectId: input.projectId,
|
|
62
|
+
connector: input.connector,
|
|
63
|
+
label: input.label,
|
|
64
|
+
actions: input.actions,
|
|
65
|
+
data: seal(input.stored),
|
|
66
|
+
})
|
|
67
|
+
.returning();
|
|
68
|
+
return row;
|
|
69
|
+
}
|
|
70
|
+
/** The provider rights the named actions need, and the connector's own base rights. */
|
|
71
|
+
function scopesOf(connector, actions) {
|
|
72
|
+
const scopes = new Set(connector.auth.kind === "oauth2" ? connector.auth.oauth2.baseScopes : []);
|
|
73
|
+
for (const id of actions) {
|
|
74
|
+
const action = connector.actions.find((a) => a.id === id);
|
|
75
|
+
if (!action) {
|
|
76
|
+
throw new Error(`${connector.name} has no action "${id}".`);
|
|
77
|
+
}
|
|
78
|
+
for (const scope of action.providerScopes ?? []) {
|
|
79
|
+
scopes.add(scope);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return [...scopes];
|
|
83
|
+
}
|
|
84
|
+
const view = (row) => ({
|
|
85
|
+
id: row.id,
|
|
86
|
+
space: row.projectId,
|
|
87
|
+
connector: row.connector,
|
|
88
|
+
label: row.label,
|
|
89
|
+
actions: row.actions,
|
|
90
|
+
createdAt: row.createdAt.toISOString(),
|
|
91
|
+
});
|
|
92
|
+
/** A state the callback can tell is a plugin's: the tenant to finish it in, or null. */
|
|
93
|
+
export function pluginStateTenant(rawState) {
|
|
94
|
+
const state = unseal(rawState);
|
|
95
|
+
return state && typeof state.plugin === "string" ? state.tenantId : null;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* The provider came back for a plugin's sign-in: keeps the account. A second sign-in to the
|
|
99
|
+
* same account for the same space replaces the first one's tokens.
|
|
100
|
+
*/
|
|
101
|
+
export async function finishPluginOAuth(answer, rawState) {
|
|
102
|
+
const state = unseal(rawState);
|
|
103
|
+
if (!state?.plugin || state.exp < Date.now()) {
|
|
104
|
+
throw new Error("The sign-in has expired. Connect again.");
|
|
105
|
+
}
|
|
106
|
+
const connector = oauthConnector(state.connectorId);
|
|
107
|
+
if (connector.auth.kind !== "oauth2") {
|
|
108
|
+
throw new Error("not an oauth connector");
|
|
109
|
+
}
|
|
110
|
+
const tokens = "ticket" in answer
|
|
111
|
+
? await redeemTicket(answer.ticket)
|
|
112
|
+
: await exchangeAuthorizationCode({
|
|
113
|
+
code: answer.code,
|
|
114
|
+
codeVerifier: state.verifier,
|
|
115
|
+
config: connector.auth.oauth2,
|
|
116
|
+
redirectUri: redirectUri(),
|
|
117
|
+
resolveEnv,
|
|
118
|
+
});
|
|
119
|
+
const account = (await connector.auth.oauth2
|
|
120
|
+
.resolveAccount?.(tokens.accessToken, fetch)
|
|
121
|
+
.catch(() => null)) ?? { label: connector.name };
|
|
122
|
+
const stored = {
|
|
123
|
+
accessToken: tokens.accessToken,
|
|
124
|
+
refreshToken: tokens.refreshToken,
|
|
125
|
+
expiresAt: tokens.expiresAt?.toISOString() ?? null,
|
|
126
|
+
scopes: tokens.grantedScopes,
|
|
127
|
+
...("ticket" in answer ? { via: "account" } : {}),
|
|
128
|
+
};
|
|
129
|
+
await keep({
|
|
130
|
+
plugin: state.plugin,
|
|
131
|
+
projectId: state.projectId,
|
|
132
|
+
connector: connector.id,
|
|
133
|
+
label: account.label,
|
|
134
|
+
actions: state.actions,
|
|
135
|
+
stored,
|
|
136
|
+
});
|
|
137
|
+
return { plugin: state.plugin, projectId: state.projectId };
|
|
138
|
+
}
|
|
139
|
+
/** The tokens of a connection, refreshed when they run out within five minutes. */
|
|
140
|
+
async function freshTokens(row, connector) {
|
|
141
|
+
let data = unseal(row.data);
|
|
142
|
+
if (!data) {
|
|
143
|
+
throw new Error("The connection's keys cannot be read here. Connect the account again.");
|
|
144
|
+
}
|
|
145
|
+
const expires = data.expiresAt ? Date.parse(data.expiresAt) : null;
|
|
146
|
+
if (connector.auth.kind === "oauth2" &&
|
|
147
|
+
data.refreshToken &&
|
|
148
|
+
expires !== null &&
|
|
149
|
+
expires - Date.now() < 5 * 60_000) {
|
|
150
|
+
const tokens = data.via === "account"
|
|
151
|
+
? await refreshThroughAccount(data.refreshToken)
|
|
152
|
+
: await refreshAccessToken({
|
|
153
|
+
config: connector.auth.oauth2,
|
|
154
|
+
refreshToken: data.refreshToken,
|
|
155
|
+
resolveEnv,
|
|
156
|
+
});
|
|
157
|
+
data = {
|
|
158
|
+
...(data.via ? { via: data.via } : {}),
|
|
159
|
+
accessToken: tokens.accessToken,
|
|
160
|
+
refreshToken: tokens.refreshToken ?? data.refreshToken,
|
|
161
|
+
expiresAt: tokens.expiresAt?.toISOString() ?? null,
|
|
162
|
+
scopes: tokens.grantedScopes.length ? tokens.grantedScopes : data.scopes,
|
|
163
|
+
};
|
|
164
|
+
await db
|
|
165
|
+
.update(schema.pluginConnection)
|
|
166
|
+
.set({ data: seal(data), updatedAt: new Date() })
|
|
167
|
+
.where(eq(schema.pluginConnection.id, row.id));
|
|
168
|
+
}
|
|
169
|
+
return data;
|
|
170
|
+
}
|
|
171
|
+
function contextOf(row, connector, data) {
|
|
172
|
+
const ctx = {
|
|
173
|
+
accessToken: data.accessToken,
|
|
174
|
+
fetchImpl: connectorFetch,
|
|
175
|
+
log: () => undefined,
|
|
176
|
+
connection: {
|
|
177
|
+
id: row.id,
|
|
178
|
+
connector_id: connector.id,
|
|
179
|
+
auth_kind: connector.auth.kind,
|
|
180
|
+
autonomous_mode: "read_only",
|
|
181
|
+
connected_by: row.createdBy,
|
|
182
|
+
created_at: row.createdAt.toISOString(),
|
|
183
|
+
display_name: row.label,
|
|
184
|
+
error_message: null,
|
|
185
|
+
external_account: row.label,
|
|
186
|
+
granted_scopes: data.scopes,
|
|
187
|
+
owner_user_id: null,
|
|
188
|
+
space_id: row.projectId,
|
|
189
|
+
status: "active",
|
|
190
|
+
tenant_id: currentTenant(),
|
|
191
|
+
},
|
|
192
|
+
};
|
|
193
|
+
return ctx;
|
|
194
|
+
}
|
|
195
|
+
/** `server.connections` of one plugin; every call runs inside the current tenant. */
|
|
196
|
+
export function pluginConnections(plugin) {
|
|
197
|
+
const own = (id) => db.query.pluginConnection.findFirst({
|
|
198
|
+
where: and(eq(schema.pluginConnection.id, id), eq(schema.pluginConnection.plugin, plugin)),
|
|
199
|
+
});
|
|
200
|
+
return {
|
|
201
|
+
async available(ids) {
|
|
202
|
+
const out = [];
|
|
203
|
+
for (const id of ids) {
|
|
204
|
+
const connector = builtinConnector(id);
|
|
205
|
+
if (!connector || connector.auth.kind === "browser" || !(await usable(connector))) {
|
|
206
|
+
continue;
|
|
207
|
+
}
|
|
208
|
+
out.push(connector.auth.kind === "api_key"
|
|
209
|
+
? {
|
|
210
|
+
id,
|
|
211
|
+
name: connector.name,
|
|
212
|
+
auth: "api_key",
|
|
213
|
+
fields: connector.auth.apiKey.fields.map((f) => ({
|
|
214
|
+
key: f.key,
|
|
215
|
+
label: f.label,
|
|
216
|
+
...(f.placeholder ? { placeholder: f.placeholder } : {}),
|
|
217
|
+
...(f.required === false ? { required: false } : {}),
|
|
218
|
+
...(f.secret ? { secret: true } : {}),
|
|
219
|
+
})),
|
|
220
|
+
}
|
|
221
|
+
: { id, name: connector.name, auth: "oauth2" });
|
|
222
|
+
}
|
|
223
|
+
return out;
|
|
224
|
+
},
|
|
225
|
+
async start({ space, connector: connectorId, actions, lang }) {
|
|
226
|
+
const connector = oauthConnector(connectorId);
|
|
227
|
+
if (connector.auth.kind !== "oauth2") {
|
|
228
|
+
throw new Error("not an oauth connector");
|
|
229
|
+
}
|
|
230
|
+
await spaceExists(space);
|
|
231
|
+
const scopes = scopesOf(connector, actions);
|
|
232
|
+
const base = {
|
|
233
|
+
plugin,
|
|
234
|
+
tenantId: currentTenant(),
|
|
235
|
+
projectId: space,
|
|
236
|
+
connectorId,
|
|
237
|
+
actions: [...new Set(actions)],
|
|
238
|
+
exp: Date.now() + 15 * 60_000,
|
|
239
|
+
lang,
|
|
240
|
+
};
|
|
241
|
+
if (await viaAccount(connector)) {
|
|
242
|
+
// The Manage-App keeps the PKCE verifier; ours stays empty.
|
|
243
|
+
try {
|
|
244
|
+
const url = await startThroughAccount(scopes, seal({ ...base, verifier: "" }), redirectUri());
|
|
245
|
+
return { url };
|
|
246
|
+
}
|
|
247
|
+
catch (err) {
|
|
248
|
+
throw err instanceof AccountConnectError
|
|
249
|
+
? Object.assign(new Error(err.message), { status: 409, code: "account" })
|
|
250
|
+
: err;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
await connector.auth.oauth2.registerClient?.();
|
|
254
|
+
const pkce = createOAuth2Pkce();
|
|
255
|
+
const url = await buildAuthorizationUrl({
|
|
256
|
+
connector,
|
|
257
|
+
pkce,
|
|
258
|
+
redirectUri: redirectUri(),
|
|
259
|
+
scopes,
|
|
260
|
+
state: seal({ ...base, verifier: pkce.codeVerifier }),
|
|
261
|
+
resolveEnv,
|
|
262
|
+
});
|
|
263
|
+
return { url };
|
|
264
|
+
},
|
|
265
|
+
async connect({ space, connector: connectorId, actions, credentials }) {
|
|
266
|
+
const connector = connectorOf(connectorId);
|
|
267
|
+
if (connector.auth.kind !== "api_key") {
|
|
268
|
+
throw new Error(`${connector.name} is connected by signing in: use start.`);
|
|
269
|
+
}
|
|
270
|
+
await spaceExists(space);
|
|
271
|
+
const wanted = knownActions(connector, actions);
|
|
272
|
+
const keys = {};
|
|
273
|
+
for (const field of connector.auth.apiKey.fields) {
|
|
274
|
+
const value = String(credentials[field.key] ?? "").trim();
|
|
275
|
+
if (!value && field.required !== false) {
|
|
276
|
+
throw Object.assign(new Error(`"${field.label}" is missing.`), {
|
|
277
|
+
status: 400,
|
|
278
|
+
code: "credentials",
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
if (value) {
|
|
282
|
+
keys[field.key] = value.slice(0, 500);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
let account;
|
|
286
|
+
try {
|
|
287
|
+
account = await connector.auth.apiKey.verify(keys, connectorFetch);
|
|
288
|
+
}
|
|
289
|
+
catch (err) {
|
|
290
|
+
throw Object.assign(new Error(String(err?.message ?? err).slice(0, 300)), {
|
|
291
|
+
status: 400,
|
|
292
|
+
code: "credentials",
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
const row = await keep({
|
|
296
|
+
plugin,
|
|
297
|
+
projectId: space,
|
|
298
|
+
connector: connector.id,
|
|
299
|
+
label: account.label,
|
|
300
|
+
actions: wanted,
|
|
301
|
+
stored: {
|
|
302
|
+
accessToken: JSON.stringify(keys),
|
|
303
|
+
refreshToken: null,
|
|
304
|
+
expiresAt: null,
|
|
305
|
+
scopes: [],
|
|
306
|
+
},
|
|
307
|
+
});
|
|
308
|
+
return view(row);
|
|
309
|
+
},
|
|
310
|
+
async list(space) {
|
|
311
|
+
const rows = await db.query.pluginConnection.findMany({
|
|
312
|
+
where: and(eq(schema.pluginConnection.plugin, plugin), eq(schema.pluginConnection.projectId, space)),
|
|
313
|
+
orderBy: [desc(schema.pluginConnection.createdAt)],
|
|
314
|
+
});
|
|
315
|
+
return rows.map(view);
|
|
316
|
+
},
|
|
317
|
+
async get(id) {
|
|
318
|
+
const row = await own(id);
|
|
319
|
+
return row ? view(row) : null;
|
|
320
|
+
},
|
|
321
|
+
async call(id, actionId, input) {
|
|
322
|
+
const row = await own(id);
|
|
323
|
+
if (!row) {
|
|
324
|
+
throw new Error(`There is no connection "${id}".`);
|
|
325
|
+
}
|
|
326
|
+
if (!row.actions.includes(actionId)) {
|
|
327
|
+
throw new Error(`The connection was not made for "${actionId}". Connect it again.`);
|
|
328
|
+
}
|
|
329
|
+
const connector = connectorOf(row.connector);
|
|
330
|
+
const action = connector.actions.find((a) => a.id === actionId);
|
|
331
|
+
if (!action) {
|
|
332
|
+
throw new Error(`${connector.name} has no action "${actionId}".`);
|
|
333
|
+
}
|
|
334
|
+
const data = await freshTokens(row, connector);
|
|
335
|
+
return (await action.handler(action.inputSchema.parse(input), contextOf(row, connector, data)));
|
|
336
|
+
},
|
|
337
|
+
async remove(id) {
|
|
338
|
+
await db
|
|
339
|
+
.delete(schema.pluginConnection)
|
|
340
|
+
.where(and(eq(schema.pluginConnection.id, id), eq(schema.pluginConnection.plugin, plugin)));
|
|
341
|
+
},
|
|
342
|
+
};
|
|
343
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { note } from "@engenty-wizards/shared/run";
|
|
2
|
+
import { accountToken } from "../auth/account.js";
|
|
3
|
+
import { env } from "../env.js";
|
|
4
|
+
import { NotedError } from "../model-errors.js";
|
|
5
|
+
/*
|
|
6
|
+
* Google accounts on a local install without an OAuth client of its own: the Manage-App of the
|
|
7
|
+
* linked account runs the consent at Google with its client and hands the tokens over, and
|
|
8
|
+
* refreshes them later (docs/manage-contract.md, "Google accounts through the Manage-App").
|
|
9
|
+
*/
|
|
10
|
+
const base = () => `${env.local.accountUrl}/v1/connect`;
|
|
11
|
+
/** Something the person can mend or retry; the message is for them. */
|
|
12
|
+
export class AccountConnectError extends NotedError {
|
|
13
|
+
}
|
|
14
|
+
let offered = null;
|
|
15
|
+
/** Whether the Manage-App connects Google accounts; asked at most every ten minutes. */
|
|
16
|
+
export async function googleThroughAccount() {
|
|
17
|
+
if (offered && Date.now() - offered.at < (offered.google ? 600_000 : 60_000)) {
|
|
18
|
+
return offered.google;
|
|
19
|
+
}
|
|
20
|
+
const google = await fetch(base(), { signal: AbortSignal.timeout(5000) })
|
|
21
|
+
.then(async (res) => res.ok ? (await res.json()).google === true : false)
|
|
22
|
+
.catch(() => false);
|
|
23
|
+
offered = { at: Date.now(), google };
|
|
24
|
+
return google;
|
|
25
|
+
}
|
|
26
|
+
async function call(path, body) {
|
|
27
|
+
const token = await accountToken();
|
|
28
|
+
if (!token) {
|
|
29
|
+
throw new AccountConnectError(note("connectEngentyAccountFirst"));
|
|
30
|
+
}
|
|
31
|
+
const res = await fetch(`${base()}${path}`, {
|
|
32
|
+
method: "POST",
|
|
33
|
+
headers: { authorization: `Bearer ${token}`, "content-type": "application/json" },
|
|
34
|
+
body: JSON.stringify(body),
|
|
35
|
+
signal: AbortSignal.timeout(20_000),
|
|
36
|
+
}).catch(() => null);
|
|
37
|
+
if (!res) {
|
|
38
|
+
throw new AccountConnectError(note("engentyAccountNotReached"));
|
|
39
|
+
}
|
|
40
|
+
const data = (await res.json().catch(() => ({})));
|
|
41
|
+
if (!res.ok) {
|
|
42
|
+
throw new AccountConnectError(data.code === "invalid_grant"
|
|
43
|
+
? note("googleNoLongerAccepts")
|
|
44
|
+
: data.code === "not_configured"
|
|
45
|
+
? note("googleNotConnectedThrough")
|
|
46
|
+
: note("viaAccountFailed", { code: data.code ?? res.status }));
|
|
47
|
+
}
|
|
48
|
+
return data;
|
|
49
|
+
}
|
|
50
|
+
const tokensOf = (t) => ({
|
|
51
|
+
accessToken: t.access_token,
|
|
52
|
+
refreshToken: t.refresh_token ?? null,
|
|
53
|
+
expiresAt: t.expires_in ? new Date(Date.now() + t.expires_in * 1000) : null,
|
|
54
|
+
grantedScopes: (t.scope ?? "").split(/\s+/).filter(Boolean),
|
|
55
|
+
});
|
|
56
|
+
/** Google's consent page for these scopes; Google comes back to `returnUrl` with a ticket. */
|
|
57
|
+
export async function startThroughAccount(scopes, state, returnUrl) {
|
|
58
|
+
return (await call("/google/start", { scopes, state, returnUrl })).url;
|
|
59
|
+
}
|
|
60
|
+
export async function redeemTicket(ticket) {
|
|
61
|
+
return tokensOf(await call("/google/redeem", { ticket }));
|
|
62
|
+
}
|
|
63
|
+
export async function refreshThroughAccount(refreshToken) {
|
|
64
|
+
return tokensOf(await call("/google/refresh", { refreshToken }));
|
|
65
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { sql } from "drizzle-orm";
|
|
2
|
+
import { db, schema } from "../db/client.js";
|
|
3
|
+
import { ManageError, managed, release, reserve, runUsage, tenantInfo } from "../manage.js";
|
|
4
|
+
import { currentTenant } from "../tenants/tenant.js";
|
|
5
|
+
/**
|
|
6
|
+
* Credits live in the Manage-App: its gateway books every model call. The runtime only asks
|
|
7
|
+
* whether a tenant may start, reserves before a run and reads what a run cost. A runtime that
|
|
8
|
+
* runs alone has no credits; it keeps the provider cost of a run for display (1 credit = 1 cent).
|
|
9
|
+
*/
|
|
10
|
+
export const MICROS_PER_CREDIT = 1_000_000;
|
|
11
|
+
export function usdToMicros(usd) {
|
|
12
|
+
return Math.ceil(usd * 100 * MICROS_PER_CREDIT);
|
|
13
|
+
}
|
|
14
|
+
/** At least one credit left — enough to start something. */
|
|
15
|
+
export async function canSpend() {
|
|
16
|
+
if (!managed) {
|
|
17
|
+
return true;
|
|
18
|
+
}
|
|
19
|
+
try {
|
|
20
|
+
const t = await tenantInfo(currentTenant());
|
|
21
|
+
return t.status === "active" && t.balanceCredits >= 1;
|
|
22
|
+
}
|
|
23
|
+
catch (err) {
|
|
24
|
+
console.error("[credits]", err);
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
export async function balanceCredits() {
|
|
29
|
+
if (!managed) {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
return (await tenantInfo(currentTenant(), true).catch(() => null))?.balanceCredits ?? null;
|
|
33
|
+
}
|
|
34
|
+
/** Holds credits for a run before it starts. False = the free balance does not cover it. */
|
|
35
|
+
export async function reserveForRun(runId, credits) {
|
|
36
|
+
if (!managed || credits <= 0) {
|
|
37
|
+
return true;
|
|
38
|
+
}
|
|
39
|
+
try {
|
|
40
|
+
await reserve(currentTenant(), runId, Math.ceil(credits));
|
|
41
|
+
return true;
|
|
42
|
+
}
|
|
43
|
+
catch (err) {
|
|
44
|
+
if (err instanceof ManageError && err.status === 402) {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
throw err;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
export async function releaseRun(runId) {
|
|
51
|
+
if (managed) {
|
|
52
|
+
await release(runId).catch((err) => console.error("[credits] release", err));
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
async function setStepCost(runId, stepId, micros) {
|
|
56
|
+
await db
|
|
57
|
+
.insert(schema.runCost)
|
|
58
|
+
.values({ runId, stepId, micros })
|
|
59
|
+
.onConflictDoUpdate({
|
|
60
|
+
target: [schema.runCost.runId, schema.runCost.stepId],
|
|
61
|
+
set: { micros },
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
/** What the ledger booked for the run so far, written to the run and its steps. */
|
|
65
|
+
export async function syncRunCost(runId) {
|
|
66
|
+
if (!managed) {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
try {
|
|
70
|
+
const usage = await runUsage(currentTenant(), runId);
|
|
71
|
+
await db
|
|
72
|
+
.update(schema.run)
|
|
73
|
+
.set({ costMicros: Math.round(usage.credits * MICROS_PER_CREDIT) })
|
|
74
|
+
.where(sql `${schema.run.id} = ${runId}`);
|
|
75
|
+
for (const [stepId, credits] of Object.entries(usage.steps)) {
|
|
76
|
+
await setStepCost(runId, stepId, Math.round(credits * MICROS_PER_CREDIT));
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
catch (err) {
|
|
80
|
+
console.error("[credits] usage", err);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
/** A runtime that runs alone adds up the provider cost itself. */
|
|
84
|
+
export async function addLocalCost(runId, stepId, usd) {
|
|
85
|
+
const micros = usdToMicros(usd);
|
|
86
|
+
if (managed || micros <= 0) {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
await db
|
|
90
|
+
.update(schema.run)
|
|
91
|
+
.set({ costMicros: sql `${schema.run.costMicros} + ${micros}` })
|
|
92
|
+
.where(sql `${schema.run.id} = ${runId}`);
|
|
93
|
+
await db
|
|
94
|
+
.insert(schema.runCost)
|
|
95
|
+
.values({ runId, stepId, micros })
|
|
96
|
+
.onConflictDoUpdate({
|
|
97
|
+
target: [schema.runCost.runId, schema.runCost.stepId],
|
|
98
|
+
set: { micros: sql `${schema.runCost.micros} + ${micros}` },
|
|
99
|
+
});
|
|
100
|
+
}
|