@shipstatic/ship 2.2.0-beta.6 → 2.2.0-beta.8

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
@@ -671,6 +671,12 @@ declare const DEPLOY_FIELDS: {
671
671
  readonly VIA: "via";
672
672
  /** Plaintext password — the API hashes it server-side. */
673
673
  readonly PASSWORD: "password";
674
+ /**
675
+ * Requested lifetime in SECONDS — a duration, never an instant. The API
676
+ * computes and stores the expiry, so the wire carries no client clock.
677
+ * See {@link validateTtl}.
678
+ */
679
+ readonly TTL: "ttl";
674
680
  /** @internal Server-processing flag — first-party `/upload` only. */
675
681
  readonly BUILD: "build";
676
682
  /** @internal Server-processing flag — first-party `/upload` only. */
@@ -725,6 +731,23 @@ declare const ErrorType: {
725
731
  readonly Maintenance: "maintenance";
726
732
  /** Network/connection error. Client-side only — set by HTTP clients on fetch failure; never produced server-side. */
727
733
  readonly Network: "network_error";
734
+ /**
735
+ * A deadline expired before the exchange completed. Client-side only — set
736
+ * by HTTP clients when a timeout signal fires; never produced server-side.
737
+ *
738
+ * A member of the NETWORK category rather than a sibling of it:
739
+ * `isNetworkError()` answers "nothing was exchanged", which is true of a
740
+ * deadline exactly as it is of a refused connection, so every consumer that
741
+ * retries, declines to report, or declines to relay a wire message on that
742
+ * category is already right about a timeout. The distinct TYPE exists for
743
+ * the one decision the category cannot make — what to SAY. "Check your
744
+ * internet connection" is the wrong sentence for a five-minute deploy
745
+ * ceiling, and a surface can only tell the two apart by type.
746
+ *
747
+ * The same relationship every comparable SDK ships:
748
+ * `APIConnectionTimeoutError extends APIConnectionError`.
749
+ */
750
+ readonly Timeout: "timeout_error";
728
751
  /** Operation was cancelled. Client-side only — set on `AbortSignal` abort; never produced server-side. */
729
752
  readonly Cancelled: "operation_cancelled";
730
753
  /** File operation error. Client-side only — set by SDK during local file processing; never produced server-side. */
@@ -769,7 +792,7 @@ declare class ShipError extends Error {
769
792
  * on the client). Falls back to status-derived (401 → Authentication,
770
793
  * 403 → Forbidden, 429 → RateLimit, else → Api) for non-API responses
771
794
  * (CDN errors, intermediaries) or malformed bodies. Client-only types
772
- * (`Network`, `Cancelled`, `File`, `Config`) are filtered out of the
795
+ * (`Network`, `Timeout`, `Cancelled`, `File`, `Config`) are filtered out of the
773
796
  * trusted set — a misbehaving server claiming one of those is ignored.
774
797
  *
775
798
  * `operationName` (e.g. `"Get account"`) is used to compose the fallback
@@ -789,8 +812,9 @@ declare class ShipError extends Error {
789
812
  * Routing:
790
813
  * - Already a `ShipError` → returned as-is (caller's intent preserved)
791
814
  * - `AbortError` → `ShipError.cancelled(...)` — someone stopped it on purpose
792
- * - `TimeoutError` → `ShipError.network(...)` — a deadline expired, so
793
- * nothing was exchanged; the message names the timeout
815
+ * - `TimeoutError` → `ShipError.timeout(...)` — a deadline expired; the
816
+ * message names the timeout, and the type is in the network CATEGORY
817
+ * because nothing was exchanged
794
818
  * - A transport failure → `ShipError.network(...)` — see `isTransportFailure`
795
819
  * for what each runtime offers as evidence
796
820
  * - Any other `Error` → `ShipError(Api, ...)` (no HTTP status — fetch never reached the server)
@@ -837,6 +861,14 @@ declare class ShipError extends Error {
837
861
  static authentication(message?: string, details?: unknown): ShipError;
838
862
  static business(message: string, status?: number, details?: unknown): ShipError;
839
863
  static network(message: string, details?: unknown): ShipError;
864
+ /**
865
+ * A deadline expired before the exchange completed.
866
+ *
867
+ * Statusless like its four client-only siblings: no exchange completed, so
868
+ * there is no HTTP status to report. `isNetworkError()` is true — see
869
+ * `ErrorType.Timeout` for why the category is shared and the type is not.
870
+ */
871
+ static timeout(message: string, details?: unknown): ShipError;
840
872
  static cancelled(message: string, details?: unknown): ShipError;
841
873
  static file(message: string, details?: unknown): ShipError;
842
874
  static config(message: string, details?: unknown): ShipError;
@@ -1233,6 +1265,47 @@ declare function validateApiUrl(apiUrl: string): void;
1233
1265
  * Example: "happy-cat-abc1234.shipstatic.com"
1234
1266
  */
1235
1267
  declare function isDeployment(input: string): boolean;
1268
+ /**
1269
+ * The envelope a requested lifetime must fit — one word, one grammar, wherever
1270
+ * the platform lets a caller choose how long something lives.
1271
+ *
1272
+ * Two resources wear it: `TokenCreateOptions.ttl` and
1273
+ * `DeploymentUploadOptions.ttl`. It lives here rather than on the server by
1274
+ * the format-vs-policy rule — a client can decide offline whether a duration
1275
+ * is well-formed, and the API rejects the same value the same way. What is
1276
+ * NOT here is any per-plan ceiling: no such policy exists, and one delivered
1277
+ * speculatively through `/limits` would be an owner for a decision nobody has
1278
+ * made.
1279
+ */
1280
+ declare const TTL_CONSTRAINTS: {
1281
+ /**
1282
+ * Shortest requestable lifetime, in seconds. One rather than zero: a
1283
+ * deployment that expires the instant it is created is not a shorter lease,
1284
+ * it is a deploy that was never live, and `0` is how an unset variable
1285
+ * arrives.
1286
+ */
1287
+ readonly MIN_SECONDS: 1;
1288
+ /** Longest requestable lifetime, in seconds — one year. */
1289
+ readonly MAX_SECONDS: number;
1290
+ };
1291
+ /**
1292
+ * Validate a requested lifetime in SECONDS and return it, or `undefined` when
1293
+ * none was asked for.
1294
+ *
1295
+ * **A duration, never an instant.** The caller says how long; the server owns
1296
+ * what time it is and stamps the expiry — so a client's clock, however wrong,
1297
+ * cannot shorten or extend a lease. That is the tokens precedent, and it is
1298
+ * why this rule measures a count of seconds rather than checking a timestamp
1299
+ * against `now`.
1300
+ *
1301
+ * Fractions are refused rather than rounded: a caller who wrote `1.5` meant
1302
+ * something the wire cannot carry, and silently choosing `1` or `2` for them
1303
+ * is a decision the platform has no standing to make.
1304
+ *
1305
+ * Single source of truth shared by the API (the tokens route and the deploy
1306
+ * schema), the SDK's request boundary, and the CLI's parser.
1307
+ */
1308
+ declare function validateTtl(value: unknown): number | undefined;
1236
1309
  /**
1237
1310
  * Request payload for SPA check endpoint
1238
1311
  */
@@ -1365,6 +1438,27 @@ interface DeploymentUploadOptions {
1365
1438
  * into missing analytics rather than an error. See {@link DeploymentVia}.
1366
1439
  */
1367
1440
  via?: DeploymentViaType;
1441
+ /**
1442
+ * Seconds until this deployment expires; omit for one that never does.
1443
+ *
1444
+ * The platform reclaims it when the time is up — an ephemeral deployment,
1445
+ * chosen by the deployer rather than by the identity. The same word and the
1446
+ * same grammar as {@link TokenCreateOptions.ttl}, bounded by
1447
+ * {@link TTL_CONSTRAINTS}.
1448
+ *
1449
+ * **Requires a credential.** An anonymous deploy has no deployer, and the
1450
+ * platform owns anonymous lifetime as policy
1451
+ * ({@link PUBLIC_DEPLOYMENT_TTL_SECONDS}) — so a ttl on one is refused
1452
+ * rather than honoured or ignored.
1453
+ *
1454
+ * **A deployment carrying one cannot be linked to a domain.** A domain is a
1455
+ * commitment and a deadline is its opposite; the API refuses the link, which
1456
+ * is what keeps the reaper from tearing a live domain's target away.
1457
+ *
1458
+ * Immutable, like every other field of a deployment: to keep something
1459
+ * longer, redeploy.
1460
+ */
1461
+ ttl?: number;
1368
1462
  /**
1369
1463
  * Optional password that protects this deployment.
1370
1464
  *
@@ -1803,14 +1897,6 @@ interface DeploymentOptions extends DeploymentUploadOptions {
1803
1897
  spaDetect?: boolean;
1804
1898
  }
1805
1899
  type ApiDeployOptions = Omit<DeploymentOptions, 'pathDetect'>;
1806
- /**
1807
- * Prepared request body for deployment.
1808
- * Created by platform-specific code, consumed by HTTP client.
1809
- */
1810
- interface DeployBody {
1811
- body: FormData | ArrayBuffer;
1812
- headers: Record<string, string>;
1813
- }
1814
1900
  /**
1815
1901
  * Context passed to the deploy body creator — everything that becomes a
1816
1902
  * form field alongside the files themselves.
@@ -1834,6 +1920,11 @@ interface DeployBodyContext {
1834
1920
  * characters. Whitespace is preserved verbatim — significant.
1835
1921
  */
1836
1922
  password?: string;
1923
+ /**
1924
+ * Requested lifetime in SECONDS — a duration, never an instant, bounded by
1925
+ * `TTL_CONSTRAINTS`. The API stamps the expiry against its own clock.
1926
+ */
1927
+ ttl?: number;
1837
1928
  /** @internal Server-side processing flags. */
1838
1929
  flags?: {
1839
1930
  build?: boolean;
@@ -1843,11 +1934,6 @@ interface DeployBodyContext {
1843
1934
  /** @internal reCAPTCHA proof for the anonymous human deploy channel (/upload). */
1844
1935
  captcha?: string;
1845
1936
  }
1846
- /**
1847
- * Function that creates a deploy request body from files.
1848
- * Implemented differently for Node.js and Browser.
1849
- */
1850
- type DeployBodyCreator = (files: StaticFile[], context?: DeployBodyContext) => Promise<DeployBody>;
1851
1937
  /** Standard `fetch` signature — the type of the `fetch` client option. */
1852
1938
  type Fetch = typeof fetch;
1853
1939
  /**
@@ -1964,17 +2050,45 @@ interface ShipClientOptions {
1964
2050
  deployEndpoint?: string | undefined;
1965
2051
  }
1966
2052
  /**
1967
- * Event map for Ship SDK events
1968
- * Core events for observability: request, response, error
2053
+ * Event map for Ship SDK events.
2054
+ *
2055
+ * **Every failure is visible, and the event NAME says whether it ended the
2056
+ * call.** One call emits `retry* (error | response)` — so the stream is
2057
+ * unambiguous at every prefix, and a consumer never has to wait to find out
2058
+ * what it is watching.
2059
+ *
2060
+ * `request` counts what went out; `retry` counts what failed and will be
2061
+ * tried again; `error` and `response` are the two terminal answers, exactly
2062
+ * one of which arrives.
1969
2063
  */
1970
2064
  interface ShipEvents {
1971
- /** Emitted before each API request */
2065
+ /** Emitted before each API request — once per ATTEMPT, so it counts what actually went out. */
1972
2066
  request: [url: string, init: RequestInit];
1973
- /** Emitted after successful API response */
2067
+ /** Emitted after successful API response — once, on the attempt that worked. */
1974
2068
  response: [response: Response, url: string];
1975
2069
  /**
1976
- * Emitted when something fails. TWO populations arrive here, which is why
1977
- * the type is `Error` and not `ShipError`:
2070
+ * Emitted when an attempt failed and the client is going to try again.
2071
+ * Carries the same normalized `ShipError` the terminal `error` would, plus
2072
+ * `attempt` — the number of the attempt that just failed, counting from 1,
2073
+ * which matches the arithmetic the docs use ("two retries by default, so
2074
+ * three attempts"). Under that numbering the value reads both ways at once:
2075
+ * attempt N failing IS retry N, so `retry 1 of ${maxRetries}` needs no
2076
+ * adjustment.
2077
+ *
2078
+ * This event exists so `error` can keep meaning what it always meant. When
2079
+ * retries landed, `error` fired per attempt — honest about what happened,
2080
+ * but it silently redefined the event: a consumer seeing `error, error,
2081
+ * response` could not tell "failed, retrying" from "failed, terminally" at
2082
+ * any prefix, and counting `error`s no longer counted failed calls. Two
2083
+ * names, two meanings, and nothing lost: every failure is still announced.
2084
+ *
2085
+ * A failure the loop will NOT retry is terminal and emits `error` directly,
2086
+ * never this. So is an abort that lands mid-backoff.
2087
+ */
2088
+ retry: [error: Error, url: string, attempt: number];
2089
+ /**
2090
+ * Emitted when the CALL failed — terminally, exactly once. TWO populations
2091
+ * arrive here, which is why the type is `Error` and not `ShipError`:
1978
2092
  *
1979
2093
  * - a failed request — always a `ShipError` (`executeRequest` normalizes
1980
2094
  * every failure through `ShipError.fromFetchError` before emitting), so
@@ -2017,28 +2131,72 @@ declare class SimpleEvents {
2017
2131
  emit<K extends keyof ShipEvents>(event: K, ...args: ShipEvents[K]): void;
2018
2132
  }
2019
2133
 
2020
- /**
2021
- * @file HTTP client for Ship API.
2022
- */
2023
-
2024
2134
  interface ApiHttpOptions extends ShipClientOptions {
2025
2135
  /** Resolves the credential slot per request — async so token providers can mint/refresh. */
2026
2136
  getAuthHeaders: () => Record<string, string> | Promise<Record<string, string>>;
2027
- createDeployBody: DeployBodyCreator;
2028
2137
  }
2029
- declare class ApiHttp extends SimpleEvents {
2138
+ interface RequestResult<T> {
2139
+ data: T;
2140
+ status: number;
2141
+ }
2142
+ /**
2143
+ * The deploy's CARRIAGE — the two facts about a deploy that are transport's
2144
+ * rather than the deployment resource's.
2145
+ *
2146
+ * The numbers are transport's because a budget for how long to wait on a wire
2147
+ * is nothing else, and the endpoint is transport's because `deployEndpoint` is
2148
+ * a client option that redirects the route. The CHOICE between the two
2149
+ * ceilings is the resource's, because only it knows that `build`/`prerender`
2150
+ * wait on work the server does after the upload lands.
2151
+ */
2152
+ interface DeployTransport {
2153
+ /** `/deployments`, or `/upload` where the `@internal` option redirects it. */
2154
+ readonly endpoint: string;
2155
+ /** The ordinary deploy ceiling. */
2156
+ readonly timeout: number;
2157
+ /** The ceiling when the server will also build. */
2158
+ readonly buildTimeout: number;
2159
+ }
2160
+ /**
2161
+ * What a resource may ask of the transport: carry this request, and tell me
2162
+ * what came back.
2163
+ *
2164
+ * This interface is the whole seam. `resources.ts` states WHICH request — the
2165
+ * path, the verb, the body, the response type — and hands it here; nothing
2166
+ * above this line knows the base URL, the credential, the retry policy or the
2167
+ * event vocabulary, and nothing below knows what a domain is.
2168
+ */
2169
+ interface Transport {
2170
+ request<T>(path: string, options: ShipRequestInit, operationName: string, timeoutMs?: number): Promise<T>;
2171
+ requestWithStatus<T>(path: string, options: ShipRequestInit, operationName: string): Promise<RequestResult<T>>;
2172
+ readonly deploy: DeployTransport;
2173
+ }
2174
+ /**
2175
+ * A request as THIS client composes one.
2176
+ *
2177
+ * Identical to `RequestInit` but for the headers, which are narrowed from the
2178
+ * DOM's three-shaped `HeadersInit` to the one shape every call site here
2179
+ * actually builds. That narrowing is load-bearing twice over: `mergeHeaders`
2180
+ * used to reach its record through an `as` cast, and `hasIdempotencyKey` used
2181
+ * to walk all three shapes to find a key that only ever arrives in one of
2182
+ * them. Narrowing at RUNTIME instead would have turned an unreachable case
2183
+ * into a SILENT no-retry — a deploy that quietly stopped replaying because
2184
+ * someone handed the transport a `Headers`. Here that is a compile error.
2185
+ */
2186
+ type ShipRequestInit = Omit<RequestInit, 'headers'> & {
2187
+ headers?: Record<string, string>;
2188
+ };
2189
+ declare class ApiHttp extends SimpleEvents implements Transport {
2030
2190
  private readonly apiUrl;
2031
2191
  private readonly getAuthHeadersCallback;
2032
2192
  private readonly session;
2033
2193
  private readonly caller;
2034
2194
  private readonly timeout;
2035
2195
  private readonly maxRetries;
2036
- private readonly deployTimeout;
2037
- private readonly deployBuildTimeout;
2038
2196
  private readonly fetch;
2039
- private readonly createDeployBody;
2040
- private readonly deployEndpoint;
2041
2197
  private globalHeaders;
2198
+ /** @see DeployTransport — the carriage facts the deployment resource reads. */
2199
+ readonly deploy: DeployTransport;
2042
2200
  constructor(options: ApiHttpOptions);
2043
2201
  /**
2044
2202
  * Set global headers included in every request.
@@ -2052,9 +2210,16 @@ declare class ApiHttp extends SimpleEvents {
2052
2210
  * for headers, the timeout signal, the events and error normalization — so
2053
2211
  * an attempt is a whole request and nothing has to be undone between two.
2054
2212
  *
2055
- * **Events stay honest across attempts**: `request` and `error` fire per
2056
- * attempt, so a consumer counting requests sees what actually went out;
2057
- * `response` fires once, on the one that worked.
2213
+ * **Every failure is visible, and the event NAME says whether it ended the
2214
+ * call.** One call emits `retry* (error | response)`: `request` fires per
2215
+ * attempt, so a consumer counting requests sees what actually went out; a
2216
+ * failure that will be tried again is a `retry`; `error` and `response` are
2217
+ * the two terminal answers, exactly one of which arrives.
2218
+ *
2219
+ * The failure events are emitted HERE rather than in `attemptOnce`, and
2220
+ * that placement is the whole mechanism: terminality is a property of the
2221
+ * loop — of `isRetryable` and the attempt budget — so it is knowable only
2222
+ * at the one point that owns both. An attempt cannot name its own failure.
2058
2223
  *
2059
2224
  * **The caller's `timeout` governs an ATTEMPT, not the wall clock.** Each
2060
2225
  * attempt is an honest request and deserves the ceiling the caller named;
@@ -2070,58 +2235,74 @@ declare class ApiHttp extends SimpleEvents {
2070
2235
  * is one that may be sent twice.
2071
2236
  */
2072
2237
  private isRetryable;
2073
- /** Did this request carry the header that makes a repeat safe? */
2238
+ /**
2239
+ * Did this request carry the header that makes a repeat safe?
2240
+ *
2241
+ * Case-insensitively, because HTTP field names are — the CLI's env tier and
2242
+ * the SDK option both spell it canonically, but a caller composing headers
2243
+ * by hand is entitled not to.
2244
+ */
2074
2245
  private hasIdempotencyKey;
2075
2246
  /**
2076
- * One attempt: headers, timeout signal, events, and error normalization.
2247
+ * One attempt: headers, timeout signal, the `request`/`response` events, and
2248
+ * error normalization.
2249
+ *
2250
+ * It does NOT emit a failure event. An attempt cannot know whether its own
2251
+ * failure ended the call — that is `executeRequest`'s question — so it
2252
+ * normalizes and throws, and the loop names what happened.
2077
2253
  */
2078
2254
  private attemptOnce;
2079
2255
  /**
2080
- * Simple request - returns data only
2256
+ * Send it; resolve what came back.
2257
+ *
2258
+ * Takes a PATH, not a URL: the base is this client's and nothing above needs
2259
+ * to know it. Twenty-two call sites wrote `${this.apiUrl}${API_PATHS.X}` by
2260
+ * hand before the endpoints moved out, which is twenty-two chances to
2261
+ * assemble it differently.
2081
2262
  */
2082
- private request;
2263
+ request<T>(path: string, options: ShipRequestInit, operationName: string, timeoutMs?: number): Promise<T>;
2083
2264
  /**
2084
- * Request with status - returns data and HTTP status code
2265
+ * The same, plus the HTTP status for the one operation where the status IS
2266
+ * the answer: a domain upsert says create-or-update in its 201/200 and
2267
+ * nowhere else in the response.
2085
2268
  */
2086
- private requestWithStatus;
2269
+ requestWithStatus<T>(path: string, options: ShipRequestInit, operationName: string): Promise<RequestResult<T>>;
2087
2270
  private mergeHeaders;
2088
2271
  private createTimeoutSignal;
2089
2272
  private safeClone;
2090
2273
  private parseResponse;
2091
- deploy(files: StaticFile[], options?: ApiDeployOptions): Promise<DeploymentCreateResponse>;
2092
- listDeployments(options?: ListOptions): Promise<DeploymentListResponse>;
2093
- getDeployment(id: string): Promise<Deployment>;
2094
- updateDeploymentLabels(id: string, labels: string[]): Promise<Deployment>;
2095
- deleteDeployment(id: string): Promise<DeploymentDeleteResponse>;
2096
- setDomain(name: string, deployment?: string, labels?: string[]): Promise<DomainSetResult>;
2097
- listDomains(options?: ListOptions): Promise<DomainListResponse>;
2098
- getDomain(name: string): Promise<Domain>;
2099
- deleteDomain(name: string): Promise<DomainDeleteResponse>;
2100
- verifyDomain(name: string): Promise<DomainVerifyResponse>;
2101
- getDomainDns(name: string): Promise<DomainDnsResponse>;
2102
- getDomainRecords(name: string): Promise<DomainRecordsResponse>;
2103
- getDomainShare(name: string): Promise<DomainShareResponse>;
2104
- validateDomain(name: string): Promise<DomainValidateResponse>;
2105
- createToken(ttl?: number, labels?: string[]): Promise<TokenCreateResponse>;
2106
- listTokens(options?: ListOptions): Promise<TokenListResponse>;
2107
- deleteToken(token: string): Promise<TokenDeleteResponse>;
2108
- getToken(token: string): Promise<Token>;
2109
- getAccount(): Promise<AccountGetResponse>;
2110
- getLimits(): Promise<PlatformLimits>;
2111
- ping(): Promise<PingResponse>;
2112
- checkSPA(files: StaticFile[], _options?: ApiDeployOptions): Promise<boolean>;
2113
2274
  }
2114
2275
 
2115
2276
  /**
2116
- * Ship SDK resource factory functions.
2277
+ * @file The SDK's vocabulary every request it can make, stated once.
2278
+ *
2279
+ * A resource method IS its endpoint: the path, the verb, the body, the
2280
+ * response type. It hands that to the transport, which knows how to carry a
2281
+ * request and nothing about what one means.
2282
+ *
2283
+ * **These were two layers until 2026-08-12.** `ApiHttp` carried eighteen
2284
+ * endpoint methods and every factory below wrapped one of them 1:1 —
2285
+ * `get: async (name) => getApi().getDomain(name)` — because this SDK mirrors
2286
+ * the wire one method per endpoint BY DESIGN (see CLAUDE.md, "Recorded
2287
+ * absences"). That design is exactly what made the second layer a restatement
2288
+ * rather than an adapter: the two could not diverge without one of them being
2289
+ * wrong. Folding DOWN rather than up is what keeps the public grouping and the
2290
+ * transport separate, which was the whole point of having two files.
2291
+ *
2292
+ * The `*Resource` interfaces come from `@shipstatic/types` and did not move.
2293
+ * They are the published contract; this file is how it is met.
2117
2294
  */
2118
2295
 
2119
2296
  /**
2120
2297
  * Shared context for all resource factories.
2298
+ *
2299
+ * A factory receives the callbacks it needs and nothing else — which is what
2300
+ * lets `getApi()` be a THUNK rather than an instance: the transport is built
2301
+ * once in the constructor, but reading it lazily is what keeps the resources
2302
+ * constructible before it exists and swappable in tests.
2121
2303
  */
2122
2304
  interface ResourceContext {
2123
- getApi: () => ApiHttp;
2124
- ensureInit: () => Promise<void>;
2305
+ getApi: () => Transport;
2125
2306
  }
2126
2307
  /**
2127
2308
  * Extended context for deployment resource.
@@ -2170,7 +2351,6 @@ declare abstract class Ship$1 {
2170
2351
  private credential;
2171
2352
  constructor(options?: ShipClientOptions);
2172
2353
  protected abstract processInput(input: DeployInput, options: DeploymentOptions): Promise<StaticFile[]>;
2173
- protected abstract getDeployBodyCreator(): DeployBodyCreator;
2174
2354
  /**
2175
2355
  * Lazy initialization — fetches platform limits (file size / count caps) once,
2176
2356
  * on the first API call. Subsequent calls reuse the resolved promise.
@@ -2535,8 +2715,13 @@ declare function validateDeployFile(input: FileRuleInput, limits: PlatformLimits
2535
2715
  declare function pluralize(count: number, singular: string, plural: string, includeCount?: boolean): string;
2536
2716
 
2537
2717
  /**
2538
- * @file Node.js-specific file utilities for the Ship SDK.
2539
- * Provides helpers for recursively discovering, filtering, and preparing files for deploy in Node.js.
2718
+ * @file The Node half of the deploy pipeline: finding files on a filesystem.
2719
+ *
2720
+ * Everything after the finding is shared (`shared/core/deploy-files.ts`) —
2721
+ * path optimization, junk filtering, the platform's rules, the checksums.
2722
+ * What is genuinely Node here is a directory walk with symlink-cycle
2723
+ * protection, a content path computed against the upload root, and the fact
2724
+ * that a Node user can point at a project folder and mean `dist/`.
2540
2725
  */
2541
2726
 
2542
2727
  /**
@@ -2551,7 +2736,7 @@ declare function pluralize(count: number, singular: string, plural: string, incl
2551
2736
  * in rather than read from a module global so concurrent Ships against
2552
2737
  * different API URLs cannot clobber each other's caps.
2553
2738
  * @returns Promise resolving to an array of StaticFile objects.
2554
- * @throws {ShipClientError} If called outside Node.js or if fs/path modules fail.
2739
+ * @throws {ShipError} If called outside Node.js or if fs/path modules fail.
2555
2740
  */
2556
2741
  declare function processFilesForNode(paths: string[], options?: DeploymentOptions, platformLimits?: PlatformLimits): Promise<StaticFile[]>;
2557
2742
 
@@ -2601,10 +2786,9 @@ declare class Ship extends Ship$1 {
2601
2786
  */
2602
2787
  deploy(input: string | string[], options?: DeploymentOptions): Promise<DeploymentCreateResponse>;
2603
2788
  protected processInput(input: DeployInput, options: DeploymentOptions): Promise<StaticFile[]>;
2604
- protected getDeployBodyCreator(): DeployBodyCreator;
2605
2789
  }
2606
2790
 
2607
2791
  declare namespace Ship {
2608
- 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, 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 };
2792
+ 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, BillingCancelResponse, BillingStatus, CALLER, CheckoutSession, DEFAULT_API, DEPLOYMENT_CONFIG_FILENAME, DEPLOY_FIELDS, DEPLOY_TOKEN, DeployBodyContext, DeployFile, DeployInput, DeployTransport, 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, RequestResult, ResourceContext, SHIP_ENV, SPACheckDebug, SPACheckRequest, SPACheckResponse, SPA_CHECK_CONSTRAINTS, SPA_DEFAULT_CONFIG, SetupInstructionsResponse, ShipClientOptions, ShipError, ShipEvents, ShipRequestInit, StaticFile, TTL_CONSTRAINTS, Token, TokenCreateOptions, TokenCreateResponse, TokenDeleteResponse, TokenKind, TokenKindType, TokenListResponse, TokenProvider, TokenResource, Transport, 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, validateTtl };
2609
2793
  }
2610
2794
  export = Ship;