@typeship-ax/cli 0.8.0 → 0.10.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 (106) hide show
  1. package/AGENTS.md +31 -0
  2. package/README.md +26 -9
  3. package/api.json +3509 -800
  4. package/api.md +444 -494
  5. package/dist/api-identity.d.ts +40 -0
  6. package/dist/api-identity.d.ts.map +1 -0
  7. package/dist/api-identity.js +128 -0
  8. package/dist/auth-profiles.d.ts +30 -0
  9. package/dist/auth-profiles.d.ts.map +1 -0
  10. package/dist/auth-profiles.js +138 -0
  11. package/dist/cli.js +522 -355
  12. package/dist/console-login-check.d.ts +21 -0
  13. package/dist/console-login-check.d.ts.map +1 -0
  14. package/dist/console-login-check.js +107 -0
  15. package/dist/console-login-contract.d.ts +45 -0
  16. package/dist/console-login-contract.d.ts.map +1 -0
  17. package/dist/console-login-contract.js +40 -0
  18. package/dist/core/http.d.ts +17 -2
  19. package/dist/core/http.d.ts.map +1 -1
  20. package/dist/core/http.js +78 -17
  21. package/dist/credential-storage.d.ts +24 -0
  22. package/dist/credential-storage.d.ts.map +1 -0
  23. package/dist/credential-storage.js +207 -0
  24. package/dist/docs.d.ts +25 -0
  25. package/dist/docs.d.ts.map +1 -1
  26. package/dist/docs.js +144 -0
  27. package/dist/errors.d.ts +18 -10
  28. package/dist/errors.d.ts.map +1 -1
  29. package/dist/errors.js +24 -14
  30. package/dist/index.d.ts +10 -3
  31. package/dist/index.d.ts.map +1 -1
  32. package/dist/index.js +20 -4
  33. package/dist/named-credentials.d.ts +21 -0
  34. package/dist/named-credentials.d.ts.map +1 -0
  35. package/dist/named-credentials.js +86 -0
  36. package/dist/oauth-login.d.ts +39 -0
  37. package/dist/oauth-login.d.ts.map +1 -0
  38. package/dist/oauth-login.js +171 -0
  39. package/dist/oauth-request.d.ts +21 -0
  40. package/dist/oauth-request.d.ts.map +1 -0
  41. package/dist/oauth-request.js +119 -0
  42. package/dist/oauth-session.d.ts +106 -0
  43. package/dist/oauth-session.d.ts.map +1 -0
  44. package/dist/oauth-session.js +244 -0
  45. package/dist/ops.d.ts +14 -1
  46. package/dist/ops.d.ts.map +1 -1
  47. package/dist/ops.js +34 -30
  48. package/dist/polling-login.d.ts +57 -0
  49. package/dist/polling-login.d.ts.map +1 -0
  50. package/dist/polling-login.js +204 -0
  51. package/dist/resources/account.d.ts +2 -2
  52. package/dist/resources/account.d.ts.map +1 -1
  53. package/dist/resources/account.js +1 -0
  54. package/dist/resources/api-keys.d.ts +3 -3
  55. package/dist/resources/api-keys.d.ts.map +1 -1
  56. package/dist/resources/api-keys.js +2 -0
  57. package/dist/resources/definition-revisions.d.ts +5 -5
  58. package/dist/resources/definition-revisions.d.ts.map +1 -1
  59. package/dist/resources/definition-revisions.js +4 -0
  60. package/dist/resources/definitions.d.ts +15 -4
  61. package/dist/resources/definitions.d.ts.map +1 -1
  62. package/dist/resources/definitions.js +11 -2
  63. package/dist/resources/generate.d.ts +14 -3
  64. package/dist/resources/generate.d.ts.map +1 -1
  65. package/dist/resources/generate.js +10 -2
  66. package/dist/resources/generations.d.ts +3 -3
  67. package/dist/resources/generations.d.ts.map +1 -1
  68. package/dist/resources/generations.js +2 -0
  69. package/dist/resources/projects.d.ts +56 -20
  70. package/dist/resources/projects.d.ts.map +1 -1
  71. package/dist/resources/projects.js +40 -4
  72. package/dist/resources/targets.d.ts +84 -10
  73. package/dist/resources/targets.d.ts.map +1 -1
  74. package/dist/resources/targets.js +127 -2
  75. package/dist/schemas.d.ts.map +1 -1
  76. package/dist/schemas.js +55 -26
  77. package/dist/types.d.ts +602 -123
  78. package/dist/types.d.ts.map +1 -1
  79. package/dist/types.js +24 -0
  80. package/package.json +2 -1
  81. package/src/api-identity.ts +98 -0
  82. package/src/auth-profiles.ts +114 -0
  83. package/src/cli.ts +444 -332
  84. package/src/console-login-check.ts +88 -0
  85. package/src/console-login-contract.ts +65 -0
  86. package/src/core/http.ts +88 -19
  87. package/src/credential-storage.ts +183 -0
  88. package/src/docs.ts +138 -0
  89. package/src/errors.ts +26 -15
  90. package/src/index.ts +29 -4
  91. package/src/named-credentials.ts +74 -0
  92. package/src/oauth-login.ts +184 -0
  93. package/src/oauth-request.ts +90 -0
  94. package/src/oauth-session.ts +258 -0
  95. package/src/ops.ts +48 -31
  96. package/src/polling-login.ts +165 -0
  97. package/src/resources/account.ts +3 -0
  98. package/src/resources/api-keys.ts +5 -0
  99. package/src/resources/definition-revisions.ts +9 -0
  100. package/src/resources/definitions.ts +25 -0
  101. package/src/resources/generate.ts +23 -0
  102. package/src/resources/generations.ts +5 -0
  103. package/src/resources/projects.ts +95 -7
  104. package/src/resources/targets.ts +241 -0
  105. package/src/schemas.ts +55 -26
  106. package/src/types.ts +640 -123
