@w6w/embed 0.0.0-stage → 0.1.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 (102) hide show
  1. package/LICENSE +105 -0
  2. package/README.md +166 -2
  3. package/dist/W6WEmbedProvider.d.ts +29 -0
  4. package/dist/chrome/CallFromCodeButton.d.ts +155 -0
  5. package/dist/chrome/CallableSettingsModal.d.ts +17 -0
  6. package/dist/chrome/ConfirmModal.d.ts +20 -0
  7. package/dist/chrome/DangerZone.d.ts +19 -0
  8. package/dist/chrome/ExecutionProfileHeader.d.ts +69 -0
  9. package/dist/chrome/HistoryButton.d.ts +8 -0
  10. package/dist/chrome/HistoryModal.d.ts +9 -0
  11. package/dist/chrome/HistoryView.d.ts +15 -0
  12. package/dist/chrome/ImportSpecModal.d.ts +40 -0
  13. package/dist/chrome/JsonToggle.d.ts +51 -0
  14. package/dist/chrome/Modal.d.ts +20 -0
  15. package/dist/chrome/RightRail.d.ts +24 -0
  16. package/dist/chrome/TagEditor.d.ts +23 -0
  17. package/dist/chrome/VersionHistoryModal.d.ts +38 -0
  18. package/dist/chrome/history-open-run.d.ts +7 -0
  19. package/dist/chrome/index.d.ts +36 -0
  20. package/dist/chrome/workspace.d.ts +67 -0
  21. package/dist/client-context-CX61Bgw-.js +16 -0
  22. package/dist/client-context-CX61Bgw-.js.map +1 -0
  23. package/dist/draft/autosave-flush.d.ts +63 -0
  24. package/dist/draft/autosave.d.ts +68 -0
  25. package/dist/draft/client-context.d.ts +8 -0
  26. package/dist/draft/draft-registry.d.ts +14 -0
  27. package/dist/draft/index.d.ts +15 -0
  28. package/dist/draft/use-workflow-draft.d.ts +67 -0
  29. package/dist/draft/workflow-save.d.ts +48 -0
  30. package/dist/draft-registry-YF0tqNN0.js +49 -0
  31. package/dist/draft-registry-YF0tqNN0.js.map +1 -0
  32. package/dist/draft.d.ts +2 -0
  33. package/dist/draft.mjs +18 -0
  34. package/dist/draft.mjs.map +1 -0
  35. package/dist/editor/WorkflowEditor.d.ts +12 -0
  36. package/dist/editor/WorkflowSettingsModal.d.ts +17 -0
  37. package/dist/editor/definition.d.ts +31 -0
  38. package/dist/editor/editor-apps.d.ts +7 -0
  39. package/dist/editor/types.d.ts +34 -0
  40. package/dist/editor.d.ts +9 -0
  41. package/dist/editor.mjs +2170 -0
  42. package/dist/editor.mjs.map +1 -0
  43. package/dist/index.d.ts +1 -0
  44. package/dist/index.mjs +67 -0
  45. package/dist/index.mjs.map +1 -0
  46. package/dist/lib/callable-descriptors.d.ts +77 -0
  47. package/dist/lib/callable-kind.d.ts +13 -0
  48. package/dist/lib/code-rail.d.ts +45 -0
  49. package/dist/lib/document-sources.d.ts +26 -0
  50. package/dist/lib/error-handler-self.d.ts +25 -0
  51. package/dist/lib/history-query.d.ts +135 -0
  52. package/dist/lib/import-paste.d.ts +41 -0
  53. package/dist/lib/index.d.ts +17 -0
  54. package/dist/lib/new-id.d.ts +10 -0
  55. package/dist/lib/rail-settings.d.ts +196 -0
  56. package/dist/lib/save-invalidation.d.ts +24 -0
  57. package/dist/lib/sdk-snippets.d.ts +96 -0
  58. package/dist/lib/settings-rail.d.ts +68 -0
  59. package/dist/lib/slug.d.ts +69 -0
  60. package/dist/lib/spec-import-invalidation.d.ts +48 -0
  61. package/dist/lib/tag-editor.d.ts +36 -0
  62. package/dist/lib/trigger-preview.d.ts +89 -0
  63. package/dist/lib/workflow-live-run.d.ts +165 -0
  64. package/dist/lib/workflow-poll.d.ts +8 -0
  65. package/dist/lib/workflow-route.d.ts +26 -0
  66. package/dist/lib/workflow-settings.d.ts +72 -0
  67. package/dist/lib/workflow-validity.d.ts +92 -0
  68. package/dist/lib/workflow-variables.d.ts +106 -0
  69. package/dist/lib.d.ts +2 -0
  70. package/dist/lib.mjs +62 -0
  71. package/dist/lib.mjs.map +1 -0
  72. package/dist/project-context-Dbk0Gr1K.js +16 -0
  73. package/dist/project-context-Dbk0Gr1K.js.map +1 -0
  74. package/dist/project-context.d.ts +11 -0
  75. package/dist/rail/CodeTool.d.ts +2 -0
  76. package/dist/rail/ErrorHandlingTool.d.ts +22 -0
  77. package/dist/rail/ExpressionScope.d.ts +21 -0
  78. package/dist/rail/SettingsTool.d.ts +27 -0
  79. package/dist/rail/editor-tools.d.ts +2 -0
  80. package/dist/rail/rail-env.d.ts +18 -0
  81. package/dist/rail/settings-sections.d.ts +93 -0
  82. package/dist/repos/documents.d.ts +102 -0
  83. package/dist/repos/history.d.ts +24 -0
  84. package/dist/repos/index.d.ts +22 -0
  85. package/dist/repos/spec-import.d.ts +44 -0
  86. package/dist/repos/step-tests.d.ts +19 -0
  87. package/dist/repos/vars.d.ts +25 -0
  88. package/dist/repos/vault.d.ts +24 -0
  89. package/dist/repos/versions.d.ts +112 -0
  90. package/dist/repos.d.ts +2 -0
  91. package/dist/repos.mjs +94 -0
  92. package/dist/repos.mjs.map +1 -0
  93. package/dist/slug-ByKQgxrf.js +642 -0
  94. package/dist/slug-ByKQgxrf.js.map +1 -0
  95. package/dist/spec-import-HgO7ZkLZ.js +898 -0
  96. package/dist/spec-import-HgO7ZkLZ.js.map +1 -0
  97. package/dist/spec-import-invalidation-D3retX4Q.js +18 -0
  98. package/dist/spec-import-invalidation-D3retX4Q.js.map +1 -0
  99. package/dist/use-workflow-draft-oI02dsP-.js +314 -0
  100. package/dist/use-workflow-draft-oI02dsP-.js.map +1 -0
  101. package/package.json +71 -3
  102. package/src/styles.css +829 -0
