@engenty/wizards-runtime 0.0.0-stage → 0.7.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +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 +93 -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 +222 -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/setup.js +335 -0
- package/apps/runtime/dist/cli/start.js +276 -0
- package/apps/runtime/dist/cli/status.js +203 -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 +196 -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 +83 -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 +295 -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/docker.js +75 -0
- package/apps/runtime/dist/sandbox/index.js +23 -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 +656 -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-D4mvc-zu.js +1 -0
- package/apps/web/dist/assets/ChangelogDialog-DLqpJsF6.js +1 -0
- package/apps/web/dist/assets/ChatView-3laypRcE.js +10 -0
- package/apps/web/dist/assets/EditorPage-BalA5U2Y.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-iYLtOLaK.js +16 -0
- package/apps/web/dist/assets/NewWizardChannels-CbwJ9A56.js +1 -0
- package/apps/web/dist/assets/NewWizardPage-BOBYiB9i.js +7 -0
- package/apps/web/dist/assets/OnboardingPage-CUwCiVIr.js +1 -0
- package/apps/web/dist/assets/ProjectPage-Bb16MdYG.js +1 -0
- package/apps/web/dist/assets/PublicRunner-BCt7Q6C-.js +1 -0
- package/apps/web/dist/assets/ReadOnly-kIHX2TEy.js +1 -0
- package/apps/web/dist/assets/RunDrawer-hZ9oeSXu.js +4 -0
- package/apps/web/dist/assets/RunnerView-DUS9fPmx.js +1 -0
- package/apps/web/dist/assets/SettingsPage-BzwR50fi.js +1 -0
- package/apps/web/dist/assets/SetupPage-gAp7rPxp.js +1 -0
- package/apps/web/dist/assets/SharePage-DqZWHva_.js +1 -0
- package/apps/web/dist/assets/changelog-DugmCNSf.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-C5Sm7tTR.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,30 @@
|
|
|
1
|
+
import { Hono } from "hono";
|
|
2
|
+
import { streamSSE } from "hono/streaming";
|
|
3
|
+
import { subscribeDraft } from "../services/draft-events.js";
|
|
4
|
+
import { ownedWizard } from "../services/wizards.js";
|
|
5
|
+
/**
|
|
6
|
+
* Live changes to a wizard the editor has open — from an MCP client, the architect or another
|
|
7
|
+
* tab. The editor refetches on `change`; `hello` carries the revision to catch up after a gap.
|
|
8
|
+
*/
|
|
9
|
+
export const wizardStream = new Hono().get("/:id/stream", async (c) => {
|
|
10
|
+
const w = await ownedWizard(c.get("user").id, c.req.param("id"));
|
|
11
|
+
return streamSSE(c, async (stream) => {
|
|
12
|
+
let closed = false;
|
|
13
|
+
const unsubscribe = subscribeDraft(w.id, (change) => {
|
|
14
|
+
if (!closed) {
|
|
15
|
+
void stream.writeSSE({ event: "change", data: JSON.stringify(change) });
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
stream.onAbort(() => {
|
|
19
|
+
closed = true;
|
|
20
|
+
unsubscribe();
|
|
21
|
+
});
|
|
22
|
+
await stream.writeSSE({ event: "hello", data: JSON.stringify({ revision: w.revision }) });
|
|
23
|
+
while (!closed) {
|
|
24
|
+
await stream.sleep(20_000);
|
|
25
|
+
if (!closed) {
|
|
26
|
+
await stream.writeSSE({ event: "ping", data: "" });
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
});
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
const FILE = "running.json";
|
|
4
|
+
export function writeRunning(dataDir, running) {
|
|
5
|
+
mkdirSync(dataDir, { recursive: true });
|
|
6
|
+
writeFileSync(join(dataDir, FILE), `${JSON.stringify(running, null, 2)}\n`, { mode: 0o600 });
|
|
7
|
+
}
|
|
8
|
+
function alive(pid) {
|
|
9
|
+
try {
|
|
10
|
+
process.kill(pid, 0);
|
|
11
|
+
return true;
|
|
12
|
+
}
|
|
13
|
+
catch (error) {
|
|
14
|
+
// EPERM: the process exists and belongs to somebody else.
|
|
15
|
+
return error.code === "EPERM";
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
/** The runtime that holds this data folder, if its process still exists. */
|
|
19
|
+
export function readRunning(dataDir) {
|
|
20
|
+
try {
|
|
21
|
+
const running = JSON.parse(readFileSync(join(dataDir, FILE), "utf8"));
|
|
22
|
+
return Number.isInteger(running.pid) && alive(running.pid) ? running : null;
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
/** Takes the note away, unless another runtime wrote it meanwhile. */
|
|
29
|
+
export function clearRunning(dataDir, pid = process.pid) {
|
|
30
|
+
try {
|
|
31
|
+
const running = JSON.parse(readFileSync(join(dataDir, FILE), "utf8"));
|
|
32
|
+
if (running.pid === pid) {
|
|
33
|
+
rmSync(join(dataDir, FILE), { force: true });
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
// nothing there
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { DockerSandbox } from "@mastra/docker";
|
|
2
|
+
/** The image's own working directory, the one its unprivileged user may write to. */
|
|
3
|
+
const WORKDIR = "/sandbox";
|
|
4
|
+
/** Bytes per append when a file is written through the shell; stays far below ARG_MAX. */
|
|
5
|
+
const WRITE_CHUNK = 48 * 1024;
|
|
6
|
+
/** What the engenty-sandbox image carries. The container sits on Docker's default bridge. */
|
|
7
|
+
export const DOCKER_CAPABILITIES = {
|
|
8
|
+
commands: ["bash", "python3", "pip", "uv", "node", "npm", "bun", "jq", "curl", "git", "unzip"],
|
|
9
|
+
network: "open internet",
|
|
10
|
+
uses: "calculations, charts or file conversion",
|
|
11
|
+
workdir: WORKDIR,
|
|
12
|
+
};
|
|
13
|
+
const quote = (value) => `'${value.replaceAll("'", `'\\''`)}'`;
|
|
14
|
+
/** One container per run through the host's Docker. */
|
|
15
|
+
export class DockerRunSandbox {
|
|
16
|
+
runId;
|
|
17
|
+
image;
|
|
18
|
+
capabilities = DOCKER_CAPABILITIES;
|
|
19
|
+
container = null;
|
|
20
|
+
constructor(runId, image) {
|
|
21
|
+
this.runId = runId;
|
|
22
|
+
this.image = image;
|
|
23
|
+
}
|
|
24
|
+
start() {
|
|
25
|
+
this.container ??= (async () => {
|
|
26
|
+
const sandbox = new DockerSandbox({
|
|
27
|
+
id: `wizards-${this.runId.toLowerCase()}`,
|
|
28
|
+
image: this.image,
|
|
29
|
+
memory: 1024 * 1024 * 1024,
|
|
30
|
+
pidsLimit: 256,
|
|
31
|
+
capDrop: ["ALL"],
|
|
32
|
+
securityOpt: ["no-new-privileges"],
|
|
33
|
+
workingDir: WORKDIR,
|
|
34
|
+
labels: { "engenty-wizards.run": this.runId },
|
|
35
|
+
});
|
|
36
|
+
await sandbox.start();
|
|
37
|
+
return sandbox;
|
|
38
|
+
})();
|
|
39
|
+
return this.container;
|
|
40
|
+
}
|
|
41
|
+
async exec(command, options = {}) {
|
|
42
|
+
const sandbox = await this.start();
|
|
43
|
+
const result = await sandbox.executeCommand(command, [], {
|
|
44
|
+
timeout: options.timeoutMs,
|
|
45
|
+
cwd: options.cwd,
|
|
46
|
+
env: options.env,
|
|
47
|
+
});
|
|
48
|
+
return { exitCode: result.exitCode, stdout: result.stdout, stderr: result.stderr };
|
|
49
|
+
}
|
|
50
|
+
async writeFile(path, data) {
|
|
51
|
+
const target = quote(path);
|
|
52
|
+
const bytes = typeof data === "string" ? Buffer.from(data, "utf8") : Buffer.from(data);
|
|
53
|
+
await this.must(`mkdir -p "$(dirname ${target})" && : > ${target}`);
|
|
54
|
+
for (let at = 0; at < bytes.length; at += WRITE_CHUNK) {
|
|
55
|
+
const chunk = bytes.subarray(at, at + WRITE_CHUNK).toString("base64");
|
|
56
|
+
await this.must(`printf %s ${chunk} | base64 -d >> ${target}`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
async readFile(path) {
|
|
60
|
+
const result = await this.must(`base64 -w0 ${quote(path)}`);
|
|
61
|
+
return Buffer.from(result.stdout.trim(), "base64");
|
|
62
|
+
}
|
|
63
|
+
async must(command) {
|
|
64
|
+
const result = await this.exec(command);
|
|
65
|
+
if (result.exitCode !== 0) {
|
|
66
|
+
throw new Error(result.stderr.trim() || `exit code ${result.exitCode}`);
|
|
67
|
+
}
|
|
68
|
+
return result;
|
|
69
|
+
}
|
|
70
|
+
async destroy() {
|
|
71
|
+
const container = this.container;
|
|
72
|
+
this.container = null;
|
|
73
|
+
await (await container?.catch(() => null))?.destroy();
|
|
74
|
+
}
|
|
75
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { env } from "../env.js";
|
|
2
|
+
import { DOCKER_CAPABILITIES, DockerRunSandbox } from "./docker.js";
|
|
3
|
+
/** What this server's sandbox runs, or null when it is switched off. */
|
|
4
|
+
export function sandboxCapabilities() {
|
|
5
|
+
if (env.sandbox === "off") {
|
|
6
|
+
return null;
|
|
7
|
+
}
|
|
8
|
+
return DOCKER_CAPABILITIES;
|
|
9
|
+
}
|
|
10
|
+
export function createSandbox(runId) {
|
|
11
|
+
if (env.sandbox === "off") {
|
|
12
|
+
throw new Error("The sandbox is switched off on this server.");
|
|
13
|
+
}
|
|
14
|
+
return new DockerRunSandbox(runId, env.sandboxImage);
|
|
15
|
+
}
|
|
16
|
+
export function shellToolDescription(caps) {
|
|
17
|
+
return `Run a shell command in a private Linux sandbox (${caps.commands.join(", ")}). Working directory ${caps.workdir}. Network: ${caps.network}.`;
|
|
18
|
+
}
|
|
19
|
+
/** The authoring guide's line about the sandbox tool. */
|
|
20
|
+
export function sandboxGuideLine() {
|
|
21
|
+
const uses = (sandboxCapabilities() ?? DOCKER_CAPABILITIES).uses;
|
|
22
|
+
return `- The sandbox runs code (python/node) for ${uses}; export_file hands files to the person.`;
|
|
23
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { createCipheriv, createDecipheriv, hkdfSync, randomBytes } from "node:crypto";
|
|
2
|
+
import { env } from "../env.js";
|
|
3
|
+
/** AES-256-GCM for what the store keeps secret (account tokens, passwords, browser sessions). */
|
|
4
|
+
const key = Buffer.from(hkdfSync("sha256", env.storeKey || env.authSecret, "engenty-wizards", "store-secrets", 32));
|
|
5
|
+
export function seal(value) {
|
|
6
|
+
const iv = randomBytes(12);
|
|
7
|
+
const cipher = createCipheriv("aes-256-gcm", key, iv);
|
|
8
|
+
const body = Buffer.concat([cipher.update(JSON.stringify(value), "utf8"), cipher.final()]);
|
|
9
|
+
return `v1.${iv.toString("base64url")}.${cipher.getAuthTag().toString("base64url")}.${body.toString("base64url")}`;
|
|
10
|
+
}
|
|
11
|
+
export function unseal(sealed) {
|
|
12
|
+
const [version, iv, tag, body] = sealed.split(".");
|
|
13
|
+
if (version !== "v1" || !iv || !tag || !body) {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
try {
|
|
17
|
+
const decipher = createDecipheriv("aes-256-gcm", key, Buffer.from(iv, "base64url"));
|
|
18
|
+
decipher.setAuthTag(Buffer.from(tag, "base64url"));
|
|
19
|
+
const plain = Buffer.concat([
|
|
20
|
+
decipher.update(Buffer.from(body, "base64url")),
|
|
21
|
+
decipher.final(),
|
|
22
|
+
]);
|
|
23
|
+
return JSON.parse(plain.toString("utf8"));
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { createHmac, timingSafeEqual } from "node:crypto";
|
|
2
|
+
import { env } from "../env.js";
|
|
3
|
+
/** The query the signature covers: everything but exp/sig, sorted, so parameter order never matters. */
|
|
4
|
+
function payload(url, exp) {
|
|
5
|
+
const params = [...url.searchParams.entries()]
|
|
6
|
+
.filter(([k]) => k !== "exp" && k !== "sig")
|
|
7
|
+
.sort(([a], [b]) => a.localeCompare(b));
|
|
8
|
+
return `${url.pathname}?${new URLSearchParams(params)}|${exp}`;
|
|
9
|
+
}
|
|
10
|
+
function sign(data) {
|
|
11
|
+
return createHmac("sha256", env.authSecret).update(data).digest("base64url");
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* A link that opens one GET path without a session — for clients that have no studio cookie,
|
|
15
|
+
* such as an MCP client handing a download to the admin.
|
|
16
|
+
*/
|
|
17
|
+
export function signedUrl(path, ttlSeconds = 3600) {
|
|
18
|
+
const url = new URL(path, env.appUrl);
|
|
19
|
+
const exp = String(Math.floor(Date.now() / 1000) + ttlSeconds);
|
|
20
|
+
url.searchParams.set("exp", exp);
|
|
21
|
+
url.searchParams.set("sig", sign(payload(url, exp)));
|
|
22
|
+
return url.toString();
|
|
23
|
+
}
|
|
24
|
+
function sameSignature(data, sig) {
|
|
25
|
+
const expected = Buffer.from(sign(data));
|
|
26
|
+
const given = Buffer.from(sig);
|
|
27
|
+
return expected.length === given.length && timingSafeEqual(expected, given);
|
|
28
|
+
}
|
|
29
|
+
export function verifySignedUrl(href) {
|
|
30
|
+
const url = new URL(href, env.appUrl);
|
|
31
|
+
const exp = url.searchParams.get("exp");
|
|
32
|
+
const sig = url.searchParams.get("sig");
|
|
33
|
+
if (!exp || !sig || Number(exp) * 1000 < Date.now()) {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
return sameSignature(payload(url, exp), sig);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* A ticket to one run's routes without a session: the widget an AI app shows runs on the host's
|
|
40
|
+
* origin and reaches the run with it. Sent as `?rt=`, since an EventSource sends no headers.
|
|
41
|
+
*/
|
|
42
|
+
export function runTicket(runId, ttlSeconds = 12 * 3600) {
|
|
43
|
+
const exp = String(Math.floor(Date.now() / 1000) + ttlSeconds);
|
|
44
|
+
return `${exp}.${sign(`run:${runId}|${exp}`)}`;
|
|
45
|
+
}
|
|
46
|
+
export function runTicketValid(runId, ticket) {
|
|
47
|
+
const [exp, sig] = (ticket ?? "").split(".");
|
|
48
|
+
if (!exp || !sig || Number(exp) * 1000 < Date.now()) {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
return sameSignature(`run:${runId}|${exp}`, sig);
|
|
52
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { execFile } from "node:child_process";
|
|
2
|
+
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { promisify } from "node:util";
|
|
5
|
+
import { env } from "../env.js";
|
|
6
|
+
import { seal, unseal } from "./crypto.js";
|
|
7
|
+
const run = promisify(execFile);
|
|
8
|
+
/**
|
|
9
|
+
* Secrets of a runtime that runs alone: the keys the person entered and the linked account's
|
|
10
|
+
* refresh token. In the desktop app (`SECRETS=keychain`) they live in the macOS Keychain, never
|
|
11
|
+
* in the database; elsewhere in an encrypted file in the data folder.
|
|
12
|
+
*/
|
|
13
|
+
const SERVICE = "engenty-wizards";
|
|
14
|
+
const keychain = process.env.SECRETS === "keychain" && process.platform === "darwin";
|
|
15
|
+
const file = join(env.dataDir, "vault");
|
|
16
|
+
function readFileVault() {
|
|
17
|
+
if (!existsSync(file)) {
|
|
18
|
+
return {};
|
|
19
|
+
}
|
|
20
|
+
return unseal(readFileSync(file, "utf8").trim()) ?? {};
|
|
21
|
+
}
|
|
22
|
+
function writeFileVault(all) {
|
|
23
|
+
writeFileSync(file, seal(all), { mode: 0o600 });
|
|
24
|
+
}
|
|
25
|
+
export async function vaultGet(name) {
|
|
26
|
+
if (!keychain) {
|
|
27
|
+
return readFileVault()[name] ?? null;
|
|
28
|
+
}
|
|
29
|
+
try {
|
|
30
|
+
const { stdout } = await run("security", [
|
|
31
|
+
"find-generic-password",
|
|
32
|
+
"-s",
|
|
33
|
+
SERVICE,
|
|
34
|
+
"-a",
|
|
35
|
+
name,
|
|
36
|
+
"-w",
|
|
37
|
+
]);
|
|
38
|
+
return stdout.replace(/\n$/, "") || null;
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
export async function vaultSet(name, value) {
|
|
45
|
+
if (!keychain) {
|
|
46
|
+
writeFileVault({ ...readFileVault(), [name]: value });
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
await run("security", ["add-generic-password", "-U", "-s", SERVICE, "-a", name, "-w", value]);
|
|
50
|
+
}
|
|
51
|
+
export async function vaultDelete(name) {
|
|
52
|
+
if (!keychain) {
|
|
53
|
+
const all = readFileVault();
|
|
54
|
+
delete all[name];
|
|
55
|
+
writeFileVault(all);
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
await run("security", ["delete-generic-password", "-s", SERVICE, "-a", name]).catch(() => undefined);
|
|
59
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2
|
+
import { note } from "@engenty-wizards/shared/run";
|
|
3
|
+
import { and, eq } from "drizzle-orm";
|
|
4
|
+
import { db, schema } from "../db/client.js";
|
|
5
|
+
import { managed, tenantInfo } from "../manage.js";
|
|
6
|
+
import { currentTenant } from "../tenants/tenant.js";
|
|
7
|
+
import { ServiceError } from "./errors.js";
|
|
8
|
+
/**
|
|
9
|
+
* Who may change what on this runtime. A project a local install synced (`origin: "local"`) is
|
|
10
|
+
* changed only by that install's next sync: here it is shown and run. And a tenant the
|
|
11
|
+
* Manage-App gives no building (`limits.build: false`) makes and changes nothing on this
|
|
12
|
+
* runtime. Every write of a project or a wizard asks here, whichever way it came in: studio,
|
|
13
|
+
* MCP client or API.
|
|
14
|
+
*/
|
|
15
|
+
const sync = new AsyncLocalStorage();
|
|
16
|
+
/** Runs the writes of a sync: they are the one way a synced project changes. */
|
|
17
|
+
export function asSync(fn) {
|
|
18
|
+
return sync.run(true, fn);
|
|
19
|
+
}
|
|
20
|
+
const syncing = () => sync.getStore() === true;
|
|
21
|
+
// --- roles -----------------------------------------------------------------------------
|
|
22
|
+
// In a team, an owner or admin makes and deletes (wizards, spaces, connectors); a member edits
|
|
23
|
+
// the wizards there are. A runtime that runs alone has one person, who does everything.
|
|
24
|
+
const actor = new AsyncLocalStorage();
|
|
25
|
+
/** Runs a request as the person's role in the tenant; set once per entry, like the tenant. */
|
|
26
|
+
export function asRole(role, fn) {
|
|
27
|
+
return actor.run(role, fn);
|
|
28
|
+
}
|
|
29
|
+
/** The role of who acts now. A context without one (a job, a sync) acts as the owner. */
|
|
30
|
+
export function currentRole() {
|
|
31
|
+
return actor.getStore() ?? "owner";
|
|
32
|
+
}
|
|
33
|
+
export const isAdminRole = (role) => role === "owner" || role === "admin";
|
|
34
|
+
export const MEMBERS_EDIT_ONLY = note("onlyTeamAdmins");
|
|
35
|
+
/** Refuses a member: making and deleting is for the owner and the admins of the team. */
|
|
36
|
+
export async function requireAdmin() {
|
|
37
|
+
if (syncing() || !managed || isAdminRole(currentRole())) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
throw new ServiceError("forbidden", MEMBERS_EDIT_ONLY);
|
|
41
|
+
}
|
|
42
|
+
/** Whether the person makes and deletes here: builds at all, and is no mere member. */
|
|
43
|
+
export async function mayCreate() {
|
|
44
|
+
return (await mayBuild()) && (!managed || isAdminRole(currentRole()));
|
|
45
|
+
}
|
|
46
|
+
/** Whether the tenant builds wizards on this runtime. A runtime that runs alone always does. */
|
|
47
|
+
export async function mayBuild() {
|
|
48
|
+
if (!managed) {
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
51
|
+
const info = await tenantInfo(currentTenant()).catch(() => null);
|
|
52
|
+
// An older Manage-App does not say: then it builds. One that cannot be reached: nothing changes.
|
|
53
|
+
return info ? info.limits.build !== false : false;
|
|
54
|
+
}
|
|
55
|
+
export const READ_ONLY_PROJECT = note("spaceEditedLocally");
|
|
56
|
+
export const READ_ONLY_TENANT = note("wizardsRunOncePublished");
|
|
57
|
+
/** Refuses when the tenant builds nothing here. */
|
|
58
|
+
export async function requireBuild() {
|
|
59
|
+
if (syncing() || (await mayBuild())) {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
throw new ServiceError("read_only", READ_ONLY_TENANT);
|
|
63
|
+
}
|
|
64
|
+
/** Refuses a change of a synced project, and any change by a tenant that builds nothing here. */
|
|
65
|
+
export async function requireWritable(project) {
|
|
66
|
+
if (syncing()) {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
if (project.origin === "local") {
|
|
70
|
+
throw new ServiceError("read_only", READ_ONLY_PROJECT);
|
|
71
|
+
}
|
|
72
|
+
await requireBuild();
|
|
73
|
+
}
|
|
74
|
+
export async function requireWritableProject(projectId) {
|
|
75
|
+
if (syncing()) {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
const project = await db.query.project.findFirst({
|
|
79
|
+
where: and(eq(schema.project.id, projectId), eq(schema.project.tenantId, currentTenant())),
|
|
80
|
+
columns: { origin: true },
|
|
81
|
+
});
|
|
82
|
+
// A project that is not there is the caller's "not found", not ours.
|
|
83
|
+
await requireWritable(project ?? { origin: null });
|
|
84
|
+
}
|
|
85
|
+
/** Whether the person may change this project's wizards and settings here. */
|
|
86
|
+
export async function projectWritable(project) {
|
|
87
|
+
return project.origin !== "local" && (await mayBuild());
|
|
88
|
+
}
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
import { textLang, wizardLang, } from "@engenty-wizards/shared/definition";
|
|
2
|
+
import { standaloneEntry } from "@engenty-wizards/shared/fit";
|
|
3
|
+
import { pluginsOf } from "@engenty-wizards/shared/marketplace";
|
|
4
|
+
import { noteText } from "@engenty-wizards/shared/run";
|
|
5
|
+
import { and, count, desc, eq, gte, inArray, isNotNull, or, sql } from "drizzle-orm";
|
|
6
|
+
import { MICROS_PER_CREDIT } from "../credits/credits.js";
|
|
7
|
+
import { db, schema } from "../db/client.js";
|
|
8
|
+
import { env } from "../env.js";
|
|
9
|
+
import { wizardUnavailable } from "../limits.js";
|
|
10
|
+
import { codeOf } from "../tenants/control.js";
|
|
11
|
+
import { currentTenant } from "../tenants/tenant.js";
|
|
12
|
+
import { serverText } from "../texts.js";
|
|
13
|
+
import { mayBuild, projectWritable, READ_ONLY_TENANT } from "./access.js";
|
|
14
|
+
import { mainLogoId } from "./brand.js";
|
|
15
|
+
import { notFound, ServiceError } from "./errors.js";
|
|
16
|
+
import { knowledgeCounts } from "./knowledge.js";
|
|
17
|
+
import { listProjects, ownedProject } from "./projects.js";
|
|
18
|
+
import { runReport } from "./runs.js";
|
|
19
|
+
import { shareUrlFor } from "./shares.js";
|
|
20
|
+
import { shareUrl, studioUrl } from "./wizards.js";
|
|
21
|
+
/** The spaces the caller works with, as the studio lists them, and whether each may change here. */
|
|
22
|
+
export async function apiSpaces(userId) {
|
|
23
|
+
const projects = await listProjects(userId);
|
|
24
|
+
return Promise.all(projects.map(async (p) => ({
|
|
25
|
+
id: p.id,
|
|
26
|
+
name: p.name,
|
|
27
|
+
title: p.brand.name ?? "",
|
|
28
|
+
wizards: p.wizardCount,
|
|
29
|
+
writable: await projectWritable(p),
|
|
30
|
+
})));
|
|
31
|
+
}
|
|
32
|
+
/** The space a call names, or the one a caller means when it names none: the first one listed. */
|
|
33
|
+
export async function apiSpace(userId, spaceId) {
|
|
34
|
+
if (spaceId) {
|
|
35
|
+
return ownedProject(userId, spaceId);
|
|
36
|
+
}
|
|
37
|
+
const [first] = await listProjects(userId);
|
|
38
|
+
if (!first) {
|
|
39
|
+
// A plan that builds nothing here has a space only once its local install synced one.
|
|
40
|
+
if (!(await mayBuild())) {
|
|
41
|
+
throw new ServiceError("read_only", READ_ONLY_TENANT);
|
|
42
|
+
}
|
|
43
|
+
throw notFound();
|
|
44
|
+
}
|
|
45
|
+
return first;
|
|
46
|
+
}
|
|
47
|
+
/** The space's own details: what it says about itself, and what its wizards look things up in. */
|
|
48
|
+
export async function apiSpaceDetails(userId, spaceId) {
|
|
49
|
+
const p = await apiSpace(userId, spaceId);
|
|
50
|
+
const logo = await mainLogoId(p.id);
|
|
51
|
+
return {
|
|
52
|
+
id: p.id,
|
|
53
|
+
name: p.name,
|
|
54
|
+
title: p.brand.name ?? "",
|
|
55
|
+
about: p.brand.about ?? "",
|
|
56
|
+
colors: p.brand.colors ?? [],
|
|
57
|
+
facts: p.facts.map(({ label, value }) => ({ label, value })),
|
|
58
|
+
logoUrl: logo ? `${env.publicUrl}/api/public/logos/${logo}` : null,
|
|
59
|
+
knowledge: await knowledgeCounts(p.id),
|
|
60
|
+
writable: await projectWritable(p),
|
|
61
|
+
studioUrl: `${env.appUrl}/studio/space`,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* The wizards of the caller's spaces, newest change first. A published one carries what a website
|
|
66
|
+
* embeds it with: its link's token and the ID the mobile app takes.
|
|
67
|
+
*/
|
|
68
|
+
export async function apiWizards(userId, spaceId) {
|
|
69
|
+
const spaces = (await listProjects(userId)).filter((p) => !spaceId || p.id === spaceId);
|
|
70
|
+
if (!spaces.length) {
|
|
71
|
+
return [];
|
|
72
|
+
}
|
|
73
|
+
const rows = await db.query.wizard.findMany({
|
|
74
|
+
where: and(eq(schema.wizard.tenantId, currentTenant()), inArray(schema.wizard.projectId, spaces.map((p) => p.id))),
|
|
75
|
+
orderBy: [desc(schema.wizard.updatedAt)],
|
|
76
|
+
});
|
|
77
|
+
const published = rows.filter((w) => w.publishedVersion !== null);
|
|
78
|
+
const versions = published.length
|
|
79
|
+
? await db.query.wizardVersion.findMany({
|
|
80
|
+
where: or(...published.map((w) => and(eq(schema.wizardVersion.wizardId, w.id), eq(schema.wizardVersion.version, w.publishedVersion)))),
|
|
81
|
+
columns: { wizardId: true, definition: true },
|
|
82
|
+
})
|
|
83
|
+
: [];
|
|
84
|
+
return Promise.all(rows.map(async (w) => {
|
|
85
|
+
const live = versions.find((v) => v.wizardId === w.id)?.definition;
|
|
86
|
+
const def = live ?? w.draft;
|
|
87
|
+
const reason = live ? await wizardUnavailable(w) : null;
|
|
88
|
+
return {
|
|
89
|
+
id: w.id,
|
|
90
|
+
spaceId: w.projectId,
|
|
91
|
+
title: def.title,
|
|
92
|
+
description: def.description ?? "",
|
|
93
|
+
avatar: def.avatar ?? null,
|
|
94
|
+
published: Boolean(live),
|
|
95
|
+
publishedVersion: w.publishedVersion,
|
|
96
|
+
token: live ? w.shareToken : null,
|
|
97
|
+
code: live ? await codeOf(w.shareToken) : null,
|
|
98
|
+
shareUrl: live ? shareUrl(w.shareToken) : null,
|
|
99
|
+
shareEnabled: w.shareEnabled,
|
|
100
|
+
iconUrl: live
|
|
101
|
+
? `${env.publicUrl}/api/public/wizards/${w.shareToken}/icons/icon-192.png`
|
|
102
|
+
: null,
|
|
103
|
+
available: Boolean(live) && !reason,
|
|
104
|
+
unavailableReason: reason && noteText(reason, wizardLang(def)),
|
|
105
|
+
dailyRunLimit: w.dailyRunLimit,
|
|
106
|
+
/** The plugins its steps call: a wizard that books needs `appointments`. */
|
|
107
|
+
plugins: pluginsOf(def),
|
|
108
|
+
/** Whether it runs on a website by itself, in the gallery's words (packages/shared/src/fit.ts). */
|
|
109
|
+
standalone: standaloneEntry(def),
|
|
110
|
+
studioUrl: studioUrl(w.id),
|
|
111
|
+
updatedAt: w.updatedAt.toISOString(),
|
|
112
|
+
};
|
|
113
|
+
}));
|
|
114
|
+
}
|
|
115
|
+
/** A value as one line of text, in the wizard's language: what the person typed or picked. */
|
|
116
|
+
function answerText(field, value, lang) {
|
|
117
|
+
if (value === undefined || value === null || value === "") {
|
|
118
|
+
return "";
|
|
119
|
+
}
|
|
120
|
+
if (typeof value === "boolean") {
|
|
121
|
+
return serverText(lang, value ? "yes" : "no");
|
|
122
|
+
}
|
|
123
|
+
if (typeof value === "string" || typeof value === "number") {
|
|
124
|
+
return String(value);
|
|
125
|
+
}
|
|
126
|
+
if (Array.isArray(value)) {
|
|
127
|
+
if (["file", "image", "audio", "signature"].includes(field.kind)) {
|
|
128
|
+
return serverText(lang, "fileCount", { count: value.length });
|
|
129
|
+
}
|
|
130
|
+
return value
|
|
131
|
+
.map((v) => (typeof v === "object" && v ? Object.values(v).join(" ") : String(v)))
|
|
132
|
+
.join(", ");
|
|
133
|
+
}
|
|
134
|
+
if (typeof value === "object") {
|
|
135
|
+
const v = value;
|
|
136
|
+
const said = v.label ?? v.address ?? v.text ?? v.name ?? v.start;
|
|
137
|
+
return typeof said === "string" ? said : JSON.stringify(value).slice(0, 200);
|
|
138
|
+
}
|
|
139
|
+
return "";
|
|
140
|
+
}
|
|
141
|
+
/** What the person answered on the run's pages, by the fields' labels, in the order asked. */
|
|
142
|
+
function answersOf(run) {
|
|
143
|
+
const answers = [];
|
|
144
|
+
const lang = textLang(wizardLang(run.definition));
|
|
145
|
+
for (const step of run.definition.steps) {
|
|
146
|
+
if (step.type !== "page") {
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
for (const field of step.fields) {
|
|
150
|
+
const value = answerText(field, run.state.values[field.id], lang);
|
|
151
|
+
if (value) {
|
|
152
|
+
answers.push({ field: field.id, label: field.label, kind: field.kind, value });
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
return answers;
|
|
157
|
+
}
|
|
158
|
+
/** The person's address where a page asked for one: the first e-mail field answered. */
|
|
159
|
+
function emailOf(answers) {
|
|
160
|
+
return (answers.find((a) => a.kind === "email")?.value ??
|
|
161
|
+
answers.find((a) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(a.value))?.value ??
|
|
162
|
+
null);
|
|
163
|
+
}
|
|
164
|
+
const PAGE = 50;
|
|
165
|
+
/** The live runs of the caller's wizards, newest first, by pages of 50: what visitors left. */
|
|
166
|
+
export async function apiRuns(userId, filter = {}) {
|
|
167
|
+
const wizards = await apiWizards(userId, filter.spaceId);
|
|
168
|
+
const ids = wizards.map((w) => w.id).filter((id) => !filter.wizardId || id === filter.wizardId);
|
|
169
|
+
const page = Math.max(1, filter.page ?? 1);
|
|
170
|
+
if (!ids.length) {
|
|
171
|
+
return { runs: [], page, pages: 0, total: 0 };
|
|
172
|
+
}
|
|
173
|
+
const q = filter.q?.trim().toLowerCase();
|
|
174
|
+
const like = q ? `%${q.replace(/[\\%_]/g, (c) => `\\${c}`)}%` : null;
|
|
175
|
+
const status = filter.status ?? "done";
|
|
176
|
+
const where = and(inArray(schema.run.wizardId, ids), eq(schema.run.mode, "live"), status === "done"
|
|
177
|
+
? eq(schema.run.status, "done")
|
|
178
|
+
: status === "open"
|
|
179
|
+
? inArray(schema.run.status, ["waiting_input", "running"])
|
|
180
|
+
: undefined, filter.days
|
|
181
|
+
? gte(schema.run.createdAt, new Date(Date.now() - filter.days * 86_400_000))
|
|
182
|
+
: undefined, like
|
|
183
|
+
? or(sql `lower(${schema.run.state}) like ${like} escape '\\'`, sql `lower(coalesce(${schema.run.origin}, '')) like ${like} escape '\\'`)
|
|
184
|
+
: undefined);
|
|
185
|
+
const [{ total }] = await db.select({ total: count() }).from(schema.run).where(where);
|
|
186
|
+
const rows = await db.query.run.findMany({
|
|
187
|
+
where,
|
|
188
|
+
orderBy: [desc(schema.run.createdAt)],
|
|
189
|
+
limit: PAGE,
|
|
190
|
+
offset: (page - 1) * PAGE,
|
|
191
|
+
});
|
|
192
|
+
const assets = rows.length
|
|
193
|
+
? await db
|
|
194
|
+
.select({ runId: schema.asset.runId, n: count() })
|
|
195
|
+
.from(schema.asset)
|
|
196
|
+
.where(and(isNotNull(schema.asset.runId), inArray(schema.asset.runId, rows.map((r) => r.id))))
|
|
197
|
+
.groupBy(schema.asset.runId)
|
|
198
|
+
: [];
|
|
199
|
+
return {
|
|
200
|
+
runs: rows.map((r) => {
|
|
201
|
+
const answers = answersOf(r);
|
|
202
|
+
return {
|
|
203
|
+
id: r.id,
|
|
204
|
+
wizardId: r.wizardId,
|
|
205
|
+
wizard: wizards.find((w) => w.id === r.wizardId)?.title ?? r.definition.title,
|
|
206
|
+
status: r.status,
|
|
207
|
+
step: r.definition.steps.find((s) => s.id === r.cursor)?.title ?? null,
|
|
208
|
+
createdAt: r.createdAt.toISOString(),
|
|
209
|
+
updatedAt: r.updatedAt.toISOString(),
|
|
210
|
+
origin: r.origin,
|
|
211
|
+
email: emailOf(answers),
|
|
212
|
+
/** The first answers, for a line in a list. */
|
|
213
|
+
summary: answers
|
|
214
|
+
.slice(0, 3)
|
|
215
|
+
.map((a) => a.value)
|
|
216
|
+
.join(" · ")
|
|
217
|
+
.slice(0, 200),
|
|
218
|
+
credits: Math.ceil(r.costMicros / MICROS_PER_CREDIT),
|
|
219
|
+
files: assets.find((a) => a.runId === r.id)?.n ?? 0,
|
|
220
|
+
};
|
|
221
|
+
}),
|
|
222
|
+
page,
|
|
223
|
+
pages: Math.ceil(total / PAGE),
|
|
224
|
+
total,
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
/** One run with everything a reader of the result needs: the answers, the outputs, the downloads. */
|
|
228
|
+
export async function apiRun(userId, runId) {
|
|
229
|
+
// Refuses what is no live run of the tenant.
|
|
230
|
+
const report = await runReport(userId, runId, 0, "live");
|
|
231
|
+
const run = await db.query.run.findFirst({
|
|
232
|
+
where: and(eq(schema.run.id, runId), eq(schema.run.tenantId, currentTenant())),
|
|
233
|
+
});
|
|
234
|
+
if (!run) {
|
|
235
|
+
throw notFound();
|
|
236
|
+
}
|
|
237
|
+
const answers = answersOf(run);
|
|
238
|
+
return {
|
|
239
|
+
...report,
|
|
240
|
+
wizard: run.definition.title,
|
|
241
|
+
createdAt: run.createdAt.toISOString(),
|
|
242
|
+
updatedAt: run.updatedAt.toISOString(),
|
|
243
|
+
origin: run.origin,
|
|
244
|
+
email: emailOf(answers),
|
|
245
|
+
answers: answers.map(({ label, kind, value }) => ({ label, kind, value })),
|
|
246
|
+
shareUrl: run.shareToken ? shareUrlFor(run.shareToken) : null,
|
|
247
|
+
};
|
|
248
|
+
}
|