@w6w/ui 0.2.11 → 0.2.55

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 (138) hide show
  1. package/CHANGELOG.md +139 -2
  2. package/README.md +28 -10
  3. package/dist/AppPicker.d.ts +12 -1
  4. package/dist/CanvasContextMenu.d.ts +19 -0
  5. package/dist/{CodeBlock-BqXDA35P.js → CodeBlock-C-oIIYfC.js} +1436 -555
  6. package/dist/CodeBlock-C-oIIYfC.js.map +1 -0
  7. package/dist/CodeBlock-CymlfyeA.cjs +15 -0
  8. package/dist/CodeBlock-CymlfyeA.cjs.map +1 -0
  9. package/dist/CodeEditor.d.ts +4 -1
  10. package/dist/ConditionEditor.d.ts +11 -0
  11. package/dist/JsonEditor.d.ts +12 -0
  12. package/dist/ParamCustomization.d.ts +5 -0
  13. package/dist/ParamsForm.d.ts +11 -3
  14. package/dist/RouterEditor.d.ts +5 -0
  15. package/dist/StepBuilderModal.d.ts +83 -13
  16. package/dist/StepNameEditor.d.ts +11 -0
  17. package/dist/StopEditor.d.ts +5 -0
  18. package/dist/TriggerFillForm.d.ts +14 -1
  19. package/dist/WebhookListenPanel.d.ts +28 -0
  20. package/dist/WorkflowConnections.d.ts +29 -0
  21. package/dist/WorkflowConnectionsPanel.d.ts +5 -0
  22. package/dist/WorkflowFlowEditor.d.ts +67 -8
  23. package/dist/assets/script-completion.worker-DDJKkj5M.js +8290 -0
  24. package/dist/assets/script-completion.worker-DDJKkj5M.js.map +1 -0
  25. package/dist/canvas-context-menu.d.ts +27 -0
  26. package/dist/code.cjs +1 -1
  27. package/dist/code.mjs +3 -4
  28. package/dist/code.mjs.map +1 -1
  29. package/dist/components/AnchoredFlyout.d.ts +7 -0
  30. package/dist/components/ColumnsEditor.d.ts +27 -0
  31. package/dist/components/Combobox.d.ts +12 -1
  32. package/dist/components/ConfirmModal.d.ts +3 -1
  33. package/dist/components/CsvPanel.d.ts +21 -0
  34. package/dist/components/DataEntryEditor.d.ts +38 -0
  35. package/dist/components/DataEntryList.d.ts +33 -0
  36. package/dist/components/DataStoreList.d.ts +33 -0
  37. package/dist/components/DataTableGrid.d.ts +46 -0
  38. package/dist/components/EventbriteTriggerPicker.d.ts +7 -0
  39. package/dist/components/ExecutionDetail.d.ts +17 -1
  40. package/dist/components/ExecutionList.d.ts +19 -1
  41. package/dist/components/ExecutionLogPanel.d.ts +61 -3
  42. package/dist/components/ExpressionEditorModal.d.ts +33 -10
  43. package/dist/components/ExpressionOptions.d.ts +101 -15
  44. package/dist/components/HtmlPreview.d.ts +7 -0
  45. package/dist/components/JsonTree.d.ts +32 -0
  46. package/dist/components/ResolvedParams.d.ts +6 -1
  47. package/dist/components/ResultViewer.d.ts +46 -0
  48. package/dist/components/ScriptBindingsNotice.d.ts +31 -0
  49. package/dist/components/ScriptCodeField.d.ts +13 -0
  50. package/dist/components/StepStatusPill.d.ts +7 -0
  51. package/dist/components/expression-authoring.d.ts +13 -0
  52. package/dist/components/expression-dom.d.ts +17 -2
  53. package/dist/components/expression-template.d.ts +25 -3
  54. package/dist/components/icons.d.ts +1 -1
  55. package/dist/components/json-compose.d.ts +53 -0
  56. package/dist/components/result-format.d.ts +13 -0
  57. package/dist/condition-editor.d.ts +44 -0
  58. package/dist/connection-app-meta-BEXlKBgV.cjs +22 -0
  59. package/dist/connection-app-meta-BEXlKBgV.cjs.map +1 -0
  60. package/dist/connection-app-meta-ZCPakGjD.js +12422 -0
  61. package/dist/connection-app-meta-ZCPakGjD.js.map +1 -0
  62. package/dist/data-stores/data-store-view.d.ts +371 -0
  63. package/dist/eventbrite-trigger-selection.d.ts +13 -0
  64. package/dist/flow-connect.d.ts +22 -16
  65. package/dist/flow-delete.d.ts +16 -0
  66. package/dist/flow-history.d.ts +75 -0
  67. package/dist/flow-layout.d.ts +13 -0
  68. package/dist/flow-loop-colors.d.ts +39 -0
  69. package/dist/flow-loop.d.ts +98 -0
  70. package/dist/flow-node-flags.d.ts +14 -0
  71. package/dist/flow-problems.d.ts +69 -0
  72. package/dist/flow-state.d.ts +20 -0
  73. package/dist/flow-types.d.ts +137 -9
  74. package/dist/flow-utils.d.ts +27 -13
  75. package/dist/flow.cjs +4 -2
  76. package/dist/flow.cjs.map +1 -1
  77. package/dist/flow.d.ts +9 -3
  78. package/dist/flow.mjs +4028 -1585
  79. package/dist/flow.mjs.map +1 -1
  80. package/dist/index.cjs +2 -1
  81. package/dist/index.cjs.map +1 -1
  82. package/dist/index.d.ts +30 -4
  83. package/dist/index.mjs +2559 -1287
  84. package/dist/index.mjs.map +1 -1
  85. package/dist/node-samples.d.ts +80 -0
  86. package/dist/output-shape.d.ts +30 -14
  87. package/dist/param-customization.d.ts +7 -0
  88. package/dist/provider.d.ts +119 -7
  89. package/dist/resolve-params.d.ts +45 -11
  90. package/dist/run-visuals.d.ts +14 -21
  91. package/dist/script-bindings.d.ts +63 -0
  92. package/dist/script-completion-service.d.ts +9 -0
  93. package/dist/script-completion.worker.d.ts +1 -0
  94. package/dist/script-completions.d.ts +2 -0
  95. package/dist/state-shape.d.ts +38 -0
  96. package/dist/step-preview-state.d.ts +155 -6
  97. package/dist/step-problems.d.ts +42 -12
  98. package/dist/test-inputs.d.ts +25 -0
  99. package/dist/trigger-registration.d.ts +28 -0
  100. package/dist/types.d.ts +70 -8
  101. package/dist/use-app-action-defs.d.ts +9 -1
  102. package/dist/use-test-input.d.ts +18 -0
  103. package/dist/workflow-connections.d.ts +78 -0
  104. package/package.json +16 -7
  105. package/src/code.css +60 -6
  106. package/src/styles/_canvas.scss +35 -0
  107. package/src/styles/_code-editor.scss +35 -0
  108. package/src/styles/_code.scss +6 -5
  109. package/src/styles/_connections.scss +64 -0
  110. package/src/styles/_copyable.scss +24 -0
  111. package/src/styles/_data-stores.scss +138 -0
  112. package/src/styles/_data-vars.scss +17 -6
  113. package/src/styles/_execution-history.scss +73 -0
  114. package/src/styles/_execution-log.scss +145 -1
  115. package/src/styles/_expression-modal.scss +106 -16
  116. package/src/styles/_fields.scss +11 -0
  117. package/src/styles/_flow.scss +166 -0
  118. package/src/styles/_fx.scss +3 -1
  119. package/src/styles/_incoming-state.scss +33 -0
  120. package/src/styles/_modal.scss +12 -0
  121. package/src/styles/_multiselect.scss +35 -0
  122. package/src/styles/_sections.scss +36 -0
  123. package/src/styles/_step-builder.scss +145 -0
  124. package/src/styles/_tester.scss +56 -0
  125. package/src/styles/_tokens.scss +27 -1
  126. package/src/styles.css +1347 -41
  127. package/src/styles.scss +2 -0
  128. package/dist/CodeBlock-BqXDA35P.js.map +0 -1
  129. package/dist/CodeBlock-CulfbnZD.cjs +0 -15
  130. package/dist/CodeBlock-CulfbnZD.cjs.map +0 -1
  131. package/dist/ConfirmModal-Ln99S9NT.js +0 -7919
  132. package/dist/ConfirmModal-Ln99S9NT.js.map +0 -1
  133. package/dist/ConfirmModal-fjHW5rN-.cjs +0 -14
  134. package/dist/ConfirmModal-fjHW5rN-.cjs.map +0 -1
  135. package/dist/Copyable-DA6eiU7w.cjs +0 -2
  136. package/dist/Copyable-DA6eiU7w.cjs.map +0 -1
  137. package/dist/Copyable-F4NTaG77.js +0 -847
  138. package/dist/Copyable-F4NTaG77.js.map +0 -1