@@ -0,0 +1 @@
1
+ export { W6WEmbedProvider, type W6WEmbedProviderProps } from './W6WEmbedProvider.tsx';
package/dist/index.mjs ADDED
@@ -0,0 +1,67 @@
1
+ "use client";
2
+ import { jsx as r } from "react/jsx-runtime";
3
+ import { QueryClientProvider as w, QueryClient as R } from "@tanstack/react-query";
4
+ import { W6WProvider as j, useW6WClient as h, createW6WUiAdapter as S } from "@w6w/react";
5
+ import { W6WUIProvider as U } from "@w6w/ui";
6
+ import { useState as u, useRef as y, useEffect as C, useMemo as x } from "react";
7
+ import { E as A } from "./client-context-CX61Bgw-.js";
8
+ import { c as D, D as Q } from "./draft-registry-YF0tqNN0.js";
9
+ import { E as B } from "./project-context-Dbk0Gr1K.js";
10
+ function W() {
11
+ return new R({
12
+ defaultOptions: { queries: { retry: !1, refetchOnWindowFocus: !1 } }
13
+ });
14
+ }
15
+ function K({ children: t }) {
16
+ return /* @__PURE__ */ r(A, { client: h(), children: t });
17
+ }
18
+ function O({ theme: t, children: o }) {
19
+ const e = h(), s = x(() => S(e), [e]);
20
+ return /* @__PURE__ */ r(U, { api: s, theme: t, children: o });
21
+ }
22
+ function L({
23
+ apiOrigin: t,
24
+ getSession: o,
25
+ identityKey: e,
26
+ theme: s,
27
+ ready: g,
28
+ project: f,
29
+ fetch: v,
30
+ children: P
31
+ }) {
32
+ const [c] = u(D), [i, E] = u(() => ({
33
+ identityKey: e,
34
+ queryClient: W()
35
+ })), b = e !== i.identityKey, d = y({ apiOrigin: t, project: f, getSession: o });
36
+ b || (d.current = { apiOrigin: t, project: f, getSession: o });
37
+ const n = d.current, a = y(n.getSession);
38
+ a.current = n.getSession;
39
+ const [q] = u(() => () => a.current());
40
+ C(() => {
41
+ if (e === i.identityKey) return;
42
+ let m = !1;
43
+ const p = () => {
44
+ m || E({ identityKey: e, queryClient: W() });
45
+ };
46
+ return c.flushAll().then(p, p), () => {
47
+ m = !0;
48
+ };
49
+ }, [e, i.identityKey, c]);
50
+ const l = i.queryClient;
51
+ return C(() => () => l.clear(), [l]), /* @__PURE__ */ r(Q, { registry: c, children: /* @__PURE__ */ r(w, { client: l, children: /* @__PURE__ */ r(
52
+ j,
53
+ {
54
+ baseUrl: n.apiOrigin,
55
+ getSession: q,
56
+ identityKey: i.identityKey,
57
+ ready: g,
58
+ project: n.project,
59
+ fetch: v,
60
+ children: /* @__PURE__ */ r(B.Provider, { value: n.project, children: /* @__PURE__ */ r(K, { children: /* @__PURE__ */ r(O, { theme: s, children: P }) }) })
61
+ }
62
+ ) }, i.identityKey) });
63
+ }
64
+ export {
65
+ L as W6WEmbedProvider
66
+ };
67
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","sources":["../src/W6WEmbedProvider.tsx"],"sourcesContent":["import { QueryClient, QueryClientProvider } from \"@tanstack/react-query\";\n/**\n * `<W6WEmbedProvider>` — everything an embedded w6w surface needs from a host, behind one\n * element: an identity-scoped `QueryClient`, a `@w6w/react` `<W6WProvider>` (client, session\n * renewal, per-request token) and `@w6w/ui`'s `<W6WUIProvider>` fed by `createW6WUiAdapter`.\n * It composes the three public pieces exactly as `@w6w/react`'s README bridge does: it never\n * spreads or patches the adapter, never reaches into `client.console`, and keeps no session\n * store of its own (`getSession` goes straight to `<W6WProvider>`).\n *\n * **Identity cache.** The `QueryClient` is owned here, not borrowed from the host, and it is a\n * NEW instance whenever `identityKey` changes — so a query cached while signed in as account A\n * is unreachable once the host switches to B. A new client alone is NOT enough: a mounted\n * `useQuery` keeps the `QueryObserver` it was born with, and that observer is bound to the client\n * it was created against, so a child that survives the swap would keep rendering A's cache. The\n * subtree is therefore also re-mounted (`key`), which drops every observer and every piece of\n * child state from the previous identity. The client, the `key` and the tuple handed to\n * `<W6WProvider>` all change in ONE state update: there is no render in which B's tree reads A's\n * cache. The old client is cleared once it is no longer mounted.\n *\n * **Identity switch (flush first).** A draft with a pending save must be written into the account\n * that produced the edit. When `identityKey` changes this provider therefore HOLDS the applied\n * tuple — `identityKey`, `apiOrigin`, `project`, `getSession`, the client — and keeps handing the\n * OLD one to `<W6WProvider>`, awaits `registry.flushAll()` (bounded, never rejects), and only then\n * applies the new tuple in a single update. `<W6WProvider>` swaps its client synchronously on a\n * new `identityKey` and detaches the old session store, so the flush must finish first; and the\n * new `getSession` is NOT forwarded early: `<W6WProvider>` reaches it through the stable wrapper\n * below, whose target is swapped in the same update as the tuple (forwarded early, the new\n * account's token would be minted on the old client). A flush that fails or times out still lets\n * the switch proceed (Q6) and is never retried with the new identity. A token rotation under an\n * unchanged `identityKey` is not a switch: it is forwarded at once, no hold.\n */\nimport { W6WProvider, type W6WSession, createW6WUiAdapter, useW6WClient } from \"@w6w/react\";\nimport type { FetchLike } from \"@w6w/sdk\";\nimport { type ThemeMode, W6WUIProvider } from \"@w6w/ui\";\nimport { type ReactNode, useEffect, useMemo, useRef, useState } from \"react\";\nimport { DraftRegistryProvider, EmbedClientProvider, createDraftRegistry } from \"./draft/index.ts\";\nimport { EmbedProjectContext } from \"./project-context.ts\";\n\nexport interface W6WEmbedProviderProps {\n /** The w6w API origin, e.g. `\"https://api.w6w.io\"`. */\n apiOrigin: string;\n /**\n * Mints a session for the CURRENT host user (`{token, expiresAt, expiresIn?}`). Always the\n * latest callback; the provider caches and renews the result.\n */\n getSession: () => Promise<W6WSession>;\n /**\n * Which signed-in identity this provider speaks for (e.g. `${userId}:${accountId}`). Changing it\n * rebuilds the API client AND replaces the `QueryClient`, so nothing cached for the previous\n * identity is ever shown under the new one.\n */\n identityKey: string;\n /** Force the `@w6w/ui` theme to follow the host's. Omit to resolve it the library's default way. */\n theme?: ThemeMode;\n /** Gates every read hook while `false` (default `true`) — e.g. until the host has a user. */\n ready?: boolean;\n /** Default project id for project-scoped operations. */\n project?: string;\n /** Transport override (tests, request recording). Defaults to `globalThis.fetch`. */\n fetch?: FetchLike;\n children: ReactNode;\n}\n\nfunction makeQueryClient(): QueryClient {\n // Same defaults as Studio's own client (`studio/src/main.tsx`).\n return new QueryClient({\n defaultOptions: { queries: { retry: false, refetchOnWindowFocus: false } },\n });\n}\n\n/** The part of the tuple that changes only when a switch has been APPLIED (after the flush). */\ninterface Applied {\n identityKey: string;\n queryClient: QueryClient;\n}\n\n/** What `<W6WProvider>` is fed while no switch is in progress; frozen at the last such render. */\ninterface Forwarded {\n apiOrigin: string;\n project: string | undefined;\n getSession: () => Promise<W6WSession>;\n}\n\n/** Hands the SDK client of the nearest `<W6WProvider>` to `useWorkflowDraft`. */\nfunction ClientBridge({ children }: { children: ReactNode }) {\n return <EmbedClientProvider client={useW6WClient()}>{children}</EmbedClientProvider>;\n}\n\n/** The README bridge: `useW6WClient` -> `createW6WUiAdapter` -> `<W6WUIProvider>`. */\nfunction UiBridge({ theme, children }: { theme?: ThemeMode; children: ReactNode }) {\n const client = useW6WClient();\n const api = useMemo(() => createW6WUiAdapter(client), [client]);\n return (\n <W6WUIProvider api={api} theme={theme}>\n {children}\n </W6WUIProvider>\n );\n}\n\nexport function W6WEmbedProvider({\n apiOrigin,\n getSession,\n identityKey,\n theme,\n ready,\n project,\n fetch,\n children,\n}: W6WEmbedProviderProps): ReactNode {\n const [registry] = useState(createDraftRegistry);\n const [applied, setApplied] = useState<Applied>(() => ({\n identityKey,\n queryClient: makeQueryClient(),\n }));\n\n // While `identityKey` differs from the applied one a switch is pending: everything below keeps\n // using the values frozen at the last render that was not pending. Otherwise props flow straight\n // through (project / origin changes, token rotation). Idempotent latest-value writes, the same\n // pattern `<W6WProvider>` uses for its own refs.\n const switching = identityKey !== applied.identityKey;\n const forwardedRef = useRef<Forwarded>({ apiOrigin, project, getSession });\n if (!switching) forwardedRef.current = { apiOrigin, project, getSession };\n const forwarded = forwardedRef.current;\n\n // The stable `getSession` handed to `<W6WProvider>`: reads whatever is applied RIGHT NOW. Its\n // target changes in the same render that applies the new tuple, never before the flush settles.\n const sessionRef = useRef(forwarded.getSession);\n sessionRef.current = forwarded.getSession;\n const [stableGetSession] = useState(() => () => sessionRef.current());\n\n useEffect(() => {\n if (identityKey === applied.identityKey) return;\n let cancelled = false;\n const apply = () => {\n if (cancelled) return;\n setApplied({ identityKey, queryClient: makeQueryClient() });\n };\n // `flushAll` never rejects and is bounded; the switch proceeds either way (Q6).\n registry.flushAll().then(apply, apply);\n return () => {\n cancelled = true;\n };\n }, [identityKey, applied.identityKey, registry]);\n\n // The replaced client is dropped once nothing mounted reads it.\n const queryClient = applied.queryClient;\n useEffect(() => () => queryClient.clear(), [queryClient]);\n\n return (\n <DraftRegistryProvider registry={registry}>\n <QueryClientProvider key={applied.identityKey} client={queryClient}>\n <W6WProvider\n baseUrl={forwarded.apiOrigin}\n getSession={stableGetSession}\n identityKey={applied.identityKey}\n ready={ready}\n project={forwarded.project}\n fetch={fetch}\n >\n <EmbedProjectContext.Provider value={forwarded.project}>\n <ClientBridge>\n <UiBridge theme={theme}>{children}</UiBridge>\n </ClientBridge>\n </EmbedProjectContext.Provider>\n </W6WProvider>\n </QueryClientProvider>\n </DraftRegistryProvider>\n );\n}\n"],"names":["makeQueryClient","QueryClient","ClientBridge","children","jsx","EmbedClientProvider","useW6WClient","UiBridge","theme","client","api","useMemo","createW6WUiAdapter","W6WUIProvider","W6WEmbedProvider","apiOrigin","getSession","identityKey","ready","project","fetch","registry","useState","createDraftRegistry","applied","setApplied","switching","forwardedRef","useRef","forwarded","sessionRef","stableGetSession","useEffect","cancelled","apply","queryClient","DraftRegistryProvider","QueryClientProvider","W6WProvider","EmbedProjectContext"],"mappings":";;;;;;;;;AA+DA,SAASA,IAA+B;AAEtC,SAAO,IAAIC,EAAY;AAAA,IACrB,gBAAgB,EAAE,SAAS,EAAE,OAAO,IAAO,sBAAsB,KAAM;AAAA,EAAE,CAC1E;AACH;AAgBA,SAASC,EAAa,EAAE,UAAAC,KAAqC;AAC3D,SAAO,gBAAAC,EAACC,GAAA,EAAoB,QAAQC,EAAA,GAAiB,UAAAH,GAAS;AAChE;AAGA,SAASI,EAAS,EAAE,OAAAC,GAAO,UAAAL,KAAwD;AACjF,QAAMM,IAASH,EAAA,GACTI,IAAMC,EAAQ,MAAMC,EAAmBH,CAAM,GAAG,CAACA,CAAM,CAAC;AAC9D,SACE,gBAAAL,EAACS,GAAA,EAAc,KAAAH,GAAU,OAAAF,GACtB,UAAAL,EAAA,CACH;AAEJ;AAEO,SAASW,EAAiB;AAAA,EAC/B,WAAAC;AAAA,EACA,YAAAC;AAAA,EACA,aAAAC;AAAA,EACA,OAAAT;AAAA,EACA,OAAAU;AAAA,EACA,SAAAC;AAAA,EACA,OAAAC;AAAA,EACA,UAAAjB;AACF,GAAqC;AACnC,QAAM,CAACkB,CAAQ,IAAIC,EAASC,CAAmB,GACzC,CAACC,GAASC,CAAU,IAAIH,EAAkB,OAAO;AAAA,IACrD,aAAAL;AAAA,IACA,aAAajB,EAAA;AAAA,EAAgB,EAC7B,GAMI0B,IAAYT,MAAgBO,EAAQ,aACpCG,IAAeC,EAAkB,EAAE,WAAAb,GAAW,SAAAI,GAAS,YAAAH,GAAY;AACzE,EAAKU,MAAWC,EAAa,UAAU,EAAE,WAAAZ,GAAW,SAAAI,GAAS,YAAAH,EAAA;AAC7D,QAAMa,IAAYF,EAAa,SAIzBG,IAAaF,EAAOC,EAAU,UAAU;AAC9C,EAAAC,EAAW,UAAUD,EAAU;AAC/B,QAAM,CAACE,CAAgB,IAAIT,EAAS,MAAM,MAAMQ,EAAW,SAAS;AAEpE,EAAAE,EAAU,MAAM;AACd,QAAIf,MAAgBO,EAAQ,YAAa;AACzC,QAAIS,IAAY;AAChB,UAAMC,IAAQ,MAAM;AAClB,MAAID,KACJR,EAAW,EAAE,aAAAR,GAAa,aAAajB,EAAA,GAAmB;AAAA,IAC5D;AAEA,WAAAqB,EAAS,SAAA,EAAW,KAAKa,GAAOA,CAAK,GAC9B,MAAM;AACX,MAAAD,IAAY;AAAA,IACd;AAAA,EACF,GAAG,CAAChB,GAAaO,EAAQ,aAAaH,CAAQ,CAAC;AAG/C,QAAMc,IAAcX,EAAQ;AAC5B,SAAAQ,EAAU,MAAM,MAAMG,EAAY,SAAS,CAACA,CAAW,CAAC,qBAGrDC,GAAA,EAAsB,UAAAf,GACrB,UAAA,gBAAAjB,EAACiC,GAAA,EAA8C,QAAQF,GACrD,UAAA,gBAAA/B;AAAA,IAACkC;AAAA,IAAA;AAAA,MACC,SAAST,EAAU;AAAA,MACnB,YAAYE;AAAA,MACZ,aAAaP,EAAQ;AAAA,MACrB,OAAAN;AAAA,MACA,SAASW,EAAU;AAAA,MACnB,OAAAT;AAAA,MAEA,UAAA,gBAAAhB,EAACmC,EAAoB,UAApB,EAA6B,OAAOV,EAAU,SAC7C,UAAA,gBAAAzB,EAACF,GAAA,EACC,UAAA,gBAAAE,EAACG,GAAA,EAAS,OAAAC,GAAe,UAAAL,EAAA,CAAS,GACpC,EAAA,CACF;AAAA,IAAA;AAAA,EAAA,KAbsBqB,EAAQ,WAelC,GACF;AAEJ;"}
@@ -0,0 +1,77 @@
1
+ import { CallableKind } from './callable-kind.ts';
2
+ export type { CallableKind };
3
+ /** The Settings modal's own per-kind behaviour (T4.2.1's formalization of the
4
+ * seven `kind ===` conditionals `CallableSettingsModal.tsx` used to carry). */
5
+ export interface CallableSettingsDescriptor {
6
+ /** May the `key` be typed here at all? Function/Workflow yes, Endpoint no
7
+ * (`rfcs/endpoint.md` — an Endpoint's address is its identity). */
8
+ canEditKey: boolean;
9
+ /** Does this kind store tags? Workflow only. */
10
+ hasTags: boolean;
11
+ /** Placeholder for the Name field. */
12
+ namePlaceholder: string;
13
+ /** Placeholder for the Key field (read only when {@link canEditKey}). */
14
+ keyPlaceholder: string;
15
+ /** Appended to the shared "Lowercase, kebab-case, 3–39 characters." hint —
16
+ * `""` for a kind that cannot unset its key, the "Leave empty to unset."
17
+ * sentence for the one that can. */
18
+ keyHintSuffix: string;
19
+ }
20
+ /** The editor chrome's own per-kind copy. */
21
+ export interface CallableEditorDescriptor {
22
+ /** The back control's label, e.g. `"← Functions"`. */
23
+ backLabel: string;
24
+ /** Heading fallback while the definition is still hydrating. */
25
+ newTitle: string;
26
+ /** Rendered in place of the form when the hydration GET 404s. */
27
+ notFoundTitle: string;
28
+ /** The Save button's idle label. */
29
+ saveLabel: string;
30
+ }
31
+ export interface CallableDescriptor {
32
+ kind: CallableKind;
33
+ /** The list page's `<h2>`, and the editor document title's second segment. */
34
+ listTitle: string;
35
+ /** The list page's explanatory paragraph. */
36
+ listDescription: string;
37
+ /** The empty-state paragraph (verbatim, including its typographic quotes). */
38
+ emptyCopy: string;
39
+ /** The create button's label, e.g. `"+ New function"`. */
40
+ newLabel: string;
41
+ /** The synthetic id's own prefix — `fn_…`/`ep_…`/`wf_…`, never user-edited. */
42
+ newIdPrefix: string;
43
+ /** `data-testid` of the list's Import affordance. */
44
+ importOpenTestId: string;
45
+ /** `data-testid` of the list's "Show archived" checkbox. */
46
+ showArchivedTestId: string;
47
+ /** `data-testid` of a row's "archived" badge. */
48
+ archivedBadgeTestId: string;
49
+ /** The row button's `title` tooltip (T4.2.3 — replaces the shared template literal
50
+ * `` `Open this ${kind} in the editor.` ``, since Workflow's own row opens the visual editor,
51
+ * not "the editor"). */
52
+ openRowTitle: string;
53
+ editor: CallableEditorDescriptor;
54
+ settings: CallableSettingsDescriptor;
55
+ }
56
+ /**
57
+ * The three kinds, every arm named explicitly — a total `Record<CallableKind,
58
+ * …>`, so a fourth kind fails to compile here rather than silently rendering
59
+ * another kind's copy (the same reasoning `COLLECTION_PATH` gives in
60
+ * `src/repos/versions.ts`).
61
+ *
62
+ * Only the `function` arm is consumed today: Endpoints and Workflows keep their
63
+ * own pages until T4.2.2/T4.2.3. Their arms are filled from those pages'
64
+ * current literals so the later nodes are a deletion, not a re-derivation.
65
+ */
66
+ export declare const CALLABLE_DESCRIPTORS: Record<CallableKind, CallableDescriptor>;
67
+ /** Look a descriptor up by kind. A plain index, never a `switch`: the `Record`
68
+ * above already made every arm total. */
69
+ export declare function descriptorFor(kind: CallableKind): CallableDescriptor;
70
+ /**
71
+ * A fresh synthetic id for a create-modal's first POST — `fn_<uuid>` for a
72
+ * Function (verbatim the `newFunctionId` `FunctionsPage.tsx` used to hold),
73
+ * `ep_`/`wf_` for the other two, whose pages mint the same shapes today. The
74
+ * prefix comes from the descriptor, so "which kind is this?" is answered by the
75
+ * same table that answers every other kind question.
76
+ */
77
+ export declare function newCallableId(kind: CallableKind): string;
@@ -0,0 +1,13 @@
1
+ /**
2
+ * The three callable kinds and the single-resource query key per kind.
3
+ *
4
+ * Moved verbatim out of Studio's `repos/callables.ts` (`CallableKind`, `callableKey` and the one
5
+ * pure table `callableKey` closes over, `RESOURCE_KEY`) so `repos/versions.ts` — which ships in
6
+ * this package for all three kind arms — can invalidate a definition by key without importing a
7
+ * Studio module. `repos/callables.ts` imports these from `@w6w/embed/repos` and does NOT re-export
8
+ * them. No React, no client: loadable by `node --test`.
9
+ */
10
+ /** The three kinds the callable repos are total over. */
11
+ export type CallableKind = "function" | "endpoint" | "workflow";
12
+ /** `GET /<coll>/:id`'s own query key — the literal `lib/save-invalidation.ts` invalidates. */
13
+ export declare function callableKey(kind: CallableKind, id: string): readonly unknown[];
@@ -0,0 +1,45 @@
1
+ import { SnippetCallable, SnippetInput } from './sdk-snippets.ts';
2
+ /** Structural mirror of T2.1.2's widened `WorkspaceCallable` (`src/ui/workspace.tsx`). */
3
+ export type RailCallable = {
4
+ kind: "function";
5
+ id: string;
6
+ key?: string;
7
+ inputs?: readonly SnippetInput[];
8
+ alias?: string;
9
+ } | {
10
+ kind: "endpoint";
11
+ id: string;
12
+ key?: string;
13
+ invokeUrl?: string;
14
+ invokeUrlByKey?: string;
15
+ urlForm?: "id" | "key";
16
+ alias?: string;
17
+ inputs?: readonly SnippetInput[];
18
+ } | {
19
+ kind: "workflow";
20
+ id: string;
21
+ label?: string;
22
+ key?: string;
23
+ } | {
24
+ kind: "connection";
25
+ id: string;
26
+ } | null;
27
+ /**
28
+ * Is a "Call from code" panel meaningful for this context? Mirrors
29
+ * `alias-rail.ts`'s `targetForCallable` fail-closed shape exactly (its own
30
+ * comment: *"'connection' and no resource at all both fail closed to null —
31
+ * house style"*) — `"connection"` and `null` both answer `false`.
32
+ */
33
+ export declare function isAvailable(ctx: RailCallable): boolean;
34
+ /**
35
+ * The widened-union -> `SnippetCallable` conversion `CodeTool.Panel` hands to
36
+ * `CallFromCodeBody`. `null` for a context this tool has no snippet for
37
+ * (`"connection"`, or no resource at all) — defensive, since `isAvailable`
38
+ * already keeps the tool off the strip for those.
39
+ *
40
+ * The one easy-to-miss field: `WorkspaceCallable`'s `label` maps to
41
+ * `SnippetCallable`'s `workflow` arm's `displayName` — NOT the same field
42
+ * name. A naive `{...ctx}` spread compiles (both optional) but silently
43
+ * drops the label everywhere it matters, never caught by `tsc`.
44
+ */
45
+ export declare function toSnippetCallable(ctx: RailCallable): SnippetCallable | null;
@@ -0,0 +1,26 @@
1
+ import { Doc } from '@w6w/sdk';
2
+ /** One document's contribution to `ExpressionOptions.documents` — structurally
3
+ * identical to `@w6w/ui`'s (unexported) `ExpressionDocumentSource`. */
4
+ export interface DocumentSource {
5
+ key: string;
6
+ fields?: {
7
+ key: string;
8
+ }[];
9
+ }
10
+ /**
11
+ * The `ExpressionOptions.documents` array: `{ key }` for every document, plus
12
+ * `fields` (raw, unfiltered top-level keys) when the gate holds AND the
13
+ * parsed object has at least one key. `fields` is OMITTED (not `[]`) both
14
+ * when the gate fails and when it holds but yields zero keys — a consumer
15
+ * must be able to tell "nothing declared" from "declared none".
16
+ */
17
+ export declare function projectDocumentSources(docs: Doc[]): DocumentSource[];
18
+ /**
19
+ * The `sampleValues` entries the ƒx Result preview substitutes for document
20
+ * refs: `documents.<key>` → the document's raw content, for every document
21
+ * (unconditional, exactly as before this project), PLUS `documents.<key>.<field>`
22
+ * → the field's own parsed value, for the gated set only. Without the second
23
+ * half, every field ref this project newly makes pickable would preview as
24
+ * the empty string (`renderResult` does an exact flat-key lookup).
25
+ */
26
+ export declare function documentSampleValues(docs: Doc[]): Record<string, unknown>;
@@ -0,0 +1,25 @@
1
+ /**
2
+ * The authoring-time half of the error-handler recursion guard. The server
3
+ * compares resolved values at dispatch time; this small, pure decision keeps
4
+ * the rail from creating the known-identical no-adapter case in the first
5
+ * place without losing an adapter imported or authored elsewhere.
6
+ */
7
+ export type ErrorHandlerSelfDecision = "allow" | "warn" | "block";
8
+ export interface ErrorHandlerSelfInput {
9
+ resource: {
10
+ kind: string;
11
+ id: string;
12
+ };
13
+ target: {
14
+ kind: string;
15
+ id: string;
16
+ };
17
+ hasAdapter: boolean;
18
+ }
19
+ /**
20
+ * Only Function and Workflow targets can re-enter the currently edited
21
+ * resource. Actions are always allowed. A self-target with no adapter passes
22
+ * the failed input through unchanged, so it is refused; an adapter is kept
23
+ * and called out because only the runtime can determine its resolved values.
24
+ */
25
+ export declare function errorHandlerSelfDecision({ resource, target, hasAdapter, }: ErrorHandlerSelfInput): ErrorHandlerSelfDecision;
@@ -0,0 +1,135 @@
1
+ import { W6WClient } from '@w6w/sdk';
2
+ export type ExecutionKind = "function" | "endpoint" | "workflow";
3
+ export type ExecutionStatus = "queued" | "running" | "succeeded" | "failed" | "canceled";
4
+ export interface ExecutionSummary {
5
+ id: string;
6
+ kind: ExecutionKind;
7
+ callableId: string;
8
+ callableName: string;
9
+ status: ExecutionStatus;
10
+ startedAt: string;
11
+ finishedAt: string | null;
12
+ durationMs: number | null;
13
+ workflowRunId: string | null;
14
+ }
15
+ export interface ExecutionStats {
16
+ total: number;
17
+ succeeded: number;
18
+ failed: number;
19
+ canceled: number;
20
+ inFlight: number;
21
+ successRate: number | null;
22
+ avgDurationMs: number | null;
23
+ }
24
+ /** Either the project-wide view or one callable's own history — mutually
25
+ * exclusive, never both, mirroring the wire's own `project`|`callable`
26
+ * params (exactly one). */
27
+ export type HistoryScope = {
28
+ project: string;
29
+ } | {
30
+ callable: string;
31
+ };
32
+ /** Everything the History page's filter chrome can set, already parsed out
33
+ * of the URL. `status`/`kind` are `""` for "any"; `from`/`to` are the
34
+ * `YYYY-MM-DD` the date pickers hand back, or `""` for unset; `offset` is
35
+ * always a non-negative integer (0 for "first page"). */
36
+ export interface HistoryFilters {
37
+ status: ExecutionStatus | "";
38
+ kind: ExecutionKind | "";
39
+ from: string;
40
+ to: string;
41
+ q: string;
42
+ offset: number;
43
+ }
44
+ export declare const EMPTY_HISTORY_FILTERS: HistoryFilters;
45
+ export declare const HISTORY_PAGE_SIZE = 25;
46
+ /**
47
+ * URL search string → `HistoryFilters`. An unrecognised `status`/`kind`, a
48
+ * `from`/`to` not matching `YYYY-MM-DD`, or a non-integer/negative `offset`
49
+ * all fall back to their empty/zero default rather than carrying a bogus
50
+ * value forward into a request — a stale or hand-edited URL degrades to "no
51
+ * filter" instead of erroring.
52
+ */
53
+ export declare function filtersFromSearch(search: string): HistoryFilters;
54
+ /**
55
+ * `HistoryFilters` → URL search string. `""` when every field is at its
56
+ * default, else a leading-`?` string with only the non-default fields, in
57
+ * the pinned key order `status,kind,from,to,q,offset` (so two renders of the
58
+ * same filters always produce byte-identical URLs — stable for bookmarking
59
+ * and for `filtersFromSearch` round-tripping).
60
+ */
61
+ export declare function filtersToSearch(f: HistoryFilters): string;
62
+ /**
63
+ * `HistoryFilters` + a scope → the wire's own query params (D3/pinned rules).
64
+ * `kind` is sent only for a project scope with a non-empty kind — a
65
+ * per-callable view already knows its one kind, and the server's `kind`
66
+ * param is project-mode-only. `from`/`to` are expanded from the picked
67
+ * calendar day into the half-open `[from, to)` ISO instant range the wire
68
+ * wants — `to` is the NEXT day's midnight so the picked day itself is fully
69
+ * inclusive. `q` is trimmed and omitted when blank (server-side id/name
70
+ * search, D3 — never a payload scan). Paging params are added only when
71
+ * `opts.paged`: `limit` always (defaulting to `HISTORY_PAGE_SIZE`), `offset`
72
+ * only when it would change anything (`> 0`).
73
+ */
74
+ export declare function historyRequestQuery(scope: HistoryScope, f: HistoryFilters, opts: {
75
+ paged: boolean;
76
+ limit?: number;
77
+ }): Record<string, string>;
78
+ /**
79
+ * Every key this domain reads or invalidates. `list`/`stats` carry the full
80
+ * scope and filters object so two distinct filter sets never collide on the
81
+ * same cache entry (and the identical pair always do) — react-query's own
82
+ * structural key hashing does the rest.
83
+ */
84
+ export declare const historyKeys: {
85
+ root: readonly ["history"];
86
+ list(scope: HistoryScope, f: HistoryFilters, limit: number): readonly unknown[];
87
+ stats(scope: HistoryScope, f: HistoryFilters): readonly unknown[];
88
+ exists(callableId: string): readonly ["history", "exists", string];
89
+ detail(kind: ExecutionKind, id: string): readonly ["history", "detail", ExecutionKind, string];
90
+ };
91
+ /** `GET /history` — paged. */
92
+ export declare function getHistory(client: W6WClient, scope: HistoryScope, f: HistoryFilters, limit?: number): Promise<{
93
+ executions: ExecutionSummary[];
94
+ hasMore: boolean;
95
+ }>;
96
+ /** `GET /history/stats` — unpaged (no `limit`/`offset`). */
97
+ export declare function getHistoryStats(client: W6WClient, scope: HistoryScope, f: HistoryFilters): Promise<ExecutionStats>;
98
+ /** One execution's full detail — the shape `ExecutionDetail` (`@w6w/ui`,
99
+ * T2.2.2) renders. `steps` is present only for a workflow run; a
100
+ * function/endpoint invocation has none. */
101
+ export interface ExecutionDetailData {
102
+ id: string;
103
+ kind: ExecutionKind;
104
+ callableName: string;
105
+ status: ExecutionStatus;
106
+ startedAt: string;
107
+ finishedAt: string | null;
108
+ durationMs: number | null;
109
+ input?: unknown;
110
+ output?: unknown;
111
+ error?: unknown;
112
+ steps?: Array<{
113
+ id: string;
114
+ status: "pending" | "running" | "succeeded" | "failed" | "skipped";
115
+ startedAt?: string;
116
+ finishedAt?: string;
117
+ input?: unknown;
118
+ output?: unknown;
119
+ }>;
120
+ }
121
+ /**
122
+ * Expand a list row into its full detail. Function/Endpoint invocations are
123
+ * synchronous calls recorded one row per call (`.claude/docs/invocations.md`)
124
+ * — `GET /invocations/:id` by the escape-hatch `client.request` (no typed SDK
125
+ * method exists for this internal route, same reasoning as
126
+ * `repos/callables.ts`'s `archiveCallable`/`deleteCallable` split; A1: no
127
+ * other runtime import needed). A workflow run instead reuses
128
+ * `client.console.workflows.getRun` (`repos/workflows.ts`'s own
129
+ * `getRunState`) — its `variables` become the detail's `input`, and its
130
+ * opaque `steps` map through the SAME `mapRunStateToLogSteps` the live-run
131
+ * overlay uses, so a historical run's step list renders identically to a
132
+ * live one. `callableName` always comes from the summary — neither read
133
+ * carries a human-readable callable name of its own.
134
+ */
135
+ export declare function getExecutionDetail(client: W6WClient, summary: ExecutionSummary): Promise<ExecutionDetailData>;
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Pure decision behind `ImportSpecModal`'s Submit gate (T1.2.1, generalizing T3.2.1's A3 over all
3
+ * three spec kinds).
4
+ *
5
+ * `/spec/import` accepts all three spec kinds at one route (T2.1.2 §B), and this affordance is now
6
+ * mounted on the Functions, Endpoints and Workflows lists alike — each instance passing its own
7
+ * `expectedKind`. Pasting a document of the WRONG kind onto a given list would still create a row
8
+ * server-side and then send the operator to e.g. `functions/<ep_…>`, which 404s in the target
9
+ * page's editor. So this module refuses, client-side, before any request is ever sent: (1) text
10
+ * that isn't JSON, (2) a parse result that isn't a plain object, (3) a parsed `kind` that doesn't
11
+ * match `expectedKind`.
12
+ *
13
+ * Nothing beyond that is checked here — `specVersion`, `callable`'s shape,
14
+ * connection/reference resolvability, all of it is the SERVER's job
15
+ * (T2.1.2 §B); duplicating any of it here would drift from what the route
16
+ * actually enforces.
17
+ *
18
+ * `node --test` throws `ERR_UNKNOWN_FILE_EXTENSION` on anything reaching the
19
+ * `@w6w/ui` import graph (`src/lib/alias-rail.ts`'s docblock), so this module
20
+ * takes no value import at all — it has no dependency to avoid in the first
21
+ * place.
22
+ */
23
+ /** The parsed paste, once it is confirmed to be a plain JSON object. */
24
+ export type ParsedSpecDocument = Record<string, unknown>;
25
+ /** The one kind a given mount of the Import affordance expects — see `ImportSpecModal`'s `kind` prop. */
26
+ export type ExpectedSpecKind = "function" | "endpoint" | "workflow";
27
+ export interface ImportPasteResult {
28
+ /**
29
+ * The parsed JSON when it is a plain object — populated even when
30
+ * `blockedReason` names a wrong `kind`, so a caller could still inspect
31
+ * what was found. `null` when the text didn't even parse to an object.
32
+ */
33
+ parsed: ParsedSpecDocument | null;
34
+ /** `null` exactly when the paste is a plausible spec document of `expectedKind`. */
35
+ blockedReason: string | null;
36
+ }
37
+ /**
38
+ * Total: never throws, always returns. `JSON.parse` is the only thing here
39
+ * that can throw, and it is caught.
40
+ */
41
+ export declare function parseImportPaste(text: string, expectedKind: ExpectedSpecKind): ImportPasteResult;
@@ -0,0 +1,17 @@
1
+ export * from './workflow-validity.ts';
2
+ export * from './workflow-variables.ts';
3
+ export * from './workflow-settings.ts';
4
+ export * from './workflow-route.ts';
5
+ export type { RailCallable } from './code-rail.ts';
6
+ export { isAvailable as isCodeRailAvailable, toSnippetCallable } from './code-rail.ts';
7
+ export * from './import-paste.ts';
8
+ export * from './error-handler-self.ts';
9
+ export * from './document-sources.ts';
10
+ export * from './rail-settings.ts';
11
+ export type { CallableDefinition, CallablePolicy, SettingsCallable, } from './settings-rail.ts';
12
+ export { definitionWithPolicy, isAvailable as isSettingsRailAvailable, policyFromDefinition, } from './settings-rail.ts';
13
+ export type { TriggerPreview, TriggerPreviewContext, TriggerPreviewFieldDef, } from './trigger-preview.ts';
14
+ export { triggerInputSeed, triggerPreviews } from './trigger-preview.ts';
15
+ export * from './sdk-snippets.ts';
16
+ export * from './slug.ts';
17
+ export * from './spec-import-invalidation.ts';
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Platform id minter (studio copy). Algorithm is byte-identical to the server's
3
+ * `packages/ids/ids.ts`: alphabet base62, drop byte b >= 248 (largest multiple of 62
4
+ * that fits a byte), keep ALPHABET[b % 62]. No modulo bias.
5
+ */
6
+ export declare const ID_ALPHABET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
7
+ /** Byte source seam; defaults to `crypto.getRandomValues`. */
8
+ export type ByteSource = (n: number) => Uint8Array;
9
+ /** `<prefix>_<len chars of base62>`. */
10
+ export declare function newId(prefix: string, len?: number, bytes?: ByteSource): string;