@shipstatic/ship 1.0.2 → 2.0.0-beta.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.
- package/README.md +28 -23
- package/SKILL.md +4 -5
- package/dist/browser.d.ts +1183 -70
- package/dist/browser.js +1 -1
- package/dist/browser.js.map +1 -1
- package/dist/cli.cjs +38 -39
- package/dist/cli.cjs.map +1 -1
- package/dist/completions/ship.bash +1 -1
- package/dist/completions/ship.fish +1 -2
- package/dist/completions/ship.zsh +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1187 -74
- package/dist/index.d.ts +1187 -74
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
package/dist/index.d.cts
CHANGED
|
@@ -1,7 +1,1102 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
/**
|
|
2
|
+
* @file Shared TypeScript types, constants, and utilities for the ShipStatic platform.
|
|
3
|
+
* This package is the single source of truth for all shared data structures.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Deployment status constants
|
|
7
|
+
*/
|
|
8
|
+
declare const DeploymentStatus: {
|
|
9
|
+
readonly PENDING: "pending";
|
|
10
|
+
readonly SUCCESS: "success";
|
|
11
|
+
readonly FAILED: "failed";
|
|
12
|
+
readonly DELETING: "deleting";
|
|
13
|
+
};
|
|
14
|
+
type DeploymentStatusType = typeof DeploymentStatus[keyof typeof DeploymentStatus];
|
|
15
|
+
/**
|
|
16
|
+
* Core deployment object - used in both API responses and SDK
|
|
17
|
+
*/
|
|
18
|
+
interface Deployment {
|
|
19
|
+
/** The deployment hostname (e.g., 'happy-cat-abc1234.shipstatic.com') */
|
|
20
|
+
readonly deployment: string;
|
|
21
|
+
/** Full URL to the deployment (e.g., 'https://happy-cat-abc1234.shipstatic.com') */
|
|
22
|
+
readonly url: string;
|
|
23
|
+
/** Number of files in this deployment */
|
|
24
|
+
readonly files: number;
|
|
25
|
+
/** Total size of all files in bytes */
|
|
26
|
+
readonly size: number;
|
|
27
|
+
/** Current deployment status */
|
|
28
|
+
status: DeploymentStatusType;
|
|
29
|
+
/** Whether deployment has a ship.json config */
|
|
30
|
+
readonly config: boolean;
|
|
31
|
+
/** Whether deployment has a password set */
|
|
32
|
+
readonly password: boolean;
|
|
33
|
+
/** Labels for categorization and filtering (lowercase, alphanumeric with separators). Always present, empty array when none. */
|
|
34
|
+
labels: string[];
|
|
35
|
+
/** The client/tool used to create this deployment (e.g., 'web', 'sdk', 'cli'), null if unknown */
|
|
36
|
+
readonly via: string | null;
|
|
37
|
+
/** Unix timestamp (seconds) when deployment was created */
|
|
38
|
+
readonly created: number;
|
|
39
|
+
/** Unix timestamp (seconds) when deployment expires, null if never */
|
|
40
|
+
expires: number | null;
|
|
41
|
+
/** Full URL to the deployment screenshot (e.g., 'https://screenshots.shipstatic.com/happy-cat-abc1234/a3f2c1b4d5e6f789') */
|
|
42
|
+
readonly screenshot: string;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Response from deployment creation. Extends Deployment with one-time fields
|
|
46
|
+
* only present on creation (not on subsequent GET requests).
|
|
47
|
+
*/
|
|
48
|
+
interface DeploymentCreateResponse extends Deployment {
|
|
49
|
+
/** Claim URL for public deployments. Present when deployed without credentials. */
|
|
50
|
+
readonly claim?: string;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Response for listing deployments
|
|
54
|
+
*/
|
|
55
|
+
interface DeploymentListResponse {
|
|
56
|
+
/** Array of deployments */
|
|
57
|
+
deployments: Deployment[];
|
|
58
|
+
/** Cursor for pagination, null if no more pages */
|
|
59
|
+
cursor: string | null;
|
|
60
|
+
/** Total number of deployments */
|
|
61
|
+
total: number;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Domain status constants
|
|
65
|
+
*
|
|
66
|
+
* - PENDING: DNS not configured
|
|
67
|
+
* - PARTIAL: DNS partially configured
|
|
68
|
+
* - SUCCESS: DNS fully verified
|
|
69
|
+
* - PAUSED: Domain paused due to plan enforcement (billing)
|
|
70
|
+
*/
|
|
71
|
+
declare const DomainStatus: {
|
|
72
|
+
readonly PENDING: "pending";
|
|
73
|
+
readonly PARTIAL: "partial";
|
|
74
|
+
readonly SUCCESS: "success";
|
|
75
|
+
readonly PAUSED: "paused";
|
|
76
|
+
};
|
|
77
|
+
type DomainStatusType = typeof DomainStatus[keyof typeof DomainStatus];
|
|
78
|
+
/**
|
|
79
|
+
* Core domain object - used in both API responses and SDK
|
|
80
|
+
*/
|
|
81
|
+
interface Domain {
|
|
82
|
+
/** The domain name */
|
|
83
|
+
readonly domain: string;
|
|
84
|
+
/** Full URL to the domain (e.g., 'https://www.example.com') */
|
|
85
|
+
readonly url: string;
|
|
86
|
+
/** The deployment hostname this domain points to (null = domain added but not yet linked) */
|
|
87
|
+
deployment: string | null;
|
|
88
|
+
/** Current domain status */
|
|
89
|
+
status: DomainStatusType;
|
|
90
|
+
/** Labels for categorization and filtering (lowercase, alphanumeric with separators). Always present, empty array when none. */
|
|
91
|
+
labels: string[];
|
|
92
|
+
/** Unix timestamp (seconds) when domain was created */
|
|
93
|
+
readonly created: number;
|
|
94
|
+
/** When deployment was last linked (Unix timestamp), null if never linked */
|
|
95
|
+
linked: number | null;
|
|
96
|
+
/** Total deployment links */
|
|
97
|
+
links: number;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Return shape of `domains.set()` — `Domain` plus an SDK-derived flag indicating
|
|
101
|
+
* whether the underlying `PUT /domains/:name` created the record (HTTP 201) or
|
|
102
|
+
* updated an existing one (HTTP 200).
|
|
103
|
+
*
|
|
104
|
+
* `isCreate` is not part of the wire format — the API returns a plain `Domain`
|
|
105
|
+
* body. The SDK derives the flag from the HTTP status code so callers (notably
|
|
106
|
+
* the CLI) can format different output for the create vs repoint paths without
|
|
107
|
+
* a second round-trip.
|
|
108
|
+
*/
|
|
109
|
+
interface DomainSetResult extends Domain {
|
|
110
|
+
/** `true` when this call created a new domain; `false` when it updated an existing one. */
|
|
111
|
+
isCreate: boolean;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Response for listing domains
|
|
115
|
+
*/
|
|
116
|
+
interface DomainListResponse {
|
|
117
|
+
/** Array of domains */
|
|
118
|
+
domains: Domain[];
|
|
119
|
+
/** Cursor for pagination, null if no more pages */
|
|
120
|
+
cursor: string | null;
|
|
121
|
+
/** Total number of domains */
|
|
122
|
+
total: number;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* DNS record types supported for domain configuration
|
|
126
|
+
*/
|
|
127
|
+
type DnsRecordType = 'A' | 'CNAME';
|
|
128
|
+
/**
|
|
129
|
+
* DNS record required for domain configuration
|
|
130
|
+
*/
|
|
131
|
+
interface DnsRecord {
|
|
132
|
+
/** Record type (A for apex, CNAME for subdomains) */
|
|
133
|
+
type: DnsRecordType;
|
|
134
|
+
/** The DNS name to configure */
|
|
135
|
+
name: string;
|
|
136
|
+
/** The value to set (IP for A, hostname for CNAME) */
|
|
137
|
+
value: string;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* DNS provider information for a domain
|
|
141
|
+
*/
|
|
142
|
+
interface DnsProvider {
|
|
143
|
+
/** Provider name (e.g., "Cloudflare", "GoDaddy"), null if unknown */
|
|
144
|
+
name: string | null;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Response for domain DNS provider lookup
|
|
148
|
+
*/
|
|
149
|
+
interface DomainDnsResponse {
|
|
150
|
+
/** The domain name */
|
|
151
|
+
domain: string;
|
|
152
|
+
/** DNS provider information, null if not yet looked up */
|
|
153
|
+
dns: {
|
|
154
|
+
provider?: DnsProvider;
|
|
155
|
+
} | null;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Response for domain DNS records
|
|
159
|
+
*/
|
|
160
|
+
interface DomainRecordsResponse {
|
|
161
|
+
/** The domain name */
|
|
162
|
+
domain: string;
|
|
163
|
+
/** The apex (registered) domain where DNS records are managed */
|
|
164
|
+
apex: string;
|
|
165
|
+
/** Required DNS records for configuration */
|
|
166
|
+
records: DnsRecord[];
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Response for domain validation
|
|
170
|
+
*/
|
|
171
|
+
interface DomainValidateResponse {
|
|
172
|
+
/** Whether the domain is valid */
|
|
173
|
+
valid: boolean;
|
|
174
|
+
/** Normalized domain name, null when invalid */
|
|
175
|
+
normalized: string | null;
|
|
176
|
+
/** Whether the domain is available, null when invalid */
|
|
177
|
+
available: boolean | null;
|
|
178
|
+
/** Error message, null when valid */
|
|
179
|
+
error: string | null;
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Token as returned by the list endpoint.
|
|
183
|
+
* The secret is shown once at creation and never again — listings carry
|
|
184
|
+
* only the management identifier and lifecycle metadata.
|
|
185
|
+
*/
|
|
186
|
+
interface TokenListItem {
|
|
187
|
+
/** 7-char management identifier (e.g., "a1b2c3d") */
|
|
188
|
+
readonly token: string;
|
|
189
|
+
/** Labels for categorization and filtering. Always present, empty array when none. */
|
|
190
|
+
labels: string[];
|
|
191
|
+
/** Unix timestamp (seconds) when token was created */
|
|
192
|
+
readonly created: number;
|
|
193
|
+
/** Unix timestamp (seconds) when token expires, null for never */
|
|
194
|
+
readonly expires: number | null;
|
|
195
|
+
/** Unix timestamp (seconds) of the last request authenticated with this token, null if never used */
|
|
196
|
+
readonly used: number | null;
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Response for listing tokens
|
|
200
|
+
*/
|
|
201
|
+
interface TokenListResponse {
|
|
202
|
+
/** Array of tokens (security-redacted for list display) */
|
|
203
|
+
tokens: TokenListItem[];
|
|
204
|
+
/** Total number of tokens */
|
|
205
|
+
total: number;
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Response for token creation
|
|
209
|
+
*/
|
|
210
|
+
interface TokenCreateResponse {
|
|
211
|
+
/** 7-char management identifier */
|
|
212
|
+
token: string;
|
|
213
|
+
/** The raw credential value (shown once at creation, then never again) */
|
|
214
|
+
secret: string;
|
|
215
|
+
/** Labels for categorization and filtering. Always present, empty array when none. */
|
|
216
|
+
labels: string[];
|
|
217
|
+
/** Unix timestamp (seconds) when token expires, null for never */
|
|
218
|
+
expires: number | null;
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Account plan constants
|
|
222
|
+
*/
|
|
223
|
+
declare const AccountPlan: {
|
|
224
|
+
readonly FREE: "free";
|
|
225
|
+
readonly STANDARD: "standard";
|
|
226
|
+
readonly SPONSORED: "sponsored";
|
|
227
|
+
readonly ENTERPRISE: "enterprise";
|
|
228
|
+
readonly SUSPENDED: "suspended";
|
|
229
|
+
readonly TERMINATING: "terminating";
|
|
230
|
+
readonly TERMINATED: "terminated";
|
|
231
|
+
};
|
|
232
|
+
type AccountPlanType = typeof AccountPlan[keyof typeof AccountPlan];
|
|
233
|
+
/**
|
|
234
|
+
* Account usage metrics — always available regardless of billing provider.
|
|
235
|
+
*/
|
|
236
|
+
interface AccountUsage {
|
|
237
|
+
/** Number of active custom domains (excludes paused) */
|
|
238
|
+
customDomains: number;
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Core account object - used in both API responses and SDK
|
|
242
|
+
* All fields are readonly to prevent accidental mutations
|
|
243
|
+
*/
|
|
244
|
+
interface Account {
|
|
245
|
+
/** User email address */
|
|
246
|
+
readonly email: string;
|
|
247
|
+
/** User display name, null if not set */
|
|
248
|
+
readonly name: string | null;
|
|
249
|
+
/** User profile picture URL, null if not set */
|
|
250
|
+
readonly picture: string | null;
|
|
251
|
+
/** Account plan status */
|
|
252
|
+
readonly plan: AccountPlanType;
|
|
253
|
+
/** Account usage metrics (custom domains, etc.) */
|
|
254
|
+
readonly usage: AccountUsage;
|
|
255
|
+
/** Unix timestamp (seconds) when account was created */
|
|
256
|
+
readonly created: number;
|
|
257
|
+
/** Unix timestamp (seconds) when account was activated (first deployment), null if not yet activated */
|
|
258
|
+
readonly activated: number | null;
|
|
259
|
+
/** Last 4 characters of the API key for identification, null when no key generated */
|
|
260
|
+
readonly hint: string | null;
|
|
261
|
+
/** Grace period expiration (unix seconds), null if no grace period active */
|
|
262
|
+
readonly grace: number | null;
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* Account as returned by `GET /account` — the entity plus how the request
|
|
266
|
+
* was authorized, so `whoami` can answer "what credential am I holding?".
|
|
267
|
+
* Request-scoped fields live on the response type, never on the entity
|
|
268
|
+
* (the `DeploymentCreateResponse` pattern).
|
|
269
|
+
*/
|
|
270
|
+
interface AccountGetResponse extends Account {
|
|
271
|
+
/** How the request that produced this response was authorized. */
|
|
272
|
+
readonly authMethod: AuthMethodType;
|
|
273
|
+
/** Present (and true) only when the caller is an operator acting as themselves. */
|
|
274
|
+
readonly isAdmin?: true;
|
|
275
|
+
/** Present only during read-only admin impersonation: the operator's account id. */
|
|
276
|
+
readonly impersonatedBy?: string;
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* Account-specific configuration overrides
|
|
280
|
+
* Allows per-account customization of limits without changing plan
|
|
281
|
+
*/
|
|
282
|
+
interface AccountOverrides {
|
|
283
|
+
/** Override for maximum number of domains */
|
|
284
|
+
domains?: number;
|
|
285
|
+
/** Override for maximum number of deployments */
|
|
286
|
+
deployments?: number;
|
|
287
|
+
/** Override for maximum individual file size in bytes */
|
|
288
|
+
fileSize?: number;
|
|
289
|
+
/** Override for maximum number of files per deployment */
|
|
290
|
+
filesCount?: number;
|
|
291
|
+
/** Override for maximum total deployment size in bytes */
|
|
292
|
+
totalSize?: number;
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* All possible error types in the ShipStatic platform.
|
|
296
|
+
*
|
|
297
|
+
* Developer-friendly key names map to stable wire-format string values.
|
|
298
|
+
* Both the value and the type are exported under the same name so callers
|
|
299
|
+
* can use `ErrorType.Validation` (value comparison) and `: ErrorType` (type
|
|
300
|
+
* annotation) without ceremony — matching the pattern other status objects
|
|
301
|
+
* (`DeploymentStatus`, `DomainStatus`, `AccountPlan`, `AuthMethod`) follow.
|
|
302
|
+
*/
|
|
303
|
+
declare const ErrorType: {
|
|
304
|
+
/** Validation failed (400). Input shape is wrong. */
|
|
305
|
+
readonly Validation: "validation_failed";
|
|
306
|
+
/** Resource not found (404). */
|
|
307
|
+
readonly NotFound: "not_found";
|
|
308
|
+
/** Authenticated but not allowed (403). User lacks permission for this action. */
|
|
309
|
+
readonly Forbidden: "forbidden";
|
|
310
|
+
/** Rate limit exceeded (429). */
|
|
311
|
+
readonly RateLimit: "rate_limit_exceeded";
|
|
312
|
+
/** Authentication required or failed (401). Missing/invalid credentials. */
|
|
313
|
+
readonly Authentication: "authentication_failed";
|
|
314
|
+
/** Business rule violation. Catch-all for 4xx state-rule errors that aren't more specific. */
|
|
315
|
+
readonly Business: "business_logic_error";
|
|
316
|
+
/** API server error (500). Generic server-side fault. */
|
|
317
|
+
readonly Api: "internal_server_error";
|
|
318
|
+
/** Network/connection error. Client-side only — set by HTTP clients on fetch failure; never produced server-side. */
|
|
319
|
+
readonly Network: "network_error";
|
|
320
|
+
/** Operation was cancelled. Client-side only — set on `AbortSignal` abort; never produced server-side. */
|
|
321
|
+
readonly Cancelled: "operation_cancelled";
|
|
322
|
+
/** File operation error. Client-side only — set by SDK during local file processing; never produced server-side. */
|
|
323
|
+
readonly File: "file_error";
|
|
324
|
+
/** Configuration error. Client-side only — set by SDK during config parsing/validation; never produced server-side. */
|
|
325
|
+
readonly Config: "config_error";
|
|
326
|
+
};
|
|
327
|
+
type ErrorType = typeof ErrorType[keyof typeof ErrorType];
|
|
328
|
+
/**
|
|
329
|
+
* Standard error response format used everywhere
|
|
330
|
+
*/
|
|
331
|
+
interface ErrorResponse {
|
|
332
|
+
/** Error type identifier */
|
|
333
|
+
error: ErrorType;
|
|
334
|
+
/** Human-readable error message */
|
|
335
|
+
message: string;
|
|
336
|
+
/** HTTP status code (API contexts) */
|
|
337
|
+
status?: number;
|
|
338
|
+
/** Optional additional error details. Untyped by design — narrow at the read site. */
|
|
339
|
+
details?: unknown;
|
|
340
|
+
}
|
|
341
|
+
/**
|
|
342
|
+
* Simple unified error class for both API and SDK
|
|
343
|
+
*/
|
|
344
|
+
declare class ShipError extends Error {
|
|
345
|
+
readonly type: ErrorType;
|
|
346
|
+
readonly status?: number | undefined;
|
|
347
|
+
readonly details?: unknown | undefined;
|
|
348
|
+
constructor(type: ErrorType, message: string, status?: number | undefined, details?: unknown | undefined);
|
|
349
|
+
/** Convert to wire format */
|
|
350
|
+
toResponse(): ErrorResponse;
|
|
351
|
+
/**
|
|
352
|
+
* Construct a `ShipError` from an HTTP error response.
|
|
353
|
+
*
|
|
354
|
+
* Best-effort body parse for `{ message, error?, details? }`. Message
|
|
355
|
+
* resolution: `body.message` → `body.error` → `"<operationName> failed with
|
|
356
|
+
* status <N>"`.
|
|
357
|
+
*
|
|
358
|
+
* Type resolution: trusts `body.error` when it's a known server-producible
|
|
359
|
+
* `ErrorType` (preserves the wire's intent — server's
|
|
360
|
+
* `ShipError.validation(...)` round-trips back to `ErrorType.Validation`
|
|
361
|
+
* on the client). Falls back to status-derived (401 → Authentication,
|
|
362
|
+
* 403 → Forbidden, 429 → RateLimit, else → Api) for non-API responses
|
|
363
|
+
* (CDN errors, intermediaries) or malformed bodies. Client-only types
|
|
364
|
+
* (`Network`, `Cancelled`, `File`, `Config`) are filtered out of the
|
|
365
|
+
* trusted set — a misbehaving server claiming one of those is ignored.
|
|
366
|
+
*
|
|
367
|
+
* `operationName` (e.g. `"Get account"`) is used to compose the fallback
|
|
368
|
+
* message. Defaults to `"Request"`. Same convention as `fromFetchError`.
|
|
369
|
+
*
|
|
370
|
+
* Async because it reads the response body. Returns rather than throws so
|
|
371
|
+
* callers can compose; most will `throw await ShipError.fromHttpResponse(...)`.
|
|
372
|
+
*/
|
|
373
|
+
static fromHttpResponse(response: Response, operationName?: string): Promise<ShipError>;
|
|
374
|
+
/**
|
|
375
|
+
* Construct a `ShipError` from an error caught around a `fetch()` call.
|
|
376
|
+
*
|
|
377
|
+
* The mirror of `fromHttpResponse` for the *other* side of the HTTP error
|
|
378
|
+
* story — the network layer failing (offline, CORS, abort) rather than the
|
|
379
|
+
* server returning a non-OK response.
|
|
380
|
+
*
|
|
381
|
+
* Routing:
|
|
382
|
+
* - Already a `ShipError` → returned as-is (caller's intent preserved)
|
|
383
|
+
* - `AbortError` → `ShipError.cancelled(...)`
|
|
384
|
+
* - `TypeError` whose message mentions "fetch" → `ShipError.network(...)`
|
|
385
|
+
* - Any other `Error` → `ShipError(Api, ...)` (no HTTP status — fetch never reached the server)
|
|
386
|
+
* - Anything else (string, undefined, etc.) → `ShipError(Api, ...)`
|
|
387
|
+
*
|
|
388
|
+
* The optional `operationName` is composed into the message for context:
|
|
389
|
+
* `"Get account was cancelled"`, `"Get account failed: ..."`. Defaults to
|
|
390
|
+
* `"Request"` when omitted.
|
|
391
|
+
*/
|
|
392
|
+
static fromFetchError(cause: unknown, operationName?: string): ShipError;
|
|
393
|
+
static validation(message: string, details?: unknown): ShipError;
|
|
394
|
+
static notFound(resource: string, id?: string): ShipError;
|
|
395
|
+
static forbidden(message: string, details?: unknown): ShipError;
|
|
396
|
+
static rateLimit(message?: string, details?: unknown): ShipError;
|
|
397
|
+
/**
|
|
398
|
+
* Construct an Authentication (401) error.
|
|
399
|
+
*
|
|
400
|
+
* **Telemetry pattern — `details: { internal: '<tag>' }`.** When the
|
|
401
|
+
* server creates an auth error with an `internal` key in `details`
|
|
402
|
+
* (e.g. `{ internal: 'session_invalid' }`), `toResponse()` strips the
|
|
403
|
+
* entire `details` object before serialization. This keeps the wire
|
|
404
|
+
* response a clean "Authentication failed" while preserving granular
|
|
405
|
+
* server-side telemetry (which strategy/check failed) for logs and tests.
|
|
406
|
+
*
|
|
407
|
+
* Use this pattern in API auth code; do not put client-visible info under
|
|
408
|
+
* `internal`. Other `details` keys round-trip normally.
|
|
409
|
+
*/
|
|
410
|
+
static authentication(message?: string, details?: unknown): ShipError;
|
|
411
|
+
static business(message: string, status?: number, details?: unknown): ShipError;
|
|
412
|
+
static network(message: string, details?: unknown): ShipError;
|
|
413
|
+
static cancelled(message: string, details?: unknown): ShipError;
|
|
414
|
+
static file(message: string, details?: unknown): ShipError;
|
|
415
|
+
static config(message: string, details?: unknown): ShipError;
|
|
416
|
+
static api(message: string, status?: number, details?: unknown): ShipError;
|
|
417
|
+
isClientError(): boolean;
|
|
418
|
+
isNetworkError(): boolean;
|
|
419
|
+
isAuthError(): boolean;
|
|
420
|
+
isType(errorType: ErrorType): boolean;
|
|
421
|
+
}
|
|
422
|
+
/**
|
|
423
|
+
* Type guard to check if an unknown value is a ShipError.
|
|
424
|
+
*
|
|
425
|
+
* Uses structural checking instead of instanceof to handle module duplication
|
|
426
|
+
* in bundled applications where multiple copies of the ShipError class may exist.
|
|
427
|
+
*
|
|
428
|
+
* @example
|
|
429
|
+
* if (isShipError(error)) {
|
|
430
|
+
* console.log(error.status, error.message);
|
|
431
|
+
* }
|
|
432
|
+
*/
|
|
433
|
+
declare function isShipError(error: unknown): error is ShipError;
|
|
434
|
+
/**
|
|
435
|
+
* Plan-based platform limits returned by the `/limits` endpoint.
|
|
436
|
+
*
|
|
437
|
+
* The SDK fetches these once on first API call to drive client-side
|
|
438
|
+
* file-size / file-count / total-size validation that mirrors what the API
|
|
439
|
+
* would enforce server-side. Limits vary by account plan.
|
|
440
|
+
*
|
|
441
|
+
* These are the *platform's* posted caps for the current account — server
|
|
442
|
+
* truth delivered at runtime, never hard-coded on the client.
|
|
443
|
+
*/
|
|
444
|
+
interface PlatformLimits {
|
|
445
|
+
/** Maximum size in bytes for a single file. */
|
|
446
|
+
maxFileSize: number;
|
|
447
|
+
/** Maximum number of files in a single deployment. */
|
|
448
|
+
maxFilesCount: number;
|
|
449
|
+
/** Maximum total size in bytes across all files in a deployment. */
|
|
450
|
+
maxTotalSize: number;
|
|
451
|
+
}
|
|
452
|
+
/**
|
|
453
|
+
* Blocked file extensions — files that cannot be uploaded.
|
|
454
|
+
*
|
|
455
|
+
* We accept any file type by default and derive Content-Type from the
|
|
456
|
+
* extension at serve time (via mime-db in the API worker). Unknown extensions
|
|
457
|
+
* are served as `application/octet-stream` with `X-Content-Type-Options: nosniff`.
|
|
458
|
+
*
|
|
459
|
+
* The blocklist targets file types that pose direct security risks when hosted:
|
|
460
|
+
* executables, disk images, malware vectors, dangerous scripts, and shortcuts.
|
|
461
|
+
*/
|
|
462
|
+
declare const BLOCKED_EXTENSIONS: ReadonlySet<string>;
|
|
463
|
+
/**
|
|
464
|
+
* Check if a filename has a blocked extension.
|
|
465
|
+
* Extracts the extension from the filename and checks against the blocklist.
|
|
466
|
+
* Case-insensitive. Returns false for files without extensions.
|
|
467
|
+
*
|
|
468
|
+
* @example
|
|
469
|
+
* isBlockedExtension('virus.exe') // true
|
|
470
|
+
* isBlockedExtension('app.dmg') // true
|
|
471
|
+
* isBlockedExtension('style.css') // false
|
|
472
|
+
* isBlockedExtension('data.custom') // false
|
|
473
|
+
* isBlockedExtension('README') // false
|
|
474
|
+
*/
|
|
475
|
+
declare function isBlockedExtension(filename: string): boolean;
|
|
476
|
+
/**
|
|
477
|
+
* Characters that are unsafe in filenames for static hosting.
|
|
478
|
+
*
|
|
479
|
+
* Blocks only characters that genuinely break the upload→serve round-trip:
|
|
480
|
+
* - # ? % URL round-trip breakers (fragment, query, encoding ambiguity)
|
|
481
|
+
* - \ Path separator confusion (upload splits on backslash)
|
|
482
|
+
* - < > " XSS vectors with zero legitimate use in filenames
|
|
483
|
+
* - \x00-\x1f \x7f Control characters (header injection, display corruption)
|
|
484
|
+
*
|
|
485
|
+
* Everything else is allowed — browser percent-encodes, Worker decodes, R2 matches.
|
|
486
|
+
*/
|
|
487
|
+
declare const UNSAFE_FILENAME_CHARS: RegExp;
|
|
488
|
+
/**
|
|
489
|
+
* Check if a filename contains unsafe characters.
|
|
490
|
+
*
|
|
491
|
+
* @example
|
|
492
|
+
* hasUnsafeChars('saved_resource(1).html') // false — parentheses are safe
|
|
493
|
+
* hasUnsafeChars('page[slug].js') // false — brackets are safe
|
|
494
|
+
* hasUnsafeChars('file#anchor.html') // true — # breaks URL resolution
|
|
495
|
+
* hasUnsafeChars('file<tag>.html') // true — < is an XSS vector
|
|
496
|
+
*/
|
|
497
|
+
declare function hasUnsafeChars(filename: string): boolean;
|
|
498
|
+
/**
|
|
499
|
+
* Path segment names that indicate an unbuilt project was uploaded instead of build output.
|
|
500
|
+
* Used for early detection in CLI, browser, and server validation.
|
|
501
|
+
*/
|
|
502
|
+
declare const UNBUILT_PROJECT_MARKERS: ReadonlySet<string>;
|
|
503
|
+
/**
|
|
504
|
+
* Check if a file path contains an unbuilt project marker.
|
|
505
|
+
*
|
|
506
|
+
* @example
|
|
507
|
+
* hasUnbuiltMarker('node_modules/react/index.js') // true
|
|
508
|
+
* hasUnbuiltMarker('package.json') // true
|
|
509
|
+
* hasUnbuiltMarker('dist/index.html') // false
|
|
510
|
+
*/
|
|
511
|
+
declare function hasUnbuiltMarker(filePath: string): boolean;
|
|
512
|
+
/**
|
|
513
|
+
* Simple ping response for health checks
|
|
514
|
+
*/
|
|
515
|
+
interface PingResponse {
|
|
516
|
+
/** Always true if service is healthy */
|
|
517
|
+
success: boolean;
|
|
518
|
+
/** Optional timestamp */
|
|
519
|
+
timestamp?: number;
|
|
520
|
+
}
|
|
521
|
+
/**
|
|
522
|
+
* How a request (or recorded activity) was authorized.
|
|
523
|
+
*
|
|
524
|
+
* Client populations: `SESSION` (first-party cookie), `API_KEY` (`ship-`
|
|
525
|
+
* key), `TOKEN` (`deploy-` deploy token), `AGENT` (anonymous public deploy —
|
|
526
|
+
* no credential; the platform grants the public-account identity per
|
|
527
|
+
* request), `OAUTH` (delegated access token). Server populations: `WEBHOOK`
|
|
528
|
+
* (signed webhook processing), `SYSTEM` (scheduled/background jobs).
|
|
529
|
+
*/
|
|
530
|
+
declare const AuthMethod: {
|
|
531
|
+
readonly SESSION: "session";
|
|
532
|
+
readonly API_KEY: "apiKey";
|
|
533
|
+
readonly TOKEN: "token";
|
|
534
|
+
readonly AGENT: "agent";
|
|
535
|
+
readonly OAUTH: "oauth";
|
|
536
|
+
readonly WEBHOOK: "webhook";
|
|
537
|
+
readonly SYSTEM: "system";
|
|
538
|
+
};
|
|
539
|
+
type AuthMethodType = typeof AuthMethod[keyof typeof AuthMethod];
|
|
540
|
+
/**
|
|
541
|
+
* Shape constants for API keys (`ship-{64 hex chars}`).
|
|
542
|
+
* Single source of truth used by validation utilities and auth middleware.
|
|
543
|
+
*/
|
|
544
|
+
declare const API_KEY: {
|
|
545
|
+
/** Prefix that identifies an API key. */
|
|
546
|
+
readonly PREFIX: "ship-";
|
|
547
|
+
/** Number of hex characters following the prefix. */
|
|
548
|
+
readonly HEX_LENGTH: 64;
|
|
549
|
+
/** Total length of an API key including prefix (`PREFIX.length + HEX_LENGTH = 69`). */
|
|
550
|
+
readonly TOTAL_LENGTH: 69;
|
|
551
|
+
/** Number of trailing characters used to display a redacted hint (e.g. last 4). */
|
|
552
|
+
readonly HINT_LENGTH: 4;
|
|
553
|
+
};
|
|
554
|
+
/**
|
|
555
|
+
* Shape constants for deploy tokens (`deploy-{64 hex chars}`).
|
|
556
|
+
* Single source of truth used by validation utilities and auth middleware.
|
|
557
|
+
*/
|
|
558
|
+
declare const DEPLOY_TOKEN: {
|
|
559
|
+
/** Prefix that identifies a deploy token. */
|
|
560
|
+
readonly PREFIX: "deploy-";
|
|
561
|
+
/** Number of hex characters following the prefix. */
|
|
562
|
+
readonly HEX_LENGTH: 64;
|
|
563
|
+
/** Total length of a deploy token including prefix (`PREFIX.length + HEX_LENGTH = 71`). */
|
|
564
|
+
readonly TOTAL_LENGTH: 71;
|
|
565
|
+
};
|
|
566
|
+
/**
|
|
567
|
+
* Shape constants for caller identifiers (the `X-Caller` instance-identity
|
|
568
|
+
* header — rate-limit bucketing for multi-tenant orchestrators). The API
|
|
569
|
+
* normalizes case and silently ignores malformed values (the header is
|
|
570
|
+
* unauthenticated); clients validate at the boundary via `validateCaller`,
|
|
571
|
+
* so a value the server would drop fails fast instead.
|
|
572
|
+
*/
|
|
573
|
+
declare const CALLER: {
|
|
574
|
+
/** HTTP header name. */
|
|
575
|
+
readonly HEADER: "X-Caller";
|
|
576
|
+
/** Maximum identifier length. */
|
|
577
|
+
readonly MAX_LENGTH: 128;
|
|
578
|
+
/** Allowed characters: alphanumeric, dot, underscore, hyphen. */
|
|
579
|
+
readonly PATTERN: RegExp;
|
|
580
|
+
};
|
|
581
|
+
/**
|
|
582
|
+
* Token populations distinguishable by shape. The platform carries every
|
|
583
|
+
* client token in one wire slot (`Authorization: Bearer <value>`) and
|
|
584
|
+
* classifies by value, never by a side channel — this is the classifier.
|
|
585
|
+
*
|
|
586
|
+
* `API_KEY` and `DEPLOY_TOKEN` *are* `AuthMethod.API_KEY` and
|
|
587
|
+
* `AuthMethod.TOKEN` — the equality is structural, so a classification flows
|
|
588
|
+
* straight into an auth method and the pair can never drift. `OPAQUE` is any
|
|
589
|
+
* other value — shape says nothing about it, so only a lookup can. Today the
|
|
590
|
+
* server refuses every opaque bearer; the OAuth access-token population
|
|
591
|
+
* resolves there when the authorization server ships.
|
|
592
|
+
*/
|
|
593
|
+
declare const TokenKind: {
|
|
594
|
+
readonly API_KEY: "apiKey";
|
|
595
|
+
readonly DEPLOY_TOKEN: "token";
|
|
596
|
+
readonly OPAQUE: "opaque";
|
|
597
|
+
};
|
|
598
|
+
type TokenKindType = typeof TokenKind[keyof typeof TokenKind];
|
|
599
|
+
/**
|
|
600
|
+
* Classify a client token by shape. The single dispatch used by both sides
|
|
601
|
+
* of the wire: API auth middleware (which population is this credential?)
|
|
602
|
+
* and SDK validation (which format rules apply before sending?). Sharing it
|
|
603
|
+
* is what guarantees client and server can never disagree on dispatch.
|
|
604
|
+
*/
|
|
605
|
+
declare function classifyToken(token: string): TokenKindType;
|
|
606
|
+
/**
|
|
607
|
+
* OAuth scope vocabulary for delegated third-party access tokens.
|
|
608
|
+
* Single source of truth used by the authorization server (advertised in
|
|
609
|
+
* `scopes_supported`), the API's scope-enforcement middleware, and consent UI
|
|
610
|
+
* copy. The standard `offline_access` scope (refresh tokens) is not platform
|
|
611
|
+
* vocabulary and is deliberately absent — the middleware never checks it.
|
|
612
|
+
*
|
|
613
|
+
* Deliberately absent by design: any `tokens:*` scope, `account:write`, or
|
|
614
|
+
* admin scope — a delegated app must never mint credentials, delete the
|
|
615
|
+
* account, or act as admin.
|
|
616
|
+
*/
|
|
617
|
+
declare const OAuthScope: {
|
|
618
|
+
readonly ACCOUNT_READ: "account:read";
|
|
619
|
+
readonly DEPLOYMENTS_READ: "deployments:read";
|
|
620
|
+
readonly DEPLOYMENTS_WRITE: "deployments:write";
|
|
621
|
+
readonly DOMAINS_READ: "domains:read";
|
|
622
|
+
readonly DOMAINS_WRITE: "domains:write";
|
|
623
|
+
};
|
|
624
|
+
type OAuthScopeType = typeof OAuthScope[keyof typeof OAuthScope];
|
|
625
|
+
declare const DEPLOYMENT_CONFIG_FILENAME = "ship.json";
|
|
626
|
+
/** Default ship.json config for SPA routing. Single source of truth — used by both API and SDK. */
|
|
627
|
+
declare const SPA_DEFAULT_CONFIG: {
|
|
628
|
+
readonly rewrites: readonly [{
|
|
629
|
+
readonly source: "/(.*)";
|
|
630
|
+
readonly destination: "/index.html";
|
|
631
|
+
}];
|
|
632
|
+
};
|
|
633
|
+
/**
|
|
634
|
+
* Validate API key format
|
|
635
|
+
*/
|
|
636
|
+
declare function validateApiKey(apiKey: string): void;
|
|
637
|
+
/**
|
|
638
|
+
* Validate deploy token format
|
|
639
|
+
*/
|
|
640
|
+
declare function validateDeployToken(deployToken: string): void;
|
|
641
|
+
/**
|
|
642
|
+
* Validate a client token of any population. Classifies by shape and applies
|
|
643
|
+
* the matching format rules: `ship-` keys and `deploy-` deploy tokens are
|
|
644
|
+
* validated strictly; opaque tokens (OAuth access tokens, future populations)
|
|
645
|
+
* only need to be non-empty — their validity is the server's to decide.
|
|
646
|
+
*/
|
|
647
|
+
declare function validateToken(token: string): void;
|
|
648
|
+
/**
|
|
649
|
+
* Validate a caller identifier against the `CALLER` shape. The server
|
|
650
|
+
* silently ignores malformed values (the header is unauthenticated); clients
|
|
651
|
+
* call this at configuration time so the drop never silently happens.
|
|
652
|
+
*/
|
|
653
|
+
declare function validateCaller(caller: string): void;
|
|
654
|
+
/**
|
|
655
|
+
* Validate API URL format
|
|
656
|
+
*/
|
|
657
|
+
declare function validateApiUrl(apiUrl: string): void;
|
|
658
|
+
/**
|
|
659
|
+
* Check if a string matches the deployment identifier pattern (word-word-alphanumeric7).
|
|
660
|
+
* Example: "happy-cat-abc1234.shipstatic.com"
|
|
661
|
+
*/
|
|
662
|
+
declare function isDeployment(input: string): boolean;
|
|
663
|
+
/**
|
|
664
|
+
* Request payload for SPA check endpoint
|
|
665
|
+
*/
|
|
666
|
+
interface SPACheckRequest {
|
|
667
|
+
/** Array of file paths */
|
|
668
|
+
files: string[];
|
|
669
|
+
/** HTML content of index.html file */
|
|
670
|
+
index: string;
|
|
671
|
+
}
|
|
672
|
+
/**
|
|
673
|
+
* Response from SPA check endpoint
|
|
674
|
+
*/
|
|
675
|
+
interface SPACheckResponse {
|
|
676
|
+
/** Whether the project is detected as a Single Page Application */
|
|
677
|
+
isSPA: boolean;
|
|
678
|
+
/** 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
|
+
};
|
|
685
|
+
}
|
|
686
|
+
/**
|
|
687
|
+
* Represents a file that has been processed and is ready for deploy.
|
|
688
|
+
* Used across the platform (API, SDK, CLI) for file operations.
|
|
689
|
+
*/
|
|
690
|
+
interface StaticFile {
|
|
691
|
+
/**
|
|
692
|
+
* The content of the file.
|
|
693
|
+
* In Node.js, this is typically a `Buffer`.
|
|
694
|
+
* In the browser, this is typically a `File` or `Blob` object.
|
|
695
|
+
*/
|
|
696
|
+
content: File | Buffer | Blob;
|
|
697
|
+
/**
|
|
698
|
+
* The desired path for the file on the server, relative to the deployment root.
|
|
699
|
+
* Should include the filename, e.g., `images/photo.jpg`.
|
|
700
|
+
*/
|
|
701
|
+
path: string;
|
|
702
|
+
/**
|
|
703
|
+
* The original absolute file system path (primarily used in Node.js environments).
|
|
704
|
+
* This helps in debugging or associating the server path back to its source.
|
|
705
|
+
*/
|
|
706
|
+
filePath?: string;
|
|
707
|
+
/**
|
|
708
|
+
* The MD5 hash (checksum) of the file's content.
|
|
709
|
+
* This is calculated by the SDK before deploy if not provided.
|
|
710
|
+
*/
|
|
711
|
+
md5?: string;
|
|
712
|
+
/** The size of the file in bytes. */
|
|
713
|
+
size: number;
|
|
714
|
+
}
|
|
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
|
+
/** Default API URL if not otherwise configured. */
|
|
730
|
+
declare const DEFAULT_API = "https://api.shipstatic.com";
|
|
731
|
+
/**
|
|
732
|
+
* Universal deploy input — the union of every shape the SDK accepts.
|
|
733
|
+
*
|
|
734
|
+
* - **Browser**: `File[]` (typically from `<input type="file">` or drag-and-drop)
|
|
735
|
+
* - **Node**: `string | string[]` (file or directory path(s) on disk; directories are walked)
|
|
736
|
+
*
|
|
737
|
+
* Each platform's SDK narrows its `deploy()` signature to the relevant shape
|
|
738
|
+
* and rejects anything else at runtime. Use the structural types directly
|
|
739
|
+
* (`File[]`, `string | string[]`) when writing platform-specific code.
|
|
740
|
+
*/
|
|
741
|
+
type DeployInput = File[] | string | string[];
|
|
742
|
+
/**
|
|
743
|
+
* Options for deployment creation at the API contract level.
|
|
744
|
+
* SDK implementations may extend with additional options (timeout, signal, callbacks, etc.).
|
|
745
|
+
*/
|
|
746
|
+
interface DeploymentUploadOptions {
|
|
747
|
+
/** Optional labels for categorization and filtering */
|
|
748
|
+
labels?: string[];
|
|
749
|
+
/** Client identifier (e.g., 'cli', 'sdk', 'web') */
|
|
750
|
+
via?: string;
|
|
751
|
+
/**
|
|
752
|
+
* Optional password that protects this deployment.
|
|
753
|
+
*
|
|
754
|
+
* Length: {@link PASSWORD_CONSTRAINTS.MIN_LENGTH} to
|
|
755
|
+
* {@link PASSWORD_CONSTRAINTS.MAX_LENGTH} characters. Leading and trailing
|
|
756
|
+
* whitespace is trimmed before validation; internal whitespace is
|
|
757
|
+
* significant. Visitors are prompted to enter the password before they can
|
|
758
|
+
* view the deployment — including on any custom domains pointing at it.
|
|
759
|
+
* To remove protection, redeploy without a password.
|
|
760
|
+
*/
|
|
761
|
+
password?: string;
|
|
762
|
+
/** @internal Trigger server-side build. Only available via /upload endpoint. */
|
|
763
|
+
build?: boolean;
|
|
764
|
+
/** @internal Trigger server-side prerender. Only available via /upload endpoint. */
|
|
765
|
+
prerender?: boolean;
|
|
766
|
+
/** @internal Trigger server-side SPA detection. Only available via /upload endpoint. */
|
|
767
|
+
spa?: boolean;
|
|
768
|
+
/** @internal reCAPTCHA proof for the anonymous human deploy channel. Only available via /upload endpoint. */
|
|
769
|
+
captcha?: string;
|
|
770
|
+
}
|
|
771
|
+
/**
|
|
772
|
+
* Deployment resource interface - the contract all implementations must follow
|
|
773
|
+
*/
|
|
774
|
+
interface DeploymentResource {
|
|
775
|
+
upload: (input: DeployInput, options?: DeploymentUploadOptions) => Promise<DeploymentCreateResponse>;
|
|
776
|
+
list: () => Promise<DeploymentListResponse>;
|
|
777
|
+
get: (id: string) => Promise<Deployment>;
|
|
778
|
+
set: (id: string, options: {
|
|
779
|
+
labels: string[];
|
|
780
|
+
}) => Promise<Deployment>;
|
|
781
|
+
remove: (id: string) => Promise<void>;
|
|
782
|
+
}
|
|
783
|
+
/**
|
|
784
|
+
* Domain resource interface - the contract all implementations must follow
|
|
785
|
+
*/
|
|
786
|
+
interface DomainResource {
|
|
787
|
+
set: (name: string, options?: {
|
|
788
|
+
deployment?: string;
|
|
789
|
+
labels?: string[];
|
|
790
|
+
}) => Promise<DomainSetResult>;
|
|
791
|
+
list: () => Promise<DomainListResponse>;
|
|
792
|
+
get: (name: string) => Promise<Domain>;
|
|
793
|
+
remove: (name: string) => Promise<void>;
|
|
794
|
+
verify: (name: string) => Promise<{
|
|
795
|
+
message: string;
|
|
796
|
+
}>;
|
|
797
|
+
validate: (name: string) => Promise<DomainValidateResponse>;
|
|
798
|
+
dns: (name: string) => Promise<DomainDnsResponse>;
|
|
799
|
+
records: (name: string) => Promise<DomainRecordsResponse>;
|
|
800
|
+
share: (name: string) => Promise<{
|
|
801
|
+
domain: string;
|
|
802
|
+
hash: string;
|
|
803
|
+
}>;
|
|
804
|
+
}
|
|
805
|
+
/**
|
|
806
|
+
* Account resource interface - the contract all implementations must follow
|
|
807
|
+
*/
|
|
808
|
+
interface AccountResource {
|
|
809
|
+
get: () => Promise<AccountGetResponse>;
|
|
810
|
+
}
|
|
811
|
+
/**
|
|
812
|
+
* Token resource interface - the contract all implementations must follow
|
|
813
|
+
*/
|
|
814
|
+
interface TokenResource {
|
|
815
|
+
create: (options?: {
|
|
816
|
+
ttl?: number;
|
|
817
|
+
labels?: string[];
|
|
818
|
+
}) => Promise<TokenCreateResponse>;
|
|
819
|
+
list: () => Promise<TokenListResponse>;
|
|
820
|
+
remove: (token: string) => Promise<void>;
|
|
821
|
+
}
|
|
822
|
+
/**
|
|
823
|
+
* Billing status response from GET /billing/status
|
|
824
|
+
*
|
|
825
|
+
* Note: The user's `plan` comes from Account, not here.
|
|
826
|
+
* This endpoint only returns billing-specific data (usage, portal, etc.)
|
|
827
|
+
*
|
|
828
|
+
* If `billing` is null, the user has no active billing.
|
|
829
|
+
*/
|
|
830
|
+
interface BillingStatus {
|
|
831
|
+
/** Creem billing ID, or null if no active billing */
|
|
832
|
+
billing: string | null;
|
|
833
|
+
/** Number of billing units (1 unit = 1 custom domain), null if no billing */
|
|
834
|
+
units: number | null;
|
|
835
|
+
/** Billing status from Creem (active, trialing, canceled, etc.), null if no billing */
|
|
836
|
+
status: string | null;
|
|
837
|
+
/** Link to Creem customer portal for billing management, null if unavailable */
|
|
838
|
+
portal: string | null;
|
|
839
|
+
}
|
|
840
|
+
/**
|
|
841
|
+
* Checkout session response from POST /billing/checkout
|
|
842
|
+
*/
|
|
843
|
+
interface CheckoutSession {
|
|
844
|
+
/** URL to redirect user to Creem checkout page */
|
|
845
|
+
url: string;
|
|
846
|
+
}
|
|
847
|
+
/**
|
|
848
|
+
* All activity event types logged in the system.
|
|
849
|
+
* Uses dot notation consistently: {resource}.{action}
|
|
850
|
+
*/
|
|
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';
|
|
852
|
+
/**
|
|
853
|
+
* Activity events visible to users in the dashboard
|
|
854
|
+
*/
|
|
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';
|
|
856
|
+
/**
|
|
857
|
+
* Activity record returned from the API
|
|
858
|
+
*/
|
|
859
|
+
interface Activity {
|
|
860
|
+
/** The event type */
|
|
861
|
+
event: ActivityEvent;
|
|
862
|
+
/** Unix timestamp (seconds) when the activity occurred */
|
|
863
|
+
created: number;
|
|
864
|
+
/** Associated deployment ID (if applicable) */
|
|
865
|
+
deployment?: string;
|
|
866
|
+
/** Associated domain name (if applicable) */
|
|
867
|
+
domain?: string;
|
|
868
|
+
/** JSON-encoded metadata (parse with JSON.parse) */
|
|
869
|
+
meta?: string;
|
|
870
|
+
}
|
|
871
|
+
/**
|
|
872
|
+
* Parsed activity metadata.
|
|
873
|
+
* Different events populate different fields.
|
|
874
|
+
*/
|
|
875
|
+
interface ActivityMeta {
|
|
876
|
+
/** Number of files in deployment */
|
|
877
|
+
files?: number;
|
|
878
|
+
/** Total size in bytes */
|
|
879
|
+
size?: number;
|
|
880
|
+
/** Whether deployment has a ship.json config */
|
|
881
|
+
hasConfig?: boolean;
|
|
882
|
+
/** Whether deployment has a password set */
|
|
883
|
+
hasPassword?: boolean;
|
|
884
|
+
/** Whether this was an update (vs create) */
|
|
885
|
+
isUpdate?: boolean;
|
|
886
|
+
/** Whether domain was already verified */
|
|
887
|
+
wasVerified?: boolean;
|
|
888
|
+
/** Previous deployment ID before relinking */
|
|
889
|
+
previousDeployment?: string;
|
|
890
|
+
/** Labels that were set/updated */
|
|
891
|
+
labels?: string[];
|
|
892
|
+
/** OAuth provider name */
|
|
893
|
+
provider?: string;
|
|
894
|
+
/** Account email */
|
|
895
|
+
email?: string;
|
|
896
|
+
/** Account display name */
|
|
897
|
+
name?: string;
|
|
898
|
+
/** Previous plan */
|
|
899
|
+
from?: string;
|
|
900
|
+
/** New plan */
|
|
901
|
+
to?: string;
|
|
902
|
+
/** Allow additional fields for future use */
|
|
903
|
+
[key: string]: unknown;
|
|
904
|
+
}
|
|
905
|
+
/**
|
|
906
|
+
* Response from GET /activities endpoint
|
|
907
|
+
*/
|
|
908
|
+
interface ActivityListResponse {
|
|
909
|
+
/** Array of activities */
|
|
910
|
+
activities: Activity[];
|
|
911
|
+
}
|
|
912
|
+
/**
|
|
913
|
+
* File status constants for validation state tracking
|
|
914
|
+
*/
|
|
915
|
+
declare const FileValidationStatus: {
|
|
916
|
+
/** File is pending validation */
|
|
917
|
+
readonly PENDING: "pending";
|
|
918
|
+
/** File failed during processing (before validation) */
|
|
919
|
+
readonly PROCESSING_ERROR: "processing_error";
|
|
920
|
+
/** File was excluded by validation warning (not an error) */
|
|
921
|
+
readonly EXCLUDED: "excluded";
|
|
922
|
+
/** File failed validation (blocks deployment) */
|
|
923
|
+
readonly VALIDATION_FAILED: "validation_failed";
|
|
924
|
+
/** File passed validation and is ready for deployment */
|
|
925
|
+
readonly READY: "ready";
|
|
926
|
+
};
|
|
927
|
+
type FileValidationStatusType = typeof FileValidationStatus[keyof typeof FileValidationStatus];
|
|
928
|
+
/**
|
|
929
|
+
* A validation issue with a display-ready message
|
|
930
|
+
*
|
|
931
|
+
* Issues are either errors (in errors[] array) or warnings (in warnings[] array).
|
|
932
|
+
* The array position determines severity - no need to duplicate it in the object.
|
|
933
|
+
*/
|
|
934
|
+
interface ValidationIssue {
|
|
935
|
+
/** File path that triggered this issue */
|
|
936
|
+
file: string;
|
|
937
|
+
/** Display-ready message explaining the issue */
|
|
938
|
+
message: string;
|
|
939
|
+
}
|
|
940
|
+
/**
|
|
941
|
+
* Minimal file interface required for validation
|
|
942
|
+
*/
|
|
943
|
+
interface ValidatableFile {
|
|
944
|
+
name: string;
|
|
945
|
+
size: number;
|
|
946
|
+
status?: FileValidationStatusType;
|
|
947
|
+
statusMessage?: string;
|
|
948
|
+
}
|
|
949
|
+
/**
|
|
950
|
+
* File validation result with severity-based issue reporting
|
|
951
|
+
*
|
|
952
|
+
* Validation checks files against constraints and categorizes issues by severity:
|
|
953
|
+
* - **Errors**: Block deployment (file too large, invalid type, etc.)
|
|
954
|
+
* - **Warnings**: Exclude files but allow deployment (empty files, etc.)
|
|
955
|
+
*
|
|
956
|
+
* @example
|
|
957
|
+
* ```typescript
|
|
958
|
+
* const result = validateFiles(files, config);
|
|
959
|
+
*
|
|
960
|
+
* if (!result.canDeploy) {
|
|
961
|
+
* // Has errors - must fix before deploying
|
|
962
|
+
* console.error('Deployment blocked:', result.errors);
|
|
963
|
+
* } else if (result.warnings.length > 0) {
|
|
964
|
+
* // Has warnings - deployment proceeds, some files excluded
|
|
965
|
+
* console.warn('Files excluded:', result.warnings);
|
|
966
|
+
* deploy(result.validFiles);
|
|
967
|
+
* } else {
|
|
968
|
+
* // All files valid
|
|
969
|
+
* deploy(result.validFiles);
|
|
970
|
+
* }
|
|
971
|
+
* ```
|
|
972
|
+
*/
|
|
973
|
+
interface FileValidationResult<T extends ValidatableFile> {
|
|
974
|
+
/** All files with updated status */
|
|
975
|
+
files: T[];
|
|
976
|
+
/** Files ready for deployment (status: 'ready') */
|
|
977
|
+
validFiles: T[];
|
|
978
|
+
/** Blocking errors that prevent deployment */
|
|
979
|
+
errors: ValidationIssue[];
|
|
980
|
+
/** Non-blocking warnings (files excluded but deployment allowed) */
|
|
981
|
+
warnings: ValidationIssue[];
|
|
982
|
+
/** Whether deployment can proceed (true if errors.length === 0) */
|
|
983
|
+
canDeploy: boolean;
|
|
984
|
+
}
|
|
985
|
+
/**
|
|
986
|
+
* Represents a file that has been uploaded and stored
|
|
987
|
+
*/
|
|
988
|
+
interface UploadedFile {
|
|
989
|
+
key: string;
|
|
990
|
+
etag: string;
|
|
991
|
+
size: number;
|
|
992
|
+
validated?: boolean;
|
|
993
|
+
}
|
|
994
|
+
/**
|
|
995
|
+
* Check if a domain is a platform domain (subdomain of our platform).
|
|
996
|
+
* Platform domains are free and don't require DNS verification.
|
|
997
|
+
*
|
|
998
|
+
* @example isPlatformDomain("www.shipstatic.com", "shipstatic.com") → true
|
|
999
|
+
* @example isPlatformDomain("example.com", "shipstatic.com") → false
|
|
1000
|
+
*/
|
|
1001
|
+
declare function isPlatformDomain(domain: string, platformDomain: string): boolean;
|
|
1002
|
+
/**
|
|
1003
|
+
* Check if a domain is a custom domain (not a platform subdomain).
|
|
1004
|
+
* Custom domains are billable and require DNS verification.
|
|
1005
|
+
*
|
|
1006
|
+
* @example isCustomDomain("example.com", "shipstatic.com") → true
|
|
1007
|
+
* @example isCustomDomain("www.shipstatic.com", "shipstatic.com") → false
|
|
1008
|
+
*/
|
|
1009
|
+
declare function isCustomDomain(domain: string, platformDomain: string): boolean;
|
|
1010
|
+
/**
|
|
1011
|
+
* Extract subdomain from a platform domain.
|
|
1012
|
+
* Returns null if not a platform domain.
|
|
1013
|
+
*
|
|
1014
|
+
* @example extractSubdomain("www.shipstatic.com", "shipstatic.com") → "www"
|
|
1015
|
+
* @example extractSubdomain("example.com", "shipstatic.com") → null
|
|
1016
|
+
*/
|
|
1017
|
+
declare function extractSubdomain(domain: string, platformDomain: string): string | null;
|
|
1018
|
+
/**
|
|
1019
|
+
* Generate HTTPS URL for a deployment hostname.
|
|
1020
|
+
*/
|
|
1021
|
+
declare function generateDeploymentUrl(deployment: string): string;
|
|
1022
|
+
/**
|
|
1023
|
+
* Generate HTTPS URL for a domain.
|
|
1024
|
+
*/
|
|
1025
|
+
declare function generateDomainUrl(domain: string): string;
|
|
1026
|
+
/**
|
|
1027
|
+
* Label validation constraints shared across UI and API.
|
|
1028
|
+
* These rules define the single source of truth for label validation.
|
|
1029
|
+
*/
|
|
1030
|
+
declare const LABEL_CONSTRAINTS: {
|
|
1031
|
+
/** Minimum label length in characters */
|
|
1032
|
+
readonly MIN_LENGTH: 3;
|
|
1033
|
+
/** Maximum label length in characters (concise labels, matches Stack Overflow's original limit) */
|
|
1034
|
+
readonly MAX_LENGTH: 25;
|
|
1035
|
+
/** Maximum number of labels allowed per resource */
|
|
1036
|
+
readonly MAX_COUNT: 10;
|
|
1037
|
+
/** Allowed separator characters between label segments */
|
|
1038
|
+
readonly SEPARATORS: "._-";
|
|
1039
|
+
};
|
|
1040
|
+
/**
|
|
1041
|
+
* Label validation pattern.
|
|
1042
|
+
* Must start and end with alphanumeric (a-z, 0-9).
|
|
1043
|
+
* Can contain separators (. _ -) between segments, but not consecutive.
|
|
1044
|
+
*
|
|
1045
|
+
* Valid examples: 'production', 'v1.2.3', 'api_v2', 'us-east-1'
|
|
1046
|
+
* Invalid examples: 'ab' (too short), '-prod' (starts with separator), 'foo--bar' (consecutive separators)
|
|
1047
|
+
*/
|
|
1048
|
+
declare const LABEL_PATTERN: RegExp;
|
|
1049
|
+
/**
|
|
1050
|
+
* Serialize labels array to JSON string for database storage.
|
|
1051
|
+
* Returns null for empty or undefined arrays.
|
|
1052
|
+
*
|
|
1053
|
+
* @example serializeLabels(['web', 'production']) → '["web","production"]'
|
|
1054
|
+
* @example serializeLabels([]) → null
|
|
1055
|
+
* @example serializeLabels(undefined) → null
|
|
1056
|
+
*/
|
|
1057
|
+
declare function serializeLabels(labels: string[] | undefined): string | null;
|
|
1058
|
+
/**
|
|
1059
|
+
* Deserialize labels from JSON string to array.
|
|
1060
|
+
* Always returns an array — empty array for null/empty/invalid input.
|
|
1061
|
+
*
|
|
1062
|
+
* @example deserializeLabels('["web","production"]') → ['web', 'production']
|
|
1063
|
+
* @example deserializeLabels(null) → []
|
|
1064
|
+
* @example deserializeLabels('') → []
|
|
1065
|
+
*/
|
|
1066
|
+
declare function deserializeLabels(labelsJson: string | null): string[];
|
|
1067
|
+
/**
|
|
1068
|
+
* Length constraints for the optional deployment password
|
|
1069
|
+
* (`DeploymentUploadOptions.password`). Single source of truth shared across
|
|
1070
|
+
* platform consumers.
|
|
1071
|
+
*/
|
|
1072
|
+
declare const PASSWORD_CONSTRAINTS: {
|
|
1073
|
+
/** Minimum password length in characters */
|
|
1074
|
+
readonly MIN_LENGTH: 6;
|
|
1075
|
+
/** Maximum password length in characters */
|
|
1076
|
+
readonly MAX_LENGTH: 128;
|
|
1077
|
+
};
|
|
1078
|
+
/**
|
|
1079
|
+
* Validate an optional deployment password and return it normalized.
|
|
1080
|
+
*
|
|
1081
|
+
* Absent (`undefined` / `null`) → returns `undefined`. Present → trim
|
|
1082
|
+
* leading/trailing whitespace, then validate against `PASSWORD_CONSTRAINTS`
|
|
1083
|
+
* length bounds (internal whitespace is significant and counts toward
|
|
1084
|
+
* length). Throws `ShipError.validation` on breach; returns the trimmed
|
|
1085
|
+
* value.
|
|
1086
|
+
*
|
|
1087
|
+
* The trim is canonical: at upload, the API hashes the trimmed value; at
|
|
1088
|
+
* unlock, the router trims submissions before hashing. Submission and storage
|
|
1089
|
+
* agree byte-for-byte. Length validation runs on the trimmed value because
|
|
1090
|
+
* that's the user's actual intent — and it disarms a class of invisible
|
|
1091
|
+
* foot-guns (trailing newlines from copy/paste, mobile auto-spacing,
|
|
1092
|
+
* password-manager artifacts).
|
|
1093
|
+
*
|
|
1094
|
+
* Single source of truth shared by SDK (client-side validation, return
|
|
1095
|
+
* ignored) and API (server-side enforcement, return threaded into config).
|
|
1096
|
+
* Length is part of the wire-format contract; strength rules, if added later,
|
|
1097
|
+
* stay server-side. See `CLAUDE.md` "Validation: format vs policy".
|
|
1098
|
+
*/
|
|
1099
|
+
declare function validatePassword(value: unknown): string | undefined;
|
|
5
1100
|
|
|
6
1101
|
/**
|
|
7
1102
|
* @file SDK-specific type definitions
|
|
@@ -14,8 +1109,6 @@ export { Account, AccountResource, DEFAULT_API, DeployInput, Deployment, Deploym
|
|
|
14
1109
|
* Extends the API contract (DeploymentUploadOptions) with SDK-specific options.
|
|
15
1110
|
*/
|
|
16
1111
|
interface DeploymentOptions extends DeploymentUploadOptions {
|
|
17
|
-
/** The API URL to use for this specific deploy. Overrides client's default. */
|
|
18
|
-
apiUrl?: string;
|
|
19
1112
|
/** An AbortSignal to allow cancellation of the deploy operation. */
|
|
20
1113
|
signal?: AbortSignal;
|
|
21
1114
|
/** Callback invoked if the deploy is cancelled via the AbortSignal. */
|
|
@@ -24,18 +1117,12 @@ interface DeploymentOptions extends DeploymentUploadOptions {
|
|
|
24
1117
|
maxConcurrency?: number;
|
|
25
1118
|
/** Timeout in milliseconds for the deploy request. */
|
|
26
1119
|
timeout?: number;
|
|
27
|
-
/** API key for this specific deploy. Overrides client's default (format: ship-<64-char-hex>, total 69 chars). */
|
|
28
|
-
apiKey?: string;
|
|
29
|
-
/** Deploy token for this specific deploy. Overrides client's default (format: token-<64-char-hex>, total 70 chars). */
|
|
30
|
-
deployToken?: string;
|
|
31
1120
|
/** Whether to auto-detect and optimize file paths by flattening common directories. Defaults to true. */
|
|
32
1121
|
pathDetect?: boolean;
|
|
33
1122
|
/** Whether to auto-detect SPAs and generate ship.json configuration. Defaults to true. */
|
|
34
1123
|
spaDetect?: boolean;
|
|
35
1124
|
/** Callback for deploy progress with detailed statistics. */
|
|
36
1125
|
onProgress?: (info: ProgressInfo) => void;
|
|
37
|
-
/** Caller identifier for multi-tenant deployments (alphanumeric, dot, underscore, hyphen). */
|
|
38
|
-
caller?: string;
|
|
39
1126
|
}
|
|
40
1127
|
type ApiDeployOptions = Omit<DeploymentOptions, 'pathDetect'>;
|
|
41
1128
|
/**
|
|
@@ -70,6 +1157,8 @@ interface DeployBodyContext {
|
|
|
70
1157
|
prerender?: boolean;
|
|
71
1158
|
spa?: boolean;
|
|
72
1159
|
};
|
|
1160
|
+
/** @internal reCAPTCHA proof for the anonymous human deploy channel (/upload). */
|
|
1161
|
+
captcha?: string;
|
|
73
1162
|
}
|
|
74
1163
|
/**
|
|
75
1164
|
* Function that creates a deploy request body from files.
|
|
@@ -78,17 +1167,36 @@ interface DeployBodyContext {
|
|
|
78
1167
|
type DeployBodyCreator = (files: StaticFile[], context?: DeployBodyContext) => Promise<DeployBody>;
|
|
79
1168
|
/** Standard `fetch` signature — the type of the `fetch` client option. */
|
|
80
1169
|
type Fetch = typeof fetch;
|
|
1170
|
+
/**
|
|
1171
|
+
* Supplies the client token per request — synchronously or asynchronously.
|
|
1172
|
+
* The provider owns freshness: callers holding short-lived credentials
|
|
1173
|
+
* (e.g. OAuth access tokens) refresh inside the provider; the SDK just asks.
|
|
1174
|
+
* A provider that yields nothing fails the request — a configured provider
|
|
1175
|
+
* is credential intent, and intent never degrades to an anonymous request.
|
|
1176
|
+
*/
|
|
1177
|
+
type TokenProvider = () => string | Promise<string>;
|
|
81
1178
|
/**
|
|
82
1179
|
* Options for configuring a `Ship` instance.
|
|
83
|
-
* Sets default API host,
|
|
1180
|
+
* Sets default API host, the client credential, progress callbacks, concurrency, and timeouts for the client.
|
|
84
1181
|
*/
|
|
85
1182
|
interface ShipClientOptions {
|
|
86
1183
|
/** Default API URL for the client instance. */
|
|
87
1184
|
apiUrl?: string | undefined;
|
|
88
|
-
/**
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
1185
|
+
/**
|
|
1186
|
+
* The client credential — any platform token, sent verbatim as
|
|
1187
|
+
* `Authorization: Bearer <value>` on every request. The token's prefix says
|
|
1188
|
+
* what it is: `ship-` API key (durable, full account), `deploy-` deploy
|
|
1189
|
+
* token (deploy-scoped, revocable, optional TTL), anything else an opaque
|
|
1190
|
+
* pre-issued bearer such as an OAuth access token. The server classifies by
|
|
1191
|
+
* value — the client never has to say which kind it holds.
|
|
1192
|
+
*
|
|
1193
|
+
* Pass a {@link TokenProvider} function instead of a string when the token
|
|
1194
|
+
* must be minted or refreshed per request.
|
|
1195
|
+
*
|
|
1196
|
+
* Omitted entirely: deploys still work — they land in the public account
|
|
1197
|
+
* with a claim URL and an expiry; every other operation requires a token.
|
|
1198
|
+
*/
|
|
1199
|
+
token?: string | TokenProvider | undefined;
|
|
92
1200
|
/**
|
|
93
1201
|
* Default callback for deploy progress for deploys made with this client.
|
|
94
1202
|
* @param info - Progress information including percentage and byte counts.
|
|
@@ -106,14 +1214,19 @@ interface ShipClientOptions {
|
|
|
106
1214
|
*/
|
|
107
1215
|
timeout?: number | undefined;
|
|
108
1216
|
/**
|
|
109
|
-
* When true,
|
|
110
|
-
*
|
|
111
|
-
*
|
|
1217
|
+
* When true, the client authenticates with the first-party cookie session
|
|
1218
|
+
* (`AuthMethod.SESSION`) — requests are sent with `credentials: 'include'`
|
|
1219
|
+
* and carry no `Authorization` header. For browser apps living on the
|
|
1220
|
+
* platform's own domains, where the API sets HTTP-only session cookies.
|
|
1221
|
+
* Mutually exclusive with `token`: a client holds one identity.
|
|
112
1222
|
*
|
|
113
|
-
*
|
|
114
|
-
*
|
|
1223
|
+
* Requires a cookie-capable transport. Browsers send first-party cookies
|
|
1224
|
+
* natively; in Node, pair it with an injected `fetch` that forwards the
|
|
1225
|
+
* session cookie (the default fetch has no cookie jar, and `session: true`
|
|
1226
|
+
* deliberately suppresses the `SHIP_TOKEN` fallback — a session client
|
|
1227
|
+
* never silently switches identity).
|
|
115
1228
|
*/
|
|
116
|
-
|
|
1229
|
+
session?: boolean | undefined;
|
|
117
1230
|
/**
|
|
118
1231
|
* Custom `fetch` implementation. Defaults to `globalThis.fetch`.
|
|
119
1232
|
*
|
|
@@ -123,14 +1236,19 @@ interface ShipClientOptions {
|
|
|
123
1236
|
*/
|
|
124
1237
|
fetch?: Fetch | undefined;
|
|
125
1238
|
/**
|
|
126
|
-
*
|
|
127
|
-
*
|
|
1239
|
+
* Caller identifier for multi-tenant orchestration — sent as `X-Caller`
|
|
1240
|
+
* on every request. Validated at construction against the shared `CALLER`
|
|
1241
|
+
* shape (`validateCaller` in `@shipstatic/types`: alphanumeric, dots,
|
|
1242
|
+
* underscores, hyphens; max 128 chars) — a value the API would silently
|
|
1243
|
+
* drop throws here instead.
|
|
128
1244
|
*
|
|
129
|
-
* Used by orchestrators (e.g.
|
|
130
|
-
*
|
|
131
|
-
* shared IP.
|
|
132
|
-
*
|
|
133
|
-
*
|
|
1245
|
+
* Used by orchestrators (e.g. the hosted MCP Worker processing many end
|
|
1246
|
+
* users from one egress) so the API's rate-limit buckets key per caller
|
|
1247
|
+
* rather than per shared IP. Instance identity metadata, like the
|
|
1248
|
+
* credential: one client speaks for one end user, and every write the
|
|
1249
|
+
* client makes is bucketed the same way. **Programmatic-only by design**
|
|
1250
|
+
* — there is no `--caller` CLI flag because every CLI invocation belongs
|
|
1251
|
+
* to one human; a per-tenant rate-limit bucket would defeat the purpose.
|
|
134
1252
|
*
|
|
135
1253
|
* Distinct from `via` (the client identifier — `'cli'`, `'sdk'`, `'web'`,
|
|
136
1254
|
* `'git'`, etc.). `via` is for analytics/origin tracking and is
|
|
@@ -197,13 +1315,15 @@ declare class SimpleEvents {
|
|
|
197
1315
|
*/
|
|
198
1316
|
|
|
199
1317
|
interface ApiHttpOptions extends ShipClientOptions {
|
|
200
|
-
|
|
1318
|
+
/** Resolves the credential slot per request — async so token providers can mint/refresh. */
|
|
1319
|
+
getAuthHeaders: () => Record<string, string> | Promise<Record<string, string>>;
|
|
201
1320
|
createDeployBody: DeployBodyCreator;
|
|
202
1321
|
}
|
|
203
1322
|
declare class ApiHttp extends SimpleEvents {
|
|
204
1323
|
private readonly apiUrl;
|
|
205
1324
|
private readonly getAuthHeadersCallback;
|
|
206
|
-
private readonly
|
|
1325
|
+
private readonly session;
|
|
1326
|
+
private readonly caller;
|
|
207
1327
|
private readonly timeout;
|
|
208
1328
|
private readonly fetch;
|
|
209
1329
|
private readonly createDeployBody;
|
|
@@ -253,8 +1373,7 @@ declare class ApiHttp extends SimpleEvents {
|
|
|
253
1373
|
createToken(ttl?: number, labels?: string[]): Promise<TokenCreateResponse>;
|
|
254
1374
|
listTokens(): Promise<TokenListResponse>;
|
|
255
1375
|
removeToken(token: string): Promise<void>;
|
|
256
|
-
|
|
257
|
-
getAccount(): Promise<Account>;
|
|
1376
|
+
getAccount(): Promise<AccountGetResponse>;
|
|
258
1377
|
getLimits(): Promise<PlatformLimits>;
|
|
259
1378
|
ping(): Promise<boolean>;
|
|
260
1379
|
checkSPA(files: StaticFile[], options?: ApiDeployOptions): Promise<boolean>;
|
|
@@ -277,10 +1396,14 @@ interface ResourceContext {
|
|
|
277
1396
|
interface DeploymentResourceContext extends ResourceContext {
|
|
278
1397
|
processInput: (input: DeployInput, options: DeploymentOptions) => Promise<StaticFile[]>;
|
|
279
1398
|
clientDefaults?: ShipClientOptions;
|
|
280
|
-
hasAuth?: () => boolean;
|
|
281
1399
|
}
|
|
282
1400
|
/**
|
|
283
1401
|
* Upload deployment resource with all CRUD operations.
|
|
1402
|
+
*
|
|
1403
|
+
* There is no client-side auth branching: an upload from a credential-less
|
|
1404
|
+
* client simply carries no `Authorization` header, and the API grants the
|
|
1405
|
+
* public-account agent identity per request (claim URL + expiry on the
|
|
1406
|
+
* response). The SDK stays a transparent pipe either way.
|
|
284
1407
|
*/
|
|
285
1408
|
declare function createDeploymentResource(ctx: DeploymentResourceContext): DeploymentResource;
|
|
286
1409
|
/**
|
|
@@ -312,7 +1435,7 @@ declare abstract class Ship$1 {
|
|
|
312
1435
|
private readonly clientOptions;
|
|
313
1436
|
private initPromise;
|
|
314
1437
|
protected platformLimits: PlatformLimits | null;
|
|
315
|
-
private
|
|
1438
|
+
private credential;
|
|
316
1439
|
constructor(options?: ShipClientOptions);
|
|
317
1440
|
protected abstract processInput(input: DeployInput, options: DeploymentOptions): Promise<StaticFile[]>;
|
|
318
1441
|
protected abstract getDeployBodyCreator(): DeployBodyCreator;
|
|
@@ -333,7 +1456,7 @@ declare abstract class Ship$1 {
|
|
|
333
1456
|
/**
|
|
334
1457
|
* Get current account information (convenience shortcut to `ship.account.get()`).
|
|
335
1458
|
*/
|
|
336
|
-
whoami(): Promise<
|
|
1459
|
+
whoami(): Promise<AccountGetResponse>;
|
|
337
1460
|
/**
|
|
338
1461
|
* Get platform limits (max file size, file count, total size).
|
|
339
1462
|
* Reuses the response fetched during initialization. Per-instance state —
|
|
@@ -352,50 +1475,40 @@ declare abstract class Ship$1 {
|
|
|
352
1475
|
*/
|
|
353
1476
|
clearHeaders(): void;
|
|
354
1477
|
/**
|
|
355
|
-
* Sets the deploy token
|
|
356
|
-
*
|
|
357
|
-
*
|
|
1478
|
+
* Sets the client token — any platform token (API key, deploy token, OAuth
|
|
1479
|
+
* access token) or a {@link TokenProvider} invoked per request. Replaces
|
|
1480
|
+
* whatever credential the client held before.
|
|
1481
|
+
* @param token A platform token, sent verbatim, or a provider function
|
|
358
1482
|
*/
|
|
359
|
-
|
|
1483
|
+
setToken(token: string | TokenProvider): void;
|
|
360
1484
|
/**
|
|
361
|
-
*
|
|
362
|
-
*
|
|
363
|
-
*
|
|
1485
|
+
* Resolve the credential slot into request headers. Async because a
|
|
1486
|
+
* provider may mint or refresh its token per request.
|
|
1487
|
+
*
|
|
1488
|
+
* Anonymity requires proven absence of credentials: a configured provider
|
|
1489
|
+
* that yields nothing is an error — the request fails typed rather than
|
|
1490
|
+
* silently proceeding as an anonymous public deploy. Empty-string
|
|
1491
|
+
* normalization at the constructor is the same invariant's boundary
|
|
1492
|
+
* condition: `''` is absence of intent, so it never reaches this point.
|
|
364
1493
|
*/
|
|
365
|
-
setApiKey(key: string): void;
|
|
366
1494
|
private getAuthHeaders;
|
|
367
|
-
/**
|
|
368
|
-
* Check whether authentication credentials are configured.
|
|
369
|
-
* Used by resources to fail fast (or trigger the agent-token fallback) when
|
|
370
|
-
* auth is required.
|
|
371
|
-
*/
|
|
372
|
-
private hasAuth;
|
|
373
1495
|
}
|
|
374
1496
|
|
|
375
1497
|
/**
|
|
376
1498
|
* @file Cross-platform configuration helpers.
|
|
377
1499
|
*
|
|
378
|
-
*
|
|
1500
|
+
* One pure helper used by the deployment resource:
|
|
379
1501
|
*
|
|
380
|
-
* - `resolveConfig(options)` — applies the API-URL default. The Node Ship
|
|
381
|
-
* calls this after merging env vars under the user's options; the Browser
|
|
382
|
-
* Ship calls it directly (no ambient sources).
|
|
383
1502
|
* - `mergeDeployOptions(perCallOptions, clientDefaults)` — overlays
|
|
384
1503
|
* instance-level defaults under per-call overrides for a single deploy.
|
|
385
1504
|
*
|
|
386
|
-
*
|
|
387
|
-
*
|
|
388
|
-
*
|
|
389
|
-
*
|
|
390
|
-
*
|
|
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.
|
|
391
1510
|
*/
|
|
392
1511
|
|
|
393
|
-
/**
|
|
394
|
-
* Apply the API-URL default and project the credential triplet into a
|
|
395
|
-
* `ResolvedConfig` shape. Optional fields are omitted (rather than set to
|
|
396
|
-
* `undefined`) so spread merges downstream behave predictably.
|
|
397
|
-
*/
|
|
398
|
-
declare function resolveConfig(options?: ShipClientOptions): ResolvedConfig;
|
|
399
1512
|
/**
|
|
400
1513
|
* Overlay client-level defaults under per-call deploy options.
|
|
401
1514
|
*
|
|
@@ -663,9 +1776,9 @@ declare function processFilesForNode(paths: string[], options?: DeploymentOption
|
|
|
663
1776
|
*
|
|
664
1777
|
* The Node-side `Ship` adds two things on top of the base class:
|
|
665
1778
|
* 1. Environment detection — refuses to construct outside Node.
|
|
666
|
-
* 2. `
|
|
667
|
-
*
|
|
668
|
-
* arguments win over env vars.
|
|
1779
|
+
* 2. `SHIP_TOKEN` / `SHIP_API_URL` env-var resolution as the universal
|
|
1780
|
+
* "process boundary" credential source — the industry's one-token
|
|
1781
|
+
* convention. Constructor arguments win over env vars.
|
|
669
1782
|
*
|
|
670
1783
|
* The SDK does NOT read `~/.shiprc` or `package.json` `"ship"` keys — that's
|
|
671
1784
|
* the CLI's job (see `cli/shiprc.ts`). Keeping file resolution out of the SDK
|
|
@@ -679,13 +1792,13 @@ declare function processFilesForNode(paths: string[], options?: DeploymentOption
|
|
|
679
1792
|
*
|
|
680
1793
|
* @example
|
|
681
1794
|
* ```typescript
|
|
682
|
-
* // Authenticated — explicit API key
|
|
683
|
-
* const ship = new Ship({
|
|
1795
|
+
* // Authenticated — explicit token (API key, deploy token, or OAuth bearer)
|
|
1796
|
+
* const ship = new Ship({ token: 'ship-xxxx' });
|
|
684
1797
|
*
|
|
685
|
-
* // Authenticated — picks up
|
|
1798
|
+
* // Authenticated — picks up SHIP_TOKEN from env
|
|
686
1799
|
* const ship = new Ship({});
|
|
687
1800
|
*
|
|
688
|
-
* // Anonymous public deploy — works when neither constructor nor env provides
|
|
1801
|
+
* // Anonymous public deploy — works when neither constructor nor env provides a token
|
|
689
1802
|
* const ship = new Ship({});
|
|
690
1803
|
* await ship.deploy('./dist');
|
|
691
1804
|
* ```
|
|
@@ -707,4 +1820,4 @@ declare class Ship extends Ship$1 {
|
|
|
707
1820
|
protected getDeployBodyCreator(): DeployBodyCreator;
|
|
708
1821
|
}
|
|
709
1822
|
|
|
710
|
-
export { type ApiDeployOptions, ApiHttp, type ApiHttpOptions, type DeployBody, type DeployBodyContext, type DeployBodyCreator, type DeployFile, type DeploymentOptions, type DeploymentResourceContext, type ExecutionEnvironment, type Fetch, JUNK_DIRECTORIES, type MD5Result, type ResourceContext, Ship, type ShipClientOptions, type ShipEvents, __setTestEnvironment, allValidFilesReady, calculateMD5, createAccountResource, createDeploymentResource, createDomainResource, createTokenResource, Ship as default, filterJunk, formatFileSize, getENV, getValidFiles, mergeDeployOptions, optimizeDeployPaths, pluralize, processFilesForNode,
|
|
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 ProgressInfo, type ResourceContext, type SPACheckRequest, type SPACheckResponse, SPA_DEFAULT_CONFIG, Ship, type ShipClientOptions, ShipError, type ShipEvents, type StaticFile, type TokenCreateResponse, TokenKind, type TokenKindType, type TokenListItem, type TokenListResponse, type TokenProvider, type TokenResource, UNBUILT_PROJECT_MARKERS, UNSAFE_FILENAME_CHARS, type UploadedFile, type UserVisibleActivityEvent, type ValidatableFile, type ValidationIssue, __setTestEnvironment, allValidFilesReady, calculateMD5, classifyToken, createAccountResource, createDeploymentResource, createDomainResource, createTokenResource, Ship as default, deserializeLabels, extractSubdomain, filterJunk, formatFileSize, generateDeploymentUrl, generateDomainUrl, getENV, getValidFiles, hasUnbuiltMarker, hasUnsafeChars, isBlockedExtension, isCustomDomain, isDeployment, isPlatformDomain, isShipError, mergeDeployOptions, optimizeDeployPaths, pluralize, processFilesForNode, serializeLabels, validateApiKey, validateApiUrl, validateCaller, validateDeployFile, validateDeployPath, validateDeployToken, validateFileName, validateFiles, validatePassword, validateToken };
|