@@ -0,0 +1,371 @@
1
+ /**
2
+ * The pure, data-free vocabulary of a Data store (F-2, lifted from Studio's
3
+ * `lib/data-stores-view`, `data-cells`, `data-grid` and `data-store-errors`).
4
+ *
5
+ * One import point for every consumer (Studio, `@w6w/embed`, the components in
6
+ * this package): the wire types, the closed kind/scalar vocabularies, the
7
+ * cell text codec, the row-draft/write helpers and the error locator. Paths,
8
+ * query builders and cache keys deliberately stay in Studio.
9
+ *
10
+ * Pure and dependency-free on purpose: no React, no SDK, no `fetch`, only
11
+ * relative imports, so `node --test` loads it with nothing but type-stripping.
12
+ */
13
+ /** Display label per store kind (shared by every list and picker). */
14
+ export declare const DATA_STORE_KIND_LABEL: {
15
+ readonly kv: "Key-value";
16
+ readonly doc: "Document";
17
+ readonly table: "Table";
18
+ };
19
+ /**
20
+ * The three store shapes. `kv` holds one value per key, `doc` holds a JSON
21
+ * document per key, `table` holds rows whose columns are declared in the
22
+ * store's schema.
23
+ */
24
+ export type DataStoreKind = "kv" | "doc" | "table";
25
+ /**
26
+ * The server's scalar vocabulary (S-1). A value of this type is validated
27
+ * server-side and stored as the string the caller sent — never coerced.
28
+ */
29
+ export type ScalarType = "string" | "number" | "integer" | "boolean" | "date" | "datetime";
30
+ /** One declared table column (S-2). `default` is the column's JSON default, verbatim. */
31
+ export interface TableColumn {
32
+ name: string;
33
+ type: ScalarType;
34
+ required: boolean;
35
+ default?: unknown;
36
+ }
37
+ /** A `kv` store's schema (S-2): one scalar type for every value. */
38
+ export interface KvSchema {
39
+ valueType: ScalarType;
40
+ }
41
+ /** A `table` store's schema (S-2); `key` names the column whose cell is the row's key. */
42
+ export interface TableSchema {
43
+ columns: TableColumn[];
44
+ key?: string;
45
+ }
46
+ /** A store as the wire carries it (S-3). Timestamps are ISO-8601 strings. */
47
+ export interface DataStore {
48
+ id: string;
49
+ kind: DataStoreKind;
50
+ name: string;
51
+ description: string;
52
+ project: string;
53
+ schema: Record<string, unknown>;
54
+ entryCount: number;
55
+ sizeBytes: number;
56
+ createdBy: string;
57
+ createdAt: string;
58
+ updatedAt: string;
59
+ }
60
+ /** One entry as the wire carries it (S-3). `expiresAt` is `null` when the entry never expires. */
61
+ export interface Entry {
62
+ key: string;
63
+ value: unknown;
64
+ version: number;
65
+ sizeBytes: number;
66
+ expiresAt: string | null;
67
+ createdAt: string;
68
+ updatedAt: string;
69
+ }
70
+ /** `GET /data-stores` — one page of stores plus the cursor for the next one. */
71
+ export interface DataStorePage {
72
+ items: DataStore[];
73
+ nextCursor?: string;
74
+ }
75
+ /** `GET /data-stores/:id/entries` — one page of entries (a table query never carries a cursor). */
76
+ export interface EntryPage {
77
+ items: Entry[];
78
+ nextCursor?: string;
79
+ }
80
+ /** `POST /data-stores/:id/import` — how many CSV rows the host upserted/appended. */
81
+ export interface ImportResult {
82
+ imported: number;
83
+ }
84
+ /** `POST /data-stores` body. `schema` is the S-2 shape for the chosen `kind`. */
85
+ export interface DataStoreCreateInput {
86
+ kind: DataStoreKind;
87
+ name: string;
88
+ description?: string;
89
+ schema?: Record<string, unknown>;
90
+ }
91
+ /** `PATCH /data-stores/:id` body — every field optional, none of them the kind. */
92
+ export interface DataStorePatch {
93
+ name?: string;
94
+ description?: string;
95
+ schema?: Record<string, unknown>;
96
+ }
97
+ /** The closed set of store kinds, in the order the create dialog offers them. */
98
+ export declare const DATA_STORE_KINDS: readonly ["kv", "doc", "table"];
99
+ /** The closed set of scalar cell types, in the order the columns editor offers them. */
100
+ export declare const SCALAR_TYPES: readonly ["string", "number", "integer", "boolean", "date", "datetime"];
101
+ /** R-7: a CSV upload is at most 5 MB (5 242 880 bytes). The client checks before sending. */
102
+ export declare const CSV_MAX_BYTES = 5242880;
103
+ /**
104
+ * A `kv` store's declared value type, defaulting to `"string"` — S-2's own
105
+ * default, and the only safe reading of a schema the client did not write
106
+ * (a store created before the field existed, or one whose schema is garbage).
107
+ */
108
+ export declare function kvValueTypeOf(store: DataStore): ScalarType;
109
+ /**
110
+ * A `table` store's schema, or `null` when the store is not a table or its
111
+ * schema has no column array. `null` — not an empty column list — so the grid
112
+ * can tell "not a table" from "a table with nothing declared".
113
+ */
114
+ export declare function tableSchemaOf(store: DataStore): TableSchema | null;
115
+ /**
116
+ * The filename to save an export under: the host's own `filename="…"` from the
117
+ * `Content-Disposition` header when it sent one, otherwise `<store name>.csv`.
118
+ * A header without that parameter (`attachment` alone, or `null` when a
119
+ * proxy stripped it) falls back rather than producing a nameless file.
120
+ */
121
+ export declare function csvFilenameOf(contentDisposition: string | null, storeName: string): string;
122
+ /** Why a cell's text could not become a value. */
123
+ export type CellProblem = "required" | "not_a_number" | "not_an_integer" | "not_a_boolean" | "not_a_date" | "not_a_datetime";
124
+ /** The one sentence rendered beside the offending cell, per problem. */
125
+ export declare const CELL_PROBLEM_COPY: Record<CellProblem, string>;
126
+ /**
127
+ * Turn the text an operator typed into the value the wire takes, for a column
128
+ * of `type`.
129
+ *
130
+ * `required` is applied to the EMPTY cell only (R-7): every other rule is the
131
+ * server's own, so a cell this returns `ok` for is a cell the server accepts.
132
+ * `string` is the one type that keeps the text as typed — trimming it would
133
+ * silently edit the operator's value.
134
+ */
135
+ export declare function parseCell(type: ScalarType, text: string, required: boolean): {
136
+ ok: true;
137
+ value: string | number | boolean | undefined;
138
+ } | {
139
+ ok: false;
140
+ problem: CellProblem;
141
+ message: string;
142
+ };
143
+ /**
144
+ * The text to put in a cell for an already-typed value.
145
+ *
146
+ * `undefined`/`null` render as the empty cell (never `"undefined"` or `"null"`);
147
+ * a string value for a string-ish column is shown as itself; a finite number
148
+ * and a boolean render as their JSON literals; anything else (an object cell,
149
+ * a `null` inside a document) falls back to its JSON text so the cell shows
150
+ * what the server holds rather than `[object Object]`.
151
+ */
152
+ export declare function serializeCell(type: ScalarType, value: unknown): string;
153
+ /**
154
+ * Is an already-typed JSON value of `type`? The same rules {@linkcode parseCell}
155
+ * applies to text, applied to a value that came back from the server — the grid
156
+ * uses it to mark a row the server would refuse before the operator presses
157
+ * Save. `required` plays no part here: an absent value is the caller's problem
158
+ * to decide about, not this predicate's.
159
+ */
160
+ export declare function isCellValue(type: ScalarType, value: unknown): boolean;
161
+ /** What is shown when the server said nothing a human can read. */
162
+ export declare const DATA_STORE_ERROR_FALLBACK = "The request failed.";
163
+ /** `rawRequest`'s `status: 0` — the request never reached the server. */
164
+ export declare const DATA_STORE_NETWORK_ERROR = "Could not reach the server.";
165
+ /** A failure, flattened into the fields the page needs and nothing else. */
166
+ export interface DataStoreErrorLocator {
167
+ /** Always present: the server's own sentence, or one of the two copy constants above. */
168
+ message: string;
169
+ /** The host's machine-readable code (`invalid_value`, `invalid_cursor`, …). */
170
+ code?: string;
171
+ /** The HTTP status; `0` is the transport-failure convention. */
172
+ status?: number;
173
+ /** The request-body field the host blamed. */
174
+ field?: string;
175
+ /** The 0-based CSV data row the host blamed (header excluded). */
176
+ row?: number;
177
+ /** The table column the host blamed. */
178
+ column?: string;
179
+ }
180
+ /**
181
+ * Locate a thrown JSON-call failure: an `ApiError` (whose parsed body lives on
182
+ * `.raw`), a plain `Error`, or anything else at all.
183
+ *
184
+ * The message falls back in that order — the envelope's `message`, the error's
185
+ * own `message`, then {@linkcode DATA_STORE_ERROR_FALLBACK} — so an unfamiliar
186
+ * throw still produces a sentence rather than an empty panel.
187
+ */
188
+ export declare function locateDataStoreError(e: unknown): DataStoreErrorLocator;
189
+ /**
190
+ * Locate a CSV-call failure from P-RAW's `{status, text}` — the body is still
191
+ * unparsed text because that transport does not know the content type.
192
+ *
193
+ * `status: 0` means the request never produced a response, and gets the
194
+ * transport sentence rather than an attempt to parse an empty body. Otherwise
195
+ * the body is parsed iff it is JSON: an HTML error page from a proxy is
196
+ * `{status, message: fallback}`, not a crash.
197
+ */
198
+ export declare function locateRawResponseError(res: {
199
+ status: number;
200
+ text: string;
201
+ }): DataStoreErrorLocator;
202
+ /** Where the message is rendered: under one table cell, under one form field, or over the whole form. */
203
+ export declare function errorPlacement(loc: DataStoreErrorLocator): {
204
+ kind: "cell";
205
+ column: string;
206
+ row?: number;
207
+ } | {
208
+ kind: "field";
209
+ field: string;
210
+ } | {
211
+ kind: "form";
212
+ };
213
+ /**
214
+ * The operator's 1-based line number in the CSV they uploaded, from the host's
215
+ * 0-based data-row index: the header row is line 1, so data row 0 is line 2.
216
+ */
217
+ export declare function csvLineOf(row: number): number;
218
+ /**
219
+ * The draft id of a row that does not exist yet: a NUL-prefixed sentinel, which
220
+ * R-5 forbids a real key from ever being (no control characters in a key), so
221
+ * `id === NEW_ROW_ID` and "this row has no server-side key" are the same fact.
222
+ */
223
+ export declare const NEW_ROW_ID = "\0new";
224
+ /** Rendered beside a row whose `ifVersion` was stale — never as the server's sentence alone. */
225
+ export declare const VERSION_CONFLICT_COPY = "Changed by someone else since you loaded it.";
226
+ /** A `doc` store holds a JSON object or array; anything else is not a document. */
227
+ export declare const DOC_VALUE_COPY = "Enter a JSON object or array.";
228
+ /** R-7's client-side ceiling copy — the check runs before anything is sent. */
229
+ export declare const CSV_TOO_LARGE_COPY = "The file is larger than 5 MB.";
230
+ /**
231
+ * One row's editable state: the id it is saved under (`entry.key`, or
232
+ * {@linkcode NEW_ROW_ID}), the version the save guards with (`null` for a new
233
+ * row) and the cell TEXT per declared column (never a parsed value — the text
234
+ * is what the operator is editing, and re-serialising it on every keystroke
235
+ * would fight their cursor).
236
+ */
237
+ export interface RowDraft {
238
+ id: string;
239
+ version: number | null;
240
+ cells: Record<string, string>;
241
+ }
242
+ /**
243
+ * An entry's value read as a table row: the object the server stored, or `{}`
244
+ * for anything that is not a plain object (a `null`, an array, a scalar from a
245
+ * column set that has since changed).
246
+ */
247
+ export declare function rowValueOf(entry: Entry): Record<string, unknown>;
248
+ /** The draft an entry starts as: its key, its version, and each declared column's text. */
249
+ export declare function draftFromEntry(entry: Entry, columns: readonly TableColumn[]): RowDraft;
250
+ /**
251
+ * The draft a brand-new row starts as: {@linkcode NEW_ROW_ID}, no version, and
252
+ * each column seeded from its declared `default` (absent default = empty cell).
253
+ */
254
+ export declare function newRowDraft(columns: readonly TableColumn[]): RowDraft;
255
+ /**
256
+ * Which declared columns the operator actually changed, in DECLARED order.
257
+ *
258
+ * Declared order (not object order) so the answer is stable across browsers and
259
+ * the row's Save button can decide "dirty" with one empty-array check. An
260
+ * untouched draft is `[]`.
261
+ */
262
+ export declare function dirtyColumns(draft: RowDraft, base: RowDraft, columns: readonly TableColumn[]): string[];
263
+ /**
264
+ * The row body a Save sends, or the per-cell refusals that stop it.
265
+ *
266
+ * Every DECLARED column is parsed through {@linkcode parseCell} with its own
267
+ * `required` flag: an absent value omits the key entirely (R-7's empty-cell
268
+ * rule, so the host's default applies), a `string` cell keeps its text verbatim
269
+ * and every other type is the JSON value the server expects — never the typed
270
+ * text. Failures are keyed by column name so the caller renders them under the
271
+ * offending cell.
272
+ */
273
+ export declare function buildRowValue(draft: RowDraft, columns: readonly TableColumn[]): {
274
+ ok: true;
275
+ value: Record<string, unknown>;
276
+ } | {
277
+ ok: false;
278
+ errors: Record<string, string>;
279
+ };
280
+ /**
281
+ * The `ttlSeconds` a save must resend so it does not CLEAR an existing expiry
282
+ * (S-1: a PUT without `ttlSeconds` sets `expires_at = NULL`).
283
+ *
284
+ * `undefined` for an entry that never expires, for an unparseable timestamp and
285
+ * for one already in the past — in all three cases sending nothing is correct
286
+ * (and a non-positive TTL is not a TTL the host accepts). Rounded UP, so a save
287
+ * one millisecond before the deadline does not shorten the entry's life.
288
+ */
289
+ export declare function remainingTtlSeconds(expiresAt: string | null, nowMs: number): number | undefined;
290
+ /**
291
+ * Which request a draft implies: an INSERT (`POST entries`, no `ifVersion`) for
292
+ * a row that does not exist yet, otherwise a PUT under the row's key guarded by
293
+ * the version the operator loaded.
294
+ *
295
+ * `ttlSeconds` is present ONLY when the caller has one: it reaches the wire as
296
+ * a defining key, and an explicit `undefined` would be indistinguishable from
297
+ * "the caller measured nothing".
298
+ */
299
+ export declare function rowWriteOf(draft: RowDraft, value: Record<string, unknown>, ttlSeconds: number | undefined): {
300
+ kind: "insert";
301
+ value: Record<string, unknown>;
302
+ ttlSeconds?: number;
303
+ } | {
304
+ kind: "put";
305
+ key: string;
306
+ value: Record<string, unknown>;
307
+ ifVersion: number;
308
+ ttlSeconds?: number;
309
+ };
310
+ /**
311
+ * The cell errors a refusal places, or `null` when it belongs somewhere else
312
+ * (the form, a request-body field, a column this table does not declare).
313
+ *
314
+ * `null` is load-bearing: the grid renders `grid-error` exactly when this
315
+ * returns `null`, so "the message shows in one slot" is a property of the
316
+ * answer rather than of the caller's care.
317
+ */
318
+ export declare function cellErrorsOf(loc: DataStoreErrorLocator, columns: readonly TableColumn[]): Record<string, string> | null;
319
+ /**
320
+ * Is this failure the optimistic-concurrency refusal — and nothing else?
321
+ *
322
+ * `409` alone is not enough: `entry_exists` and `store_exists` share the status
323
+ * and neither is fixed by reloading, so both halves of the locator must agree.
324
+ */
325
+ export declare function isVersionConflict(loc: DataStoreErrorLocator): boolean;
326
+ /**
327
+ * A `doc` store's value from the editor's text: any JSON object or array.
328
+ *
329
+ * A scalar is refused rather than wrapped — the store's own `doc` shape is an
330
+ * object/array (S-2), and the host would refuse `42` anyway; failing here means
331
+ * the operator sees why without a round trip. `null` parses but is not a
332
+ * document, so it is refused with the same sentence.
333
+ */
334
+ export declare function parseDocText(text: string): {
335
+ ok: true;
336
+ value: object;
337
+ } | {
338
+ ok: false;
339
+ message: string;
340
+ };
341
+ /**
342
+ * A `kv` store's value from the editor's text.
343
+ *
344
+ * `string` is the one type whose text IS the value, empty string included (an
345
+ * empty `string` entry is a real value, not an absent one), so it never passes
346
+ * through {@linkcode parseCell} — which reads an empty cell as absent. Every
347
+ * other type is parsed exactly as a table cell would be, `required` on, because
348
+ * a kv entry always has a value.
349
+ */
350
+ export declare function kvValueOf(type: ScalarType, text: string): {
351
+ ok: true;
352
+ value: unknown;
353
+ } | {
354
+ ok: false;
355
+ message: string;
356
+ };
357
+ /**
358
+ * What a CSV import's `RawResponse` says to the operator.
359
+ *
360
+ * The host is the only parser (R-7): a `200` reports how many rows it took, and
361
+ * a refusal is located rather than interpreted — a `row` becomes the operator's
362
+ * own 1-based line (`csvLineOf`), the `column` is named when the host named one,
363
+ * and everything else is the host's sentence verbatim.
364
+ */
365
+ export declare function csvImportMessage(res: {
366
+ status: number;
367
+ text: string;
368
+ }): {
369
+ ok: boolean;
370
+ message: string;
371
+ };
@@ -0,0 +1,13 @@
1
+ import { ActionDef } from './types.ts';
2
+ export interface EventbriteTriggerChoices {
3
+ triggerKey: string;
4
+ options: {
5
+ value: string;
6
+ label: string;
7
+ triggerKey: string;
8
+ }[];
9
+ selected: string[];
10
+ }
11
+ /** Eventbrite's activity trigger registers several events on one webhook. Keep its
12
+ * event catalog in the app manifest; the editor only adapts the existing trigger keys. */
13
+ export declare function eventbriteTriggerChoices(appId: string, triggers: ActionDef[] | null, triggerKey: string, values: Record<string, unknown>): EventbriteTriggerChoices | null;
@@ -1,5 +1,6 @@
1
1
  import { Edge } from '@xyflow/react';
