@w6w/sdk 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 (59) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +131 -0
  3. package/dist/mod.d.ts +37 -0
  4. package/dist/mod.d.ts.map +1 -0
  5. package/dist/mod.js +51 -0
  6. package/dist/mod.js.map +1 -0
  7. package/dist/src/client.d.ts +134 -0
  8. package/dist/src/client.d.ts.map +1 -0
  9. package/dist/src/client.js +165 -0
  10. package/dist/src/client.js.map +1 -0
  11. package/dist/src/config.d.ts +151 -0
  12. package/dist/src/config.d.ts.map +1 -0
  13. package/dist/src/config.js +161 -0
  14. package/dist/src/config.js.map +1 -0
  15. package/dist/src/connections.d.ts +58 -0
  16. package/dist/src/connections.d.ts.map +1 -0
  17. package/dist/src/connections.js +52 -0
  18. package/dist/src/connections.js.map +1 -0
  19. package/dist/src/documents.d.ts +168 -0
  20. package/dist/src/documents.d.ts.map +1 -0
  21. package/dist/src/documents.js +178 -0
  22. package/dist/src/documents.js.map +1 -0
  23. package/dist/src/env.d.ts +61 -0
  24. package/dist/src/env.d.ts.map +1 -0
  25. package/dist/src/env.js +73 -0
  26. package/dist/src/env.js.map +1 -0
  27. package/dist/src/errors.d.ts +79 -0
  28. package/dist/src/errors.d.ts.map +1 -0
  29. package/dist/src/errors.js +88 -0
  30. package/dist/src/errors.js.map +1 -0
  31. package/dist/src/http.d.ts +130 -0
  32. package/dist/src/http.d.ts.map +1 -0
  33. package/dist/src/http.js +150 -0
  34. package/dist/src/http.js.map +1 -0
  35. package/dist/src/me.d.ts +53 -0
  36. package/dist/src/me.d.ts.map +1 -0
  37. package/dist/src/me.js +77 -0
  38. package/dist/src/me.js.map +1 -0
  39. package/dist/src/run.d.ts +92 -0
  40. package/dist/src/run.d.ts.map +1 -0
  41. package/dist/src/run.js +83 -0
  42. package/dist/src/run.js.map +1 -0
  43. package/dist/src/types.d.ts +362 -0
  44. package/dist/src/types.d.ts.map +1 -0
  45. package/dist/src/types.js +109 -0
  46. package/dist/src/types.js.map +1 -0
  47. package/dist/src/vars.d.ts +149 -0
  48. package/dist/src/vars.d.ts.map +1 -0
  49. package/dist/src/vars.js +149 -0
  50. package/dist/src/vars.js.map +1 -0
  51. package/dist/src/version.d.ts +14 -0
  52. package/dist/src/version.d.ts.map +1 -0
  53. package/dist/src/version.js +14 -0
  54. package/dist/src/version.js.map +1 -0
  55. package/dist/src/workflows.d.ts +180 -0
  56. package/dist/src/workflows.d.ts.map +1 -0
  57. package/dist/src/workflows.js +160 -0
  58. package/dist/src/workflows.js.map +1 -0
  59. package/package.json +36 -0
