@typeship-ax/cli 0.22.0 → 0.24.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 (146) hide show
  1. package/AGENTS.md +13 -9
  2. package/README.md +14 -27
  3. package/api.json +8898 -9026
  4. package/api.md +370 -328
  5. package/dist/arguments.d.ts +54 -0
  6. package/dist/arguments.d.ts.map +1 -0
  7. package/dist/arguments.js +265 -0
  8. package/dist/cli-agent.d.ts +73 -9
  9. package/dist/cli-agent.d.ts.map +1 -1
  10. package/dist/cli-agent.js +331 -44
  11. package/dist/cli.js +802 -291
  12. package/dist/core/http.d.ts +162 -19
  13. package/dist/core/http.d.ts.map +1 -1
  14. package/dist/core/http.js +381 -48
  15. package/dist/core/pagination.d.ts +42 -6
  16. package/dist/core/pagination.d.ts.map +1 -1
  17. package/dist/core/pagination.js +111 -17
  18. package/dist/credential-storage.d.ts +10 -3
  19. package/dist/credential-storage.d.ts.map +1 -1
  20. package/dist/credential-storage.js +15 -6
  21. package/dist/dates.d.ts +1 -1
  22. package/dist/dates.js +1 -1
  23. package/dist/errors.d.ts +20 -84
  24. package/dist/errors.d.ts.map +1 -1
  25. package/dist/errors.js +20 -108
  26. package/dist/fields.d.ts +36 -0
  27. package/dist/fields.d.ts.map +1 -0
  28. package/dist/fields.js +187 -0
  29. package/dist/index.d.ts +28 -18
  30. package/dist/index.d.ts.map +1 -1
  31. package/dist/index.js +35 -25
  32. package/dist/named-credentials.d.ts +19 -0
  33. package/dist/named-credentials.d.ts.map +1 -1
  34. package/dist/named-credentials.js +81 -1
  35. package/dist/oauth-login.d.ts +8 -2
  36. package/dist/oauth-login.d.ts.map +1 -1
  37. package/dist/oauth-login.js +31 -19
  38. package/dist/oauth-request.d.ts +7 -1
  39. package/dist/oauth-request.d.ts.map +1 -1
  40. package/dist/oauth-request.js +26 -4
  41. package/dist/oauth-session.d.ts +13 -1
  42. package/dist/oauth-session.d.ts.map +1 -1
  43. package/dist/oauth-session.js +34 -18
  44. package/dist/ops.d.ts +58 -5
  45. package/dist/ops.d.ts.map +1 -1
  46. package/dist/ops.js +110 -41
  47. package/dist/polling-login.d.ts +8 -2
  48. package/dist/polling-login.d.ts.map +1 -1
  49. package/dist/polling-login.js +25 -11
  50. package/dist/resources/api-keys.d.ts +10 -7
  51. package/dist/resources/api-keys.d.ts.map +1 -1
  52. package/dist/resources/api-keys.js +10 -31
  53. package/dist/resources/deliveries.d.ts +89 -5
  54. package/dist/resources/deliveries.d.ts.map +1 -1
  55. package/dist/resources/deliveries.js +96 -19
  56. package/dist/resources/drafts.d.ts +16 -16
  57. package/dist/resources/drafts.d.ts.map +1 -1
  58. package/dist/resources/drafts.js +12 -65
  59. package/dist/resources/files.d.ts +4 -4
  60. package/dist/resources/files.d.ts.map +1 -1
  61. package/dist/resources/files.js +3 -12
  62. package/dist/resources/generations.d.ts +16 -16
  63. package/dist/resources/generations.d.ts.map +1 -1
  64. package/dist/resources/generations.js +23 -47
  65. package/dist/resources/organization.d.ts +4 -4
  66. package/dist/resources/organization.d.ts.map +1 -1
  67. package/dist/resources/organization.js +3 -10
  68. package/dist/resources/{generate.d.ts → packages.d.ts} +16 -16
  69. package/dist/resources/packages.d.ts.map +1 -0
  70. package/dist/resources/{generate.js → packages.js} +13 -29
  71. package/dist/resources/projects.d.ts +50 -50
  72. package/dist/resources/projects.d.ts.map +1 -1
  73. package/dist/resources/projects.js +60 -116
  74. package/dist/resources/releases.d.ts +22 -17
  75. package/dist/resources/releases.d.ts.map +1 -1
  76. package/dist/resources/releases.js +19 -40
  77. package/dist/resources/spec-revisions.d.ts +16 -7
  78. package/dist/resources/spec-revisions.d.ts.map +1 -1
  79. package/dist/resources/spec-revisions.js +7 -29
  80. package/dist/resources/specs.d.ts +7 -7
  81. package/dist/resources/specs.d.ts.map +1 -1
  82. package/dist/resources/specs.js +6 -34
  83. package/dist/resources/targets.d.ts +49 -49
  84. package/dist/resources/targets.d.ts.map +1 -1
  85. package/dist/resources/targets.js +59 -115
  86. package/dist/schemas.d.ts.map +1 -1
  87. package/dist/schemas.js +83 -81
  88. package/dist/search.d.ts +54 -0
  89. package/dist/search.d.ts.map +1 -0
  90. package/dist/search.js +421 -0
  91. package/dist/table.d.ts +28 -0
  92. package/dist/table.d.ts.map +1 -0
  93. package/dist/table.js +167 -0
  94. package/dist/type-docs.d.ts +61 -0
  95. package/dist/type-docs.d.ts.map +1 -0
  96. package/dist/type-docs.js +174 -0
  97. package/dist/types.d.ts +499 -339
  98. package/dist/types.d.ts.map +1 -1
  99. package/dist/types.js +18 -18
  100. package/package.json +5 -2
  101. package/src/arguments.ts +254 -0
  102. package/src/cli-agent.ts +351 -46
  103. package/src/cli.ts +753 -266
  104. package/src/core/http.ts +457 -58
  105. package/src/core/pagination.ts +129 -18
  106. package/src/credential-storage.ts +16 -6
  107. package/src/dates.ts +1 -1
  108. package/src/errors.ts +46 -115
  109. package/src/fields.ts +167 -0
  110. package/src/index.ts +45 -28
  111. package/src/named-credentials.ts +66 -1
  112. package/src/oauth-login.ts +36 -21
  113. package/src/oauth-request.ts +32 -6
  114. package/src/oauth-session.ts +37 -19
  115. package/src/ops.ts +146 -45
  116. package/src/polling-login.ts +24 -11
  117. package/src/resources/api-keys.ts +34 -48
  118. package/src/resources/deliveries.ts +213 -32
  119. package/src/resources/drafts.ts +62 -109
  120. package/src/resources/files.ts +19 -20
  121. package/src/resources/generations.ts +61 -79
  122. package/src/resources/organization.ts +11 -16
  123. package/src/resources/{generate.ts → packages.ts} +43 -51
  124. package/src/resources/projects.ts +145 -200
  125. package/src/resources/releases.ts +50 -67
  126. package/src/resources/spec-revisions.ts +40 -49
  127. package/src/resources/specs.ts +39 -59
  128. package/src/resources/targets.ts +144 -194
  129. package/src/schemas.ts +83 -81
  130. package/src/search.ts +434 -0
  131. package/src/table.ts +167 -0
  132. package/src/type-docs.ts +205 -0
  133. package/src/types.ts +538 -357
  134. package/dist/console-login-check.d.ts +0 -21
  135. package/dist/console-login-check.d.ts.map +0 -1
  136. package/dist/console-login-check.js +0 -107
  137. package/dist/console-login-contract.d.ts +0 -45
  138. package/dist/console-login-contract.d.ts.map +0 -1
  139. package/dist/console-login-contract.js +0 -40
  140. package/dist/resources/generate.d.ts.map +0 -1
  141. package/dist/resources/publications.d.ts +0 -47
  142. package/dist/resources/publications.d.ts.map +0 -1
  143. package/dist/resources/publications.js +0 -70
  144. package/src/console-login-check.ts +0 -88
  145. package/src/console-login-contract.ts +0 -65
  146. package/src/resources/publications.ts +0 -140