2
- import { PortsLookup } from './flow-types.ts';
2
+ import { LoopRefusalReason } from './flow-loop.ts';
3
+ import { CanvasLane, PortsLookup } from './flow-types.ts';
3
4
  import { StepNode } from './flow-utils.ts';
4
5
  /**
5
6
  * Which lane a React Flow edge belongs to (core `rfcs/workflow.md` · `Edge.when`
@@ -8,7 +9,7 @@ import { StepNode } from './flow-utils.ts';
8
9
  * `data` at all. The single accessor: every consumer calls this rather than
9
10
  * re-deriving the fallback, so "absent means success" is decided once.
10
11
  */
11
- export declare function edgeLane(e: Edge): "success" | "error";
12
+ export declare function edgeLane(e: Edge): CanvasLane;
12
13
  /**
13
14
  * A refused connection: the source's exit port is full **in this lane** and the cap
14
15
  * is finite. Drawing past a finite `out` cap is refused, never satisfied by evicting
@@ -18,14 +19,22 @@ export type OutCapRefusal = {
18
19
  refused: "out_cap";
19
20
  cap: number;
20
21
  };
22
+ /**
23
+ * A refused connection that would break the v1 linear-body rule of a For each
24
+ * (see {@link loopRefusal}). Raised before the out-cap census and before any
25
+ * inbound eviction, always against the INPUT edges.
26
+ */
27
+ export type LoopRefusal = {
28
+ refused: "loop";
29
+ reason: LoopRefusalReason;
30
+ };
21
31
  /**
22
32
  * The hard rules for an edge `source → target` — the ones no amount of
23
33
  * replacement can satisfy: a real, *distinct* pair (no self-loops), no duplicate
24
34
  * edge, the target accepts an entry port (blocks connecting *into* a trigger,
25
35
  * which declares `in: 0`), and the source has an exit port. Port **capacity** is
26
- * deliberately NOT checked here: a full single-slot port is freed by replacement
27
- * (see `applyConnect`), so dragging a new wire from an already-connected node
28
- * re-points it rather than being rejected. Used as the live `isValidConnection`.
36
+ * deliberately NOT checked here: an input accepts any number of edges, and the exit
37
+ * cap is refused in `applyConnect`. Used as the live `isValidConnection`.
29
38
  *
30
39
  * The duplicate-pair check is **lane-blind by design**, and that is a v1 *editor*
31
40
  * limit, not a model limit: the model permits a success edge and an error edge
@@ -41,13 +50,13 @@ export type OutCapRefusal = {
41
50
  * Letting the drop through and refusing in `applyConnect` is what lets the reason
42
51
  * paint — see {@link connectConflict}.
43
52
  */
