@gusnips/sdkgen 0.1.0 → 0.2.1

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.
package/README.md CHANGED
@@ -1,7 +1,8 @@
1
1
  # @gusnips/sdkgen
2
2
 
3
- The parts of a script that writes a TypeScript SDK for your API. You keep the script, because the
4
- methods it writes are yours. This package holds the parts that are easy to get wrong.
3
+ The parts of a script that writes a TypeScript SDK for your API. You keep the script: it picks the
4
+ names, the doc text and anything written by hand. This package writes the rest, including the
5
+ parts that are easy to get wrong.
5
6
 
6
7
  ```bash
7
8
  bun add -d @gusnips/sdkgen prettier
@@ -39,6 +40,9 @@ fieldsOf(inputJsonSchema(z.object({ to: z.string().describe("Who gets it.") })))
39
40
  | `camelCase`, `pascalCase` | `send_message` gives `sendMessage` and `SendMessage`. |
40
41
  | `inputJsonSchema` | Turns a zod schema into JSON Schema. JSON Schema passes through as it is. |
41
42
  | `writeGenerated` | Formats and writes the files, or lists the ones that are out of date. |
43
+ | `sdkMethods` | Writes one SDK method per operation, and the params type each one takes. |
44
+ | `transportSource` | Returns the code every method runs on: the request, the retries, the error. |
45
+ | `retrySource` | Returns the rule for when a failed call is worth another try. |
42
46
 
43
47
  ## Copy your API's types
44
48
 
@@ -76,6 +80,141 @@ output drops the comments. It finds `export interface`, `export type`, `export c
76
80
  If a real type has a name that short, the SDK will not compile, so you find out.
77
81
  - A quote inside a regex literal, like `/"/`, is read as the start of a string.
78
82
 
