@shipstatic/ship 2.0.0-beta.0 → 2.0.0-beta.10
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 +22 -19
- package/SKILL.md +5 -4
- package/dist/browser.d.ts +670 -256
- package/dist/browser.js +1 -1
- package/dist/browser.js.map +1 -1
- package/dist/cli.cjs +39 -40
- package/dist/cli.cjs.map +1 -1
- package/dist/completions/ship.bash +6 -6
- package/dist/completions/ship.fish +4 -4
- package/dist/completions/ship.zsh +6 -6
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +678 -256
- package/dist/index.d.ts +675 -256
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +36 -28
package/dist/index.d.ts
CHANGED
|
@@ -11,7 +11,7 @@ declare const DeploymentStatus: {
|
|
|
11
11
|
readonly FAILED: "failed";
|
|
12
12
|
readonly DELETING: "deleting";
|
|
13
13
|
};
|
|
14
|
-
type DeploymentStatusType = typeof DeploymentStatus[keyof typeof DeploymentStatus];
|
|
14
|
+
type DeploymentStatusType = (typeof DeploymentStatus)[keyof typeof DeploymentStatus];
|
|
15
15
|
/**
|
|
16
16
|
* Core deployment object - used in both API responses and SDK
|
|
17
17
|
*/
|
|
@@ -49,16 +49,122 @@ interface DeploymentCreateResponse extends Deployment {
|
|
|
49
49
|
/** Claim URL for public deployments. Present when deployed without credentials. */
|
|
50
50
|
readonly claim?: string;
|
|
51
51
|
}
|
|
52
|
+
/**
|
|
53
|
+
* Every path the public API answers on, declared once.
|
|
54
|
+
*
|
|
55
|
+
* The URL surface was written out in four places — the API's mounts, the
|
|
56
|
+
* SDK's client, the dashboard's client, and the post-deploy smoke — so a
|
|
57
|
+
* rename meant finding all four. The first three now read this table.
|
|
58
|
+
*
|
|
59
|
+
* The smoke (`cloudflare/api/smoke.mjs`) deliberately still spells its own:
|
|
60
|
+
* five of its nine paths are `/admin/*`, which this table excludes by
|
|
61
|
+
* design, and splitting one list between a registry and literals reads worse
|
|
62
|
+
* than keeping it uniform.
|
|
63
|
+
*
|
|
64
|
+
* **What this guarantees, exactly.** Collection paths are mounted from here,
|
|
65
|
+
* so producer and consumer cannot diverge. Item paths are declared here and
|
|
66
|
+
* consumed by clients, but the API spells them relative to their mount
|
|
67
|
+
* (`/:deployment/config`), so the table does not *generate* them — it is
|
|
68
|
+
* held to them by `api/tests/architecture/api-paths.test.ts`, which fails if
|
|
69
|
+
* any entry names a path no route answers. Some entries have no client yet
|
|
70
|
+
* (`DEPLOYMENT_CONFIG`, `DOMAIN_PROPAGATION` — endpoints the SDK
|
|
71
|
+
* deliberately does not reach); the fence is what keeps those honest rather
|
|
72
|
+
* than merely asserted.
|
|
73
|
+
*
|
|
74
|
+
* **The operator surface is deliberately absent.** `/admin/*` paths belong
|
|
75
|
+
* to `web/my`, for the same reason its row types do: this package is
|
|
76
|
+
* published, and the operator surface is not public (see `CLAUDE.md`, "Admin
|
|
77
|
+
* types"). A path here is a promise to every npm consumer; `/admin` is a
|
|
78
|
+
* promise to one dashboard.
|
|
79
|
+
*
|
|
80
|
+
* Item paths are functions rather than templates so the key is interpolated
|
|
81
|
+
* in one place, encoded the same way by every caller.
|
|
82
|
+
*/
|
|
83
|
+
declare const API_PATHS: {
|
|
84
|
+
readonly DEPLOYMENTS: "/deployments";
|
|
85
|
+
readonly DEPLOYMENT: (deployment: string) => string;
|
|
86
|
+
readonly DEPLOYMENT_CONFIG: (deployment: string) => string;
|
|
87
|
+
readonly DOMAINS: "/domains";
|
|
88
|
+
readonly DOMAIN: (domain: string) => string;
|
|
89
|
+
readonly DOMAIN_VERIFY: (domain: string) => string;
|
|
90
|
+
readonly DOMAIN_DNS: (domain: string) => string;
|
|
91
|
+
readonly DOMAIN_RECORDS: (domain: string) => string;
|
|
92
|
+
readonly DOMAIN_SHARE: (domain: string) => string;
|
|
93
|
+
readonly DOMAIN_PROPAGATION: (domain: string) => string;
|
|
94
|
+
readonly DOMAINS_VALIDATE: "/domains/validate";
|
|
95
|
+
readonly TOKENS: "/tokens";
|
|
96
|
+
readonly TOKEN: (token: string) => string;
|
|
97
|
+
readonly ACCOUNT: "/account";
|
|
98
|
+
readonly ACCOUNT_KEY: "/account/key";
|
|
99
|
+
readonly ACCOUNT_CLAIM: "/account/claim";
|
|
100
|
+
readonly ACTIVITIES: "/activities";
|
|
101
|
+
readonly LABELS: "/labels";
|
|
102
|
+
readonly LIMITS: "/limits";
|
|
103
|
+
readonly PING: "/ping";
|
|
104
|
+
readonly SETUP: "/setup";
|
|
105
|
+
readonly SPA_CHECK: "/spa-check";
|
|
106
|
+
readonly UPLOAD: "/upload";
|
|
107
|
+
};
|
|
108
|
+
/**
|
|
109
|
+
* The half of a list response that is identical on every list.
|
|
110
|
+
*
|
|
111
|
+
* `GET /<collection>` answers exactly two fields — the collection under its
|
|
112
|
+
* own plural noun, and this cursor — so the cursor is declared once here and
|
|
113
|
+
* each response below adds only its noun. `cursor: null` means last page and
|
|
114
|
+
* is the ENTIRE has-more signal, which is why there is no `has_more`.
|
|
115
|
+
*
|
|
116
|
+
* There is deliberately no `total`. A count is an aggregate over a
|
|
117
|
+
* collection, not a property of a page; producing one would cost a COUNT
|
|
118
|
+
* beside every page read, which is precisely what keyset pagination exists
|
|
119
|
+
* to avoid. Counts live on the resource that summarises the collection —
|
|
120
|
+
* `GET /account`'s `usage` for one caller, `GET /admin/stats` platform-wide.
|
|
121
|
+
*/
|
|
122
|
+
interface ListResponse {
|
|
123
|
+
/** Opaque cursor from this page; `null` on the last page. */
|
|
124
|
+
cursor: string | null;
|
|
125
|
+
}
|
|
52
126
|
/**
|
|
53
127
|
* Response for listing deployments
|
|
54
128
|
*/
|
|
55
|
-
interface DeploymentListResponse {
|
|
129
|
+
interface DeploymentListResponse extends ListResponse {
|
|
56
130
|
/** Array of deployments */
|
|
57
131
|
deployments: Deployment[];
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Acknowledgement of `DELETE /deployments/:deployment` — and the shape every
|
|
135
|
+
* mutation with no entity left to return follows.
|
|
136
|
+
*
|
|
137
|
+
* **The law:** a mutation answers with the resource it affected. If the
|
|
138
|
+
* resource still exists, that means the entity itself (`Deployment`,
|
|
139
|
+
* `Domain`, …). Otherwise it means this: the resource noun carrying the
|
|
140
|
+
* item's canonical key, plus the resource's own state field — and ONLY when
|
|
141
|
+
* the resource survived in a transitional state, as an async deletion's does.
|
|
142
|
+
* Where the resource is simply gone, the key alone is the whole answer
|
|
143
|
+
* ({@link DomainDeleteResponse}, {@link TokenDeleteResponse}).
|
|
144
|
+
*
|
|
145
|
+
* Put positively: **an acknowledgement is a projection of the resource** —
|
|
146
|
+
* its key, plus its own state field where the state changed. That is the
|
|
147
|
+
* test to apply, and it is sharper than "no constant", which this shape
|
|
148
|
+
* would fail on its own terms: `status` here is the literal `'deleting'` on
|
|
149
|
+
* every success, exactly as fixed as a `changed: true` would be.
|
|
150
|
+
*
|
|
151
|
+
* The difference is not how predictable the value is, it is what the field
|
|
152
|
+
* IS. `status` is the deployment's own field — the same one `GET
|
|
153
|
+
* /deployments/:deployment` returns — so this response is `Deployment`
|
|
154
|
+
* narrowed to two members, and a client renders it with the code it already
|
|
155
|
+
* has. `changed: true`, `queued: true` and `success: true` are not fields of
|
|
156
|
+
* any entity; they exist only to assert that the call worked, which the
|
|
157
|
+
* status code already said. Sync versus accepted is likewise the status
|
|
158
|
+
* code's job — 200 versus 202 — not a boolean's.
|
|
159
|
+
*
|
|
160
|
+
* No prose either (`message`): an acknowledgement is data, and each surface
|
|
161
|
+
* composes its own copy.
|
|
162
|
+
*/
|
|
163
|
+
interface DeploymentDeleteResponse {
|
|
164
|
+
/** The deployment hostname that was marked for removal */
|
|
165
|
+
readonly deployment: string;
|
|
166
|
+
/** The state the deployment is in while background cleanup runs */
|
|
167
|
+
readonly status: DeploymentStatusType;
|
|
62
168
|
}
|
|
63
169
|
/**
|
|
64
170
|
* Domain status constants
|
|
@@ -74,7 +180,7 @@ declare const DomainStatus: {
|
|
|
74
180
|
readonly SUCCESS: "success";
|
|
75
181
|
readonly PAUSED: "paused";
|
|
76
182
|
};
|
|
77
|
-
type DomainStatusType = typeof DomainStatus[keyof typeof DomainStatus];
|
|
183
|
+
type DomainStatusType = (typeof DomainStatus)[keyof typeof DomainStatus];
|
|
78
184
|
/**
|
|
79
185
|
* Core domain object - used in both API responses and SDK
|
|
80
186
|
*/
|
|
@@ -91,7 +197,7 @@ interface Domain {
|
|
|
91
197
|
labels: string[];
|
|
92
198
|
/** Unix timestamp (seconds) when domain was created */
|
|
93
199
|
readonly created: number;
|
|
94
|
-
/**
|
|
200
|
+
/** Unix timestamp (seconds) when deployment was last linked, null if never linked */
|
|
95
201
|
linked: number | null;
|
|
96
202
|
/** Total deployment links */
|
|
97
203
|
links: number;
|
|
@@ -113,13 +219,28 @@ interface DomainSetResult extends Domain {
|
|
|
113
219
|
/**
|
|
114
220
|
* Response for listing domains
|
|
115
221
|
*/
|
|
116
|
-
interface DomainListResponse {
|
|
222
|
+
interface DomainListResponse extends ListResponse {
|
|
117
223
|
/** Array of domains */
|
|
118
224
|
domains: Domain[];
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Acknowledgement of `DELETE /domains/:domain`. The row is gone, so there is
|
|
228
|
+
* no state to state — the canonical domain name is the whole answer. See
|
|
229
|
+
* {@link DeploymentDeleteResponse} for the law.
|
|
230
|
+
*/
|
|
231
|
+
interface DomainDeleteResponse {
|
|
232
|
+
/** The domain name that was removed, normalized */
|
|
233
|
+
readonly domain: string;
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Acknowledgement of `POST /domains/:domain/verify` (202). The DNS check is
|
|
237
|
+
* queued, not performed — the accepted status code says so, and the domain's
|
|
238
|
+
* own status is unchanged until the check runs, which is why none is stated
|
|
239
|
+
* here. See {@link DeploymentDeleteResponse} for the law.
|
|
240
|
+
*/
|
|
241
|
+
interface DomainVerifyResponse {
|
|
242
|
+
/** The domain whose DNS verification was queued, normalized */
|
|
243
|
+
readonly domain: string;
|
|
123
244
|
}
|
|
124
245
|
/**
|
|
125
246
|
* DNS record types supported for domain configuration
|
|
@@ -146,16 +267,46 @@ interface DnsProvider {
|
|
|
146
267
|
/**
|
|
147
268
|
* Response for domain DNS provider lookup
|
|
148
269
|
*/
|
|
270
|
+
/**
|
|
271
|
+
* What a DNS lookup found for a domain. An envelope rather than a bare
|
|
272
|
+
* {@link DnsProvider} because a lookup can succeed and learn more than the
|
|
273
|
+
* provider later; the shape is named so a consumer can hold one.
|
|
274
|
+
*/
|
|
275
|
+
interface DnsLookup {
|
|
276
|
+
/** The provider serving this domain's DNS, absent when unidentified */
|
|
277
|
+
provider?: DnsProvider;
|
|
278
|
+
}
|
|
279
|
+
/**
|
|
280
|
+
* A report: it answers a question and carries only the answer (`CLAUDE.md`,
|
|
281
|
+
* "A report answers a question").
|
|
282
|
+
*/
|
|
149
283
|
interface DomainDnsResponse {
|
|
150
284
|
/** The domain name */
|
|
151
285
|
domain: string;
|
|
152
286
|
/** DNS provider information, null if not yet looked up */
|
|
153
|
-
dns:
|
|
154
|
-
|
|
155
|
-
|
|
287
|
+
dns: DnsLookup | null;
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* Response for `GET /domains/:domain/share` — the domain plus the salted
|
|
291
|
+
* hash that lets someone else complete its DNS setup without an account.
|
|
292
|
+
*
|
|
293
|
+
* `/admin/domains/:domain/share` answers the same shape, which is the admin
|
|
294
|
+
* law working: the operator surface is the public grammar with a prefix.
|
|
295
|
+
*
|
|
296
|
+
* A report: it answers a question and carries only the answer (`CLAUDE.md`,
|
|
297
|
+
* "A report answers a question").
|
|
298
|
+
*/
|
|
299
|
+
interface DomainShareResponse {
|
|
300
|
+
/** The domain the setup link is for */
|
|
301
|
+
readonly domain: string;
|
|
302
|
+
/** The salted setup hash that authorizes the share */
|
|
303
|
+
readonly hash: string;
|
|
156
304
|
}
|
|
157
305
|
/**
|
|
158
306
|
* Response for domain DNS records
|
|
307
|
+
*
|
|
308
|
+
* A report: it answers a question and carries only the answer (`CLAUDE.md`,
|
|
309
|
+
* "A report answers a question").
|
|
159
310
|
*/
|
|
160
311
|
interface DomainRecordsResponse {
|
|
161
312
|
/** The domain name */
|
|
@@ -166,7 +317,69 @@ interface DomainRecordsResponse {
|
|
|
166
317
|
records: DnsRecord[];
|
|
167
318
|
}
|
|
168
319
|
/**
|
|
169
|
-
*
|
|
320
|
+
* The envelope an `Idempotency-Key` must fit, and how long a replay lasts.
|
|
321
|
+
*
|
|
322
|
+
* Format lives here rather than on the server alone by the format-vs-policy
|
|
323
|
+
* rule: a client can decide offline whether a key is well-formed, and the
|
|
324
|
+
* API would reject the same value the same way.
|
|
325
|
+
*/
|
|
326
|
+
declare const IDEMPOTENCY_KEY_CONSTRAINTS: {
|
|
327
|
+
readonly MAX_LENGTH: 256;
|
|
328
|
+
/** How long a stored 201 stays replayable. */
|
|
329
|
+
readonly WINDOW_SECONDS: number;
|
|
330
|
+
};
|
|
331
|
+
/**
|
|
332
|
+
* Validate an idempotency key, returning the trimmed value or `undefined`
|
|
333
|
+
* when none was supplied. Throws {@link ShipError.validation} when the value
|
|
334
|
+
* cannot be sent — the same verdict the API would reach, reached earlier.
|
|
335
|
+
*/
|
|
336
|
+
declare function validateIdempotencyKey(value: unknown): string | undefined;
|
|
337
|
+
/**
|
|
338
|
+
* Response for `GET /labels` — every label in use across the caller's
|
|
339
|
+
* deployments, domains and tokens, grouped and ordered by last use.
|
|
340
|
+
*
|
|
341
|
+
* The one plural noun outside the list contract, deliberately: labels have
|
|
342
|
+
* no identity, no row and no `created`, so there is nothing for a keyset
|
|
343
|
+
* cursor to resume after, and its consumer is an autocomplete that wants the
|
|
344
|
+
* whole set. Bounded by `PAGINATION.GLOBAL_LIMIT` rather than paginated.
|
|
345
|
+
*
|
|
346
|
+
* A report: it answers a question and carries only the answer (`CLAUDE.md`,
|
|
347
|
+
* "A report answers a question").
|
|
348
|
+
*/
|
|
349
|
+
interface LabelsResponse {
|
|
350
|
+
readonly labels: string[];
|
|
351
|
+
}
|
|
352
|
+
/**
|
|
353
|
+
* Response for `POST /setup` — the DNS instructions for one domain, written
|
|
354
|
+
* for a human to follow at their registrar.
|
|
355
|
+
*
|
|
356
|
+
* `custom` is the provider-specific walkthrough when the provider is known;
|
|
357
|
+
* `generic` always answers, so a caller never has nothing to show.
|
|
358
|
+
*
|
|
359
|
+
* A report: it answers a question and carries only the answer (`CLAUDE.md`,
|
|
360
|
+
* "A report answers a question").
|
|
361
|
+
*/
|
|
362
|
+
interface SetupInstructionsResponse {
|
|
363
|
+
/** The domain the instructions are for — a report names its subject */
|
|
364
|
+
readonly domain: string;
|
|
365
|
+
/** One-line summary of what to do */
|
|
366
|
+
readonly tldr: string;
|
|
367
|
+
/** Provider-specific instructions, null when the provider is unknown */
|
|
368
|
+
readonly custom: string | null;
|
|
369
|
+
/** Provider-agnostic instructions — always present */
|
|
370
|
+
readonly generic: string;
|
|
371
|
+
/** The identified DNS provider, null when unknown */
|
|
372
|
+
readonly provider: string | null;
|
|
373
|
+
}
|
|
374
|
+
/**
|
|
375
|
+
* `POST /domains/validate` — a report answering "is this name usable, and if
|
|
376
|
+
* not, why".
|
|
377
|
+
*
|
|
378
|
+
* An unusable name is a legitimate ANSWER, not a failure, so this is a 200 and
|
|
379
|
+
* the verdict rides the body. `reason` was named `error` until 2026-07-29,
|
|
380
|
+
* which collided with {@link ErrorResponse}'s reserved key — there `error` is
|
|
381
|
+
* an `ErrorType` a client branches on, here it is prose a client displays, and
|
|
382
|
+
* one key cannot mean both. See {@link DeploymentDeleteResponse} for the law.
|
|
170
383
|
*/
|
|
171
384
|
interface DomainValidateResponse {
|
|
172
385
|
/** Whether the domain is valid */
|
|
@@ -175,15 +388,17 @@ interface DomainValidateResponse {
|
|
|
175
388
|
normalized: string | null;
|
|
176
389
|
/** Whether the domain is available, null when invalid */
|
|
177
390
|
available: boolean | null;
|
|
178
|
-
/**
|
|
179
|
-
|
|
391
|
+
/** Why the name is unusable, null when valid — displayed verbatim. */
|
|
392
|
+
reason: string | null;
|
|
180
393
|
}
|
|
181
394
|
/**
|
|
182
|
-
*
|
|
183
|
-
*
|
|
184
|
-
*
|
|
395
|
+
* Core deploy token object - used in both API responses and SDK.
|
|
396
|
+
*
|
|
397
|
+
* The secret is never here: it is shown once at creation
|
|
398
|
+
* ({@link TokenCreateResponse.secret}) and never again, so an entity read
|
|
399
|
+
* carries only the management identifier and lifecycle metadata.
|
|
185
400
|
*/
|
|
186
|
-
interface
|
|
401
|
+
interface Token {
|
|
187
402
|
/** 7-char management identifier (e.g., "a1b2c3d") */
|
|
188
403
|
readonly token: string;
|
|
189
404
|
/** Labels for categorization and filtering. Always present, empty array when none. */
|
|
@@ -198,24 +413,28 @@ interface TokenListItem {
|
|
|
198
413
|
/**
|
|
199
414
|
* Response for listing tokens
|
|
200
415
|
*/
|
|
201
|
-
interface TokenListResponse {
|
|
202
|
-
/** Array of tokens (
|
|
203
|
-
tokens:
|
|
204
|
-
/** Total number of tokens */
|
|
205
|
-
total: number;
|
|
416
|
+
interface TokenListResponse extends ListResponse {
|
|
417
|
+
/** Array of tokens (the secret is never among them) */
|
|
418
|
+
tokens: Token[];
|
|
206
419
|
}
|
|
207
420
|
/**
|
|
208
|
-
* Response
|
|
421
|
+
* Response from token creation. Extends Token with the one field that
|
|
422
|
+
* exists only on creation — the same shape as
|
|
423
|
+
* {@link DeploymentCreateResponse}, because a 201 returns the resource it
|
|
424
|
+
* created plus whatever is knowable only once.
|
|
209
425
|
*/
|
|
210
|
-
interface TokenCreateResponse {
|
|
211
|
-
/** 7-char management identifier */
|
|
212
|
-
token: string;
|
|
426
|
+
interface TokenCreateResponse extends Token {
|
|
213
427
|
/** The raw credential value (shown once at creation, then never again) */
|
|
214
|
-
secret: string;
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
428
|
+
readonly secret: string;
|
|
429
|
+
}
|
|
430
|
+
/**
|
|
431
|
+
* Acknowledgement of `DELETE /tokens/:token`. The credential is revoked and
|
|
432
|
+
* its row is gone, so the management identifier is the whole answer. See
|
|
433
|
+
* {@link DeploymentDeleteResponse} for the law.
|
|
434
|
+
*/
|
|
435
|
+
interface TokenDeleteResponse {
|
|
436
|
+
/** The 7-char management identifier that was revoked */
|
|
437
|
+
readonly token: string;
|
|
219
438
|
}
|
|
220
439
|
/**
|
|
221
440
|
* Account plan constants
|
|
@@ -229,13 +448,37 @@ declare const AccountPlan: {
|
|
|
229
448
|
readonly TERMINATING: "terminating";
|
|
230
449
|
readonly TERMINATED: "terminated";
|
|
231
450
|
};
|
|
232
|
-
type AccountPlanType = typeof AccountPlan[keyof typeof AccountPlan];
|
|
451
|
+
type AccountPlanType = (typeof AccountPlan)[keyof typeof AccountPlan];
|
|
233
452
|
/**
|
|
234
453
|
* Account usage metrics — always available regardless of billing provider.
|
|
454
|
+
*
|
|
455
|
+
* This is where a caller's own totals live. Lists answer pages and carry no
|
|
456
|
+
* `total` (see {@link ListOptions}); a count is an aggregate over a
|
|
457
|
+
* collection, so it belongs to the summary resource that owns the
|
|
458
|
+
* collection. `GET /account` is that resource for one caller, `GET
|
|
459
|
+
* /admin/stats` for the platform.
|
|
460
|
+
*
|
|
461
|
+
* The counted dimensions are the ones the plan caps — deployments and
|
|
462
|
+
* domains (`PlatformLimits`) — plus the billable custom-domain subset, so a
|
|
463
|
+
* surface can render "3 of 10" without a second request.
|
|
235
464
|
*/
|
|
236
465
|
interface AccountUsage {
|
|
237
466
|
/** Number of active custom domains (excludes paused) */
|
|
238
467
|
customDomains: number;
|
|
468
|
+
/**
|
|
469
|
+
* Deployments counted against the plan's deployment cap — every row
|
|
470
|
+
* whatever its status, because that is what the cap counts, so a surface
|
|
471
|
+
* renders "3 of 10" against the denominator the 403 divides by. (`GET
|
|
472
|
+
* /deployments` lists successful ones only; that is a different question
|
|
473
|
+
* asked of a different resource.) Optional by the additive-evolution law:
|
|
474
|
+
* an API predating this field omits it.
|
|
475
|
+
*/
|
|
476
|
+
deployments?: number;
|
|
477
|
+
/**
|
|
478
|
+
* Domains counted against the plan's domain cap — every domain, platform
|
|
479
|
+
* and custom alike, unlike `customDomains`. Optional for the same reason.
|
|
480
|
+
*/
|
|
481
|
+
domains?: number;
|
|
239
482
|
}
|
|
240
483
|
/**
|
|
241
484
|
* Core account object - used in both API responses and SDK
|
|
@@ -258,6 +501,13 @@ interface Account {
|
|
|
258
501
|
readonly activated: number | null;
|
|
259
502
|
/** Last 4 characters of the API key for identification, null when no key generated */
|
|
260
503
|
readonly hint: string | null;
|
|
504
|
+
/**
|
|
505
|
+
* Unix timestamp (seconds) of the API key's last use, null when never
|
|
506
|
+
* used or no key generated. Optional on the type by the additive-evolution
|
|
507
|
+
* law: published SDK versions may predate the field, so consumers read it
|
|
508
|
+
* when present rather than forcing a lockstep SDK release.
|
|
509
|
+
*/
|
|
510
|
+
readonly used?: number | null;
|
|
261
511
|
/** Grace period expiration (unix seconds), null if no grace period active */
|
|
262
512
|
readonly grace: number | null;
|
|
263
513
|
}
|
|
@@ -275,6 +525,35 @@ interface AccountGetResponse extends Account {
|
|
|
275
525
|
/** Present only during read-only admin impersonation: the operator's account id. */
|
|
276
526
|
readonly impersonatedBy?: string;
|
|
277
527
|
}
|
|
528
|
+
/**
|
|
529
|
+
* Acknowledgement of `DELETE /account` (202). Termination is asynchronous —
|
|
530
|
+
* a cleanup consumer finishes the job — so the account survives long enough
|
|
531
|
+
* to state the plan it is transitioning through. `plan` is the account's
|
|
532
|
+
* state field, the way `status` is a deployment's. See
|
|
533
|
+
* {@link DeploymentDeleteResponse} for the law.
|
|
534
|
+
*/
|
|
535
|
+
interface AccountDeleteResponse {
|
|
536
|
+
/** The account that was marked for termination */
|
|
537
|
+
readonly account: string;
|
|
538
|
+
/** The plan the account is in while cleanup runs */
|
|
539
|
+
readonly plan: AccountPlanType;
|
|
540
|
+
}
|
|
541
|
+
/**
|
|
542
|
+
* Response from `PUT /account/key` — the account's single API key, minted in
|
|
543
|
+
* place of whatever was there before.
|
|
544
|
+
*
|
|
545
|
+
* There is no entity to return: only the key's last-4 `hint` is durable
|
|
546
|
+
* (`Account.hint`), and the plaintext exists exactly once, in this response.
|
|
547
|
+
* The raw credential is `secret` on every surface that mints one — the same
|
|
548
|
+
* field `TokenCreateResponse` carries — because one concept gets one name.
|
|
549
|
+
*
|
|
550
|
+
* A report: it answers a question and carries only the answer (`CLAUDE.md`,
|
|
551
|
+
* "A report answers a question").
|
|
552
|
+
*/
|
|
553
|
+
interface AccountKeyResponse {
|
|
554
|
+
/** The raw API key (shown once at mint, then never again) */
|
|
555
|
+
readonly secret: string;
|
|
556
|
+
}
|
|
278
557
|
/**
|
|
279
558
|
* Account-specific configuration overrides
|
|
280
559
|
* Allows per-account customization of limits without changing plan
|
|
@@ -301,7 +580,15 @@ interface AccountOverrides {
|
|
|
301
580
|
* (`DeploymentStatus`, `DomainStatus`, `AccountPlan`, `AuthMethod`) follow.
|
|
302
581
|
*/
|
|
303
582
|
declare const ErrorType: {
|
|
304
|
-
/**
|
|
583
|
+
/**
|
|
584
|
+
* Validation failed. Input shape is wrong.
|
|
585
|
+
*
|
|
586
|
+
* Carries 400 when an API judged it — including a client-side pre-check of a
|
|
587
|
+
* rule the server enforces too, which keeps the error identical wherever it
|
|
588
|
+
* was caught. **Statusless** when a client rejects something no API judges,
|
|
589
|
+
* such as a CLI's own command grammar: `status` is documented "(API
|
|
590
|
+
* contexts)" on `ErrorResponse`, so there is none to report.
|
|
591
|
+
*/
|
|
305
592
|
readonly Validation: "validation_failed";
|
|
306
593
|
/** Resource not found (404). */
|
|
307
594
|
readonly NotFound: "not_found";
|
|
@@ -324,7 +611,7 @@ declare const ErrorType: {
|
|
|
324
611
|
/** Configuration error. Client-side only — set by SDK during config parsing/validation; never produced server-side. */
|
|
325
612
|
readonly Config: "config_error";
|
|
326
613
|
};
|
|
327
|
-
type ErrorType = typeof ErrorType[keyof typeof ErrorType];
|
|
614
|
+
type ErrorType = (typeof ErrorType)[keyof typeof ErrorType];
|
|
328
615
|
/**
|
|
329
616
|
* Standard error response format used everywhere
|
|
330
617
|
*/
|
|
@@ -414,6 +701,18 @@ declare class ShipError extends Error {
|
|
|
414
701
|
static file(message: string, details?: unknown): ShipError;
|
|
415
702
|
static config(message: string, details?: unknown): ShipError;
|
|
416
703
|
static api(message: string, status?: number, details?: unknown): ShipError;
|
|
704
|
+
/**
|
|
705
|
+
* The caller is at fault — by HTTP's own definition of a 4xx, or by a type
|
|
706
|
+
* that is client-attributable without ever having a status (`Config`,
|
|
707
|
+
* `File`, raised locally by the SDK).
|
|
708
|
+
*
|
|
709
|
+
* Both arms are load-bearing, because type and status are independent
|
|
710
|
+
* axes. `fromHttpResponse` trusts `body.error` only when it names a
|
|
711
|
+
* server-producible type; a non-OK response without one is status-derived,
|
|
712
|
+
* so a CDN 404 or any intermediary error arrives as `Api` — a server-fault
|
|
713
|
+
* *type* carrying a client *status*. Judging by type alone would report it
|
|
714
|
+
* as a platform failure and bury the server's own message.
|
|
715
|
+
*/
|
|
417
716
|
isClientError(): boolean;
|
|
418
717
|
isNetworkError(): boolean;
|
|
419
718
|
isAuthError(): boolean;
|
|
@@ -440,6 +739,9 @@ declare function isShipError(error: unknown): error is ShipError;
|
|
|
440
739
|
*
|
|
441
740
|
* These are the *platform's* posted caps for the current account — server
|
|
442
741
|
* truth delivered at runtime, never hard-coded on the client.
|
|
742
|
+
*
|
|
743
|
+
* A report: it answers a question and carries only the answer (`CLAUDE.md`,
|
|
744
|
+
* "A report answers a question").
|
|
443
745
|
*/
|
|
444
746
|
interface PlatformLimits {
|
|
445
747
|
/** Maximum size in bytes for a single file. */
|
|
@@ -510,14 +812,29 @@ declare const UNBUILT_PROJECT_MARKERS: ReadonlySet<string>;
|
|
|
510
812
|
*/
|
|
511
813
|
declare function hasUnbuiltMarker(filePath: string): boolean;
|
|
512
814
|
/**
|
|
513
|
-
*
|
|
815
|
+
* `GET /ping` — a report of the server clock.
|
|
816
|
+
*
|
|
817
|
+
* Liveness is the STATUS CODE's answer, not a field's: a 200 means reachable,
|
|
818
|
+
* and any other outcome throws before a body is read. So the body carries the
|
|
819
|
+
* one thing a status code cannot — the server's own clock, which is what lets a
|
|
820
|
+
* client detect skew against a token expiry. It read `{ success: true,
|
|
821
|
+
* timestamp? }` until 2026-07-29, where `success` was a literal constant in the
|
|
822
|
+
* route (zero bits, and the platform's own named anti-pattern) while the field
|
|
823
|
+
* that IS the payload was optional. See {@link DeploymentDeleteResponse} for
|
|
824
|
+
* the law, and `tests/response-shapes.test.ts` for the fence that holds it.
|
|
514
825
|
*/
|
|
515
826
|
interface PingResponse {
|
|
516
|
-
/**
|
|
517
|
-
|
|
518
|
-
/** Optional timestamp */
|
|
519
|
-
timestamp?: number;
|
|
827
|
+
/** Server time in unix seconds — the one wire unit for timestamps. */
|
|
828
|
+
readonly timestamp: number;
|
|
520
829
|
}
|
|
830
|
+
/**
|
|
831
|
+
* Where human identity is mounted on the API host. The API mounts Better
|
|
832
|
+
* Auth at this path (sign-in, sign-out, session reads, admin impersonation)
|
|
833
|
+
* and the web console's auth client posts to it — shared here so the two
|
|
834
|
+
* halves of the auth pair agree by construction, the same way both sides
|
|
835
|
+
* already share the credential prefixes below.
|
|
836
|
+
*/
|
|
837
|
+
declare const AUTH_BASE_PATH = "/auth";
|
|
521
838
|
/**
|
|
522
839
|
* How a request (or recorded activity) was authorized.
|
|
523
840
|
*
|
|
@@ -536,7 +853,7 @@ declare const AuthMethod: {
|
|
|
536
853
|
readonly WEBHOOK: "webhook";
|
|
537
854
|
readonly SYSTEM: "system";
|
|
538
855
|
};
|
|
539
|
-
type AuthMethodType = typeof AuthMethod[keyof typeof AuthMethod];
|
|
856
|
+
type AuthMethodType = (typeof AuthMethod)[keyof typeof AuthMethod];
|
|
540
857
|
/**
|
|
541
858
|
* Shape constants for API keys (`ship-{64 hex chars}`).
|
|
542
859
|
* Single source of truth used by validation utilities and auth middleware.
|
|
@@ -595,7 +912,7 @@ declare const TokenKind: {
|
|
|
595
912
|
readonly DEPLOY_TOKEN: "token";
|
|
596
913
|
readonly OPAQUE: "opaque";
|
|
597
914
|
};
|
|
598
|
-
type TokenKindType = typeof TokenKind[keyof typeof TokenKind];
|
|
915
|
+
type TokenKindType = (typeof TokenKind)[keyof typeof TokenKind];
|
|
599
916
|
/**
|
|
600
917
|
* Classify a client token by shape. The single dispatch used by both sides
|
|
601
918
|
* of the wire: API auth middleware (which population is this credential?)
|
|
@@ -621,7 +938,7 @@ declare const OAuthScope: {
|
|
|
621
938
|
readonly DOMAINS_READ: "domains:read";
|
|
622
939
|
readonly DOMAINS_WRITE: "domains:write";
|
|
623
940
|
};
|
|
624
|
-
type OAuthScopeType = typeof OAuthScope[keyof typeof OAuthScope];
|
|
941
|
+
type OAuthScopeType = (typeof OAuthScope)[keyof typeof OAuthScope];
|
|
625
942
|
declare const DEPLOYMENT_CONFIG_FILENAME = "ship.json";
|
|
626
943
|
/** Default ship.json config for SPA routing. Single source of truth — used by both API and SDK. */
|
|
627
944
|
declare const SPA_DEFAULT_CONFIG: {
|
|
@@ -630,6 +947,36 @@ declare const SPA_DEFAULT_CONFIG: {
|
|
|
630
947
|
readonly destination: "/index.html";
|
|
631
948
|
}];
|
|
632
949
|
};
|
|
950
|
+
/**
|
|
951
|
+
* Assert that a ship.json file is *syntactically* loadable. Syntax only —
|
|
952
|
+
* never schema.
|
|
953
|
+
*
|
|
954
|
+
* ship.json is validated and compiled on the server, deliberately: the schema
|
|
955
|
+
* and the compiler evolve, and a client that judged them would reject configs
|
|
956
|
+
* a newer platform accepts. That reasoning bounds what a client may check to
|
|
957
|
+
* the properties which are true of *every* past and future schema:
|
|
958
|
+
*
|
|
959
|
+
* 1. it parses as JSON — JSON syntax is frozen (RFC 8259), so text that
|
|
960
|
+
* does not parse can never be a valid config;
|
|
961
|
+
* 2. its top level is an object — ship.json is `{ ... }` in every version.
|
|
962
|
+
*
|
|
963
|
+
* Both are monotonic: neither can ever reject something the server would
|
|
964
|
+
* accept. Everything beyond them (field names, types, rule semantics, which
|
|
965
|
+
* keys are permitted) stays server-side, where it can change.
|
|
966
|
+
*
|
|
967
|
+
* The payoff is the common case. Hand-edited JSON fails on a trailing comma,
|
|
968
|
+
* a `//` comment, single quotes, unquoted keys, or smart quotes pasted from
|
|
969
|
+
* documentation — mistakes that otherwise cost a full upload round-trip to
|
|
970
|
+
* discover. A UTF-8 BOM (Windows editors, PowerShell redirects) is stripped
|
|
971
|
+
* before parsing rather than rejected, because the server accepts it too;
|
|
972
|
+
* diverging there would reintroduce exactly the false rejection this
|
|
973
|
+
* function exists to avoid.
|
|
974
|
+
*
|
|
975
|
+
* @throws {ShipError} `ErrorType.Config` — the same type the server's own
|
|
976
|
+
* config rejection carries, so the error contract is identical wherever the
|
|
977
|
+
* failure is detected.
|
|
978
|
+
*/
|
|
979
|
+
declare function assertShipJsonSyntax(text: string): void;
|
|
633
980
|
/**
|
|
634
981
|
* Validate API key format
|
|
635
982
|
*/
|
|
@@ -672,16 +1019,26 @@ interface SPACheckRequest {
|
|
|
672
1019
|
/**
|
|
673
1020
|
* Response from SPA check endpoint
|
|
674
1021
|
*/
|
|
1022
|
+
/**
|
|
1023
|
+
* Which of the classifier's tiers reached the verdict, and why. Named rather
|
|
1024
|
+
* than inline so the API's own `checkSPA` can return `SPACheckResponse`
|
|
1025
|
+
* instead of restating its shape.
|
|
1026
|
+
*/
|
|
1027
|
+
interface SPACheckDebug {
|
|
1028
|
+
/** Which tier made the detection */
|
|
1029
|
+
tier: 'exclusions' | 'inclusions' | 'scoring' | 'ai' | 'fallback';
|
|
1030
|
+
/** The reason for the detection result */
|
|
1031
|
+
reason: string;
|
|
1032
|
+
}
|
|
1033
|
+
/**
|
|
1034
|
+
* A report: it answers a question and carries only the answer (`CLAUDE.md`,
|
|
1035
|
+
* "A report answers a question").
|
|
1036
|
+
*/
|
|
675
1037
|
interface SPACheckResponse {
|
|
676
1038
|
/** Whether the project is detected as a Single Page Application */
|
|
677
1039
|
isSPA: boolean;
|
|
678
1040
|
/** Debugging information about detection */
|
|
679
|
-
debug:
|
|
680
|
-
/** Which tier made the detection: 'exclusions', 'inclusions', 'scoring', 'ai', or 'fallback' */
|
|
681
|
-
tier: 'exclusions' | 'inclusions' | 'scoring' | 'ai' | 'fallback';
|
|
682
|
-
/** The reason for the detection result */
|
|
683
|
-
reason: string;
|
|
684
|
-
};
|
|
1041
|
+
debug: SPACheckDebug;
|
|
685
1042
|
}
|
|
686
1043
|
/**
|
|
687
1044
|
* Represents a file that has been processed and is ready for deploy.
|
|
@@ -712,20 +1069,6 @@ interface StaticFile {
|
|
|
712
1069
|
/** The size of the file in bytes. */
|
|
713
1070
|
size: number;
|
|
714
1071
|
}
|
|
715
|
-
/**
|
|
716
|
-
* Progress information for deploy/upload operations.
|
|
717
|
-
* Provides consistent percentage-based progress with byte-level details.
|
|
718
|
-
*/
|
|
719
|
-
interface ProgressInfo {
|
|
720
|
-
/** Progress percentage (0-100) */
|
|
721
|
-
percent: number;
|
|
722
|
-
/** Number of bytes loaded so far */
|
|
723
|
-
loaded: number;
|
|
724
|
-
/** Total number of bytes to load. May be 0 if unknown initially */
|
|
725
|
-
total: number;
|
|
726
|
-
/** Current file being processed (optional) */
|
|
727
|
-
file?: string;
|
|
728
|
-
}
|
|
729
1072
|
/** Default API URL if not otherwise configured. */
|
|
730
1073
|
declare const DEFAULT_API = "https://api.shipstatic.com";
|
|
731
1074
|
/**
|
|
@@ -767,40 +1110,103 @@ interface DeploymentUploadOptions {
|
|
|
767
1110
|
spa?: boolean;
|
|
768
1111
|
/** @internal reCAPTCHA proof for the anonymous human deploy channel. Only available via /upload endpoint. */
|
|
769
1112
|
captcha?: string;
|
|
1113
|
+
/**
|
|
1114
|
+
* Makes this deploy replayable instead of repeatable.
|
|
1115
|
+
*
|
|
1116
|
+
* A deploy is not naturally idempotent: a client-side timeout on a slow
|
|
1117
|
+
* one leaves the caller unable to tell "it never landed" from "it landed
|
|
1118
|
+
* and the response was lost", and retrying produces a second deployment.
|
|
1119
|
+
* Send the same key on the retry and the platform replays the original
|
|
1120
|
+
* 201 verbatim rather than creating anything
|
|
1121
|
+
* ({@link IDEMPOTENCY_KEY_CONSTRAINTS.WINDOW_SECONDS}).
|
|
1122
|
+
*
|
|
1123
|
+
* **Agents are the audience.** A human notices a duplicate; an automated
|
|
1124
|
+
* retry does not. Pick a key that identifies the ATTEMPT — a run id, a
|
|
1125
|
+
* commit sha, a uuid minted before the first try — never one that varies
|
|
1126
|
+
* per attempt, which would defeat the point.
|
|
1127
|
+
*
|
|
1128
|
+
* The replay is per-caller, and it stores successes only: a failed deploy
|
|
1129
|
+
* retries fresh under the same key.
|
|
1130
|
+
*/
|
|
1131
|
+
idempotencyKey?: string;
|
|
1132
|
+
}
|
|
1133
|
+
/**
|
|
1134
|
+
* Pagination options for every list endpoint. The response's `cursor` feeds
|
|
1135
|
+
* the next request; a `null` cursor means the last page. Omitting both
|
|
1136
|
+
* returns the server's default first page.
|
|
1137
|
+
*
|
|
1138
|
+
* A list answers `{ <collection>, cursor }` and nothing else — `cursor`
|
|
1139
|
+
* carries the entire has-more signal, so no redundant boolean, and no
|
|
1140
|
+
* `total`. **A count is an aggregate over a collection, not a property of a
|
|
1141
|
+
* page:** including one makes every read pay for a full scan it did not ask
|
|
1142
|
+
* for, which is precisely the cost keyset pagination exists to avoid.
|
|
1143
|
+
*
|
|
1144
|
+
* Counts therefore live on the summary resource that owns them —
|
|
1145
|
+
* `GET /account` (`usage`) for a caller's own totals, `GET /admin/stats` for
|
|
1146
|
+
* platform-wide ones. Ask for a count when you want a count; ask for a page
|
|
1147
|
+
* when you want a page.
|
|
1148
|
+
*/
|
|
1149
|
+
interface ListOptions {
|
|
1150
|
+
/** Maximum number of items to return in one page. */
|
|
1151
|
+
limit?: number;
|
|
1152
|
+
/** Opaque cursor from the previous page's response. */
|
|
1153
|
+
cursor?: string;
|
|
1154
|
+
}
|
|
1155
|
+
/**
|
|
1156
|
+
* What a caller may change on an existing deployment.
|
|
1157
|
+
*
|
|
1158
|
+
* Labels and nothing else: a deployment's content is immutable by design, so
|
|
1159
|
+
* this is the whole mutable surface rather than a subset someone chose.
|
|
1160
|
+
*/
|
|
1161
|
+
interface DeploymentSetOptions {
|
|
1162
|
+
labels: string[];
|
|
1163
|
+
}
|
|
1164
|
+
/**
|
|
1165
|
+
* What `domains.set()` may create or change. Every field is optional because
|
|
1166
|
+
* the call is a natural-key upsert: omitting `deployment` reserves the
|
|
1167
|
+
* domain, naming one links or re-points it, and labels travel either way.
|
|
1168
|
+
*
|
|
1169
|
+
* `deployment` is deliberately not nullable — unlinking is refused (400).
|
|
1170
|
+
* See `npm/ship/CLAUDE.md`, "Domain Write Semantics".
|
|
1171
|
+
*/
|
|
1172
|
+
interface DomainSetOptions {
|
|
1173
|
+
deployment?: string;
|
|
1174
|
+
labels?: string[];
|
|
1175
|
+
}
|
|
1176
|
+
/** What a caller may set when minting a deploy token. */
|
|
1177
|
+
interface TokenCreateOptions {
|
|
1178
|
+
/** Seconds until expiry; omit for a token that never expires. */
|
|
1179
|
+
ttl?: number;
|
|
1180
|
+
labels?: string[];
|
|
770
1181
|
}
|
|
771
1182
|
/**
|
|
772
|
-
* Deployment resource interface - the contract all implementations must follow
|
|
1183
|
+
* Deployment resource interface - the contract all implementations must follow.
|
|
1184
|
+
*
|
|
1185
|
+
* The interface defines the minimal wire contract; SDK implementations may
|
|
1186
|
+
* extend the upload options with runtime concerns (timeout, signal, progress
|
|
1187
|
+
* callbacks) by parameterizing: `DeploymentResource<MyUploadOptions>`. The
|
|
1188
|
+
* default keeps plain `DeploymentResource` valid for wire-only consumers.
|
|
773
1189
|
*/
|
|
774
|
-
interface DeploymentResource {
|
|
775
|
-
upload: (input: DeployInput, options?:
|
|
776
|
-
list: () => Promise<DeploymentListResponse>;
|
|
1190
|
+
interface DeploymentResource<UploadOptions extends DeploymentUploadOptions = DeploymentUploadOptions> {
|
|
1191
|
+
upload: (input: DeployInput, options?: UploadOptions) => Promise<DeploymentCreateResponse>;
|
|
1192
|
+
list: (options?: ListOptions) => Promise<DeploymentListResponse>;
|
|
777
1193
|
get: (id: string) => Promise<Deployment>;
|
|
778
|
-
set: (id: string, options:
|
|
779
|
-
|
|
780
|
-
}) => Promise<Deployment>;
|
|
781
|
-
remove: (id: string) => Promise<void>;
|
|
1194
|
+
set: (id: string, options: DeploymentSetOptions) => Promise<Deployment>;
|
|
1195
|
+
delete: (id: string) => Promise<DeploymentDeleteResponse>;
|
|
782
1196
|
}
|
|
783
1197
|
/**
|
|
784
1198
|
* Domain resource interface - the contract all implementations must follow
|
|
785
1199
|
*/
|
|
786
1200
|
interface DomainResource {
|
|
787
|
-
set: (name: string, options?:
|
|
788
|
-
|
|
789
|
-
labels?: string[];
|
|
790
|
-
}) => Promise<DomainSetResult>;
|
|
791
|
-
list: () => Promise<DomainListResponse>;
|
|
1201
|
+
set: (name: string, options?: DomainSetOptions) => Promise<DomainSetResult>;
|
|
1202
|
+
list: (options?: ListOptions) => Promise<DomainListResponse>;
|
|
792
1203
|
get: (name: string) => Promise<Domain>;
|
|
793
|
-
|
|
794
|
-
verify: (name: string) => Promise<
|
|
795
|
-
message: string;
|
|
796
|
-
}>;
|
|
1204
|
+
delete: (name: string) => Promise<DomainDeleteResponse>;
|
|
1205
|
+
verify: (name: string) => Promise<DomainVerifyResponse>;
|
|
797
1206
|
validate: (name: string) => Promise<DomainValidateResponse>;
|
|
798
1207
|
dns: (name: string) => Promise<DomainDnsResponse>;
|
|
799
1208
|
records: (name: string) => Promise<DomainRecordsResponse>;
|
|
800
|
-
share: (name: string) => Promise<
|
|
801
|
-
domain: string;
|
|
802
|
-
hash: string;
|
|
803
|
-
}>;
|
|
1209
|
+
share: (name: string) => Promise<DomainShareResponse>;
|
|
804
1210
|
}
|
|
805
1211
|
/**
|
|
806
1212
|
* Account resource interface - the contract all implementations must follow
|
|
@@ -812,12 +1218,10 @@ interface AccountResource {
|
|
|
812
1218
|
* Token resource interface - the contract all implementations must follow
|
|
813
1219
|
*/
|
|
814
1220
|
interface TokenResource {
|
|
815
|
-
create: (options?:
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
list: () => Promise<TokenListResponse>;
|
|
820
|
-
remove: (token: string) => Promise<void>;
|
|
1221
|
+
create: (options?: TokenCreateOptions) => Promise<TokenCreateResponse>;
|
|
1222
|
+
list: (options?: ListOptions) => Promise<TokenListResponse>;
|
|
1223
|
+
get: (token: string) => Promise<Token>;
|
|
1224
|
+
delete: (token: string) => Promise<TokenDeleteResponse>;
|
|
821
1225
|
}
|
|
822
1226
|
/**
|
|
823
1227
|
* Billing status response from GET /billing/status
|
|
@@ -837,6 +1241,25 @@ interface BillingStatus {
|
|
|
837
1241
|
/** Link to Creem customer portal for billing management, null if unavailable */
|
|
838
1242
|
portal: string | null;
|
|
839
1243
|
}
|
|
1244
|
+
/**
|
|
1245
|
+
* Acknowledgement of `POST /billing/cancel`.
|
|
1246
|
+
*
|
|
1247
|
+
* Cancelling leaves no billing entity to return, so it answers with the
|
|
1248
|
+
* account and the one field of the account the call changed — the plan it
|
|
1249
|
+
* landed on. See {@link DeploymentDeleteResponse} for the law.
|
|
1250
|
+
*
|
|
1251
|
+
* This read `{ success: true, message: 'Subscription canceled successfully…' }`
|
|
1252
|
+
* until 2026-07-29, an anonymous shape that `web/my` redeclared inline and
|
|
1253
|
+
* whose prose no surface ever displayed: both callers await the promise and
|
|
1254
|
+
* discard the body, then compose their own toast. The message was written,
|
|
1255
|
+
* serialized, and thrown away on every cancellation.
|
|
1256
|
+
*/
|
|
1257
|
+
interface BillingCancelResponse {
|
|
1258
|
+
/** The account whose subscription was cancelled */
|
|
1259
|
+
readonly account: string;
|
|
1260
|
+
/** The plan the account now holds — `free` on a successful cancellation */
|
|
1261
|
+
readonly plan: AccountPlanType;
|
|
1262
|
+
}
|
|
840
1263
|
/**
|
|
841
1264
|
* Checkout session response from POST /billing/checkout
|
|
842
1265
|
*/
|
|
@@ -848,11 +1271,11 @@ interface CheckoutSession {
|
|
|
848
1271
|
* All activity event types logged in the system.
|
|
849
1272
|
* Uses dot notation consistently: {resource}.{action}
|
|
850
1273
|
*/
|
|
851
|
-
type ActivityEvent = 'account.create' | 'account.update' | 'account.delete' | 'account.key.generate' | 'account.plan.paid' | 'account.plan.transition' | 'account.suspended' | 'deployment.create' | 'deployment.update' | 'deployment.delete' | 'deployment.claim' | 'deployment.flagged' | 'domain.create' | 'domain.update' | 'domain.delete' | 'domain.verify' | 'token.create' | 'token.consume' | 'admin.account.plan.update' | 'admin.account.ref.update' | 'admin.account.billing.update' | 'admin.account.labels.update' | 'admin.deployment.delete' | 'admin.domain.delete' | 'admin.billing.sync' | 'admin.billing.terminated' | 'admin.impersonate' | 'billing.active' | 'billing.canceled' | 'billing.paused' | 'billing.expired' | 'billing.paid' | 'billing.trialing' | 'billing.scheduled_cancel' | 'billing.unpaid' | 'billing.update' | 'billing.past_due' | 'refund.created' | 'dispute.created' | 'billing.sync' | 'billing.stale' | 'billing.race';
|
|
1274
|
+
type ActivityEvent = 'account.create' | 'account.update' | 'account.delete' | 'account.key.generate' | 'account.plan.paid' | 'account.plan.transition' | 'account.suspended' | 'deployment.create' | 'deployment.update' | 'deployment.delete' | 'deployment.claim' | 'deployment.flagged' | 'domain.create' | 'domain.update' | 'domain.delete' | 'domain.verify' | 'token.create' | 'token.consume' | 'token.delete' | 'admin.account.plan.update' | 'admin.account.ref.update' | 'admin.account.billing.update' | 'admin.account.labels.update' | 'admin.deployment.delete' | 'admin.domain.delete' | 'admin.billing.sync' | 'admin.billing.terminated' | 'admin.impersonate' | 'billing.active' | 'billing.canceled' | 'billing.paused' | 'billing.expired' | 'billing.paid' | 'billing.trialing' | 'billing.scheduled_cancel' | 'billing.unpaid' | 'billing.update' | 'billing.past_due' | 'refund.created' | 'dispute.created' | 'billing.sync' | 'billing.stale' | 'billing.race';
|
|
852
1275
|
/**
|
|
853
1276
|
* Activity events visible to users in the dashboard
|
|
854
1277
|
*/
|
|
855
|
-
type UserVisibleActivityEvent = 'account.create' | 'account.update' | 'account.delete' | 'account.key.generate' | 'account.plan.transition' | 'deployment.create' | 'deployment.update' | 'deployment.delete' | 'deployment.claim' | 'domain.create' | 'domain.update' | 'domain.delete' | 'domain.verify' | 'token.create' | 'token.consume';
|
|
1278
|
+
type UserVisibleActivityEvent = 'account.create' | 'account.update' | 'account.delete' | 'account.key.generate' | 'account.plan.transition' | 'deployment.create' | 'deployment.update' | 'deployment.delete' | 'deployment.claim' | 'domain.create' | 'domain.update' | 'domain.delete' | 'domain.verify' | 'token.create' | 'token.consume' | 'token.delete';
|
|
856
1279
|
/**
|
|
857
1280
|
* Activity record returned from the API
|
|
858
1281
|
*/
|
|
@@ -871,6 +1294,12 @@ interface Activity {
|
|
|
871
1294
|
/**
|
|
872
1295
|
* Parsed activity metadata.
|
|
873
1296
|
* Different events populate different fields.
|
|
1297
|
+
*
|
|
1298
|
+
* Naming convention: meta booleans are event-scoped predicates and carry
|
|
1299
|
+
* their prefix (`isUpdate`, `wasVerified`, `hasConfig`, `hasPassword`),
|
|
1300
|
+
* while entity booleans are bare nouns (`Deployment.config`,
|
|
1301
|
+
* `Deployment.password`). Two vocabularies, each internally consistent —
|
|
1302
|
+
* deliberate, not drift.
|
|
874
1303
|
*/
|
|
875
1304
|
interface ActivityMeta {
|
|
876
1305
|
/** Number of files in deployment */
|
|
@@ -905,7 +1334,7 @@ interface ActivityMeta {
|
|
|
905
1334
|
/**
|
|
906
1335
|
* Response from GET /activities endpoint
|
|
907
1336
|
*/
|
|
908
|
-
interface ActivityListResponse {
|
|
1337
|
+
interface ActivityListResponse extends ListResponse {
|
|
909
1338
|
/** Array of activities */
|
|
910
1339
|
activities: Activity[];
|
|
911
1340
|
}
|
|
@@ -924,7 +1353,7 @@ declare const FileValidationStatus: {
|
|
|
924
1353
|
/** File passed validation and is ready for deployment */
|
|
925
1354
|
readonly READY: "ready";
|
|
926
1355
|
};
|
|
927
|
-
type FileValidationStatusType = typeof FileValidationStatus[keyof typeof FileValidationStatus];
|
|
1356
|
+
type FileValidationStatusType = (typeof FileValidationStatus)[keyof typeof FileValidationStatus];
|
|
928
1357
|
/**
|
|
929
1358
|
* A validation issue with a display-ready message
|
|
930
1359
|
*
|
|
@@ -1109,20 +1538,17 @@ declare function validatePassword(value: unknown): string | undefined;
|
|
|
1109
1538
|
* Extends the API contract (DeploymentUploadOptions) with SDK-specific options.
|
|
1110
1539
|
*/
|
|
1111
1540
|
interface DeploymentOptions extends DeploymentUploadOptions {
|
|
1112
|
-
/**
|
|
1541
|
+
/**
|
|
1542
|
+
* An AbortSignal to allow cancellation of the deploy operation. The one
|
|
1543
|
+
* cancellation mechanism — abort the signal and the request rejects with
|
|
1544
|
+
* a typed `Cancelled` error. Request timeouts are a client concern
|
|
1545
|
+
* (`ShipClientOptions.timeout`), not a per-deploy one.
|
|
1546
|
+
*/
|
|
1113
1547
|
signal?: AbortSignal;
|
|
1114
|
-
/** Callback invoked if the deploy is cancelled via the AbortSignal. */
|
|
1115
|
-
onCancel?: () => void;
|
|
1116
|
-
/** Maximum number of concurrent operations. */
|
|
1117
|
-
maxConcurrency?: number;
|
|
1118
|
-
/** Timeout in milliseconds for the deploy request. */
|
|
1119
|
-
timeout?: number;
|
|
1120
1548
|
/** Whether to auto-detect and optimize file paths by flattening common directories. Defaults to true. */
|
|
1121
1549
|
pathDetect?: boolean;
|
|
1122
1550
|
/** Whether to auto-detect SPAs and generate ship.json configuration. Defaults to true. */
|
|
1123
1551
|
spaDetect?: boolean;
|
|
1124
|
-
/** Callback for deploy progress with detailed statistics. */
|
|
1125
|
-
onProgress?: (info: ProgressInfo) => void;
|
|
1126
1552
|
}
|
|
1127
1553
|
type ApiDeployOptions = Omit<DeploymentOptions, 'pathDetect'>;
|
|
1128
1554
|
/**
|
|
@@ -1177,7 +1603,7 @@ type Fetch = typeof fetch;
|
|
|
1177
1603
|
type TokenProvider = () => string | Promise<string>;
|
|
1178
1604
|
/**
|
|
1179
1605
|
* Options for configuring a `Ship` instance.
|
|
1180
|
-
* Sets
|
|
1606
|
+
* Sets the API host, the client credential, the request timeout, and the transport.
|
|
1181
1607
|
*/
|
|
1182
1608
|
interface ShipClientOptions {
|
|
1183
1609
|
/** Default API URL for the client instance. */
|
|
@@ -1198,19 +1624,8 @@ interface ShipClientOptions {
|
|
|
1198
1624
|
*/
|
|
1199
1625
|
token?: string | TokenProvider | undefined;
|
|
1200
1626
|
/**
|
|
1201
|
-
*
|
|
1202
|
-
*
|
|
1203
|
-
*/
|
|
1204
|
-
onProgress?: ((info: ProgressInfo) => void) | undefined;
|
|
1205
|
-
/**
|
|
1206
|
-
* Default for maximum concurrent deploys.
|
|
1207
|
-
* Used if an deploy operation doesn't specify its own `maxConcurrency`.
|
|
1208
|
-
* Defaults to 4 if not set here or in the specific deploy call.
|
|
1209
|
-
*/
|
|
1210
|
-
maxConcurrency?: number | undefined;
|
|
1211
|
-
/**
|
|
1212
|
-
* Default timeout in milliseconds for API requests made by this client instance.
|
|
1213
|
-
* Used if an deploy operation doesn't specify its own timeout.
|
|
1627
|
+
* Timeout in milliseconds for every API request made by this client
|
|
1628
|
+
* instance. Defaults to 30 seconds.
|
|
1214
1629
|
*/
|
|
1215
1630
|
timeout?: number | undefined;
|
|
1216
1631
|
/**
|
|
@@ -1277,7 +1692,19 @@ interface ShipEvents {
|
|
|
1277
1692
|
request: [url: string, init: RequestInit];
|
|
1278
1693
|
/** Emitted after successful API response */
|
|
1279
1694
|
response: [response: Response, url: string];
|
|
1280
|
-
/**
|
|
1695
|
+
/**
|
|
1696
|
+
* Emitted when something fails. TWO populations arrive here, which is why
|
|
1697
|
+
* the type is `Error` and not `ShipError`:
|
|
1698
|
+
*
|
|
1699
|
+
* - a failed request — always a `ShipError` (`executeRequest` normalizes
|
|
1700
|
+
* every failure through `ShipError.fromFetchError` before emitting), so
|
|
1701
|
+
* `isShipError(error)` narrows and `.type` / `.status` are readable;
|
|
1702
|
+
* - a THROWING HANDLER of yours — `SimpleEvents.emit` evicts it and
|
|
1703
|
+
* re-emits the raw failure here, which is a plain `Error`.
|
|
1704
|
+
*
|
|
1705
|
+
* Narrowing this to `ShipError` was tried on 2026-07-27 and reverted: it
|
|
1706
|
+
* made the second population a lie.
|
|
1707
|
+
*/
|
|
1281
1708
|
error: [error: Error, url: string];
|
|
1282
1709
|
}
|
|
1283
1710
|
|
|
@@ -1325,6 +1752,8 @@ declare class ApiHttp extends SimpleEvents {
|
|
|
1325
1752
|
private readonly session;
|
|
1326
1753
|
private readonly caller;
|
|
1327
1754
|
private readonly timeout;
|
|
1755
|
+
private readonly deployTimeout;
|
|
1756
|
+
private readonly deployBuildTimeout;
|
|
1328
1757
|
private readonly fetch;
|
|
1329
1758
|
private readonly createDeployBody;
|
|
1330
1759
|
private readonly deployEndpoint;
|
|
@@ -1352,31 +1781,27 @@ declare class ApiHttp extends SimpleEvents {
|
|
|
1352
1781
|
private safeClone;
|
|
1353
1782
|
private parseResponse;
|
|
1354
1783
|
deploy(files: StaticFile[], options?: ApiDeployOptions): Promise<DeploymentCreateResponse>;
|
|
1355
|
-
listDeployments(): Promise<DeploymentListResponse>;
|
|
1784
|
+
listDeployments(options?: ListOptions): Promise<DeploymentListResponse>;
|
|
1356
1785
|
getDeployment(id: string): Promise<Deployment>;
|
|
1357
1786
|
updateDeploymentLabels(id: string, labels: string[]): Promise<Deployment>;
|
|
1358
|
-
|
|
1787
|
+
deleteDeployment(id: string): Promise<DeploymentDeleteResponse>;
|
|
1359
1788
|
setDomain(name: string, deployment?: string, labels?: string[]): Promise<DomainSetResult>;
|
|
1360
|
-
listDomains(): Promise<DomainListResponse>;
|
|
1789
|
+
listDomains(options?: ListOptions): Promise<DomainListResponse>;
|
|
1361
1790
|
getDomain(name: string): Promise<Domain>;
|
|
1362
|
-
|
|
1363
|
-
verifyDomain(name: string): Promise<
|
|
1364
|
-
message: string;
|
|
1365
|
-
}>;
|
|
1791
|
+
deleteDomain(name: string): Promise<DomainDeleteResponse>;
|
|
1792
|
+
verifyDomain(name: string): Promise<DomainVerifyResponse>;
|
|
1366
1793
|
getDomainDns(name: string): Promise<DomainDnsResponse>;
|
|
1367
1794
|
getDomainRecords(name: string): Promise<DomainRecordsResponse>;
|
|
1368
|
-
getDomainShare(name: string): Promise<
|
|
1369
|
-
domain: string;
|
|
1370
|
-
hash: string;
|
|
1371
|
-
}>;
|
|
1795
|
+
getDomainShare(name: string): Promise<DomainShareResponse>;
|
|
1372
1796
|
validateDomain(name: string): Promise<DomainValidateResponse>;
|
|
1373
1797
|
createToken(ttl?: number, labels?: string[]): Promise<TokenCreateResponse>;
|
|
1374
|
-
listTokens(): Promise<TokenListResponse>;
|
|
1375
|
-
|
|
1798
|
+
listTokens(options?: ListOptions): Promise<TokenListResponse>;
|
|
1799
|
+
deleteToken(token: string): Promise<TokenDeleteResponse>;
|
|
1800
|
+
getToken(token: string): Promise<Token>;
|
|
1376
1801
|
getAccount(): Promise<AccountGetResponse>;
|
|
1377
1802
|
getLimits(): Promise<PlatformLimits>;
|
|
1378
|
-
ping(): Promise<
|
|
1379
|
-
checkSPA(files: StaticFile[],
|
|
1803
|
+
ping(): Promise<PingResponse>;
|
|
1804
|
+
checkSPA(files: StaticFile[], _options?: ApiDeployOptions): Promise<boolean>;
|
|
1380
1805
|
}
|
|
1381
1806
|
|
|
1382
1807
|
/**
|
|
@@ -1395,7 +1820,6 @@ interface ResourceContext {
|
|
|
1395
1820
|
*/
|
|
1396
1821
|
interface DeploymentResourceContext extends ResourceContext {
|
|
1397
1822
|
processInput: (input: DeployInput, options: DeploymentOptions) => Promise<StaticFile[]>;
|
|
1398
|
-
clientDefaults?: ShipClientOptions;
|
|
1399
1823
|
}
|
|
1400
1824
|
/**
|
|
1401
1825
|
* Upload deployment resource with all CRUD operations.
|
|
@@ -1405,7 +1829,7 @@ interface DeploymentResourceContext extends ResourceContext {
|
|
|
1405
1829
|
* public-account agent identity per request (claim URL + expiry on the
|
|
1406
1830
|
* response). The SDK stays a transparent pipe either way.
|
|
1407
1831
|
*/
|
|
1408
|
-
declare function createDeploymentResource(ctx: DeploymentResourceContext): DeploymentResource
|
|
1832
|
+
declare function createDeploymentResource(ctx: DeploymentResourceContext): DeploymentResource<DeploymentOptions>;
|
|
1409
1833
|
/**
|
|
1410
1834
|
* Create domain resource with all CRUD operations.
|
|
1411
1835
|
*
|
|
@@ -1427,7 +1851,7 @@ declare function createTokenResource(ctx: ResourceContext): TokenResource;
|
|
|
1427
1851
|
* Abstract base class for Ship SDK implementations.
|
|
1428
1852
|
*/
|
|
1429
1853
|
declare abstract class Ship$1 {
|
|
1430
|
-
readonly deployments: DeploymentResource
|
|
1854
|
+
readonly deployments: DeploymentResource<DeploymentOptions>;
|
|
1431
1855
|
readonly domains: DomainResource;
|
|
1432
1856
|
readonly account: AccountResource;
|
|
1433
1857
|
readonly tokens: TokenResource;
|
|
@@ -1446,13 +1870,20 @@ declare abstract class Ship$1 {
|
|
|
1446
1870
|
protected ensureInitialized(): Promise<void>;
|
|
1447
1871
|
private fetchPlatformLimits;
|
|
1448
1872
|
/**
|
|
1449
|
-
* Ping the API server
|
|
1873
|
+
* Ping the API server, resolving its answer: `{ success, timestamp }`, where
|
|
1874
|
+
* `timestamp` is the server clock in unix SECONDS.
|
|
1875
|
+
*
|
|
1876
|
+
* It resolves the response rather than a bare `true` because every other
|
|
1877
|
+
* method here does — narrowing to a boolean discarded the one thing ping
|
|
1878
|
+
* carries beyond liveness, and made `success` mean a boolean on the wire and
|
|
1879
|
+
* something else by the time it reached a caller. A non-OK response throws in
|
|
1880
|
+
* transport, so a resolved value always means the API answered.
|
|
1450
1881
|
*/
|
|
1451
|
-
ping(): Promise<
|
|
1882
|
+
ping(): Promise<PingResponse>;
|
|
1452
1883
|
/**
|
|
1453
1884
|
* Deploy project (convenience shortcut to `ship.deployments.upload()`).
|
|
1454
1885
|
*/
|
|
1455
|
-
deploy(input: DeployInput, options?: DeploymentOptions): Promise<
|
|
1886
|
+
deploy(input: DeployInput, options?: DeploymentOptions): Promise<DeploymentCreateResponse>;
|
|
1456
1887
|
/**
|
|
1457
1888
|
* Get current account information (convenience shortcut to `ship.account.get()`).
|
|
1458
1889
|
*/
|
|
@@ -1494,115 +1925,6 @@ declare abstract class Ship$1 {
|
|
|
1494
1925
|
private getAuthHeaders;
|
|
1495
1926
|
}
|
|
1496
1927
|
|
|
1497
|
-
/**
|
|
1498
|
-
* @file Cross-platform configuration helpers.
|
|
1499
|
-
*
|
|
1500
|
-
* One pure helper used by the deployment resource:
|
|
1501
|
-
*
|
|
1502
|
-
* - `mergeDeployOptions(perCallOptions, clientDefaults)` — overlays
|
|
1503
|
-
* instance-level defaults under per-call overrides for a single deploy.
|
|
1504
|
-
*
|
|
1505
|
-
* Deploy options are pure deploy concerns (progress, timeout, concurrency).
|
|
1506
|
-
* Credentials, the API URL, and the caller identifier are client identity —
|
|
1507
|
-
* they live on the instance, never per call: one client is one principal
|
|
1508
|
-
* speaking for one end user against one API. Callers that need a different
|
|
1509
|
-
* identity construct another Ship.
|
|
1510
|
-
*/
|
|
1511
|
-
|
|
1512
|
-
/**
|
|
1513
|
-
* Overlay client-level defaults under per-call deploy options.
|
|
1514
|
-
*
|
|
1515
|
-
* Per-call options always win — they're the explicit override for a single
|
|
1516
|
-
* `deployments.upload()`. Defaults fill in only when the per-call option is
|
|
1517
|
-
* `undefined` (an explicit `null` / empty value passes through).
|
|
1518
|
-
*/
|
|
1519
|
-
declare function mergeDeployOptions(options: DeploymentOptions, clientDefaults: ShipClientOptions): DeploymentOptions;
|
|
1520
|
-
|
|
1521
|
-
interface MD5Result {
|
|
1522
|
-
md5: string;
|
|
1523
|
-
}
|
|
1524
|
-
declare function calculateMD5(input: Blob | Buffer | string): Promise<MD5Result>;
|
|
1525
|
-
|
|
1526
|
-
/**
|
|
1527
|
-
* Utility functions for string manipulation.
|
|
1528
|
-
*/
|
|
1529
|
-
/**
|
|
1530
|
-
* Simple utility to pluralize a word based on a count.
|
|
1531
|
-
* @param count The number to determine pluralization.
|
|
1532
|
-
* @param singular The singular form of the word.
|
|
1533
|
-
* @param plural The plural form of the word.
|
|
1534
|
-
* @param includeCount Whether to include the count in the returned string. Defaults to true.
|
|
1535
|
-
* @returns A string with the count and the correctly pluralized word.
|
|
1536
|
-
*/
|
|
1537
|
-
declare function pluralize(count: number, singular: string, plural: string, includeCount?: boolean): string;
|
|
1538
|
-
|
|
1539
|
-
/**
|
|
1540
|
-
* List of directory names considered as junk
|
|
1541
|
-
*
|
|
1542
|
-
* Files within these directories (at any level in the path hierarchy) will be excluded.
|
|
1543
|
-
* The comparison is case-insensitive for cross-platform compatibility.
|
|
1544
|
-
*
|
|
1545
|
-
* @internal
|
|
1546
|
-
*/
|
|
1547
|
-
declare const JUNK_DIRECTORIES: readonly ["__MACOSX", ".Trashes", ".fseventsd", ".Spotlight-V100"];
|
|
1548
|
-
/**
|
|
1549
|
-
* Filters an array of file paths, removing those considered junk
|
|
1550
|
-
*
|
|
1551
|
-
* Throws if any path contains an unbuilt project marker (e.g. `node_modules`, `package.json`).
|
|
1552
|
-
* This check runs first because the dot-file filter below would strip paths like
|
|
1553
|
-
* `node_modules/.pnpm/...`, destroying the evidence.
|
|
1554
|
-
*
|
|
1555
|
-
* A path is filtered out if any of these conditions are met:
|
|
1556
|
-
* 1. The basename is identified as junk by the 'junk' package (e.g., .DS_Store, Thumbs.db)
|
|
1557
|
-
* 2. Any path segment starts with a dot (e.g., .env, .git, .htaccess)
|
|
1558
|
-
* Exception: `.well-known` is allowed (RFC 8615 — ACME, security.txt, app links)
|
|
1559
|
-
* 3. Any path segment exceeds 255 characters (filesystem limit)
|
|
1560
|
-
* 4. Any directory segment in the path matches an entry in JUNK_DIRECTORIES (case-insensitive)
|
|
1561
|
-
*
|
|
1562
|
-
* All path separators are normalized to forward slashes for consistent cross-platform behavior.
|
|
1563
|
-
*
|
|
1564
|
-
* Dot files are filtered for security — they typically contain sensitive configuration
|
|
1565
|
-
* (.env, .git) or are not meant to be served publicly. This matches server-side filtering.
|
|
1566
|
-
*
|
|
1567
|
-
* @param filePaths - An array of file path strings to filter
|
|
1568
|
-
* @param options - Optional settings
|
|
1569
|
-
* @param options.allowUnbuilt - When true, skip the unbuilt project marker check (for server-processed uploads)
|
|
1570
|
-
* @returns A new array containing only non-junk file paths
|
|
1571
|
-
* @throws {ShipError} If any path contains an unbuilt project marker (unless allowUnbuilt is true)
|
|
1572
|
-
*
|
|
1573
|
-
* @example
|
|
1574
|
-
* ```typescript
|
|
1575
|
-
* import { filterJunk } from '@shipstatic/ship';
|
|
1576
|
-
*
|
|
1577
|
-
* // Filter an array of file paths
|
|
1578
|
-
* const paths = ['index.html', '.DS_Store', '.gitattributes', '__MACOSX/file.txt', 'app.js'];
|
|
1579
|
-
* const clean = filterJunk(paths);
|
|
1580
|
-
* // Result: ['index.html', 'app.js']
|
|
1581
|
-
* ```
|
|
1582
|
-
*
|
|
1583
|
-
* @example
|
|
1584
|
-
* ```typescript
|
|
1585
|
-
* // Use with browser File objects
|
|
1586
|
-
* import { filterJunk } from '@shipstatic/ship';
|
|
1587
|
-
*
|
|
1588
|
-
* const files: File[] = [...]; // From input or drag-drop
|
|
1589
|
-
*
|
|
1590
|
-
* // Extract paths from File objects
|
|
1591
|
-
* const filePaths = files.map(f => f.webkitRelativePath || f.name);
|
|
1592
|
-
*
|
|
1593
|
-
* // Filter out junk paths
|
|
1594
|
-
* const validPaths = new Set(filterJunk(filePaths));
|
|
1595
|
-
*
|
|
1596
|
-
* // Filter the original File array
|
|
1597
|
-
* const validFiles = files.filter(f =>
|
|
1598
|
-
* validPaths.has(f.webkitRelativePath || f.name)
|
|
1599
|
-
* );
|
|
1600
|
-
* ```
|
|
1601
|
-
*/
|
|
1602
|
-
declare function filterJunk(filePaths: string[], options?: {
|
|
1603
|
-
allowUnbuilt?: boolean;
|
|
1604
|
-
}): string[];
|
|
1605
|
-
|
|
1606
1928
|
/**
|
|
1607
1929
|
* @file Deploy path optimization - the core logic that makes Ship deployments clean and intuitive.
|
|
1608
1930
|
* Automatically strips common parent directories to create clean deployment URLs.
|
|
@@ -1727,6 +2049,85 @@ declare function getValidFiles<T extends ValidatableFile>(files: T[]): T[];
|
|
|
1727
2049
|
*/
|
|
1728
2050
|
declare function allValidFilesReady<T extends ValidatableFile>(files: T[]): boolean;
|
|
1729
2051
|
|
|
2052
|
+
/**
|
|
2053
|
+
* @file Utility for filtering out junk files and directories from file paths
|
|
2054
|
+
*
|
|
2055
|
+
* This module provides functionality to filter out common system junk files and directories
|
|
2056
|
+
* from a list of file paths. It uses the 'junk' package to identify junk filenames and
|
|
2057
|
+
* a custom list to filter out common junk directories.
|
|
2058
|
+
*/
|
|
2059
|
+
/**
|
|
2060
|
+
* List of directory names considered as junk
|
|
2061
|
+
*
|
|
2062
|
+
* Files within these directories (at any level in the path hierarchy) will be excluded.
|
|
2063
|
+
* The comparison is case-insensitive for cross-platform compatibility.
|
|
2064
|
+
*
|
|
2065
|
+
* @internal
|
|
2066
|
+
*/
|
|
2067
|
+
declare const JUNK_DIRECTORIES: readonly ["__MACOSX", ".Trashes", ".fseventsd", ".Spotlight-V100"];
|
|
2068
|
+
/**
|
|
2069
|
+
* Filters an array of file paths, removing those considered junk
|
|
2070
|
+
*
|
|
2071
|
+
* Throws if any path contains an unbuilt project marker (e.g. `node_modules`, `package.json`).
|
|
2072
|
+
* This check runs first because the dot-file filter below would strip paths like
|
|
2073
|
+
* `node_modules/.pnpm/...`, destroying the evidence.
|
|
2074
|
+
*
|
|
2075
|
+
* A path is filtered out if any of these conditions are met:
|
|
2076
|
+
* 1. The basename is identified as junk by the 'junk' package (e.g., .DS_Store, Thumbs.db)
|
|
2077
|
+
* 2. Any path segment starts with a dot (e.g., .env, .git, .htaccess)
|
|
2078
|
+
* Exception: `.well-known` is allowed (RFC 8615 — ACME, security.txt, app links)
|
|
2079
|
+
* 3. Any path segment exceeds 255 characters (filesystem limit)
|
|
2080
|
+
* 4. Any directory segment in the path matches an entry in JUNK_DIRECTORIES (case-insensitive)
|
|
2081
|
+
*
|
|
2082
|
+
* All path separators are normalized to forward slashes for consistent cross-platform behavior.
|
|
2083
|
+
*
|
|
2084
|
+
* Dot files are filtered for security — they typically contain sensitive configuration
|
|
2085
|
+
* (.env, .git) or are not meant to be served publicly. This matches server-side filtering.
|
|
2086
|
+
*
|
|
2087
|
+
* @param filePaths - An array of file path strings to filter
|
|
2088
|
+
* @param options - Optional settings
|
|
2089
|
+
* @param options.allowUnbuilt - When true, skip the unbuilt project marker check (for server-processed uploads)
|
|
2090
|
+
* @returns A new array containing only non-junk file paths
|
|
2091
|
+
* @throws {ShipError} If any path contains an unbuilt project marker (unless allowUnbuilt is true)
|
|
2092
|
+
*
|
|
2093
|
+
* @example
|
|
2094
|
+
* ```typescript
|
|
2095
|
+
* import { filterJunk } from '@shipstatic/ship';
|
|
2096
|
+
*
|
|
2097
|
+
* // Filter an array of file paths
|
|
2098
|
+
* const paths = ['index.html', '.DS_Store', '.gitattributes', '__MACOSX/file.txt', 'app.js'];
|
|
2099
|
+
* const clean = filterJunk(paths);
|
|
2100
|
+
* // Result: ['index.html', 'app.js']
|
|
2101
|
+
* ```
|
|
2102
|
+
*
|
|
2103
|
+
* @example
|
|
2104
|
+
* ```typescript
|
|
2105
|
+
* // Use with browser File objects
|
|
2106
|
+
* import { filterJunk } from '@shipstatic/ship';
|
|
2107
|
+
*
|
|
2108
|
+
* const files: File[] = [...]; // From input or drag-drop
|
|
2109
|
+
*
|
|
2110
|
+
* // Extract paths from File objects
|
|
2111
|
+
* const filePaths = files.map(f => f.webkitRelativePath || f.name);
|
|
2112
|
+
*
|
|
2113
|
+
* // Filter out junk paths
|
|
2114
|
+
* const validPaths = new Set(filterJunk(filePaths));
|
|
2115
|
+
*
|
|
2116
|
+
* // Filter the original File array
|
|
2117
|
+
* const validFiles = files.filter(f =>
|
|
2118
|
+
* validPaths.has(f.webkitRelativePath || f.name)
|
|
2119
|
+
* );
|
|
2120
|
+
* ```
|
|
2121
|
+
*/
|
|
2122
|
+
declare function filterJunk(filePaths: string[], options?: {
|
|
2123
|
+
allowUnbuilt?: boolean;
|
|
2124
|
+
}): string[];
|
|
2125
|
+
|
|
2126
|
+
interface MD5Result {
|
|
2127
|
+
md5: string;
|
|
2128
|
+
}
|
|
2129
|
+
declare function calculateMD5(input: Blob | Buffer | string): Promise<MD5Result>;
|
|
2130
|
+
|
|
1730
2131
|
/**
|
|
1731
2132
|
* Validate a deploy path for security concerns.
|
|
1732
2133
|
* Rejects paths containing path traversal patterns or null bytes.
|
|
@@ -1755,6 +2156,24 @@ declare function validateDeployPath(deployPath: string, sourceIdentifier: string
|
|
|
1755
2156
|
*/
|
|
1756
2157
|
declare function validateDeployFile(deployPath: string, sourceIdentifier: string): void;
|
|
1757
2158
|
|
|
2159
|
+
/**
|
|
2160
|
+
* Utility functions for string manipulation.
|
|
2161
|
+
*/
|
|
2162
|
+
/**
|
|
2163
|
+
* Simple utility to pluralize a word based on a count.
|
|
2164
|
+
* @param count The number to determine pluralization.
|
|
2165
|
+
* @param singular The singular form of the word.
|
|
2166
|
+
* @param plural The plural form of the word.
|
|
2167
|
+
* @param includeCount Whether to include the count in the returned string. Defaults to true.
|
|
2168
|
+
* @returns A string with the count and the correctly pluralized word.
|
|
2169
|
+
*/
|
|
2170
|
+
declare function pluralize(count: number, singular: string, plural: string, includeCount?: boolean): string;
|
|
2171
|
+
|
|
2172
|
+
/**
|
|
2173
|
+
* @file Node.js-specific file utilities for the Ship SDK.
|
|
2174
|
+
* Provides helpers for recursively discovering, filtering, and preparing files for deploy in Node.js.
|
|
2175
|
+
*/
|
|
2176
|
+
|
|
1758
2177
|
/**
|
|
1759
2178
|
* Processes Node.js file and directory paths into an array of StaticFile objects ready for deploy.
|
|
1760
2179
|
* Computes content paths relative to the upload root before filtering, so only the deployed
|
|
@@ -1763,7 +2182,7 @@ declare function validateDeployFile(deployPath: string, sourceIdentifier: string
|
|
|
1763
2182
|
* @param paths - File or directory paths to scan and process.
|
|
1764
2183
|
* @param options - Processing options (pathDetect, etc.).
|
|
1765
2184
|
* @param platformLimits - Per-instance platform limits (file-size / count /
|
|
1766
|
-
* total-size caps) from the originating Ship's `GET /
|
|
2185
|
+
* total-size caps) from the originating Ship's `GET /limits` fetch. Passed
|
|
1767
2186
|
* in rather than read from a module global so concurrent Ships against
|
|
1768
2187
|
* different API URLs cannot clobber each other's caps.
|
|
1769
2188
|
* @returns Promise resolving to an array of StaticFile objects.
|
|
@@ -1815,9 +2234,9 @@ declare class Ship extends Ship$1 {
|
|
|
1815
2234
|
* intentional: the convenience shortcut narrows; the resource-layer
|
|
1816
2235
|
* contract stays platform-neutral.
|
|
1817
2236
|
*/
|
|
1818
|
-
deploy(input: string | string[], options?: DeploymentOptions): Promise<
|
|
2237
|
+
deploy(input: string | string[], options?: DeploymentOptions): Promise<DeploymentCreateResponse>;
|
|
1819
2238
|
protected processInput(input: DeployInput, options: DeploymentOptions): Promise<StaticFile[]>;
|
|
1820
2239
|
protected getDeployBodyCreator(): DeployBodyCreator;
|
|
1821
2240
|
}
|
|
1822
2241
|
|
|
1823
|
-
export { API_KEY, type Account, type AccountGetResponse, type AccountOverrides, AccountPlan, type AccountPlanType, type AccountResource, type AccountUsage, type Activity, type ActivityEvent, type ActivityListResponse, type ActivityMeta, type ApiDeployOptions, ApiHttp, type ApiHttpOptions, AuthMethod, type AuthMethodType, BLOCKED_EXTENSIONS, type BillingStatus, CALLER, type CheckoutSession, DEFAULT_API, DEPLOYMENT_CONFIG_FILENAME, DEPLOY_TOKEN, type DeployBody, type DeployBodyContext, type DeployBodyCreator, type DeployFile, type DeployInput, type Deployment, type DeploymentCreateResponse, type DeploymentListResponse, type DeploymentOptions, type DeploymentResource, type DeploymentResourceContext, DeploymentStatus, type DeploymentStatusType, type DeploymentUploadOptions, type DnsProvider, type DnsRecord, type DnsRecordType, type Domain, type DomainDnsResponse, type DomainListResponse, type DomainRecordsResponse, type DomainResource, type DomainSetResult, DomainStatus, type DomainStatusType, type DomainValidateResponse, type ErrorResponse, ErrorType, type ExecutionEnvironment, FileValidationStatus as FILE_VALIDATION_STATUS, type Fetch, type FileValidationResult, FileValidationStatus, type FileValidationStatusType, JUNK_DIRECTORIES, LABEL_CONSTRAINTS, LABEL_PATTERN, type MD5Result, OAuthScope, type OAuthScopeType, PASSWORD_CONSTRAINTS, type PingResponse, type PlatformLimits, type
|
|
2242
|
+
export { API_KEY, API_PATHS, AUTH_BASE_PATH, type Account, type AccountDeleteResponse, type AccountGetResponse, type AccountKeyResponse, type AccountOverrides, AccountPlan, type AccountPlanType, type AccountResource, type AccountUsage, type Activity, type ActivityEvent, type ActivityListResponse, type ActivityMeta, type ApiDeployOptions, ApiHttp, type ApiHttpOptions, AuthMethod, type AuthMethodType, BLOCKED_EXTENSIONS, type BillingCancelResponse, type BillingStatus, CALLER, type CheckoutSession, DEFAULT_API, DEPLOYMENT_CONFIG_FILENAME, DEPLOY_TOKEN, type DeployBody, type DeployBodyContext, type DeployBodyCreator, type DeployFile, type DeployInput, type Deployment, type DeploymentCreateResponse, type DeploymentDeleteResponse, type DeploymentListResponse, type DeploymentOptions, type DeploymentResource, type DeploymentResourceContext, type DeploymentSetOptions, DeploymentStatus, type DeploymentStatusType, type DeploymentUploadOptions, type DnsLookup, type DnsProvider, type DnsRecord, type DnsRecordType, type Domain, type DomainDeleteResponse, type DomainDnsResponse, type DomainListResponse, type DomainRecordsResponse, type DomainResource, type DomainSetOptions, type DomainSetResult, type DomainShareResponse, DomainStatus, type DomainStatusType, type DomainValidateResponse, type DomainVerifyResponse, type ErrorResponse, ErrorType, type ExecutionEnvironment, FileValidationStatus as FILE_VALIDATION_STATUS, type Fetch, type FileValidationResult, FileValidationStatus, type FileValidationStatusType, IDEMPOTENCY_KEY_CONSTRAINTS, JUNK_DIRECTORIES, LABEL_CONSTRAINTS, LABEL_PATTERN, type LabelsResponse, type ListOptions, type ListResponse, type MD5Result, OAuthScope, type OAuthScopeType, PASSWORD_CONSTRAINTS, type PingResponse, type PlatformLimits, type ResourceContext, type SPACheckDebug, type SPACheckRequest, type SPACheckResponse, SPA_DEFAULT_CONFIG, type SetupInstructionsResponse, Ship, type ShipClientOptions, ShipError, type ShipEvents, type StaticFile, type Token, type TokenCreateOptions, type TokenCreateResponse, type TokenDeleteResponse, TokenKind, type TokenKindType, type TokenListResponse, type TokenProvider, type TokenResource, UNBUILT_PROJECT_MARKERS, UNSAFE_FILENAME_CHARS, type UploadedFile, type UserVisibleActivityEvent, type ValidatableFile, type ValidationIssue, __setTestEnvironment, allValidFilesReady, assertShipJsonSyntax, calculateMD5, classifyToken, createAccountResource, createDeploymentResource, createDomainResource, createTokenResource, Ship as default, deserializeLabels, extractSubdomain, filterJunk, formatFileSize, generateDeploymentUrl, generateDomainUrl, getENV, getValidFiles, hasUnbuiltMarker, hasUnsafeChars, isBlockedExtension, isCustomDomain, isDeployment, isPlatformDomain, isShipError, optimizeDeployPaths, pluralize, processFilesForNode, serializeLabels, validateApiKey, validateApiUrl, validateCaller, validateDeployFile, validateDeployPath, validateDeployToken, validateFileName, validateFiles, validateIdempotencyKey, validatePassword, validateToken };
|