@@ -0,0 +1,165 @@
1
+ import { createHash, randomBytes } from "node:crypto";
2
+ import { oauthJsonRequest, oauthDeviceRequest, OAuthResponseError } from "./oauth-request.js";
3
+
4
+ export class LoginPollingError extends Error {
5
+ constructor(readonly code: "cancelled" | "expired" | "denied" | "invalid_response" | "request_failed") {
6
+ super({ cancelled: "Login was cancelled.", expired: "Login expired. Run login again and approve the new request.", denied: "Login was denied. Run login again if you want to retry.", invalid_response: "The login service returned an invalid response. Check its configuration.", request_failed: "The login request failed. Check the service and start a new login." }[code]);
7
+ this.name = "LoginPollingError";
8
+ }
9
+ }
10
+
11
+ export function loginEndpoint(value: string): URL {
12
+ try {
13
+ if (typeof value !== "string" || /[\x00-\x20\x7f]/.test(value)) throw new Error();
14
+ const url = new URL(value);
15
+ const local = ["localhost", "127.0.0.1", "[::1]"].includes(url.hostname);
16
+ if ((url.protocol !== "https:" && !(url.protocol === "http:" && local)) || url.username || url.password || url.hash) throw new Error();
17
+ return url;
18
+ } catch { throw new LoginPollingError("invalid_response"); }
19
+ }
20
+ function text(value: unknown, limit = 65_536): value is string {
21
+ return typeof value === "string" && value.trim().length > 0 && value.length <= limit && !/[\x00-\x1f\x7f]/.test(value);
22
+ }
23
+ function seconds(value: unknown): value is number {
24
+ return typeof value === "number" && Number.isFinite(value) && value > 0 && Number.isSafeInteger(Math.ceil(value * 1000));
25
+ }
26
+ function interval(value: unknown, fallback: number): number {
27
+ if (value === undefined) return fallback * 1000;
28
+ if (typeof value !== "number" || !Number.isFinite(value) || value < 0 || !Number.isSafeInteger(Math.ceil(value * 1000))) throw new LoginPollingError("invalid_response");
29
+ return Math.max(1, value) * 1000;
30
+ }
31
+ function lifetime(signal: AbortSignal | undefined, timeoutMs: number, maximum: number) {
32
+ if (!Number.isFinite(timeoutMs) || timeoutMs <= 0 || timeoutMs > maximum) throw new LoginPollingError("invalid_response");
33
+ const controller = new AbortController();
34
+ let expired = false;
35
+ const cancel = () => controller.abort();
36
+ const timer = setTimeout(() => { expired = true; controller.abort(); }, timeoutMs);
37
+ signal?.addEventListener("abort", cancel, { once: true });
38
+ if (signal?.aborted) cancel();
39
+ const check = () => { if (controller.signal.aborted) throw new LoginPollingError(expired ? "expired" : "cancelled"); };
40
+ return { signal: controller.signal, check, close() { clearTimeout(timer); signal?.removeEventListener("abort", cancel); } };
41
+ }
42
+ async function pause(ms: number, signal: AbortSignal): Promise<void> {
43
+ if (signal.aborted) throw new LoginPollingError("cancelled");
44
+ await new Promise<void>((resolve, reject) => {
45
+ const done = () => { clearTimeout(timer); signal.removeEventListener("abort", abort); resolve(); };
46
+ const abort = () => { clearTimeout(timer); signal.removeEventListener("abort", abort); reject(new LoginPollingError("cancelled")); };
47
+ const timer = setTimeout(done, Math.min(ms, 2_147_483_647));
48
+ signal.addEventListener("abort", abort, { once: true });
49
+ });
50
+ }
51
+ const form = (params: Record<string, string>, signal: AbortSignal): RequestInit => ({ method: "POST", headers: { "Content-Type": "application/x-www-form-urlencoded", Accept: "application/json" }, body: new URLSearchParams(params), signal });
52
+
53
+ export interface DeviceLoginConfig {
54
+ clientId: string; issuer?: string | null; discoveryUrls: string[];
55
+ deviceUrl?: string | null; tokenUrl?: string | null;
56
+ scopes: string[]; audience?: string; resource?: string;
57
+ }
58
+ export interface DeviceLoginSession {
59
+ accessToken: string; refreshToken?: string; expiresAt?: number;
60
+ tokenUrl: string; issuer?: string; clientId: string; revocationUrl?: string; scopes?: string[];
61
+ }
62
+
63
+ /** RFC 8628: pending and slow_down are the only responses that keep polling.
64
+ * All deadlines include response bodies; cancellation also interrupts waits. */
65
+ export async function oauthDeviceLogin(config: DeviceLoginConfig, interaction: {
66
+ authorize(value: { verificationUri: string; userCode: string; expiresIn: number }): void;
67
+ signal?: AbortSignal; timeoutMs?: number;
68
+ }): Promise<DeviceLoginSession> {
69
+ const flow = lifetime(interaction.signal, interaction.timeoutMs ?? 900_000, 900_000);
70
+ try {
71
+ flow.check();
72
+ if (!text(config.clientId)) throw new LoginPollingError("invalid_response");
73
+ if (config.issuer && loginEndpoint(config.issuer).search) throw new LoginPollingError("invalid_response");
74
+ let deviceUrl = config.deviceUrl ? loginEndpoint(config.deviceUrl).href : undefined;
75
+ let tokenUrl = config.tokenUrl ? loginEndpoint(config.tokenUrl).href : undefined;
76
+ let revocationUrl: string | undefined;
77
+ for (const url of config.discoveryUrls) {
78
+ if (deviceUrl && tokenUrl) break;
79
+ const response = await oauthJsonRequest(loginEndpoint(url), { headers: { Accept: "application/json" }, signal: flow.signal }, 10_000);
80
+ if (response.status !== 200) continue;
81
+ const data = response.data!;
82
+ if (config.issuer && data.issuer !== config.issuer) throw new LoginPollingError("invalid_response");
83
+ if (!deviceUrl && typeof data.device_authorization_endpoint === "string") deviceUrl = loginEndpoint(data.device_authorization_endpoint).href;
84
+ if (!tokenUrl && typeof data.token_endpoint === "string") tokenUrl = loginEndpoint(data.token_endpoint).href;
85
+ if (data.revocation_endpoint !== undefined) revocationUrl = loginEndpoint(data.revocation_endpoint as string).href;
86
+ }
87
+ if (!deviceUrl || !tokenUrl) throw new LoginPollingError("invalid_response");
88
+ const params = { ...(config.audience ? { audience: config.audience } : {}), ...(config.resource ? { resource: config.resource } : {}) };
89
+ const start = await oauthJsonRequest(deviceUrl, form({ client_id: config.clientId, ...(config.scopes.length ? { scope: config.scopes.join(" ") } : {}), ...params }, flow.signal));
90
+ const data = start.data;
91
+ if (start.status !== 200) throw new LoginPollingError("request_failed");
92
+ if (!data || !text(data.device_code) || !text(data.user_code, 512) || !text(data.verification_uri, 8192) || !seconds(data.expires_in)) throw new LoginPollingError("invalid_response");
93
+ loginEndpoint(data.verification_uri);
94
+ const verificationUri = loginEndpoint((data.verification_uri_complete ?? data.verification_uri) as string).href;
95
+ let intervalMs = interval(data.interval, 5);
96
+ const expiresIn = Math.min(data.expires_in, 900), deadline = Date.now() + expiresIn * 1000;
97
+ interaction.authorize({ verificationUri, userCode: data.user_code, expiresIn });
98
+ while (true) {
99
+ await pause(Math.min(intervalMs, Math.max(0, deadline - Date.now())), flow.signal);
100
+ flow.check();
101
+ if (Date.now() >= deadline) throw new LoginPollingError("expired");
102
+ let response: Awaited<ReturnType<typeof oauthDeviceRequest>>;
103
+ try { response = await oauthDeviceRequest(tokenUrl, form({ ...params, grant_type: "urn:ietf:params:oauth:grant-type:device_code", device_code: data.device_code, client_id: config.clientId }, flow.signal), Math.min(30_000, deadline - Date.now())); }
104
+ catch (error) {
105
+ flow.check();
106
+ if (error instanceof OAuthResponseError && error.code === "timed_out") { intervalMs *= 2; continue; }
107
+ throw error;
108
+ }
109
+ flow.check();
110
+ if (Date.now() >= deadline) throw new LoginPollingError("expired");
111
+ if (response.status === 400 && response.error === "authorization_pending") continue;
112
+ if (response.status === 400 && response.error === "slow_down") { intervalMs += 5000; continue; }
113
+ if (response.status === 400 && response.error === "access_denied") throw new LoginPollingError("denied");
114
+ if (response.status === 400 && response.error === "expired_token") throw new LoginPollingError("expired");
115
+ if (response.status !== 200) throw new LoginPollingError("request_failed");
116
+ const token = response.data!;
117
+ if (!text(token.access_token) || typeof token.token_type !== "string" || token.token_type.toLowerCase() !== "bearer" || token.error !== undefined || token.refresh_token !== undefined && !text(token.refresh_token) || token.expires_in !== undefined && !seconds(token.expires_in) || token.scope !== undefined && typeof token.scope !== "string") throw new LoginPollingError("invalid_response");
118
+ return { accessToken: token.access_token, ...(typeof token.refresh_token === "string" ? { refreshToken: token.refresh_token } : {}), ...(typeof token.expires_in === "number" ? { expiresAt: Date.now() + token.expires_in * 1000 } : {}), clientId: config.clientId, tokenUrl, ...(config.issuer ? { issuer: config.issuer } : {}), ...(revocationUrl ? { revocationUrl } : {}), ...(typeof token.scope === "string" ? { scopes: token.scope.split(/\s+/).filter(Boolean) } : {}) };
119
+ }
120
+ } catch (error) { flow.check(); throw error; }
121
+ finally { flow.close(); }
122
+ }
123
+
124
+ export interface ApprovedCredential { api_key: string; key_name: string; org_id?: string; revocationUrl: string }
125
+
126
+ /** This is the owner's custom approval contract, not an OAuth grant. A failed
127
+ * poll is not replayed: its one-use credential may already have been consumed. */
128
+ export async function customBrowserApproval(config: { authUrl: string; name: string; source: "agent" | "cli" }, interaction: {
129
+ authorize(value: { verificationUrl: string; expiresIn: number }): void;
130
+ signal?: AbortSignal; timeoutMs?: number;
131
+ }): Promise<ApprovedCredential> {
132
+ const flow = lifetime(interaction.signal, interaction.timeoutMs ?? 600_000, 600_000);
133
+ try {
134
+ flow.check();
135
+ const base = loginEndpoint(config.authUrl);
136
+ if (base.search) throw new LoginPollingError("invalid_response");
137
+ const url = base.href.replace(/\/$/, "");
138
+ const verifier = randomBytes(32).toString("base64url"), challenge = createHash("sha256").update(verifier).digest("base64url");
139
+ const post = (body: unknown): RequestInit => ({ method: "POST", headers: { "Content-Type": "application/json", Accept: "application/json" }, body: JSON.stringify(body), signal: flow.signal });
140
+ const response = await oauthJsonRequest(url + "/start", post({ code_challenge: challenge, name: config.name, source: config.source }), 15_000);
141
+ if (response.status !== 200) throw new LoginPollingError("request_failed");
142
+ const start = response.data!;
143
+ if (!text(start.session) || !text(start.verification_url, 8192) || start.expires_in !== undefined && !seconds(start.expires_in)) throw new LoginPollingError("invalid_response");
144
+ const verificationUrl = loginEndpoint(start.verification_url).href;
145
+ const expiresIn = Math.min(typeof start.expires_in === "number" ? start.expires_in : 600, 600);
146
+ const intervalMs = interval(start.interval, 3), deadline = Date.now() + expiresIn * 1000;
147
+ interaction.authorize({ verificationUrl, expiresIn });
148
+ while (true) {
149
+ await pause(Math.min(intervalMs, Math.max(0, deadline - Date.now())), flow.signal);
150
+ flow.check();
151
+ if (Date.now() >= deadline) throw new LoginPollingError("expired");
152
+ const result = await oauthJsonRequest(url + "/status", post({ session: start.session, code_verifier: verifier }), Math.min(15_000, deadline - Date.now()));
153
+ flow.check();
154
+ if (Date.now() >= deadline) throw new LoginPollingError("expired");
155
+ if (result.status !== 200) throw new LoginPollingError("request_failed");
156
+ const poll = result.data!;
157
+ if (poll.status === "pending") continue;
158
+ if (poll.status === "denied") throw new LoginPollingError("denied");
159
+ if (poll.status === "expired") throw new LoginPollingError("expired");
160
+ if (poll.status !== "complete" || !text(poll.api_key) || poll.key_name !== undefined && !text(poll.key_name, 1024) || poll.org_id !== undefined && !text(poll.org_id, 1024)) throw new LoginPollingError("invalid_response");
161
+ return { api_key: poll.api_key, key_name: typeof poll.key_name === "string" ? poll.key_name : config.name, ...(typeof poll.org_id === "string" ? { org_id: poll.org_id } : {}), revocationUrl: url + "/revoke" };
162
+ }
163
+ } catch (error) { flow.check(); throw error; }
164
+ finally { flow.close(); }
165
+ }
@@ -3,6 +3,7 @@
3
3
 
