@shipstatic/ship 2.0.0-beta.9 → 2.1.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/dist/index.d.cts CHANGED
@@ -12,6 +12,28 @@ declare const DeploymentStatus: {
12
12
  readonly DELETING: "deleting";
13
13
  };
14
14
  type DeploymentStatusType = (typeof DeploymentStatus)[keyof typeof DeploymentStatus];
15
+ /**
16
+ * Which client made a deployment — the origin-tracking vocabulary.
17
+ *
18
+ * A closed set with many authors: the CLI, the SDK, the dashboard, both MCP
19
+ * transports, the GitHub Action, the n8n node and the VS Code extension each
20
+ * name themselves here. It lived in the API's config until 2026-08-06, where
21
+ * being server-side made it unenforceable in the one direction that matters —
22
+ * every client wrote a bare string, and a value outside the set was **silently
23
+ * dropped** by the server, so a typo did not fail anywhere. It stopped
24
+ * recording where deploys came from and said nothing.
25
+ */
26
+ declare const DeploymentVia: {
27
+ readonly WEB: "web";
28
+ readonly SDK: "sdk";
29
+ readonly CLI: "cli";
30
+ readonly MCP: "mcp";
31
+ readonly GIT: "git";
32
+ readonly N8N: "n8n";
33
+ readonly GPT: "gpt";
34
+ readonly VSC: "vsc";
35
+ };
36
+ type DeploymentViaType = (typeof DeploymentVia)[keyof typeof DeploymentVia];
15
37
  /**
16
38
  * Core deployment object - used in both API responses and SDK
17
39
  */
@@ -32,7 +54,15 @@ interface Deployment {
32
54
  readonly password: boolean;
33
55
  /** Labels for categorization and filtering (lowercase, alphanumeric with separators). Always present, empty array when none. */
34
56
  labels: string[];
35
- /** The client/tool used to create this deployment (e.g., 'web', 'sdk', 'cli'), null if unknown */
57
+ /**
58
+ * The client/tool that created this deployment, null if unknown.
59
+ *
60
+ * Deliberately wider than {@link DeploymentViaType}: this is stored data,
61
+ * and rows predate the vocabulary being closed. Narrowing the ENTITY would
62
+ * be a claim about every row already in the database; narrowing the
63
+ * REQUEST option ({@link DeploymentUploadOptions.via}) is a claim about
64
+ * what a client may send, which is ours to make.
65
+ */
36
66
  readonly via: string | null;
37
67
  /** Unix timestamp (seconds) when deployment was created */
38
68
  readonly created: number;
@@ -49,62 +79,6 @@ interface DeploymentCreateResponse extends Deployment {
49
79
  /** Claim URL for public deployments. Present when deployed without credentials. */
50
80
  readonly claim?: string;
51
81
  }
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
82
  /**
109
83
  * The half of a list response that is identical on every list.
110
84
  *
@@ -123,6 +97,28 @@ interface ListResponse {
123
97
  /** Opaque cursor from this page; `null` on the last page. */
124
98
  cursor: string | null;
125
99
  }
100
+ /**
101
+ * Pagination options for every list endpoint. The response's `cursor` feeds
102
+ * the next request; a `null` cursor means the last page. Omitting both
103
+ * returns the server's default first page.
104
+ *
105
+ * A list answers `{ <collection>, cursor }` and nothing else — `cursor`
106
+ * carries the entire has-more signal, so no redundant boolean, and no
107
+ * `total`. **A count is an aggregate over a collection, not a property of a
108
+ * page:** including one makes every read pay for a full scan it did not ask
109
+ * for, which is precisely the cost keyset pagination exists to avoid.
110
+ *
111
+ * Counts therefore live on the summary resource that owns them —
112
+ * `GET /account` (`usage`) for a caller's own totals, `GET /admin/stats` for
113
+ * platform-wide ones. Ask for a count when you want a count; ask for a page
114
+ * when you want a page.
115
+ */
116
+ interface ListOptions {
117
+ /** Maximum number of items to return in one page. */
118
+ limit?: number;
119
+ /** Opaque cursor from the previous page's response. */
120
+ cursor?: string;
121
+ }
126
122
  /**
127
123
  * Response for listing deployments
128
124
  */
