@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,149 @@
1
+ /**
2
+ * `client.vars.*` — typed variables, addressed the way the server addresses
3
+ * them.
4
+ *
5
+ * Six operations, one HTTP call each. **Create by `name`, read by id or by
6
+ * name, update and delete by id** (`docs/implementation.md` §7, D6 amended by
7
+ * D12). No client-side list-then-filter: `getByName` targets a real route,
8
+ * `GET /vars/by-name/{name}` (verified live 2026-07-28).
9
+ *
10
+ * **There is no scoping query parameter on any variable operation, and this
11
+ * module cannot invent one.** Variables are scoped by tenant/subject only; the
12
+ * server's `vars` routes read no such parameter and the table has no column for
13
+ * it, while every document route does — so the two asset surfaces are
14
+ * deliberately asymmetric (`docs/implementation.md` §7, and `src/documents.ts`
15
+ * for the other half). The asymmetry is enforced structurally rather than by
16
+ * discipline: {@linkcode VarsHost} exposes the transport and **not** the
17
+ * client's resolved configuration, so nothing in this file can reach a default
18
+ * scope to send even by accident. Adding the parameter later, once the server
19
+ * honours it, is purely additive; adding it now would be an argument the server
20
+ * ignores — a lie that typechecks.
21
+ *
22
+ * @module
23
+ */
24
+ import { path } from "./http.js";
25
+ import { unwrap } from "./types.js";
26
+ /**
27
+ * The `vars` namespace on a `W6wClient`.
28
+ *
29
+ * @example
30
+ * ```ts
31
+ * const v = await client.vars.create({ name: "sender_email", type: "string", value: "a@b.c" });
32
+ * await client.vars.update(v.id, { value: "c@d.e" });
33
+ * await client.vars.delete(v.id);
34
+ * ```
35
+ */
36
+ export class VarsApi {
37
+ #host;
38
+ /**
39
+ * @param host - The client this namespace issues requests through.
40
+ */
41
+ constructor(host) {
42
+ this.#host = host;
43
+ }
44
+ /**
45
+ * List the caller's variables.
46
+ *
47
+ * @returns The variables, unwrapped from the `vars` envelope.
48
+ * @throws {ApiError} On any non-2xx.
49
+ */
50
+ async list() {
51
+ const res = await this.#host.request({ method: "GET", path: "/vars" });
52
+ return unwrap(res, "vars");
53
+ }
54
+ /**
55
+ * Fetch one variable by its server-issued id.
56
+ *
57
+ * @param id - The `var_…` id.
58
+ * @returns The variable.
59
+ * @throws {ApiError} `404 unknown_var` when there is no such id.
60
+ */
61
+ async get(id) {
62
+ const res = await this.#host.request({ method: "GET", path: path `/vars/${id}` });
63
+ // The singular envelope key is `var` — a reserved word in TypeScript, so it
64
+ // is read as a property and never destructured into a binding.
65
+ return unwrap(res, "var");
66
+ }
67
+ /**
68
+ * Fetch one variable by the `name` its author chose.
69
+ *
70
+ * The name is percent-encoded at interpolation by the `path` tag. The server's
71
+ * own rule (`^[a-z_][a-z0-9_]*$`) contains nothing that needs encoding — but
72
+ * that rule is the *server's* to enforce, and this method encodes rather than
73
+ * validates: a name the server accepts is sent as-is (encoded), and a name it
74
+ * rejects comes back as `400 invalid_name` from the one place that owns the
75
+ * rule, instead of as a client-side error that would go stale the moment the
76
+ * rule changed.
77
+ *
78
+ * @param name - The variable name, sent encoded and otherwise untouched.
79
+ * @returns The variable.
80
+ * @throws {ApiError} `404 unknown_var` when there is no such name.
81
+ */
82
+ async getByName(name) {
83
+ const res = await this.#host.request({
84
+ method: "GET",
85
+ path: path `/vars/by-name/${name}`,
86
+ });
87
+ return unwrap(res, "var");
88
+ }
89
+ /**
90
+ * Create a typed variable under a caller-chosen name.
91
+ *
92
+ * @param input - `name`, `type` and `value` are required.
93
+ * @returns The created variable (the server answers `201`).
94
+ * @throws {ApiError} `409 var_exists` on a duplicate name — the code reaches the caller intact.
95
+ */
96
+ async create(input) {
97
+ const res = await this.#host.request({
98
+ method: "POST",
99
+ path: "/vars",
100
+ // Assembled field by field rather than forwarded wholesale: the body that
101
+ // goes on the wire is exactly the four documented fields, and `undefined`
102
+ // ones are dropped by JSON serialisation.
103
+ body: {
104
+ name: input.name,
105
+ type: input.type,
106
+ value: input.value,
107
+ description: input.description,
108
+ },
109
+ });
110
+ return unwrap(res, "var");
111
+ }
112
+ /**
113
+ * Patch a variable's type, value or description.
114
+ *
115
+ * Addressed by id, never by name, and the name itself cannot be changed.
116
+ *
117
+ * @param id - The `var_…` id.
118
+ * @param patch - The fields to change; omitted fields are left alone.
119
+ * @returns The updated variable.
120
+ * @throws {ApiError} `404 unknown_var` when there is no such id.
121
+ */
122
+ async update(id, patch) {
123
+ const res = await this.#host.request({
124
+ method: "PATCH",
125
+ path: path `/vars/${id}`,
126
+ body: {
127
+ type: patch.type,
128
+ value: patch.value,
129
+ description: patch.description,
130
+ },
131
+ });
132
+ return unwrap(res, "var");
133
+ }
134
+ /**
135
+ * Delete a variable.
136
+ *
137
+ * Returns nothing: the server's `{ok: true}` carries no information a caller
138
+ * can use. Deleting an unknown id is `404 unknown_var`, **not** a silent
139
+ * success — the delete is not idempotent and this method does not pretend
140
+ * otherwise.
141
+ *
142
+ * @param id - The `var_…` id.
143
+ * @throws {ApiError} `404 unknown_var` when there is no such id.
144
+ */
145
+ async delete(id) {
146
+ await this.#host.request({ method: "DELETE", path: path `/vars/${id}` });
147
+ }
148
+ }
149
+ //# sourceMappingURL=vars.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vars.js","sourceRoot":"","sources":["../../src/vars.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EAAqB,IAAI,EAAuB,MAAM,WAAW,CAAC;AACzE,OAAO,EAAE,MAAM,EAA0B,MAAM,YAAY,CAAC;AAiD5D;;;;;;;;;GASG;AACH,MAAM,OAAO,OAAO;IACT,KAAK,CAAW;IAEzB;;OAEG;IACH,YAAY,IAAc;QACxB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;IACpB,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,IAAI;QACR,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,CAAU,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;QAChF,OAAO,MAAM,CAAQ,GAAG,EAAE,MAAM,CAAC,CAAC;IACpC,CAAC;IAED;;;;;;OAMG;IACH,KAAK,CAAC,GAAG,CAAC,EAAU;QAClB,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,CAAU,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,CAAA,SAAS,EAAE,EAAE,EAAE,CAAC,CAAC;QAC1F,4EAA4E;QAC5E,+DAA+D;QAC/D,OAAO,MAAM,CAAM,GAAG,EAAE,KAAK,CAAC,CAAC;IACjC,CAAC;IAED;;;;;;;;;;;;;;OAcG;IACH,KAAK,CAAC,SAAS,CAAC,IAAY;QAC1B,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,CAAU;YAC5C,MAAM,EAAE,KAAK;YACb,IAAI,EAAE,IAAI,CAAA,iBAAiB,IAAI,EAAE;SAClC,CAAC,CAAC;QACH,OAAO,MAAM,CAAM,GAAG,EAAE,KAAK,CAAC,CAAC;IACjC,CAAC;IAED;;;;;;OAMG;IACH,KAAK,CAAC,MAAM,CAAC,KAAqB;QAChC,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,CAAU;YAC5C,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,OAAO;YACb,0EAA0E;YAC1E,0EAA0E;YAC1E,0CAA0C;YAC1C,IAAI,EAAE;gBACJ,IAAI,EAAE,KAAK,CAAC,IAAI;gBAChB,IAAI,EAAE,KAAK,CAAC,IAAI;gBAChB,KAAK,EAAE,KAAK,CAAC,KAAK;gBAClB,WAAW,EAAE,KAAK,CAAC,WAAW;aAC/B;SACF,CAAC,CAAC;QACH,OAAO,MAAM,CAAM,GAAG,EAAE,KAAK,CAAC,CAAC;IACjC,CAAC;IAED;;;;;;;;;OASG;IACH,KAAK,CAAC,MAAM,CAAC,EAAU,EAAE,KAAe;QACtC,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,CAAU;YAC5C,MAAM,EAAE,OAAO;YACf,IAAI,EAAE,IAAI,CAAA,SAAS,EAAE,EAAE;YACvB,IAAI,EAAE;gBACJ,IAAI,EAAE,KAAK,CAAC,IAAI;gBAChB,KAAK,EAAE,KAAK,CAAC,KAAK;gBAClB,WAAW,EAAE,KAAK,CAAC,WAAW;aAC/B;SACF,CAAC,CAAC;QACH,OAAO,MAAM,CAAM,GAAG,EAAE,KAAK,CAAC,CAAC;IACjC,CAAC;IAED;;;;;;;;;;OAUG;IACH,KAAK,CAAC,MAAM,CAAC,EAAU;QACrB,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,CAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,CAAA,SAAS,EAAE,EAAE,EAAE,CAAC,CAAC;IACnF,CAAC;CACF"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * The published version of this package.
3
+ *
4
+ * It is the same string as `deno.json`'s `version`, `package.json`'s `version`
5
+ * and the monorepo's `packages/wrappers/VERSION` — the single source of truth all
6
+ * three w6w wrappers publish under (see `docs/parity.md`). `tests/version_test.ts`
7
+ * fails if any of those four disagree, so this constant cannot drift silently.
8
+ *
9
+ * The explicit `: string` annotation is required, not decorative: JSR publishes
10
+ * this file as TypeScript source and rejects inferred public types ("no slow
11
+ * types").
12
+ */
13
+ export declare const VERSION: string;
14
+ //# sourceMappingURL=version.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../../src/version.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,OAAO,EAAE,MAAgB,CAAC"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * The published version of this package.
3
+ *
4
+ * It is the same string as `deno.json`'s `version`, `package.json`'s `version`
5
+ * and the monorepo's `packages/wrappers/VERSION` — the single source of truth all
6
+ * three w6w wrappers publish under (see `docs/parity.md`). `tests/version_test.ts`
7
+ * fails if any of those four disagree, so this constant cannot drift silently.
8
+ *
9
+ * The explicit `: string` annotation is required, not decorative: JSR publishes
10
+ * this file as TypeScript source and rejects inferred public types ("no slow
11
+ * types").
12
+ */
13
+ export const VERSION = "0.1.0";
14
+ //# sourceMappingURL=version.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.js","sourceRoot":"","sources":["../../src/version.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,OAAO,GAAW,OAAO,CAAC"}
@@ -0,0 +1,180 @@
1
+ /**
2
+ * `client.workflows.*` — discovery and the typed run.
3
+ *
4
+ * Two operations: `list` (T2.1.4) and `run` (T2.1.5). `list` earns its place in
5
+ * a minimal surface for the same reason `connections.list` does (D4): it is how
6
+ * a caller discovers a `wf_…` id to pass to `run`.
7
+ *
8
+ * ── `run`, and the three things this API gets called wrong ──
9
+ * 1. **`202` is success.** No `wait` → the run is queued and the server answers
10
+ * `202 {runId, status:"queued"}`. With `?wait=true` and a timeout → `202`
11
+ * again, with the current status. Neither raises.
12
+ * 2. **A failed run is data.** `?wait=true` on a run that failed is a plain
13
+ * `200` carrying `status: "failed"` and an `error`. This module returns it
14
+ * like any other result. Mapping it to an exit code is the CLI's job
15
+ * (`cli.exitCodes` in `endpoints.json`), not the SDK's.
16
+ * 3. **No client-side polling.** The server already polls internally for
17
+ * `?wait=true`, up to its own `RUN_WAIT_TIMEOUT_SEC`. The studio's 600 × 500 ms
18
+ * browser loop predates that and is deliberately **not** transcribed
19
+ * (`docs/implementation.md` §4): three wrappers each re-implementing a poll
20
+ * would be three timeout policies and three retry-storm bugs to keep in sync.
21
+ * There is no timer, no delay and no retry anywhere in this package — a `202`
22
+ * hands the caller `runId` and lets them decide.
23
+ *
24
+ * Workflows are **project-scoped**, like documents and unlike vars: the route
25
+ * accepts an optional `?project=`, resolved per call, then from the client's
26
+ * default, and otherwise left to the server. This host therefore sees the
27
+ * client's resolved configuration, which `connections` and `vars` deliberately
28
+ * do not.
29
+ *
30
+ * ── Pagination ──
31
+ * The route is **not paginated today** and this module does not pretend
32
+ * otherwise: there is no `cursor` argument, no `cursor` field, and no
33
+ * client-side paging loop. `list` returns the unwrapped array, exactly as
34
+ * `docs/implementation.md` §6 pins it.
35
+ *
36
+ * That is not a corner this signature is painted into. A JavaScript array is an
37
+ * object, so the day the server grows a cursor the wrapper can return an array
38
+ * that carries it (`WorkflowSummary[] & {cursor?: string}`) and widen this
39
+ * return type to match — every existing caller, which only ever reads the list,
40
+ * keeps compiling and keeps working. Inventing the field now would put a key on
41
+ * the type that no server has ever sent, which is the failure mode
42
+ * `endpoints.json` actually warns about.
43
+ *
44
+ * @module
45
+ */
46
+ import type { ResolvedConfig } from "./config.ts";
47
+ import { type HttpResponse, type RequestOptions } from "./http.ts";
48
+ import { type RunResult, type WorkflowSummary } from "./types.ts";
49
+ /**
50
+ * The slice of `W6wClient` this namespace needs: the transport, plus the
51
+ * resolved configuration it reads the **default project** out of. Structural
52
+ * rather than a concrete client type, so the namespace stays independently
53
+ * constructible in a test and this module never imports the client back.
54
+ */
55
+ export interface WorkflowsHost {
56
+ /** The resolved configuration; only `project` is read. */
57
+ readonly config: ResolvedConfig;
58
+ /** Perform one request. */
59
+ request<T>(options: RequestOptions): Promise<HttpResponse<T>>;
60
+ }
61
+ /**
62
+ * Per-call options for `workflows.list`.
63
+ *
64
+ * A named interface rather than a bare `project?: string` parameter, so the
65
+ * operation can accept a further argument later without changing its arity.
66
+ */
67
+ export interface WorkflowListOptions {
68
+ /** Project id to scope this call to; overrides the client's default. */
69
+ project?: string;
70
+ }
71
+ /**
72
+ * Per-call options for `workflows.run`.
73
+ *
74
+ * **No `project` here, on purpose.** A `wf_…` id is unambiguous on its own, and
75
+ * `endpoints.json` gives this operation exactly four parameters — `id`, `wait`,
76
+ * `variables`, `trigger`. Sending a `?project=` the route does not read would be
77
+ * inventing a parameter.
78
+ */
79
+ export interface WorkflowRunOptions {
80
+ /**
81
+ * Wait for the run to reach a terminal state before answering.
82
+ *
83
+ * Sent as `?wait=true` **only when `true`**: the server compares the raw query
84
+ * value to the string `"true"`, so `?wait=false` would mean the same thing as
85
+ * omitting it while looking like it meant something else.
86
+ *
87
+ * The wait happens **server-side**, bounded by the server's own timeout. On a
88
+ * timeout the answer is a `202` carrying the current status, which is a normal
89
+ * outcome — see {@linkcode WorkflowRunResult.terminal}.
90
+ */
91
+ wait?: boolean;
92
+ /** Variables handed to the run, merged into its scope by the engine. Opaque pass-through. */
93
+ variables?: Record<string, unknown>;
94
+ /**
95
+ * What triggered the run; defaults to `"manual"` server-side.
96
+ *
97
+ * Typed as a plain `string` rather than a closed union: the value is a
98
+ * server-owned enum (`"manual" | "schedule" | "webhook" | "event" | "replay"`
99
+ * today) that the server may extend, and an SDK that froze the set would
100
+ * reject a value a newer server accepts.
101
+ */
102
+ trigger?: string;
103
+ }
104
+ /**
105
+ * What `workflows.run` returns: the server's flat body, plus two signals derived
106
+ * locally.
107
+ *
108
+ * It **is** a `RunResult` — the wire fields are present under their wire names,
109
+ * unwrapped from nothing (this route has no envelope). The two extra fields
110
+ * exist because a caller otherwise cannot tell a queued run from a finished one
111
+ * without re-deriving the rule:
112
+ *
113
+ * - {@linkcode terminal} answers "has this run finished?" from the **run's own
114
+ * status**, which is the question a caller actually has.
115
+ * - {@linkcode httpStatus} is the transport's own answer (`200` finished in
116
+ * time, `202` still going), kept because it is the distinction the server
117
+ * makes and dropping it would leave a caller unable to tell a `?wait=` timeout
118
+ * from a run that was never waited on.
119
+ */
120
+ export interface WorkflowRunResult extends RunResult {
121
+ /** `true` when `status` is `succeeded`, `failed` or `canceled`. */
122
+ terminal: boolean;
123
+ /** The HTTP status that carried this body: `200` terminal, `202` queued or still running. */
124
+ httpStatus: number;
125
+ }
126
+ /**
127
+ * The `workflows` namespace on a `W6wClient`.
128
+ *
129
+ * @example
130
+ * ```ts
131
+ * const active = (await client.workflows.list()).filter((w) => w.status === "active");
132
+ *
133
+ * const run = await client.workflows.run(active[0].id, { wait: true });
134
+ * if (run.status === "failed") console.error(run.error); // data, not an exception
135
+ * ```
136
+ */
137
+ export declare class WorkflowsApi {
138
+ #private;
139
+ /**
140
+ * @param host - The client this namespace issues requests through.
141
+ */
142
+ constructor(host: WorkflowsHost);
143
+ /**
144
+ * List the caller's workflow definitions.
145
+ *
146
+ * The project this call is scoped to is the per-call argument first, then the
147
+ * client's default, then nothing at all — an absent value means "no
148
+ * `?project=`", which is how the caller asks for every project the credential
149
+ * can see.
150
+ *
151
+ * @param options - Optional per-call project scope.
152
+ * @returns The workflows, unwrapped from the `workflows` envelope.
153
+ * @throws {ApiError} On any non-2xx.
154
+ */
155
+ list(options?: WorkflowListOptions): Promise<WorkflowSummary[]>;
156
+ /**
157
+ * Start a run of one workflow, optionally waiting for it to finish.
158
+ *
159
+ * Returns on **both** success statuses this route uses:
160
+ *
161
+ * | Call | HTTP | Body | `terminal` |
162
+ * |---|---|---|---|
163
+ * | no `wait` | `202` | `{runId, status:"queued"}` | `false` |
164
+ * | `wait: true`, finished in time | `200` | `{runId, status, output, error, steps}` | `true` |
165
+ * | `wait: true`, timed out | `202` | `{runId, status}` | `false` |
166
+ *
167
+ * **A run that failed is the second row, not an error**: `200` with
168
+ * `status: "failed"` and the failure in `error`. This method returns it. It
169
+ * raises only when the *request* failed — `404 unknown_workflow`, a rejected
170
+ * token, a transport failure.
171
+ *
172
+ * @param id - The `wf_…` id, percent-encoded into the path.
173
+ * @param options - `wait`, plus the `variables` and `trigger` that go in the body.
174
+ * @returns The run handle, its status, and the result when the run has one.
175
+ * @throws {ApiError} `404 unknown_workflow` when there is no such workflow.
176
+ * @throws {ApiError} `bad_response` when a success body is not a run object.
177
+ */
178
+ run(id: string, options?: WorkflowRunOptions): Promise<WorkflowRunResult>;
179
+ }
180
+ //# sourceMappingURL=workflows.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workflows.d.ts","sourceRoot":"","sources":["../../src/workflows.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElD,OAAO,EAAE,KAAK,YAAY,EAAQ,KAAK,cAAc,EAAE,MAAM,WAAW,CAAC;AACzE,OAAO,EAEL,KAAK,SAAS,EAGd,KAAK,eAAe,EACrB,MAAM,YAAY,CAAC;AAEpB;;;;;GAKG;AACH,MAAM,WAAW,aAAa;IAC5B,0DAA0D;IAC1D,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAC;IAChC,2BAA2B;IAC3B,OAAO,CAAC,CAAC,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC;CAC/D;AAED;;;;;GAKG;AACH,MAAM,WAAW,mBAAmB;IAClC,wEAAwE;IACxE,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,kBAAkB;IACjC;;;;;;;;;;OAUG;IACH,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,6FAA6F;IAC7F,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACpC;;;;;;;OAOG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,WAAW,iBAAkB,SAAQ,SAAS;IAClD,mEAAmE;IACnE,QAAQ,EAAE,OAAO,CAAC;IAClB,6FAA6F;IAC7F,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;;;GAUG;AACH,qBAAa,YAAY;;IAGvB;;OAEG;gBACS,IAAI,EAAE,aAAa;IAI/B;;;;;;;;;;;OAWG;IACG,IAAI,CAAC,OAAO,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;IASrE;;;;;;;;;;;;;;;;;;;;;OAqBG;IACG,GAAG,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,iBAAiB,CAAC;CAyDhF"}
@@ -0,0 +1,160 @@
1
+ /**
2
+ * `client.workflows.*` — discovery and the typed run.
3
+ *
4
+ * Two operations: `list` (T2.1.4) and `run` (T2.1.5). `list` earns its place in
5
+ * a minimal surface for the same reason `connections.list` does (D4): it is how
6
+ * a caller discovers a `wf_…` id to pass to `run`.
7
+ *
8
+ * ── `run`, and the three things this API gets called wrong ──
9
+ * 1. **`202` is success.** No `wait` → the run is queued and the server answers
10
+ * `202 {runId, status:"queued"}`. With `?wait=true` and a timeout → `202`
11
+ * again, with the current status. Neither raises.
12
+ * 2. **A failed run is data.** `?wait=true` on a run that failed is a plain
13
+ * `200` carrying `status: "failed"` and an `error`. This module returns it
14
+ * like any other result. Mapping it to an exit code is the CLI's job
15
+ * (`cli.exitCodes` in `endpoints.json`), not the SDK's.
16
+ * 3. **No client-side polling.** The server already polls internally for
17
+ * `?wait=true`, up to its own `RUN_WAIT_TIMEOUT_SEC`. The studio's 600 × 500 ms
18
+ * browser loop predates that and is deliberately **not** transcribed
19
+ * (`docs/implementation.md` §4): three wrappers each re-implementing a poll
20
+ * would be three timeout policies and three retry-storm bugs to keep in sync.
21
+ * There is no timer, no delay and no retry anywhere in this package — a `202`
22
+ * hands the caller `runId` and lets them decide.
23
+ *
24
+ * Workflows are **project-scoped**, like documents and unlike vars: the route
25
+ * accepts an optional `?project=`, resolved per call, then from the client's
26
+ * default, and otherwise left to the server. This host therefore sees the
27
+ * client's resolved configuration, which `connections` and `vars` deliberately
28
+ * do not.
29
+ *
30
+ * ── Pagination ──
31
+ * The route is **not paginated today** and this module does not pretend
32
+ * otherwise: there is no `cursor` argument, no `cursor` field, and no
33
+ * client-side paging loop. `list` returns the unwrapped array, exactly as
34
+ * `docs/implementation.md` §6 pins it.
35
+ *
36
+ * That is not a corner this signature is painted into. A JavaScript array is an
37
+ * object, so the day the server grows a cursor the wrapper can return an array
38
+ * that carries it (`WorkflowSummary[] & {cursor?: string}`) and widen this
39
+ * return type to match — every existing caller, which only ever reads the list,
40
+ * keeps compiling and keeps working. Inventing the field now would put a key on
41
+ * the type that no server has ever sent, which is the failure mode
42
+ * `endpoints.json` actually warns about.
43
+ *
44
+ * @module
45
+ */
46
+ import { ApiError } from "./errors.js";
47
+ import { path } from "./http.js";
48
+ import { isTerminalRunStatus, unwrap, } from "./types.js";
49
+ /**
50
+ * The `workflows` namespace on a `W6wClient`.
51
+ *
52
+ * @example
53
+ * ```ts
54
+ * const active = (await client.workflows.list()).filter((w) => w.status === "active");
55
+ *
56
+ * const run = await client.workflows.run(active[0].id, { wait: true });
57
+ * if (run.status === "failed") console.error(run.error); // data, not an exception
58
+ * ```
59
+ */
60
+ export class WorkflowsApi {
61
+ #host;
62
+ /**
63
+ * @param host - The client this namespace issues requests through.
64
+ */
65
+ constructor(host) {
66
+ this.#host = host;
67
+ }
68
+ /**
69
+ * List the caller's workflow definitions.
70
+ *
71
+ * The project this call is scoped to is the per-call argument first, then the
72
+ * client's default, then nothing at all — an absent value means "no
73
+ * `?project=`", which is how the caller asks for every project the credential
74
+ * can see.
75
+ *
76
+ * @param options - Optional per-call project scope.
77
+ * @returns The workflows, unwrapped from the `workflows` envelope.
78
+ * @throws {ApiError} On any non-2xx.
79
+ */
80
+ async list(options) {
81
+ const res = await this.#host.request({
82
+ method: "GET",
83
+ path: "/workflows",
84
+ query: { project: options?.project ?? this.#host.config.project ?? undefined },
85
+ });
86
+ return unwrap(res, "workflows");
87
+ }
88
+ /**
89
+ * Start a run of one workflow, optionally waiting for it to finish.
90
+ *
91
+ * Returns on **both** success statuses this route uses:
92
+ *
93
+ * | Call | HTTP | Body | `terminal` |
94
+ * |---|---|---|---|
95
+ * | no `wait` | `202` | `{runId, status:"queued"}` | `false` |
96
+ * | `wait: true`, finished in time | `200` | `{runId, status, output, error, steps}` | `true` |
97
+ * | `wait: true`, timed out | `202` | `{runId, status}` | `false` |
98
+ *
99
+ * **A run that failed is the second row, not an error**: `200` with
100
+ * `status: "failed"` and the failure in `error`. This method returns it. It
101
+ * raises only when the *request* failed — `404 unknown_workflow`, a rejected
102
+ * token, a transport failure.
103
+ *
104
+ * @param id - The `wf_…` id, percent-encoded into the path.
105
+ * @param options - `wait`, plus the `variables` and `trigger` that go in the body.
106
+ * @returns The run handle, its status, and the result when the run has one.
107
+ * @throws {ApiError} `404 unknown_workflow` when there is no such workflow.
108
+ * @throws {ApiError} `bad_response` when a success body is not a run object.
109
+ */
110
+ async run(id, options) {
111
+ const res = await this.#host.request({
112
+ method: "POST",
113
+ path: path `/workflows/${id}/run`,
114
+ // `?wait=true` or no `wait` at all — never `?wait=false`, which the server
115
+ // reads as "no wait" anyway and which would misrepresent the request in a
116
+ // log or a proxy.
117
+ query: { wait: options?.wait ? true : undefined },
118
+ // Always a body, even when empty: the route parses one when the text is
119
+ // non-empty and defaults to `{}` otherwise, so `{}` and no body are the
120
+ // same request — and sending the object keeps the two optional fields at
121
+ // one place instead of behind a conditional.
122
+ body: { variables: options?.variables, trigger: options?.trigger },
123
+ });
124
+ const body = res.body;
125
+ // The `runId` and `status` checks are the guard, not decoration. An
126
+ // object-only check let `{}`, `[]`, `[{…}]` and `{"ok":true}` through and
127
+ // returned a `WorkflowRunResult` whose `runId: string` and `status:
128
+ // RunStatus` were **`undefined` at runtime** (measured) — a lie the compiler
129
+ // cannot catch, which becomes a `TypeError` somewhere in the caller minutes
130
+ // later. That is the failure this package's own `unwrap` exists to prevent.
131
+ //
132
+ // Requiring the two fields also subsumes the array case (`[].runId` is
133
+ // `undefined`), and makes this guard exactly as strict as its sibling in
134
+ // `src/run.ts`, which requires a string `kind`: two operations in one
135
+ // package must not disagree about what a malformed success body is. It
136
+ // keeps the lanes in step too — python's idiomatic `isinstance(body, dict)`
137
+ // rejects `[]` where `typeof [] === "object"` accepts it.
138
+ if (typeof body !== "object" || body === null ||
139
+ typeof body.runId !== "string" ||
140
+ typeof body.status !== "string") {
141
+ throw new ApiError(res.status, "bad_response", `Server returned a ${res.status} whose body is not a run object.`, body);
142
+ }
143
+ const run = body;
144
+ const status = run.status;
145
+ return {
146
+ // Spread first so any field a newer server adds survives; the normalised
147
+ // ones below then take their pinned shape.
148
+ ...run,
149
+ runId: run.runId,
150
+ status,
151
+ // A `202` carries no `steps`. Normalised to `{}` rather than left absent,
152
+ // so a caller iterating a run's steps never has to branch on which status
153
+ // carried it — the same reason an empty list is `[]` and not `null`.
154
+ steps: run.steps ?? {},
155
+ terminal: isTerminalRunStatus(status),
156
+ httpStatus: res.status,
157
+ };
158
+ }
159
+ }
160
+ //# sourceMappingURL=workflows.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workflows.js","sourceRoot":"","sources":["../../src/workflows.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AAGH,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,EAAqB,IAAI,EAAuB,MAAM,WAAW,CAAC;AACzE,OAAO,EACL,mBAAmB,EAGnB,MAAM,GAEP,MAAM,YAAY,CAAC;AAmFpB;;;;;;;;;;GAUG;AACH,MAAM,OAAO,YAAY;IACd,KAAK,CAAgB;IAE9B;;OAEG;IACH,YAAY,IAAmB;QAC7B,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;IACpB,CAAC;IAED;;;;;;;;;;;OAWG;IACH,KAAK,CAAC,IAAI,CAAC,OAA6B;QACtC,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,CAAU;YAC5C,MAAM,EAAE,KAAK;YACb,IAAI,EAAE,YAAY;YAClB,KAAK,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,IAAI,SAAS,EAAE;SAC/E,CAAC,CAAC;QACH,OAAO,MAAM,CAAoB,GAAG,EAAE,WAAW,CAAC,CAAC;IACrD,CAAC;IAED;;;;;;;;;;;;;;;;;;;;;OAqBG;IACH,KAAK,CAAC,GAAG,CAAC,EAAU,EAAE,OAA4B;QAChD,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,CAAU;YAC5C,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,IAAI,CAAA,cAAc,EAAE,MAAM;YAChC,2EAA2E;YAC3E,0EAA0E;YAC1E,kBAAkB;YAClB,KAAK,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,EAAE;YACjD,wEAAwE;YACxE,wEAAwE;YACxE,yEAAyE;YACzE,6CAA6C;YAC7C,IAAI,EAAE,EAAE,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE;SACnE,CAAC,CAAC;QAEH,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC;QACtB,oEAAoE;QACpE,0EAA0E;QAC1E,oEAAoE;QACpE,6EAA6E;QAC7E,4EAA4E;QAC5E,4EAA4E;QAC5E,EAAE;QACF,uEAAuE;QACvE,yEAAyE;QACzE,sEAAsE;QACtE,uEAAuE;QACvE,4EAA4E;QAC5E,0DAA0D;QAC1D,IACE,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,IAAI;YACzC,OAAQ,IAA4B,CAAC,KAAK,KAAK,QAAQ;YACvD,OAAQ,IAA6B,CAAC,MAAM,KAAK,QAAQ,EACzD,CAAC;YACD,MAAM,IAAI,QAAQ,CAChB,GAAG,CAAC,MAAM,EACV,cAAc,EACd,qBAAqB,GAAG,CAAC,MAAM,kCAAkC,EACjE,IAAI,CACL,CAAC;QACJ,CAAC;QACD,MAAM,GAAG,GAAG,IAA0B,CAAC;QACvC,MAAM,MAAM,GAAG,GAAG,CAAC,MAAmB,CAAC;QACvC,OAAO;YACL,yEAAyE;YACzE,2CAA2C;YAC3C,GAAG,GAAG;YACN,KAAK,EAAE,GAAG,CAAC,KAAe;YAC1B,MAAM;YACN,0EAA0E;YAC1E,0EAA0E;YAC1E,qEAAqE;YACrE,KAAK,EAAE,GAAG,CAAC,KAAK,IAAI,EAAE;YACtB,QAAQ,EAAE,mBAAmB,CAAC,MAAM,CAAC;YACrC,UAAU,EAAE,GAAG,CAAC,MAAM;SACvB,CAAC;IACJ,CAAC;CACF"}
package/package.json ADDED
@@ -0,0 +1,36 @@
1
+ {
2
+ "name": "@w6w/sdk",
3
+ "version": "0.1.0",
4
+ "description": "Typed client for the w6w HTTP API. Thin transport, auth and error mapping — nothing else.",
5
+ "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/w6w-io/w6w-node.git"
9
+ },
10
+ "homepage": "https://github.com/w6w-io/w6w-node#readme",
11
+ "bugs": "https://github.com/w6w-io/w6w-node/issues",
12
+ "keywords": ["w6w", "workflow", "sdk", "client", "api"],
13
+ "type": "module",
14
+ "types": "./dist/mod.d.ts",
15
+ "main": "./dist/mod.js",
16
+ "exports": {
17
+ ".": {
18
+ "types": "./dist/mod.d.ts",
19
+ "import": "./dist/mod.js"
20
+ }
21
+ },
22
+ "files": ["dist"],
23
+ "sideEffects": false,
24
+ "engines": {
25
+ "node": ">=18"
26
+ },
27
+ "scripts": {
28
+ "build": "tsc -p tsconfig.build.json"
29
+ },
30
+ "devDependencies": {
31
+ "typescript": "^5.7.2"
32
+ },
33
+ "publishConfig": {
34
+ "access": "public"
35
+ }
36
+ }