44
- export declare function canConnect(source: string | null | undefined, target: string | null | undefined, nodes: StepNode[], edges: Edge[], lookup?: PortsLookup): boolean;
53
+ export declare function canConnect(source: string | null | undefined, target: string | null | undefined, nodes: StepNode[], edges: Edge[], lookup?: PortsLookup, route?: string): boolean;
45
54
  /**
46
55
  * Build the next edge set for a new `source → target` connection. **Additive at the
47
56
  * source**: a source under its `out` cap (or unbounded) keeps every existing edge and
48
57
  * gains one; at a finite cap the connection is **refused** (see {@link connectRefusal}),
49
- * never satisfied by evicting. The target's entry port is still single-slot-replacing:
50
- * the oldest inbound edge(s) are dropped to make room. Returns `null` when the
58
+ * never satisfied by evicting. The target's entry port accepts any number of
59
+ * inbound edges, so nothing is ever evicted there. Returns `null` when the
51
60
  * connection is disallowed by {@link canConnect}, refused at the out cap — **or when the minted id would
52
61
  * duplicate a surviving edge's id**, the same refusal {@link setEdgeWhen} performs
53
62
  * through the same {@link collidingEdgeId} test.
@@ -68,13 +77,10 @@ export declare function canConnect(source: string | null | undefined, target: st
68
77
  * `send → (error) → fallback` shape authorable at all. No `ports.out` bump is
69
78
  * needed, so every persisted definition and palette entry stays valid.
70
79
  *
71
- * The target's entry capacity stays **lane-blind**, and that asymmetry is the
72
- * point: a converging tail step receiving one success and one error edge is
73
- * governed by `ports.in` alone. Partitioning the target rule by lane too — the
74
- * plausible "symmetry" cleanup — would let a `ports.in: 1` node silently accept
75
- * two inbound edges.
80
+ * The target's entry has no capacity: any number of edges, from any number of
81
+ * sources (several triggers may feed one node), converge on it.
76
82
  */