4
4
  import { HttpCore, type ApiResult, type RequestOptions } from "../core/http.js";
5
5
  import {
6
+ ResponseParseError,
6
7
  TransportError,
7
8
  UnexpectedApiError,
8
9
  ValidationError,
@@ -25,6 +26,7 @@ export class AccountResource {
25
26
  return this._core.request<AccountRead, AccountRetrieveError>({
26
27
  method: "GET",
27
28
  path: "/me",
29
+ security: [{"apiKey":[]}],
28
30
  errors: { "401": UnauthorizedError, "403": ForbiddenError, "429": RateLimitedError },
29
31
  idempotent: true,
30
32
  schemaKey: "account.retrieve",
@@ -39,5 +41,6 @@ export type AccountRetrieveError =
39
41
  | ForbiddenError
40
42
  | RateLimitedError
41
43
  | UnexpectedApiError
44
+ | ResponseParseError
42
45
  | TransportError
43
46
  | ValidationError;
@@ -4,6 +4,7 @@
4
4
  import { HttpCore, type ApiResult, type RequestOptions } from "../core/http.js";
5
5
  import { paginate, PagePromise } from "../core/pagination.js";
6
6
  import {
7
+ ResponseParseError,
7
8
  TransportError,
8
9
  UnexpectedApiError,
9
10
  ValidationError,
@@ -37,6 +38,7 @@ export class ApiKeysResource {
37
38
  return paginate<ApiKeyRead, ApiKeysListError>(this._core, {
38
39
  method: "GET",
39
40
  path: "/api_keys",
41
+ security: [{"apiKey":[]}],
40
42
  query: {
41
43
  limit: params?.limit,
42
44
  cursor: params?.cursor,
@@ -76,6 +78,7 @@ export class ApiKeysResource {
76
78
  return this._core.request<ApiKeyResponseRead, ApiKeysRevokeError>({
77
79
  method: "DELETE",
78
80
  path: `/api_keys/${encodeURIComponent(String(apiKeyId))}`,
81
+ security: [{"apiKey":[]}],
79
82
  errors: {
80
83
  "401": UnauthorizedError,
81
84
  "403": ForbiddenError,
@@ -106,6 +109,7 @@ export type ApiKeysListError =
106
109
  | ForbiddenError
107
110
  | RateLimitedError
108
111
  | UnexpectedApiError
112
+ | ResponseParseError
109
113
  | TransportError
110
114
  | ValidationError;
111
115
 
@@ -116,5 +120,6 @@ export type ApiKeysRevokeError =
116
120
  | NotFoundError
117
121
  | RateLimitedError
118
122
  | UnexpectedApiError
123
+ | ResponseParseError
119
124
  | TransportError
120
125
  | ValidationError;
@@ -4,6 +4,7 @@
4
4
  import { HttpCore, type ApiResult, type RequestOptions } from "../core/http.js";
5
5
  import { paginate, PagePromise } from "../core/pagination.js";
6
6
  import {
7
+ ResponseParseError,
7
8
  TransportError,
8
9
  UnexpectedApiError,
9
10
  ValidationError,
@@ -45,6 +46,7 @@ export class DefinitionRevisionsResource {
45
46
  return paginate<DefinitionRevisionRead, DefinitionRevisionsListError>(this._core, {
46
47
  method: "GET",
47
48
  path: `/definitions/${encodeURIComponent(String(definitionId))}/revisions`,
49
+ security: [{"apiKey":[]}],
48
50
  query: {
49
51
  limit: params?.limit,
50
52
  cursor: params?.cursor,
@@ -83,6 +85,7 @@ export class DefinitionRevisionsResource {
83
85
  return this._core.request<DefinitionRevisionResponseRead, DefinitionRevisionsRetrieveError>({
84
86
  method: "GET",
85
87
  path: `/definition_revisions/${encodeURIComponent(String(definitionRevisionId))}`,
88
+ security: [{"apiKey":[]}],
86
89
  errors: {
87
90
  "401": UnauthorizedError,
88
91
  "403": ForbiddenError,
@@ -109,6 +112,7 @@ export class DefinitionRevisionsResource {
109
112
  return this._core.request<string, DefinitionRevisionsRetrieveContentError>({
110
113
  method: "GET",
111
114
  path: `/definition_revisions/${encodeURIComponent(String(definitionRevisionId))}/content`,
115
+ security: [{"apiKey":[]}],
112
116
  errors: {
113
117
  "401": UnauthorizedError,
114
118
  "403": ForbiddenError,
@@ -133,6 +137,7 @@ export class DefinitionRevisionsResource {
133
137
  return this._core.request<string, DefinitionRevisionsRetrieveDocumentContentError>({
134
138
  method: "GET",
135
139
  path: `/definition_revisions/${encodeURIComponent(String(definitionRevisionId))}/documents/${encodeURIComponent(String(documentId))}/content`,
140
+ security: [{"apiKey":[]}],
136
141
  errors: {
137
142
  "401": UnauthorizedError,
138
143
  "403": ForbiddenError,
@@ -164,6 +169,7 @@ export type DefinitionRevisionsListError =
164
169
  | NotFoundError
165
170
  | RateLimitedError
166
171
  | UnexpectedApiError
172
+ | ResponseParseError
167
173
  | TransportError
168
174
  | ValidationError;
169
175
 
@@ -174,6 +180,7 @@ export type DefinitionRevisionsRetrieveError =
174
180
  | NotFoundError
175
181
  | RateLimitedError
176
182
  | UnexpectedApiError
183
+ | ResponseParseError
177
184
  | TransportError
178
185
  | ValidationError;
179
186
 
@@ -184,6 +191,7 @@ export type DefinitionRevisionsRetrieveContentError =
184
191
  | NotFoundError
185
192
  | RateLimitedError
186
193
  | UnexpectedApiError
194
+ | ResponseParseError
187
195
  | TransportError
188
196
  | ValidationError;
189
197
 
@@ -194,5 +202,6 @@ export type DefinitionRevisionsRetrieveDocumentContentError =
194
202
  | NotFoundError
195
203
  | RateLimitedError
196
204
  | UnexpectedApiError
205
+ | ResponseParseError
197
206
  | TransportError
198
207
  | ValidationError;
@@ -3,10 +3,12 @@
3
3
 
4
4
  import { HttpCore, type ApiResult, type RequestOptions } from "../core/http.js";
5
5
  import {
6
+ ResponseParseError,
6
7
  TransportError,
7
8
  UnexpectedApiError,
8
9
  ValidationError,
9
10
  BadRequestError,
11
+ ConflictError,
10
12
  ForbiddenError,
11
13
  NotFoundError,
12
14
  RateLimitedError,
@@ -33,6 +35,7 @@ export class DefinitionsResource {
33
35
  return this._core.request<DefinitionRead, DefinitionsRetrieveError>({
34
36
  method: "GET",
35
37
  path: `/definitions/${encodeURIComponent(String(definitionId))}`,
38
+ security: [{"apiKey":[]}],
36
39
  errors: {
37
40
  "401": UnauthorizedError,
38
41
  "403": ForbiddenError,
@@ -49,25 +52,34 @@ export class DefinitionsResource {
49
52
  * Update and resolve a Definition
50
53
  *
51
54
  * Resolves the complete document graph and records a new immutable revision before saving.
55
+ *
56
+ * A `Idempotency-Key` UUID is generated per call (stable across retries) unless you pass one.
52
57
  * `PATCH /definitions/{definition_id}`
53
58
  */
54
59
  async update(
55
60
  definitionId: DefinitionId,
56
61
  body: DefinitionUpdateRequest,
62
+ params?: DefinitionsUpdateParams,
57
63
  options?: RequestOptions,
58
64
  ): Promise<ApiResult<DefinitionRead, DefinitionsUpdateError>> {
59
65
  return this._core.request<DefinitionRead, DefinitionsUpdateError>({
60
66
  method: "PATCH",
61
67
  path: `/definitions/${encodeURIComponent(String(definitionId))}`,
68
+ security: [{"apiKey":[]}],
69
+ headers: {
70
+ "Idempotency-Key": params?.idempotencyKey === undefined ? undefined : String(params?.idempotencyKey),
71
+ },
62
72
  body,
63
73
  errors: {
64
74
  "400": BadRequestError,
65
75
  "401": UnauthorizedError,
66
76
  "403": ForbiddenError,
67
77
  "404": NotFoundError,
78
+ "409": ConflictError,
68
79
  "422": UnprocessableEntityError,
69
80
  "429": RateLimitedError,
70
81
  },
82
+ idempotencyKey: "Idempotency-Key",
71
83
  schemaKey: "definitions.update",
72
84
  options,
73
85
  });
@@ -81,17 +93,30 @@ export type DefinitionsRetrieveError =
81
93
  | NotFoundError
82
94
  | RateLimitedError
83
95
  | UnexpectedApiError
96
+ | ResponseParseError
84
97
  | TransportError
85
98
  | ValidationError;
86
99
 
100
+ export interface DefinitionsUpdateParams {
101
+ /**
102
+ * Identifies one logical write for 24 hours. The key is scoped to the authenticated account and
103
+ * operation; account-less generation uses a hashed network identity. Retrying the same method,
104
+ * path, query, and JSON body replays the original response. Reusing the key with changed intent
105
+ * returns 409. After expiry the key starts a new write.
106
+ */
107
+ idempotencyKey?: string;
108
+ }
109
+
87
110
  /** Every error `update` can produce, as a discriminated union. */
88
111
  export type DefinitionsUpdateError =
89
112
  | BadRequestError
90
113
  | UnauthorizedError
91
114
  | ForbiddenError
92
115
  | NotFoundError
116
+ | ConflictError
93
117
  | UnprocessableEntityError
94
118
  | RateLimitedError
95
119
  | UnexpectedApiError
120
+ | ResponseParseError
96
121
  | TransportError
97
122
  | ValidationError;
@@ -3,11 +3,13 @@
3
3
 
4
4
  import { HttpCore, type ApiResult, type RequestOptions } from "../core/http.js";
5
5
  import {
6
+ ResponseParseError,
6
7
  TransportError,
7
8
  UnexpectedApiError,
8
9
  ValidationError,
9
10
  ApiResponseError,
10
11
  BadRequestError,
12
+ ConflictError,
11
13
  ForbiddenError,
12
14
  PayloadTooLargeError,
13
15
  RateLimitedError,
@@ -30,40 +32,61 @@ export class GenerateResource {
30
32
  * the first 25 operations and
31
33
  * paid plans generate the complete Definition. A present but invalid key is a
32
34
  * 401, not a downgrade to anonymous.
35
+ *
36
+ * A `Idempotency-Key` UUID is generated per call (stable across retries) unless you pass one.
33
37
  * `POST /generate`
34
38
  */
35
39
  async run(
36
40
  body: GenerateRequest,
41
+ params?: GenerateRunParams,
37
42
  options?: RequestOptions,
38
43
  ): Promise<ApiResult<GenerationResultRead, GenerateRunError>> {
39
44
  return this._core.request<GenerationResultRead, GenerateRunError>({
40
45
  method: "POST",
41
46
  path: "/generate",
47
+ security: [{},{"apiKey":[]}],
48
+ headers: {
49
+ "Idempotency-Key": params?.idempotencyKey === undefined ? undefined : String(params?.idempotencyKey),
50
+ },
42
51
  body,
43
52
  errors: {
44
53
  "400": BadRequestError,
45
54
  "401": UnauthorizedError,
46
55
  "403": ForbiddenError,
56
+ "409": ConflictError,
47
57
  "413": PayloadTooLargeError,
48
58
  "422": UnprocessableEntityError,
49
59
  "429": RateLimitedError,
50
60
  default: ApiResponseError,
51
61
  },
62
+ idempotencyKey: "Idempotency-Key",
52
63
  schemaKey: "generate.run",
53
64
  options,
54
65
  });
55
66
  }
56
67
  }
57
68
 
69
+ export interface GenerateRunParams {
70
+ /**
71
+ * Identifies one logical write for 24 hours. The key is scoped to the authenticated account and
72
+ * operation; account-less generation uses a hashed network identity. Retrying the same method,
73
+ * path, query, and JSON body replays the original response. Reusing the key with changed intent
74
+ * returns 409. After expiry the key starts a new write.
75
+ */
76
+ idempotencyKey?: string;
77
+ }
78
+
58
79
  /** Every error `run` can produce, as a discriminated union. */
59
80
  export type GenerateRunError =
60
81
  | BadRequestError
61
82
  | UnauthorizedError
62
83
  | ForbiddenError
84
+ | ConflictError
63
85
  | PayloadTooLargeError
64
86
  | UnprocessableEntityError
65
87
  | RateLimitedError
66
88
  | ApiResponseError
67
89
  | UnexpectedApiError
90
+ | ResponseParseError
68
91
  | TransportError
69
92
  | ValidationError;
@@ -3,6 +3,7 @@
3
3
 
4
4
  import { HttpCore, type ApiResult, type RequestOptions } from "../core/http.js";
5
5
  import {
6
+ ResponseParseError,
6
7
  TransportError,
7
8
  UnexpectedApiError,
8
9
  ValidationError,
@@ -29,6 +30,7 @@ export class GenerationsResource {
29
30
  return this._core.request<GenerationResponseRead, GenerationsRetrieveError>({
30
31
  method: "GET",
31
32
  path: `/generations/${encodeURIComponent(String(generationId))}`,
33
+ security: [{"apiKey":[]}],
32
34
  errors: {
33
35
  "401": UnauthorizedError,
34
36
  "403": ForbiddenError,
@@ -56,6 +58,7 @@ export class GenerationsResource {
56
58
  return this._core.request<string, GenerationsRetrieveFileError>({
57
59
  method: "GET",
58
60
  path: `/generations/${encodeURIComponent(String(generationId))}/file`,
61
+ security: [{"apiKey":[]}],
59
62
  query: {
60
63
  path: params.path,
61
64
  },
@@ -80,6 +83,7 @@ export type GenerationsRetrieveError =
80
83
  | NotFoundError
81
84
  | RateLimitedError
82
85
  | UnexpectedApiError
86
+ | ResponseParseError
83
87
  | TransportError
84
88
  | ValidationError;
85
89
 
@@ -96,5 +100,6 @@ export type GenerationsRetrieveFileError =
96
100
  | NotFoundError
97
101
  | RateLimitedError
98
102
  | UnexpectedApiError
103
+ | ResponseParseError
99
104
  | TransportError
100
105
  | ValidationError;