@@ -324,10 +320,33 @@ interface DomainRecordsResponse {
324
320
  * API would reject the same value the same way.
325
321
  */
326
322
  declare const IDEMPOTENCY_KEY_CONSTRAINTS: {
323
+ /**
324
+ * HTTP header name. Here for the same reason {@link CALLER.HEADER} is: a
325
+ * wire header has two ends, and the package that owns the value's format
326
+ * is the only place both ends can read its name from.
327
+ */
328
+ readonly HEADER: "Idempotency-Key";
327
329
  readonly MAX_LENGTH: 256;
328
330
  /** How long a stored 201 stays replayable. */
329
331
  readonly WINDOW_SECONDS: number;
330
332
  };
333
+ /**
334
+ * Normalize a `via` value from any transport — trimmed, lowercased, and a
335
+ * member of {@link DeploymentVia}, or `undefined`.
336
+ *
337
+ * A format rule by this package's own test: a client can decide offline
338
+ * whether a value is well-formed, and the API reaches the same verdict on the
339
+ * same input. It lived server-side until 2026-08-06, which meant clients could
340
+ * only learn their label was unusable by noticing analytics had gone quiet.
341
+ *
342
+ * **Not knowing your `via` is not an error** — an unrecognized value yields
343
+ * `undefined` rather than throwing, because origin tracking is telemetry and a
344
+ * deploy must never fail over it. A caller that has an honest default should
345
+ * prefer it (`normalizeVia(process.env.SHIP_VIA) ?? DeploymentVia.CLI`): the
346
+ * deploy really did come from the CLI, so recording that beats recording
347
+ * nothing.
348
+ */
349
+ declare function normalizeVia(value: unknown): DeploymentViaType | undefined;
331
350
  /**
332
351
  * Validate an idempotency key, returning the trimmed value or `undefined`
333
352
  * when none was supplied. Throws {@link ShipError.validation} when the value
@@ -570,6 +589,97 @@ interface AccountOverrides {
570
589
  /** Override for maximum total deployment size in bytes */
571
590
  totalSize?: number;
572
591
  }
