@w6w/ui 0.0.0-stage → 0.1.1

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 (142) hide show
  1. package/CHANGELOG.md +68 -0
  2. package/LICENSE +21 -0
  3. package/README.md +275 -2
  4. package/dist/ActionTestForm.d.ts +76 -0
  5. package/dist/AddConnectionModal.d.ts +24 -0
  6. package/dist/AppPicker.d.ts +83 -0
  7. package/dist/CodeBlock-CZu4TFSi.cjs +15 -0
  8. package/dist/CodeBlock-CZu4TFSi.cjs.map +1 -0
  9. package/dist/CodeBlock-Dot3Pd7P.js +2889 -0
  10. package/dist/CodeBlock-Dot3Pd7P.js.map +1 -0
  11. package/dist/CodeBlock.d.ts +65 -0
  12. package/dist/CodeEditor.d.ts +42 -0
  13. package/dist/ConfirmModal-8avl9Nv8.cjs +11 -0
  14. package/dist/ConfirmModal-8avl9Nv8.cjs.map +1 -0
  15. package/dist/ConfirmModal-CD-P8mhN.js +6335 -0
  16. package/dist/ConfirmModal-CD-P8mhN.js.map +1 -0
  17. package/dist/Copyable-1niV9gUa.js +771 -0
  18. package/dist/Copyable-1niV9gUa.js.map +1 -0
  19. package/dist/Copyable-CYZU1o4X.cjs +2 -0
  20. package/dist/Copyable-CYZU1o4X.cjs.map +1 -0
  21. package/dist/JsonEditor.d.ts +60 -0
  22. package/dist/NodeConfigForm.d.ts +70 -0
  23. package/dist/ParamsForm.d.ts +56 -0
  24. package/dist/PropertyEntryForm.d.ts +56 -0
  25. package/dist/RetryPolicyFields.d.ts +18 -0
  26. package/dist/StepBuilderModal.d.ts +375 -0
  27. package/dist/TriggerFillForm.d.ts +52 -0
  28. package/dist/WaitEditor.d.ts +6 -0
  29. package/dist/WorkflowFlowEditor.d.ts +119 -0
  30. package/dist/YamlEditor.d.ts +46 -0
  31. package/dist/app-categories.d.ts +38 -0
  32. package/dist/app-pages.d.ts +111 -0
  33. package/dist/code.cjs +2 -0
  34. package/dist/code.cjs.map +1 -0
  35. package/dist/code.d.ts +29 -0
  36. package/dist/code.mjs +8 -0
  37. package/dist/code.mjs.map +1 -0
  38. package/dist/components/ApiCallsPanel.d.ts +41 -0
  39. package/dist/components/AppIcon.d.ts +25 -0
  40. package/dist/components/AuthFieldsForm.d.ts +22 -0
  41. package/dist/components/Combobox.d.ts +24 -0
  42. package/dist/components/ConfirmModal.d.ts +33 -0
  43. package/dist/components/Copyable.d.ts +51 -0
  44. package/dist/components/CopyableText.d.ts +40 -0
  45. package/dist/components/DeleteButton.d.ts +16 -0
  46. package/dist/components/EditButton.d.ts +10 -0
  47. package/dist/components/ExecutionDetail.d.ts +70 -0
  48. package/dist/components/ExecutionFilters.d.ts +59 -0
  49. package/dist/components/ExecutionList.d.ts +60 -0
  50. package/dist/components/ExecutionLogPanel.d.ts +98 -0
  51. package/dist/components/ExecutionStats.d.ts +47 -0
  52. package/dist/components/ExpressionEditorModal.d.ts +42 -0
  53. package/dist/components/ExpressionInput.d.ts +36 -0
  54. package/dist/components/ExpressionOptions.d.ts +185 -0
  55. package/dist/components/HealthStatusPill.d.ts +25 -0
  56. package/dist/components/HistoryTimeline.d.ts +56 -0
  57. package/dist/components/Icon.d.ts +34 -0
  58. package/dist/components/IconButton.d.ts +60 -0
  59. package/dist/components/InfoTip.d.ts +15 -0
  60. package/dist/components/InternalIcon.d.ts +19 -0
  61. package/dist/components/ListItem.d.ts +25 -0
  62. package/dist/components/Modal.d.ts +29 -0
  63. package/dist/components/RepoSyncIndicator.d.ts +29 -0
  64. package/dist/components/ResolvedParams.d.ts +31 -0
  65. package/dist/components/ServerResources.d.ts +47 -0
  66. package/dist/components/StepStatusPill.d.ts +51 -0
  67. package/dist/components/UptimeStrip.d.ts +56 -0
  68. package/dist/components/execution-format.d.ts +24 -0
  69. package/dist/components/expression-dom.d.ts +154 -0
  70. package/dist/components/expression-template.d.ts +86 -0
  71. package/dist/components/history-scale.d.ts +33 -0
  72. package/dist/components/icons.d.ts +41 -0
  73. package/dist/components/resolved-clip.d.ts +42 -0
  74. package/dist/components/server-resources-format.d.ts +68 -0
  75. package/dist/components/server-resources.fixture.d.ts +9 -0
  76. package/dist/components/use-copy.d.ts +14 -0
  77. package/dist/createW6WApi.d.ts +31 -0
  78. package/dist/flow-connect.d.ts +138 -0
  79. package/dist/flow-fanout.d.ts +15 -0
  80. package/dist/flow-types.d.ts +356 -0
  81. package/dist/flow-utils.d.ts +284 -0
  82. package/dist/flow.cjs +3 -0
  83. package/dist/flow.cjs.map +1 -0
  84. package/dist/flow.d.ts +24 -0
  85. package/dist/flow.mjs +1978 -0
  86. package/dist/flow.mjs.map +1 -0
  87. package/dist/index.cjs +2 -0
  88. package/dist/index.cjs.map +1 -0
  89. package/dist/index.d.ts +94 -0
  90. package/dist/index.mjs +1812 -0
  91. package/dist/index.mjs.map +1 -0
  92. package/dist/oauth-popup.d.ts +17 -0
  93. package/dist/output-shape.d.ts +58 -0
  94. package/dist/provider.d.ts +421 -0
  95. package/dist/resolve-params.d.ts +112 -0
  96. package/dist/resolved-json.d.ts +21 -0
  97. package/dist/run-visuals.d.ts +90 -0
  98. package/dist/step-preview-state.d.ts +143 -0
  99. package/dist/theme.d.ts +32 -0
  100. package/dist/trigger-fields.d.ts +56 -0
  101. package/dist/types.d.ts +413 -0
  102. package/dist/use-app-action-defs.d.ts +7 -0
  103. package/dist/use-enter-submit.d.ts +23 -0
  104. package/dist/use-seed-sources.d.ts +16 -0
  105. package/package.json +112 -3
  106. package/src/code.css +561 -0
  107. package/src/styles/_buttons.scss +38 -0
  108. package/src/styles/_chips.scss +210 -0
  109. package/src/styles/_code.scss +139 -0
  110. package/src/styles/_copyable.scss +147 -0
  111. package/src/styles/_data-vars.scss +38 -0
  112. package/src/styles/_execution-history.scss +282 -0
  113. package/src/styles/_execution-log.scss +178 -0
  114. package/src/styles/_expression-field.scss +65 -0
  115. package/src/styles/_expression-inline.scss +63 -0
  116. package/src/styles/_expression-modal.scss +292 -0
  117. package/src/styles/_fields.scss +161 -0
  118. package/src/styles/_flow.scss +217 -0
  119. package/src/styles/_fx.scss +158 -0
  120. package/src/styles/_health.scss +46 -0
  121. package/src/styles/_history-timeline.scss +156 -0
  122. package/src/styles/_icon-button.scss +22 -0
  123. package/src/styles/_icon.scss +15 -0
  124. package/src/styles/_icons.scss +31 -0
  125. package/src/styles/_incoming-state.scss +46 -0
  126. package/src/styles/_info-tip.scss +9 -0
  127. package/src/styles/_layout.scss +6 -0
  128. package/src/styles/_lists.scss +64 -0
  129. package/src/styles/_modal.scss +125 -0
  130. package/src/styles/_multiselect.scss +69 -0
  131. package/src/styles/_repo-sync-indicator.scss +99 -0
  132. package/src/styles/_scale.scss +70 -0
  133. package/src/styles/_sections.scss +36 -0
  134. package/src/styles/_server-resources.scss +163 -0
  135. package/src/styles/_step-builder.scss +376 -0
  136. package/src/styles/_step-config.scss +195 -0
  137. package/src/styles/_tabs.scss +54 -0
  138. package/src/styles/_tester.scss +111 -0
  139. package/src/styles/_tokens.scss +160 -0
  140. package/src/styles/_uptime.scss +61 -0
  141. package/src/styles.css +4894 -0
  142. package/src/styles.scss +61 -0