83
+ ## Write the methods
84
+
85
+ Give each operation an `sdk` field that says what its method is called and what it returns. An
86
+ operation without one gets no method.
87
+
88
+ ```ts
89
+ import { sdkMethods } from "@gusnips/sdkgen";
90
+
91
+ const { members } = sdkMethods([
92
+ {
93
+ name: "health",
94
+ method: "get",
95
+ path: "/health",
96
+ summary: "Check the API is up.",
97
+ sdk: { method: "health", returns: "HealthDto" },
98
+ },
99
+ ]);
100
+ ```
101
+
102
+ `members` is the method as text, ready to go inside a class:
103
+
104
+ ```ts
105
+ /**
106
+ * Check the API is up.
107
+ */
108
+ health(opts?: Omit<RequestOptions, "idempotencyKey">): Promise<HealthDto> {
109
+ return this.request({ method: "GET", path: "/health" }, undefined, opts);
110
+ }
111
+ ```
112
+
113
+ The operations are the same list you hand `buildOpenApi` from `@gusnips/server`, so you write them
114
+ once. `sdk.method` is a name like `sendMessage`, or `numbers.pair` to put the method in a `numbers`
115
+ group. `sdk.returns` is the type `data` holds: `MessageDto`, `NumberDto[]`, or `void` for a 204.
116
+ From `@gusnips/server` 0.8.24, `buildOpenApi` checks the `sdk` field and writes it into the
117
+ reference as `x-sdk`.
118
+
119
+ Each method calls `this.request(spec, params, opts)`. Your class declares it and sends the call
120
+ through the transport, below. `sdkMethods` also returns:
121
+
122
+ - `params`: an `export interface …Params` for each method that takes arguments, written from the
123
+ operation's `input` schema. A path slot is filled from the field of its name, or the one
124
+ `params` maps to it.
125
+ - `paramTypes` and `returnTypes`: the names your file has to import.
126
+ - `routes`: where each generated method sends its call, keyed by the method. Here that is
127
+ `{ health: { method: "GET", path: "/health", pathParams: [] } }`. A slot in `path` carries the
128
+ argument's name, and `pathParams` lists those arguments in path order. Use it for a docs page
129
+ that shows a REST call beside the SDK call that makes it.
130
+
131
+ Four options:
132
+
133
+ - `namespaces`: the groups, in the order the client lists them. A group missing from the list is an
134
+ error, so a typo cannot start a new one.
135
+ - `doc(op)`: the method's doc comment, one string per paragraph. Default: the summary, then the
136
+ description.
137
+ - `specExtra(op)`: more fields on the spec, for your own `request` to read.
138
+ - `inject`: methods you write by hand, such as one that polls a job. They go beside the generated
139
+ ones and must not take one of their names.
140
+
141
+ It stops with an error that names the operation when a method name has more than one dot, two
142
+ methods want one name, a status with no body (204, 205, 304) returns something, or a path slot is
143
+ filled by a field the caller may leave out.
144
+
145
+ ## Send the calls
146
+
147
+ Two more files go into the SDK. `transportSource()` is the code that sends each call: it fills the
148
+ path, tries again when that is safe, and turns a failure into your SDK's own error.
149
+ `retrySource()` is the rule it asks, from `@gusnips/http`. Both are plain TypeScript that import
150
+ nothing else, so the SDK installs nothing.
151
+
152
+ ```ts
153
+ import { retrySource, transportSource } from "@gusnips/sdkgen";
154
+
155
+ const files = {
156
+ "packages/sdk/src/generated/retry.ts": retrySource(),
157
+ "packages/sdk/src/generated/transport.ts": transportSource(),
158
+ };
159
+ ```
160
+
161
+ Your client hands its settings to `send`, which returns `{ data, meta }`:
162
+
163
+ ```ts
164
+ import { GeneratedOperations } from "./generated/operations.ts";
165
+ import {
166
+ send,
167
+ type RequestOptions,
168
+ type RequestSpec,
169
+ type Transport,
170
+ } from "./generated/transport.ts";
171
+
172
+ export class Example extends GeneratedOperations {
173
+ private readonly transport: Transport;
174
+
175
+ constructor(apiKey: string) {
176
+ super();
177
+ this.transport = {
178
+ baseUrl: "https://api.example.com/v1",
179
+ headers: { authorization: `Bearer ${apiKey}` },
180
+ error: (failure) => new ExampleError(failure),
181
+ };
182
+ }
183
+
184
+ protected async request<T>(spec: RequestSpec, params?: object, opts?: RequestOptions) {
185
+ return (await send<T>(this.transport, spec, params, opts)).data;
186
+ }
187
+ }
188
+ ```
189
+
190
+ | Setting | Default | What it does |
191
+ | ------------------------- | --------- | --------------------------------------------------------------------------- |
192
+ | `baseUrl` | required | Where the API lives, with its base path. |
193
+ | `error(failure)` | required | Builds your SDK's error. The transport throws what it returns. |
194
+ | `headers` | none | Sent on every call. |
195
+ | `fetch` | global | The fetch to call, such as a fake one in tests. |
196
+ | `timeoutMs(spec, params)` | 30,000 ms | How long one try waits for an answer. A call's `opts.timeoutMs` wins. |
197
+ | `maxRetries` | 2 | Extra tries after a failure worth repeating. |
198
+ | `durableCodes` | none | Error codes that waiting does not fix, such as a spent monthly quota. |
199
+ | `mintKeys` | false | Makes up an idempotency key for a call that takes one, so it can try again. |
200
+
201
+ `failure` has the status (0 when no answer came back), the API's `error`, the `Retry-After` wait,
202
+ the request id, and the idempotency key the call went out with. A call that may have run can be
203
+ sent again with that key, and the API answers from the first run.
204
+
205
+ A failed call is tried again:
206
+
207
+ - **After a 408, 425 or 429**, whatever it is. Those say the API did not run it.
208
+ - **After no answer, a 5xx, or a 409 that says when to come back**, only if running it twice is
209
+ safe. A GET is. A write is when its operation reads an `Idempotency-Key` and the call has one, or
210
+ when its `sdk.repeatable` is true. A write without a key is not sent twice, because it may
211
+ already have run.
212
+ - **Never** when the answer says waiting will not help: a code in `durableCodes`,
213
+ `details.retryAfterSecs: null`, or a wait longer than 10 seconds.
214
+
215
+ It waits what the `Retry-After` header says, in seconds or as a date, then what
216
+ `details.retryAfterSecs` says. With neither, it waits about 1 second, then 2.
217
+
79
218
  ## Keep the SDK current
