@w6w/embed 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.
- package/LICENSE +105 -0
- package/README.md +166 -2
- package/dist/W6WEmbedProvider.d.ts +29 -0
- package/dist/chrome/CallFromCodeButton.d.ts +155 -0
- package/dist/chrome/CallableSettingsModal.d.ts +17 -0
- package/dist/chrome/ConfirmModal.d.ts +20 -0
- package/dist/chrome/DangerZone.d.ts +19 -0
- package/dist/chrome/ExecutionProfileHeader.d.ts +69 -0
- package/dist/chrome/HistoryButton.d.ts +8 -0
- package/dist/chrome/HistoryModal.d.ts +9 -0
- package/dist/chrome/HistoryView.d.ts +15 -0
- package/dist/chrome/ImportSpecModal.d.ts +40 -0
- package/dist/chrome/JsonToggle.d.ts +51 -0
- package/dist/chrome/Modal.d.ts +20 -0
- package/dist/chrome/RightRail.d.ts +24 -0
- package/dist/chrome/TagEditor.d.ts +23 -0
- package/dist/chrome/VersionHistoryModal.d.ts +38 -0
- package/dist/chrome/history-open-run.d.ts +7 -0
- package/dist/chrome/index.d.ts +36 -0
- package/dist/chrome/workspace.d.ts +67 -0
- package/dist/client-context-CX61Bgw-.js +16 -0
- package/dist/client-context-CX61Bgw-.js.map +1 -0
- package/dist/draft/autosave-flush.d.ts +63 -0
- package/dist/draft/autosave.d.ts +68 -0
- package/dist/draft/client-context.d.ts +8 -0
- package/dist/draft/draft-registry.d.ts +14 -0
- package/dist/draft/index.d.ts +15 -0
- package/dist/draft/use-workflow-draft.d.ts +67 -0
- package/dist/draft/workflow-save.d.ts +48 -0
- package/dist/draft-registry-YF0tqNN0.js +49 -0
- package/dist/draft-registry-YF0tqNN0.js.map +1 -0
- package/dist/draft.d.ts +2 -0
- package/dist/draft.mjs +18 -0
- package/dist/draft.mjs.map +1 -0
- package/dist/editor/WorkflowEditor.d.ts +12 -0
- package/dist/editor/WorkflowSettingsModal.d.ts +17 -0
- package/dist/editor/definition.d.ts +31 -0
- package/dist/editor/editor-apps.d.ts +7 -0
- package/dist/editor/types.d.ts +34 -0
- package/dist/editor.d.ts +9 -0
- package/dist/editor.mjs +2170 -0
- package/dist/editor.mjs.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.mjs +67 -0
- package/dist/index.mjs.map +1 -0
- package/dist/lib/callable-descriptors.d.ts +77 -0
- package/dist/lib/callable-kind.d.ts +13 -0
- package/dist/lib/code-rail.d.ts +45 -0
- package/dist/lib/document-sources.d.ts +26 -0
- package/dist/lib/error-handler-self.d.ts +25 -0
- package/dist/lib/history-query.d.ts +135 -0
- package/dist/lib/import-paste.d.ts +41 -0
- package/dist/lib/index.d.ts +17 -0
- package/dist/lib/new-id.d.ts +10 -0
- package/dist/lib/rail-settings.d.ts +196 -0
- package/dist/lib/save-invalidation.d.ts +24 -0
- package/dist/lib/sdk-snippets.d.ts +96 -0
- package/dist/lib/settings-rail.d.ts +68 -0
- package/dist/lib/slug.d.ts +69 -0
- package/dist/lib/spec-import-invalidation.d.ts +48 -0
- package/dist/lib/tag-editor.d.ts +36 -0
- package/dist/lib/trigger-preview.d.ts +89 -0
- package/dist/lib/workflow-live-run.d.ts +165 -0
- package/dist/lib/workflow-poll.d.ts +8 -0
- package/dist/lib/workflow-route.d.ts +26 -0
- package/dist/lib/workflow-settings.d.ts +72 -0
- package/dist/lib/workflow-validity.d.ts +92 -0
- package/dist/lib/workflow-variables.d.ts +106 -0
- package/dist/lib.d.ts +2 -0
- package/dist/lib.mjs +62 -0
- package/dist/lib.mjs.map +1 -0
- package/dist/project-context-Dbk0Gr1K.js +16 -0
- package/dist/project-context-Dbk0Gr1K.js.map +1 -0
- package/dist/project-context.d.ts +11 -0
- package/dist/rail/CodeTool.d.ts +2 -0
- package/dist/rail/ErrorHandlingTool.d.ts +22 -0
- package/dist/rail/ExpressionScope.d.ts +21 -0
- package/dist/rail/SettingsTool.d.ts +27 -0
- package/dist/rail/editor-tools.d.ts +2 -0
- package/dist/rail/rail-env.d.ts +18 -0
- package/dist/rail/settings-sections.d.ts +93 -0
- package/dist/repos/documents.d.ts +102 -0
- package/dist/repos/history.d.ts +24 -0
- package/dist/repos/index.d.ts +22 -0
- package/dist/repos/spec-import.d.ts +44 -0
- package/dist/repos/step-tests.d.ts +19 -0
- package/dist/repos/vars.d.ts +25 -0
- package/dist/repos/vault.d.ts +24 -0
- package/dist/repos/versions.d.ts +112 -0
- package/dist/repos.d.ts +2 -0
- package/dist/repos.mjs +94 -0
- package/dist/repos.mjs.map +1 -0
- package/dist/slug-ByKQgxrf.js +642 -0
- package/dist/slug-ByKQgxrf.js.map +1 -0
- package/dist/spec-import-HgO7ZkLZ.js +898 -0
- package/dist/spec-import-HgO7ZkLZ.js.map +1 -0
- package/dist/spec-import-invalidation-D3retX4Q.js +18 -0
- package/dist/spec-import-invalidation-D3retX4Q.js.map +1 -0
- package/dist/use-workflow-draft-oI02dsP-.js +314 -0
- package/dist/use-workflow-draft-oI02dsP-.js.map +1 -0
- package/package.json +84 -3
- package/src/styles.css +829 -0
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure decisions behind the right rail's Settings tool (`src/ui/rail/SettingsTool.tsx`,
|
|
3
|
+
* `id: "aliases"`, `title: "Settings"` since T3.1.2 — the tool widened past aliases alone
|
|
4
|
+
* into a resource Settings panel: a metadata block and, for Functions and Endpoints, an
|
|
5
|
+
* Export / Edit JSON action row (T3.3.1 — the definition itself no longer renders in the
|
|
6
|
+
* panel, only the two buttons that open it in a modal), alongside the alias list
|
|
7
|
+
* `../lib/alias-rail.ts` already decides). Split out so `node --test` can gate them
|
|
8
|
+
* directly — same reasoning as
|
|
9
|
+
* `alias-rail.ts`'s own header: `node --test` throws `ERR_UNKNOWN_FILE_EXTENSION` on
|
|
10
|
+
* anything reaching the `@w6w/ui` / `Layout.tsx` import graph, and `src/ui/workspace.tsx`
|
|
11
|
+
* sits one hop from that barrel through `Layout.tsx`'s import graph. So this module
|
|
12
|
+
* declares its own structural mirror of the kinds it cares about instead of importing
|
|
13
|
+
* `WorkspaceKind`, and takes only `import type` throughout.
|
|
14
|
+
*
|
|
15
|
+
* T4.1.1 widens this file's scope past the Settings tool itself: `restoreRailState`
|
|
16
|
+
* (A2, `RightRail.tsx`'s persisted-state read path) and `isRowArchived`/`visibleRows`
|
|
17
|
+
* (A6, the three listing pages' "Show archived" toggle) are pure decisions with the
|
|
18
|
+
* exact same `node --test`-reachability constraint, so they land here rather than in
|
|
19
|
+
* a new sibling module the contract's `inputs.touch` list didn't ask for.
|
|
20
|
+
*/
|
|
21
|
+
/** Structural mirror of `WorkspaceCallable["kind"]` (`src/ui/workspace.tsx`) — every kind
|
|
22
|
+
* the rail can have open, not only the two this tool's action-row/metadata sections
|
|
23
|
+
* apply to. */
|
|
24
|
+
export type RailSettingsKind = "workflow" | "function" | "endpoint" | "connection";
|
|
25
|
+
/**
|
|
26
|
+
* A4/T3.1.1: which metadata rows the Settings panel shows for this kind. `id` always
|
|
27
|
+
* (every kind the tool is available on carries one). `key` for `function`/`endpoint`
|
|
28
|
+
* (unchanged) AND, since T3.1.1, `workflow` too — `GET /workflows` now carries `key`
|
|
29
|
+
* on every row (`string | null`, D-1: nullable, no backfill), and the panel renders it
|
|
30
|
+
* as an editable control for `function`/`workflow` and the existing read-only `<code>`
|
|
31
|
+
* for `endpoint` (`SettingsTool.tsx` gates that render choice on `ctx.kind` directly,
|
|
32
|
+
* never on this array — an Endpoint's `key` entry here must not be read as "editable").
|
|
33
|
+
* `updatedAt` stays `function`/`endpoint`-only: nothing asks for a Workflow Updated row,
|
|
34
|
+
* and adding one would be a second, unrelated rail row. Deliberately never `createdAt`
|
|
35
|
+
* (note 6): neither `GET /functions/:id` nor `GET /endpoints/:id` returns it, so
|
|
36
|
+
* surfacing it would take a server change for one cosmetic field — this function's own
|
|
37
|
+
* absence of a `createdAt` arm is half of that gate, the other half is the negative
|
|
38
|
+
* assertion in the caller's markup.
|
|
39
|
+
*/
|
|
40
|
+
export declare function metadataFieldsForKind(kind: RailSettingsKind): ReadonlyArray<"id" | "key" | "updatedAt">;
|
|
41
|
+
/**
|
|
42
|
+
* A2/A5: the Export / Edit JSON action row exists for `function`/`endpoint` only. A
|
|
43
|
+
* Workflow already has its own read-only Definition card
|
|
44
|
+
* (`pages/WorkflowDetailPage.tsx:371-388`); a Connection has no stored definition shaped
|
|
45
|
+
* like these two to show at all. (T3.3.1: renamed from the panel's earlier JSON-section
|
|
46
|
+
* name — there is no JSON section left in the panel to describe, only the two buttons
|
|
47
|
+
* that open one in a modal.)
|
|
48
|
+
*/
|
|
49
|
+
export declare function hasDefinitionActions(kind: RailSettingsKind): boolean;
|
|
50
|
+
/**
|
|
51
|
+
* A1/T3.1.1: does this kind have a version-history browser (the read-only browse list plus
|
|
52
|
+
* Publish and Enable/Disable) in the Settings panel? `true` for `function`/`workflow`/`endpoint`,
|
|
53
|
+
* `false` for `connection` — written as a `switch` naming every one of the four `RailSettingsKind`
|
|
54
|
+
* arms explicitly, with no `default:`, matching {@link specCollectionForKind}'s shape and the
|
|
55
|
+
* reason its own docblock gives (`:69` below — "every one of the four `RailSettingsKind` arms is
|
|
56
|
+
* named explicitly below" so a kind can never silently fall through). Deliberately NOT derived
|
|
57
|
+
* from {@link hasDefinitionActions}, which is `function`/`endpoint`-only: History covers Workflow
|
|
58
|
+
* too, so deriving one from the other would silently drop it.
|
|
59
|
+
*/
|
|
60
|
+
export declare function hasVersionHistory(kind: RailSettingsKind): boolean;
|
|
61
|
+
/**
|
|
62
|
+
* A1/T1.3.1: does this kind get a Delete (or, for `workflow`, Archive-then-Delete) affordance at
|
|
63
|
+
* the bottom of the Settings panel? `true` for `function`/`workflow`/`endpoint`, `false` for
|
|
64
|
+
* `connection` — written as a named `switch` naming every one of the four `RailSettingsKind` arms
|
|
65
|
+
* explicitly, with no `default:`, matching {@link hasVersionHistory}'s exact shape (`:72-81` above)
|
|
66
|
+
* for the same reason its own doc comment gives: a kind can never silently fall through. Deliberately
|
|
67
|
+
* NOT derived from {@link hasVersionHistory} even though the two currently agree on every arm — a
|
|
68
|
+
* future kind that gets history but not deletion (or vice versa) must not silently inherit the
|
|
69
|
+
* wrong answer from a sibling predicate.
|
|
70
|
+
*/
|
|
71
|
+
export declare function hasDelete(kind: RailSettingsKind): boolean;
|
|
72
|
+
/**
|
|
73
|
+
* A4: which `/<collection>/:id/spec` route the Export button's `useSpecQuery`
|
|
74
|
+
* (`../repos/spec-export.ts`) must call for this kind — `null` for the two kinds A2's
|
|
75
|
+
* action row never renders on. Kept in lockstep with {@link hasDefinitionActions}
|
|
76
|
+
* (both are `function`/`endpoint`-only) but expressed as its own total function rather
|
|
77
|
+
* than derived from it, so a Function can never be exported through
|
|
78
|
+
* `/endpoints/:id/spec` by a wrong `if`/`else` fallthrough — every one of the four
|
|
79
|
+
* `RailSettingsKind` arms is named explicitly below.
|
|
80
|
+
*/
|
|
81
|
+
export declare function specCollectionForKind(kind: RailSettingsKind): "functions" | "endpoints" | null;
|
|
82
|
+
/** What A8's `evaluateEdit` needs to know about the row already on screen — deliberately
|
|
83
|
+
* narrower than a whole `FunctionDef`/`EndpointDef`: the two fields a hand-edit must not
|
|
84
|
+
* be allowed to change out from under the row it opened on. */
|
|
85
|
+
export interface EditStored {
|
|
86
|
+
id: string;
|
|
87
|
+
key: string;
|
|
88
|
+
}
|
|
89
|
+
/** A8's total function's result: the parsed body (when parseable and a plain object, even
|
|
90
|
+
* if it goes on to fail arm 2 or 3 — the modal still has something to inspect for the
|
|
91
|
+
* render, just never something Save may submit) plus the one reason Save is refused, or
|
|
92
|
+
* `null` when the edit is allowed through. */
|
|
93
|
+
export interface EditEvaluation {
|
|
94
|
+
parsed: Record<string, unknown> | null;
|
|
95
|
+
blockedReason: string | null;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* A8: is this edited text a Save the rail may submit? A total function over the modal's
|
|
99
|
+
* OWN text state — never `JsonEditor`'s `onValidityChange` (note 10: the only browser
|
|
100
|
+
* harness this repo has stubs `JsonEditor` with a callback that is wired but never
|
|
101
|
+
* invoked, so a Save gated on it would look gated and be inert; parsing `text` here is
|
|
102
|
+
* behaviourally identical and fully observable by a page guard).
|
|
103
|
+
*
|
|
104
|
+
* Three refusals, evaluated in order, each named for the near-miss it kills:
|
|
105
|
+
* 1. the text does not parse as JSON, or parses to something that is not a plain object
|
|
106
|
+
* (`null` and an array both fail here, not a dedicated fourth arm — a
|
|
107
|
+
* `FunctionDef`/`EndpointDef` is never legitimately either);
|
|
108
|
+
* 2. `parsed.id !== stored.id` (note 9 — `FunctionsRepo.upsert` selects the row by
|
|
109
|
+
* `definition.id`, so an edited id does not edit this row, it creates or hijacks a
|
|
110
|
+
* different one);
|
|
111
|
+
* 3. `parsed.key !== stored.key` (note 8 — `POST /endpoints` 409s on a changed key while
|
|
112
|
+
* `POST /functions` silently accepts one; locking it here keeps both kinds behaving
|
|
113
|
+
* the same from this one modal).
|
|
114
|
+
*/
|
|
115
|
+
export declare function evaluateEdit(text: string, stored: EditStored): EditEvaluation;
|
|
116
|
+
/** A7/D-3's total function's result: may the save proceed, and if not, why —
|
|
117
|
+
* rendered verbatim in `WorkflowsPage.tsx`'s existing error/banner idiom. */
|
|
118
|
+
export interface KeyEditEvaluation {
|
|
119
|
+
allowed: boolean;
|
|
120
|
+
reason: string | null;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* D-3: is a Workflow save carrying this `key` one `WorkflowsPage.tsx`'s raw-JSON
|
|
124
|
+
* editor may submit? The right rail's Key control (`SettingsTool.tsx`) is the ONLY
|
|
125
|
+
* path allowed to assign or change a workflow's key (see this project's Requirement);
|
|
126
|
+
* this total function is what keeps a hand-edit of the JSON — via the Save button OR
|
|
127
|
+
* auto-save, both of which must fold this in (see `WorkflowsPage.tsx`'s `canSave`) —
|
|
128
|
+
* from doing it silently instead.
|
|
129
|
+
*
|
|
130
|
+
* `loadedKey` is the key `WorkflowsPage.tsx` most recently loaded FROM THE SERVER
|
|
131
|
+
* (its own `loadedKeyRef`, captured at both of its load sites — the initial `editId`
|
|
132
|
+
* effect and `reloadFromServer`). `undefined` means nothing has loaded yet, which
|
|
133
|
+
* refuses unconditionally: there is nothing yet to compare the parsed text against,
|
|
134
|
+
* so allowing the save through would let an unloaded/stale comparison pass by
|
|
135
|
+
* accident. Once loaded, `loadedKey` is `string | null` (P5's unset state, D-1).
|
|
136
|
+
*
|
|
137
|
+
* `parsedKey` is whatever the parsed JSON text's own `key` field currently holds.
|
|
138
|
+
* `undefined` (the field is absent from the text) is treated exactly like an
|
|
139
|
+
* explicit `null` — both mean "no key" on the wire, and a definition that dropped
|
|
140
|
+
* the field entirely must be refused exactly like one that changed it, never waved
|
|
141
|
+
* through as "nothing to compare".
|
|
142
|
+
*/
|
|
143
|
+
export declare function workflowKeyEditAllowed(loadedKey: string | null | undefined, parsedKey: unknown): KeyEditEvaluation;
|
|
144
|
+
/**
|
|
145
|
+
* T4.1.1/A2: the shape actually written to `localStorage` for the right
|
|
146
|
+
* rail's persisted state (`RightRail.tsx`'s `PersistedRail`) — `activeTool`
|
|
147
|
+
* ONLY. `open` is deliberately absent from this interface, not merely
|
|
148
|
+
* unwritten: {@link restoreRailState} below has nothing to read it FROM, so
|
|
149
|
+
* a pre-existing `{"open":true,…}` value written before this task cannot
|
|
150
|
+
* reopen the rail even by accident.
|
|
151
|
+
*/
|
|
152
|
+
export interface StoredRailState {
|
|
153
|
+
activeTool: string | null;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* A2: parses `localStorage`'s raw rail entry into {@link StoredRailState}.
|
|
157
|
+
* Missing/unparsable input, or a non-string `activeTool`, all fall back to
|
|
158
|
+
* `{ activeTool: null }` — the same defensive shape `RightRail.tsx`'s own
|
|
159
|
+
* `readStoredState` used before this task, minus the `open` field entirely.
|
|
160
|
+
* `RightRail.tsx` is the one caller; it combines this result with a hardcoded
|
|
161
|
+
* `open: false` on every read (D-I0-2) — that combination happens there, not
|
|
162
|
+
* here, because `open`'s absence from THIS function's return type is the
|
|
163
|
+
* proof a page guard can pin: there is no `open` member left to misread.
|
|
164
|
+
*/
|
|
165
|
+
export declare function restoreRailState(raw: string | null): StoredRailState;
|
|
166
|
+
/**
|
|
167
|
+
* A6: a listing row either Workflow, Function or Endpoint's list carries —
|
|
168
|
+
* whichever archived signal the row's own kind uses. Workflow rows signal
|
|
169
|
+
* archived via the existing `status === "archived"` (`WorkflowSummary`);
|
|
170
|
+
* Function/Endpoint rows via the new `archivedAt` column T1.1.1 ships
|
|
171
|
+
* (`string | null`). Both fields optional so one predicate below covers all
|
|
172
|
+
* three wire shapes without a per-kind branch at each listing page's call
|
|
173
|
+
* site.
|
|
174
|
+
*/
|
|
175
|
+
export interface ArchivableRow {
|
|
176
|
+
status?: string;
|
|
177
|
+
archivedAt?: string | null;
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* A6: is this row archived? `status` takes priority when the row carries one
|
|
181
|
+
* (Workflow rows always do) — falls back to `archivedAt` otherwise (Function/
|
|
182
|
+
* Endpoint rows, which have no `status` field at all).
|
|
183
|
+
*/
|
|
184
|
+
export declare function isRowArchived(row: ArchivableRow): boolean;
|
|
185
|
+
/**
|
|
186
|
+
* A6: which rows a listing page's "Show archived" toggle should render.
|
|
187
|
+
* `showArchived` false (the default) drops every archived row; `true`
|
|
188
|
+
* reveals them ALONGSIDE the live ones — an include, never a toggle that
|
|
189
|
+
* hides the rest (the contract's mutation M6: a toggle that hides LIVE rows
|
|
190
|
+
* once ON must fail the "both a live and an archived row survive together"
|
|
191
|
+
* case below; M7: defaulting to showing archived rows must fail the
|
|
192
|
+
* toggle-OFF case). One pure function shared by `WorkflowsPage.tsx`,
|
|
193
|
+
* `FunctionsPage.tsx` and `EndpointsPage.tsx` rather than three inline
|
|
194
|
+
* `.filter`s.
|
|
195
|
+
*/
|
|
196
|
+
export declare function visibleRows<T extends ArchivableRow>(rows: readonly T[], showArchived: boolean): T[];
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared invalidation for a whole-definition save (T3.1.1). `useSaveFunctionMutation` and
|
|
3
|
+
* `useSaveEndpointMutation` (`src/repos/functions.ts`, `src/repos/endpoints.ts`) both route their
|
|
4
|
+
* `onSuccess` through this one helper rather than inlining the two `invalidateQueries` calls at
|
|
5
|
+
* each site — so a save invalidates the LIST key (both list pages and the editor depend on it)
|
|
6
|
+
* *and* the saved resource's own single-resource key (`functionKey(id)` / `endpointKey(id)`),
|
|
7
|
+
* never just the list.
|
|
8
|
+
*
|
|
9
|
+
* No value imports on purpose: `node --test` throws `ERR_UNKNOWN_FILE_EXTENSION` on anything that
|
|
10
|
+
* reaches the `@w6w/ui` / `Layout.tsx` import graph, and `src/repos/*.ts` reaches it through
|
|
11
|
+
* `../api/apiClient.tsx` (JSX). This module has none of that, so it is loadable by `node --test`
|
|
12
|
+
* directly — see `src/lib/alias-rail.ts`'s docstring for the same reasoning.
|
|
13
|
+
*/
|
|
14
|
+
export interface QueryInvalidator {
|
|
15
|
+
invalidateQueries(filters: {
|
|
16
|
+
queryKey: readonly unknown[];
|
|
17
|
+
}): unknown;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Invalidate the list key, then the saved resource's own key. List first: both keys are
|
|
21
|
+
* invalidated regardless of order, but the order is asserted (see the unit test) so a future edit
|
|
22
|
+
* that drops one call is a diff a reviewer can spot in a single line.
|
|
23
|
+
*/
|
|
24
|
+
export declare function invalidateSavedCallable(qc: QueryInvalidator, listKey: readonly unknown[], callableKey: readonly unknown[]): void;
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { TriggerPreviewFieldDef } from './trigger-preview.ts';
|
|
2
|
+
/**
|
|
3
|
+
* One declared input of a Function or Endpoint, as a snippet needs it.
|
|
4
|
+
*
|
|
5
|
+
* A BARE STRING is treated as REQUIRED. That is the shape this file took before
|
|
6
|
+
* it knew about optionality, when every input rendered active — so a caller that
|
|
7
|
+
* only has keys keeps its existing output rather than silently having every
|
|
8
|
+
* field commented out.
|
|
9
|
+
*/
|
|
10
|
+
export type SnippetInput = string | {
|
|
11
|
+
key: string;
|
|
12
|
+
required?: boolean;
|
|
13
|
+
};
|
|
14
|
+
/** What the caller is looking at. Mirrors the four runnable URN arms plus assets. */
|
|
15
|
+
export type SnippetCallable = {
|
|
16
|
+
kind: "workflow";
|
|
17
|
+
id: string;
|
|
18
|
+
displayName?: string;
|
|
19
|
+
key?: string;
|
|
20
|
+
alias?: string;
|
|
21
|
+
} | {
|
|
22
|
+
kind: "function";
|
|
23
|
+
id: string;
|
|
24
|
+
key?: string;
|
|
25
|
+
inputs?: readonly SnippetInput[];
|
|
26
|
+
alias?: string;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* An Endpoint. `invokeUrl` / `invokeUrlByKey` are the two SERVER-rendered
|
|
30
|
+
* forms of its public address, passed straight through from the endpoints
|
|
31
|
+
* envelope; `urlForm` is which of them the page currently has selected, so a
|
|
32
|
+
* raw-HTTP sample follows the toggle the reader can see. All three are
|
|
33
|
+
* optional — an Endpoint with no URL in hand simply gets no HTTP snippet.
|
|
34
|
+
* `inputs` are the target's input parameter keys, resolved from the Function
|
|
35
|
+
* or Workflow the Endpoint dispatches to.
|
|
36
|
+
*/
|
|
37
|
+
| {
|
|
38
|
+
kind: "endpoint";
|
|
39
|
+
id: string;
|
|
40
|
+
key?: string;
|
|
41
|
+
invokeUrl?: string;
|
|
42
|
+
invokeUrlByKey?: string;
|
|
43
|
+
urlForm?: "id" | "key";
|
|
44
|
+
alias?: string;
|
|
45
|
+
inputs?: readonly SnippetInput[];
|
|
46
|
+
}
|
|
47
|
+
/** One app action, invoked through a connection — the `conn_` URN arm. */
|
|
48
|
+
| {
|
|
49
|
+
kind: "connection";
|
|
50
|
+
id: string;
|
|
51
|
+
action: string;
|
|
52
|
+
params?: string[];
|
|
53
|
+
} | {
|
|
54
|
+
kind: "var";
|
|
55
|
+
name: string;
|
|
56
|
+
} | {
|
|
57
|
+
kind: "document";
|
|
58
|
+
key: string;
|
|
59
|
+
};
|
|
60
|
+
export interface Snippet {
|
|
61
|
+
/** Runnable TypeScript against `@w6w/sdk`. */
|
|
62
|
+
node: string;
|
|
63
|
+
/** A single `w6w …` invocation. */
|
|
64
|
+
cli: string;
|
|
65
|
+
/** Runnable Python against `w6w` (PyPI). */
|
|
66
|
+
python: string;
|
|
67
|
+
/**
|
|
68
|
+
* A raw-HTTP (`curl`) call against the resource's own public URL — OPTIONAL,
|
|
69
|
+
* and emitted only where such a URL exists and was handed in (today: an
|
|
70
|
+
* Endpoint). Optional rather than required so the other five `case` arms of
|
|
71
|
+
* {@link buildSnippet} are untouched, and so the tab strip can render only
|
|
72
|
+
* the tabs a built snippet actually carries.
|
|
73
|
+
*/
|
|
74
|
+
curl?: string;
|
|
75
|
+
/** The contract operation this maps to, shown so the snippet is checkable. */
|
|
76
|
+
operation: string;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Can this id be passed to `client.run({urn})` at all?
|
|
80
|
+
*
|
|
81
|
+
* Ids are host-issued and carry a kind prefix (rfcs/function.md §id — "host-issued
|
|
82
|
+
* opaque id (`fn_…`)"), but the create routes do not *enforce* it, so a
|
|
83
|
+
* hand-authored id can reach the database without one. Such a resource is
|
|
84
|
+
* reachable through the studio and through its own `/invoke` route, but NOT
|
|
85
|
+
* through the URN operation the wrappers expose — and a snippet is a promise
|
|
86
|
+
* that the code in it runs.
|
|
87
|
+
*/
|
|
88
|
+
export declare function isUrnAddressable(id: string): boolean;
|
|
89
|
+
/**
|
|
90
|
+
* Build the Node + CLI snippet for one resource, or `null` when the contract
|
|
91
|
+
* has no operation for it (today: a function or endpoint whose id carries no
|
|
92
|
+
* runnable prefix).
|
|
93
|
+
*/
|
|
94
|
+
export declare function buildSnippet(resource: SnippetCallable, triggerFields?: readonly TriggerPreviewFieldDef[]): Snippet | null;
|
|
95
|
+
/** Why no snippet exists, phrased for the reader rather than for a log. */
|
|
96
|
+
export declare function unavailableReason(resource: SnippetCallable): string;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { CallableOnError, ErrorReroute, RetryPolicy } from '@w6w/sdk/console';
|
|
2
|
+
/** Structural mirror of `WorkspaceCallable` (`src/ui/workspace.tsx`) — only
|
|
3
|
+
* the fields this module reads. `onPolicyChange` is the WORKFLOW arm's
|
|
4
|
+
* injected writer (see {@link isAvailable}); the two callable arms have no
|
|
5
|
+
* such member and never read it. */
|
|
6
|
+
export type SettingsCallable = {
|
|
7
|
+
kind: string;
|
|
8
|
+
id: string;
|
|
9
|
+
onPolicyChange?: (policy: CallablePolicy) => void;
|
|
10
|
+
} | null;
|
|
11
|
+
/** The three fields this tool owns on a Function/Endpoint definition —
|
|
12
|
+
* TC2's pinned shape, shared by both `Fn` and `Endpoint`. */
|
|
13
|
+
export interface CallablePolicy {
|
|
14
|
+
retry?: RetryPolicy;
|
|
15
|
+
onError?: CallableOnError;
|
|
16
|
+
reroute?: ErrorReroute;
|
|
17
|
+
}
|
|
18
|
+
/** A definition carrying (at least) the three fields above, plus whatever
|
|
19
|
+
* else `Fn`/`Endpoint` declares — `definitionWithPolicy` preserves every
|
|
20
|
+
* field this type doesn't name. */
|
|
21
|
+
export type CallableDefinition = CallablePolicy;
|
|
22
|
+
/**
|
|
23
|
+
* Is the Error handling tool meaningful for this context?
|
|
24
|
+
*
|
|
25
|
+
* A Function and an Endpoint: always — the panel owns their whole
|
|
26
|
+
* read-modify-write, because nothing else on the page is editing the same
|
|
27
|
+
* definition at the same time.
|
|
28
|
+
*
|
|
29
|
+
* A Workflow: only when the publishing page injects `onPolicyChange` (core
|
|
30
|
+
* Workflow RFC — *Amendment — 2026-08-21: the run-level error handler*). This
|
|
31
|
+
* is not fussiness. The workflow canvas holds the definition as JSON TEXT it
|
|
32
|
+
* owns, and auto-saves it (`settings.autoSave` defaults to ON), so a rail
|
|
33
|
+
* panel doing its own read-modify-write against the server would be racing the
|
|
34
|
+
* editor: whichever wrote last would silently drop the other's edit, and the
|
|
35
|
+
* loser would most often be the rail, since the canvas re-sends its whole
|
|
36
|
+
* buffer on the next keystroke. Injecting the writer instead means the rail
|
|
37
|
+
* edits the SAME buffer the canvas is about to save. A page that does not own
|
|
38
|
+
* that buffer (the run-detail page) publishes no writer, and the tool simply
|
|
39
|
+
* does not appear there.
|
|
40
|
+
*
|
|
41
|
+
* A Connection has no run-level policy at all. `null` (no resource published)
|
|
42
|
+
* fails closed, house style (mirrors `code-rail.ts`'s `isAvailable`).
|
|
43
|
+
*/
|
|
44
|
+
export declare function isAvailable(ctx: SettingsCallable): boolean;
|
|
45
|
+
/**
|
|
46
|
+
* Read a definition's `{retry, onError, reroute}` into the shape the panel's
|
|
47
|
+
* local editing state starts from. Normalizes the same way
|
|
48
|
+
* `definitionWithPolicy` writes: a stored `onError: "fail"` (never written by
|
|
49
|
+
* this tool, but defensive against a hand-edited or older definition) reads
|
|
50
|
+
* back as absent, matching how `NodeConfigForm` already treats `"fail"` as
|
|
51
|
+
* its own default.
|
|
52
|
+
*/
|
|
53
|
+
export declare function policyFromDefinition(def: CallableDefinition): CallablePolicy;
|
|
54
|
+
/**
|
|
55
|
+
* Read-modify-write: apply `policy`'s `{retry, onError, reroute}` onto `def`,
|
|
56
|
+
* preserving every OTHER field untouched (`impl`/`inputs`/`key` on a
|
|
57
|
+
* Function, `target`/`input`/`key` on an Endpoint, …) — the save this tool
|
|
58
|
+
* issues is never a bare `{retry, onError, reroute}` object. A field whose
|
|
59
|
+
* value is the default is OMITTED entirely, not written as `undefined`:
|
|
60
|
+
* `policy.onError === "fail"` (or absent) drops the key, matching
|
|
61
|
+
* `NodeConfigForm`'s own "fail" -> absent convention for the field it edits
|
|
62
|
+
* in place. Built by destructuring the three fields OUT of `def` and
|
|
63
|
+
* conditionally re-spreading them, rather than `delete`, so the key is
|
|
64
|
+
* genuinely absent from the returned object, not merely `undefined`-valued —
|
|
65
|
+
* `node:assert/strict`'s deep-equal distinguishes the two (this module's own
|
|
66
|
+
* test pins it).
|
|
67
|
+
*/
|
|
68
|
+
export declare function definitionWithPolicy<T extends CallableDefinition>(def: T, policy: CallablePolicy): T;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Slug rules — the ONE place in `studio/src` that owns one.
|
|
3
|
+
*
|
|
4
|
+
* Two rules live here and they are deliberately NOT the same rule:
|
|
5
|
+
*
|
|
6
|
+
* · `slugify()` turns a human display name into a machine key. It is the
|
|
7
|
+
* fallback the Endpoint and Function editors use when the operator leaves
|
|
8
|
+
* `key` blank, and it is permissive on purpose: whatever it returns is a
|
|
9
|
+
* legal resource key, digits-first and two characters included.
|
|
10
|
+
* · `ACCOUNT_SLUG_RE` / `isValidAccountSlug()` decide whether a string is a
|
|
11
|
+
* legal ACCOUNT slug — the account segment a key-form invoke URL is
|
|
12
|
+
* addressed by. That rule is stricter: it must start with a letter and run to
|
|
13
|
+
* at least three characters, so `2024-team` and `ab` are both perfectly good
|
|
14
|
+
* keys and both invalid account slugs.
|
|
15
|
+
*
|
|
16
|
+
* The regex is exported rather than re-typed by each caller. A second copy is
|
|
17
|
+
* exactly how a form comes to accept a value the server rejects, so the literal
|
|
18
|
+
* appears in this file and nowhere else in `src/`.
|
|
19
|
+
*
|
|
20
|
+
* Why `src/lib` and why this module imports nothing: `src/lib/*.ts` is the only
|
|
21
|
+
* place studio's `node --test` suite can reach. A rule living inside a `.tsx`
|
|
22
|
+
* page cannot be unit-tested at all (Node's type-stripping does not parse JSX),
|
|
23
|
+
* and a `src/lib` module that imports `@w6w/ui` throws
|
|
24
|
+
* `ERR_UNKNOWN_FILE_EXTENSION` under the same runner because the barrel
|
|
25
|
+
* re-exports `.tsx`. Same constraint documented at
|
|
26
|
+
* `src/lib/workflow-validity.ts:11-20`.
|
|
27
|
+
*/
|
|
28
|
+
/** Kebab-case a display name into a machine key (the fallback when key is blank). */
|
|
29
|
+
export declare function slugify(s: string): string;
|
|
30
|
+
/**
|
|
31
|
+
* A legal account slug: lowercase, opens with a LETTER, then two or more
|
|
32
|
+
* letters/digits/hyphens — three characters minimum.
|
|
33
|
+
*
|
|
34
|
+
* Note this is NOT the server's `tenants.ts` `SLUG_RE`
|
|
35
|
+
* (`/^[a-z0-9][a-z0-9_-]*$/`), which governs tenant ids and is a different,
|
|
36
|
+
* more permissive rule. Do not merge the two.
|
|
37
|
+
*/
|
|
38
|
+
export declare const ACCOUNT_SLUG_RE: RegExp;
|
|
39
|
+
/** Does `s` satisfy {@link ACCOUNT_SLUG_RE}? */
|
|
40
|
+
export declare function isValidAccountSlug(s: string): boolean;
|
|
41
|
+
/**
|
|
42
|
+
* A legal Endpoint `key` — mirrors the server's rule VERBATIM, not
|
|
43
|
+
* {@link ACCOUNT_SLUG_RE} above: that one is `{2,}` with no 39-character cap
|
|
44
|
+
* and encodes neither the `--` rule nor the trailing-`-` rule, so a form that
|
|
45
|
+
* validated a key with it would accept a value the server rejects.
|
|
46
|
+
*
|
|
47
|
+
* Source of truth: `packages/server/packages/bll/accounts.ts:72`
|
|
48
|
+
* (`ACCOUNT_SLUG_RE = /^[a-z][a-z0-9-]{2,38}$/`) + `:216-218` (`isAccountSlug`),
|
|
49
|
+
* reached from `packages/server/packages/api/invoke-address.ts:55-57`
|
|
50
|
+
* (`isEndpointKey = isAccountSlug`). There is no reserved-word check on an
|
|
51
|
+
* Endpoint key server-side — `isAccountSlug` only, never
|
|
52
|
+
* `RESERVED_ACCOUNT_SLUGS` — so none is added here either.
|
|
53
|
+
*/
|
|
54
|
+
export declare function isEndpointKey(s: string): boolean;
|
|
55
|
+
/**
|
|
56
|
+
* Filters a keystroke into a key input down to what {@link isEndpointKey}'s
|
|
57
|
+
* grammar can ever accept: lowercase letters, digits, hyphens — nothing
|
|
58
|
+
* else, capped at the grammar's own 39-character ceiling. A space or any
|
|
59
|
+
* other disallowed character is dropped outright rather than folded into a
|
|
60
|
+
* `-` ({@link slugify}'s job, for the one-time displayName-to-key fallback —
|
|
61
|
+
* this is a LIVE filter on a field the operator is typing directly into, so
|
|
62
|
+
* silently substituting a different character would be its own surprise).
|
|
63
|
+
* Positional rules the grammar also enforces (must START with a letter, no
|
|
64
|
+
* `--`, no trailing `-`) are left to {@link isEndpointKey} at Save time —
|
|
65
|
+
* blocking those mid-keystroke would refuse a caller who is one keystroke
|
|
66
|
+
* away from a valid value (e.g. typing `"2"` before backspacing to start
|
|
67
|
+
* over).
|
|
68
|
+
*/
|
|
69
|
+
export declare function filterKeyInput(raw: string): string;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The extracted decision behind `useImportSpecMutation`'s `onSuccess` (T1.2.1, AC-3): given the
|
|
3
|
+
* KIND of document that was just imported, which single list-query key must be invalidated — and
|
|
4
|
+
* only that one.
|
|
5
|
+
*
|
|
6
|
+
* The bug this exists to kill: `src/repos/spec-import.ts` used to run an unconditional
|
|
7
|
+
* `qc.invalidateQueries({ queryKey: functionsKey })` on every import — invisible to `tsc`, only
|
|
8
|
+
* visible when a human imports an Endpoint or Workflow and its OWN list stays stale while
|
|
9
|
+
* Functions gets pointlessly invalidated.
|
|
10
|
+
*
|
|
11
|
+
* The three real list keys live in `src/repos/functions.ts` / `endpoints.ts` / `workflows.ts`, and
|
|
12
|
+
* this module cannot import them as VALUES: `node --test` throws `ERR_UNKNOWN_FILE_EXTENSION` on
|
|
13
|
+
* anything reaching the `@w6w/ui` / JSX import graph, and `src/repos/*.ts` reaches it through
|
|
14
|
+
* `../api/apiClient.tsx` — see `src/lib/save-invalidation.ts`'s docstring for the identical
|
|
15
|
+
* constraint. So the caller (`spec-import.ts`, which already imports all three) hands them in; this
|
|
16
|
+
* module owns only the DISPATCH — which kind picks which key — not the keys' own values. That keeps
|
|
17
|
+
* the two ends impossible to drift apart on the workflow arm's shape in particular: `workflowsKey`
|
|
18
|
+
* is `(project?: string) => ["workflows", project]`, NOT a bare constant like the other two, and
|
|
19
|
+
* `WorkflowsPage`'s list branch (`CallableList`, `pages/CallablePage.tsx`) reads its cache through
|
|
20
|
+
* `useCallableListQuery("workflow", …, projectId)` — an invalidation that drops the project id hits
|
|
21
|
+
* a DIFFERENT cache entry and the imported row would not appear without a manual refresh, which is
|
|
22
|
+
* the exact bug this module exists to prevent.
|
|
23
|
+
*/
|
|
24
|
+
export type SpecImportKind = "function" | "endpoint" | "workflow";
|
|
25
|
+
/** Mirrors `src/lib/save-invalidation.ts`'s `QueryInvalidator` — re-declared, not imported, so this
|
|
26
|
+
* module's zero-value-import rule needs no exception (a structural type has no runtime cost either
|
|
27
|
+
* way; TanStack Query's real `QueryClient` satisfies both). */
|
|
28
|
+
export interface QueryInvalidator {
|
|
29
|
+
invalidateQueries(filters: {
|
|
30
|
+
queryKey: readonly unknown[];
|
|
31
|
+
}): unknown;
|
|
32
|
+
}
|
|
33
|
+
/** The three list-key producers, handed in by the caller — see the module docblock for why this
|
|
34
|
+
* module cannot hold them itself. `workflowsKey` is a function, not a value, because it is scoped
|
|
35
|
+
* by project. */
|
|
36
|
+
export interface SpecImportListKeys {
|
|
37
|
+
functionsKey: readonly unknown[];
|
|
38
|
+
endpointsKey: readonly unknown[];
|
|
39
|
+
workflowsKey: (projectId: string | undefined) => readonly unknown[];
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Total: exhaustively switched over the three spec kinds (mirrors `specCollectionForKind`'s idiom
|
|
43
|
+
* in `src/lib/rail-settings.ts` — a plain switch with no default arm, so an unhandled kind is a
|
|
44
|
+
* compile error rather than a silent fallthrough).
|
|
45
|
+
*/
|
|
46
|
+
export declare function specImportListKey(kind: SpecImportKind, keys: SpecImportListKeys, projectId: string | undefined): readonly unknown[];
|
|
47
|
+
/** Invalidate the ONE list key the imported document's own kind reads — never more than one. */
|
|
48
|
+
export declare function invalidateImportedCallable(qc: QueryInvalidator, kind: SpecImportKind, keys: SpecImportListKeys, projectId: string | undefined): void;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure decision logic behind `../components/TagEditor.tsx` — kept out of the
|
|
3
|
+
* component so `node --test` can exercise it directly
|
|
4
|
+
* (`__tests__/tag-editor.test.ts`) without touching React, mirroring
|
|
5
|
+
* `alias-rail.ts`/`rail-settings.ts`'s own split. Carries over the retiring
|
|
6
|
+
* `WorkflowsPage.tsx`'s retired tags-editing modal's data contract verbatim:
|
|
7
|
+
* `string[]`, trim, dedupe-on-add, drop empties.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Applies a chip input's freeform text to the committed tag list. Called on
|
|
11
|
+
* every change to the trailing, not-yet-committed input — `typed` is always
|
|
12
|
+
* the FULL current value of just that one input, which resets to `""` after
|
|
13
|
+
* a commit, so a single keystroke never carries more than the one character
|
|
14
|
+
* just typed.
|
|
15
|
+
*
|
|
16
|
+
* A comma anywhere in `typed` is the commit signal: every comma-delimited
|
|
17
|
+
* segment is trimmed and, if non-empty and not already present, appended as
|
|
18
|
+
* a chip — in order, regardless of whether it sits before or after the last
|
|
19
|
+
* comma. That is what makes both shapes work from the one rule: typing
|
|
20
|
+
* `"alpha,"` one character at a time commits `"alpha"` the moment the comma
|
|
21
|
+
* lands, and pasting `"a,b,c"` in one go (no trailing comma at all) still
|
|
22
|
+
* commits all three, because nothing here treats "the last segment" as
|
|
23
|
+
* special. The returned `typed` is always `""` once a comma triggered a
|
|
24
|
+
* commit. With no comma present at all, nothing commits and `typed` passes
|
|
25
|
+
* through unchanged, so the caller can just store it as the next draft.
|
|
26
|
+
*/
|
|
27
|
+
export declare function commitTag(tags: string[], typed: string): {
|
|
28
|
+
tags: string[];
|
|
29
|
+
typed: string;
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Removes exactly one tag by VALUE, never by position — a list carrying both
|
|
33
|
+
* a tag and a second tag that merely contains it as a prefix (`["ab", "b"]`)
|
|
34
|
+
* only ever loses the exact match.
|
|
35
|
+
*/
|
|
36
|
+
export declare function removeTag(tags: string[], tag: string): string[];
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* "Call from code" trigger preview (T2.2.1, HITL-2/HITL-4 pinned):
|
|
3
|
+
*
|
|
4
|
+
* > one tab per MANUAL (`@w6w/trigger`) trigger step, in declared order,
|
|
5
|
+
* > labelled `step.displayName ?? step.id`. Webhook/scheduler steps are
|
|
6
|
+
* > excluded — they declare named params, never a generic `fields` array.
|
|
7
|
+
*
|
|
8
|
+
* Pure and testable by design, same shape as `workflow-validity.ts`:
|
|
9
|
+
* `WorkflowDetailPage.tsx`/`WorkflowsPage.tsx` are JSX, which Node 24's
|
|
10
|
+
* type-stripping cannot parse, so nothing in it can be loaded by
|
|
11
|
+
* `node --test`. This module cannot import `@w6w/ui`/`@w6w/ui/flow` either
|
|
12
|
+
* way (`ERR_UNKNOWN_FILE_EXTENSION` — see `workflow-validity.ts`'s docstring).
|
|
13
|
+
* Instead, "is this step a MANUAL trigger" and "read a trigger's declared
|
|
14
|
+
* `fields`" are **caller-injected** on `TriggerPreviewContext` —
|
|
15
|
+
* `WorkflowsPage.tsx`/`WorkflowDetailPage.tsx` import the real
|
|
16
|
+
* `TRIGGER_APP`/`asFieldDefs` from `@w6w/ui/flow` and pass them in. This file
|
|
17
|
+
* contains no `@w6w/*` app-id string literal.
|
|
18
|
+
*
|
|
19
|
+
* Deliberately narrower than `@w6w/ui/flow`'s own `isTriggerApp`, which also
|
|
20
|
+
* matches `@w6w/webhook`/`@w6w/scheduler` (all three are "entry nodes" for the
|
|
21
|
+
* canvas). Those two kinds declare named params, not a generic `fields`
|
|
22
|
+
* array, so they cannot be previewed the same way — the injected predicate a
|
|
23
|
+
* caller supplies here is expected to be the MANUAL-only check
|
|
24
|
+
* (`app === TRIGGER_APP`), not the broader `isTriggerApp`.
|
|
25
|
+
*/
|
|
26
|
+
/** One field a trigger declares — just enough of `@w6w/ui/flow`'s
|
|
27
|
+
* `TriggerFieldDef` for this preview (structurally compatible, not imported). */
|
|
28
|
+
export interface TriggerPreviewFieldDef {
|
|
29
|
+
key?: string;
|
|
30
|
+
type?: string;
|
|
31
|
+
required?: boolean;
|
|
32
|
+
default?: unknown;
|
|
33
|
+
}
|
|
34
|
+
/** A workflow graph step, just enough of it for this preview. */
|
|
35
|
+
export interface WorkflowStepLike {
|
|
36
|
+
id: string;
|
|
37
|
+
/** Human-facing step name, when the author set one. Falls back to `id`. */
|
|
38
|
+
displayName?: string;
|
|
39
|
+
uses?: {
|
|
40
|
+
app?: string;
|
|
41
|
+
action?: string;
|
|
42
|
+
};
|
|
43
|
+
with?: Record<string, unknown>;
|
|
44
|
+
}
|
|
45
|
+
/** A workflow definition, just enough of it for this preview. */
|
|
46
|
+
export interface WorkflowLike {
|
|
47
|
+
steps?: WorkflowStepLike[];
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Everything `triggerPreviews` needs that this pure module cannot compute or
|
|
51
|
+
* import itself — see the module docstring for why each field is
|
|
52
|
+
* caller-injected rather than derived in here.
|
|
53
|
+
*/
|
|
54
|
+
export interface TriggerPreviewContext {
|
|
55
|
+
/** Is this step's `uses.app` a MANUAL trigger (`@w6w/trigger`)? Webhook and
|
|
56
|
+
* scheduler steps must answer `false` here even though they are also
|
|
57
|
+
* "entry nodes" — they have no generic `fields` array to preview. */
|
|
58
|
+
isManualTrigger: (app: string) => boolean;
|
|
59
|
+
/** `@w6w/ui/flow`'s `asFieldDefs`, injected — reads a step's `with.fields`
|
|
60
|
+
* param value as an array of field definitions. */
|
|
61
|
+
asFieldDefs: (fields: unknown) => TriggerPreviewFieldDef[];
|
|
62
|
+
}
|
|
63
|
+
/** One manual trigger's declared fields, ready for the modal's picker. */
|
|
64
|
+
export interface TriggerPreview {
|
|
65
|
+
id: string;
|
|
66
|
+
/** `step.displayName ?? step.id`. */
|
|
67
|
+
label: string;
|
|
68
|
+
fields: TriggerPreviewFieldDef[];
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* One `TriggerPreview` per manual trigger step in `workflow.steps`, in
|
|
72
|
+
* declared order. Non-manual steps (including webhook/scheduler entry nodes)
|
|
73
|
+
* are excluded. A field with a missing/blank `key` is dropped — mirrors
|
|
74
|
+
* `@w6w/ui/flow`'s `fieldsToParams`, which does the same before turning
|
|
75
|
+
* `TriggerFieldDef[]` into a fillable form.
|
|
76
|
+
*/
|
|
77
|
+
export declare function triggerPreviews(workflow: WorkflowLike, ctx: TriggerPreviewContext): TriggerPreview[];
|
|
78
|
+
/**
|
|
79
|
+
* A start-payload skeleton for one manual trigger — every declared field at its
|
|
80
|
+
* declared default, so the Run panel opens with the shape the workflow actually
|
|
81
|
+
* expects instead of an empty object the author has to reconstruct by hand.
|
|
82
|
+
*
|
|
83
|
+
* Mirrors `@w6w/ui/flow`'s `seedValues` (which this module cannot import — see
|
|
84
|
+
* the header): an explicit `default` wins; otherwise the empty value for the
|
|
85
|
+
* declared type. Unknown types fall to `""`, matching that function.
|
|
86
|
+
*
|
|
87
|
+
* `undefined` in → `{}`, so a caller can pass a still-loading preview.
|
|
88
|
+
*/
|
|
89
|
+
export declare function triggerInputSeed(preview: TriggerPreview | undefined): Record<string, unknown>;
|