@withandeo/cli 0.12.0 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/README.md +28 -11
  2. package/dist/api.d.ts +21 -2
  3. package/dist/api.d.ts.map +1 -1
  4. package/dist/api.js +9 -0
  5. package/dist/api.js.map +1 -1
  6. package/dist/artifact.d.ts.map +1 -1
  7. package/dist/artifact.js +21 -0
  8. package/dist/artifact.js.map +1 -1
  9. package/dist/capability-preflight.d.ts +7 -0
  10. package/dist/capability-preflight.d.ts.map +1 -0
  11. package/dist/capability-preflight.js +48 -0
  12. package/dist/capability-preflight.js.map +1 -0
  13. package/dist/contracts.d.ts +18 -0
  14. package/dist/contracts.d.ts.map +1 -1
  15. package/dist/documentation.d.ts +13 -0
  16. package/dist/documentation.d.ts.map +1 -0
  17. package/dist/documentation.js +70 -0
  18. package/dist/documentation.js.map +1 -0
  19. package/dist/main.d.ts.map +1 -1
  20. package/dist/main.js +80 -16
  21. package/dist/main.js.map +1 -1
  22. package/package.json +1 -1
  23. package/skill/tender-accounts/SKILL.md +48 -385
  24. package/skill/tender-accounts/references/authentication.md +38 -0
  25. package/skill/tender-accounts/references/configuration-secrets.md +21 -0
  26. package/skill/tender-accounts/references/delivery.md +125 -0
  27. package/skill/tender-accounts/references/domains-auth.md +13 -0
  28. package/skill/tender-accounts/references/managed-source.md +124 -0
  29. package/skill/tender-accounts/references/observability.md +18 -0
  30. package/skill/tender-accounts/references/releases-recovery.md +16 -0
  31. package/skill/tender-accounts/references/services.md +11 -0
  32. package/skill/tender-accounts/references/storage.md +13 -0
  33. package/skill/tender-accounts/references/workflows.md +69 -0
  34. package/templates/shopify-customer-account/apps/gateway/.tender/artifacts/current/tender-accounts-build.json +99 -0
  35. package/templates/shopify-customer-account/apps/gateway/.tender/artifacts/current/worker.mjs +1785 -0
  36. package/templates/shopify-customer-account/apps/gateway/.tender/build/worker.mjs +1785 -0
  37. package/templates/shopify-customer-account/apps/gateway/scripts/pack-tender-artifact.mjs +5 -2