80
219
 
81
220
  ```ts
@@ -108,6 +247,11 @@ error and not "out of date".
108
247
  - **A `*/` in a description is broken up**, so it cannot end the doc comment early.
109
248
  - **A zod schema needs zod 4.4 or later.** Older versions cannot describe themselves as JSON
110
249
  Schema, and the error says so.
250
+ - **A call with a missing path value throws a TypeError** before anything is sent, rather than
251
+ calling `/numbers//pair`.
252
+ - **An idempotency key on a call that takes none throws.** The API would ignore it, so it could not
253
+ stop the call running twice. The method's type refuses it first: only a call that takes a key
254
+ accepts `idempotencyKey` in its options.
111
255
 
112
256
  ## Why it exists
113
257
 
@@ -121,7 +265,7 @@ had fixed something the others had not, and every one still had these bugs:
121
265
  - `export interface Empty {}` on one line swallowed the declaration after it.
122
266
  - A comment written `/*/` ended on the character that opened it.
123
267
 
124
- This package is the merge, with each fix pinned by a test. Two of those generators were rewritten
125
- on it and wrote every file byte for byte as before, 268 and 281 lines shorter.
268
+ This package is the merge, with each fix pinned by a test. All five generators were then rewritten
269
+ on it and wrote every file byte for byte as before, each 267 to 281 lines shorter.
126
270
 
127
271
  MIT
package/dist/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export { liftContract, type LiftOptions } from "./contract.ts";
2
+ export { retrySource, sdkMethods, transportSource, type InjectedMember, type SdkMethods, type SdkMethodsOptions, type SdkOperation, type SdkPlacement, type SdkRoute, } from "./methods.ts";
2
3
  export { camelCase, docComment, fieldsOf, inputJsonSchema, paramsInterface, pascalCase, typeNames, typeOf, wrapLines, type JsonObject, type SchemaSource, type StandardJsonSchema, } from "./types.ts";
3
4
  export { writeGenerated, type GeneratedFiles, type WriteOptions, type WriteResult, } from "./write.ts";
4
5
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,KAAK,WAAW,EAAE,MAAM,eAAe,CAAC;AAC/D,OAAO,EACL,SAAS,EACT,UAAU,EACV,QAAQ,EACR,eAAe,EACf,eAAe,EACf,UAAU,EACV,SAAS,EACT,MAAM,EACN,SAAS,EACT,KAAK,UAAU,EACf,KAAK,YAAY,EACjB,KAAK,kBAAkB,GACxB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,cAAc,EACd,KAAK,cAAc,EACnB,KAAK,YAAY,EACjB,KAAK,WAAW,GACjB,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,KAAK,WAAW,EAAE,MAAM,eAAe,CAAC;AAC/D,OAAO,EACL,WAAW,EACX,UAAU,EACV,eAAe,EACf,KAAK,cAAc,EACnB,KAAK,UAAU,EACf,KAAK,iBAAiB,EACtB,KAAK,YAAY,EACjB,KAAK,YAAY,EACjB,KAAK,QAAQ,GACd,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,SAAS,EACT,UAAU,EACV,QAAQ,EACR,eAAe,EACf,eAAe,EACf,UAAU,EACV,SAAS,EACT,MAAM,EACN,SAAS,EACT,KAAK,UAAU,EACf,KAAK,YAAY,EACjB,KAAK,kBAAkB,GACxB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,cAAc,EACd,KAAK,cAAc,EACnB,KAAK,YAAY,EACjB,KAAK,WAAW,GACjB,MAAM,YAAY,CAAC"}
package/dist/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  export { liftContract } from "./contract.js";
2
+ export { retrySource, sdkMethods, transportSource, } from "./methods.js";
2
3
  export { camelCase, docComment, fieldsOf, inputJsonSchema, paramsInterface, pascalCase, typeNames, typeOf, wrapLines, } from "./types.js";
3
4
  export { writeGenerated, } from "./write.js";