77
- export declare function applyConnect(source: string | null | undefined, target: string | null | undefined, nodes: StepNode[], edges: Edge[], when?: "success" | "error", lookup?: PortsLookup): Edge[] | null;
83
+ export declare function applyConnect(source: string | null | undefined, target: string | null | undefined, nodes: StepNode[], edges: Edge[], when?: CanvasLane, lookup?: PortsLookup, route?: string): Edge[] | null;
78
84
  /**
79
85
  * The id of the existing edge that drawing `source → target` would collide with, or
80
86
  * `null` when the connection is safe (or refused for an ordinary reason — a
@@ -85,13 +91,13 @@ export declare function applyConnect(source: string | null | undefined, target:
85
91
  * selects that edge and renders the message in the edge-lane panel (never a browser
86
92
  * dialog; see `.ai/conventions.md`).
87
93
  */
88
- export declare function connectConflict(source: string | null | undefined, target: string | null | undefined, nodes: StepNode[], edges: Edge[], when?: "success" | "error", lookup?: PortsLookup): string | null;
94
+ export declare function connectConflict(source: string | null | undefined, target: string | null | undefined, nodes: StepNode[], edges: Edge[], when?: CanvasLane, lookup?: PortsLookup, route?: string): string | null;
89
95
  /**
90
96
  * The out-cap refusal for drawing `source → target`, or `null` when the source has
91
97
  * room (or is unbounded). The editor renders `cap` in an inline message on the same
92
98
  * channel as {@link connectConflict}; {@link applyConnect} returns `null` for it.
93
99
  */