@@ -2,9 +2,12 @@ import { createHash, randomBytes } from "node:crypto";
2
2
  import { oauthJsonRequest, oauthDeviceRequest, OAuthResponseError } from "./oauth-request.js";
3
3
 
4
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]);
5
+ /** The provider's own `error: error_description`, when it sent one. */
6
+ readonly providerError?: string;
7
+ constructor(readonly code: "cancelled" | "expired" | "denied" | "consumed" | "invalid_response" | "request_failed", providerError?: string) {
8
+ super((providerError ? "The provider returned " + providerError + ". " : "") + { 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.", consumed: "This approval was already used. Run login again.", 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
9
  this.name = "LoginPollingError";
10
+ if (providerError) this.providerError = providerError;
8
11
  }
9
12
  }
10
13
 
@@ -50,6 +53,11 @@ async function pause(ms: number, signal: AbortSignal): Promise<void> {
50
53
  }
51
54
  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
55
 
56
+ /** Neither the API Spec nor the provider's metadata declares a device endpoint. */
57
+ export class DeviceFlowUnavailableError extends Error {
58
+ constructor() { super("This provider does not declare device authorization. Use browser login instead."); this.name = "DeviceFlowUnavailableError"; }
59
+ }
60
+
53
61
  export interface DeviceLoginConfig {
54
62
  clientId: string; issuer?: string | null; discoveryUrls: string[];
55
63
  deviceUrl?: string | null; tokenUrl?: string | null;
@@ -84,11 +92,11 @@ export async function oauthDeviceLogin(config: DeviceLoginConfig, interaction: {
84
92
  if (!tokenUrl && typeof data.token_endpoint === "string") tokenUrl = loginEndpoint(data.token_endpoint).href;
85
93
  if (data.revocation_endpoint !== undefined) revocationUrl = loginEndpoint(data.revocation_endpoint as string).href;
86
94
  }
87
- if (!deviceUrl || !tokenUrl) throw new LoginPollingError("invalid_response");
95
+ if (!deviceUrl || !tokenUrl) throw new DeviceFlowUnavailableError();
88
96
  const params = { ...(config.audience ? { audience: config.audience } : {}), ...(config.resource ? { resource: config.resource } : {}) };
89
97
  const start = await oauthJsonRequest(deviceUrl, form({ client_id: config.clientId, ...(config.scopes.length ? { scope: config.scopes.join(" ") } : {}), ...params }, flow.signal));
90
98
  const data = start.data;
91
- if (start.status !== 200) throw new LoginPollingError("request_failed");
99
+ if (start.status !== 200) throw new LoginPollingError("request_failed", start.providerError);
92
100
  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
101
  loginEndpoint(data.verification_uri);
94
102
  const verificationUri = loginEndpoint((data.verification_uri_complete ?? data.verification_uri) as string).href;
@@ -98,9 +106,12 @@ export async function oauthDeviceLogin(config: DeviceLoginConfig, interaction: {
98
106
  while (true) {
99
107
  await pause(Math.min(intervalMs, Math.max(0, deadline - Date.now())), flow.signal);
100
108
  flow.check();
101
- if (Date.now() >= deadline) throw new LoginPollingError("expired");
109
+ // One reading of the clock: a request budget of zero or less is the
110
+ // login expiring, not a failed request.
111
+ const remaining = deadline - Date.now();
112
+ if (remaining <= 0) throw new LoginPollingError("expired");
102
113
  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())); }
114
+ 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, remaining)); }
104
115
  catch (error) {
105
116
  flow.check();
106
117
  if (error instanceof OAuthResponseError && error.code === "timed_out") { intervalMs *= 2; continue; }
@@ -112,7 +123,7 @@ export async function oauthDeviceLogin(config: DeviceLoginConfig, interaction: {
112
123
  if (response.status === 400 && response.error === "slow_down") { intervalMs += 5000; continue; }
113
124
  if (response.status === 400 && response.error === "access_denied") throw new LoginPollingError("denied");
114
125
  if (response.status === 400 && response.error === "expired_token") throw new LoginPollingError("expired");
115
- if (response.status !== 200) throw new LoginPollingError("request_failed");
126
+ if (response.status !== 200) throw new LoginPollingError("request_failed", response.providerError);
116
127
  const token = response.data!;
117
128
  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
129
  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) } : {}) };