4
5
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAoB,MAAM,eAAe,CAAC;AAC/D,OAAO,EACL,SAAS,EACT,UAAU,EACV,QAAQ,EACR,eAAe,EACf,eAAe,EACf,UAAU,EACV,SAAS,EACT,MAAM,EACN,SAAS,GAIV,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,cAAc,GAIf,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAoB,MAAM,eAAe,CAAC;AAC/D,OAAO,EACL,WAAW,EACX,UAAU,EACV,eAAe,GAOhB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,SAAS,EACT,UAAU,EACV,QAAQ,EACR,eAAe,EACf,eAAe,EACf,UAAU,EACV,SAAS,EACT,MAAM,EACN,SAAS,GAIV,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,cAAc,GAIf,MAAM,YAAY,CAAC"}
@@ -0,0 +1,119 @@
1
+ import { type SchemaSource } from "./types.ts";
2
+ /** Where the generated SDK puts an operation. */
3
+ export interface SdkPlacement {
4
+ /** `sendMessage`, or `numbers.pair` in a namespace. One dot at most; unique. */
5
+ method: string;
6
+ /** What `data` holds, as the SDK names it: `MessageDto`, `NumberDto[]`; `void` for a 204. */
7
+ returns: string;
8
+ /**
9
+ * Safe to run twice with no key: a read sent as a POST, or a write the server dedupes on its
10
+ * own. Default: a GET only.
11
+ */
12
+ repeatable?: boolean;
13
+ }
14
+ /**
15
+ * The part of an operation the generator reads. It is a structural subset of `@gusnips/server`'s
16
+ * `OpenApiOperation`, so the list an API hands `buildOpenApi` fits here unchanged.
17
+ */
18
+ export interface SdkOperation {
19
+ name: string;
20
+ method: "get" | "post" | "put" | "patch" | "delete";
21
+ /** The route as the router spells it: `/numbers/:id`. */
22
+ path: string;
23
+ summary: string;
24
+ description?: string;
25
+ /** Everything the operation reads. It becomes the method's params interface. */
26
+ input?: SchemaSource;
27
+ /** Input field → path slot, where the two names differ: `{ numberId: "id" }`. */
28
+ params?: Readonly<Record<string, string>>;
29
+ /** Fields the route fills in itself. The SDK leaves them out. */
30
+ fixed?: readonly string[];
31
+ /** Request headers the operation reads. An `Idempotency-Key` here makes the call keyed. */
32
+ headers?: readonly {
33
+ readonly name: string;
34
+ }[];
35
+ /** The success status. A 204, 205 or 304 has no body, so it returns `void`. */
36
+ status?: number;
37
+ extensions?: Readonly<Record<`x-${string}`, unknown>>;
38
+ /** Where the generated SDK puts this operation. Absent: no method. */
39
+ sdk?: SdkPlacement;
40
+ }
41
+ /** A member written by hand, placed beside the generated ones and held to the same names. */
42
+ export interface InjectedMember {
43
+ /** `jobs.wait`, or `wait` at the top level. */
44
+ method: string;
45
+ /** Its parameters and return type: `(jobId: string, opts?: WaitOptions): Promise<JobDto>`. */
46
+ signature: string;
47
+ /** What it returns: `this.waitForJob(jobId, opts)`. */
48
+ call: string;
49
+ /** Its doc comment, one string per paragraph. */
50
+ doc?: readonly string[];
51
+ }
52
+ export interface SdkMethodsOptions {
53
+ /**
54
+ * The namespaces, in the order the client lists them. Given, a namespace not in it throws, so a
55
+ * typo cannot start a new one. Default: the order they first appear.
56
+ */
57
+ namespaces?: readonly string[];
58
+ /**
59
+ * A method's doc comment, one string per paragraph; `undefined` ones are skipped. Default: the
60
+ * summary, then the description.
61
+ */
62
+ doc?: (op: SdkOperation) => readonly (string | undefined)[];
63
+ /** Fields to add to the spec an operation hands `request`, such as its proxy block's fields. */
64
+ specExtra?: (op: SdkOperation) => Readonly<Record<string, unknown>> | undefined;
65
+ /** Members written by hand, each after the generated ones in its place. */
66
+ inject?: readonly InjectedMember[];
67
+ }
68
+ export interface SdkMethods {
69
+ /** An `export interface …Params` for each method that takes arguments: the body of `params.ts`. */
70
+ params: string;
71
+ /**
72
+ * The class members: top-level methods first, then one object per namespace. Each calls
73
+ * `this.request(spec, params, opts)`, which the class declares and the SDK implements.
74
+ */
75
+ members: string;
76
+ /** The params interfaces the members name, sorted, for their import line. */
77
+ paramTypes: string[];
78
+ /** The declared types the `returns` name, sorted, for their import from the contract. */
79
+ returnTypes: string[];
80
+ /**
81
+ * Each generated method's route as the SDK spells it, keyed by the method: `numbers.get` →
82
+ * `{ method: "GET", path: "/numbers/:numberId", pathParams: ["numberId"] }`. For a page that
83
+ * shows a REST call beside the SDK call that makes it. Hand-written members have none.
84
+ */
85
+ routes: Record<string, SdkRoute>;
86
+ }
87
+ /** Where a generated method sends its call. */
88
+ export interface SdkRoute {
89
+ method: "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
90
+ /** The path with each slot named for the argument that fills it: `/numbers/:numberId`. */
91
+ path: string;
92
+ /** The arguments that fill the path, in the order the path has them. */
93
+ pathParams: string[];
94
+ }
95
+ /**
96
+ * The SDK's methods for every operation that names an `sdk` place, with the params interfaces they
97
+ * take.
98
+ *
99
+ * ```ts
100
+ * const { params, members, paramTypes, returnTypes } = sdkMethods(operations);
101
+ * const file = `export abstract class GeneratedOperations {
102
+ * protected abstract request<T>(spec: RequestSpec, params?: object, opts?: RequestOptions): Promise<T>;
103
+ * ${members}}\n`;
104
+ * ```
105
+ */
106
+ export declare function sdkMethods(operations: readonly SdkOperation[], options?: SdkMethodsOptions): SdkMethods;
107
+ /**
108
+ * `@gusnips/http`'s retry rule, its `src/retry.ts` whole, for an SDK to carry as
109
+ * `generated/retry.ts`. It is read from this package's own dependency, never the adopter's, so
110
+ * every SDK built with one sdkgen carries one rule. When an sdkgen release moves the rule, each
111
+ * SDK's `--check` fails, and that is the signal to release the SDK.
112
+ */
113
+ export declare function retrySource(): string;
114
+ /**
115
+ * The transport every generated method runs on, for an SDK to carry as `generated/transport.ts`
116
+ * beside `retry.ts`: this package's own `src/transport.ts`, importing the rule from `./retry.ts`.
117
+ */
118
+ export declare function transportSource(): string;
119
+ //# sourceMappingURL=methods.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"methods.d.ts","sourceRoot":"","sources":["../src/methods.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,248 @@
1
+ /**
2
+ * The methods an SDK exposes, written from the operation list the API already mounts, and the two
3
+ * files they run on.
4
+ *
5
+ * Five generators each wrote this loop, and what they shared is here: one method per operation,
6
+ * grouped by namespace, taking the params interface its input schema gives and returning the type
7
+ * the operation says `data` holds; a path whose slots carry the argument's own name, so the
8
+ * transport can fill them; and the checks that stop a wrong SDK at generation rather than in the
9
+ * hands of whoever installs it. What differs by product comes in through options: the doc
10
+ * comment's paragraphs, what the spec carries beyond the route, and members written by hand.
11
+ *
12
+ * It reads the operation list in-process, never the published OpenAPI document. The document has
13
+ * lost the type names, the argument renames and the typed query params, and a type JSON cannot
14
+ * carry reaches it as `{}`, where the schema writer here would have stopped.
15
+ */
16
+ import { readFileSync } from "node:fs";
17
+ import { createRequire } from "node:module";
18
+ import { dirname, join } from "node:path";
19
+ import { fileURLToPath } from "node:url";
20
+ import { inputJsonSchema, paramsInterface, pascalCase, typeNames, wrapLines, } from "./types.js";
21
+ /** Success statuses with no body (RFC 9110), the same three the server's reference documents so. */
22
+ const NO_BODY = new Set([204, 205, 304]);
23
+ /** Class members a method must not be named: the seam every method calls, and the constructor. */
24
+ const RESERVED = new Set(["request", "constructor"]);
25
+ /** The spec fields the generator writes, which `specExtra` must not overwrite. */
26
+ const SPEC_FIELDS = new Set(["method", "path", "keyed", "repeatable"]);
27
+ const IDENTIFIER = /^[A-Za-z_$][\w$]*$/;
28
+ const VERB = { get: "GET", post: "POST", put: "PUT", patch: "PATCH", delete: "DELETE" };
29
+ /**
30
+ * The SDK's methods for every operation that names an `sdk` place, with the params interfaces they
31
+ * take.
32
+ *
33
+ * ```ts
34
+ * const { params, members, paramTypes, returnTypes } = sdkMethods(operations);
35
+ * const file = `export abstract class GeneratedOperations {
36
+ * protected abstract request<T>(spec: RequestSpec, params?: object, opts?: RequestOptions): Promise<T>;
37
+ * ${members}}\n`;
38
+ * ```
39
+ */
40
+ export function sdkMethods(operations, options = {}) {
41
+ const { doc = (op) => [op.summary, op.description], specExtra, inject = [] } = options;
42
+ const members = [];
43
+ const params = [];
44
+ const paramTypes = [];
45
+ const returnTypes = new Set();
46
+ const routes = {};
47
+ for (const op of operations) {
48
+ const sdk = op.sdk;
49
+ if (sdk === undefined)
50
+ continue;
51
+ const where = `${op.method.toUpperCase()} ${op.path} (${op.name})`;
52
+ if (op.status !== undefined && NO_BODY.has(op.status) && sdk.returns !== "void") {
53
+ throw new Error(`${where} answers ${op.status}, which has no body, so \`sdk.returns\` must be "void".`);
54
+ }
55
+ const schema = op.input === undefined ? undefined : schemaOf(op.input, where);
56
+ const fixed = op.fixed ?? [];
57
+ const typeName = `${pascalCase(op.name)}Params`;
58
+ const iface = schema === undefined ? null : paramsInterface(typeName, schema, fixed);
59
+ if (iface !== null) {
60
+ params.push(`/** Arguments for \`${sdk.method}()\`. */\n${iface.source}`);
61
+ paramTypes.push(typeName);
62
+ }
63
+ for (const name of typeNames(sdk.returns))
64
+ returnTypes.add(name);
65
+ const listed = schema?.["required"];
66
+ const required = new Set(Array.isArray(listed)
67
+ ? listed.filter((f) => typeof f === "string" && !fixed.includes(f))
68
+ : []);
69
+ const method = VERB[op.method];
70
+ const path = sdkPath(op, required, where);
71
+ routes[sdk.method] = {
72
+ method,
73
+ path,
74
+ pathParams: [...path.matchAll(/:(\w+)/g)].flatMap((match) => match[1] ?? []),
75
+ };
76
+ const fields = [`method: "${method}"`, `path: ${JSON.stringify(path)}`];
77
+ const keyed = op.headers?.some((h) => h.name.toLowerCase() === "idempotency-key") === true;
78
+ if (keyed)
79
+ fields.push("keyed: true");
80
+ if (sdk.repeatable !== undefined)
81
+ fields.push(`repeatable: ${sdk.repeatable}`);
82
+ for (const [key, value] of Object.entries(specExtra?.(op) ?? {})) {
83
+ if (SPEC_FIELDS.has(key)) {
84
+ throw new Error(`${where}: \`specExtra\` sets "${key}", which the generator writes itself.`);
85
+ }
86
+ if (value !== undefined)
87
+ fields.push(`${propertyKey(key)}: ${JSON.stringify(value)}`);
88
+ }
89
+ const argument = iface === null ? "" : `params${iface.optional ? "?" : ""}: ${typeName}, `;
90
+ // A key on a call that takes none is refused by the transport at runtime; the type refuses it
91
+ // first, where the caller's editor shows it.
92
+ const options = keyed ? "RequestOptions" : `Omit<RequestOptions, "idempotencyKey">`;
93
+ members.push({
94
+ where,
95
+ ...place(sdk.method, where),
96
+ doc: doc(op),
97
+ signature: `(${argument}opts?: ${options}): Promise<${sdk.returns}>`,
98
+ call: `this.request({ ${fields.join(", ")} }, ${iface === null ? "undefined" : "params"}, opts)`,
99
+ });
100
+ }
101
+ for (const member of inject) {
102
+ const where = `The hand-written ${member.method}`;
103
+ members.push({
104
+ where,
105
+ ...place(member.method, where),
106
+ doc: member.doc ?? [],
107
+ signature: member.signature,
108
+ call: member.call,
109
+ });
110
+ }
111
+ return {
112
+ params: params.join("\n"),
113
+ members: writeMembers(members, options.namespaces),
114
+ paramTypes: paramTypes.sort(),
115
+ returnTypes: [...returnTypes].sort(),
116
+ routes,
117
+ };
118
+ }
119
+ /** `numbers.pair` → its namespace and name, each checked to be a name a class member can have. */
120
+ function place(method, where) {
121
+ const parts = method.split(".");
122
+ if (parts.length > 2 || !parts.every((part) => IDENTIFIER.test(part))) {
123
+ throw new Error(`${where}: \`${method}\` is not a method name. Write \`name\`, or \`namespace.name\` with one dot.`);
124
+ }
125
+ const [first = "", second] = parts;
126
+ return second === undefined
127
+ ? { namespace: undefined, name: first }
128
+ : { namespace: first, name: second };
129
+ }
130
+ /** Top-level methods first, then one `readonly namespace = { … }` per namespace. */
131
+ function writeMembers(members, order) {
132
+ const seen = new Map();
133
+ const topLevel = new Set();
134
+ const namespaces = [];
135
+ for (const { where, namespace, name } of members) {
136
+ const full = namespace === undefined ? name : `${namespace}.${name}`;
137
+ const first = seen.get(full);
138
+ if (first !== undefined) {
139
+ throw new Error(`Two methods want to be \`${full}\`: ${first}, and ${where}. Rename one.`);
140
+ }
141
+ seen.set(full, where);
142
+ if (namespace === undefined)
143
+ topLevel.add(name);
144
+ else if (!namespaces.includes(namespace))
145
+ namespaces.push(namespace);
146
+ }
147
+ for (const name of [...topLevel, ...namespaces]) {
148
+ if (RESERVED.has(name)) {
149
+ throw new Error(`\`${name}\` is a class member every SDK already has. Pick another name.`);
150
+ }
151
+ if (topLevel.has(name) && namespaces.includes(name)) {
152
+ throw new Error(`\`${name}\` is both a method and a namespace. Rename one.`);
153
+ }
154
+ }
155
+ if (order !== undefined) {
156
+ const unknown = namespaces.find((namespace) => !order.includes(namespace));
157
+ if (unknown !== undefined) {
158
+ throw new Error(`The namespace \`${unknown}\` is not in \`namespaces\`. Add it there, or use one of: ${order.join(", ")}.`);
159
+ }
160
+ }
161
+ let out = "";
162
+ for (const member of members.filter((m) => m.namespace === undefined)) {
163
+ out += `\n${jsdoc(member.doc, " ")} ${member.name}${member.signature} {\n`;
164
+ out += ` return ${member.call};\n }\n`;
165
+ }
166
+ for (const namespace of (order ?? namespaces).filter((ns) => namespaces.includes(ns))) {
167
+ out += `\n readonly ${namespace} = {\n`;
168
+ for (const member of members.filter((m) => m.namespace === namespace)) {
169
+ out += `${jsdoc(member.doc, " ")} ${member.name}: ${member.signature} =>\n`;
170
+ out += ` ${member.call},\n`;
171
+ }
172
+ out += ` };\n`;
173
+ }
174
+ return out;
175
+ }
176
+ /**
177
+ * The route with each slot named for the argument that fills it: `/numbers/:id` with
178
+ * `{ numberId: "id" }` → `/numbers/:numberId`. A slot's argument must be required, or the SDK
179
+ * would let a caller leave out part of the address.
180
+ */
181
+ function sdkPath(op, required, where) {
182
+ // A constraint such as `:id{[0-9]+}` is the router's business, and the SDK drops it.
183
+ const slot = /:(\w+)(\{[^}]*\})?(\?)?/g;
184
+ const slots = new Set([...op.path.matchAll(slot)].map((match) => match[1]));
185
+ const fieldIn = new Map();
186
+ for (const [field, name] of Object.entries(op.params ?? {})) {
187
+ if (!slots.has(name)) {
188
+ throw new Error(`${where}: \`params\` sends ${field} in ":${name}", which the path does not have.`);
189
+ }
190
+ fieldIn.set(name, field);
191
+ }
192
+ return op.path.replace(slot, (_match, name, _re, optional) => {
193
+ if (optional) {
194
+ throw new Error(`${where} has an optional slot ":${name}?". List it as two operations, with and without it.`);
195
+ }
196
+ const field = fieldIn.get(name) ?? name;
197
+ if (!/^\w+$/.test(field)) {
198
+ throw new Error(`${where}: the path's ":${name}" is filled from \`${field}\`, which a path cannot name. Rename the field.`);
199
+ }
200
+ if (!required.has(field)) {
201
+ throw new Error(`${where}: the path's ":${name}" is filled from \`${field}\`, which the input does not require. ` +
202
+ "Make it required, or map the slot to another field with `params`.");
203
+ }
204
+ return `:${field}`;
205
+ });
206
+ }
207
+ /** The input as JSON Schema, with the operation named when it cannot be written. */
208
+ function schemaOf(input, where) {
209
+ try {
210
+ return inputJsonSchema(input);
211
+ }
212
+ catch (err) {
213
+ throw new Error(`${where}: ${err instanceof Error ? err.message : String(err)}`, {
214
+ cause: err,
215
+ });
216
+ }
217
+ }
218
+ /** `/**` over paragraphs, a blank ` *` line between them, each wrapped for its indent. */
219
+ function jsdoc(paragraphs, indent) {
220
+ const blocks = paragraphs
221
+ .map((paragraph) => (paragraph === undefined ? [] : wrapLines(paragraph, indent)))
222
+ .filter((lines) => lines.length > 0);
223
+ if (blocks.length === 0)
224
+ return "";
225
+ const line = `\n${indent} * `;
226
+ return `${indent}/**${line}${blocks.map((lines) => lines.join(line)).join(`\n${indent} *${line}`)}\n${indent} */\n`;
227
+ }
228
+ /** A key that is not an identifier has to be quoted. */
229
+ const propertyKey = (key) => (IDENTIFIER.test(key) ? key : JSON.stringify(key));
230
+ /**
231
+ * `@gusnips/http`'s retry rule, its `src/retry.ts` whole, for an SDK to carry as
232
+ * `generated/retry.ts`. It is read from this package's own dependency, never the adopter's, so
233
+ * every SDK built with one sdkgen carries one rule. When an sdkgen release moves the rule, each
234
+ * SDK's `--check` fails, and that is the signal to release the SDK.
235
+ */
236
+ export function retrySource() {
237
+ const entry = createRequire(import.meta.url).resolve("@gusnips/http/retry");
238
+ return readFileSync(join(dirname(entry), "../src/retry.ts"), "utf8");
239
+ }
240
+ /**
241
+ * The transport every generated method runs on, for an SDK to carry as `generated/transport.ts`
242
+ * beside `retry.ts`: this package's own `src/transport.ts`, importing the rule from `./retry.ts`.
243
+ */
244
+ export function transportSource() {
245
+ const path = fileURLToPath(new URL("../src/transport.ts", import.meta.url));
246
+ return readFileSync(path, "utf8").replace(`from "@gusnips/http/retry";`, `from "./retry.ts";`);
247
+ }
248
+ //# sourceMappingURL=methods.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"methods.js","sourceRoot":"","sources":["../src/methods.ts"],"names":[],"mappings":"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"}