@@ -0,0 +1,58 @@
1
+ /**
2
+ * An upstream step's output SHAPE — the field paths a later step can pick —
3
+ * from the three places one can come from, in precedence order:
4
+ *
5
+ * 1. **Declared** — the app action's `output` (`core/rfcs/action.md`
6
+ * `OutputField[]`), so a downstream step can reference `get-event`'s
7
+ * `name.text` before anything has run.
8
+ * 2. **Sample** — the action's `sample` value, when it declares no `output`.
9
+ * 3. **Test run** — the step's last saved test output, when the action
10
+ * declares neither. With none of the three, the author has to run a test.
11
+ *
12
+ * Every field is a dot-separated PATH (`start.utc`), the spec's own notation
13
+ * for nesting (`OutputField.key`: "Dot notation for nested paths"). That is
14
+ * also exactly how the engine resolves a ref — JSONLogic `var` splits on `.`
15
+ * (`core/packages/expr/src/jsonlogic.ts` `getVar`) — so `steps.<id>.output.<path>`
16
+ * reaches the nested value. A segment that can't survive that split is dropped
17
+ * by the picker (`isRefSafePath`).
18
+ *
19
+ * Pure and JSX-free so `node --test` exercises it directly.
20
+ */
21
+ /** One pickable output field of a step. `key` is a dot path; `label` is display-only. */
22
+ export interface OutputFieldRef {
23
+ key: string;
24
+ label?: string;
25
+ /** `true` — `key` is a dot path whose segments are checked one by one. */
26
+ path: true;
27
+ }
28
+ /** Where a step's offered fields came from. */
29
+ export type OutputShapeSource = "declared" | "sample" | "test";
30
+ /**
31
+ * The fields an action's `output` declares, or `undefined` when it declares
32
+ * none. A `DynamicOutput` (`{ source }`) is resolved by a hook the editor does
33
+ * not run, so it counts as "nothing declared" and the test-run fallback applies.
34
+ */
35
+ export declare function declaredOutputFields(output: unknown): OutputFieldRef[] | undefined;
36
+ /**
37
+ * Field paths inferred from a concrete value (an action's `sample` or a test
38
+ * run's output): every key of a plain object, recursing into nested plain
39
+ * objects up to {@link MAX_DEPTH}. Arrays and scalars are leaves. `undefined`
40
+ * when the value isn't a plain object with at least one key.
41
+ */
42
+ export declare function inferOutputFields(value: unknown): OutputFieldRef[] | undefined;
43
+ /** The value at a dot path inside `value`, or `undefined` when any segment is missing. */
44
+ export declare function valueAtPath(value: unknown, path: string): unknown;
45
+ /** The subset of an action definition this module reads. */
46
+ export interface ActionShapeDef {
47
+ output?: unknown;
48
+ sample?: unknown;
49
+ }
50
+ /**
51
+ * Resolve a step's offered fields by the precedence above. `action` is the
52
+ * app action definition (`undefined` while its app's actions are loading, or
53
+ * for a node that has none); `testOutput` is the step's last saved test output.
54
+ */
55
+ export declare function resolveOutputShape(action: ActionShapeDef | undefined, testOutput: unknown): {
56
+ fields: OutputFieldRef[];
57
+ from: OutputShapeSource;
58
+ } | undefined;
@@ -0,0 +1,421 @@
1
+ import { ReactNode } from 'react';
2
+ import { ActionDef, ApiCallRecord, AppSummary, AuthDef, ConnectionSummary, FunctionDetail, FunctionSummary, SavedTest, SubscriptionSummary, ThemeMode, TriggerSummary, WorkflowDetail, WorkflowSummary } from './types.ts';
3
+ /**
4
+ * A single tester-run summary from the unified `run_log` ledger, keyed to a
5
+ * connection. Thin by design — the full result payload stays server-side in
6
+ * `saved_test_runs`; this is the history row shown in the test screens.
7
+ * `summary` is null when the run recorded no summary; `occurredAt` is ISO.
8
+ */
9
+ export interface TestRunSummary {
10
+ id: string;
11
+ actionKey: string;
12
+ ok: boolean;
13
+ summary: string | null;
14
+ occurredAt: string;
15
+ }
16
+ /**
17
+ * Which app, version, action and connection a step ran with. A local structural
18
+ * copy of the engine's `StepMeta` (`@w6w/workflow-types`); the server sanitizes it.
19
+ */
20
+ export interface StepMeta {
21
+ app: string;
22
+ version: string;
23
+ action: string;
24
+ connectionId: string | null;
25
+ }
26
+ /**
27
+ * A saved per-step test fixture — a reusable, project-owned named capture of a
28
+ * workflow step's resolved incoming state (`input`) and its params (`with`),
29
+ * keyed by `(workflowId, stepId)`. Mirrors the connection-scoped `SavedTest`,
30
+ * re-keyed to a workflow step. `lastRun*` denormalizes the most recent run.
31
+ */
32
+ export interface StepTest {
33
+ id: string;
34
+ workflowId: string;
35
+ stepId: string;
36
+ name: string | null;
37
+ input: Record<string, unknown>;
38
+ with: Record<string, unknown>;
39
+ createdAt: string;
40
+ updatedAt: string;
41
+ /** When this fixture was last run (ISO), or null/undefined if never run. */
42
+ lastRunAt?: string | null;
43
+ /** The most recent run's status (e.g. `succeeded`/`failed`), or null. */
44
+ lastRunStatus?: string | null;
45
+ /** The most recent run's error payload, or null when it succeeded/never ran. */
46
+ lastRunError?: unknown;
47
+ /** The most recent run's captured output, or null. */
48
+ lastRunOutput?: unknown;
49
+ /** The most recent run's step metadata; omitted when the server has none. */
50
+ lastRunMeta?: StepMeta | null;
51
+ }
52
+ /**
53
+ * The **start state** a single-step invoke may carry — the RFC's third
54
+ * `executeNode(workflow, nodeId, startState)` argument
55
+ * (`core/rfcs/node-types.md`), sent as the invoke body's `state` field.
56
+ *
57
+ * Structurally the server's `StartStateInput`
58
+ * (`server/packages/api/ambient-scope.ts`): `steps` seeds `steps.<id>.output`
59
+ * and `trigger.event` seeds `trigger.event`, so a `with` block written as
60
+ * `{{ steps.<id>.output.<field> }}` resolves instead of concatenating as `""`.
61
+ * Anything else in it is ignored server-side — `vars`, `documents` and
62
+ * `secrets` are host-owned and loaded from the caller's authenticated scope, so
63
+ * a start state can only echo back data the caller already had.
64
+ *
65
+ * ⚠️ It is honoured by the **single-step** invoke route only. A full run
66
+ * (`POST /workflows/:id/run`) builds its own scope and takes nothing from here.
67
+ */
68
+ export interface StepStartState {
69
+ /** Outputs of steps that already ran, keyed by step id → `steps.<id>.output`. */
70
+ steps?: Record<string, {
71
+ output?: unknown;
72
+ meta?: StepMeta;
73
+ }>;
74
+ /** Trigger context; only `event` is honoured → `trigger.event`. */
75
+ trigger?: {
76
+ event?: unknown;
77
+ };
78
+ }
79
+ /**
80
+ * A caller-supplied override merged into an app action's outbound request at
81
+ * the wire — the escape hatch for a vendor field the Action's own `params`
82
+ * don't declare (`.claude/docs/overrides.md`). Rides on the invocation
83
+ * envelope beside `params`, never inside it; `resolveParams` never sees it.
84
+ * Mirrors the server's `RequestOverrides`
85
+ * (`core/packages/types/src/overrides.ts`) structurally.
86
+ */
87
+ export interface RequestOverrides {
88
+ /** Merged over the request body — deep-merges objects, index-merges arrays. */
89
+ body?: Record<string, unknown>;
90
+ /** Merged into the URL's query string; `null` removes a key the action set. */
91
+ query?: Record<string, string | number | boolean | null>;
92
+ /** Added to the request headers; applied before the auth `sign` hook, so it can't hijack it. */
93
+ headers?: Record<string, string>;
94
+ /** Which outbound request receives the overrides. Defaults to `"first"`. */
95
+ target?: "first" | "first-write" | "all";
96
+ /** Restrict the merge to requests whose URL contains this substring. */
97
+ match?: string;
98
+ }
99
+ /**
100
+ * The surface every w6w-io component may call. Grows as we add components;
101
+ * new members are added at the end so consumer implementations only need to
102
+ * grow when they want to use the new component.
103
+ */
104
+ /**
105
+ * Options for {@link W6WApi.listAppsPage} — one bounded, server-paged
106
+ * request. Every member is optional; an omitted member is a host-defined
107
+ * default (usually "no filter"/"first page"), never a client-side guess.
108
+ */
109
+ export interface ListAppsPageOptions {
110
+ /** Full-text search term, forwarded to the server verbatim. */
111
+ q?: string;
112
+ /** Server-side category filter (e.g. `"ai"`). */
113
+ category?: string;
114
+ /** Opaque pagination cursor from a prior {@link AppsPageResult.nextCursor}. */
115
+ cursor?: string;
116
+ /** Page size; a host may clamp this to its own bounds. */
117
+ limit?: number;
118
+ /** Ask the host for a bounded picker-summary projection (heavy fields like inline icons may be trimmed). */
119
+ compact?: boolean;
120
+ /** Abort this request. Local request control only; never a wire field. */
121
+ signal?: AbortSignal;
122
+ }
123
+ /** One page of apps, as returned by {@link W6WApi.listAppsPage}. */
124
+ export interface AppsPageResult {
125
+ apps: AppSummary[];
126
+ /** Present unless this is the last page. */
127
+ nextCursor?: string;
128
+ }
129
+ export interface W6WApi {
130
+ /**
131
+ * List registered apps to pick from in the connection modal.
132
+ *
133
+ * OPTIONAL: the legacy, full-catalog counterpart to {@link listAppsPage}
134
+ * and {@link listAppsByIds} — `createW6WApi.ts`'s own implementation still
135
+ * provides it, and every bounded seam above is preferred wherever a host
136
+ * implements it. Callers MUST guard on `typeof api.listApps === "function"`
137
+ * before invoking it: a host with neither this nor a bounded seam settles
138
+ * into that call site's own existing empty state instead of making a
139
+ * request, never a crash.
140
+ */
141
+ listApps?(): Promise<AppSummary[]>;
142
+ /**
143
+ * Fetch ONE bounded, server-paged slice of the app catalog — the seam every
144
+ * bounded picker UI (`AppPicker`'s paged mode, `StepBuilderModal`'s
145
+ * Apps/AI/Triggers tabs) prefers over {@link listApps} when a host
146
+ * implements it. OPTIONAL and ADDITIVE: an older/imported provider that
147
+ * only implements `listApps` still typechecks and simply keeps the
148
+ * eager-list behavior everywhere this member is absent — and a host with
149
+ * neither this nor `listApps` settles into each caller's own existing empty
150
+ * state instead of ever requesting a catalog.
151
+ */
152
+ listAppsPage?(options?: ListAppsPageOptions): Promise<AppsPageResult>;
153
+ /**
154
+ * Resolve a bounded, explicit set of app ids to their summaries — the seam
155
+ * behind the "Ready to use" tab's connected-app batching and
156
+ * `AddConnectionModal`'s `initialAppId` resolution: a caller that already
157
+ * knows exactly which ids it needs never has to fetch (or filter) the whole
158
+ * catalog to find them. OPTIONAL, like {@link listAppsPage}: absent, a
159
+ * caller falls back to its pre-existing `listApps`-based resolution; absent
160
+ * too, that caller settles into its own not-found/empty outcome instead of
161
+ * ever calling an undefined function.
162
+ * Missing/404 ids are simply omitted from the result, never an error for
163
+ * the whole batch.
164
+ */
165
+ listAppsByIds?(ids: readonly string[], options?: {
166
+ signal?: AbortSignal;
167
+ }): Promise<AppSummary[]>;
168
+ /** Load auth methods declared by an app's manifest, with availability flags. */
169
+ getAppAuth(appId: string): Promise<AuthDef[]>;
170
+ /** Create a non-OAuth connection with a user-supplied credential. */
171
+ createConnection(appId: string, body: {
172
+ authKey: string;
173
+ credential: Record<string, unknown>;
174
+ displayName?: string;
175
+ profile?: Record<string, unknown>;
176
+ }): Promise<ConnectionSummary>;
177
+ /**
178
+ * Start an OAuth 2.0 flow. Server builds the provider's authorize URL and
179
+ * returns it; the caller opens it in a popup and awaits the server's
180
+ * callback message (see `startOAuthPopup`).
181
+ */
182
+ startAppOAuthFlow(appId: string, authKey: string, body: {
183
+ displayName?: string;
184
+ }): Promise<{
185
+ authorizationUrl: string;
186
+ }>;
187
+ /** List the actions an app exposes, to pick from in the step builder. */
188
+ getAppActions(appId: string): Promise<ActionDef[]>;
189
+ /** List the connections that already exist for a given app. */
190
+ listConnectionsForApp(appId: string): Promise<ConnectionSummary[]>;
191
+ /** List every connection across apps — drives the "Connected apps" tab. */
192
+ listConnections(): Promise<ConnectionSummary[]>;
193
+ /**
194
+ * Invoke a single action — used to test-run one step from the visual editor.
195
+ * Pass `connectionId` to run with a stored connection's credential. Pass
196
+ * `project` to resolve document expressions against the workflow's selected
197
+ * project (omitted → the scope's default/starter project). Pass `state` — the
198
+ * {@link StepStartState} — so `{{ steps.<id>.output.<field> }}` in the params
199
+ * resolves against what those upstream steps last produced; omitted, every
200
+ * such reference resolves to the empty string.
201
+ *
202
+ * `apiCalls` carries the outbound HTTP calls the action made (redacted); a
203
+ * failed invoke rejects with an `ApiError` whose `body ?? raw` holds the same
204
+ * field (ui's own class carries it on `body`, `@w6w/sdk`'s on `raw`).
205
+ *
206
+ * Pass `overrides` — a {@link RequestOverrides} — to reach a vendor field the
207
+ * action's own params don't declare. It rides on the invocation envelope,
208
+ * never merged into `params`; an absent or empty envelope is a no-op.
209
+ */
210
+ invokeAction(appId: string, actionKey: string, params: Record<string, unknown>, opts?: {
211
+ connectionId?: string;
212
+ project?: string;
213
+ state?: StepStartState;
214
+ overrides?: RequestOverrides;
215
+ }): Promise<{
216
+ value: unknown;
217
+ logs?: string[];
218
+ apiCalls?: ApiCallRecord[];
219
+ meta?: StepMeta;
220
+ }>;
221
+ /** List the saved action-test inputs stored against a connection. */
222
+ listSavedTests(connectionId: string): Promise<SavedTest[]>;
223
+ /** Save a new set of action-test inputs against a connection. */
224
+ createSavedTest(connectionId: string, body: {
225
+ actionKey: string;
226
+ name: string;
227
+ values: Record<string, unknown>;
228
+ }): Promise<SavedTest>;
229
+ /** Rename a saved test or replace its stored input values. */
230
+ updateSavedTest(connectionId: string, id: string, patch: {
231
+ name?: string;
232
+ values?: Record<string, unknown>;
233
+ }): Promise<SavedTest>;
234
+ /** Delete a saved test by id. */
235
+ deleteSavedTest(connectionId: string, id: string): Promise<void>;
236
+ /**
237
+ * Record the outcome of an action-test run against a connection. Appends a
238
+ * run-log row server-side; when `savedTestId` is present the saved test's
239
+ * `lastRun*` fields are updated too. POSTs to `/connections/:connId/test-runs`.
240
+ */
241
+ recordTestRun(connId: string, body: {
242
+ savedTestId?: string | null;
243
+ actionKey: string;
244
+ ok: boolean;
245
+ summary?: string;
246
+ result?: unknown;
247
+ }): Promise<void>;
248
+ /**
249
+ * List a connection's recent tester-run history from the unified `run_log`
250
+ * ledger (`GET /connections/:connId/test-runs` → the `.runs` array). Powers
251
+ * the run-history list in the test screens, complementing the per-test
252
+ * `lastRun*` badge with the full ledger.
253
+ *
254
+ * OPTIONAL: consumers that don't render history (or haven't wired it up yet)
255
+ * may omit it, so a missing member never poisons their typecheck. Callers
256
+ * MUST guard on its presence before invoking.
257
+ */
258
+ listTestRuns?(connectionId: string): Promise<TestRunSummary[]>;
259
+ /**
260
+ * Save a reusable per-step test fixture against a workflow step. Captures the
261
+ * resolved incoming state (`input`) and the step's params (`with`); the server
262
+ * stores both verbatim, project-owned. Mirrors `createSavedTest`, re-keyed from
263
+ * a connection to a `(workflowId, stepId)`. POSTs to
264
+ * `/workflows/:workflowId/steps/:stepId/tests`.
265
+ */
266
+ saveStepTest(workflowId: string, stepId: string, body: {
267
+ name?: string;
268
+ input: Record<string, unknown>;
269
+ with: Record<string, unknown>;
270
+ }): Promise<StepTest>;
271
+ /**
272
+ * Record the outcome of a step-test run so every run (saved or ad-hoc) is
273
+ * logged authoritatively server-side. The run row mirrors `node_executions`
274
+ * (status/input/output/error). When `stepTestId` is present the fixture's
275
+ * `lastRun*` fields are updated too. Mirrors `recordTestRun`, re-keyed to a
276
+ * workflow step. POSTs to `/workflows/:workflowId/steps/:stepId/test-runs`.
277
+ */
278
+ recordStepTestRun(workflowId: string, stepId: string, body: {
279
+ stepTestId?: string | null;
280
+ status: string;
281
+ input?: unknown;
282
+ output?: unknown;
283
+ error?: unknown;
284
+ meta?: unknown;
285
+ }): Promise<void>;
286
+ /**
287
+ * List the saved test fixtures for a workflow step (project-owned, not
288
+ * subject-filtered). Added now so the ui-only incoming-state picker and
289
+ * test-gate tasks need no further studio change. Mirrors `listSavedTests`,
290
+ * re-keyed to a `(workflowId, stepId)`. GETs
291
+ * `/workflows/:workflowId/steps/:stepId/tests`.
292
+ */
293
+ listStepTests(workflowId: string, stepId: string): Promise<StepTest[]>;
294
+ /**
295
+ * List the caller's registered Functions (core rfcs/function.md) — drives
296
+ * the step builder's Functions tab (F-2.0). GETs `/functions`.
297
+ */
298
+ listFunctions(): Promise<FunctionSummary[]>;
299
+ /**
300
+ * Load one Function's canonical interface (`inputs`), so the Functions tab
301
+ * can render its Configure stage's `ParamsForm`. GETs `/functions/:id`.
302
+ */
303
+ getFunction(id: string): Promise<FunctionDetail>;
304
+ /**
305
+ * Invoke a Function directly — the Functions tab's Test stage
306
+ * (`CallableStepConfig`), NOT the `@w6w/call` node's own run-time path (that
307
+ * goes through `ctx.invokeCallable`, host-side). Returns the raw output —
308
+ * `unknown`, not an invocation envelope — matching the committed
309
+ * `studio/src/repos/functions.ts`. POSTs `/functions/:id/invoke`.
310
+ */
311
+ invokeFunction(id: string, inputs: Record<string, unknown>): Promise<unknown>;
312
+ /**
313
+ * List the caller's registered Workflows — drives the step builder's
314
+ * Workflows tab (F-2.0). GETs `/workflows`.
315
+ */
316
+ listWorkflows(): Promise<WorkflowSummary[]>;
317
+ /**
318
+ * Load one Workflow's full definition, so the Workflows tab can derive its
319
+ * entry/trigger step's declared `with.fields` for the Configure stage's
320
+ * `ParamsForm`. GETs `/workflows/:id`.
321
+ */
322
+ getWorkflow(id: string): Promise<WorkflowDetail>;
323
+ /**
324
+ * Run a Workflow synchronously — the Workflows tab's Test stage (D-11/
325
+ * D-15(c)): the SAME `?wait=true` path the saved `@w6w/call` step takes at
326
+ * run time, never a client-side enqueue-and-poll. `terminal` is derived from
327
+ * the response's HTTP status (`200` ⇒ `true`, the server's own `202`
328
+ * synchronous-wait timeout ⇒ `false` — a legitimate "still running" outcome,
329
+ * not an error). POSTs `/workflows/:id/run?wait=true`.
330
+ */
331
+ runWorkflow(id: string, opts?: {
332
+ variables?: Record<string, unknown>;
333
+ input?: Record<string, unknown>;
334
+ }): Promise<{
335
+ runId: string;
336
+ status: string;
337
+ output?: unknown;
338
+ error?: unknown;
339
+ terminal: boolean;
340
+ }>;
341
+ /**
342
+ * List apps that declare at least one trigger — the Triggers tab's
343
+ * "App triggers" section (T-0). GETs whatever the host resolves to (e.g.
344
+ * apps filtered by `triggerCount > 0`).
345
+ *
346
+ * OPTIONAL, like `listTestRuns?` above: a host that hasn't wired this member
347
+ * still typechecks and simply doesn't render the App-triggers section.
348
+ */
349
+ listTriggerApps?(): Promise<AppSummary[]>;
350
+ /**
351
+ * List one app's declared triggers. GETs `/apps/:id/triggers`.
352
+ */
353
+ getAppTriggers?(appId: string): Promise<TriggerSummary[]>;
354
+ /**
355
+ * List the Subscriptions bound to one workflow (rfcs/trigger.md). Powers
356
+ * the webhook-URL panel's get-or-create check (I-2) — GETs
357
+ * `/workflows/:id/subscriptions`.
358
+ */
359
+ listSubscriptionsForWorkflow?(workflowId: string): Promise<SubscriptionSummary[]>;
360
+ /**
361
+ * Create a Subscription binding an app trigger to a workflow — the one
362
+ * explicit user action both the Triggers-tab app section (T-0) and the
363
+ * webhook-URL panel (I-2) call, per DECISIONS.md HITL-1. POSTs
364
+ * `/apps/:id/triggers/:key/subscriptions`.
365
+ */
366
+ createSubscription?(appId: string, triggerKey: string, input: {
367
+ workflowId: string;
368
+ connectionId?: string | null;
369
+ params?: Record<string, unknown>;
370
+ /** Poll triggers only, in milliseconds. */
371
+ intervalMs?: number;
372
+ }): Promise<SubscriptionSummary>;
373
+ }
374
+ export interface W6WUIProviderProps {
375
+ api: W6WApi;
376
+ /**
377
+ * Force the theme every `@w6w/ui` component resolves to — both the CSS
378
+ * tokens (`styles.css`'s `:where([data-theme=...])` blocks; `color-scheme` is
379
+ * declared on component roots, never on the host `<html>`) and the
380
+ * JS-side theme-aware components (`AppIcon`, `CodeEditor`, `JsonEditor`,
381
+ * `WorkflowFlowEditor`, via `useEffectiveTheme`) — instead of each one
382
+ * independently falling back to `data-theme` on `<html>` or the visitor's
383
+ * OS `prefers-color-scheme`.
384
+ *
385
+ * Omit to keep that pre-existing default — the right choice for `@w6w/ui`'s
386
+ * own app (studio), which already manages `data-theme` on `<html>` itself.
387
+ * But it's a silent trap for a HOST embedding these components inside its
388
+ * own page: without this prop, `@w6w/ui` resolves its theme from the
389
+ * visitor's OS setting, independently of whatever theme the host's own
390
+ * page is using — a visitor with a dark-mode OS preference gets `@w6w/ui`
391
+ * components rendered in ITS dark palette sitting inside an otherwise-light
392
+ * host page (or vice versa). Pass your host's own resolved theme here to
393
+ * make `@w6w/ui` follow it instead. See `docs/theming.md`.
394
+ */
395
+ theme?: ThemeMode;
396
+ children: ReactNode;
397
+ }
398
+ /**
399
+ * Provides the w6w API client to every component under it, and — when
400
+ * `theme` is given — forces `@w6w/ui`'s theme to match it (see
401
+ * `W6WUIProviderProps.theme` above). Setting `theme` wraps `children` in a
402
+ * `data-theme` DOM node: CSS custom properties cascade to every descendant
403
+ * regardless of specificity, so this alone is enough for every `@w6w/ui`
404
+ * stylesheet rule to resolve correctly — no need to also set the attribute
405
+ * on `<html>` yourself. `display: contents` keeps that wrapper invisible to
406
+ * layout (flex/grid gap, `:nth-child`, etc. all behave as if it weren't
407
+ * there).
408
+ */
409
+ export declare function W6WUIProvider({ api, theme, children }: W6WUIProviderProps): import("react").JSX.Element;
410
+ /**
411
+ * Access the w6w API client. Throws a helpful error if used outside a
412
+ * `<W6WUIProvider>` — the common mistake is forgetting to wrap the app root.
413
+ */
414
+ export declare function useW6WApi(): W6WApi;
415
+ /** Scopes test-invokes under it to `project`; the editor wraps its body with this. */
416
+ export declare function WorkflowProjectProvider({ project, children, }: {
417
+ project?: string;
418
+ children: ReactNode;
419
+ }): import("react").JSX.Element;
420
+ /** The selected workflow project id in scope, or `undefined` outside the editor. */
421
+ export declare function useWorkflowProject(): string | undefined;
@@ -0,0 +1,112 @@
1
+ import { StepMeta, StepStartState } from './provider.tsx';
2
+ /**
3
+ * Per-segment resolution outcome. Every value that can contain a `var`/`expr`
4
+ * part resolves to an ARRAY of these (one per part of a multipart `ExprValue`,
5
+ * or one for a single top-level marker/literal) — never a bare `string`, which
6
+ * is exactly the shape `renderResult` collapses to and loses the distinction.
7
+ *
8
+ * `value` on `"resolved"` is `unknown` and explicitly INCLUDES `null` / `""` /
9
+ * `false` / `0` — those are real, present values, not absence. `"unresolved"`
10
+ * carries no `value` at all (there is nothing to show) and always carries the
11
+ * `ref` that failed to resolve, so a caller can render "this ref, unresolved"
12
+ * without ever falling back to rendering the ref as if it WERE the value.
13
+ */
14
+ export type ResolvedSegment = {
15
+ status: "resolved";
16
+ ref?: string;
17
+ value: unknown;
18
+ } | {
19
+ status: "unresolved";
20
+ ref: string;
21
+ } | {
22
+ status: "not-evaluated";
23
+ ref?: string;
24
+ } | {
25
+ status: "masked";
26
+ ref?: string;
27
+ };
28
+ /**
29
+ * The scope a param's `var` refs resolve against. Built by {@link buildResolveScope}
30
+ * from the SAME two things `StepEditModal` already computes: `testStartState`
31
+ * (for `steps.*`/`trigger.*` — the object literally sent as the test's `state`)
32
+ * and `sampleValues` (for `vars.*`/`documents.*`).
33
+ */
34
+ export interface ResolveScope {
35
+ vars: Record<string, unknown>;
36
+ documents: Record<string, unknown>;
37
+ steps: Record<string, {
38
+ output?: unknown;
39
+ meta?: StepMeta;
40
+ }>;
41
+ trigger: {
42
+ event?: unknown;
43
+ };
44
+ /**
45
+ * The original flat `sampleValues` map, keyed by full ref string — checked
46
+ * BEFORE the nested walk in {@link resolveRef}. `documentSampleValues`
47
+ * (`document-sources.ts`) emits a document field's sample as its OWN
48
+ * complete flat entry (`"documents.<key>.<field>"`), not as a nested value
49
+ * living under the shorter `"documents.<key>"` entry — so the one-hop strip
50
+ * below reconstructs `documents["<key>.<field>"]` (one key, a literal dot
51
+ * in it) instead of `documents["<key>"]["<field>"]`, and a real
52
+ * `"<key>"` entry (the whole document's raw content, a string) already
53
+ * occupies that slot besides. `walkPath`'s segment-by-segment walk can
54
+ * never reach either shape. An exact flat-key hit here resolves any ref
55
+ * `sampleValues` names directly, regardless of how many segments it has;
56
+ * the nested walk stays the fallback for a ref whose own reconstructed
57
+ * value happens to be an object (`vars.address` = `{ city: "X" }`, walking
58
+ * into it for `vars.address.city`), which is a value shape `sampleValues`
59
+ * never produces a matching flat key for in the first place.
60
+ *
61
+ * Optional: a `ResolveScope` built by hand (as most tests in
62
+ * `resolve-params.test.ts` do, to exercise the walk directly) has no flat
63
+ * map to check and falls straight through to `walkPath` — only
64
+ * `buildResolveScope` populates it.
65
+ */
66
+ flat?: Record<string, unknown>;
67
+ }
68
+ /**
69
+ * Build a {@link ResolveScope} from the two sources scope fidelity requires
70
+ * they come from separately:
71
+ *
72
+ * - `steps`/`trigger` come from `testStartState` — the exact object the test
73
+ * invoke sends as `state`, so a `steps.<id>.output.<field>` ref resolves to
74
+ * what the test will ACTUALLY see, not a design-time sample.
75
+ * - `vars`/`documents` come from `sampleValues` (`useExpressionOptions()`), a
76
+ * FLAT map keyed by full ref (`"vars.from_email"`, `"documents.<key>"`).
77
+ * Reconstructed into a nested object here (strip the root prefix, one hop)
78
+ * so {@link walkPath} can dot-walk into a var/document whose OWN value is an
79
+ * object — `sampleValues["vars.address"]` holding `{ city: "X" }` still
80
+ * resolves `vars.address.city` correctly, because the walk continues INTO
81
+ * the reconstructed value rather than doing a second flat-key lookup.
82
+ */
83
+ export declare function buildResolveScope(sampleValues: Record<string, unknown> | undefined, testStartState: StepStartState | undefined): ResolveScope;
84
+ /** A hand-authored whole-value path marker: `{ "$": "<path>" }`, exactly one key. */
85
+ export declare function isDollarPath(v: unknown): v is {
86
+ $: unknown;
87
+ };
88
+ /** A hand-authored whole-value JSONLogic marker: `{ "$expr": <logic> }`, exactly one key. */
89
+ export declare function isDollarExpr(v: unknown): v is {
90
+ $expr: unknown;
91
+ };
92
+ /**
93
+ * Resolve one configured param VALUE (or one `vars`-row's `value`, per A5 — the
94
+ * same function, called again per row) against `scope`. Returns one segment
95
+ * per part of a multipart `ExprValue`, or a single segment for anything else:
96
+ * a `SecretValue` at-rest envelope (`masked`), a hand-authored `{"$":…}` /
97
+ * `{"$expr":…}` marker (resolved as a ref lookup / not-evaluated — NOT as a
98
+ * literal object, per the acceptance pin), or a plain literal (`resolved`,
99
+ * `value` as-is, no `ref`).
100
+ */
101
+ export declare function resolveParamValue(value: unknown, scope: ResolveScope): ResolvedSegment[];
102
+ /**
103
+ * Structural deep-equality over JSON-shaped values (primitives, arrays, plain
104
+ * objects, recursively) — no new dependency. Used by the Test tab's "unchanged
105
+ * from default" filter (D-1/A1): equality, not presence, so a value the
106
+ * hand-editable JSON view baked in explicitly is still recognized as
107
+ * unchanged when it matches the declared default. `a === b` covers primitives
108
+ * (including `undefined === undefined`, so a param with neither a value nor a
109
+ * declared default is "equal" too) and short-circuits identical references
110
+ * before the recursive object/array walk.
111
+ */
112
+ export declare function deepEqual(a: unknown, b: unknown): boolean;
@@ -0,0 +1,21 @@
1
+ import { ResolveScope, ResolvedSegment } from './resolve-params.ts';
2
+ /**
3
+ * Fold a param's full segment array (the shape {@link resolveParamValue}
4
+ * returns) into ONE JSON value, per A6's pinned table: a single segment folds
5
+ * to its own token/value; multiple segments (a multipart `ExprValue`)
6
+ * concatenate into one string, each `resolved` part contributing its text
7
+ * (strings as-is, non-strings `JSON.stringify`d) and every other part
8
+ * contributing its placeholder token.
9
+ */
10
+ export declare function foldResolvedSegments(segments: ResolvedSegment[]): unknown;
11
+ /** Resolve + fold one param VALUE against `scope` in a single call. */
12
+ export declare function resolveParamJson(value: unknown, scope: ResolveScope): unknown;
13
+ /**
14
+ * A `vars`-typed param's configured rows, folded into one object keyed by
15
+ * each row's own `key` (`"(no key)"` when blank — mirrors `ResolvedVarsRow`'s
16
+ * fallback), each row's `value` folded by the same rules as any other param.
17
+ */
18
+ export declare function resolveVarsJson(rows: Array<{
19
+ key?: string;
20
+ value: unknown;
21
+ }>, scope: ResolveScope): Record<string, unknown>;