592
+ /**
593
+ * Every path the public API answers on, declared once.
594
+ *
595
+ * The URL surface was written out in four places — the API's mounts, the
596
+ * SDK's client, the dashboard's client, and the post-deploy smoke — so a
597
+ * rename meant finding all four. The first three now read this table.
598
+ *
599
+ * The smoke (`cloudflare/api/smoke.mjs`) deliberately still spells its own:
600
+ * five of its nine paths are `/admin/*`, which this table excludes by
601
+ * design, and splitting one list between a registry and literals reads worse
602
+ * than keeping it uniform.
603
+ *
604
+ * **What this guarantees, exactly.** Collection paths are mounted from here,
605
+ * so producer and consumer cannot diverge. Item paths are declared here and
606
+ * consumed by clients, but the API spells them relative to their mount
607
+ * (`/:deployment/config`), so the table does not *generate* them — it is
608
+ * held to them by `api/tests/architecture/api-paths.test.ts`, which fails if
609
+ * any entry names a path no route answers. Some entries have no client yet
610
+ * (`DEPLOYMENT_CONFIG`, `DOMAIN_PROPAGATION` — endpoints the SDK
611
+ * deliberately does not reach); the fence is what keeps those honest rather
612
+ * than merely asserted.
613
+ *
614
+ * **The operator surface is deliberately absent.** `/admin/*` paths belong
615
+ * to `web/my`, for the same reason its row types do: this package is
616
+ * published, and the operator surface is not public (see `CLAUDE.md`, "Admin
617
+ * types"). A path here is a promise to every npm consumer; `/admin` is a
618
+ * promise to one dashboard.
619
+ *
620
+ * Item paths are functions rather than templates so the key is interpolated
621
+ * in one place, encoded the same way by every caller.
622
+ */
623
+ declare const API_PATHS: {
624
+ readonly DEPLOYMENTS: "/deployments";
625
+ readonly DEPLOYMENT: (deployment: string) => string;
626
+ readonly DEPLOYMENT_CONFIG: (deployment: string) => string;
627
+ readonly DOMAINS: "/domains";
628
+ readonly DOMAIN: (domain: string) => string;
629
+ readonly DOMAIN_VERIFY: (domain: string) => string;
630
+ readonly DOMAIN_DNS: (domain: string) => string;
631
+ readonly DOMAIN_RECORDS: (domain: string) => string;
632
+ readonly DOMAIN_SHARE: (domain: string) => string;
633
+ readonly DOMAIN_PROPAGATION: (domain: string) => string;
634
+ readonly DOMAINS_VALIDATE: "/domains/validate";
635
+ readonly TOKENS: "/tokens";
636
+ readonly TOKEN: (token: string) => string;
637
+ readonly ACCOUNT: "/account";
638
+ readonly ACCOUNT_KEY: "/account/key";
639
+ readonly ACCOUNT_CLAIM: "/account/claim";
640
+ readonly ACTIVITIES: "/activities";
641
+ readonly LABELS: "/labels";
642
+ readonly LIMITS: "/limits";
643
+ readonly PING: "/ping";
644
+ readonly SETUP: "/setup";
645
+ readonly SPA_CHECK: "/spa-check";
646
+ readonly UPLOAD: "/upload";
647
+ };
648
+ /**
649
+ * The deploy request's multipart field names — the other half of the wire
650
+ * surface beside {@link API_PATHS}. `POST /deployments` (and the first-party
651
+ * `/upload`) is multipart/form-data, and these are the names the API reads.
652
+ *
653
+ * Declared once because the body has three independent WRITERS — the SDK's
654
+ * Node and browser body builders, and the n8n community node's hand-rolled
655
+ * client (which cannot import this under n8n Cloud's zero-dependency rule,
656
+ * and fences its restated copy instead) — and until this export every writer
657
+ * restated the strings the API parses, with nothing comparing them.
658
+ *
659
+ * `FILES` carries one entry per file (the API reads it with `getAll`); every
660
+ * other field is single. The `@internal` flags are serialized as the literal
661
+ * string `'true'` and belong to first-party surfaces only.
662
+ */
663
+ declare const DEPLOY_FIELDS: {
664
+ /** One entry per file — read with `getAll`. */
665
+ readonly FILES: "files[]";
666
+ /** JSON array of MD5 hex digests, index-aligned with `FILES`. */
667
+ readonly CHECKSUMS: "checksums";
668
+ /** JSON array of label strings. */
669
+ readonly LABELS: "labels";
670
+ /** The deploying surface's {@link DeploymentVia} member. */
671
+ readonly VIA: "via";
672
+ /** Plaintext password — the API hashes it server-side. */
673
+ readonly PASSWORD: "password";
674
+ /** @internal Server-processing flag — first-party `/upload` only. */
675
+ readonly BUILD: "build";
676
+ /** @internal Server-processing flag — first-party `/upload` only. */
677
+ readonly PRERENDER: "prerender";
678
+ /** @internal Server-processing flag — first-party `/upload` only. */
679
+ readonly SPA: "spa";
680
+ /** @internal reCAPTCHA proof — `web/www`'s public uploader only. */
681
+ readonly CAPTCHA: "captcha";
682
+ };
573
683
  /**
574
684
  * All possible error types in the ShipStatic platform.
575
685
  *
@@ -602,6 +712,17 @@ declare const ErrorType: {
602
712
  readonly Business: "business_logic_error";
603
713
  /** API server error (500). Generic server-side fault. */
604
714
  readonly Api: "internal_server_error";
