@w6w/embed 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (148) hide show
  1. package/README.md +231 -4
  2. package/dist/ConfirmModal-RLbZT5_k.js +181 -0
  3. package/dist/ConfirmModal-RLbZT5_k.js.map +1 -0
  4. package/dist/CreateFunctionModal-DRsFx-FB.js +221 -0
  5. package/dist/CreateFunctionModal-DRsFx-FB.js.map +1 -0
  6. package/dist/DocumentFormModal-BExK1V-B.js +89 -0
  7. package/dist/DocumentFormModal-BExK1V-B.js.map +1 -0
  8. package/dist/ImportSpecModal-BDQIf6rg.js +136 -0
  9. package/dist/ImportSpecModal-BDQIf6rg.js.map +1 -0
  10. package/dist/W6WEmbedProvider.d.ts +22 -4
  11. package/dist/WorkflowEditor-DlbVv6Fs.js +854 -0
  12. package/dist/WorkflowEditor-DlbVv6Fs.js.map +1 -0
  13. package/dist/api-calls--JHyif6a.js +107 -0
  14. package/dist/api-calls--JHyif6a.js.map +1 -0
  15. package/dist/apps-1FNUwbGv.js +77 -0
  16. package/dist/apps-1FNUwbGv.js.map +1 -0
  17. package/dist/callables-3mFrMVG_.js +151 -0
  18. package/dist/callables-3mFrMVG_.js.map +1 -0
  19. package/dist/chrome/index.d.ts +6 -0
  20. package/dist/chrome/workspace.d.ts +29 -1
  21. package/dist/coerce-input-BicYr7nc.js +139 -0
  22. package/dist/coerce-input-BicYr7nc.js.map +1 -0
  23. package/dist/connections-CjjYeRqb.js +78 -0
  24. package/dist/connections-CjjYeRqb.js.map +1 -0
  25. package/dist/document-sources-C0grrtdq.js +86 -0
  26. package/dist/document-sources-C0grrtdq.js.map +1 -0
  27. package/dist/draft/index.d.ts +3 -1
  28. package/dist/draft/use-callable-draft.d.ts +65 -0
  29. package/dist/draft/workflow-save.d.ts +3 -0
  30. package/dist/draft.mjs +9 -5
  31. package/dist/draft.mjs.map +1 -1
  32. package/dist/editor/CallableEditorFrame.d.ts +33 -0
  33. package/dist/editor/EditorShell.d.ts +16 -0
  34. package/dist/editor/EndpointCards.d.ts +56 -0
  35. package/dist/editor/EndpointEditor.d.ts +26 -0
  36. package/dist/editor/FunctionEditor.d.ts +21 -0
  37. package/dist/editor/InputListEditor.d.ts +29 -0
  38. package/dist/editor/TargetSelector.d.ts +30 -0
  39. package/dist/editor/TargetSelector.types.d.ts +62 -0
  40. package/dist/editor/editor-apps.d.ts +8 -2
  41. package/dist/editor/types.d.ts +57 -0
  42. package/dist/editor-apps-BdenSV1o.js +95 -0
  43. package/dist/editor-apps-BdenSV1o.js.map +1 -0
  44. package/dist/editor-tools-RxmY5iyi.js +1279 -0
  45. package/dist/editor-tools-RxmY5iyi.js.map +1 -0
  46. package/dist/editor.mjs +2 -2166
  47. package/dist/editor.mjs.map +1 -1
  48. package/dist/editors/DocumentEditor.d.ts +20 -0
  49. package/dist/editors/doc-format.d.ts +3 -0
  50. package/dist/editors.d.ts +12 -0
  51. package/dist/editors.mjs +1313 -0
  52. package/dist/editors.mjs.map +1 -0
  53. package/dist/embed-status.d.ts +20 -0
  54. package/dist/endpoints-B2ynbZo-.js +227 -0
  55. package/dist/endpoints-B2ynbZo-.js.map +1 -0
  56. package/dist/forms/CreateEndpointModal.d.ts +54 -0
  57. package/dist/forms/CreateFunctionModal.d.ts +55 -0
  58. package/dist/forms/DocumentFormModal.d.ts +8 -0
  59. package/dist/forms/SecretsManager.d.ts +12 -0
  60. package/dist/forms/VarsManager.d.ts +29 -0
  61. package/dist/forms.d.ts +6 -0
  62. package/dist/forms.mjs +407 -0
  63. package/dist/forms.mjs.map +1 -0
  64. package/dist/index.d.ts +3 -1
  65. package/dist/index.mjs +153 -50
  66. package/dist/index.mjs.map +1 -1
  67. package/dist/lib/callable-record.d.ts +21 -0
  68. package/dist/lib/coerce-input.d.ts +6 -0
  69. package/dist/lib/endpoint-editor.d.ts +23 -0
  70. package/dist/lib/index.d.ts +7 -0
  71. package/dist/lib/input-coverage.d.ts +28 -0
  72. package/dist/lib/input-seeding.d.ts +67 -0
  73. package/dist/lib/rail-settings.d.ts +3 -3
  74. package/dist/lib/recent-activity.d.ts +128 -0
  75. package/dist/lib/target-fields.d.ts +168 -0
  76. package/dist/lib/workflow-blank.d.ts +2 -0
  77. package/dist/lib.mjs +70 -48
  78. package/dist/lib.mjs.map +1 -1
  79. package/dist/lists/ActivitySummary.d.ts +29 -0
  80. package/dist/lists/CallableKindList.d.ts +34 -0
  81. package/dist/lists/ConnectionDetail.d.ts +17 -0
  82. package/dist/lists/ConnectionList.d.ts +16 -0
  83. package/dist/lists/DocumentList.d.ts +29 -0
  84. package/dist/lists/EndpointList.d.ts +19 -0
  85. package/dist/lists/FunctionList.d.ts +18 -0
  86. package/dist/lists/ReliabilityBoard.d.ts +23 -0
  87. package/dist/lists/RunHistory.d.ts +11 -0
  88. package/dist/lists/ServiceDetail.d.ts +20 -0
  89. package/dist/lists/WorkflowList.d.ts +19 -0
  90. package/dist/lists/vendor-history.d.ts +40 -0
  91. package/dist/lists.d.ts +20 -0
  92. package/dist/lists.mjs +1185 -0
  93. package/dist/lists.mjs.map +1 -0
  94. package/dist/project-context-BiCjv_E3.js +25 -0
  95. package/dist/project-context-BiCjv_E3.js.map +1 -0
  96. package/dist/project-context.d.ts +15 -1
  97. package/dist/rail/CallableRail.d.ts +12 -0
  98. package/dist/rail/CallableWorkspace.d.ts +16 -0
  99. package/dist/rail/SettingsTool.d.ts +7 -1
  100. package/dist/rail/settings-sections.d.ts +2 -2
  101. package/dist/rail-settings-XYGToh00.js +111 -0
  102. package/dist/rail-settings-XYGToh00.js.map +1 -0
  103. package/dist/rail.d.ts +11 -0
  104. package/dist/rail.mjs +35 -0
  105. package/dist/rail.mjs.map +1 -0
  106. package/dist/repos/api-calls.d.ts +4 -0
  107. package/dist/repos/apps.d.ts +14 -0
  108. package/dist/repos/callables.d.ts +91 -0
  109. package/dist/repos/connections.d.ts +33 -0
  110. package/dist/repos/dashboard.d.ts +4 -0
  111. package/dist/repos/endpoints.d.ts +125 -0
  112. package/dist/repos/functions.d.ts +79 -0
  113. package/dist/repos/index.d.ts +10 -0
  114. package/dist/repos/reliability.d.ts +42 -0
  115. package/dist/repos/saved-tests.d.ts +46 -0
  116. package/dist/repos/spec-export.d.ts +23 -0
  117. package/dist/repos/workflows.d.ts +138 -0
  118. package/dist/repos.mjs +174 -88
  119. package/dist/repos.mjs.map +1 -1
  120. package/dist/settings-rail--GdRMusb.js +33 -0
  121. package/dist/settings-rail--GdRMusb.js.map +1 -0
  122. package/dist/slug-C4ktDPdy.js +315 -0
  123. package/dist/slug-C4ktDPdy.js.map +1 -0
  124. package/dist/spec-export-Cf3VQSQS.js +176 -0
  125. package/dist/spec-export-Cf3VQSQS.js.map +1 -0
  126. package/dist/spec-import-CjmxyZDR.js +465 -0
  127. package/dist/spec-import-CjmxyZDR.js.map +1 -0
  128. package/dist/step-tests-CivICmTq.js +18 -0
  129. package/dist/step-tests-CivICmTq.js.map +1 -0
  130. package/dist/trigger-preview-VPkrryDl.js +120 -0
  131. package/dist/trigger-preview-VPkrryDl.js.map +1 -0
  132. package/dist/use-callable-draft-zHLpcr-b.js +271 -0
  133. package/dist/use-callable-draft-zHLpcr-b.js.map +1 -0
  134. package/dist/{use-workflow-draft-oI02dsP-.js → use-workflow-draft-DzAyUeA6.js} +48 -46
  135. package/dist/use-workflow-draft-DzAyUeA6.js.map +1 -0
  136. package/dist/vault-BSEWhMYC.js +117 -0
  137. package/dist/vault-BSEWhMYC.js.map +1 -0
  138. package/dist/workflow-blank-DyL3_RUA.js +14 -0
  139. package/dist/workflow-blank-DyL3_RUA.js.map +1 -0
  140. package/package.json +21 -5
  141. package/src/styles.css +408 -1
  142. package/dist/project-context-Dbk0Gr1K.js +0 -16
  143. package/dist/project-context-Dbk0Gr1K.js.map +0 -1
  144. package/dist/slug-ByKQgxrf.js +0 -642
  145. package/dist/slug-ByKQgxrf.js.map +0 -1
  146. package/dist/spec-import-HgO7ZkLZ.js +0 -898
  147. package/dist/spec-import-HgO7ZkLZ.js.map +0 -1
  148. package/dist/use-workflow-draft-oI02dsP-.js.map +0 -1