@@ -138,7 +149,7 @@ export async function customBrowserApproval(config: { authUrl: string; name: str
138
149
  const verifier = randomBytes(32).toString("base64url"), challenge = createHash("sha256").update(verifier).digest("base64url");
139
150
  const post = (body: unknown): RequestInit => ({ method: "POST", headers: { "Content-Type": "application/json", Accept: "application/json" }, body: JSON.stringify(body), signal: flow.signal });
140
151
  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");
152
+ if (response.status !== 200) throw new LoginPollingError("request_failed", response.providerError);
142
153
  const start = response.data!;
143
154
  if (!text(start.session) || !text(start.verification_url, 8192) || start.expires_in !== undefined && !seconds(start.expires_in)) throw new LoginPollingError("invalid_response");
144
155
  const verificationUrl = loginEndpoint(start.verification_url).href;
@@ -148,10 +159,11 @@ export async function customBrowserApproval(config: { authUrl: string; name: str
148
159
  while (true) {
149
160
  await pause(Math.min(intervalMs, Math.max(0, deadline - Date.now())), flow.signal);
150
161
  flow.check();
151
- if (Date.now() >= deadline) throw new LoginPollingError("expired");
162
+ const remaining = deadline - Date.now();
163
+ if (remaining <= 0) throw new LoginPollingError("expired");
152
164
  let result: Awaited<ReturnType<typeof oauthJsonRequest>>;
153
165
  try {
154
- result = await oauthJsonRequest(url + "/status", post({ session: start.session, code_verifier: verifier }), Math.min(15_000, deadline - Date.now()));
166
+ result = await oauthJsonRequest(url + "/status", post({ session: start.session, code_verifier: verifier }), Math.min(15_000, remaining));
155
167
  } catch (error) {
156
168
  flow.check();
157
169
  if (error instanceof OAuthResponseError && error.code === "timed_out" && Date.now() >= deadline) {
@@ -161,11 +173,12 @@ export async function customBrowserApproval(config: { authUrl: string; name: str
161
173
  }
162
174
  flow.check();
163
175
  if (Date.now() >= deadline) throw new LoginPollingError("expired");
164
- if (result.status !== 200) throw new LoginPollingError("request_failed");
176
+ if (result.status !== 200) throw new LoginPollingError("request_failed", result.providerError);
165
177
  const poll = result.data!;
166
178
  if (poll.status === "pending") continue;
167
179
  if (poll.status === "denied") throw new LoginPollingError("denied");
168
180
  if (poll.status === "expired") throw new LoginPollingError("expired");
181
+ if (poll.status === "consumed") throw new LoginPollingError("consumed");
169
182
  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");
170
183
  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" };
171
184
  }
@@ -1,19 +1,19 @@
1
- // typeship — apiKeys resource.
2
- // Generated by typeship — https://typeship.dev
1
+ // Typeship — apiKeys resource.
2
+ // Generated by Typeship — https://typeship.dev
3
3
 
4
4
  import { HttpCore, type RequestOptions } from "../core/http.js";
5
5
  import { paginate, PagePromise } from "../core/pagination.js";
6
6
  import {
7
+ RateLimitError,
7
8
  ResponseParseError,
8
9
  TransportError,
9
10
  UnexpectedApiError,
10
11
  ValidationError,
11
12
  BadRequestError,
12
13
  ForbiddenError,
13
- InternalServerError,
14
14
  NotFoundError,
15
15
  PreconditionFailedError,
16
- RateLimitedError,
16
+ ServerError,
17
17
  UnauthorizedError,
18
18
  } from "../errors.js";
19
19
  import type {
@@ -23,6 +23,8 @@ import type {
23
23
  ApiKeyRead,
24
24
  ApiKeyResponse,
25
25
  ApiKeyResponseRead,
26
+ ErrorModel,
27
+ ErrorModelRead,
26
28
  } from "../types.js";
27
29
 
28
30
  export class ApiKeysResource {
@@ -44,13 +46,7 @@ export class ApiKeysResource {
44
46
  query: {
45
47
  limit: params?.limit,
46
48
  cursor: params?.cursor,
47
- },
48
- errors: {
49
- "400": BadRequestError,
50
- "401": UnauthorizedError,
51
- "403": ForbiddenError,
52
- "429": RateLimitedError,
53
- "500": InternalServerError,
49
+ status: params?.status,
54
50
  },
55
51
  idempotent: true,
56
52
  schemaKey: "apiKeys.list",
@@ -76,13 +72,6 @@ export class ApiKeysResource {
76
72
  method: "GET",
77
73
  path: `/api-keys/${encodeURIComponent(String(apiKeyId))}`,
78
74
  security: [{"apiKey":[]}],
79
- errors: {
80
- "401": UnauthorizedError,
81
- "403": ForbiddenError,
82
- "404": NotFoundError,
83
- "429": RateLimitedError,
84
- "500": InternalServerError,
85
- },
86
75
  idempotent: true,
87
76
  schemaKey: "apiKeys.get",
88
77
  options,
@@ -92,13 +81,14 @@ export class ApiKeysResource {
92
81
  /**
93
82
  * Revoke an API key
94
83
  *
95
- * Revokes a key. Repeating the request returns the same result.
84
+ * Revokes a key immediately. The key stays listed with `status: revoked`. Repeating the request
85
+ * returns the same result.
96
86
  *
97
87
  * With OAuth, members can revoke their own keys; organization admins can revoke any key.
98
88
  * Organization API keys can revoke any key in their organization.
99
89
  * See [conditional writes](https://typeship.dev/docs/typeship-api#conditional-writes) for ETag
100
90
  * and If-Match.
101
- * `DELETE /api-keys/{api_key_id}`
91
+ * `POST /api-keys/{api_key_id}/revoke`
102
92
  */
103
93
  async revoke(
104
94
  apiKeyId: string,
@@ -106,22 +96,13 @@ export class ApiKeysResource {
106
96
  options?: RequestOptions,
107
97
  ): Promise<ApiKeyResponseRead> {
108
98
  return this._core.requestData<ApiKeyResponseRead, ApiKeysRevokeError>({
109
- method: "DELETE",
110
- path: `/api-keys/${encodeURIComponent(String(apiKeyId))}`,
99
+ method: "POST",
100
+ path: `/api-keys/${encodeURIComponent(String(apiKeyId))}/revoke`,
111
101
  security: [{"apiKey":[]}],
112
102
  headers: {
113
103
  "If-Match": params?.ifMatch === undefined ? undefined : String(params?.ifMatch),
114
104
  },
115
- errors: {
116
- "400": BadRequestError,
117
- "401": UnauthorizedError,
118
- "403": ForbiddenError,
119
- "404": NotFoundError,
120
- "412": PreconditionFailedError,
121
- "429": RateLimitedError,
122
- "500": InternalServerError,
123
- },
124
- idempotent: true,
105
+ errors: { "412": PreconditionFailedError },
125
106
  schemaKey: "apiKeys.revoke",
126
107
  options,
127
108
  });
@@ -144,15 +125,18 @@ export interface ApiKeysListParams {
144
125
  * change between requests.
145
126
  */
146
127
  cursor?: string;
128
+ /** Only keys with this status. */
129
+ status?: "active" | "revoked";
147
130
  }
148
131
 
149
132
  /** Typed errors `list` can throw. */
150
133
  export type ApiKeysListError =
151
- | BadRequestError
152
- | UnauthorizedError
153
- | ForbiddenError
154
- | RateLimitedError
155
- | InternalServerError
134
+ | BadRequestError<ErrorModelRead>
135
+ | UnauthorizedError<ErrorModelRead>
136
+ | ForbiddenError<ErrorModelRead>
137
+ | RateLimitError<ErrorModelRead>
138
+ | ServerError<ErrorModelRead>
139
+ | RateLimitError
156
140
  | UnexpectedApiError
157
141
  | ResponseParseError
158
142
  | TransportError
@@ -160,11 +144,12 @@ export type ApiKeysListError =
160
144
 
161
145
  /** Typed errors `get` can throw. */
162
146
  export type ApiKeysGetError =
163
- | UnauthorizedError
164
- | ForbiddenError
165
- | NotFoundError
166
- | RateLimitedError
167
- | InternalServerError
147
+ | UnauthorizedError<ErrorModelRead>
148
+ | ForbiddenError<ErrorModelRead>
149
+ | NotFoundError<ErrorModelRead>
150
+ | RateLimitError<ErrorModelRead>
151
+ | ServerError<ErrorModelRead>
152
+ | RateLimitError
168
153
  | UnexpectedApiError
169
154
  | ResponseParseError
170
155
  | TransportError
@@ -181,13 +166,14 @@ export interface ApiKeysRevokeParams {
181
166
 
182
167
  /** Typed errors `revoke` can throw. */
183
168
  export type ApiKeysRevokeError =
184
- | BadRequestError
185
- | UnauthorizedError
186
- | ForbiddenError
187
- | NotFoundError
169
+ | BadRequestError<ErrorModelRead>
170
+ | UnauthorizedError<ErrorModelRead>
171
+ | ForbiddenError<ErrorModelRead>
172
+ | NotFoundError<ErrorModelRead>
188
173
  | PreconditionFailedError
189
- | RateLimitedError
190
- | InternalServerError
174
+ | RateLimitError<ErrorModelRead>
175
+ | ServerError<ErrorModelRead>
176
+ | RateLimitError
191
177
  | UnexpectedApiError
192
178
  | ResponseParseError
193
179
  | TransportError
@@ -1,33 +1,78 @@
1
- // typeship — deliveries resource.
2
- // Generated by typeship — https://typeship.dev
1
+ // Typeship — deliveries resource.
2
+ // Generated by Typeship — https://typeship.dev
3
3
 
4
4
  import { HttpCore, type RequestOptions } from "../core/http.js";
5
5
  import { paginate, PagePromise } from "../core/pagination.js";
6
6
  import {
7
+ RateLimitError,
7
8
  ResponseParseError,
8
9
  TransportError,
9
10
  UnexpectedApiError,
10
11
  ValidationError,
11
12
  BadRequestError,
13
+ ConflictError,
12
14
  ForbiddenError,
13
- InternalServerError,
14
15
  NotFoundError,
15
- RateLimitedError,
16
+ PreconditionFailedError,
17
+ ServerError,
16
18
  UnauthorizedError,
19
+ UnprocessableEntityError,
17
20
  } from "../errors.js";
18
21
  import type {
22
+ DeletedDelivery,
23
+ DeletedDeliveryRead,
19
24
  Delivery,
25
+ DeliveryCreateRequest,
20
26
  DeliveryId,
21
27
  DeliveryList,
22
28
  DeliveryListRead,
23
29
  DeliveryRead,
24
30
  DeliveryResponse,
25
31
  DeliveryResponseRead,
32
+ DeliveryUpdateRequest,
33
+ ErrorModel,
34
+ ErrorModelRead,
26
35
  TargetId,
27
36
  } from "../types.js";
28
37
 
29
38
  export class DeliveriesResource {
30
39
  constructor(private readonly _core: HttpCore) {}
40
+ /**
41
+ * Create a Delivery
42
+ *
43
+ * Adds a repository or hosted MCP Delivery to a Target. A Target has at most one Delivery of each
44
+ * type; a `409 delivery_exists` means it already has one, so update that Delivery instead.
45
+ * With Project auto_generate enabled, adding a Delivery queues the Target's Generation. A queued
46
+ * or running Target reuses that Generation.
47
+ *
48
+ * A `409 delivery_conflict` means another Target owns the requested repository directory. A `409
49
+ * target_busy` means the Target is publishing; wait for it to finish.
50
+ * A `502 follow_up_failed` means the Delivery was saved, but retiring an obsolete review or
51
+ * regenerating the Target failed. Get the Delivery and follow the error's retryable and
52
+ * suggested_action fields.
53
+ *
54
+ * A `Idempotency-Key` UUID is generated per call (stable across retries) unless you pass one.
55
+ * `POST /deliveries`
56
+ */
57
+ async create(
58
+ body: DeliveryCreateRequest,
59
+ params?: DeliveriesCreateParams,
60
+ options?: RequestOptions,
61
+ ): Promise<DeliveryResponseRead> {
62
+ return this._core.requestData<DeliveryResponseRead, DeliveriesCreateError>({
63
+ method: "POST",
64
+ path: "/deliveries",
65
+ security: [{"apiKey":[]}],
66
+ headers: {
67
+ "Idempotency-Key": params?.idempotencyKey === undefined ? undefined : String(params?.idempotencyKey),
68
+ },
69
+ body,
70
+ idempotencyKey: "Idempotency-Key",
71
+ schemaKey: "deliveries.create",
72
+ options,
73
+ });
74
+ }
75
+
31
76
  /**
32
77
  * List Deliveries
33
78
  *
@@ -45,15 +90,7 @@ export class DeliveriesResource {
45
90
  query: {
46
91
  limit: params?.limit,
47
92
  cursor: params?.cursor,
48
- target_id: params?.targetId,
49
- },
50
- errors: {
51
- "400": BadRequestError,
52
- "401": UnauthorizedError,
53
- "403": ForbiddenError,
54
- "404": NotFoundError,
55
- "429": RateLimitedError,
56
- "500": InternalServerError,
93
+ target_id: params?.target_id,
57
94
  },
58
95
  idempotent: true,
59
96
  schemaKey: "deliveries.list",
@@ -80,20 +117,111 @@ export class DeliveriesResource {
80
117
  method: "GET",
81
118
  path: `/deliveries/${encodeURIComponent(String(deliveryId))}`,
82
119
  security: [{"apiKey":[]}],
83
- errors: {
84
- "401": UnauthorizedError,
85
- "403": ForbiddenError,
86
- "404": NotFoundError,
87
- "429": RateLimitedError,
88
- "500": InternalServerError,
89
- },
90
120
  idempotent: true,
91
121
  schemaKey: "deliveries.get",
92
122
  options,
93
123
  });
94
124
  }
125
+
126
+ /**
127
+ * Update a Delivery
128
+ *
129
+ * Replaces a repository Delivery's settings. Omitted optional settings reset to their defaults.
130
+ * Hosted MCP Deliveries have no settings to update.
131
+ * With Project auto_generate enabled, changing a Delivery queues the Target's Generation. A
132
+ * queued or running Target reuses that Generation.
133
+ * Omitting If-Match applies the update to the current Delivery; with If-Match, a stale ETag
134
+ * returns 412 precondition_failed without saving.
135
+ *
136
+ * A `409 delivery_conflict` means another Target owns the requested repository directory. A `409
137
+ * target_busy` means the Target is publishing; wait for it to finish.
138
+ * A `502 follow_up_failed` means the Delivery was saved, but retiring an obsolete review or
139
+ * regenerating the Target failed. Get the Delivery and follow the error's retryable and
140
+ * suggested_action fields.
141
+ * See [conditional writes](https://typeship.dev/docs/typeship-api#conditional-writes) for ETag
142
+ * and If-Match.
143
+ * `PATCH /deliveries/{delivery_id}`
144
+ */
145
+ async update(
146
+ deliveryId: DeliveryId,
147
+ body: DeliveryUpdateRequest,
148
+ params?: DeliveriesUpdateParams,
149
+ options?: RequestOptions,
150
+ ): Promise<DeliveryResponseRead> {
151
+ return this._core.requestData<DeliveryResponseRead, DeliveriesUpdateError>({
152
+ method: "PATCH",
153
+ path: `/deliveries/${encodeURIComponent(String(deliveryId))}`,
154
+ security: [{"apiKey":[]}],
155
+ headers: {
156
+ "If-Match": params?.ifMatch === undefined ? undefined : String(params?.ifMatch),
157
+ },
158
+ body,
159
+ errors: { "412": PreconditionFailedError },
160
+ schemaKey: "deliveries.update",
161
+ options,
162
+ });
163
+ }
164
+
165
+ /**
166
+ * Delete a Delivery
167
+ *
168
+ * Removes a Delivery from its Target. Removing a repository Delivery retires the Target's open
169
+ * Draft pull request; removing a hosted MCP Delivery stops serving its URL. Recreating the type
170
+ * later allocates a new ID and, for hosted MCP, a new URL.
171
+ *
172
+ * A `409 target_busy` means the Target is publishing; wait for it to finish. A `502
173
+ * follow_up_failed` means the Delivery was removed, but retiring an obsolete review or
174
+ * regenerating the Target failed.
175
+ * See [conditional writes](https://typeship.dev/docs/typeship-api#conditional-writes) for ETag
176
+ * and If-Match.
177
+ * `DELETE /deliveries/{delivery_id}`
178
+ */
179
+ async delete(
180
+ deliveryId: DeliveryId,
181
+ params?: DeliveriesDeleteParams,
182
+ options?: RequestOptions,
183
+ ): Promise<DeletedDeliveryRead> {
184
+ return this._core.requestData<DeletedDeliveryRead, DeliveriesDeleteError>({
185
+ method: "DELETE",
186
+ path: `/deliveries/${encodeURIComponent(String(deliveryId))}`,
187
+ security: [{"apiKey":[]}],
188
+ headers: {
189
+ "If-Match": params?.ifMatch === undefined ? undefined : String(params?.ifMatch),
190
+ },
191
+ errors: { "412": PreconditionFailedError },
192
+ idempotent: true,
193
+ schemaKey: "deliveries.delete",
194
+ options,
195
+ });
196
+ }
95
197
  }
96
198
 
199
+ export interface DeliveriesCreateParams {
200
+ /**
201
+ * Identifies one logical write for 24 hours. The key is scoped to the authenticated organization
202
+ * and operation; generation without an organization uses a hashed network identity. Retrying the
203
+ * same method, path, query, If-Match header, and JSON body replays the original response. Reusing
204
+ * the key with changed intent returns 409. After expiry the key starts a new write.
205
+ */
206
+ idempotencyKey?: string;
207
+ }
208
+
209
+ /** Typed errors `create` can throw. */
210
+ export type DeliveriesCreateError =
211
+ | BadRequestError<ErrorModelRead>
212
+ | UnauthorizedError<ErrorModelRead>
213
+ | ForbiddenError<ErrorModelRead>
214
+ | NotFoundError<ErrorModelRead>
215
+ | ConflictError<ErrorModelRead>
216
+ | UnprocessableEntityError<ErrorModelRead>
217
+ | RateLimitError<ErrorModelRead>
218
+ | ServerError<ErrorModelRead>
219
+ | RateLimitError
220
+ | UnexpectedApiError
221
+ | ResponseParseError
222
+ | TransportError
223
+ | ValidationError;
224
+
97
225
  export interface DeliveriesListParams {
98
226
  /**
99
227
  * Maximum number of resources to return. Omit for 20; otherwise supply base-10 digits
@@ -111,17 +239,18 @@ export interface DeliveriesListParams {
111
239
  */
112
240
  cursor?: string;
113
241
  /** Only Deliveries of this Target. */
114
- targetId?: TargetId;
242
+ target_id?: TargetId;
115
243
  }
116
244
 
117
245
  /** Typed errors `list` can throw. */
118
246
  export type DeliveriesListError =
119
- | BadRequestError
120
- | UnauthorizedError
121
- | ForbiddenError
122
- | NotFoundError
123
- | RateLimitedError
124
- | InternalServerError
247
+ | BadRequestError<ErrorModelRead>
248
+ | UnauthorizedError<ErrorModelRead>
249
+ | ForbiddenError<ErrorModelRead>
250
+ | NotFoundError<ErrorModelRead>
251
+ | RateLimitError<ErrorModelRead>
252
+ | ServerError<ErrorModelRead>
253
+ | RateLimitError
125
254
  | UnexpectedApiError
126
255
  | ResponseParseError
127
256
  | TransportError
@@ -129,11 +258,63 @@ export type DeliveriesListError =
129
258
 
130
259
  /** Typed errors `get` can throw. */
131
260
  export type DeliveriesGetError =
132
- | UnauthorizedError
133
- | ForbiddenError
134
- | NotFoundError
135
- | RateLimitedError
136
- | InternalServerError
261
+ | UnauthorizedError<ErrorModelRead>
262
+ | ForbiddenError<ErrorModelRead>
263
+ | NotFoundError<ErrorModelRead>
264
+ | RateLimitError<ErrorModelRead>
265
+ | ServerError<ErrorModelRead>
266
+ | RateLimitError
267
+ | UnexpectedApiError
268
+ | ResponseParseError
269
+ | TransportError
270
+ | ValidationError;
271
+
272
+ export interface DeliveriesUpdateParams {
273
+ /**
274
+ * ETag from a preceding response. The write applies only if the resource still has that version;
275
+ * otherwise it returns 412 precondition_failed without changes. Omit to write the current
276
+ * version. See https://typeship.dev/docs/typeship-api#conditional-writes.
277
+ */
278
+ ifMatch?: string;
279
+ }
280
+
281
+ /** Typed errors `update` can throw. */
282
+ export type DeliveriesUpdateError =
283
+ | BadRequestError<ErrorModelRead>
284
+ | UnauthorizedError<ErrorModelRead>
285
+ | ForbiddenError<ErrorModelRead>
286
+ | NotFoundError<ErrorModelRead>
287
+ | ConflictError<ErrorModelRead>
288
+ | PreconditionFailedError
289
+ | UnprocessableEntityError<ErrorModelRead>
290
+ | RateLimitError<ErrorModelRead>
291
+ | ServerError<ErrorModelRead>
292
+ | RateLimitError
293
+ | UnexpectedApiError
294
+ | ResponseParseError
295
+ | TransportError
296
+ | ValidationError;
297
+
298
+ export interface DeliveriesDeleteParams {
299
+ /**
300
+ * ETag from a preceding response. The write applies only if the resource still has that version;
301
+ * otherwise it returns 412 precondition_failed without changes. Omit to write the current
302
+ * version. See https://typeship.dev/docs/typeship-api#conditional-writes.
303
+ */
304
+ ifMatch?: string;
305
+ }
306
+
307
+ /** Typed errors `delete` can throw. */
308
+ export type DeliveriesDeleteError =
309
+ | BadRequestError<ErrorModelRead>
310
+ | UnauthorizedError<ErrorModelRead>
311
+ | ForbiddenError<ErrorModelRead>
312
+ | NotFoundError<ErrorModelRead>
313
+ | ConflictError<ErrorModelRead>
314
+ | PreconditionFailedError
315
+ | RateLimitError<ErrorModelRead>
316
+ | ServerError<ErrorModelRead>
317
+ | RateLimitError
137
318
  | UnexpectedApiError
138
319
  | ResponseParseError
139
320
  | TransportError