715
+ /**
716
+ * The platform is closed for maintenance (503). A deliberate operator
717
+ * state, not a fault — nothing errored; the API is refusing work on
718
+ * purpose, and deployed sites keep serving throughout.
719
+ *
720
+ * Distinct from `Api` at 503, which the platform already uses for a
721
+ * dependency that failed (moderation unavailable). A consumer has to tell
722
+ * "we closed the door" from "something broke": the two get opposite words
723
+ * and opposite retry behaviour.
724
+ */
725
+ readonly Maintenance: "maintenance";
605
726
  /** Network/connection error. Client-side only — set by HTTP clients on fetch failure; never produced server-side. */
606
727
  readonly Network: "network_error";
607
728
  /** Operation was cancelled. Client-side only — set on `AbortSignal` abort; never produced server-side. */
@@ -668,7 +789,8 @@ declare class ShipError extends Error {
668
789
  * Routing:
669
790
  * - Already a `ShipError` → returned as-is (caller's intent preserved)
670
791
  * - `AbortError` → `ShipError.cancelled(...)`
671
- * - `TypeError` whose message mentions "fetch" → `ShipError.network(...)`
792
+ * - A transport failure → `ShipError.network(...)` — see `isTransportFailure`
793
+ * for what each runtime offers as evidence
672
794
  * - Any other `Error` → `ShipError(Api, ...)` (no HTTP status — fetch never reached the server)
673
795
  * - Anything else (string, undefined, etc.) → `ShipError(Api, ...)`
674
796
  *
@@ -701,6 +823,16 @@ declare class ShipError extends Error {
701
823
  static file(message: string, details?: unknown): ShipError;
702
824
  static config(message: string, details?: unknown): ShipError;
703
825
  static api(message: string, status?: number, details?: unknown): ShipError;
826
+ /**
827
+ * The platform is closed for maintenance (503).
828
+ *
829
+ * `message` is REQUIRED and has no default here. The API is the only
830
+ * producer of that sentence, and a default in this file would be a second
831
+ * owner of one fact — see CLAUDE.md, "The Constellation Law" (stopping
832
+ * rule). It is also the one factory whose status is fixed rather than
833
+ * defaulted: a maintenance refusal is 503 or it is not this error.
834
+ */
835
+ static maintenance(message: string, details?: unknown): ShipError;
704
836
  /**
705
837
  * The caller is at fault — by HTTP's own definition of a 4xx, or by a type
706
838
  * that is client-attributable without ever having a status (`Config`,
@@ -775,6 +907,28 @@ declare const BLOCKED_EXTENSIONS: ReadonlySet<string>;
775
907
  * isBlockedExtension('README') // false
776
908
  */
777
909
  declare function isBlockedExtension(filename: string): boolean;
910
+ /**
911
+ * The `accept` attribute value for a browser file picker offering web files.
912
+ *
913
+ * **This is a hint, never a rule.** `BLOCKED_EXTENSIONS` is the platform's
914
+ * gate and the only thing that decides what may be hosted; this constant
915
+ * decides what a *file dialog* shows first. The two are not two halves of one
916
+ * policy, and this one must never be consulted to accept or reject a file.
917
+ *
918
+ * The distinction is structural, not stylistic. `accept` can express only an
919
+ * allowlist, while the platform's rule is a blocklist — so this list is
920
+ * necessarily *narrower* than what the platform hosts, and reading it as
921
+ * authority would reject files the platform serves happily. It is also not
922
+ * enforcement in the browser's own terms: every file dialog offers an
923
+ * all-files escape, and **drag-and-drop ignores `accept` entirely**. The
924
+ * dropzone and the picker must reach the same verdict on the same files, and
925
+ * they do — because the verdict is `validateFiles`, downstream of both.
926
+ *
927
+ * Kept beside `BLOCKED_EXTENSIONS` so one file holds both, which is what lets
928
+ * `tests/validation-constants.test.ts` fence the invariant that matters: the
929
+ * picker must never offer a file the platform will refuse.
930
+ */
931
+ declare const WEB_FILE_ACCEPT: string;
778
932
  /**
779
933
  * Characters that are unsafe in filenames for static hosting.
780
934
  *
@@ -855,30 +1009,35 @@ declare const AuthMethod: {
855
1009
  };
856
1010
  type AuthMethodType = (typeof AuthMethod)[keyof typeof AuthMethod];
857
1011
  /**
858
- * Shape constants for API keys (`ship-{64 hex chars}`).
1012
+ * Shape constants for API keys (`ship-{32 hex chars}`).
859
1013
  * Single source of truth used by validation utilities and auth middleware.
860
1014
  */
861
1015
  declare const API_KEY: {
862
1016
  /** Prefix that identifies an API key. */
863
1017
  readonly PREFIX: "ship-";
864
1018
  /** Number of hex characters following the prefix. */
865
- readonly HEX_LENGTH: 64;
866
- /** Total length of an API key including prefix (`PREFIX.length + HEX_LENGTH = 69`). */
867
- readonly TOTAL_LENGTH: 69;
1019
+ readonly HEX_LENGTH: 32;
1020
+ /** Total length of an API key including prefix (`PREFIX.length + HEX_LENGTH = 37`). */
1021
+ readonly TOTAL_LENGTH: 37;
868
1022
  /** Number of trailing characters used to display a redacted hint (e.g. last 4). */
869
1023
  readonly HINT_LENGTH: 4;
870
1024
  };
871
1025
  /**
872
- * Shape constants for deploy tokens (`deploy-{64 hex chars}`).
1026
+ * Shape constants for deploy tokens (`deploy-{32 hex chars}`).
873
1027
  * Single source of truth used by validation utilities and auth middleware.
1028
+ *
1029
+ * Deliberately the same width as `API_KEY`: both are minted by one generator
1030
+ * and classified by prefix alone, so a length that differed between them
1031
+ * would be a second thing to know about a credential whose prefix already
1032
+ * says what it is.
874
1033
  */
875
1034
  declare const DEPLOY_TOKEN: {
876
1035
  /** Prefix that identifies a deploy token. */
877
1036
  readonly PREFIX: "deploy-";
878
1037
  /** Number of hex characters following the prefix. */
879
- readonly HEX_LENGTH: 64;
880
- /** Total length of a deploy token including prefix (`PREFIX.length + HEX_LENGTH = 71`). */
881
- readonly TOTAL_LENGTH: 71;
1038
+ readonly HEX_LENGTH: 32;
1039
+ /** Total length of a deploy token including prefix (`PREFIX.length + HEX_LENGTH = 39`). */
1040
+ readonly TOTAL_LENGTH: 39;
882
1041
  };
883
1042
  /**
884
1043
  * Shape constants for caller identifiers (the `X-Caller` instance-identity
@@ -947,6 +1106,26 @@ declare const SPA_DEFAULT_CONFIG: {
947
1106
  readonly destination: "/index.html";
948
1107
  }];
949
1108
  };
1109
+ /**
1110
+ * The `/spa-check` pre-flight's client-side envelope: which file is the
1111
+ * check's subject, and how large it may be before a client skips the call.
1112
+ *
1113
+ * One fact with three holders until this export — the API's config declared
1114
+ * the cap, the SDK's `checkSPA` hardcoded `100 * 1024`, and prose restated
1115
+ * "100KB". `INDEX_FILE` is the selection rule (the file whose content rides
1116
+ * `SPACheckRequest.index`), restated by every client that builds the request.
1117
+ *
1118
+ * Neither member is a validation boundary: a client over the cap simply
1119
+ * skips the pre-flight, because the server answers an oversized index
1120
+ * `isSPA: false` anyway. A consumer that cannot import this (n8n) needs no
1121
+ * size copy at all — outcome parity is the server's, not the client's.
1122
+ */
1123
+ declare const SPA_CHECK_CONSTRAINTS: {
1124
+ /** The file whose content is the check's subject. */
1125
+ readonly INDEX_FILE: "index.html";
1126
+ /** Skip the pre-flight above this size — the server would answer false. */
1127
+ readonly MAX_INDEX_BYTES: number;
1128
+ };
950
1129
  /**
951
1130
  * Assert that a ship.json file is *syntactically* loadable. Syntax only —
952
1131
  * never schema.
@@ -1071,6 +1250,50 @@ interface StaticFile {
1071
1250
  }
1072
1251
  /** Default API URL if not otherwise configured. */
1073
1252
  declare const DEFAULT_API = "https://api.shipstatic.com";
1253
+ /**
1254
+ * The Node SDK's ambient configuration pair — the ONLY environment variables
1255
+ * the SDK reads, and therefore the COMPLETE list an embedding host must
1256
+ * scrub (per `npm/ship`'s strict-isolation contract, scrubbing is the host's
1257
+ * job, not the SDK's). A host that derives its scrub from this object's
1258
+ * values — as the VS Code extension's child-process env block does — picks
1259
+ * up a grown contract at the next pin bump instead of by remembered prose.
1260
+ *
1261
+ * Browser builds read no environment at all, and the CLI-only variables
1262
+ * (`SHIP_PASSWORD`, `SHIP_VIA`) are deliberately NOT here: they are the
1263
+ * CLI's operational levers, not the SDK's ambient contract — see
1264
+ * `npm/ship/CLAUDE.md`, "CLI-only env vars".
1265
+ */
1266
+ declare const SHIP_ENV: {
1267
+ /** The one credential slot — any platform token. */
1268
+ readonly TOKEN: "SHIP_TOKEN";
1269
+ /** The API endpoint override. */
1270
+ readonly API_URL: "SHIP_API_URL";
1271
+ };
1272
+ /**
1273
+ * Where a human creates an API key — the console deep link quoted by every
1274
+ * surface that teaches authentication (the CLI's config wizard, the VS Code
1275
+ * and n8n listings, the n8n rate-limit hint and credential copy). Written
1276
+ * out in five files across three repos until this export.
1277
+ *
1278
+ * Production-branded by design: published artifacts name the product, never
1279
+ * an environment (root `CLAUDE.md`, "Environment-Aware URLs").
1280
+ */
1281
+ declare const MY_API_KEY_URL = "https://my.shipstatic.com/api-key";
1282
+ /**
1283
+ * How long an anonymous deployment lives before it expires.
1284
+ *
1285
+ * The lifetime of the public tier, and one fact with several readers. The API
1286
+ * stamps a deployment's `expires` from it and gives a claim code exactly the
1287
+ * same window — a live site with a dead claim link is a coherence bug, so the
1288
+ * two are one constant rather than two that agree. Both MCP transports quote
1289
+ * the duration in prose an agent reads, and derive it from here rather than
1290
+ * writing it out, which they did in eight places until this export existed.
1291
+ *
1292
+ * Seconds, spelled in the name: this platform has both second- and
1293
+ * millisecond-valued durations, and the pair is only safe when each says which
1294
+ * it is.
1295
+ */
1296
+ declare const PUBLIC_DEPLOYMENT_TTL_SECONDS: number;
1074
1297
  /**
1075
1298
  * Universal deploy input — the union of every shape the SDK accepts.
1076
1299
  *
@@ -1089,8 +1312,12 @@ type DeployInput = File[] | string | string[];
1089
1312
  interface DeploymentUploadOptions {
1090
1313
  /** Optional labels for categorization and filtering */
1091
1314
  labels?: string[];
1092
- /** Client identifier (e.g., 'cli', 'sdk', 'web') */
1093
- via?: string;
1315
+ /**
1316
+ * Which client is making this deploy. Closed, because the server silently
1317
+ * ignores anything outside the set — so an unchecked string turned a typo
1318
+ * into missing analytics rather than an error. See {@link DeploymentVia}.
1319
+ */
1320
+ via?: DeploymentViaType;
1094
1321
  /**
1095
1322
  * Optional password that protects this deployment.
1096
1323
  *
@@ -1122,36 +1349,14 @@ interface DeploymentUploadOptions {
1122
1349
  *
1123
1350
  * **Agents are the audience.** A human notices a duplicate; an automated
1124
1351
  * 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.
1352
+ * commit sha, a uuid minted before the first try — never one minted fresh
1353
+ * on each retry, which would defeat the point.
1127
1354
  *
1128
1355
  * The replay is per-caller, and it stores successes only: a failed deploy
1129
1356
  * retries fresh under the same key.
1130
1357
  */
1131
1358
  idempotencyKey?: string;
1132
1359
  }
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
1360
  /**
1156
1361
  * What a caller may change on an existing deployment.
1157
1362
  *
@@ -1569,8 +1774,13 @@ interface DeployBodyContext {
1569
1774
  * `LABEL_CONSTRAINTS` (length and pattern, lowercased+trimmed).
1570
1775
  */
1571
1776
  labels?: string[];
1572
- /** Client identifier (`cli`, `sdk`, `web`). */
1573
- via?: string;
1777
+ /**
1778
+ * Which client is deploying — the same closed vocabulary the public option
1779
+ * carries, not a second `string`. This context receives an already-narrowed
1780
+ * value and passed it on widened, which made the narrowing stop one seam
1781
+ * short of the wire.
1782
+ */
1783
+ via?: DeploymentViaType;
1574
1784
  /**
1575
1785
  * Optional plaintext password to protect the deployment.
1576
1786
  * Length: `PASSWORD_CONSTRAINTS.MIN_LENGTH` to `PASSWORD_CONSTRAINTS.MAX_LENGTH`
@@ -2240,6 +2450,6 @@ declare class Ship extends Ship$1 {
2240
2450
  }
2241
2451
 
2242
2452
  declare namespace Ship {
2243
- export { API_KEY, API_PATHS, AUTH_BASE_PATH, Account, AccountDeleteResponse, AccountGetResponse, AccountKeyResponse, AccountOverrides, AccountPlan, AccountPlanType, AccountResource, AccountUsage, Activity, ActivityEvent, ActivityListResponse, ActivityMeta, ApiDeployOptions, ApiHttp, ApiHttpOptions, AuthMethod, AuthMethodType, BLOCKED_EXTENSIONS, BillingCancelResponse, BillingStatus, CALLER, CheckoutSession, DEFAULT_API, DEPLOYMENT_CONFIG_FILENAME, DEPLOY_TOKEN, DeployBody, DeployBodyContext, DeployBodyCreator, DeployFile, DeployInput, Deployment, DeploymentCreateResponse, DeploymentDeleteResponse, DeploymentListResponse, DeploymentOptions, DeploymentResource, DeploymentResourceContext, DeploymentSetOptions, DeploymentStatus, DeploymentStatusType, DeploymentUploadOptions, DnsLookup, DnsProvider, DnsRecord, DnsRecordType, Domain, DomainDeleteResponse, DomainDnsResponse, DomainListResponse, DomainRecordsResponse, DomainResource, DomainSetOptions, DomainSetResult, DomainShareResponse, DomainStatus, DomainStatusType, DomainValidateResponse, DomainVerifyResponse, ErrorResponse, ErrorType, ExecutionEnvironment, FileValidationStatus as FILE_VALIDATION_STATUS, Fetch, FileValidationResult, FileValidationStatus, FileValidationStatusType, IDEMPOTENCY_KEY_CONSTRAINTS, JUNK_DIRECTORIES, LABEL_CONSTRAINTS, LABEL_PATTERN, LabelsResponse, ListOptions, ListResponse, MD5Result, OAuthScope, OAuthScopeType, PASSWORD_CONSTRAINTS, PingResponse, PlatformLimits, ResourceContext, SPACheckDebug, SPACheckRequest, SPACheckResponse, SPA_DEFAULT_CONFIG, SetupInstructionsResponse, ShipClientOptions, ShipError, ShipEvents, StaticFile, Token, TokenCreateOptions, TokenCreateResponse, TokenDeleteResponse, TokenKind, TokenKindType, TokenListResponse, TokenProvider, TokenResource, UNBUILT_PROJECT_MARKERS, UNSAFE_FILENAME_CHARS, UploadedFile, UserVisibleActivityEvent, ValidatableFile, ValidationIssue, __setTestEnvironment, allValidFilesReady, assertShipJsonSyntax, calculateMD5, classifyToken, createAccountResource, createDeploymentResource, createDomainResource, createTokenResource, 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 };
2453
+ export { API_KEY, API_PATHS, AUTH_BASE_PATH, Account, AccountDeleteResponse, AccountGetResponse, AccountKeyResponse, AccountOverrides, AccountPlan, AccountPlanType, AccountResource, AccountUsage, Activity, ActivityEvent, ActivityListResponse, ActivityMeta, ApiDeployOptions, ApiHttp, ApiHttpOptions, AuthMethod, AuthMethodType, BLOCKED_EXTENSIONS, BillingCancelResponse, BillingStatus, CALLER, CheckoutSession, DEFAULT_API, DEPLOYMENT_CONFIG_FILENAME, DEPLOY_FIELDS, DEPLOY_TOKEN, DeployBody, DeployBodyContext, DeployBodyCreator, DeployFile, DeployInput, Deployment, DeploymentCreateResponse, DeploymentDeleteResponse, DeploymentListResponse, DeploymentOptions, DeploymentResource, DeploymentResourceContext, DeploymentSetOptions, DeploymentStatus, DeploymentStatusType, DeploymentUploadOptions, DeploymentVia, DeploymentViaType, DnsLookup, DnsProvider, DnsRecord, DnsRecordType, Domain, DomainDeleteResponse, DomainDnsResponse, DomainListResponse, DomainRecordsResponse, DomainResource, DomainSetOptions, DomainSetResult, DomainShareResponse, DomainStatus, DomainStatusType, DomainValidateResponse, DomainVerifyResponse, ErrorResponse, ErrorType, ExecutionEnvironment, FileValidationStatus as FILE_VALIDATION_STATUS, Fetch, FileValidationResult, FileValidationStatus, FileValidationStatusType, IDEMPOTENCY_KEY_CONSTRAINTS, JUNK_DIRECTORIES, LABEL_CONSTRAINTS, LABEL_PATTERN, LabelsResponse, ListOptions, ListResponse, MD5Result, MY_API_KEY_URL, OAuthScope, OAuthScopeType, PASSWORD_CONSTRAINTS, PUBLIC_DEPLOYMENT_TTL_SECONDS, PingResponse, PlatformLimits, ResourceContext, SHIP_ENV, SPACheckDebug, SPACheckRequest, SPACheckResponse, SPA_CHECK_CONSTRAINTS, SPA_DEFAULT_CONFIG, SetupInstructionsResponse, ShipClientOptions, ShipError, ShipEvents, StaticFile, Token, TokenCreateOptions, TokenCreateResponse, TokenDeleteResponse, TokenKind, TokenKindType, TokenListResponse, TokenProvider, TokenResource, UNBUILT_PROJECT_MARKERS, UNSAFE_FILENAME_CHARS, UploadedFile, UserVisibleActivityEvent, ValidatableFile, ValidationIssue, WEB_FILE_ACCEPT, __setTestEnvironment, allValidFilesReady, assertShipJsonSyntax, calculateMD5, classifyToken, createAccountResource, createDeploymentResource, createDomainResource, createTokenResource, deserializeLabels, extractSubdomain, filterJunk, formatFileSize, generateDeploymentUrl, generateDomainUrl, getENV, getValidFiles, hasUnbuiltMarker, hasUnsafeChars, isBlockedExtension, isCustomDomain, isDeployment, isPlatformDomain, isShipError, normalizeVia, optimizeDeployPaths, pluralize, processFilesForNode, serializeLabels, validateApiKey, validateApiUrl, validateCaller, validateDeployFile, validateDeployPath, validateDeployToken, validateFileName, validateFiles, validateIdempotencyKey, validatePassword, validateToken };
2244
2454
  }
2245
2455
  export = Ship;