94
- export declare function connectRefusal(source: string | null | undefined, target: string | null | undefined, nodes: StepNode[], edges: Edge[], when?: "success" | "error", lookup?: PortsLookup): OutCapRefusal | null;
100
+ export declare function connectRefusal(source: string | null | undefined, target: string | null | undefined, nodes: StepNode[], edges: Edge[], when?: CanvasLane, lookup?: PortsLookup, route?: string): OutCapRefusal | LoopRefusal | null;
95
101
  /**
96
102
  * Re-lane one edge. Updates its `data.when`, its visuals and its id, and frees
97
103
  * nothing: when the destination lane is at a finite out cap the switch is refused
@@ -0,0 +1,16 @@
1
+ import { Edge } from '@xyflow/react';
2
+ import { FlowCanvas } from './canvas-types.ts';
3
+ import { StepNode } from './flow-utils.ts';
4
+ export interface FlowDeleteSelection {
5
+ nodeIds: string[];
6
+ edgeIds: string[];
7
+ }
8
+ /** Capture the full selection, independently of the first item shown in the side panel. */
9
+ export declare function selectedFlowElements(nodes: StepNode[], edges: Edge[]): FlowDeleteSelection;
10
+ /** Apply the entire confirmed selection before the editor emits one change/history entry. */
11
+ export declare function deleteFlowSelection(selection: FlowDeleteSelection, nodes: StepNode[], edges: Edge[], canvas: FlowCanvas): {
12
+ nodes: StepNode[];
13
+ edges: Edge[];
14
+ canvas: FlowCanvas;
15
+ };
16
+ export declare function flowDeleteMessage(selection: FlowDeleteSelection, nodes: StepNode[], edges: Edge[]): string;
@@ -0,0 +1,75 @@
1
+ import { Edge } from '@xyflow/react';
2
+ import { FlowCanvas } from './canvas-types.ts';
3
+ import { FlowStep, FlowWorkflow } from './flow-types.ts';
4
+ import { StepNode } from './flow-utils.ts';
5
+ /** Only authored graph data. Tests, samples, run paint, selection and viewport never enter history. */
6
+ export interface FlowEditSnapshot {
7
+ nodes: FlowStep[];
8
+ edges: NonNullable<FlowWorkflow["edges"]>;
9
+ connections: NonNullable<FlowWorkflow["connections"]>;
10
+ canvas: FlowCanvas;
11
+ /** Keep the live layout even when saving positions is switched off. */
12
+ positions: Record<string, {
13
+ x: number;
14
+ y: number;
15
+ }>;
16
+ }
17
+ export declare function captureFlowEdit(base: FlowWorkflow, nodes: StepNode[], edges: Edge[], connections: FlowEditSnapshot["connections"], canvas: FlowCanvas): FlowEditSnapshot;
18
+ export declare function restoreFlowEdit(base: FlowWorkflow, snapshot: FlowEditSnapshot): {
19
+ nodes: {
20
+ position: {
21
+ x: number;
22
+ y: number;
23
+ };
24
+ id: string;
25
+ data: import('./flow-utils.ts').StepNodeData;
26
+ sourcePosition?: import('@xyflow/react').Position;
27
+ targetPosition?: import('@xyflow/react').Position;
28
+ hidden?: boolean;
29
+ selected?: boolean;
30
+ dragging?: boolean;
31
+ draggable?: boolean;
32
+ selectable?: boolean;
33
+ connectable?: boolean;
34
+ deletable?: boolean;
35
+ dragHandle?: string;
36
+ width?: number;
37
+ height?: number;
38
+ initialWidth?: number;
39
+ initialHeight?: number;
40
+ parentId?: string;
41
+ zIndex?: number;
42
+ extent?: "parent" | import('@xyflow/react').CoordinateExtent | null;
43
+ expandParent?: boolean;
44
+ ariaLabel?: string;
45
+ origin?: import('@xyflow/react').NodeOrigin;
46
+ handles?: import('@xyflow/react').NodeHandle[];
47
+ measured?: {
48
+ width?: number;
49
+ height?: number;
50
+ };
51
+ type?: string | undefined;
52
+ style?: import('react').CSSProperties;
53
+ className?: string;
54
+ resizing?: boolean;
55
+ focusable?: boolean;
56
+ ariaRole?: import('react').AriaRole;
57
+ domAttributes?: Omit<import('react').HTMLAttributes<HTMLDivElement>, "id" | "style" | "className" | "draggable" | "role" | "aria-label" | "defaultValue" | "dangerouslySetInnerHTML" | keyof import('react').DOMAttributes<HTMLDivElement>>;
58
+ }[];
59
+ edges: Edge[];
60
+ };
61
+ /** Bounded, editor-session history. One text-field focus session is one undoable edit. */
62
+ export declare class FlowEditHistory {
63
+ private past;
64
+ private future;
65
+ private present;
66
+ private group;
67
+ private readonly limit;
68
+ constructor(initial: FlowEditSnapshot, limit?: number);
69
+ reset(initial: FlowEditSnapshot): void;
70
+ record(snapshot: FlowEditSnapshot, group?: object): void;
71
+ undo(): FlowEditSnapshot | undefined;
72
+ redo(): FlowEditSnapshot | undefined;
73
+ }
74
+ /** Leave native text undo and CodeMirror's own history alone. */
75
+ export declare function isFlowTextTarget(target: EventTarget | null): boolean;
@@ -0,0 +1,13 @@
1
+ import { Edge } from '@xyflow/react';
2
+ import { FlowCanvas } from './canvas-types.ts';
3
+ import { StepNode } from './flow-utils.ts';
4
+ /**
5
+ * Arrange paths and their section frames together. Membership is authored data:
6
+ * fit each frame to its members, never infer new membership from moved geometry.
7
+ * A section spanning non-members is moved with its members below the obstruction.
8
+ * Notes and empty sections retain their authored geometry.
9
+ */
10
+ export declare function relayoutFlow(nodes: StepNode[], edges: Edge[], canvas: FlowCanvas): {
11
+ nodes: StepNode[];
12
+ canvas: FlowCanvas;
13
+ };
@@ -0,0 +1,39 @@
1
+ import { Edge } from '@xyflow/react';
2
+ import { CSSProperties } from 'react';
3
+ import { StepNode } from './flow-utils.ts';
4
+ /** How many `--w6w-loop-N` tokens `_tokens.scss` defines. */
5
+ export declare const LOOP_TONES = 6;
6
+ /**
7
+ * Tone index (1-based) per For each id. Ids are visited in sorted order so the result
8
+ * does not depend on node order; each takes its hashed tone, or the next free one.
9
+ */
10
+ export declare function assignLoopTones(foreachIds: Iterable<string>): Map<string, number>;
11
+ /** The CSS colour for a tone index. */
12
+ export declare function loopToneVar(tone: number): string;
13
+ /** The loops enclosing `id`, outermost first, following each For each's own `loopOf`. */
14
+ export declare function enclosingLoops(id: string, loopOfById: ReadonlyMap<string, string | undefined>): string[];
15
+ /**
16
+ * Paint each-lane edges with the colour of the loop they belong to: the For each itself
17
+ * for its Each item link, else the loop the edge's source step runs in. Sets the
18
+ * `--w6w-loop-color` custom property the `.w6w-edge-each` rule reads, so run-state
19
+ * classes still compose over it. Same array when nothing needs painting.
20
+ */
21
+ export declare function paintLoopEdges(edges: Edge[], tones: ReadonlyMap<string, number>, loopOfById: ReadonlyMap<string, string | undefined>): Edge[];
22
+ /**
23
+ * The colour custom property a card's root carries: a For each's own tone, read by its
24
+ * Each item port. A loop-body step gets none — it looks exactly like a step outside a
25
+ * loop; its dots are what mark it.
26
+ */
27
+ export declare function loopCardStyle(id: string, tones: ReadonlyMap<string, number>): CSSProperties | undefined;
28
+ /** What the canvas paints loops from: each For each's tone, and each step's own loop. */
29
+ export type LoopPaint = {
30
+ tones: ReadonlyMap<string, number>;
31
+ loopOf: ReadonlyMap<string, string | undefined>;
32
+ };
33
+ /**
34
+ * A string that changes only when a loop's membership does — the memo key for
35
+ * {@link loopPaint}, so dragging a node does not hand every card a new context value.
36
+ */
37
+ export declare function loopPaintKey(nodes: readonly StepNode[]): string;
38
+ /** Rebuild the {@link LoopPaint} a {@link loopPaintKey} describes. */
39
+ export declare function loopPaint(key: string): LoopPaint;