@@ -0,0 +1,315 @@
1
+ const N = ["conn_", "fn_", "wf_", "ep_"];
2
+ function d(n) {
3
+ return N.some((t) => n.startsWith(t));
4
+ }
5
+ function m(n) {
6
+ var e;
7
+ const t = (e = n.key) == null ? void 0 : e.trim();
8
+ return t && t.length > 0 ? t : n.id;
9
+ }
10
+ function l(n) {
11
+ return `'${n.replaceAll("'", "'\\''")}'`;
12
+ }
13
+ const v = 72;
14
+ function p(n, ...t) {
15
+ const e = [n, ...t].filter((o) => o.length > 0), i = e.join(" ");
16
+ return t.length === 0 || i.length <= v ? i : e.join(` \\
17
+ `);
18
+ }
19
+ function $(n) {
20
+ return !n || n.length === 0 ? [] : n.map(
21
+ (t) => typeof t == "string" ? { key: t, required: !0 } : {
22
+ key: t.key,
23
+ // Only an explicit `true` is required — an undeclared flag means the
24
+ // Function did not mark it, which is exactly what optional means.
25
+ required: t.required === !0
26
+ }
27
+ ).filter((t) => typeof t.key == "string" && t.key.trim() !== "");
28
+ }
29
+ function h(n, t = !1) {
30
+ const e = $(n), i = t ? e.filter((o) => o.required) : e;
31
+ return Object.fromEntries(i.map((o) => [o.key, `<${o.key}>`]));
32
+ }
33
+ function y(n, t) {
34
+ const e = $(n);
35
+ return e.length === 0 ? "{}" : t.compact && e.every((o) => o.required) ? JSON.stringify(Object.fromEntries(e.map((o) => [o.key, `<${o.key}>`]))) : `{
36
+ ${e.map(({ key: o, required: a }) => {
37
+ const r = `${JSON.stringify(o)}: ${JSON.stringify(`<${o}>`)},`;
38
+ return a ? `${t.indent} ${r}` : `${t.indent} ${t.comment} ${r}`;
39
+ }).join(`
40
+ `)}
41
+ ${t.indent}}`;
42
+ }
43
+ function w(n) {
44
+ return $(n).filter((t) => !t.required).map((t) => `
45
+ # optional: ${t.key}`).join("");
46
+ }
47
+ function S(n) {
48
+ return n ? n.filter((t) => typeof t.key == "string" && t.key.trim() !== "") : [];
49
+ }
50
+ function k(n, t) {
51
+ return n === "number" ? 0 : n === "boolean" ? !1 : n === "json" ? {} : `<${t}>`;
52
+ }
53
+ function g(n, t, e) {
54
+ const i = k(n, t);
55
+ return typeof i == "boolean" ? e ? "False" : "false" : JSON.stringify(i);
56
+ }
57
+ function b(n) {
58
+ return n.length === 0 ? "" : `
59
+ input: {
60
+ ${n.map((e) => {
61
+ const i = `${JSON.stringify(e.key)}: ${g(e.type, e.key, !1)},`;
62
+ return e.required === !0 ? ` ${i}` : ` // ${i}`;
63
+ }).join(`
64
+ `)}
65
+ },`;
66
+ }
67
+ function _(n, t) {
68
+ const e = JSON.stringify(n);
69
+ if (t.length === 0) return `client.workflows.run(${e}, wait=True)`;
70
+ const i = t.map((o) => {
71
+ const a = `"${o.key}": ${g(o.type, o.key, !0)},`;
72
+ return o.required === !0 ? ` ${a}` : ` # ${a}`;
73
+ });
74
+ return `client.workflows.run(
75
+ ${e},
76
+ wait=True,
77
+ input={
78
+ ${i.join(`
79
+ `)}
80
+ },
81
+ )`;
82
+ }
83
+ function T(n, t) {
84
+ if (t.length === 0) return p(`w6w workflows run ${n}`, "--wait");
85
+ const e = t.filter((r) => r.required === !0), i = t.filter((r) => r.required !== !0), o = Object.fromEntries(
86
+ e.map((r) => [r.key, k(r.type, r.key)])
87
+ );
88
+ let a = p(
89
+ `w6w workflows run ${n}`,
90
+ "--wait",
91
+ `--input ${l(JSON.stringify(o))}`
92
+ );
93
+ for (const r of i)
94
+ a += `
95
+ # optional: ${r.key} (${r.type ?? "string"})`;
96
+ return a;
97
+ }
98
+ function u(...n) {
99
+ return `import { ${["W6WClient", ...n].join(", ")} } from "@w6w/sdk";
100
+
101
+ // Reads W6W_BASE_URL and W6W_TOKEN from the environment when omitted.
102
+ const client = new W6WClient();`;
103
+ }
104
+ function c(...n) {
105
+ return `from w6w import ${["Client", ...n].join(", ")}
106
+
107
+ # Reads W6W_BASE_URL and W6W_TOKEN from the environment when omitted.
108
+ client = Client()`;
109
+ }
110
+ function f(n, t) {
111
+ return `curl -X POST ${n} \\
112
+ -H "authorization: Bearer $W6W_TOKEN" \\
113
+ -H 'content-type: application/json' \\
114
+ -d ${l(JSON.stringify(t))}`;
115
+ }
116
+ function J(n, t) {
117
+ return f(l(n), t ?? {});
118
+ }
119
+ function E(n, t, e, i) {
120
+ const o = `"$W6W_BASE_URL/${n}/${encodeURIComponent(t)}/invoke"`;
121
+ return f(o, { [e]: i });
122
+ }
123
+ function W(n, t) {
124
+ const e = `"$W6W_BASE_URL/workflows/${n}/run?wait=true"`;
125
+ if (t.length === 0) return f(e, {});
126
+ const i = t.filter((s) => s.required === !0), o = t.filter((s) => s.required !== !0), a = Object.fromEntries(
127
+ i.map((s) => [s.key, k(s.type, s.key)])
128
+ );
129
+ let r = f(e, { input: a });
130
+ for (const s of o)
131
+ r += `
132
+ # optional: ${s.key} (${s.type ?? "string"})`;
133
+ return r;
134
+ }
135
+ function U(n, t) {
136
+ switch (n.kind) {
137
+ case "workflow": {
138
+ if (!d(n.id)) return null;
139
+ const e = m(n), i = S(t);
140
+ return {
141
+ operation: "workflows.run — POST /workflows/{idOrKey}/run",
142
+ node: `${u()}
143
+
144
+ // \`wait: true\` blocks until the run reaches a terminal state.
145
+ // Omit it and you get \`{ runId, status: "queued" }\` back immediately.
146
+ const result = await client.workflows.run(${JSON.stringify(e)}, {
147
+ wait: true,${b(i)}
148
+ });
149
+
150
+ console.log(result.status, result.runId);`,
151
+ cli: T(e, i),
152
+ python: `${c()}
153
+
154
+ # \`wait=True\` blocks until the run reaches a terminal state.
155
+ # Omit it and you get \`WorkflowRunResult(status="queued", ...)\` back immediately.
156
+ result = ${_(e, i)}
157
+
158
+ print(result.status, result.runId)`,
159
+ curl: W(e, i)
160
+ };
161
+ }
162
+ case "function": {
163
+ if (!d(n.id)) return null;
164
+ const e = m(n), i = h(n.inputs, !0), o = JSON.stringify(i), a = w(n.inputs), r = y(n.inputs, { indent: " ", comment: "//" }), s = y(n.inputs, {
165
+ indent: "",
166
+ comment: "#",
167
+ compact: !0
168
+ });
169
+ return {
170
+ operation: "functions.run — POST /functions/{idOrKey}/invoke",
171
+ node: `${u()}
172
+
173
+ // The name is the first argument, and it may be the Function's key or its
174
+ // \`fn_…\` id — one slot takes either. Returns the OUTPUT directly: the kind is
175
+ // settled by the method, so there is no envelope to narrow.
176
+ const output = await client.functions.run(${JSON.stringify(e)}, {
177
+ payload: ${r},
178
+ });
179
+
180
+ console.log(output);`,
181
+ cli: p(`w6w functions run ${e}`, `--payload ${l(o)}`) + a,
182
+ python: `${c()}
183
+
184
+ # The name is the first argument — the Function's key or its \`fn_…\` id.
185
+ output = client.functions.run(${JSON.stringify(e)}, payload=${s})
186
+
187
+ print(output)`,
188
+ curl: E("functions", e, "inputs", i) + a
189
+ };
190
+ }
191
+ case "endpoint": {
192
+ if (!d(n.id)) return null;
193
+ const e = n.urlForm === "key" && n.invokeUrlByKey ? n.invokeUrlByKey : n.invokeUrl, i = m(n), o = h(n.inputs, !0), a = JSON.stringify(o), r = w(n.inputs), s = y(n.inputs, { indent: " ", comment: "//" }), O = y(n.inputs, {
194
+ indent: "",
195
+ comment: "#",
196
+ compact: !0
197
+ });
198
+ return {
199
+ operation: "endpoints.run — POST /endpoints/{idOrKey}/invoke",
200
+ node: `${u()}
201
+
202
+ // The name is the first argument — the Endpoint's key or its \`ep_…\` id. Unlike
203
+ // \`functions.run\` this returns the ENVELOPE: an Endpoint dispatches to an app
204
+ // action, a Function or a Workflow, and only \`kind\` says which answered.
205
+ const envelope = await client.endpoints.run(${JSON.stringify(i)}, {
206
+ payload: ${s},
207
+ });
208
+
209
+ console.log(envelope.kind, envelope);`,
210
+ cli: p(`w6w endpoints run ${i}`, `--payload ${l(a)}`) + r,
211
+ python: `${c()}
212
+
213
+ # The name is the first argument — the Endpoint's key or its \`ep_…\` id.
214
+ envelope = client.endpoints.run(${JSON.stringify(i)}, payload=${O})
215
+
216
+ print(envelope["kind"], envelope)`,
217
+ ...typeof e == "string" && e !== "" ? { curl: J(e, o) + r } : {}
218
+ };
219
+ }
220
+ case "connection": {
221
+ if (!d(n.id)) return null;
222
+ const e = h(n.params);
223
+ return {
224
+ operation: "run — POST /run",
225
+ node: `${u("isActionRun")}
226
+
227
+ // An app action runs through the CONNECTION that authenticates it, so the URN
228
+ // is the connection id and \`action\` names the action on its app. This is the
229
+ // one arm where \`action\` is required — a workflow, function or endpoint URN
230
+ // has no action to name.
231
+ const envelope = await client.run({
232
+ urn: ${JSON.stringify(n.id)},
233
+ action: ${JSON.stringify(n.action)},
234
+ payload: ${JSON.stringify(e, null, 2).replaceAll(`
235
+ `, `
236
+ `)},
237
+ });
238
+
239
+ if (isActionRun(envelope)) console.log(envelope.value);`,
240
+ cli: p(
241
+ `w6w run ${n.id}`,
242
+ `--action ${n.action}`,
243
+ `--payload ${l(JSON.stringify(e))}`
244
+ ),
245
+ python: `${c("is_action_run")}
246
+
247
+ # An app action runs through the CONNECTION that authenticates it, so the URN
248
+ # is the connection id and \`action\` names the action on its app. This is the
249
+ # one arm where \`action\` is required — a workflow, function or endpoint URN
250
+ # has no action to name.
251
+ envelope = client.run(
252
+ ${JSON.stringify(n.id)},
253
+ action=${JSON.stringify(n.action)},
254
+ payload=${JSON.stringify(e)},
255
+ )
256
+
257
+ if is_action_run(envelope):
258
+ print(envelope["value"])`
259
+ };
260
+ }
261
+ case "var":
262
+ return {
263
+ operation: "vars.getByName — GET /vars/by-name/{name}",
264
+ node: `${u()}
265
+
266
+ const variable = await client.vars.getByName(${JSON.stringify(n.name)});
267
+ console.log(variable.value);`,
268
+ cli: `w6w vars get-by-name ${n.name}`,
269
+ python: `${c()}
270
+
271
+ variable = client.vars.get_by_name(${JSON.stringify(n.name)})
272
+ print(variable.value)`
273
+ };
274
+ case "document":
275
+ return {
276
+ operation: "documents.getByKey — GET /documents/by-key/{key}",
277
+ node: `${u()}
278
+
279
+ const doc = await client.documents.getByKey(${JSON.stringify(n.key)});
280
+ console.log(doc.content);`,
281
+ cli: `w6w documents get-by-key ${l(n.key)}`,
282
+ python: `${c()}
283
+
284
+ doc = client.documents.get_by_key(${JSON.stringify(n.key)})
285
+ print(doc.content)`
286
+ };
287
+ }
288
+ }
289
+ function C(n) {
290
+ return (n.kind === "function" || n.kind === "endpoint" || n.kind === "workflow") && !d(n.id) ? `This ${n.kind}'s id (${n.id}) has no \`${n.kind === "workflow" ? "wf_" : n.kind === "function" ? "fn_" : "ep_"}\` prefix, so it cannot be addressed by URN. The SDK and CLI reach ${n.kind}s through \`run\`, which resolves a URN by that prefix — re-create it with a host-issued id to call it from code.` : "The client libraries do not expose an operation for this yet.";
291
+ }
292
+ function q(n) {
293
+ return n.toLowerCase().trim().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
294
+ }
295
+ const R = /^[a-z][a-z0-9-]{2,}$/;
296
+ function A(n) {
297
+ return R.test(n);
298
+ }
299
+ function B(n) {
300
+ return /^[a-z][a-z0-9-]{2,38}$/.test(n) && !n.includes("--") && !n.endsWith("-");
301
+ }
302
+ function P(n) {
303
+ return n.toLowerCase().replace(/[^a-z0-9-]/g, "").slice(0, 39);
304
+ }
305
+ export {
306
+ R as A,
307
+ d as a,
308
+ U as b,
309
+ A as c,
310
+ P as f,
311
+ B as i,
312
+ q as s,
313
+ C as u
314
+ };
315
+ //# sourceMappingURL=slug-C4ktDPdy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slug-C4ktDPdy.js","sources":["../src/lib/sdk-snippets.ts","../src/lib/slug.ts"],"sourcesContent":["/**\n * Node/CLI call snippets for a studio resource — \"how do I do this from code?\"\n *\n * Pure string builders over the wrapper contract at `packages/wrappers`\n * (`endpoints.json` + `docs/endpoints.md`). Nothing here fetches, and nothing\n * here invents an operation: every snippet emitted maps to an operation the\n * contract lists as `status: required, serverImplemented: true`, using the exact\n * symbol its `naming.ts` / `naming.cli` field pins. If an operation is not in\n * the contract there is no snippet for it — a copyable example of a method that\n * does not exist is worse than no example.\n *\n * The surface at contract v0.3.0, and what each studio page can therefore show:\n *\n * | Resource | Node | CLI | Python | curl |\n * |-----------|-------------------------------------|------------------------------|--------|------|\n * | Workflow | `client.workflows.run(id, opts?)` | `w6w workflows run <id>` | `client.workflows.run(id, ...)` | `curl … /workflows/{id}/run?wait=true` |\n * | Function | `client.functions.run(name, {payload})` | `w6w functions run <name>` | `client.functions.run(name, payload=...)` | `curl … /functions/{name}/invoke` |\n * | Endpoint | `client.endpoints.run(name, {payload})` | `w6w endpoints run <name>` | `client.endpoints.run(name, payload=...)` | `curl … <server-rendered URL>` |\n * | Connection | `client.run({urn, action, payload})` | `w6w run <urn> --action` | `client.run(urn, action=..., payload=...)` | — |\n * | Var | `client.vars.getByName(name)` | `w6w vars get-by-name <n>` | `client.vars.get_by_name(name)` | — |\n * | Document | `client.documents.getByKey(key)` | `w6w documents get-by-key` | `client.documents.get_by_key(key)` | — |\n *\n * There is a fourth, contract-free arm: a raw-HTTP (`curl`) snippet, for the\n * three kinds a caller reaches through a fixed route — Function and Workflow\n * against the `$W6W_BASE_URL` env placeholder (the same one the node/cli/python\n * arms already tell the reader to export), and Endpoint against the URL the\n * SERVER rendered, handed in on the resource. It maps to no wrapper operation\n * on purpose — the three wrapper arms reach a Function or Endpoint through\n * `run`, which takes a URN and not a URL, so raw HTTP is the only place a\n * literal route (or, for an Endpoint, the id-form / key-form URL toggle) can\n * even be shown. An Endpoint's URL is used VERBATIM: nothing here concatenates\n * a host, a path or a slug onto it. Connection, Var and Document have no\n * fixed single-resource route to curl against, so they carry no `curl` arm.\n *\n * **Functions and Endpoints have their own namespaces** as of `@w6w/sdk` 0.6.0\n * (contract 0.3.0): `functions.run(name, {payload})` and\n * `endpoints.run(name, {payload})`, with the NAME FIRST and the same slot\n * accepting either the resource's key or its `fn_…`/`ep_…` id — the two shapes\n * cannot collide, so nothing is tagged. This module used to emit\n * `client.run({urn: \"fn:send-email\"})`, a kind smuggled into a string because\n * the field was one string; that form is gone.\n *\n * **One form per kind, always.** An earlier version rendered\n * `client.run({urn: alias})` for a resource that carried an alias, which put\n * two different call styles side by side for two Functions. `key` is required\n * on every Function and Endpoint server-side, so the namespace call always\n * works and the alias form was never the only way in. An alias is a SECOND\n * address with its own rail (`alias-rail.ts`); it is not advertised here,\n * because the answer to \"how do I call this Function?\" should not change shape\n * depending on whether someone aliased it. See {@link addressName}.\n *\n * `isUrnAddressable` still gates every arm: an id without its kind prefix is\n * not addressable by `run`, so the snippet is withheld rather than emitting a\n * call that cannot work.\n */\n\nimport type { TriggerPreviewFieldDef } from \"./trigger-preview.ts\";\n\n/**\n * One declared input of a Function or Endpoint, as a snippet needs it.\n *\n * A BARE STRING is treated as REQUIRED. That is the shape this file took before\n * it knew about optionality, when every input rendered active — so a caller that\n * only has keys keeps its existing output rather than silently having every\n * field commented out.\n */\nexport type SnippetInput = string | { key: string; required?: boolean };\n\n/** Normalized, so the renderers below never branch on the union. */\ninterface ResolvedInput {\n key: string;\n required: boolean;\n}\n\n/** What the caller is looking at. Mirrors the four runnable URN arms plus assets. */\nexport type SnippetCallable =\n | { kind: \"workflow\"; id: string; displayName?: string; key?: string; alias?: string }\n | { kind: \"function\"; id: string; key?: string; inputs?: readonly SnippetInput[]; alias?: string }\n /**\n * An Endpoint. `invokeUrl` / `invokeUrlByKey` are the two SERVER-rendered\n * forms of its public address, passed straight through from the endpoints\n * envelope; `urlForm` is which of them the page currently has selected, so a\n * raw-HTTP sample follows the toggle the reader can see. All three are\n * optional — an Endpoint with no URL in hand simply gets no HTTP snippet.\n * `inputs` are the target's input parameter keys, resolved from the Function\n * or Workflow the Endpoint dispatches to.\n */\n | {\n kind: \"endpoint\";\n id: string;\n key?: string;\n invokeUrl?: string;\n invokeUrlByKey?: string;\n urlForm?: \"id\" | \"key\";\n alias?: string;\n inputs?: readonly SnippetInput[];\n }\n /** One app action, invoked through a connection — the `conn_` URN arm. */\n | { kind: \"connection\"; id: string; action: string; params?: string[] }\n | { kind: \"var\"; name: string }\n | { kind: \"document\"; key: string };\n\nexport interface Snippet {\n /** Runnable TypeScript against `@w6w/sdk`. */\n node: string;\n /** A single `w6w …` invocation. */\n cli: string;\n /** Runnable Python against `w6w` (PyPI). */\n python: string;\n /**\n * A raw-HTTP (`curl`) call against the resource's own public URL — OPTIONAL,\n * and emitted only where such a URL exists and was handed in (today: an\n * Endpoint). Optional rather than required so the other five `case` arms of\n * {@link buildSnippet} are untouched, and so the tab strip can render only\n * the tabs a built snippet actually carries.\n */\n curl?: string;\n /** The contract operation this maps to, shown so the snippet is checkable. */\n operation: string;\n}\n\n/**\n * The URN prefixes `POST /run` resolves. Kept as data rather than inlined so\n * the gate below and the docs above cannot drift apart.\n */\nconst RUNNABLE_PREFIXES = [\"conn_\", \"fn_\", \"wf_\", \"ep_\"] as const;\n\n/**\n * Can this id be passed to `client.run({urn})` at all?\n *\n * Ids are host-issued and carry a kind prefix (rfcs/function.md §id — \"host-issued\n * opaque id (`fn_…`)\"), but the create routes do not *enforce* it, so a\n * hand-authored id can reach the database without one. Such a resource is\n * reachable through the studio and through its own `/invoke` route, but NOT\n * through the URN operation the wrappers expose — and a snippet is a promise\n * that the code in it runs.\n */\nexport function isUrnAddressable(id: string): boolean {\n return RUNNABLE_PREFIXES.some((p) => id.startsWith(p));\n}\n\n/**\n * The three kinds `POST /run` addresses by URN and that can carry an alias.\n */\ntype AddressableCallable = Extract<SnippetCallable, { kind: \"workflow\" | \"function\" | \"endpoint\" }>;\n\n/**\n * The name a snippet addresses a resource by: its own `key`, falling back to\n * the opaque id when it somehow has none.\n *\n * ONE FORM, ALWAYS — `functions.run(name)` / `endpoints.run(name)`. An earlier\n * version branched to `client.run({urn: alias})` when the resource carried an\n * alias, which rendered two different call styles for two Functions side by\n * side. That inconsistency bought nothing: `key` is REQUIRED on every Function\n * and Endpoint server-side (`admin/functions.ts`: \"`key` is required\"), so the\n * namespace call always works and the alias form was never the only way in.\n *\n * An alias is a SECOND address, not a substitute for the first, and it has its\n * own rail (`alias-rail.ts`) on the page where it belongs. It is deliberately\n * not advertised here: this snippet answers \"how do I call this Function?\",\n * and the answer should not change shape depending on whether someone happened\n * to alias it.\n *\n * `key` is optional on the type rather than on the wire — a row that predates\n * the requirement can still reach the studio — so the id fallback stays.\n */\nfunction addressName(resource: AddressableCallable): string {\n const key = (resource as { key?: string }).key?.trim();\n return key && key.length > 0 ? key : resource.id;\n}\n\n/** Single-quoted shell literal — `'` closed, escaped, reopened. */\nfunction shellQuote(value: string): string {\n return `'${value.replaceAll(\"'\", `'\\\\''`)}'`;\n}\n\n/**\n * Past this many characters a one-line command is harder to read than a\n * continued one. Chosen so the common `w6w run <urn> --action <a>` stays on one\n * line and only a real payload pushes it over.\n */\nconst CLI_WRAP_AT = 72;\n\n/**\n * Assemble a CLI command, breaking it across lines with `\\` when it is long.\n *\n * A single-line `w6w run conn_… --action … --payload '{\"a\":\"<a>\",\"b\":\"<b>\"}'`\n * runs off the edge of the panel, so the reader scrolls sideways to find out\n * what the flags even are. Continued, each flag is its own line and the shape\n * of the call is visible at a glance:\n *\n * w6w run conn_c19f4db6 \\\n * --action message-post \\\n * --payload '{\"channel\":\"<channel>\"}'\n *\n * `\\`-newline is the POSIX continuation, so the wrapped form pastes into\n * bash/zsh **and copies as one command** — the text is identical to what the\n * shell sees. (It is not `cmd.exe` syntax; the snippets already assume a POSIX\n * shell for their single-quoting.)\n *\n * Short commands are left alone: breaking `w6w vars get-by-name x` across two\n * lines makes it less readable, not more.\n *\n * @param head the command and its positional argument(s), never split\n * @param flags one `--flag value` (or bare `--flag`) per entry\n */\nfunction cliCommand(head: string, ...flags: string[]): string {\n const parts = [head, ...flags].filter((p) => p.length > 0);\n const oneLine = parts.join(\" \");\n if (flags.length === 0 || oneLine.length <= CLI_WRAP_AT) return oneLine;\n return parts.join(\" \\\\\\n \");\n}\n\n/** Normalize the caller's input list. A bare key is required — see {@link SnippetInput}. */\nfunction resolveInputs(inputs: readonly SnippetInput[] | undefined): ResolvedInput[] {\n if (!inputs || inputs.length === 0) return [];\n return inputs\n .map((i) =>\n typeof i === \"string\"\n ? { key: i, required: true }\n : {\n key: i.key,\n // Only an explicit `true` is required — an undeclared flag means the\n // Function did not mark it, which is exactly what optional means.\n required: i.required === true,\n },\n )\n .filter((i) => typeof i.key === \"string\" && i.key.trim() !== \"\");\n}\n\n/**\n * A sample payload for a Function's declared inputs, so the snippet shows the\n * shape rather than an empty object the reader has to go and look up.\n * Values are placeholders — this is an example, not a saved request.\n *\n * `requiredOnly` is for the comment-less lanes (JSON has no comments), which\n * carry the required fields and name the optional ones in trailing shell\n * comments instead — the same D-4 split the workflow arm already makes.\n */\nfunction samplePayload(\n inputs: readonly SnippetInput[] | undefined,\n requiredOnly = false,\n): Record<string, string> {\n const resolved = resolveInputs(inputs);\n const used = requiredOnly ? resolved.filter((i) => i.required) : resolved;\n return Object.fromEntries(used.map((i) => [i.key, `<${i.key}>`]));\n}\n\n/**\n * The payload object rendered as SOURCE, with optional inputs commented out —\n * the same active/commented rule {@link nodeInputBlock} applies to a trigger's\n * fields, so both halves of this file read alike.\n *\n * EVERY line ends with a comma, active or commented. A JS object literal\n * tolerates the trailing one, and without it uncommenting the last optional\n * field would leave the line above it without a separator — a paste that no\n * longer parses, produced by doing exactly what the comment invites.\n */\nfunction payloadSource(\n inputs: readonly SnippetInput[] | undefined,\n opts: { indent: string; comment: string; compact?: boolean },\n): string {\n const resolved = resolveInputs(inputs);\n if (resolved.length === 0) return \"{}\";\n // Python's payload is a one-liner today, and stays one when there is nothing\n // to comment: the multi-line form exists to carry the `#` lines, so growing\n // it for a Function whose inputs are all required would be churn in every\n // snippet to serve the minority that needs it.\n if (opts.compact && resolved.every((i) => i.required)) {\n return JSON.stringify(Object.fromEntries(resolved.map((i) => [i.key, `<${i.key}>`])));\n }\n const lines = resolved.map(({ key, required }) => {\n const member = `${JSON.stringify(key)}: ${JSON.stringify(`<${key}>`)},`;\n return required ? `${opts.indent} ${member}` : `${opts.indent} ${opts.comment} ${member}`;\n });\n return `{\\n${lines.join(\"\\n\")}\\n${opts.indent}}`;\n}\n\n/**\n * Trailing `# optional: <key>` lines for the lanes that cannot carry a comment\n * INSIDE the payload (CLI and curl both pass JSON). Appended after the command,\n * and none of them ends with a backslash, so the block still pastes and runs as\n * one command. Mirrors `cliWorkflowCommand`/`curlWorkflowCommand`.\n */\nfunction optionalNotes(inputs: readonly SnippetInput[] | undefined): string {\n return resolveInputs(inputs)\n .filter((i) => !i.required)\n .map((i) => `\\n# optional: ${i.key}`)\n .join(\"\");\n}\n\n/**\n * A trigger field with no declared/blank `key` is dropped — mirrors\n * `trigger-preview.ts`'s own `triggerPreviews()` (and `@w6w/ui/flow`'s\n * `fieldsToParams`), which do the same before turning field defs into\n * anything fillable. Declared order is preserved.\n */\nfunction usableTriggerFields(\n fields: readonly TriggerPreviewFieldDef[] | undefined,\n): TriggerPreviewFieldDef[] {\n if (!fields) return [];\n return fields.filter((f) => typeof f.key === \"string\" && f.key.trim() !== \"\");\n}\n\n/**\n * The D-3 placeholder VALUE for a trigger field's declared `type`. The domain\n * is closed at four values — `trigger-fields.ts`'s `fieldWidget()` collapses\n * anything else to `\"string\"` — so this mirrors that collapse rather than\n * re-deriving it. The `\"<key>\"` form mirrors `samplePayload()`'s own\n * convention, so both arms of this file stay idiomatic.\n */\nfunction fieldPlaceholderValue(\n type: string | undefined,\n key: string,\n): string | number | boolean | Record<string, never> {\n if (type === \"number\") return 0;\n if (type === \"boolean\") return false;\n if (type === \"json\") return {};\n return `<${key}>`;\n}\n\n/**\n * The placeholder rendered as SOURCE CODE for one lane. Only the boolean\n * literal differs between Python (`False`) and Node/JSON (`false`) — a\n * shared `JSON.stringify` across all three lanes would emit `false` into\n * Python and raise `NameError` the moment the pasted snippet runs, which is\n * why this branches on `python` rather than reusing one formatter.\n */\nfunction fieldSourceLiteral(type: string | undefined, key: string, python: boolean): string {\n const value = fieldPlaceholderValue(type, key);\n if (typeof value === \"boolean\") return python ? \"False\" : \"false\";\n return JSON.stringify(value);\n}\n\n/**\n * The trigger's `input` object rendered into the Node call — required fields\n * active, optional fields commented out with `//` (D-3/D-4). `\"\"` when there\n * is nothing to show, so the caller can splice it straight after `wait: true,`\n * without leaving a dangling empty block.\n */\nfunction nodeInputBlock(fields: readonly TriggerPreviewFieldDef[]): string {\n if (fields.length === 0) return \"\";\n const lines = fields.map((f) => {\n // A field key is free text (`packages/ui/src/flow-types.ts:340`, no\n // validation) — `first-name`, `2fa`, `api key` are all reachable. A bare\n // object member (`first-name: ...`) is not valid TypeScript; quoting the\n // key with `JSON.stringify` (the same shape `:311`'s payload already\n // uses) is correct for every key by construction, so nothing here has to\n // decide what counts as a \"safe\" identifier.\n const member = `${JSON.stringify(f.key)}: ${fieldSourceLiteral(f.type, f.key as string, false)},`;\n return f.required === true ? ` ${member}` : ` // ${member}`;\n });\n return `\n input: {\n${lines.join(\"\\n\")}\n },`;\n}\n\n/**\n * The whole `client.workflows.run(...)` call expression for Python — not just\n * the `input=` block, because the no-fields case keeps the existing\n * single-line call rather than growing an empty `input={}`. Same active/\n * commented rule as `nodeInputBlock()`, `#` in place of `//`.\n */\nfunction pythonWorkflowCall(id: string, fields: readonly TriggerPreviewFieldDef[]): string {\n const idLiteral = JSON.stringify(id);\n if (fields.length === 0) return `client.workflows.run(${idLiteral}, wait=True)`;\n const lines = fields.map((f) => {\n const member = `\"${f.key}\": ${fieldSourceLiteral(f.type, f.key as string, true)},`;\n return f.required === true ? ` ${member}` : ` # ${member}`;\n });\n return `client.workflows.run(\n ${idLiteral},\n wait=True,\n input={\n${lines.join(\"\\n\")}\n },\n)`;\n}\n\n/**\n * The CLI arm of the same rule (D-4): JSON admits no comments, so\n * `--input '<json>'` carries the REQUIRED fields only, and each optional\n * field's key is instead named in a trailing `#` shell-comment line. Those\n * lines are appended after `cliCommand()` returns and none of them ends\n * with `\\`, so the whole block — command plus comments — still pastes and\n * runs as one command.\n */\nfunction cliWorkflowCommand(id: string, fields: readonly TriggerPreviewFieldDef[]): string {\n if (fields.length === 0) return cliCommand(`w6w workflows run ${id}`, \"--wait\");\n const required = fields.filter((f) => f.required === true);\n const optional = fields.filter((f) => f.required !== true);\n const payload = Object.fromEntries(\n required.map((f) => [f.key as string, fieldPlaceholderValue(f.type, f.key as string)]),\n );\n let cmd = cliCommand(\n `w6w workflows run ${id}`,\n \"--wait\",\n `--input ${shellQuote(JSON.stringify(payload))}`,\n );\n for (const f of optional) {\n cmd += `\\n# optional: ${f.key} (${f.type ?? \"string\"})`;\n }\n return cmd;\n}\n\n/**\n * The lines every Node snippet opens with. `extra` names any additional symbol\n * the body uses — the import list has to be complete or the snippet does not\n * compile when pasted, which is the one thing a copyable example must not do.\n */\nfunction nodePreamble(...extra: string[]): string {\n const symbols = [\"W6WClient\", ...extra].join(\", \");\n return `import { ${symbols} } from \"@w6w/sdk\";\n\n// Reads W6W_BASE_URL and W6W_TOKEN from the environment when omitted.\nconst client = new W6WClient();`;\n}\n\n/**\n * The lines every Python snippet opens with. Mirrors `nodePreamble()`:\n * `extra` names any additional symbol the body uses (a discriminator\n * free-function), and the import list has to be complete or the snippet does\n * not run when pasted.\n */\nfunction pythonPreamble(...extra: string[]): string {\n const symbols = [\"Client\", ...extra].join(\", \");\n return `from w6w import ${symbols}\n\n# Reads W6W_BASE_URL and W6W_TOKEN from the environment when omitted.\nclient = Client()`;\n}\n\n/**\n * The two header lines and the `-d` line every curl arm shares — the \"one\n * body builder, not three\" the three curl arms below are built on. `urlToken`\n * is the URL already rendered as a shell token: `\"$W6W_BASE_URL/…\"`\n * double-quoted so the env var expands (the function/workflow arms), or\n * `shellQuote`d (the endpoint arm, whose URL is a server-rendered literal\n * that may carry an operator-typed `'`). The auth header is DOUBLE-quoted so\n * `$W6W_TOKEN` expands on paste; `content-type` keeps single quotes (nothing\n * in it expands); `-d`'s JSON body is always `shellQuote`d — double-quoting\n * it would let the shell eat its own `\"` characters.\n */\nfunction curlBody(urlToken: string, data: unknown): string {\n return `curl -X POST ${urlToken} \\\\\n -H \"authorization: Bearer $W6W_TOKEN\" \\\\\n -H 'content-type: application/json' \\\\\n -d ${shellQuote(JSON.stringify(data))}`;\n}\n\n/**\n * A raw-HTTP call against a URL the SERVER rendered (the Endpoint arm).\n *\n * `url` is spliced in verbatim (through the same `shellQuote` every other shell\n * literal in this file uses) — this function has no notion of a host, a path, an\n * account or a key, and must never grow one: the whole point of the id/key\n * toggle is that both strings arrive fully formed from the server.\n * `payload` is the optional data payload to send with the request.\n */\nfunction curlCommand(url: string, payload?: Record<string, string>): string {\n return curlBody(shellQuote(url), payload ?? {});\n}\n\n/**\n * The name-addressed arm: `POST $W6W_BASE_URL/{group}/{name}/invoke`.\n *\n * `bodyKey` is a parameter because the wire is inconsistent where the SDK is\n * not — a Function takes `inputs`, an Endpoint takes `input`. The wrappers\n * spell both `payload`; raw HTTP cannot, so the caller passes the real one and\n * this helper never guesses.\n *\n * `name` is percent-encoded: it lands in a URL path, and a key that predates\n * the kebab-slug grammar may still contain something that needs escaping.\n */\nfunction curlInvokeCommand(\n group: \"functions\" | \"endpoints\",\n name: string,\n bodyKey: \"inputs\" | \"input\",\n payload: Record<string, string>,\n): string {\n const url = `\"$W6W_BASE_URL/${group}/${encodeURIComponent(name)}/invoke\"`;\n return curlBody(url, { [bodyKey]: payload });\n}\n\n/**\n * The Workflow arm: `POST /workflows/{id}/run?wait=true` — same route as the\n * node/cli/python lanes' `wait: true` / `--wait`. Mirrors `cliWorkflowCommand`\n * (D-3/D-4): required trigger fields are active JSON, optional ones are named\n * in a trailing `#` comment line each (JSON admits no comments), and a\n * trigger with no usable fields emits a bare `{}` body and no trailer.\n */\nfunction curlWorkflowCommand(id: string, fields: readonly TriggerPreviewFieldDef[]): string {\n const url = `\"$W6W_BASE_URL/workflows/${id}/run?wait=true\"`;\n if (fields.length === 0) return curlBody(url, {});\n const required = fields.filter((f) => f.required === true);\n const optional = fields.filter((f) => f.required !== true);\n const payload = Object.fromEntries(\n required.map((f) => [f.key as string, fieldPlaceholderValue(f.type, f.key as string)]),\n );\n let cmd = curlBody(url, { input: payload });\n for (const f of optional) {\n cmd += `\\n# optional: ${f.key} (${f.type ?? \"string\"})`;\n }\n return cmd;\n}\n\n/**\n * Build the Node + CLI snippet for one resource, or `null` when the contract\n * has no operation for it (today: a function or endpoint whose id carries no\n * runnable prefix).\n */\nexport function buildSnippet(\n resource: SnippetCallable,\n triggerFields?: readonly TriggerPreviewFieldDef[],\n): Snippet | null {\n switch (resource.kind) {\n case \"workflow\": {\n if (!isUrnAddressable(resource.id)) return null;\n const name = addressName(resource);\n const fields = usableTriggerFields(triggerFields);\n return {\n operation: \"workflows.run — POST /workflows/{idOrKey}/run\",\n node: `${nodePreamble()}\n\n// \\`wait: true\\` blocks until the run reaches a terminal state.\n// Omit it and you get \\`{ runId, status: \"queued\" }\\` back immediately.\nconst result = await client.workflows.run(${JSON.stringify(name)}, {\n wait: true,${nodeInputBlock(fields)}\n});\n\nconsole.log(result.status, result.runId);`,\n cli: cliWorkflowCommand(name, fields),\n python: `${pythonPreamble()}\n\n# \\`wait=True\\` blocks until the run reaches a terminal state.\n# Omit it and you get \\`WorkflowRunResult(status=\"queued\", ...)\\` back immediately.\nresult = ${pythonWorkflowCall(name, fields)}\n\nprint(result.status, result.runId)`,\n curl: curlWorkflowCommand(name, fields),\n };\n }\n\n case \"function\": {\n if (!isUrnAddressable(resource.id)) return null;\n const name = addressName(resource);\n // JSON carries no comments, so the CLI/curl lanes take the REQUIRED\n // inputs and name the optional ones underneath; Node and Python render\n // every input and comment the optional ones out in place.\n const payload = samplePayload(resource.inputs, true);\n const payloadJson = JSON.stringify(payload);\n const notes = optionalNotes(resource.inputs);\n const payloadBlock = payloadSource(resource.inputs, { indent: \" \", comment: \"//\" });\n const pythonPayload = payloadSource(resource.inputs, {\n indent: \"\",\n comment: \"#\",\n compact: true,\n });\n return {\n operation: \"functions.run — POST /functions/{idOrKey}/invoke\",\n node: `${nodePreamble()}\n\n// The name is the first argument, and it may be the Function's key or its\n// \\`fn_…\\` id — one slot takes either. Returns the OUTPUT directly: the kind is\n// settled by the method, so there is no envelope to narrow.\nconst output = await client.functions.run(${JSON.stringify(name)}, {\n payload: ${payloadBlock},\n});\n\nconsole.log(output);`,\n cli:\n cliCommand(`w6w functions run ${name}`, `--payload ${shellQuote(payloadJson)}`) + notes,\n python: `${pythonPreamble()}\n\n# The name is the first argument — the Function's key or its \\`fn_…\\` id.\noutput = client.functions.run(${JSON.stringify(name)}, payload=${pythonPayload})\n\nprint(output)`,\n curl: curlInvokeCommand(\"functions\", name, \"inputs\", payload) + notes,\n };\n }\n\n case \"endpoint\": {\n if (!isUrnAddressable(resource.id)) return null;\n // Which of the two server-rendered URLs the raw-HTTP arm shows. The\n // absence of a URL altogether means no `curl` snippet at all, rather than\n // a plausible-looking one built here.\n const httpUrl =\n resource.urlForm === \"key\" && resource.invokeUrlByKey\n ? resource.invokeUrlByKey\n : resource.invokeUrl;\n const name = addressName(resource);\n const payload = samplePayload(resource.inputs, true);\n const payloadJson = JSON.stringify(payload);\n const notes = optionalNotes(resource.inputs);\n const payloadBlock = payloadSource(resource.inputs, { indent: \" \", comment: \"//\" });\n const pythonPayload = payloadSource(resource.inputs, {\n indent: \"\",\n comment: \"#\",\n compact: true,\n });\n return {\n operation: \"endpoints.run — POST /endpoints/{idOrKey}/invoke\",\n node: `${nodePreamble()}\n\n// The name is the first argument — the Endpoint's key or its \\`ep_…\\` id. Unlike\n// \\`functions.run\\` this returns the ENVELOPE: an Endpoint dispatches to an app\n// action, a Function or a Workflow, and only \\`kind\\` says which answered.\nconst envelope = await client.endpoints.run(${JSON.stringify(name)}, {\n payload: ${payloadBlock},\n});\n\nconsole.log(envelope.kind, envelope);`,\n cli:\n cliCommand(`w6w endpoints run ${name}`, `--payload ${shellQuote(payloadJson)}`) + notes,\n python: `${pythonPreamble()}\n\n# The name is the first argument — the Endpoint's key or its \\`ep_…\\` id.\nenvelope = client.endpoints.run(${JSON.stringify(name)}, payload=${pythonPayload})\n\nprint(envelope[\"kind\"], envelope)`,\n ...(typeof httpUrl === \"string\" && httpUrl !== \"\"\n ? { curl: curlCommand(httpUrl, payload) + notes }\n : {}),\n };\n }\n\n case \"connection\": {\n if (!isUrnAddressable(resource.id)) return null;\n const payload = samplePayload(resource.params);\n return {\n operation: \"run — POST /run\",\n node: `${nodePreamble(\"isActionRun\")}\n\n// An app action runs through the CONNECTION that authenticates it, so the URN\n// is the connection id and \\`action\\` names the action on its app. This is the\n// one arm where \\`action\\` is required — a workflow, function or endpoint URN\n// has no action to name.\nconst envelope = await client.run({\n urn: ${JSON.stringify(resource.id)},\n action: ${JSON.stringify(resource.action)},\n payload: ${JSON.stringify(payload, null, 2).replaceAll(\"\\n\", \"\\n \")},\n});\n\nif (isActionRun(envelope)) console.log(envelope.value);`,\n cli: cliCommand(\n `w6w run ${resource.id}`,\n `--action ${resource.action}`,\n `--payload ${shellQuote(JSON.stringify(payload))}`,\n ),\n python: `${pythonPreamble(\"is_action_run\")}\n\n# An app action runs through the CONNECTION that authenticates it, so the URN\n# is the connection id and \\`action\\` names the action on its app. This is the\n# one arm where \\`action\\` is required — a workflow, function or endpoint URN\n# has no action to name.\nenvelope = client.run(\n ${JSON.stringify(resource.id)},\n action=${JSON.stringify(resource.action)},\n payload=${JSON.stringify(payload)},\n)\n\nif is_action_run(envelope):\n print(envelope[\"value\"])`,\n };\n }\n\n case \"var\":\n return {\n operation: \"vars.getByName — GET /vars/by-name/{name}\",\n node: `${nodePreamble()}\n\nconst variable = await client.vars.getByName(${JSON.stringify(resource.name)});\nconsole.log(variable.value);`,\n cli: `w6w vars get-by-name ${resource.name}`,\n python: `${pythonPreamble()}\n\nvariable = client.vars.get_by_name(${JSON.stringify(resource.name)})\nprint(variable.value)`,\n };\n\n case \"document\":\n return {\n operation: \"documents.getByKey — GET /documents/by-key/{key}\",\n node: `${nodePreamble()}\n\nconst doc = await client.documents.getByKey(${JSON.stringify(resource.key)});\nconsole.log(doc.content);`,\n cli: `w6w documents get-by-key ${shellQuote(resource.key)}`,\n python: `${pythonPreamble()}\n\ndoc = client.documents.get_by_key(${JSON.stringify(resource.key)})\nprint(doc.content)`,\n };\n }\n}\n\n/** Why no snippet exists, phrased for the reader rather than for a log. */\nexport function unavailableReason(resource: SnippetCallable): string {\n if (\n (resource.kind === \"function\" ||\n resource.kind === \"endpoint\" ||\n resource.kind === \"workflow\") &&\n !isUrnAddressable(resource.id)\n ) {\n return `This ${resource.kind}'s id (${resource.id}) has no \\`${\n resource.kind === \"workflow\" ? \"wf_\" : resource.kind === \"function\" ? \"fn_\" : \"ep_\"\n }\\` prefix, so it cannot be addressed by URN. The SDK and CLI reach ${resource.kind}s through \\`run\\`, which resolves a URN by that prefix — re-create it with a host-issued id to call it from code.`;\n }\n return \"The client libraries do not expose an operation for this yet.\";\n}\n","/**\n * Slug rules — the ONE place in `studio/src` that owns one.\n *\n * Two rules live here and they are deliberately NOT the same rule:\n *\n * · `slugify()` turns a human display name into a machine key. It is the\n * fallback the Endpoint and Function editors use when the operator leaves\n * `key` blank, and it is permissive on purpose: whatever it returns is a\n * legal resource key, digits-first and two characters included.\n * · `ACCOUNT_SLUG_RE` / `isValidAccountSlug()` decide whether a string is a\n * legal ACCOUNT slug — the account segment a key-form invoke URL is\n * addressed by. That rule is stricter: it must start with a letter and run to\n * at least three characters, so `2024-team` and `ab` are both perfectly good\n * keys and both invalid account slugs.\n *\n * The regex is exported rather than re-typed by each caller. A second copy is\n * exactly how a form comes to accept a value the server rejects, so the literal\n * appears in this file and nowhere else in `src/`.\n *\n * Why `src/lib` and why this module imports nothing: `src/lib/*.ts` is the only\n * place studio's `node --test` suite can reach. A rule living inside a `.tsx`\n * page cannot be unit-tested at all (Node's type-stripping does not parse JSX),\n * and a `src/lib` module that imports `@w6w/ui` throws\n * `ERR_UNKNOWN_FILE_EXTENSION` under the same runner because the barrel\n * re-exports `.tsx`. Same constraint documented at\n * `src/lib/workflow-validity.ts:11-20`.\n */\n\n/** Kebab-case a display name into a machine key (the fallback when key is blank). */\nexport function slugify(s: string): string {\n return s\n .toLowerCase()\n .trim()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\");\n}\n\n/**\n * A legal account slug: lowercase, opens with a LETTER, then two or more\n * letters/digits/hyphens — three characters minimum.\n *\n * Note this is NOT the server's `tenants.ts` `SLUG_RE`\n * (`/^[a-z0-9][a-z0-9_-]*$/`), which governs tenant ids and is a different,\n * more permissive rule. Do not merge the two.\n */\nexport const ACCOUNT_SLUG_RE = /^[a-z][a-z0-9-]{2,}$/;\n\n/** Does `s` satisfy {@link ACCOUNT_SLUG_RE}? */\nexport function isValidAccountSlug(s: string): boolean {\n return ACCOUNT_SLUG_RE.test(s);\n}\n\n/**\n * A legal Endpoint `key` — mirrors the server's rule VERBATIM, not\n * {@link ACCOUNT_SLUG_RE} above: that one is `{2,}` with no 39-character cap\n * and encodes neither the `--` rule nor the trailing-`-` rule, so a form that\n * validated a key with it would accept a value the server rejects.\n *\n * Source of truth: `packages/server/packages/bll/accounts.ts:72`\n * (`ACCOUNT_SLUG_RE = /^[a-z][a-z0-9-]{2,38}$/`) + `:216-218` (`isAccountSlug`),\n * reached from `packages/server/packages/api/invoke-address.ts:55-57`\n * (`isEndpointKey = isAccountSlug`). There is no reserved-word check on an\n * Endpoint key server-side — `isAccountSlug` only, never\n * `RESERVED_ACCOUNT_SLUGS` — so none is added here either.\n */\nexport function isEndpointKey(s: string): boolean {\n return /^[a-z][a-z0-9-]{2,38}$/.test(s) && !s.includes(\"--\") && !s.endsWith(\"-\");\n}\n\n/**\n * Filters a keystroke into a key input down to what {@link isEndpointKey}'s\n * grammar can ever accept: lowercase letters, digits, hyphens — nothing\n * else, capped at the grammar's own 39-character ceiling. A space or any\n * other disallowed character is dropped outright rather than folded into a\n * `-` ({@link slugify}'s job, for the one-time displayName-to-key fallback —\n * this is a LIVE filter on a field the operator is typing directly into, so\n * silently substituting a different character would be its own surprise).\n * Positional rules the grammar also enforces (must START with a letter, no\n * `--`, no trailing `-`) are left to {@link isEndpointKey} at Save time —\n * blocking those mid-keystroke would refuse a caller who is one keystroke\n * away from a valid value (e.g. typing `\"2\"` before backspacing to start\n * over).\n */\nexport function filterKeyInput(raw: string): string {\n return raw\n .toLowerCase()\n .replace(/[^a-z0-9-]/g, \"\")\n .slice(0, 39);\n}\n"],"names":["RUNNABLE_PREFIXES","isUrnAddressable","id","p","addressName","resource","_a","key","shellQuote","value","CLI_WRAP_AT","cliCommand","head","flags","parts","oneLine","resolveInputs","inputs","i","samplePayload","requiredOnly","resolved","used","payloadSource","opts","required","member","optionalNotes","usableTriggerFields","fields","f","fieldPlaceholderValue","type","fieldSourceLiteral","python","nodeInputBlock","pythonWorkflowCall","idLiteral","lines","cliWorkflowCommand","optional","payload","cmd","nodePreamble","extra","pythonPreamble","curlBody","urlToken","data","curlCommand","url","curlInvokeCommand","group","name","bodyKey","curlWorkflowCommand","buildSnippet","triggerFields","payloadJson","notes","payloadBlock","pythonPayload","httpUrl","unavailableReason","slugify","s","ACCOUNT_SLUG_RE","isValidAccountSlug","isEndpointKey","filterKeyInput","raw"],"mappings":"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"}
@@ -0,0 +1,176 @@
1
+ import { useQueryClient as c, useMutation as l, useQuery as f } from "@tanstack/react-query";
2
+ import { path as i } from "@w6w/sdk";
3
+ import { u } from "./client-context-CX61Bgw-.js";
4
+ import { j as p, d } from "./callables-3mFrMVG_.js";
5
+ import { m as y, Z as b } from "./spec-import-CjmxyZDR.js";
6
+ const h = (t) => d("endpoint", t), m = (t) => d("function", t), a = {
7
+ function: "functions",
8
+ workflow: "workflows",
9
+ endpoint: "endpoints"
10
+ }, q = {
11
+ function: "invoke",
12
+ endpoint: "invoke",
13
+ workflow: "run"
14
+ };
15
+ function w(t, n) {
16
+ return ["versions", t, n];
17
+ }
18
+ function $(t, n, s) {
19
+ return ["version", t, n, s];
20
+ }
21
+ function T(t, n, s) {
22
+ const e = u();
23
+ return f({
24
+ queryKey: w(t, n),
25
+ queryFn: async () => {
26
+ switch (t) {
27
+ case "workflow":
28
+ return await e.workflows.listVersions(n);
29
+ case "function":
30
+ return await e.functions.listVersions(n);
31
+ case "endpoint":
32
+ return (await e.request({
33
+ method: "GET",
34
+ path: i`/${a.endpoint}/${n}/versions`
35
+ })).body;
36
+ }
37
+ },
38
+ enabled: s && t !== null && n !== ""
39
+ });
40
+ }
41
+ function O(t, n, s, e) {
42
+ const o = u();
43
+ return f({
44
+ queryKey: $(t, n, s),
45
+ queryFn: async () => {
46
+ const r = s;
47
+ switch (t) {
48
+ case "workflow":
49
+ return await o.workflows.getVersion(n, r);
50
+ case "function":
51
+ return await o.functions.getVersion(n, r);
52
+ case "endpoint":
53
+ return (await o.request({
54
+ method: "GET",
55
+ path: i`/${a.endpoint}/${n}/versions/${String(r)}`
56
+ })).body.version;
57
+ }
58
+ },
59
+ enabled: e && t !== null && n !== "" && s !== null
60
+ });
61
+ }
62
+ function Q(t) {
63
+ const n = u(), s = c();
64
+ return l({
65
+ mutationFn: async (e) => {
66
+ switch (t) {
67
+ case "workflow":
68
+ return await n.workflows.publish(e);
69
+ case "function":
70
+ return await n.functions.publish(e);
71
+ case "endpoint":
72
+ return (await n.request({
73
+ method: "POST",
74
+ path: i`/${a.endpoint}/${e}/publish`
75
+ })).body;
76
+ }
77
+ },
78
+ onSuccess: (e, o) => {
79
+ s.invalidateQueries({ queryKey: w(t, o) });
80
+ }
81
+ });
82
+ }
83
+ function v(t) {
84
+ const n = u(), s = c();
85
+ return l({
86
+ mutationFn: async (e) => {
87
+ switch (t) {
88
+ case "workflow":
89
+ return e.enabled ? await n.workflows.enable(e.id) : await n.workflows.disable(e.id), { enabled: e.enabled };
90
+ case "function":
91
+ return e.enabled ? await n.functions.enable(e.id) : await n.functions.disable(e.id), { enabled: e.enabled };
92
+ case "endpoint":
93
+ return (await n.request({
94
+ method: "POST",
95
+ path: i`/${a.endpoint}/${e.id}/${e.enabled ? "enable" : "disable"}`
96
+ })).body;
97
+ }
98
+ },
99
+ onSuccess: (e, o) => {
100
+ s.invalidateQueries({ queryKey: w(t, o.id) });
101
+ }
102
+ });
103
+ }
104
+ function F(t) {
105
+ const n = u(), s = c();
106
+ return l({
107
+ mutationFn: async (e) => {
108
+ switch (t) {
109
+ case "workflow":
110
+ return { reverted: await n.workflows.revert(e.id, e.versionNumber) };
111
+ case "function":
112
+ return { reverted: await n.functions.revert(e.id, e.versionNumber) };
113
+ case "endpoint":
114
+ return (await n.request({
115
+ method: "POST",
116
+ path: i`/${a.endpoint}/${e.id}/versions/${String(e.versionNumber)}/revert`
117
+ })).body;
118
+ }
119
+ },
120
+ onSuccess: (e, o) => {
121
+ let r;
122
+ switch (t) {
123
+ case "function":
124
+ r = m(o.id);
125
+ break;
126
+ case "workflow":
127
+ r = b(o.id);
128
+ break;
129
+ case "endpoint":
130
+ r = h(o.id);
131
+ break;
132
+ }
133
+ p(s, w(t, o.id), r);
134
+ }
135
+ });
136
+ }
137
+ function g(t) {
138
+ const n = u(), s = c();
139
+ return l({
140
+ mutationFn: async (e) => {
141
+ if (t === "workflow") {
142
+ const r = await n.workflows.runVersion(e.id, e.versionNumber, {});
143
+ return { runId: r.runId, status: r.status };
144
+ }
145
+ return (await n.request({
146
+ method: "POST",
147
+ path: i`/${a[t]}/${e.id}/versions/${String(e.versionNumber)}/${q[t]}`,
148
+ body: {}
149
+ })).body;
150
+ },
151
+ onSettled: () => s.invalidateQueries({ queryKey: y.root })
152
+ });
153
+ }
154
+ function I(t, n, s) {
155
+ const e = u();
156
+ return f({
157
+ queryKey: ["spec", t, n],
158
+ queryFn: async () => (await e.request({
159
+ method: "GET",
160
+ path: i`/${t}/${n}/spec`
161
+ })).body.spec,
162
+ enabled: s && t !== null
163
+ });
164
+ }
165
+ export {
166
+ Q as a,
167
+ F as b,
168
+ v as c,
169
+ I as d,
170
+ O as e,
171
+ T as f,
172
+ w as g,
173
+ g as u,
174
+ $ as v
175
+ };
176
+ //# sourceMappingURL=spec-export-Cf3VQSQS.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spec-export-Cf3VQSQS.js","sources":["../src/repos/versions.ts","../src/repos/spec-export.ts"],"sourcesContent":["/**\n * The `/<collection>/:id/{publish,versions,enable,disable}` repo (T3.1.1) — the Settings rail's\n * read-only version-history browser plus Publish and Enable/Disable. A NEW file, mirroring\n * `src/repos/spec-export.ts` in full: kept out of `repos/functions.ts` / `repos/workflows.ts` /\n * `repos/endpoints.ts` so this node never collides with any of them on the same file, exactly the\n * reason `spec-export.ts`'s own docblock gives for the sibling `/spec` route.\n *\n * **Workflow and Function arms go through the public `@w6w/sdk` methods** (`listVersions`,\n * `getVersion`, `publish`, `revert`, `enable`, `disable`, and `workflows.runVersion`), never\n * `apiClient.console.*`. Each hook dispatches with an explicit per-kind `switch` over LITERAL\n * receivers (`apiClient.workflows.publish(id)`, `apiClient.functions.publish(id)`) and no `default:`\n * — the same reasoning `COLLECTION_PATH` and `useRevertMutation` give against derived dispatch.\n *\n * **Two arms deliberately stay on `W6WClient.request<T>()`:** the ENDPOINT arm of every hook\n * (R-5: endpoint versions have no SDK method — intentionally excluded from the public surface),\n * and the FUNCTION arm of {@link useInvokeVersionMutation} (F-P4: `VersionHistoryModal` renders the\n * raw invocation frame, but `functions.runVersion` unwraps the output like `functions.run`, so the\n * SDK method would drop the frame; follow-up F-6).\n *\n * Every query below is gated on the CALLER'S OWN `enabled` flag, ANDed with `kind !== null` and\n * `id !== \"\"` — never on mount alone (`packages/studio/.ai/PLANNER.md` fact 11): a hook that fires\n * unconditionally against an unresolved `null`/`\"\"` argument 404s once and, because `main.tsx`\n * sets `retry: false` and an unchanged query key never re-fetches, never self-corrects. Opening\n * the Settings panel must issue ZERO `/versions` requests; only opening its History section (or\n * `WorkflowsPage.tsx`'s own editor, a separate call site with its own gate) flips `enabled`.\n *\n * T5.3.1 (project.md Phase 2, Amendments #5/#6): a version can now be reverted to and invoked\n * directly, superseding the earlier \"read-only history, restore out of scope\" pin. `useRevertMutation`\n * overwrites the LIVE resource's `definition` with the archived version's content — never its\n * `key`/address (HITL-4's pinned default) — and does post a `definition` back, by design.\n * `useInvokeVersionMutation` runs that ARCHIVED version's own definition, not the live one, which is\n * exactly why it exists as a separate call from the live invoke/run routes `functions.ts`/\n * `endpoints.ts`/`workflows.ts` already expose.\n */\nimport { useMutation, useQuery, useQueryClient } from \"@tanstack/react-query\";\nimport { path } from \"@w6w/sdk\";\nimport { useEmbedClient } from \"../draft/client-context.ts\";\nimport { callableKey } from \"../lib/callable-kind.ts\";\nimport { historyKeys } from \"../lib/history-query.ts\";\nimport { invalidateSavedCallable } from \"../lib/save-invalidation.ts\";\nimport { workflowKey } from \"./workflows.ts\";\n\n/** The Endpoint / Function single-resource keys the revert arm invalidates: the same\n * `callableKey(\"<kind>\", id)` Studio's `repos/endpoints.ts` / `repos/functions.ts` export as\n * `endpointKey` / `functionKey` (byte-identical `[\"endpoint\", id]` / `[\"function\", id]`). */\nconst endpointKey = (id: string) => callableKey(\"endpoint\", id);\nconst functionKey = (id: string) => callableKey(\"function\", id);\n\n/** The three kinds the wire contract's version-history routes exist for — `connection` has none\n * (see `hasVersionHistory`, `../lib/rail-settings.ts`). */\nexport type VersionsKind = \"function\" | \"workflow\" | \"endpoint\";\n\n/** `<coll>` — the wire contract's own path segment for each kind, every one of the three arms\n * named explicitly (never derived by string pluralization), mirroring `specCollectionForKind`'s\n * own reasoning (`../lib/rail-settings.ts:69`): a typo'd suffix rule would silently send one\n * kind's requests at another kind's collection. */\nconst COLLECTION_PATH: Record<VersionsKind, \"functions\" | \"workflows\" | \"endpoints\"> = {\n function: \"functions\",\n workflow: \"workflows\",\n endpoint: \"endpoints\",\n};\n\n/** One row of `GET /<coll>/:id/versions`'s `versions` array — newest first, per the wire contract. */\nexport interface VersionSummary {\n versionNumber: number;\n createdAt: string;\n createdBy: string | null;\n isCurrentPublished: boolean;\n}\n\n/** `GET /<coll>/:id/versions`'s full 200 body. */\nexport interface VersionsEnvelope {\n enabled: boolean;\n currentPublishedVersion: number | null;\n versions: VersionSummary[];\n}\n\n/** `GET /<coll>/:id/versions/:n`'s `version` field — `definition` is the redacted stored\n * definition for THIS query; {@link useRevertMutation} is what posts a version's definition\n * back onto the live resource, and {@link useInvokeVersionMutation} is what runs it. */\nexport interface VersionDetail {\n versionNumber: number;\n createdAt: string;\n createdBy: string | null;\n isCurrentPublished: boolean;\n definition: Record<string, unknown>;\n}\n\n/** `POST /<coll>/:id/publish`'s 200 body. */\nexport interface PublishResult {\n version: {\n kind: string;\n callableId: string;\n versionNumber: number;\n createdAt: string;\n createdBy: string | null;\n };\n currentPublishedVersion: number;\n}\n\n/** `POST /<coll>/:id/versions/:n/revert`'s 200 body. */\nexport interface RevertResult {\n reverted: {\n kind: string;\n callableId: string;\n versionNumber: number;\n };\n}\n\n/** `<coll>` per kind ends its live invoke/run route in `/invoke` (Function, Endpoint) or `/run`\n * (Workflow, matching that kind's existing unversioned route) — every arm named explicitly\n * (never derived by suffix rule), mirroring `COLLECTION_PATH`'s own reasoning above: a derived\n * rule would silently send one kind's requests at the wrong verb. */\nconst VERSION_INVOKE_VERB: Record<VersionsKind, \"invoke\" | \"run\"> = {\n function: \"invoke\",\n endpoint: \"invoke\",\n workflow: \"run\",\n};\n\nexport function versionsKey(kind: VersionsKind | null, id: string) {\n return [\"versions\", kind, id] as const;\n}\n\nexport function versionKey(kind: VersionsKind | null, id: string, versionNumber: number | null) {\n return [\"version\", kind, id, versionNumber] as const;\n}\n\n/**\n * `GET /<collection>/:id/versions`. Never fires on mount — `enabled` is the caller's own flag\n * (the Settings panel's History-open state, or `WorkflowsPage.tsx`'s own editor-open gate), ANDed\n * with `kind !== null` and `id !== \"\"`, exactly `useSpecQuery`'s shape (`spec-export.ts:45-57`).\n */\nexport function useVersionsQuery(kind: VersionsKind | null, id: string, enabled: boolean) {\n const apiClient = useEmbedClient();\n return useQuery({\n queryKey: versionsKey(kind, id),\n queryFn: async (): Promise<VersionsEnvelope> => {\n switch (kind as VersionsKind) {\n case \"workflow\":\n return await apiClient.workflows.listVersions(id);\n case \"function\":\n return await apiClient.functions.listVersions(id);\n case \"endpoint\": {\n // R-5: no SDK method for endpoint versions.\n const res = await apiClient.request<VersionsEnvelope>({\n method: \"GET\",\n path: path`/${COLLECTION_PATH.endpoint}/${id}/versions`,\n });\n return res.body;\n }\n }\n },\n enabled: enabled && kind !== null && id !== \"\",\n });\n}\n\n/**\n * `GET /<collection>/:id/versions/:n`. Same gating shape as {@link useVersionsQuery}, plus\n * `versionNumber !== null` — the modal opens this only once a row has been clicked.\n */\nexport function useVersionQuery(\n kind: VersionsKind | null,\n id: string,\n versionNumber: number | null,\n enabled: boolean,\n) {\n const apiClient = useEmbedClient();\n return useQuery({\n queryKey: versionKey(kind, id, versionNumber),\n queryFn: async (): Promise<VersionDetail> => {\n // The SDK's `getVersion` already unwraps the `{ version }` envelope.\n const n = versionNumber as number;\n switch (kind as VersionsKind) {\n case \"workflow\":\n return (await apiClient.workflows.getVersion(id, n)) as VersionDetail;\n case \"function\":\n return (await apiClient.functions.getVersion(id, n)) as VersionDetail;\n case \"endpoint\": {\n // R-5: no SDK method for endpoint versions.\n const res = await apiClient.request<{ version: VersionDetail }>({\n method: \"GET\",\n path: path`/${COLLECTION_PATH.endpoint}/${id}/versions/${String(n)}`,\n });\n return res.body.version;\n }\n }\n },\n enabled: enabled && kind !== null && id !== \"\" && versionNumber !== null,\n });\n}\n\n/**\n * `POST /<collection>/:id/publish`. `kind` is fixed per hook instance — the caller already knows\n * which kind it is publishing (the rail's `ctx.kind`, or `WorkflowsPage.tsx`'s hardcoded\n * `\"workflow\"`) — and `mutate(id)` supplies the resource. `onSuccess` invalidates the SAME\n * `[\"versions\", kind, id]` key {@link useVersionsQuery} reads, so the panel's published pointer\n * and version list are fresh without a reload (A3), mirroring `useSaveFunctionMutation`'s\n * `onSuccess` shape (`./functions.ts`).\n */\nexport function usePublishMutation(kind: VersionsKind) {\n const apiClient = useEmbedClient();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (id: string): Promise<PublishResult> => {\n switch (kind) {\n case \"workflow\":\n return await apiClient.workflows.publish(id);\n case \"function\":\n return await apiClient.functions.publish(id);\n case \"endpoint\": {\n // R-5: no SDK method for endpoint versions.\n const res = await apiClient.request<PublishResult>({\n method: \"POST\",\n path: path`/${COLLECTION_PATH.endpoint}/${id}/publish`,\n });\n return res.body;\n }\n }\n },\n onSuccess: (_result, id) => {\n qc.invalidateQueries({ queryKey: versionsKey(kind, id) });\n },\n });\n}\n\n/**\n * `POST /<collection>/:id/{enable,disable}`. One mutation for both — the wire contract is two\n * routes distinguished only by which one is called, so `vars.enabled` picks the path segment\n * rather than this module carrying two near-identical mutations. `onSuccess` invalidates the same\n * key {@link usePublishMutation} does, for the same reason.\n */\nexport function useSetEnabledMutation(kind: VersionsKind) {\n const apiClient = useEmbedClient();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (vars: { id: string; enabled: boolean }): Promise<{ enabled: boolean }> => {\n // The SDK's `enable`/`disable` return void; the hook's result stays `{ enabled }`.\n switch (kind) {\n case \"workflow\":\n if (vars.enabled) await apiClient.workflows.enable(vars.id);\n else await apiClient.workflows.disable(vars.id);\n return { enabled: vars.enabled };\n case \"function\":\n if (vars.enabled) await apiClient.functions.enable(vars.id);\n else await apiClient.functions.disable(vars.id);\n return { enabled: vars.enabled };\n case \"endpoint\": {\n // R-5: no SDK method for endpoint versions.\n const res = await apiClient.request<{ enabled: boolean }>({\n method: \"POST\",\n path: path`/${COLLECTION_PATH.endpoint}/${vars.id}/${vars.enabled ? \"enable\" : \"disable\"}`,\n });\n return res.body;\n }\n }\n },\n onSuccess: (_result, vars) => {\n qc.invalidateQueries({ queryKey: versionsKey(kind, vars.id) });\n },\n });\n}\n\n/**\n * `POST /<collection>/:id/versions/:n/revert`, no body — overwrites the LIVE resource's\n * `definition` with the archived version's content, preserving its `key`/address (HITL-4's\n * pinned default; see the module docblock). This is the first mutation in this family that\n * changes `definition` rather than merely appending to or flipping a flag on the version history\n * (`usePublishMutation`/`useSetEnabledMutation` above do neither), so `onSuccess` invalidates\n * BOTH `versionsKey(kind, id)` (the same key those two invalidate) AND the kind's own\n * definition-edit key — via the shared `invalidateSavedCallable` helper\n * `useSaveFunctionMutation`/`useSaveEndpointMutation` already route through\n * (`../lib/save-invalidation.ts`) — or the page a user reverted FROM keeps showing the\n * pre-revert draft until a manual reload. The definition key is picked by a `switch` naming all\n * three arms explicitly, with no `default:` — the same reasoning `COLLECTION_PATH`'s own docblock\n * gives: a derived rule would silently send one kind at another kind's key.\n */\nexport function useRevertMutation(kind: VersionsKind) {\n const apiClient = useEmbedClient();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (vars: { id: string; versionNumber: number }): Promise<RevertResult> => {\n // The SDK's `revert` unwraps `{ reverted }`; the hook re-wraps it to keep its result shape.\n switch (kind) {\n case \"workflow\":\n return { reverted: await apiClient.workflows.revert(vars.id, vars.versionNumber) };\n case \"function\":\n return { reverted: await apiClient.functions.revert(vars.id, vars.versionNumber) };\n case \"endpoint\": {\n // R-5: no SDK method for endpoint versions.\n const res = await apiClient.request<RevertResult>({\n method: \"POST\",\n path: path`/${COLLECTION_PATH.endpoint}/${vars.id}/versions/${String(vars.versionNumber)}/revert`,\n });\n return res.body;\n }\n }\n },\n onSuccess: (_result, vars) => {\n let definitionKey: readonly unknown[];\n switch (kind) {\n case \"function\":\n definitionKey = functionKey(vars.id);\n break;\n case \"workflow\":\n definitionKey = workflowKey(vars.id);\n break;\n case \"endpoint\":\n definitionKey = endpointKey(vars.id);\n break;\n }\n invalidateSavedCallable(qc, versionsKey(kind, vars.id), definitionKey);\n },\n });\n}\n\n/**\n * `POST /<collection>/:id/versions/:n/{invoke,run}`, an EMPTY JSON body — identical to that\n * kind's unversioned invoke/run route's success body, except the requested version's OWN\n * `impl`/definition runs instead of the live one (T5.3.1's wire contract table). Unlike\n * {@link useRevertMutation}, invoking changes no resource state, so it invalidates History ONLY\n * (`onSettled`, `historyKeys.root` — a version run is a run, failed ones included, like every other\n * run path) and no resource query — the caller (`VersionHistoryModal`) renders the mutation's own `data`/`error` state\n * directly, and that state is naturally cleared whenever the modal remounts for a different\n * version (`SettingsTool.tsx`'s `openVersion` gate fully unmounts/remounts it, never leaves it\n * mounted across a prop change).\n */\nexport function useInvokeVersionMutation(kind: VersionsKind) {\n const apiClient = useEmbedClient();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (vars: {\n id: string;\n versionNumber: number;\n }): Promise<Record<string, unknown>> => {\n // The workflow arm moves to `workflows.runVersion`. The FUNCTION arm (F-P4 / F-6) and the\n // ENDPOINT arm (R-5) stay on `request()`: this hook's caller renders the raw invocation\n // frame, and `functions.runVersion` unwraps the output like `functions.run` — it would drop\n // the frame. The workflow arm returns only `{ runId, status }`, as the raw body did.\n if (kind === \"workflow\") {\n const run = await apiClient.workflows.runVersion(vars.id, vars.versionNumber, {});\n // Project back to the server's own run-start body: the SDK adds `steps`/`terminal`/\n // `httpStatus`, and `VersionHistoryModal` prints this value verbatim as JSON.\n return { runId: run.runId, status: run.status };\n }\n const res = await apiClient.request<Record<string, unknown>>({\n method: \"POST\",\n path: path`/${COLLECTION_PATH[kind]}/${vars.id}/versions/${String(vars.versionNumber)}/${VERSION_INVOKE_VERB[kind]}`,\n body: {},\n });\n return res.body;\n },\n onSettled: () => qc.invalidateQueries({ queryKey: historyKeys.root }),\n });\n}\n","/**\n * The `/<collection>/:id/spec` export repo (T3.3.1) — the Settings rail's Export\n * button. A NEW file, deliberately kept out of `repos/functions.ts` /\n * `repos/endpoints.ts` (T3.1.1 owns both), exactly as T3.2.1 put `/spec/import` in\n * its own `repos/spec-import.ts` for the same reason — the two nodes never\n * collide on the same file.\n *\n * **Goes through `W6WClient.request<T>()`, never `apiClient.console.*`.** There\n * is no SDK method for this route, exactly as `repos/spec-import.ts`'s own\n * docblock records for the sibling `/spec/import` route.\n *\n * `useSpecQuery` is gated on the caller's `enabled` flag (the export modal's own\n * open state) AND `collection !== null` — never on `ctx.kind` alone, and never\n * on mount: the contract pins that opening the Settings panel must issue ZERO\n * `/spec` requests, and exactly one fires per Export click.\n */\nimport { useQuery } from \"@tanstack/react-query\";\nimport { path } from \"@w6w/sdk\";\nimport { useEmbedClient } from \"../draft/client-context.ts\";\n\n/** The collections that carry a `/spec` export route — `specCollectionForKind`\n * (`../lib/rail-settings.ts`) is the sole producer of this type's values. */\nexport type SpecCollection = \"functions\" | \"endpoints\";\n\n/**\n * Mirrors T2.1.1's `SpecDocument`, also mirrored by `repos/spec-import.ts`'s\n * `SpecImportDocument` for the sibling import route: the portable document a\n * `GET /<kind>/:id/spec` export produces. Not a bare `FunctionDef`/`EndpointDef`\n * — `id` is deleted server-side (`admin/spec.ts:96-108`) and connection/var\n * references ride as re-bindable `rebind` entries, never live ids.\n */\nexport interface SpecDocument {\n specVersion: string;\n kind: \"function\" | \"endpoint\" | \"workflow\";\n callable: Record<string, unknown>;\n rebind: unknown[];\n}\n\n/**\n * `GET /<collection>/:id/spec`. `collection` is `null` for a kind the Export\n * button never renders on (`specCollectionForKind`'s `workflow`/`connection`\n * arms) — passing `null` disables the query regardless of `enabled`, so a\n * caller need not re-derive that guard itself.\n */\nexport function useSpecQuery(collection: SpecCollection | null, id: string, enabled: boolean) {\n const apiClient = useEmbedClient();\n return useQuery({\n queryKey: [\"spec\", collection, id],\n queryFn: async () => {\n const res = await apiClient.request<{ spec: SpecDocument }>({\n method: \"GET\",\n path: path`/${collection as SpecCollection}/${id}/spec`,\n });\n return res.body.spec;\n },\n enabled: enabled && collection !== null,\n });\n}\n"],"names":["endpointKey","id","callableKey","functionKey","COLLECTION_PATH","VERSION_INVOKE_VERB","versionsKey","kind","versionKey","versionNumber","useVersionsQuery","enabled","apiClient","useEmbedClient","useQuery","path","useVersionQuery","n","usePublishMutation","qc","useQueryClient","useMutation","_result","useSetEnabledMutation","vars","useRevertMutation","definitionKey","workflowKey","invalidateSavedCallable","useInvokeVersionMutation","run","historyKeys","useSpecQuery","collection"],"mappings":"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"}