@@ -0,0 +1,150 @@
1
+ /**
2
+ * The transport: one `request()`, three failure modes, no policy.
3
+ *
4
+ * Everything the operation modules do goes through {@linkcode request}. It
5
+ * attaches the bearer, serialises a JSON body, reads the response exactly once,
6
+ * parses it guardedly, and raises one of the three failure modes pinned in
7
+ * `docs/implementation.md` §3 — and nothing else. In particular it does **not**
8
+ * retry, does **not** refresh a token, does **not** poll, and does **not**
9
+ * inspect an error code to decide on a side effect. A `401` raises and stops.
10
+ *
11
+ * It also returns the **HTTP status** alongside the parsed body, because a
12
+ * `202` is a normal outcome on this API (a queued workflow run), not an error —
13
+ * and a signature that dropped the status would leave the run operations unable
14
+ * to tell "finished" from "queued" (§4).
15
+ *
16
+ * @module
17
+ */
18
+ import { requireToken } from "./config.js";
19
+ import { ApiError } from "./errors.js";
20
+ /**
21
+ * Build a base-relative path, percent-encoding every interpolated value.
22
+ *
23
+ * ```ts
24
+ * path`/documents/by-key/${key}` // key "a/b" → "/documents/by-key/a%2Fb"
25
+ * ```
26
+ *
27
+ * **Use this tag for every path that contains a caller-supplied value**, per the
28
+ * encoding pin in `docs/implementation.md` §2. It exists as a tag rather than a
29
+ * helper function because the encoding then happens at the point of
30
+ * interpolation and cannot be forgotten one call site at a time: there is no way
31
+ * to write the template and skip it.
32
+ *
33
+ * Why it matters, in one line: the server accepts any non-empty key up to 128
34
+ * characters, so `".."` is a key a user can legitimately create — and
35
+ * `` `/documents/by-key/${".."}` `` naively concatenated resolves to the
36
+ * **list** route, returning every document with a `200` and no error anywhere.
37
+ *
38
+ * This is encoding, never validation. A key the server accepts is sent as-is
39
+ * (encoded); the wrapper does not reject, canonicalise or rewrite it. A
40
+ * character policy for keys is business logic, and it lives in the server.
41
+ *
42
+ * The one case encoding cannot fix is a dot-only segment: `.` is unreserved in
43
+ * RFC 3986, and the URL parser behind `fetch` removes dot segments regardless of
44
+ * how they are spelled. `"."` and `".."` are therefore not addressable through a
45
+ * path segment from this runtime — encode and send anyway, and let the server
46
+ * decide what it means.
47
+ *
48
+ * @param strings - Template literal fragments (author-controlled, not encoded).
49
+ * @param values - Interpolated values (caller-controlled, each percent-encoded).
50
+ * @returns The assembled path.
51
+ */
52
+ export function path(strings, ...values) {
53
+ return strings.reduce((acc, fragment, i) => i === 0 ? fragment : `${acc}${encodeURIComponent(values[i - 1])}${fragment}`, "");
54
+ }
55
+ /**
56
+ * Assemble the full request URL from a resolved base, a path and query params.
57
+ *
58
+ * The base is already joined with the API base path by `src/config.ts`; the
59
+ * path is appended verbatim (it is expected to be encoded already — see
60
+ * {@linkcode path}), and the query string is built with `URLSearchParams`,
61
+ * which encodes both names and values.
62
+ *
63
+ * @param config - The resolved configuration.
64
+ * @param options - The request being built.
65
+ * @returns The absolute URL to fetch.
66
+ */
67
+ export function buildUrl(config, options) {
68
+ const params = new URLSearchParams();
69
+ for (const [name, value] of Object.entries(options.query ?? {})) {
70
+ if (value !== undefined)
71
+ params.set(name, String(value));
72
+ }
73
+ const query = params.toString();
74
+ return `${config.baseUrl}${options.path}${query ? `?${query}` : ""}`;
75
+ }
76
+ /**
77
+ * Perform one request and map its outcome.
78
+ *
79
+ * Returns `{status, body}` on any `2xx`. Raises {@linkcode ApiError} in exactly
80
+ * three cases, transcribed from the studio's client, which has these three and
81
+ * no others:
82
+ *
83
+ * 1. **Transport failure** — `fetch` itself rejected: server down, DNS, TLS,
84
+ * connection refused. `status` `0`, code `network_error`, and the message
85
+ * names the **method and full URL** plus the underlying message, because a
86
+ * bare `TypeError: Failed to fetch` says nothing a user can act on.
87
+ * 2. **Non-JSON body on a non-OK status** — a proxy or Cloudflare HTML error
88
+ * page. `code` `bad_response`, message carrying a ≤200-character snippet;
89
+ * reporting it as an opaque `SyntaxError` would throw away the only
90
+ * diagnostic present. A non-JSON body on an **OK** status is not an error.
91
+ * 3. **Envelope error** — a non-OK status with a JSON body. `code` from
92
+ * `body.error.code` (else `"error"`), `message` from `body.error.message`
93
+ * (else the status text), and `raw` = the parsed body, which carries the
94
+ * fields an invoke failure rides alongside (`logs`, `apiCalls`).
95
+ *
96
+ * A `424` lands in case 3 like any other non-OK JSON status: it means the
97
+ * target app or its upstream vendor failed during execute, and it is
98
+ * deliberately a 4xx so Cloudflare cannot swallow it. It is never a transport
99
+ * error and is never normalised into a 5xx.
100
+ *
101
+ * @param config - Resolved configuration (base URL and credential).
102
+ * @param fetchImpl - The transport to use; injected, never read from a module global.
103
+ * @param options - The request.
104
+ * @returns The status and parsed body.
105
+ * @throws {ConfigError} When no token is configured.
106
+ * @throws {ApiError} On any of the three failure modes above.
107
+ */
108
+ export async function request(config, fetchImpl, options) {
109
+ const url = buildUrl(config, options);
110
+ const headers = new Headers();
111
+ // Resolved per request rather than at construction: a client with no token is
112
+ // constructible (so a CLI's --help works offline) and fails here instead.
113
+ headers.set("authorization", `Bearer ${requireToken(config)}`);
114
+ const hasBody = options.body !== undefined;
115
+ if (hasBody)
116
+ headers.set("content-type", "application/json");
117
+ let res;
118
+ try {
119
+ res = await fetchImpl(url, {
120
+ method: options.method,
121
+ headers,
122
+ body: hasBody ? JSON.stringify(options.body) : undefined,
123
+ });
124
+ }
125
+ catch (err) {
126
+ throw new ApiError(0, "network_error", `Could not reach the w6w server (${options.method} ${url}). ` +
127
+ `It may be down or unreachable. (${err instanceof Error ? err.message : String(err)})`);
128
+ }
129
+ // Read the body exactly once, as text, then parse it guardedly — a response
130
+ // body is a single-use stream, and `res.json()` on an HTML error page throws
131
+ // an opaque SyntaxError that loses the page.
132
+ const text = await res.text();
133
+ let data = null;
134
+ if (text) {
135
+ try {
136
+ data = JSON.parse(text);
137
+ }
138
+ catch {
139
+ if (!res.ok) {
140
+ throw new ApiError(res.status, "bad_response", `Server returned a non-JSON ${res.status} response: ${text.slice(0, 200)}`);
141
+ }
142
+ }
143
+ }
144
+ if (!res.ok) {
145
+ const envelope = data?.error ?? {};
146
+ throw new ApiError(res.status, envelope.code ?? "error", envelope.message ?? res.statusText, data);
147
+ }
148
+ return { status: res.status, body: data };
149
+ }
150
+ //# sourceMappingURL=http.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.js","sourceRoot":"","sources":["../../src/http.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * `client.me()` — who the caller is, and what answered.
3
+ *
4
+ * One GET to `/auth/me` — the server's real identity route (verified live).
5
+ * The response body is **flat** — `{tenant, subject, account, role,
6
+ * versions?}` — so there is nothing for `unwrap` to do here, and this is the
7
+ * one read operation in the package that does not call it.
8
+ *
9
+ * The one thing this module adds to the body is `versions.wrapper`, which the
10
+ * server cannot know — it is this package's own published version. It is a
11
+ * **fill, never an overwrite**: a key the server supplied wins, including
12
+ * `wrapper` itself, so a future host that has a better answer is not silently
13
+ * overruled by the client. The server does not send a `versions` block today,
14
+ * so every call currently returns just `{wrapper: VERSION}` — expected, not
15
+ * an error.
16
+ *
17
+ * It is deliberately not a namespace class. `endpoints.json` names this
18
+ * operation `client.me()`, a method on the client itself, so the module exports
19
+ * a function over a narrow host interface and `W6wClient` delegates to it —
20
+ * same layering as the namespaces, without inventing a `client.me.me()`.
21
+ *
22
+ * @module
23
+ */
24
+ import type { HttpResponse, RequestOptions } from "./http.ts";
25
+ import type { Me } from "./types.ts";
26
+ /**
27
+ * The slice of `W6wClient` this operation needs: the transport, and nothing
28
+ * else. Structural rather than a concrete client type, so it stays
29
+ * independently callable in a test and this module never imports the client
30
+ * back.
31
+ */
32
+ export interface MeHost {
33
+ /** Perform one request. */
34
+ request<T>(options: RequestOptions): Promise<HttpResponse<T>>;
35
+ }
36
+ /**
37
+ * Fetch the caller's identity and the component versions behind it.
38
+ *
39
+ * The identity fields are returned exactly as they arrived — unknown ones
40
+ * included, since the return is an interface and not a closed schema.
41
+ * `versions` is normalised to always exist and to always carry a `wrapper`
42
+ * entry, so a caller printing a version banner never has to branch on whether
43
+ * the server sent the block at all.
44
+ *
45
+ * @param host - The client this operation issues its request through.
46
+ * @returns The caller's identity, with `versions.wrapper` filled in.
47
+ * @throws {ApiError} On any non-2xx, e.g. `401` when the token is not accepted.
48
+ * @throws {ApiError} `bad_response` when a 2xx body is not a plain object — an
49
+ * array included, since `typeof [] === "object"` and a spread array yields
50
+ * character-indexed keys rather than identity fields.
51
+ */
52
+ export declare function fetchMe(host: MeHost): Promise<Me>;
53
+ //# sourceMappingURL=me.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"me.d.ts","sourceRoot":"","sources":["../../src/me.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAC9D,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,YAAY,CAAC;AAGrC;;;;;GAKG;AACH,MAAM,WAAW,MAAM;IACrB,2BAA2B;IAC3B,OAAO,CAAC,CAAC,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC;CAC/D;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,EAAE,CAAC,CAuCvD"}
package/dist/src/me.js ADDED
@@ -0,0 +1,77 @@
1
+ /**
2
+ * `client.me()` — who the caller is, and what answered.
3
+ *
4
+ * One GET to `/auth/me` — the server's real identity route (verified live).
5
+ * The response body is **flat** — `{tenant, subject, account, role,
6
+ * versions?}` — so there is nothing for `unwrap` to do here, and this is the
7
+ * one read operation in the package that does not call it.
8
+ *
9
+ * The one thing this module adds to the body is `versions.wrapper`, which the
10
+ * server cannot know — it is this package's own published version. It is a
11
+ * **fill, never an overwrite**: a key the server supplied wins, including
12
+ * `wrapper` itself, so a future host that has a better answer is not silently
13
+ * overruled by the client. The server does not send a `versions` block today,
14
+ * so every call currently returns just `{wrapper: VERSION}` — expected, not
15
+ * an error.
16
+ *
17
+ * It is deliberately not a namespace class. `endpoints.json` names this
18
+ * operation `client.me()`, a method on the client itself, so the module exports
19
+ * a function over a narrow host interface and `W6wClient` delegates to it —
20
+ * same layering as the namespaces, without inventing a `client.me.me()`.
21
+ *
22
+ * @module
23
+ */
24
+ import { ApiError } from "./errors.js";
25
+ import { VERSION } from "./version.js";
26
+ /**
27
+ * Fetch the caller's identity and the component versions behind it.
28
+ *
29
+ * The identity fields are returned exactly as they arrived — unknown ones
30
+ * included, since the return is an interface and not a closed schema.
31
+ * `versions` is normalised to always exist and to always carry a `wrapper`
32
+ * entry, so a caller printing a version banner never has to branch on whether
33
+ * the server sent the block at all.
34
+ *
35
+ * @param host - The client this operation issues its request through.
36
+ * @returns The caller's identity, with `versions.wrapper` filled in.
37
+ * @throws {ApiError} On any non-2xx, e.g. `401` when the token is not accepted.
38
+ * @throws {ApiError} `bad_response` when a 2xx body is not a plain object — an
39
+ * array included, since `typeof [] === "object"` and a spread array yields
40
+ * character-indexed keys rather than identity fields.
41
+ */
42
+ export async function fetchMe(host) {
43
+ const res = await host.request({ method: "GET", path: "/auth/me" });
44
+ const body = res.body;
45
+ // A body that is not an object cannot be identity data. Raise rather than
46
+ // spread it — the same `bad_response` class the envelope reader uses for the
47
+ // keyed routes — so a proxy answering `200 "ok"` fails here instead of
48
+ // returning a `Me` whose only populated field is the one this client just
49
+ // added.
50
+ //
51
+ // `Array.isArray` is load-bearing, not belt-and-braces: `typeof [] === "object"`
52
+ // and `[] !== null`, so without it a `200 []` spread into exactly the degenerate
53
+ // value described above — measured, `{"versions":{"wrapper":"0.1.0"}}` — and
54
+ // `200 [{...}]` produced character-indexed keys. It also keeps this lane in step
55
+ // with python, whose natural `isinstance(body, dict)` excludes a list already.
56
+ if (typeof body !== "object" || body === null || Array.isArray(body)) {
57
+ throw new ApiError(res.status, "bad_response", `Server returned a ${res.status} whose body is not an identity object.`, body);
58
+ }
59
+ // Same reasoning one level down: `versions` is typed `Record<string, string>`,
60
+ // but the wire can carry anything, and spreading a string produces
61
+ // character-indexed junk (`"1.2.3"` → `{"0":"1","1":".",…}`) that satisfies the
62
+ // type and so is invisible to the compiler. A `versions` that is not a plain
63
+ // object is dropped in favour of the client's own fill rather than merged —
64
+ // this operation reports identity, and inventing keys out of a malformed block
65
+ // would be worse than reporting only what this client actually knows.
66
+ const versions = body.versions;
67
+ const merged = typeof versions === "object" && versions !== null && !Array.isArray(versions)
68
+ ? versions
69
+ : undefined;
70
+ return {
71
+ ...body,
72
+ // Spread order is the policy: the wrapper's own version is the DEFAULT and
73
+ // every key the server sent lands on top of it, `wrapper` included.
74
+ versions: { wrapper: VERSION, ...merged },
75
+ };
76
+ }
77
+ //# sourceMappingURL=me.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"me.js","sourceRoot":"","sources":["../../src/me.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAGvC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAavC;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,IAAY;IACxC,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,OAAO,CAAK,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,CAAC;IACxE,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC;IACtB,0EAA0E;IAC1E,6EAA6E;IAC7E,uEAAuE;IACvE,0EAA0E;IAC1E,SAAS;IACT,EAAE;IACF,iFAAiF;IACjF,iFAAiF;IACjF,6EAA6E;IAC7E,iFAAiF;IACjF,+EAA+E;IAC/E,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;QACrE,MAAM,IAAI,QAAQ,CAChB,GAAG,CAAC,MAAM,EACV,cAAc,EACd,qBAAqB,GAAG,CAAC,MAAM,wCAAwC,EACvE,IAAI,CACL,CAAC;IACJ,CAAC;IACD,+EAA+E;IAC/E,mEAAmE;IACnE,gFAAgF;IAChF,6EAA6E;IAC7E,4EAA4E;IAC5E,+EAA+E;IAC/E,sEAAsE;IACtE,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC;IAC/B,MAAM,MAAM,GAAG,OAAO,QAAQ,KAAK,QAAQ,IAAI,QAAQ,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC;QAC1F,CAAC,CAAC,QAAQ;QACV,CAAC,CAAC,SAAS,CAAC;IACd,OAAO;QACL,GAAG,IAAI;QACP,2EAA2E;QAC3E,oEAAoE;QACpE,QAAQ,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,MAAM,EAAE;KAC1C,CAAC;AACJ,CAAC"}
@@ -0,0 +1,92 @@
1
+ /**
2
+ * `client.run({urn, action, payload})` — run anything a URN addresses.
3
+ *
4
+ * One POST, one kind-tagged body, no envelope key. The URN resolves over the
5
+ * four runnable arms — `conn_…`, `wf_…`, `fn_…`, `ep_…` (D16) — and the answer
6
+ * says which one it hit:
7
+ *
8
+ * | `kind` | Field | HTTP |
9
+ * |---|---|---|
10
+ * | `"action"` | `value` | `200` |
11
+ * | `"function"` | `output` | `200` |
12
+ * | `"workflow"` | `runId` + `status` | `202` |
13
+ *
14
+ * `value` and `output` are **deliberately different names** and are never
15
+ * normalised into one field: the discrimination is the whole point of the
16
+ * operation (D3). `202` on the workflow arm is **success** — the run is queued
17
+ * and `runId` is how the caller follows it.
18
+ *
19
+ * ── The unknown fourth kind ──
20
+ * A `kind` this release has never heard of is **returned verbatim**, never
21
+ * raised (`docs/implementation.md` §5). `run` dispatches on whatever a URN
22
+ * resolves to, and the server can grow a new kind before the wrappers do — a
23
+ * purely additive change. Raising would turn that into a hard breakage for every
24
+ * installed client on the one operation whose entire job is dispatch, and would
25
+ * leave the caller with an exception instead of a payload this module had
26
+ * already parsed and held. Callers discriminate with `isActionRun`,
27
+ * `isFunctionRun` and `isWorkflowRun` (`src/types.ts`), which narrow properly —
28
+ * a bare `env.kind === "action"` check does not, because the union is open.
29
+ *
30
+ * `POST /api/run` (verified live 2026-07-28): the URN resolver dispatches to
31
+ * the same runner each dedicated route already uses — no new execution path.
32
+ *
33
+ * ── Why this is not folded into `workflows.run` ──
34
+ * D4: `?wait=`, `variables` and `trigger` have no slot in the three-field
35
+ * `{urn, action, payload}` shape, and a workflow has no `action`. The two
36
+ * operations ship side by side — this one dispatches, `workflows.run` is the
37
+ * typed path.
38
+ *
39
+ * Like `me`, this is a function over a narrow host interface rather than a
40
+ * namespace class, because `endpoints.json` names the symbol `client.run(input)`
41
+ * — a method on the client itself, not a `client.run.run()`.
42
+ *
43
+ * @module
44
+ */
45
+ import type { HttpResponse, RequestOptions } from "./http.ts";
46
+ import type { RunEnvelope } from "./types.ts";
47
+ /**
48
+ * The slice of `W6wClient` this operation needs: the transport, and nothing
49
+ * else. Structural rather than a concrete client type, so it stays
50
+ * independently callable in a test and this module never imports the client
51
+ * back.
52
+ */
53
+ export interface RunHost {
54
+ /** Perform one request. */
55
+ request<T>(options: RequestOptions): Promise<HttpResponse<T>>;
56
+ }
57
+ /**
58
+ * The body of `client.run()`.
59
+ *
60
+ * All three fields travel in the **request body**, so none of them is
61
+ * percent-encoded: `/run` is a fixed path with no interpolation, and a URN in
62
+ * JSON needs no escaping. (The `path` tag is for path segments — `workflows.run`
63
+ * uses it for its `wf_…` id.)
64
+ */
65
+ export interface RunInput {
66
+ /** What to run: `conn_…`, `wf_…`, `fn_…` or `ep_…`. */
67
+ urn: string;
68
+ /**
69
+ * Which action to invoke. Optional, because a workflow, function or endpoint
70
+ * URN has no action; required in practice for a `conn_…` URN, and the server
71
+ * is what says so — this client does not second-guess the URN's arm.
72
+ */
73
+ action?: string;
74
+ /** Input to the run. Defaults to `{}`. Opaque pass-through. */
75
+ payload?: Record<string, unknown>;
76
+ }
77
+ /**
78
+ * Run whatever a URN addresses.
79
+ *
80
+ * @param host - The client this operation issues its request through.
81
+ * @param input - The URN, the optional action, and the payload.
82
+ * @returns The kind-tagged envelope, with `kind` and the arm's field verbatim.
83
+ * @throws {ApiError} On any non-2xx — `404` for an unresolvable URN, `424` when
84
+ * the app or its upstream vendor failed during execute (a 4xx on purpose, so
85
+ * Cloudflare cannot swallow the message; never normalised into a transport
86
+ * error).
87
+ * @throws {ApiError} `bad_response` when a success body carries no `kind` at all
88
+ * — that is a malformed dispatch response, not a new arm, and it is the one
89
+ * shape a caller cannot do anything with.
90
+ */
91
+ export declare function runUrn(host: RunHost, input: RunInput): Promise<RunEnvelope>;
92
+ //# sourceMappingURL=run.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../src/run.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAC9D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C;;;;;GAKG;AACH,MAAM,WAAW,OAAO;IACtB,2BAA2B;IAC3B,OAAO,CAAC,CAAC,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC;CAC/D;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,QAAQ;IACvB,uDAAuD;IACvD,GAAG,EAAE,MAAM,CAAC;IACZ;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,+DAA+D;IAC/D,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,MAAM,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,GAAG,OAAO,CAAC,WAAW,CAAC,CA8BjF"}
@@ -0,0 +1,83 @@
1
+ /**
2
+ * `client.run({urn, action, payload})` — run anything a URN addresses.
3
+ *
4
+ * One POST, one kind-tagged body, no envelope key. The URN resolves over the
5
+ * four runnable arms — `conn_…`, `wf_…`, `fn_…`, `ep_…` (D16) — and the answer
6
+ * says which one it hit:
7
+ *
8
+ * | `kind` | Field | HTTP |
9
+ * |---|---|---|
10
+ * | `"action"` | `value` | `200` |
11
+ * | `"function"` | `output` | `200` |
12
+ * | `"workflow"` | `runId` + `status` | `202` |
13
+ *
14
+ * `value` and `output` are **deliberately different names** and are never
15
+ * normalised into one field: the discrimination is the whole point of the
16
+ * operation (D3). `202` on the workflow arm is **success** — the run is queued
17
+ * and `runId` is how the caller follows it.
18
+ *
19
+ * ── The unknown fourth kind ──
20
+ * A `kind` this release has never heard of is **returned verbatim**, never
21
+ * raised (`docs/implementation.md` §5). `run` dispatches on whatever a URN
22
+ * resolves to, and the server can grow a new kind before the wrappers do — a
23
+ * purely additive change. Raising would turn that into a hard breakage for every
24
+ * installed client on the one operation whose entire job is dispatch, and would
25
+ * leave the caller with an exception instead of a payload this module had
26
+ * already parsed and held. Callers discriminate with `isActionRun`,
27
+ * `isFunctionRun` and `isWorkflowRun` (`src/types.ts`), which narrow properly —
28
+ * a bare `env.kind === "action"` check does not, because the union is open.
29
+ *
30
+ * `POST /api/run` (verified live 2026-07-28): the URN resolver dispatches to
31
+ * the same runner each dedicated route already uses — no new execution path.
32
+ *
33
+ * ── Why this is not folded into `workflows.run` ──
34
+ * D4: `?wait=`, `variables` and `trigger` have no slot in the three-field
35
+ * `{urn, action, payload}` shape, and a workflow has no `action`. The two
36
+ * operations ship side by side — this one dispatches, `workflows.run` is the
37
+ * typed path.
38
+ *
39
+ * Like `me`, this is a function over a narrow host interface rather than a
40
+ * namespace class, because `endpoints.json` names the symbol `client.run(input)`
41
+ * — a method on the client itself, not a `client.run.run()`.
42
+ *
43
+ * @module
44
+ */
45
+ import { ApiError } from "./errors.js";
46
+ /**
47
+ * Run whatever a URN addresses.
48
+ *
49
+ * @param host - The client this operation issues its request through.
50
+ * @param input - The URN, the optional action, and the payload.
51
+ * @returns The kind-tagged envelope, with `kind` and the arm's field verbatim.
52
+ * @throws {ApiError} On any non-2xx — `404` for an unresolvable URN, `424` when
53
+ * the app or its upstream vendor failed during execute (a 4xx on purpose, so
54
+ * Cloudflare cannot swallow the message; never normalised into a transport
55
+ * error).
56
+ * @throws {ApiError} `bad_response` when a success body carries no `kind` at all
57
+ * — that is a malformed dispatch response, not a new arm, and it is the one
58
+ * shape a caller cannot do anything with.
59
+ */
60
+ export async function runUrn(host, input) {
61
+ const res = await host.request({
62
+ method: "POST",
63
+ path: "/run",
64
+ body: {
65
+ urn: input.urn,
66
+ action: input.action,
67
+ // Defaulted rather than omitted: the server's parameter schemas are
68
+ // written against an object, and `{}` says "no input" where an absent key
69
+ // says "I forgot".
70
+ payload: input.payload ?? {},
71
+ },
72
+ });
73
+ const body = res.body;
74
+ if (typeof body !== "object" || body === null ||
75
+ typeof body.kind !== "string") {
76
+ throw new ApiError(res.status, "bad_response", `Server returned a ${res.status} with no "kind" in the response body.`, body);
77
+ }
78
+ // Returned as it arrived — no rebuild, no field renaming, no per-arm
79
+ // destructure. An unknown `kind` therefore reaches the caller with every
80
+ // sibling field intact.
81
+ return body;
82
+ }
83
+ //# sourceMappingURL=run.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run.js","sourceRoot":"","sources":["../../src/run.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAoCvC;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,IAAa,EAAE,KAAe;IACzD,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,OAAO,CAAU;QACtC,MAAM,EAAE,MAAM;QACd,IAAI,EAAE,MAAM;QACZ,IAAI,EAAE;YACJ,GAAG,EAAE,KAAK,CAAC,GAAG;YACd,MAAM,EAAE,KAAK,CAAC,MAAM;YACpB,oEAAoE;YACpE,0EAA0E;YAC1E,mBAAmB;YACnB,OAAO,EAAE,KAAK,CAAC,OAAO,IAAI,EAAE;SAC7B;KACF,CAAC,CAAC;IAEH,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC;IACtB,IACE,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,IAAI;QACzC,OAAQ,IAA2B,CAAC,IAAI,KAAK,QAAQ,EACrD,CAAC;QACD,MAAM,IAAI,QAAQ,CAChB,GAAG,CAAC,MAAM,EACV,cAAc,EACd,qBAAqB,GAAG,CAAC,MAAM,uCAAuC,EACtE,IAAI,CACL,CAAC;IACJ,CAAC;IACD,qEAAqE;IACrE,yEAAyE;IACzE,wBAAwB;IACxB,OAAO,IAAmB,CAAC;AAC7B,CAAC"}