@@ -0,0 +1,125 @@
1
+ # Build, preview and publish
2
+
3
+ ## Implement and validate
4
+
5
+ 1. Inspect the existing application and tests before changing code.
6
+ 2. Use the repository's own development workflow. `npx @withandeo/cli dev` delegates to the committed `commands.dev`, starts local development, and never creates an Andeo deployment.
7
+ 3. Make the smallest source change that satisfies the request.
8
+ 4. Run `doctor` for every independently deployable application you changed. In a generated repository:
9
+
10
+ ```sh
11
+ npx @withandeo/cli doctor --cwd apps/portal --json
12
+ npx @withandeo/cli doctor --cwd apps/gateway --json
13
+ ```
14
+
15
+ Do not require gateway access for a portal-only task. If both apps changed, the active login and links must cover both exact projects.
16
+ 5. Run the deterministic repository checks:
17
+
18
+ ```sh
19
+ npx @withandeo/cli check --json
20
+ ```
21
+
22
+ 6. Validate the complete portable artifact without uploading it:
23
+
24
+ ```sh
25
+ npx @withandeo/cli preview --dry-run --json
26
+ ```
27
+
28
+ Do not weaken checks, remove declared bindings, or place runtime values in the artifact to make validation pass.
29
+
30
+ ## Retain a local build for administrator publication
31
+
32
+ When the user requests the manual build path, use `andeo upload --dry-run --json`
33
+ and then `andeo upload --json`. This runs the repository checks and packaging,
34
+ verifies and retains the artifact, and returns its exact release ID and digest.
35
+ It does not create a preview runtime or publish production. An administrator
36
+ reviews the artifact in **Changes → Publish a retained artifact** and approves
37
+ publication explicitly. Local builds do not require a GitHub run for this
38
+ manual path; their source labels remain unverified. The CLI cannot approve
39
+ publication, and automatic source publication still requires trusted main
40
+ evidence. Continue to honor explicit production approval from the user.
41
+
42
+ ## Create an exact preview
43
+
44
+ After local validation succeeds, preview each changed application. For a portal-only change, run:
45
+
46
+ ```sh
47
+ npx @withandeo/cli preview --cwd apps/portal --json
48
+ ```
49
+
50
+ For a new account stack or a change spanning both apps, package and preview the portal and gateway as separate projects:
51
+
52
+ ```sh
53
+ npx @withandeo/cli preview --cwd apps/portal --json
54
+ npx @withandeo/cli preview --cwd apps/gateway --json
55
+ ```
56
+
57
+ On the first stack preview, the first command may retain its exact release and return `bootstrap_counterpart_release_missing`. This is an expected incomplete stack, not permission to change IDs or bypass Andeo: build the named counterpart once, then rerun the failed side only if the second command did not already seal the composition. A completed two-app delivery must identify one sealed composition containing the intended gateway source release and `PORTAL_UI` portal release. Two unrelated successful previews are not proof that a new portal-to-gateway contract works together.
58
+
59
+ Treat stdout as one machine-readable JSON object. Preserve and report:
60
+
61
+ - `previewUrl`;
62
+ - `deliveryId`;
63
+ - `releaseId`;
64
+ - `bundleDigest`;
65
+ - `compositionId` when the delivery sealed one;
66
+ - validation performed before delivery.
67
+
68
+ The CLI may label an uncommitted local preview with a `local-...` source revision. The immutable bundle digest remains the content identity. Do not claim the change is committed or pushed unless separately verified.
69
+
70
+ ## Prove the customer journey
71
+
72
+ Local development proves layout and explicitly local behavior; it intentionally stays signed out for the generated Shopify starter. Real Shopify sign-in must be tested on an immutable HTTPS Andeo preview.
73
+
74
+ Inspect the actual rendered application, not only an HTTP `200` or deployment result. For the requested journey:
75
+
76
+ - verify `/api/bootstrap`, `/api/session`, and every new same-origin route on the exact preview;
77
+ - prove signed-out and signed-in behavior without reading or exposing tokens;
78
+ - exercise the requested read or mutation and confirm the authoritative response is reflected in the UI;
79
+ - verify a relevant empty or non-subscriber state and a contained provider failure;
80
+ - inspect desktop and 390 x 844 mobile behavior, including keyboard focus and pending/saved feedback.
81
+
82
+ If the portal shell works but an authenticated route returns `404`, classify it as gateway release or composition evidence. Do not repair it with client-side fallback data. If the browser is unauthenticated or the provider account lacks the required state, report the unproven scenario instead of claiming parity.
83
+
84
+ ## Diagnose a delivery
85
+
86
+ Read exact workflow state:
87
+
88
+ ```sh
89
+ npx @withandeo/cli delivery status --delivery <delivery-id> --json
90
+ ```
91
+
92
+ Retry only a requested or failed preview workflow:
93
+
94
+ ```sh
95
+ npx @withandeo/cli delivery retry --delivery <delivery-id> --json
96
+ ```
97
+
98
+ CLI 0.12.0 carries artifact/delivery access across automatic token refresh within
99
+ the same login. Logout, session expiry, or revoked owner/project access still
100
+ stop background work. For a pre-session-tracking preview stranded by an expired
101
+ credential, only its original owner may explicitly recover it from the linked
102
+ app with `delivery retry --delivery <delivery-id> --reauthorize --json`. This
103
+ requires current developer access, retains the exact artifact and upload
104
+ receipts, and cannot replace an already tracked login or publish production.
105
+ Do not clear pending provider holds or rewrite credential IDs to recover work.
106
+
107
+ Mint a new browser session for an already-succeeded delivery without rebuilding:
108
+
109
+ ```sh
110
+ npx @withandeo/cli preview entries --json
111
+ npx @withandeo/cli preview open --from <delivery-id> --json
112
+ npx @withandeo/cli preview open --from sbl_EXAMPLE --return-path /account --json
113
+ ```
114
+
115
+ Preview entry selection follows published app connections automatically. When the response requires a choice, select an eligible app using `--through prj_ENTRY`. Only the previewed app's developer grant is needed. Private apps cannot open directly; a connection administrator must enable an eligible entry. Preserve the exact `from` ID when recovering from a session error and use `preview open` instead of rebuilding. Opening replaces the browser's previous preview selection and preserves sign-in.
116
+
117
+ `<delivery-id>` is the `dly_` value returned by `preview`. A `dwf_` value is a production workflow ID and must not be passed to developer-delivery commands. If a merchant administrator sees a `dwf_` publish waiting with zero attempts, the supported recovery is **Activity → Resume exact publish**; it resumes the stored exact composition without rebuilding. Use the error code, request ID, and suggested command from the CLI. Do not retry with altered IDs, another project, or raw HTTP requests.
118
+
119
+ When runtime evidence is needed, stream only the linked project and exact target:
120
+
121
+ ```sh
122
+ npx @withandeo/cli tail --delivery <delivery-id> --status error --json
123
+ ```
124
+
125
+ Use `--production` only when the user is a merchant administrator and explicitly wants current production diagnostics. Tail output is sensitive even though Andeo omits request headers and redacts known secret fields. Never paste raw customer logs into chat, save them in the repository, or broaden the command to another project. Stop the stream as soon as the diagnostic is complete.
@@ -0,0 +1,13 @@
1
+ # Domains and customer authentication
2
+
3
+ Treat three configurations separately:
4
+
5
+ 1. Andeo routing plus merchant DNS and certificate.
6
+ 2. The app's exact hostname allowlist; the Shopify starter uses `ACCOUNT_VANITY_HOSTNAMES`.
7
+ 3. Shopify's registered JavaScript origins, `/auth/callback` and `/auth/logout/callback` URLs.
8
+
9
+ Add only the merchant-approved hostname, preserve existing hosts, package configuration and publish through Andeo. Keep generated-host authentication working. Do not introduce wildcard origins or bypass checks after a 404.
10
+
11
+ Verify `/api/health`, `/api/bootstrap`, `/api/session` and the rendered sign-in/account journey on both domains. HTML 200 does not prove authentication works. In the starter, healthy gateway plus session `not_found` can indicate hostname-policy rejection. Bootstrap should select the custom-domain login URL. Inspect stale browser preview selection before blaming production.
12
+
13
+ Keep customer authentication, Andeo administrator sign-in, protected app visibility and preview grants separate. Use supported administrator controls; do not assume every custom-domain/visibility combination works. Check signed-out denial, signed-in data, renewal and logout. Preserve provider adapter headers, redirects and timeouts when adding authenticated queries.
@@ -0,0 +1,124 @@
1
+ # Managed source
2
+
3
+ If the merchant wants Andeo to own the Git transport, use the CLI for either
4
+ the linked gateway or service project:
5
+
6
+ ```sh
7
+ npx @withandeo/cli source connect --publication preview-only --json
8
+ npx @withandeo/cli source status --json
9
+ npx @withandeo/cli source pull --json
10
+ npx @withandeo/cli source push --json
11
+ ```
12
+
13
+ Run these commands from the independently deployable app directory, or use its
14
+ exact `--cwd`. `source connect` derives the project working directory and build
15
+ contract from Git plus `tender-accounts.json`; do not recreate that contract by
16
+ hand in the admin. New connections default to preview-only. Both gateways and services support `--publication default-branch` when a merchant administrator explicitly enables automatic publication. For an existing connection use `source policy show`, then `source policy set --repository SRC_ID --publication default-branch --expected-revision N --idempotency-key KEY`. Saving the policy affects future source builds; it does not publish an existing build. Reconnecting never changes the policy.
17
+
18
+ `source push` includes only the committed revision. On a reviewed repository it
19
+ uploads a bounded Git bundle through Andeo; the trusted runner verifies the
20
+ exact commit and may update only the named non-default branch. The developer
21
+ never receives a provider write credential. On a repository that has not yet
22
+ enabled reviewed changes, the legacy short-lived Git credential path remains
23
+ available during migration. Never copy any credential into a remote URL,
24
+ credential helper, repository file, shell script, or chat. `source pull` is the
25
+ inverse operation for an already connected repository and never creates or
26
+ replaces the source connection. `source token` is read-only.
27
+
28
+ When `source status` reports `changeRequestProtection: enabled`, use the normal
29
+ reviewed flow:
30
+
31
+ ```sh
32
+ npx @withandeo/cli source push --branch feature/account-copy --json
33
+ npx @withandeo/cli source change create \
34
+ --head feature/account-copy \
35
+ --title "Update account copy" --json
36
+ npx @withandeo/cli source change show --change scr_... --json
37
+ ```
38
+
39
+ Return the `scr_` ID and exact preview state to the user. A developer or coding
40
+ agent stops after the exact preview is ready. Approval and **Land in main** are
41
+ merchant-administrator actions in Andeo. Do not push the default branch,
42
+ obtain a raw provider token, call internal APIs, or replace this flow with
43
+ `source promote` after reviewed changes are enabled.
44
+
45
+ After a successful landing, inspect `branchCleanup` in
46
+ `source change show --change scr_... --json`. `requested` and `running` need no
47
+ developer action. `succeeded` means the exact landed feature ref was deleted or
48
+ already absent. `retained` means Andeo deliberately kept a moved, reused, or
49
+ otherwise unsafe ref. `failed` does not undo landing; ask a merchant
50
+ administrator to retry cleanup in Andeo. Never obtain a provider write token
51
+ or delete the branch directly. All immutable build, release, composition,
52
+ approval, landing, and audit records remain available after cleanup.
53
+ Do not reuse the same feature branch or make it the default while cleanup is
54
+ `requested`, `running`, or retryable: Andeo deliberately fences that ref until
55
+ cleanup succeeds, retains it, or exhausts its bounded retry budget.
56
+
57
+ Inspect branches and history through read-only ephemeral credentials:
58
+
59
+ ```sh
60
+ npx @withandeo/cli source branches --json
61
+ npx @withandeo/cli source log --branch main --limit 20 --json
62
+ npx @withandeo/cli source compare --base main --head feature/account-copy --json
63
+ ```
64
+
65
+ Use standalone source-administration commands only for repositories where
66
+ reviewed changes are not enabled and when the user explicitly requests a
67
+ default-branch or history change and the active profile belongs to a merchant
68
+ source administrator. First record `source branches`, `source compare`, the
69
+ successful exact preview for the proposed head, and the current production
70
+ composition. Run the exact operation with `--dry-run` before applying it.
71
+
72
+ For an ordinary checked fast-forward, supply the current target SHA and a
73
+ stable idempotency key:
74
+
75
+ ```sh
76
+ npx @withandeo/cli source promote \
77
+ --head feature/account-copy \
78
+ --expected-current <exact-current-default-sha> \
79
+ --idempotency-key account-copy-v1 \
80
+ --dry-run --json
81
+ ```
82
+
83
+ For an exceptional migration, use only the guarded history workflow:
84
+
85
+ ```sh
86
+ npx @withandeo/cli source history replace \
87
+ --head app-only-main \
88
+ --expected-current <exact-current-default-sha> \
89
+ --confirm <exact-src-repository-id> \
90
+ --idempotency-key app-only-history-v1 \
91
+ --dry-run --json
92
+ ```
93
+
94
+ Inspect the returned `sop_` operation with `source operation status`. Apply the
95
+ same request without `--dry-run` only after the dry-run evidence matches the
96
+ intended repository, project, branches, SHA, preview build, and composition.
97
+ Never substitute a raw token, direct API, Git force push, ref deletion, or database
98
+ edit. Andeo creates and verifies an archive before history replacement and
99
+ uses an expected-SHA compare-and-swap for the target. History migration always
100
+ suppresses automatic production publication.
101
+
102
+ If a durable source operation fails for a transient provider or runner reason,
103
+ inspect and resume that same reviewed intent by ID:
104
+
105
+ ```sh
106
+ npx @withandeo/cli source operation status --operation sop_... --json
107
+ npx @withandeo/cli source operation retry --operation sop_... --json
108
+ ```
109
+
110
+ Do not create a replacement request merely to retry infrastructure. A stale
111
+ target, missing preview, archive conflict, or rejected permission requires the
112
+ stated remediation and a newly reviewed request instead.
113
+
114
+ For reviewed repositories, a moved head invalidates the previous approval and
115
+ the newest source build becomes the next exact snapshot. A moved base makes the
116
+ change stale. Rebase or update the feature branch, push a new committed
117
+ revision, wait for its exact preview, and have the administrator review that
118
+ new snapshot. Source landing never calls the production publisher directly;
119
+ after landing, the repository's already configured default-branch policy may
120
+ publish the same artifact after its exact preview and production validation succeed.
121
+
122
+ Treat source administration and production publication as different acts. A
123
+ source operation may create a new immutable preview lineage, but only the
124
+ merchant's saved policy or explicit publication approval can authorize production. Portal and gateway remain independent apps: configure variables, policy and delivery for each. Do not imply that two repository refs or apps publish atomically.
@@ -0,0 +1,18 @@
1
+ # Observability and diagnosis
2
+
3
+ | Layer | Investigation |
4
+ | --- | --- |
5
+ | Local setup | `andeo doctor --json`, checks, artifact dry-run |
6
+ | Preview delivery | `andeo delivery status --delivery dly_... --json` |
7
+ | Production publication | Exact `dwf_` in administrator Activity |
8
+ | Preview invocation | `andeo tail --delivery dly_... --status error --json` |
9
+ | Production invocation | `andeo tail --production --status error --json`, with merchant-admin authority |
10
+ | App workflow | `andeo workflows status`, `history`, `diagnostics`, `export` for exact scope/run |
11
+
12
+ Distinguish app runs from deployment workflows. Correlate project, environment, composition/release and safe run/request IDs. Never dump cookies, tokens, customer payloads or full provider errors. Sanitization cannot reliably protect secrets in arbitrary log strings.
13
+
14
+ Live tail is short-lived, not historical search. Workflow lists are projections; exact run status reads engine state. History/export is bounded/sanitized with cursors, not raw native output or a live stream. Service diagnostics identify service revisions and attempts but do not imply equivalent instrumentation for every direct fetch. Record business receipts with non-secret correlation fields when needed.
15
+
16
+ OTLP export is a separate administrator operation that can transmit raw telemetry to a merchant-approved destination. Verify deployment/support and destination approval first; do not invent export commands, install a new provider or promise historical dashboards from platform collection alone.
17
+
18
+ For 503s, distinguish identity lookup, storage, admission/create, execution and callbacks before retrying. Ambiguous create/event/provider outcomes require reconciliation using the same logical operation. Publication or accepted start is not proof of the business effect.
@@ -0,0 +1,16 @@
1
+ # Production releases and recovery
2
+
3
+ Production changes require explicit user authorization and an eligible merchant administrator. Developer preview permission is not production authority. No CLI publish command exists; use the protected policy or administrator console.
4
+
5
+ ```sh
6
+ andeo production releases --json
7
+ andeo production rollback --release TARGET_RELEASE_ID \
8
+ --expected-release CURRENT_RELEASE_ID --expected-revision N \
9
+ --idempotency-key approved-restore-001 --json
10
+ ```
11
+
12
+ Only run rollback when explicitly requested. Select an eligible retained target and current release/revision from platform results; never guess or silently replace stale expectations. Rollback creates a new audited activation, not a Git reset, database restore or old secret-value restoration. Reconcile uncertain outcomes before another request.
13
+
14
+ Recover `dwf_` publications via administrator Activity → Resume exact publish. `delivery retry` accepts `dly_` preview IDs, not production workflows. Preserve the approved intent; never edit platform records or submit duplicates to escape a hold.
15
+
16
+ Verify final state and actual live composition, same-origin authenticated APIs and relevant generated/custom hostnames. Retained artifacts, preview readiness, stale UI toasts or HTML success are insufficient. Running workflows can retain old definitions and service contracts; code rollback does not cancel them.
@@ -0,0 +1,11 @@
1
+ # Connected apps and service bindings
2
+
3
+ Use independently published private apps for secret-backed integrations or reusable operations. Declare the portable artifact connection, for example `services: [{ "name": "DELIVERY_SERVICE", "targetProject": "delivery-service" }]`, using the configured target slug. An administrator must allow the connection in Settings; a declaration cannot grant access.
4
+
5
+ Call `env.DELIVERY_SERVICE.fetch(...)`. Never reference physical Workers, namespaces or platform routing headers. Private apps cannot open directly. Keep browser APIs same-origin through the gateway and authorize business operations server-side.
6
+
7
+ Publish dependencies before consumers. Workflow targets must publish a public string `WORKFLOW_SERVICE_CONTRACT`, such as `delivery-v1`. Preserve compatibility while definitions/runs retain it; drain dependencies or introduce a separately versioned service for breaking changes. Workflow services support bounded fetch, not arbitrary business RPC.
8
+
9
+ Use `andeo preview entries --json` and `andeo preview open --from dly_... --json`. Preview-through permission is distinct from call permission. Apps without a selected preview use published revisions; verify the sealed composition, not an assumed collection of latest previews.
10
+
11
+ Inspect `andeo workflows preview-services --json` and `preview-service-set --help` for explicit workflow preview dependency selection. Never silently cross app/environment boundaries. Verify permitted calls and revoked/unauthorized denial. Revocation does not undo effects or block unrelated direct Internet requests.
@@ -0,0 +1,13 @@
1
+ # App-owned storage
2
+
3
+ Use storage for sessions, workflow receipts and app-owned state, not a replacement source of truth for provider business data. Run `andeo capabilities --json`: recognized resource types and enabled quotas do not prove automated provisioning support.
4
+
5
+ The supported automated database path is D1. Declare a named resource in the portable artifact, for example `resources: [{ "type": "d1", "name": "APP_DB" }]`. Account enablement and quota are prerequisites. Andeo owns trusted provisioning and exact environment bindings; never supply physical IDs or provision through provider credentials.
6
+
7
+ Hosted preview and production databases are separate. Do not assume preview has production rows. Local schema setup is app-owned; use the repository's schema declaration/packaging conventions and validate through preview/publication.
8
+
9
+ Prefer additive, backwards-compatible changes while old code/runs remain active. Code rollback does not restore data or undo migrations. Complex schema evolution, destructive changes and restores require an explicit reviewed plan and supported operator path.
10
+
11
+ KV, R2, Queues and Durable Objects may appear in contracts, entitlements or emulation, but are not automatically provisioned merchant resources without explicit support and hosted proof. Unsupported bindings must fail delivery, never disappear silently. Workflows have their own supported account resource lifecycle; read [Workflows](workflows.md).
12
+
13
+ Verify persistence after reload, customer-scoped queries, cross-customer denial and environment isolation. Parameterize queries; keep customer data out of logs and fixtures.
@@ -0,0 +1,69 @@
1
+ # App-defined workflows
2
+
3
+ Use workflows for durable multi-step work, delays and event waits. An administrator must enable the account's workflow capability and definition quota first; declarations cannot enable it. No separate feature flag is required. Authenticate and authorize the customer in the app action before starting a run.
4
+
5
+ ## Declare and build
6
+
7
+ Export the class from the app's Worker entry module and declare it in that app's Wrangler config:
8
+
9
+ ```jsonc
10
+ { "workflows": [{ "name": "customer-activity", "binding": "CUSTOMER_ACTIVITY", "class_name": "CustomerActivity" }] }
11
+ ```
12
+
13
+ ```ts
14
+ import { WorkflowEntrypoint, type WorkflowEvent, type WorkflowStep } from "cloudflare:workers";
15
+
16
+ export class CustomerActivity extends WorkflowEntrypoint<{}, { runId: string }> {
17
+ async run(event: WorkflowEvent<{ runId: string }>, step: WorkflowStep) {
18
+ await step.do("notify", async () => {
19
+ // Replace this example with a fixed, approved application endpoint.
20
+ const response = await fetch("https://gateway.example.com/api/workflow-receipts", {
21
+ method: "POST",
22
+ headers: { "Content-Type": "application/json" },
23
+ body: JSON.stringify({ runId: event.payload.runId, phase: "started" }),
24
+ redirect: "manual",
25
+ signal: AbortSignal.timeout(10_000),
26
+ });
27
+ await response.body?.cancel();
28
+ if (!response.ok) throw new Error("Receipt failed");
29
+ return { sent: true };
30
+ });
31
+ await step.sleep("delay", "2 seconds");
32
+ }
33
+ }
34
+
35
+ // In an authorized app action, use a stable logical operation ID:
36
+ // const run = await env.CUSTOMER_ACTIVITY.create({ id: runId, params: { runId } });
37
+ // return Response.json({ runId: await run.id }, { status: 202 });
38
+ ```
39
+
40
+ The CLI packages code for Andeo's Dynamic Workflow hosts. Do not deploy a separate Cloudflare workflow. Global `fetch()` works inside durable steps; a service is not required merely for HTTP. Pin approved destinations, validate variable URLs, bound timeouts/redirects, and make external effects idempotent because steps retry. A callback that only knows a run ID is a demo receipt, not sender authentication; use secret-backed verification for trusted callbacks.
41
+
42
+ ## Environment and services
43
+
44
+ Workflow code receives declared public string vars and scoped service capabilities—not app secrets, direct D1/KV/R2 bindings or the platform dispatcher. Never pass tokens through params, events or step results. Put secret-backed HTTP/storage operations in a connected service; read [Services](services.md) and [Configuration](configuration-secrets.md). Publish its `WORKFLOW_SERVICE_CONTRACT` first. Direct outbound access is independent of service permission revocation.
45
+
46
+ ## Local and hosted validation
47
+
48
+ Use `andeo dev` for the local Workflow/Loader runtime. Map service bindings to built local artifact directories in `andeo.workflow-dev.json`, for example `{ "DELIVERY_SERVICE": "../delivery-service/dist/andeo" }`. Build services first. Local state is under `.tender/workflows-local`; restart after source changes (no hot reload). Local schema setup is app-owned. Local success does not prove hosted authorization or isolation.
49
+
50
+ Use normal build/preview delivery. Verify an authenticated start, durable completion, the external effect and persistence after reload. The reference demo writes a requested row and receives started/completed POSTs in its gateway. Customer identity lookups must preserve the provider's required headers; the reference Shopify queries use an explicit User-Agent.
51
+
52
+ ## Inspect and control
53
+
54
+ ```sh
55
+ andeo workflows list --environment preview --json
56
+ andeo workflows runs --scope SCOPE_ID --json
57
+ andeo workflows status --scope SCOPE_ID --run RUN_ID --json
58
+ andeo workflows history --scope SCOPE_ID --run RUN_ID --json
59
+ andeo workflows diagnostics --scope SCOPE_ID --run RUN_ID --json
60
+ andeo workflows export --scope SCOPE_ID --run RUN_ID --limit 100 --offset 0 --json
61
+ ```
62
+
63
+ Read `andeo workflows --help` for start/event/pause/resume/terminate/restart and preview-service selection. Obtain scopes from list results; never invent physical IDs. Identical scoped run IDs and inputs converge; changed inputs conflict. Lists are timestamped projections; single-run status reads the engine. Follow returned cursors/offsets. Exports omit raw payloads, provider errors and free-form logs.
64
+
65
+ Viewers can read; developers can control runs. Termination/restart and uncertain-event acknowledgement require exact run confirmation. Never replay ambiguous events automatically. Acknowledgement clears a fence; it does not prove delivery. Termination cannot reverse completed or in-flight effects. Disabling entitlement blocks new starts/restarts and workflow-bearing releases, not already running work.
66
+
67
+ ## Limits
68
+
69
+ Use the supported adapter surface: create/get/status, bounded createBatch, sendEvent, pause/resume/terminate/restart and bounded history. `createBatch` returns per-member acceptance/error records, not native handle-array parity; use `await run.id`. Schedules, custom retention, cross-app `script_name`, arbitrary business RPC and full native API parity are unsupported. Restart requires a terminal run within the supported retention window. Check runtime errors for current payload/admission/service limits; upstream Cloudflare limits are not Andeo's contract.
@@ -0,0 +1,99 @@
1
+ {
2
+ "schema": "tender.external-app-build/v1",
3
+ "sourceRevision": "ffffffffffffffffffffffffffffffffffffffff",
4
+ "bundleDigest": "e66389b6c7916261dd8989277e73cccc53c361d1796eb481f832b73ecca66eb9",
5
+ "manifest": {
6
+ "schema": "tender.account-artifact/v1",
7
+ "app": {
8
+ "slug": "__APP_SLUG__-gateway",
9
+ "version": "0.1.0",
10
+ "label": "__APP_NAME__ gateway",
11
+ "fixture": false
12
+ },
13
+ "runtime": {
14
+ "kind": "worker",
15
+ "compatibilityDate": "2026-08-25",
16
+ "mainModule": "worker.mjs",
17
+ "assetPrefix": "/_tenant-artifacts/e66389b6c7916261dd8989277e73cccc53c361d1796eb481f832b73ecca66eb9"
18
+ },
19
+ "module": {
20
+ "path": "worker.mjs",
21
+ "sha256": "a4e09ddcd26055ce1305ba6ce2d45e648208338615c2b1e72a0ed9d3ad37fa1e",
22
+ "bytes": 73369,
23
+ "contentType": "application/javascript+module"
24
+ },
25
+ "files": [],
26
+ "health": {
27
+ "path": "/api/health"
28
+ },
29
+ "resources": [
30
+ {
31
+ "type": "d1",
32
+ "name": "APP_DB"
33
+ }
34
+ ],
35
+ "services": [
36
+ {
37
+ "name": "PORTAL_UI",
38
+ "targetProject": "__APP_SLUG__-portal-ui"
39
+ }
40
+ ],
41
+ "vars": {
42
+ "ACCOUNT_PROJECT_ID": "prj_replace_me",
43
+ "ACCOUNT_RUNTIME_BASE_DOMAIN": "tenderprompt.dev",
44
+ "ACCOUNT_TENANT_ID": "ten_replace_me",
45
+ "SHOPIFY_CUSTOMER_ACCOUNT_CLIENT_ID": "replace_me",
46
+ "SHOPIFY_CUSTOMER_ACCOUNT_DOMAIN": "shopify.com",
47
+ "SHOPIFY_STOREFRONT_DOMAIN": "example.myshopify.com"
48
+ },
49
+ "databaseSchema": {
50
+ "schema": "tender.d1-schema/v1",
51
+ "statements": [
52
+ "CREATE TABLE IF NOT EXISTS public_customer_auth_flows (\n project_id TEXT NOT NULL,\n state_digest TEXT NOT NULL,\n browser_binding_digest TEXT NOT NULL,\n client_key_digest TEXT NOT NULL,\n interaction_mode TEXT NOT NULL,\n pkce_verifier TEXT NOT NULL,\n return_hostname TEXT NOT NULL,\n created_at INTEGER NOT NULL,\n expires_at INTEGER NOT NULL,\n consumed_at INTEGER,\n PRIMARY KEY (project_id, state_digest),\n CHECK (length(project_id) BETWEEN 2 AND 128),\n CHECK (length(state_digest) = 64),\n CHECK (state_digest NOT GLOB '*[^0-9a-f]*'),\n CHECK (length(browser_binding_digest) = 64),\n CHECK (browser_binding_digest NOT GLOB '*[^0-9a-f]*'),\n CHECK (length(client_key_digest) = 64),\n CHECK (client_key_digest NOT GLOB '*[^0-9a-f]*'),\n CHECK (interaction_mode IN ('interactive', 'silent')),\n CHECK (length(pkce_verifier) BETWEEN 43 AND 128),\n CHECK (length(return_hostname) BETWEEN 1 AND 253),\n CHECK (return_hostname = lower(return_hostname)),\n CHECK (expires_at > created_at),\n CHECK (consumed_at IS NULL OR consumed_at BETWEEN created_at AND expires_at)\n )",
53
+ "CREATE INDEX IF NOT EXISTS public_customer_auth_flows_by_expiry\n ON public_customer_auth_flows (expires_at)",
54
+ "CREATE TABLE IF NOT EXISTS public_customer_auth_sessions (\n project_id TEXT NOT NULL,\n session_digest TEXT NOT NULL,\n audience_hostname TEXT NOT NULL,\n session_data TEXT NOT NULL,\n created_at INTEGER NOT NULL,\n expires_at INTEGER NOT NULL,\n PRIMARY KEY (project_id, session_digest),\n CHECK (length(project_id) BETWEEN 2 AND 128),\n CHECK (length(session_digest) = 64),\n CHECK (session_digest NOT GLOB '*[^0-9a-f]*'),\n CHECK (length(audience_hostname) BETWEEN 1 AND 253),\n CHECK (audience_hostname = lower(audience_hostname)),\n CHECK (length(session_data) BETWEEN 1 AND 65536),\n CHECK (expires_at > created_at)\n )",
55
+ "CREATE INDEX IF NOT EXISTS public_customer_auth_sessions_by_expiry\n ON public_customer_auth_sessions (expires_at)",
56
+ "CREATE TABLE IF NOT EXISTS public_customer_auth_handoffs (\n project_id TEXT NOT NULL,\n handoff_digest TEXT NOT NULL,\n return_hostname TEXT NOT NULL,\n session_digest TEXT NOT NULL,\n session_seal TEXT NOT NULL,\n created_at INTEGER NOT NULL,\n expires_at INTEGER NOT NULL,\n claimed_at INTEGER,\n PRIMARY KEY (project_id, handoff_digest),\n CHECK (length(project_id) BETWEEN 2 AND 128),\n CHECK (length(handoff_digest) = 64),\n CHECK (handoff_digest NOT GLOB '*[^0-9a-f]*'),\n CHECK (length(return_hostname) BETWEEN 1 AND 253),\n CHECK (return_hostname = lower(return_hostname)),\n CHECK (length(session_digest) = 64),\n CHECK (session_digest NOT GLOB '*[^0-9a-f]*'),\n CHECK (length(session_seal) BETWEEN 80 AND 100000),\n CHECK (expires_at > created_at),\n CHECK (claimed_at IS NULL OR claimed_at BETWEEN created_at AND expires_at)\n )",
57
+ "CREATE INDEX IF NOT EXISTS public_customer_auth_handoffs_by_expiry\n ON public_customer_auth_handoffs (expires_at)"
58
+ ],
59
+ "objects": [
60
+ {
61
+ "type": "table",
62
+ "name": "public_customer_auth_flows",
63
+ "tableName": "public_customer_auth_flows",
64
+ "statementIndex": 0
65
+ },
66
+ {
67
+ "type": "index",
68
+ "name": "public_customer_auth_flows_by_expiry",
69
+ "tableName": "public_customer_auth_flows",
70
+ "statementIndex": 1
71
+ },
72
+ {
73
+ "type": "table",
74
+ "name": "public_customer_auth_sessions",
75
+ "tableName": "public_customer_auth_sessions",
76
+ "statementIndex": 2
77
+ },
78
+ {
79
+ "type": "index",
80
+ "name": "public_customer_auth_sessions_by_expiry",
81
+ "tableName": "public_customer_auth_sessions",
82
+ "statementIndex": 3
83
+ },
84
+ {
85
+ "type": "table",
86
+ "name": "public_customer_auth_handoffs",
87
+ "tableName": "public_customer_auth_handoffs",
88
+ "statementIndex": 4
89
+ },
90
+ {
91
+ "type": "index",
92
+ "name": "public_customer_auth_handoffs_by_expiry",
93
+ "tableName": "public_customer_auth_handoffs",
94
+ "statementIndex": 5
95
+ }
96
+ ]
97
+ }
98
+ }
99
+ }