wizards 0.1.9
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 +170 -0
- package/apps/runtime/dist/agents/architect.js +453 -0
- package/apps/runtime/dist/agents/project-assistant.js +354 -0
- package/apps/runtime/dist/agents/subscription.js +206 -0
- package/apps/runtime/dist/agents/thought.js +21 -0
- package/apps/runtime/dist/agents/website.js +197 -0
- package/apps/runtime/dist/app.js +153 -0
- package/apps/runtime/dist/auth/account.js +121 -0
- package/apps/runtime/dist/auth/index.js +329 -0
- package/apps/runtime/dist/auth/keys.js +55 -0
- package/apps/runtime/dist/auth/local-ticket.js +23 -0
- package/apps/runtime/dist/authoring/example.js +73 -0
- package/apps/runtime/dist/authoring/guide.js +259 -0
- package/apps/runtime/dist/authoring/ops.js +117 -0
- package/apps/runtime/dist/cli/autostart.js +134 -0
- package/apps/runtime/dist/cli/clients.js +44 -0
- package/apps/runtime/dist/cli/environment.js +81 -0
- package/apps/runtime/dist/cli/exec.js +45 -0
- package/apps/runtime/dist/cli/home.js +74 -0
- package/apps/runtime/dist/cli/machine.js +145 -0
- package/apps/runtime/dist/cli/main.js +125 -0
- package/apps/runtime/dist/cli/setup.js +273 -0
- package/apps/runtime/dist/cli/start.js +190 -0
- package/apps/runtime/dist/cli/status.js +120 -0
- package/apps/runtime/dist/cli/ui.js +12 -0
- package/apps/runtime/dist/cli/update.js +58 -0
- package/apps/runtime/dist/connectors/builtin.js +70 -0
- package/apps/runtime/dist/connectors/external.js +400 -0
- package/apps/runtime/dist/connectors/gmail.js +107 -0
- package/apps/runtime/dist/connectors/imap.js +217 -0
- package/apps/runtime/dist/connectors/index.js +266 -0
- package/apps/runtime/dist/connectors/mail.js +72 -0
- package/apps/runtime/dist/connectors/outlook.js +90 -0
- package/apps/runtime/dist/credits/credits.js +103 -0
- package/apps/runtime/dist/credits/estimate.js +132 -0
- package/apps/runtime/dist/db/adopt.js +149 -0
- package/apps/runtime/dist/db/client.js +146 -0
- package/apps/runtime/dist/db/control-schema.js +70 -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/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/_journal.json +41 -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/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/_journal.json +41 -0
- package/apps/runtime/dist/db/schema.js +278 -0
- package/apps/runtime/dist/documents/parse.js +230 -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 +359 -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 +464 -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 +3 -0
- package/apps/runtime/dist/engenty/web-ingest/ssrf.js +277 -0
- package/apps/runtime/dist/engine/asks.js +60 -0
- package/apps/runtime/dist/engine/events.js +46 -0
- package/apps/runtime/dist/engine/input.js +170 -0
- package/apps/runtime/dist/engine/prepare.js +51 -0
- package/apps/runtime/dist/engine/requirements.js +124 -0
- package/apps/runtime/dist/engine/resources.js +89 -0
- package/apps/runtime/dist/engine/runner.js +560 -0
- package/apps/runtime/dist/engine/steps.js +598 -0
- package/apps/runtime/dist/engine/template.js +183 -0
- package/apps/runtime/dist/engine/types.js +3 -0
- package/apps/runtime/dist/env.js +224 -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 +95 -0
- package/apps/runtime/dist/geocode.js +58 -0
- package/apps/runtime/dist/harness/claude.js +138 -0
- package/apps/runtime/dist/harness/codex.js +228 -0
- package/apps/runtime/dist/harness/cursor.js +93 -0
- package/apps/runtime/dist/harness/env.js +124 -0
- package/apps/runtime/dist/harness/gemini.js +126 -0
- package/apps/runtime/dist/harness/index.js +99 -0
- package/apps/runtime/dist/harness/model.js +267 -0
- package/apps/runtime/dist/harness/prompt.js +121 -0
- package/apps/runtime/dist/harness/terminal.js +193 -0
- package/apps/runtime/dist/harness/types.js +7 -0
- package/apps/runtime/dist/index.js +76 -0
- package/apps/runtime/dist/limits.js +57 -0
- package/apps/runtime/dist/link-preview.js +59 -0
- package/apps/runtime/dist/manage.js +151 -0
- package/apps/runtime/dist/mcp/auth.js +102 -0
- package/apps/runtime/dist/mcp/bridge.js +59 -0
- package/apps/runtime/dist/mcp/handler.js +42 -0
- package/apps/runtime/dist/mcp/scopes.js +5 -0
- package/apps/runtime/dist/mcp/tools.js +401 -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 +30 -0
- package/apps/runtime/dist/model-errors.js +3 -0
- package/apps/runtime/dist/models.js +489 -0
- package/apps/runtime/dist/plugin.js +61 -0
- package/apps/runtime/dist/render/chromium.js +85 -0
- package/apps/runtime/dist/render/convert.js +161 -0
- package/apps/runtime/dist/render/downloads.js +277 -0
- package/apps/runtime/dist/render/guard.js +25 -0
- package/apps/runtime/dist/routes/api.js +74 -0
- package/apps/runtime/dist/routes/delivery.js +52 -0
- package/apps/runtime/dist/routes/internal.js +49 -0
- package/apps/runtime/dist/routes/marketplace.js +36 -0
- package/apps/runtime/dist/routes/runs.js +805 -0
- package/apps/runtime/dist/routes/studio.js +702 -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.js +191 -0
- package/apps/runtime/dist/sandbox/docker.js +77 -0
- package/apps/runtime/dist/sandbox/index.js +30 -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 +34 -0
- package/apps/runtime/dist/secrets/vault.js +59 -0
- package/apps/runtime/dist/services/architect.js +92 -0
- package/apps/runtime/dist/services/brand.js +20 -0
- package/apps/runtime/dist/services/cloud.js +52 -0
- package/apps/runtime/dist/services/draft-events.js +27 -0
- package/apps/runtime/dist/services/errors.js +24 -0
- package/apps/runtime/dist/services/files.js +129 -0
- package/apps/runtime/dist/services/links.js +16 -0
- package/apps/runtime/dist/services/marketplace.js +292 -0
- package/apps/runtime/dist/services/package.js +202 -0
- package/apps/runtime/dist/services/profile.js +23 -0
- package/apps/runtime/dist/services/project-files.js +266 -0
- package/apps/runtime/dist/services/project-index.js +109 -0
- package/apps/runtime/dist/services/projects.js +181 -0
- package/apps/runtime/dist/services/runs.js +224 -0
- package/apps/runtime/dist/services/shares.js +129 -0
- package/apps/runtime/dist/services/widgets.js +34 -0
- package/apps/runtime/dist/services/wizards.js +342 -0
- package/apps/runtime/dist/settings.js +16 -0
- package/apps/runtime/dist/store/index.js +279 -0
- package/apps/runtime/dist/tenants/control.js +106 -0
- package/apps/runtime/dist/tenants/tenant.js +26 -0
- package/apps/runtime/dist/tools/browser.js +380 -0
- package/apps/runtime/dist/tools/connector.js +204 -0
- package/apps/runtime/dist/tools/index.js +234 -0
- package/apps/runtime/dist/tools/mail.js +104 -0
- package/apps/runtime/dist/tools/net-guard.js +59 -0
- package/apps/runtime/dist/tools/project.js +53 -0
- package/apps/runtime/dist/tools/shared.js +42 -0
- package/apps/runtime/dist/tools/store.js +238 -0
- package/apps/runtime/dist/update.js +118 -0
- package/apps/runtime/dist/widgets/bundle.js +99 -0
- package/apps/runtime/dist/widgets/render.js +312 -0
- package/apps/runtime/dist/widgets/runtime.js +84 -0
- package/apps/runtime/dist/widgets/script.js +30 -0
- package/apps/runtime/dist/widgets/step.js +192 -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/ChangelogDialog-O00vEnbm.js +1 -0
- package/apps/web/dist/assets/ChatPanel-CH9ry0Hp.js +1 -0
- package/apps/web/dist/assets/CreditsDialog-DRzecwUw.js +1 -0
- package/apps/web/dist/assets/EditorPage-BRnBf02Q.js +2 -0
- package/apps/web/dist/assets/FlowPreview-DDOj8IAH.js +1 -0
- package/apps/web/dist/assets/HomePage-CAGTTG3N.js +1 -0
- package/apps/web/dist/assets/ImportWizard-0RRrAnX3.js +1 -0
- package/apps/web/dist/assets/LocalRuntime-BrP-ENHg.css +1 -0
- package/apps/web/dist/assets/LocalRuntime-C-TBYrzs.js +16 -0
- package/apps/web/dist/assets/NewWizardPage-kI90h3_9.js +2 -0
- package/apps/web/dist/assets/PublicRunner-CKRDeIVd.js +1 -0
- package/apps/web/dist/assets/RunnerView-Rc4H8wYH.js +2 -0
- package/apps/web/dist/assets/SettingsPage-CESMuZxq.js +2 -0
- package/apps/web/dist/assets/SetupPage-D1rrYU14.js +1 -0
- package/apps/web/dist/assets/SharePage-COTAmOgh.js +1 -0
- package/apps/web/dist/assets/api-BY28cjGY.js +10 -0
- package/apps/web/dist/assets/arrow-left-UpjOBfQp.js +1 -0
- package/apps/web/dist/assets/arrow-right-CucQycEy.js +1 -0
- package/apps/web/dist/assets/changelog-p3wsaDDS.js +1 -0
- package/apps/web/dist/assets/check-Bjx41xbB.js +1 -0
- package/apps/web/dist/assets/createLucideIcon-DBu2Ovxj.js +1 -0
- package/apps/web/dist/assets/definition-cy7uvY5L.js +55 -0
- package/apps/web/dist/assets/engenty-CWIFpgKq.js +1 -0
- package/apps/web/dist/assets/esm-D1OEhjTK.js +7 -0
- package/apps/web/dist/assets/external-link-CRg6DVdO.js +1 -0
- package/apps/web/dist/assets/fluffy-engenty-CJ3wCQgT.js +456 -0
- package/apps/web/dist/assets/index-CQ_q9iMO.css +1 -0
- package/apps/web/dist/assets/index-D0gxh90t.js +10 -0
- package/apps/web/dist/assets/jsx-runtime-Dk72oS4N.js +1 -0
- package/apps/web/dist/assets/meta-BbSdtTUa.js +1 -0
- package/apps/web/dist/assets/mic-CeqQ89Dj.js +1 -0
- package/apps/web/dist/assets/oss-credits-cPuZUFHD.js +1 -0
- package/apps/web/dist/assets/outputs-D6pxH6ve.js +69 -0
- package/apps/web/dist/assets/plus-HA210wXA.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/type-BzYgVWKL.js +1 -0
- package/apps/web/dist/assets/ui-Ddwl35A6.js +1 -0
- package/apps/web/dist/assets/upload-DsgLfQ3U.js +1 -0
- package/apps/web/dist/assets/video-Dk1fuTDl.js +1 -0
- package/apps/web/dist/assets/wand-sparkles-Bf97fs8T.js +1 -0
- package/apps/web/dist/embed.js +102 -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 +46 -0
- package/apps/web/dist/install.sh +532 -0
- package/apps/web/dist/manifest.webmanifest +20 -0
- package/apps/web/dist/sw.js +15 -0
- package/bin/wizards.mjs +13 -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/definition.d.ts +1415 -0
- package/node_modules/@engenty-wizards/shared/dist/definition.js +762 -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 +216 -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/marketplace-entry.d.ts +35 -0
- package/node_modules/@engenty-wizards/shared/dist/marketplace-entry.js +86 -0
- package/node_modules/@engenty-wizards/shared/dist/marketplace-search.d.ts +20 -0
- package/node_modules/@engenty-wizards/shared/dist/marketplace-search.js +133 -0
- package/node_modules/@engenty-wizards/shared/dist/marketplace.d.ts +298 -0
- package/node_modules/@engenty-wizards/shared/dist/marketplace.js +211 -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/projects.d.ts +74 -0
- package/node_modules/@engenty-wizards/shared/dist/projects.js +96 -0
- package/node_modules/@engenty-wizards/shared/dist/run.d.ts +219 -0
- package/node_modules/@engenty-wizards/shared/dist/run.js +1 -0
- package/node_modules/@engenty-wizards/shared/dist/store.d.ts +100 -0
- package/node_modules/@engenty-wizards/shared/dist/store.js +44 -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 +62 -0
- 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
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { writeStoreFile } from "../store/index.js";
|
|
2
|
+
export const TEXT_LIMIT = 8000;
|
|
3
|
+
export function clip(s, limit = TEXT_LIMIT) {
|
|
4
|
+
return s.length > limit ? `${s.slice(0, limit)}\n…[truncated ${s.length - limit} chars]` : s;
|
|
5
|
+
}
|
|
6
|
+
/** A tool failure is something the model reads and reacts to, never a crashed step. */
|
|
7
|
+
export async function attempt(run) {
|
|
8
|
+
try {
|
|
9
|
+
return await run();
|
|
10
|
+
}
|
|
11
|
+
catch (err) {
|
|
12
|
+
return { error: String(err?.message ?? err).slice(0, 400) };
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Files a step collects go two places: the wizard's store (kept for next time) and the step's
|
|
17
|
+
* result (this run's download). One keeper per step, so a file saved twice is one result.
|
|
18
|
+
*/
|
|
19
|
+
export class FileKeeper {
|
|
20
|
+
ctx;
|
|
21
|
+
assets;
|
|
22
|
+
kept = new Map();
|
|
23
|
+
constructor(ctx, assets) {
|
|
24
|
+
this.ctx = ctx;
|
|
25
|
+
this.assets = assets;
|
|
26
|
+
}
|
|
27
|
+
async keep(rawPath, data, meta) {
|
|
28
|
+
const scope = this.ctx.store;
|
|
29
|
+
const file = await writeStoreFile(scope, rawPath, data, meta);
|
|
30
|
+
if (!this.kept.has(file.path)) {
|
|
31
|
+
const ref = await this.ctx.saveAsset({
|
|
32
|
+
kind: "file",
|
|
33
|
+
mime: file.mime,
|
|
34
|
+
name: file.path.split("/").pop() ?? "file",
|
|
35
|
+
data,
|
|
36
|
+
});
|
|
37
|
+
this.kept.set(file.path, ref);
|
|
38
|
+
this.assets.push(ref);
|
|
39
|
+
}
|
|
40
|
+
return { path: file.path, mime: file.mime, size: file.size };
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
import { allFields } from "@engenty-wizards/shared/definition";
|
|
2
|
+
import { TableColumnValueError } from "@engenty-wizards/shared/engenty/data-tables";
|
|
3
|
+
import { createTool } from "@mastra/core/tools";
|
|
4
|
+
import { eq } from "drizzle-orm";
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
import { db, schema } from "../db/client.js";
|
|
7
|
+
import { parseDocument, scanDocument } from "../documents/parse.js";
|
|
8
|
+
import { loadAsset } from "../files/storage.js";
|
|
9
|
+
import { deleteRows, listRows, readStoreFile, saveRows, storeFiles } from "../store/index.js";
|
|
10
|
+
import { attempt, clip } from "./shared.js";
|
|
11
|
+
/** Files the person gave on earlier pages: `upload:<id>` is how tools address them. */
|
|
12
|
+
export async function personUploads(ctx) {
|
|
13
|
+
const out = [];
|
|
14
|
+
for (const field of allFields(ctx.def)) {
|
|
15
|
+
if (field.kind !== "image" && field.kind !== "file") {
|
|
16
|
+
continue;
|
|
17
|
+
}
|
|
18
|
+
const value = ctx.state.values[field.id];
|
|
19
|
+
const ids = (Array.isArray(value) ? value : [value]).filter((v) => typeof v === "string" && v.length > 0);
|
|
20
|
+
for (const id of ids) {
|
|
21
|
+
const row = await db.query.asset.findFirst({ where: eq(schema.asset.id, id) });
|
|
22
|
+
if (row?.runId === ctx.runId) {
|
|
23
|
+
out.push({ ref: `upload:${id}`, name: row.name, mime: row.mime, field: field.label });
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return out;
|
|
28
|
+
}
|
|
29
|
+
/** A file by the name agents use: `upload:<id>` (given by the person) or a path in the store. */
|
|
30
|
+
export async function resolveFile(ctx, file) {
|
|
31
|
+
if (file.startsWith("upload:")) {
|
|
32
|
+
const found = await loadAsset(file.slice("upload:".length));
|
|
33
|
+
if (!found || found.row.runId !== ctx.runId) {
|
|
34
|
+
throw new Error(`No upload ${file}.`);
|
|
35
|
+
}
|
|
36
|
+
return { data: new Uint8Array(found.data), name: found.row.name, mime: found.row.mime };
|
|
37
|
+
}
|
|
38
|
+
const stored = await readStoreFile(ctx.store, file);
|
|
39
|
+
if (!stored) {
|
|
40
|
+
throw new Error(`No file "${file}". Use files_list to see what is kept.`);
|
|
41
|
+
}
|
|
42
|
+
return {
|
|
43
|
+
data: new Uint8Array(stored.data),
|
|
44
|
+
name: stored.file.path.split("/").pop() ?? stored.file.path,
|
|
45
|
+
mime: stored.file.mime,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
function describeColumns(def) {
|
|
49
|
+
return def.columns
|
|
50
|
+
.map((c) => {
|
|
51
|
+
const rule = c.type === "date"
|
|
52
|
+
? c.format.kind === "date"
|
|
53
|
+
? "YYYY-MM-DD"
|
|
54
|
+
: c.format.kind
|
|
55
|
+
: c.type === "number"
|
|
56
|
+
? c.format.style === "currency"
|
|
57
|
+
? `number, ${c.format.currency}`
|
|
58
|
+
: "number"
|
|
59
|
+
: c.type === "select"
|
|
60
|
+
? `one of: ${c.format.options.map((o) => o.id).join(", ")}${c.format.allowCustom ? " (or your own)" : ""}`
|
|
61
|
+
: c.type;
|
|
62
|
+
return `${c.id} (${rule}${c.required ? ", required" : ""})`;
|
|
63
|
+
})
|
|
64
|
+
.join("; ");
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* What every agent step can do with the wizard's store and the person's files: read and write
|
|
68
|
+
* the lists, read documents (PDF, scans, photos, Word, Excel, CSV, saved mails).
|
|
69
|
+
*/
|
|
70
|
+
export function storeTools(ctx, uploads, keeper) {
|
|
71
|
+
const tools = {};
|
|
72
|
+
const lists = ctx.def.lists ?? [];
|
|
73
|
+
const charge = (usd) => ctx.chargeUsd(usd);
|
|
74
|
+
if (lists.length) {
|
|
75
|
+
const listId = z.enum(lists.map((l) => l.id));
|
|
76
|
+
const defOf = (id) => lists.find((l) => l.id === id);
|
|
77
|
+
const catalog = lists
|
|
78
|
+
.map((l) => `- ${l.id} — ${l.title}${l.key ? ` (rows are matched on "${l.key}")` : ""}: ${describeColumns(l)}`)
|
|
79
|
+
.join("\n");
|
|
80
|
+
tools.list_read = createTool({
|
|
81
|
+
id: "list_read",
|
|
82
|
+
description: `Read one of the lists this wizard keeps for the person between runs.\n${catalog}`,
|
|
83
|
+
inputSchema: z.object({ list: listId }),
|
|
84
|
+
execute: ({ list }) => attempt(async () => {
|
|
85
|
+
const rows = await listRows(ctx.store, list);
|
|
86
|
+
return {
|
|
87
|
+
list,
|
|
88
|
+
total: rows.length,
|
|
89
|
+
rows: rows.slice(0, 300).map((r) => ({ id: r.id, ...r.cells })),
|
|
90
|
+
};
|
|
91
|
+
}),
|
|
92
|
+
});
|
|
93
|
+
tools.list_write = createTool({
|
|
94
|
+
id: "list_write",
|
|
95
|
+
description: `Save rows into one of the wizard's lists, so the next run knows them. A row whose key column matches an existing row updates that row (only the columns you give change); otherwise it is added. Values must fit the column: dates as YYYY-MM-DD, numbers as numbers.\n${catalog}`,
|
|
96
|
+
inputSchema: z.object({
|
|
97
|
+
list: listId,
|
|
98
|
+
rows: z
|
|
99
|
+
.array(z.record(z.string(), z.unknown()))
|
|
100
|
+
.max(200)
|
|
101
|
+
.optional()
|
|
102
|
+
.describe("Rows as { columnId: value }."),
|
|
103
|
+
delete: z
|
|
104
|
+
.array(z.string())
|
|
105
|
+
.max(200)
|
|
106
|
+
.optional()
|
|
107
|
+
.describe("Rows to remove: their key column's value, or their id."),
|
|
108
|
+
}),
|
|
109
|
+
execute: ({ list, rows, delete: remove }) => attempt(async () => {
|
|
110
|
+
const def = defOf(list);
|
|
111
|
+
try {
|
|
112
|
+
const saved = rows?.length
|
|
113
|
+
? await saveRows(ctx.store, def, rows)
|
|
114
|
+
: { added: 0, updated: 0 };
|
|
115
|
+
const deleted = remove?.length ? await deleteRows(ctx.store, def, remove) : 0;
|
|
116
|
+
await ctx.emit("tool", `Merkt sich ${def.title}`);
|
|
117
|
+
return { ...saved, deleted };
|
|
118
|
+
}
|
|
119
|
+
catch (err) {
|
|
120
|
+
if (err instanceof TableColumnValueError) {
|
|
121
|
+
return {
|
|
122
|
+
error: `Column "${err.columnId}": ${err.message}. Nothing after that row was saved.`,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
throw err;
|
|
126
|
+
}
|
|
127
|
+
}),
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
tools.files_list = createTool({
|
|
131
|
+
id: "files_list",
|
|
132
|
+
description: "List the files this wizard keeps for the person (invoices collected on earlier runs, scans …), optionally only one folder.",
|
|
133
|
+
inputSchema: z.object({ folder: z.string().optional() }),
|
|
134
|
+
execute: ({ folder }) => attempt(async () => {
|
|
135
|
+
const files = await storeFiles(ctx.store, folder);
|
|
136
|
+
return {
|
|
137
|
+
total: files.length,
|
|
138
|
+
files: files.slice(0, 300).map((f) => ({
|
|
139
|
+
path: f.path,
|
|
140
|
+
mime: f.mime,
|
|
141
|
+
size: f.size,
|
|
142
|
+
source: f.source,
|
|
143
|
+
date: f.updatedAt.slice(0, 10),
|
|
144
|
+
})),
|
|
145
|
+
};
|
|
146
|
+
}),
|
|
147
|
+
});
|
|
148
|
+
if (uploads.length) {
|
|
149
|
+
tools.files_keep = createTool({
|
|
150
|
+
id: "files_keep",
|
|
151
|
+
description: "Keep files the person gave in the wizard's files, several at once: each is stored under `path`, is there on the next run and belongs to this step's result. Returns the path each file now has.",
|
|
152
|
+
inputSchema: z.object({
|
|
153
|
+
items: z
|
|
154
|
+
.array(z.object({
|
|
155
|
+
file: z.string().describe("An upload reference, upload:<id>."),
|
|
156
|
+
path: z.string().describe("e.g. belege/2026-09/2026-09-03_Notion_INV-123.pdf"),
|
|
157
|
+
}))
|
|
158
|
+
.min(1)
|
|
159
|
+
.max(40),
|
|
160
|
+
}),
|
|
161
|
+
execute: ({ items }) => attempt(async () => {
|
|
162
|
+
await ctx.emit("tool", `Legt ${items.length} Dateien ab`);
|
|
163
|
+
const kept = [];
|
|
164
|
+
for (const item of items) {
|
|
165
|
+
try {
|
|
166
|
+
const source = await resolveFile(ctx, item.file);
|
|
167
|
+
const file = await keeper.keep(item.path, source.data, {
|
|
168
|
+
mime: source.mime,
|
|
169
|
+
source: `Von der Person: ${source.name}`,
|
|
170
|
+
});
|
|
171
|
+
kept.push({ file: item.file, path: file.path });
|
|
172
|
+
}
|
|
173
|
+
catch (err) {
|
|
174
|
+
kept.push({ file: item.file, error: String(err.message).slice(0, 200) });
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
return { kept };
|
|
178
|
+
}),
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
const fileHint = uploads.length
|
|
182
|
+
? ` The person gave: ${uploads.map((u) => `${u.ref} (${u.name})`).join(", ")}.`
|
|
183
|
+
: "";
|
|
184
|
+
tools.read_document = createTool({
|
|
185
|
+
id: "read_document",
|
|
186
|
+
description: `Read a document as text: PDF, scan or photo (read by a vision model), Word, Excel, CSV, a saved mail. \`file\` is an upload reference or a path in the wizard's files.${fileHint}`,
|
|
187
|
+
inputSchema: z.object({
|
|
188
|
+
file: z.string(),
|
|
189
|
+
offset: z.number().int().min(0).optional().describe("Start at this character, to read on."),
|
|
190
|
+
}),
|
|
191
|
+
execute: ({ file, offset }) => attempt(async () => {
|
|
192
|
+
const source = await resolveFile(ctx, file);
|
|
193
|
+
await ctx.emit("tool", `Liest ${source.name}`, file.startsWith("upload:") && source.mime.startsWith("image/")
|
|
194
|
+
? file.slice("upload:".length)
|
|
195
|
+
: undefined);
|
|
196
|
+
const doc = await parseDocument(source, { charge, signal: ctx.signal, call: ctx.call });
|
|
197
|
+
const start = offset ?? 0;
|
|
198
|
+
return {
|
|
199
|
+
file,
|
|
200
|
+
pages: doc.pages,
|
|
201
|
+
readBy: doc.via,
|
|
202
|
+
length: doc.markdown.length,
|
|
203
|
+
text: clip(doc.markdown.slice(start), 12_000),
|
|
204
|
+
};
|
|
205
|
+
}),
|
|
206
|
+
});
|
|
207
|
+
tools.scan_documents = createTool({
|
|
208
|
+
id: "scan_documents",
|
|
209
|
+
description: `Pull the key fields out of invoices or receipts, several at once: vendor, number, dates, net/tax/total, currency, VAT id. Cheaper and more exact than reading each document yourself. Amounts come back exactly as printed.${fileHint}`,
|
|
210
|
+
inputSchema: z.object({
|
|
211
|
+
files: z.array(z.string()).min(1).max(30),
|
|
212
|
+
kind: z.enum(["invoice", "receipt"]),
|
|
213
|
+
}),
|
|
214
|
+
execute: ({ files, kind }) => attempt(async () => {
|
|
215
|
+
await ctx.emit("tool", `Liest ${files.length} ${kind === "invoice" ? "Rechnungen" : "Belege"}`);
|
|
216
|
+
const results = [];
|
|
217
|
+
for (let i = 0; i < files.length; i += 4) {
|
|
218
|
+
const batch = await Promise.all(files.slice(i, i + 4).map(async (file) => {
|
|
219
|
+
try {
|
|
220
|
+
const source = await resolveFile(ctx, file);
|
|
221
|
+
const scan = await scanDocument(source, kind, {
|
|
222
|
+
charge,
|
|
223
|
+
signal: ctx.signal,
|
|
224
|
+
});
|
|
225
|
+
const { line_items: _items, ...fields } = scan;
|
|
226
|
+
return { file, ...fields };
|
|
227
|
+
}
|
|
228
|
+
catch (err) {
|
|
229
|
+
return { file, error: String(err.message).slice(0, 200) };
|
|
230
|
+
}
|
|
231
|
+
}));
|
|
232
|
+
results.push(...batch);
|
|
233
|
+
}
|
|
234
|
+
return { documents: results };
|
|
235
|
+
}),
|
|
236
|
+
});
|
|
237
|
+
return tools;
|
|
238
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { mkdirSync, openSync } from "node:fs";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { installedByScript, isCheckout, layout, packageRoot, packageVersion } from "./cli/home.js";
|
|
5
|
+
const RELEASES_URL = process.env.ENGENTY_WIZARDS_RELEASES_URL?.trim() ||
|
|
6
|
+
"https://api.github.com/repos/engenty/engenty-wizards/releases/latest";
|
|
7
|
+
const FOUND_FOR_MS = 6 * 60 * 60_000;
|
|
8
|
+
const MISSED_FOR_MS = 60 * 60_000;
|
|
9
|
+
/**
|
|
10
|
+
* The exit code with which the runtime asks the command that started it for a restart: after an
|
|
11
|
+
* update, that command starts the new version (cli/start.ts).
|
|
12
|
+
*/
|
|
13
|
+
export const RESTART_EXIT = 75;
|
|
14
|
+
/** Set by the command that starts the runtime when it starts it again on RESTART_EXIT. */
|
|
15
|
+
const RESTARTS = "ENGENTY_WIZARDS_RESTARTS";
|
|
16
|
+
let cached = null;
|
|
17
|
+
let applying = "idle";
|
|
18
|
+
let restart = null;
|
|
19
|
+
/** How the runtime stops cleanly; the update calls it with RESTART_EXIT once it is installed. */
|
|
20
|
+
export function onRestart(shutdown) {
|
|
21
|
+
restart = shutdown;
|
|
22
|
+
}
|
|
23
|
+
function restarts() {
|
|
24
|
+
return process.env[RESTARTS] === "1" && restart !== null;
|
|
25
|
+
}
|
|
26
|
+
/** `0.2.0` or `v0.2.0` as numbers; anything after a `-` (a pre-release) is ignored. */
|
|
27
|
+
function numbers(version) {
|
|
28
|
+
return version
|
|
29
|
+
.replace(/^v/, "")
|
|
30
|
+
.split("-")[0]
|
|
31
|
+
.split(".")
|
|
32
|
+
.map((part) => Number.parseInt(part, 10) || 0);
|
|
33
|
+
}
|
|
34
|
+
export function isNewer(latest, current) {
|
|
35
|
+
const a = numbers(latest);
|
|
36
|
+
const b = numbers(current);
|
|
37
|
+
for (let i = 0; i < Math.max(a.length, b.length); i++) {
|
|
38
|
+
const diff = (a[i] ?? 0) - (b[i] ?? 0);
|
|
39
|
+
if (diff !== 0) {
|
|
40
|
+
return diff > 0;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
async function newestRelease() {
|
|
46
|
+
if (process.env.ENGENTY_WIZARDS_NO_UPDATE_CHECK) {
|
|
47
|
+
return { latest: null, url: null };
|
|
48
|
+
}
|
|
49
|
+
const age = cached ? Date.now() - cached.at : Number.POSITIVE_INFINITY;
|
|
50
|
+
if (cached && age < (cached.latest ? FOUND_FOR_MS : MISSED_FOR_MS)) {
|
|
51
|
+
return cached;
|
|
52
|
+
}
|
|
53
|
+
let found = { latest: null, url: null };
|
|
54
|
+
try {
|
|
55
|
+
const response = await fetch(RELEASES_URL, {
|
|
56
|
+
headers: { accept: "application/vnd.github+json", "user-agent": "engenty-wizards" },
|
|
57
|
+
signal: AbortSignal.timeout(5000),
|
|
58
|
+
});
|
|
59
|
+
if (response.ok) {
|
|
60
|
+
const release = (await response.json());
|
|
61
|
+
if (typeof release.tag_name === "string" && /^v?\d+\.\d+/.test(release.tag_name)) {
|
|
62
|
+
found = { latest: release.tag_name.replace(/^v/, ""), url: release.html_url ?? null };
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
// offline: the studio says nothing
|
|
68
|
+
}
|
|
69
|
+
cached = { at: Date.now(), ...found };
|
|
70
|
+
return found;
|
|
71
|
+
}
|
|
72
|
+
function installKind() {
|
|
73
|
+
return installedByScript() ? "script" : isCheckout() ? "checkout" : "npm";
|
|
74
|
+
}
|
|
75
|
+
export async function updateStatus() {
|
|
76
|
+
const current = packageVersion();
|
|
77
|
+
const { latest, url } = await newestRelease();
|
|
78
|
+
const kind = installKind();
|
|
79
|
+
return {
|
|
80
|
+
current,
|
|
81
|
+
latest,
|
|
82
|
+
newer: latest !== null && isNewer(latest, current),
|
|
83
|
+
kind,
|
|
84
|
+
url,
|
|
85
|
+
canApply: kind === "script",
|
|
86
|
+
restarts: restarts(),
|
|
87
|
+
applying,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Runs `wizards update` in the background, the same steps as in a terminal. Afterwards a
|
|
92
|
+
* runtime started by the command restarts into the new version; any other keeps running the old
|
|
93
|
+
* one until somebody restarts it. The output goes to logs/update.log.
|
|
94
|
+
*/
|
|
95
|
+
export function applyUpdate() {
|
|
96
|
+
if (applying === "running" || installKind() !== "script") {
|
|
97
|
+
return applying;
|
|
98
|
+
}
|
|
99
|
+
const paths = layout();
|
|
100
|
+
mkdirSync(paths.logs, { recursive: true });
|
|
101
|
+
const log = openSync(join(paths.logs, "update.log"), "a");
|
|
102
|
+
applying = "running";
|
|
103
|
+
const child = spawn(process.execPath, [join(packageRoot, "bin/wizards.mjs"), "update"], {
|
|
104
|
+
cwd: paths.home,
|
|
105
|
+
stdio: ["ignore", log, log],
|
|
106
|
+
});
|
|
107
|
+
child.on("error", () => {
|
|
108
|
+
applying = "failed";
|
|
109
|
+
});
|
|
110
|
+
child.on("exit", (code) => {
|
|
111
|
+
applying = code === 0 ? "done" : "failed";
|
|
112
|
+
if (applying === "done" && restarts()) {
|
|
113
|
+
// A moment for the page to hear that it is done.
|
|
114
|
+
setTimeout(() => restart?.(RESTART_EXIT), 1500);
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
return applying;
|
|
118
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { posix } from "node:path";
|
|
2
|
+
import { isTextMime } from "@engenty-wizards/shared/workspace";
|
|
3
|
+
import { getBlob } from "../files/blobs.js";
|
|
4
|
+
import { guardHtml } from "../render/guard.js";
|
|
5
|
+
import { WIDGET_RUNTIME } from "./runtime.js";
|
|
6
|
+
const MAX_BUNDLE_BYTES = 30_000_000;
|
|
7
|
+
function isExternal(ref) {
|
|
8
|
+
return /^(?:[a-z][a-z0-9+.-]*:|\/\/|#)/i.test(ref);
|
|
9
|
+
}
|
|
10
|
+
/** A reference in a file at `fromDir`, as a workspace path. */
|
|
11
|
+
function resolvePath(ref, fromDir) {
|
|
12
|
+
const clean = ref.split(/[?#]/)[0];
|
|
13
|
+
return clean.startsWith("/")
|
|
14
|
+
? posix.normalize(clean.slice(1))
|
|
15
|
+
: posix.normalize(posix.join(fromDir, clean));
|
|
16
|
+
}
|
|
17
|
+
function dataUri(l) {
|
|
18
|
+
return `data:${l.file.mime};base64,${l.data.toString("base64")}`;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* The widget as ONE self-contained HTML file: its scripts, styles and images inlined, every other
|
|
22
|
+
* workspace file in the payload `wizard.file()` reads, and the run's data. This file is the result:
|
|
23
|
+
* it is what the preview shows, what is shared, downloaded, and rendered to PNG/PDF/MP4.
|
|
24
|
+
*/
|
|
25
|
+
export async function bundleWidget(input) {
|
|
26
|
+
const loaded = new Map();
|
|
27
|
+
for (const file of input.files) {
|
|
28
|
+
loaded.set(file.path, { file, data: await getBlob(file.hash) });
|
|
29
|
+
}
|
|
30
|
+
const entry = loaded.get(input.entry);
|
|
31
|
+
if (!entry) {
|
|
32
|
+
throw new Error(`The widget file ${input.entry} is missing from the workspace.`);
|
|
33
|
+
}
|
|
34
|
+
const inlined = new Set([input.entry]);
|
|
35
|
+
const lookup = (ref, fromDir) => {
|
|
36
|
+
if (isExternal(ref)) {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
return loaded.get(resolvePath(ref, fromDir)) ?? loaded.get(resolvePath(ref, "")) ?? null;
|
|
40
|
+
};
|
|
41
|
+
const inlineCssUrls = (css, fromDir) => css.replace(/url\(\s*(['"]?)([^'")]+)\1\s*\)/g, (m, _q, ref) => {
|
|
42
|
+
const l = lookup(ref, fromDir);
|
|
43
|
+
return l ? `url("${dataUri(l)}")` : m;
|
|
44
|
+
});
|
|
45
|
+
const entryDir = posix.dirname(input.entry) === "." ? "" : posix.dirname(input.entry);
|
|
46
|
+
let html = entry.data.toString("utf8");
|
|
47
|
+
html = html.replace(/<script\b([^>]*?)\bsrc\s*=\s*(['"])([^'"]+)\2([^>]*)>\s*<\/script>/gi, (m, before, _q, ref, after) => {
|
|
48
|
+
const l = lookup(ref, entryDir);
|
|
49
|
+
if (!l) {
|
|
50
|
+
return m;
|
|
51
|
+
}
|
|
52
|
+
inlined.add(l.file.path);
|
|
53
|
+
const code = l.data.toString("utf8").replace(/<\/script/gi, "<\\/script");
|
|
54
|
+
return `<script${before}${after}>${code}</script>`;
|
|
55
|
+
});
|
|
56
|
+
html = html.replace(/<link\b[^>]*>/gi, (tag) => {
|
|
57
|
+
if (!/\brel\s*=\s*(['"]?)stylesheet\1/i.test(tag)) {
|
|
58
|
+
return tag;
|
|
59
|
+
}
|
|
60
|
+
const ref = tag.match(/\bhref\s*=\s*(['"])([^'"]+)\1/i)?.[2];
|
|
61
|
+
const l = ref ? lookup(ref, entryDir) : null;
|
|
62
|
+
if (!l) {
|
|
63
|
+
return tag;
|
|
64
|
+
}
|
|
65
|
+
inlined.add(l.file.path);
|
|
66
|
+
const dir = posix.dirname(l.file.path) === "." ? "" : posix.dirname(l.file.path);
|
|
67
|
+
return `<style>${inlineCssUrls(l.data.toString("utf8"), dir)}</style>`;
|
|
68
|
+
});
|
|
69
|
+
html = html.replace(/(<style\b[^>]*>)([\s\S]*?)(<\/style>)/gi, (_m, open, css, close) => `${open}${inlineCssUrls(css, entryDir)}${close}`);
|
|
70
|
+
html = html.replace(/(<(?:img|source|video|audio|image|use)\b[^>]*?\b(?:src|href|poster|xlink:href)\s*=\s*)(['"])([^'"]+)\2/gi, (m, head, q, ref) => {
|
|
71
|
+
const l = lookup(ref, entryDir);
|
|
72
|
+
return l ? `${head}${q}${dataUri(l)}${q}` : m;
|
|
73
|
+
});
|
|
74
|
+
const payloadFiles = {};
|
|
75
|
+
for (const [path, l] of loaded) {
|
|
76
|
+
if (inlined.has(path)) {
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
payloadFiles[path] = isTextMime(l.file.mime)
|
|
80
|
+
? { mime: l.file.mime, text: l.data.toString("utf8") }
|
|
81
|
+
: { mime: l.file.mime, b64: l.data.toString("base64") };
|
|
82
|
+
}
|
|
83
|
+
const payload = JSON.stringify({
|
|
84
|
+
data: input.data ?? {},
|
|
85
|
+
brand: input.brand,
|
|
86
|
+
ai: input.ai ?? null,
|
|
87
|
+
files: payloadFiles,
|
|
88
|
+
base: entryDir ? `${entryDir}/` : "",
|
|
89
|
+
}).replace(/</g, "\\u003c");
|
|
90
|
+
const boot = `<script type="application/json" id="wizard-payload">${payload}</script><script>${WIDGET_RUNTIME}</script>`;
|
|
91
|
+
html = /<head[^>]*>/i.test(html)
|
|
92
|
+
? html.replace(/<head[^>]*>/i, (m) => `${m}${boot}`)
|
|
93
|
+
: `<!doctype html><html><head>${boot}</head><body>${html}</body></html>`;
|
|
94
|
+
const out = guardHtml(html, input.media);
|
|
95
|
+
if (Buffer.byteLength(out) > MAX_BUNDLE_BYTES) {
|
|
96
|
+
throw new Error("The widget with its files is larger than 30 MB.");
|
|
97
|
+
}
|
|
98
|
+
return out;
|
|
99
|
+
}
|