@shipstatic/types 0.9.0 → 0.9.1

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 CHANGED
@@ -62,7 +62,7 @@ import {
62
62
 
63
63
  ```typescript
64
64
  import type {
65
- ConfigResponse,
65
+ PlatformLimits, // plan-based caps from /config (file size, file count, total size)
66
66
  BillingStatus,
67
67
  CheckoutSession,
68
68
  ActivityListResponse,
@@ -80,8 +80,6 @@ import type {
80
80
  DomainResource,
81
81
  AccountResource,
82
82
  TokenResource,
83
- BillingResource,
84
- KeysResource,
85
83
  } from '@shipstatic/types';
86
84
  ```
87
85
 
@@ -138,8 +136,8 @@ import {
138
136
  ```typescript
139
137
  import {
140
138
  DEFAULT_API,
141
- API_KEY_PREFIX,
142
- DEPLOY_TOKEN_PREFIX,
139
+ API_KEY, // { PREFIX, HEX_LENGTH, TOTAL_LENGTH, HINT_LENGTH }
140
+ DEPLOY_TOKEN, // { PREFIX, HEX_LENGTH, TOTAL_LENGTH }
143
141
  DEPLOYMENT_CONFIG_FILENAME,
144
142
  } from '@shipstatic/types';
145
143
  ```
package/dist/index.d.ts CHANGED
@@ -296,31 +296,37 @@ export interface AccountOverrides {
296
296
  totalSize?: number;
297
297
  }
298
298
  /**
299
- * All possible error types in the ShipStatic platform
300
- * Names are developer-friendly while wire format stays consistent
299
+ * All possible error types in the ShipStatic platform.
300
+ *
301
+ * Developer-friendly key names map to stable wire-format string values.
302
+ * Both the value and the type are exported under the same name so callers
303
+ * can use `ErrorType.Validation` (value comparison) and `: ErrorType` (type
304
+ * annotation) without ceremony — matching the pattern other status objects
305
+ * (`DeploymentStatus`, `DomainStatus`, `AccountPlan`, `AuthMethod`) follow.
301
306
  */
302
- export declare enum ErrorType {
307
+ export declare const ErrorType: {
303
308
  /** Validation failed (400) */
304
- Validation = "validation_failed",
309
+ readonly Validation: "validation_failed";
305
310
  /** Resource not found (404) */
306
- NotFound = "not_found",
311
+ readonly NotFound: "not_found";
307
312
  /** Rate limit exceeded (429) */
308
- RateLimit = "rate_limit_exceeded",
313
+ readonly RateLimit: "rate_limit_exceeded";
309
314
  /** Authentication required (401) */
310
- Authentication = "authentication_failed",
315
+ readonly Authentication: "authentication_failed";
311
316
  /** Business logic error (400) */
312
- Business = "business_logic_error",
313
- /** API server error (500) - renamed from Internal for clarity */
314
- Api = "internal_server_error",
317
+ readonly Business: "business_logic_error";
318
+ /** API server error (500) */
319
+ readonly Api: "internal_server_error";
315
320
  /** Network/connection error */
316
- Network = "network_error",
321
+ readonly Network: "network_error";
317
322
  /** Operation was cancelled */
318
- Cancelled = "operation_cancelled",
323
+ readonly Cancelled: "operation_cancelled";
319
324
  /** File operation error */
320
- File = "file_error",
325
+ readonly File: "file_error";
321
326
  /** Configuration error */
322
- Config = "config_error"
323
- }
327
+ readonly Config: "config_error";
328
+ };
329
+ export type ErrorType = typeof ErrorType[keyof typeof ErrorType];
324
330
  /**
325
331
  * Standard error response format used everywhere
326
332
  */
@@ -380,12 +386,22 @@ export declare class ShipError extends Error {
380
386
  */
381
387
  export declare function isShipError(error: unknown): error is ShipError;
382
388
  /**
383
- * Dynamic platform configuration returned by the /config endpoint.
384
- * Contains plan-based limits that vary by account.
389
+ * Plan-based platform limits returned by the `/config` endpoint.
390
+ *
391
+ * The SDK fetches these once on first API call to drive client-side
392
+ * file-size / file-count / total-size validation that mirrors what the API
393
+ * would enforce server-side. Limits vary by account plan.
394
+ *
395
+ * Distinct from `ResolvedConfig` (which carries the *client's* credentials
396
+ * and API URL after defaulting); this one carries the *platform's* posted
397
+ * caps for the current account.
385
398
  */
386
- export interface ConfigResponse {
399
+ export interface PlatformLimits {
400
+ /** Maximum size in bytes for a single file. */
387
401
  maxFileSize: number;
402
+ /** Maximum number of files in a single deployment. */
388
403
  maxFilesCount: number;
404
+ /** Maximum total size in bytes across all files in a deployment. */
389
405
  maxTotalSize: number;
390
406
  }
391
407
  /**
@@ -457,13 +473,32 @@ export interface PingResponse {
457
473
  /** Optional timestamp */
458
474
  timestamp?: number;
459
475
  }
460
- export declare const API_KEY_PREFIX = "ship-";
461
- export declare const API_KEY_HEX_LENGTH = 64;
462
- export declare const API_KEY_TOTAL_LENGTH: number;
463
- export declare const API_KEY_HINT_LENGTH = 4;
464
- export declare const DEPLOY_TOKEN_PREFIX = "token-";
465
- export declare const DEPLOY_TOKEN_HEX_LENGTH = 64;
466
- export declare const DEPLOY_TOKEN_TOTAL_LENGTH: number;
476
+ /**
477
+ * Shape constants for API keys (`ship-{64 hex chars}`).
478
+ * Single source of truth used by validation utilities and auth middleware.
479
+ */
480
+ export declare const API_KEY: {
481
+ /** Prefix that identifies an API key. */
482
+ readonly PREFIX: "ship-";
483
+ /** Number of hex characters following the prefix. */
484
+ readonly HEX_LENGTH: 64;
485
+ /** Total length of an API key including prefix (`PREFIX.length + HEX_LENGTH = 69`). */
486
+ readonly TOTAL_LENGTH: 69;
487
+ /** Number of trailing characters used to display a redacted hint (e.g. last 4). */
488
+ readonly HINT_LENGTH: 4;
489
+ };
490
+ /**
491
+ * Shape constants for deploy tokens (`token-{64 hex chars}`).
492
+ * Single source of truth used by validation utilities and auth middleware.
493
+ */
494
+ export declare const DEPLOY_TOKEN: {
495
+ /** Prefix that identifies a deploy token. */
496
+ readonly PREFIX: "token-";
497
+ /** Number of hex characters following the prefix. */
498
+ readonly HEX_LENGTH: 64;
499
+ /** Total length of a deploy token including prefix (`PREFIX.length + HEX_LENGTH = 70`). */
500
+ readonly TOTAL_LENGTH: 70;
501
+ };
467
502
  export declare const AuthMethod: {
468
503
  readonly JWT: "jwt";
469
504
  readonly API_KEY: "apiKey";
@@ -584,26 +619,16 @@ export interface ProgressInfo {
584
619
  /** Default API URL if not otherwise configured. */
585
620
  export declare const DEFAULT_API = "https://api.shipstatic.com";
586
621
  /**
587
- * Browser-specific deploy input — an array of `File` objects (typically from
588
- * `<input type="file">` or drag-and-drop). The Browser SDK rejects any other
589
- * shape at runtime.
590
- */
591
- export type BrowserDeployInput = File[];
592
- /**
593
- * Node-specific deploy input — file or directory path(s) on disk. A single
594
- * path or an array of paths; directories are walked recursively. The Node
595
- * SDK rejects any other shape at runtime.
596
- */
597
- export type NodeDeployInput = string | string[];
598
- /**
599
- * Universal deploy input — the union of every platform's accepted shape.
622
+ * Universal deploy input — the union of every shape the SDK accepts.
623
+ *
624
+ * - **Browser**: `File[]` (typically from `<input type="file">` or drag-and-drop)
625
+ * - **Node**: `string | string[]` (file or directory path(s) on disk; directories are walked)
600
626
  *
601
- * Prefer the platform-specific aliases (`BrowserDeployInput` /
602
- * `NodeDeployInput`) when writing platform-specific code; `DeployInput` is
603
- * the right type only for code that genuinely needs to accept either. Each
604
- * platform's SDK validates at runtime and throws on the wrong shape.
627
+ * Each platform's SDK narrows its `deploy()` signature to the relevant shape
628
+ * and rejects anything else at runtime. Use the structural types directly
629
+ * (`File[]`, `string | string[]`) when writing platform-specific code.
605
630
  */
606
- export type DeployInput = BrowserDeployInput | NodeDeployInput;
631
+ export type DeployInput = File[] | string | string[];
607
632
  /**
608
633
  * Options for deployment creation at the API contract level.
609
634
  * SDK implementations may extend with additional options (timeout, signal, callbacks, etc.).
@@ -706,32 +731,6 @@ export interface CheckoutSession {
706
731
  /** URL to redirect user to Creem checkout page */
707
732
  url: string;
708
733
  }
709
- /**
710
- * Billing resource interface - the contract all implementations must follow
711
- *
712
- * IMPOSSIBLE SIMPLICITY: No sync() method needed!
713
- * Webhooks are the single source of truth. Frontend just polls status().
714
- */
715
- export interface BillingResource {
716
- /**
717
- * Create a checkout session
718
- * @returns Checkout session with URL to redirect user
719
- */
720
- checkout: () => Promise<CheckoutSession>;
721
- /**
722
- * Get current billing status
723
- * @returns Billing status and usage information
724
- */
725
- status: () => Promise<BillingStatus>;
726
- }
727
- /**
728
- * Keys resource interface - the contract all implementations must follow
729
- */
730
- export interface KeysResource {
731
- create: () => Promise<{
732
- apiKey: string;
733
- }>;
734
- }
735
734
  /**
736
735
  * All activity event types logged in the system.
737
736
  * Uses dot notation consistently: {resource}.{action}
package/dist/index.js CHANGED
@@ -50,34 +50,40 @@ export const AccountPlan = {
50
50
  // ERROR SYSTEM
51
51
  // =============================================================================
52
52
  /**
53
- * All possible error types in the ShipStatic platform
54
- * Names are developer-friendly while wire format stays consistent
53
+ * All possible error types in the ShipStatic platform.
54
+ *
55
+ * Developer-friendly key names map to stable wire-format string values.
56
+ * Both the value and the type are exported under the same name so callers
57
+ * can use `ErrorType.Validation` (value comparison) and `: ErrorType` (type
58
+ * annotation) without ceremony — matching the pattern other status objects
59
+ * (`DeploymentStatus`, `DomainStatus`, `AccountPlan`, `AuthMethod`) follow.
55
60
  */
56
- export var ErrorType;
57
- (function (ErrorType) {
61
+ export const ErrorType = {
58
62
  /** Validation failed (400) */
59
- ErrorType["Validation"] = "validation_failed";
63
+ Validation: 'validation_failed',
60
64
  /** Resource not found (404) */
61
- ErrorType["NotFound"] = "not_found";
65
+ NotFound: 'not_found',
62
66
  /** Rate limit exceeded (429) */
63
- ErrorType["RateLimit"] = "rate_limit_exceeded";
67
+ RateLimit: 'rate_limit_exceeded',
64
68
  /** Authentication required (401) */
65
- ErrorType["Authentication"] = "authentication_failed";
69
+ Authentication: 'authentication_failed',
66
70
  /** Business logic error (400) */
67
- ErrorType["Business"] = "business_logic_error";
68
- /** API server error (500) - renamed from Internal for clarity */
69
- ErrorType["Api"] = "internal_server_error";
71
+ Business: 'business_logic_error',
72
+ /** API server error (500) */
73
+ Api: 'internal_server_error',
70
74
  /** Network/connection error */
71
- ErrorType["Network"] = "network_error";
75
+ Network: 'network_error',
72
76
  /** Operation was cancelled */
73
- ErrorType["Cancelled"] = "operation_cancelled";
77
+ Cancelled: 'operation_cancelled',
74
78
  /** File operation error */
75
- ErrorType["File"] = "file_error";
79
+ File: 'file_error',
76
80
  /** Configuration error */
77
- ErrorType["Config"] = "config_error";
78
- })(ErrorType || (ErrorType = {}));
81
+ Config: 'config_error',
82
+ };
79
83
  /**
80
- * Categorizes error types for better type checking
84
+ * Categorizes error types for the `isClientError` / `isNetworkError` /
85
+ * `isAuthError` helpers. Each `Set` is typed against the wider `ErrorType`
86
+ * union so `.has(error.type)` accepts any value from the union.
81
87
  */
82
88
  const ERROR_CATEGORIES = {
83
89
  client: new Set([ErrorType.Business, ErrorType.Config, ErrorType.File, ErrorType.Validation]),
@@ -299,15 +305,32 @@ export function hasUnbuiltMarker(filePath) {
299
305
  const segments = filePath.replace(/\\/g, '/').split('/').filter(Boolean);
300
306
  return segments.some(s => UNBUILT_PROJECT_MARKERS.has(s));
301
307
  }
302
- // API Key Configuration
303
- export const API_KEY_PREFIX = 'ship-';
304
- export const API_KEY_HEX_LENGTH = 64;
305
- export const API_KEY_TOTAL_LENGTH = API_KEY_PREFIX.length + API_KEY_HEX_LENGTH; // 69
306
- export const API_KEY_HINT_LENGTH = 4;
307
- // Deploy Token Configuration
308
- export const DEPLOY_TOKEN_PREFIX = 'token-';
309
- export const DEPLOY_TOKEN_HEX_LENGTH = 64;
310
- export const DEPLOY_TOKEN_TOTAL_LENGTH = DEPLOY_TOKEN_PREFIX.length + DEPLOY_TOKEN_HEX_LENGTH; // 70
308
+ /**
309
+ * Shape constants for API keys (`ship-{64 hex chars}`).
310
+ * Single source of truth used by validation utilities and auth middleware.
311
+ */
312
+ export const API_KEY = {
313
+ /** Prefix that identifies an API key. */
314
+ PREFIX: 'ship-',
315
+ /** Number of hex characters following the prefix. */
316
+ HEX_LENGTH: 64,
317
+ /** Total length of an API key including prefix (`PREFIX.length + HEX_LENGTH = 69`). */
318
+ TOTAL_LENGTH: 69,
319
+ /** Number of trailing characters used to display a redacted hint (e.g. last 4). */
320
+ HINT_LENGTH: 4,
321
+ };
322
+ /**
323
+ * Shape constants for deploy tokens (`token-{64 hex chars}`).
324
+ * Single source of truth used by validation utilities and auth middleware.
325
+ */
326
+ export const DEPLOY_TOKEN = {
327
+ /** Prefix that identifies a deploy token. */
328
+ PREFIX: 'token-',
329
+ /** Number of hex characters following the prefix. */
330
+ HEX_LENGTH: 64,
331
+ /** Total length of a deploy token including prefix (`PREFIX.length + HEX_LENGTH = 70`). */
332
+ TOTAL_LENGTH: 70,
333
+ };
311
334
  // Authentication Method Constants
312
335
  export const AuthMethod = {
313
336
  JWT: 'jwt',
@@ -327,30 +350,30 @@ export const SPA_DEFAULT_CONFIG = { rewrites: [{ source: '/(.*)', destination: '
327
350
  * Validate API key format
328
351
  */
329
352
  export function validateApiKey(apiKey) {
330
- if (!apiKey.startsWith(API_KEY_PREFIX)) {
331
- throw ShipError.validation(`API key must start with "${API_KEY_PREFIX}"`);
353
+ if (!apiKey.startsWith(API_KEY.PREFIX)) {
354
+ throw ShipError.validation(`API key must start with "${API_KEY.PREFIX}"`);
332
355
  }
333
- if (apiKey.length !== API_KEY_TOTAL_LENGTH) {
334
- throw ShipError.validation(`API key must be ${API_KEY_TOTAL_LENGTH} characters total (${API_KEY_PREFIX} + ${API_KEY_HEX_LENGTH} hex chars)`);
356
+ if (apiKey.length !== API_KEY.TOTAL_LENGTH) {
357
+ throw ShipError.validation(`API key must be ${API_KEY.TOTAL_LENGTH} characters total (${API_KEY.PREFIX} + ${API_KEY.HEX_LENGTH} hex chars)`);
335
358
  }
336
- const hexPart = apiKey.slice(API_KEY_PREFIX.length);
359
+ const hexPart = apiKey.slice(API_KEY.PREFIX.length);
337
360
  if (!/^[a-f0-9]{64}$/i.test(hexPart)) {
338
- throw ShipError.validation(`API key must contain ${API_KEY_HEX_LENGTH} hexadecimal characters after "${API_KEY_PREFIX}" prefix`);
361
+ throw ShipError.validation(`API key must contain ${API_KEY.HEX_LENGTH} hexadecimal characters after "${API_KEY.PREFIX}" prefix`);
339
362
  }
340
363
  }
341
364
  /**
342
365
  * Validate deploy token format
343
366
  */
344
367
  export function validateDeployToken(deployToken) {
345
- if (!deployToken.startsWith(DEPLOY_TOKEN_PREFIX)) {
346
- throw ShipError.validation(`Deploy token must start with "${DEPLOY_TOKEN_PREFIX}"`);
368
+ if (!deployToken.startsWith(DEPLOY_TOKEN.PREFIX)) {
369
+ throw ShipError.validation(`Deploy token must start with "${DEPLOY_TOKEN.PREFIX}"`);
347
370
  }
348
- if (deployToken.length !== DEPLOY_TOKEN_TOTAL_LENGTH) {
349
- throw ShipError.validation(`Deploy token must be ${DEPLOY_TOKEN_TOTAL_LENGTH} characters total (${DEPLOY_TOKEN_PREFIX} + ${DEPLOY_TOKEN_HEX_LENGTH} hex chars)`);
371
+ if (deployToken.length !== DEPLOY_TOKEN.TOTAL_LENGTH) {
372
+ throw ShipError.validation(`Deploy token must be ${DEPLOY_TOKEN.TOTAL_LENGTH} characters total (${DEPLOY_TOKEN.PREFIX} + ${DEPLOY_TOKEN.HEX_LENGTH} hex chars)`);
350
373
  }
351
- const hexPart = deployToken.slice(DEPLOY_TOKEN_PREFIX.length);
374
+ const hexPart = deployToken.slice(DEPLOY_TOKEN.PREFIX.length);
352
375
  if (!/^[a-f0-9]{64}$/i.test(hexPart)) {
353
- throw ShipError.validation(`Deploy token must contain ${DEPLOY_TOKEN_HEX_LENGTH} hexadecimal characters after "${DEPLOY_TOKEN_PREFIX}" prefix`);
376
+ throw ShipError.validation(`Deploy token must contain ${DEPLOY_TOKEN.HEX_LENGTH} hexadecimal characters after "${DEPLOY_TOKEN.PREFIX}" prefix`);
354
377
  }
355
378
  }
356
379
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shipstatic/types",
3
- "version": "0.9.0",
3
+ "version": "0.9.1",
4
4
  "description": "Shared types for ShipStatic platform",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
package/src/index.ts CHANGED
@@ -341,39 +341,48 @@ export interface AccountOverrides {
341
341
  // =============================================================================
342
342
 
343
343
  /**
344
- * All possible error types in the ShipStatic platform
345
- * Names are developer-friendly while wire format stays consistent
344
+ * All possible error types in the ShipStatic platform.
345
+ *
346
+ * Developer-friendly key names map to stable wire-format string values.
347
+ * Both the value and the type are exported under the same name so callers
348
+ * can use `ErrorType.Validation` (value comparison) and `: ErrorType` (type
349
+ * annotation) without ceremony — matching the pattern other status objects
350
+ * (`DeploymentStatus`, `DomainStatus`, `AccountPlan`, `AuthMethod`) follow.
346
351
  */
347
- export enum ErrorType {
352
+ export const ErrorType = {
348
353
  /** Validation failed (400) */
349
- Validation = "validation_failed",
354
+ Validation: 'validation_failed',
350
355
  /** Resource not found (404) */
351
- NotFound = "not_found",
356
+ NotFound: 'not_found',
352
357
  /** Rate limit exceeded (429) */
353
- RateLimit = "rate_limit_exceeded",
358
+ RateLimit: 'rate_limit_exceeded',
354
359
  /** Authentication required (401) */
355
- Authentication = "authentication_failed",
360
+ Authentication: 'authentication_failed',
356
361
  /** Business logic error (400) */
357
- Business = "business_logic_error",
358
- /** API server error (500) - renamed from Internal for clarity */
359
- Api = "internal_server_error",
362
+ Business: 'business_logic_error',
363
+ /** API server error (500) */
364
+ Api: 'internal_server_error',
360
365
  /** Network/connection error */
361
- Network = "network_error",
366
+ Network: 'network_error',
362
367
  /** Operation was cancelled */
363
- Cancelled = "operation_cancelled",
368
+ Cancelled: 'operation_cancelled',
364
369
  /** File operation error */
365
- File = "file_error",
370
+ File: 'file_error',
366
371
  /** Configuration error */
367
- Config = "config_error"
368
- }
372
+ Config: 'config_error',
373
+ } as const;
374
+
375
+ export type ErrorType = typeof ErrorType[keyof typeof ErrorType];
369
376
 
370
377
  /**
371
- * Categorizes error types for better type checking
378
+ * Categorizes error types for the `isClientError` / `isNetworkError` /
379
+ * `isAuthError` helpers. Each `Set` is typed against the wider `ErrorType`
380
+ * union so `.has(error.type)` accepts any value from the union.
372
381
  */
373
382
  const ERROR_CATEGORIES = {
374
- client: new Set([ErrorType.Business, ErrorType.Config, ErrorType.File, ErrorType.Validation]),
375
- network: new Set([ErrorType.Network]),
376
- auth: new Set([ErrorType.Authentication]),
383
+ client: new Set<ErrorType>([ErrorType.Business, ErrorType.Config, ErrorType.File, ErrorType.Validation]),
384
+ network: new Set<ErrorType>([ErrorType.Network]),
385
+ auth: new Set<ErrorType>([ErrorType.Authentication]),
377
386
  } as const;
378
387
 
379
388
  /**
@@ -536,12 +545,22 @@ export function isShipError(error: unknown): error is ShipError {
536
545
  // =============================================================================
537
546
 
538
547
  /**
539
- * Dynamic platform configuration returned by the /config endpoint.
540
- * Contains plan-based limits that vary by account.
548
+ * Plan-based platform limits returned by the `/config` endpoint.
549
+ *
550
+ * The SDK fetches these once on first API call to drive client-side
551
+ * file-size / file-count / total-size validation that mirrors what the API
552
+ * would enforce server-side. Limits vary by account plan.
553
+ *
554
+ * Distinct from `ResolvedConfig` (which carries the *client's* credentials
555
+ * and API URL after defaulting); this one carries the *platform's* posted
556
+ * caps for the current account.
541
557
  */
542
- export interface ConfigResponse {
558
+ export interface PlatformLimits {
559
+ /** Maximum size in bytes for a single file. */
543
560
  maxFileSize: number;
561
+ /** Maximum number of files in a single deployment. */
544
562
  maxFilesCount: number;
563
+ /** Maximum total size in bytes across all files in a deployment. */
545
564
  maxTotalSize: number;
546
565
  }
547
566
 
@@ -667,16 +686,33 @@ export interface PingResponse {
667
686
  timestamp?: number;
668
687
  }
669
688
 
670
- // API Key Configuration
671
- export const API_KEY_PREFIX = 'ship-';
672
- export const API_KEY_HEX_LENGTH = 64;
673
- export const API_KEY_TOTAL_LENGTH = API_KEY_PREFIX.length + API_KEY_HEX_LENGTH; // 69
674
- export const API_KEY_HINT_LENGTH = 4;
689
+ /**
690
+ * Shape constants for API keys (`ship-{64 hex chars}`).
691
+ * Single source of truth used by validation utilities and auth middleware.
692
+ */
693
+ export const API_KEY = {
694
+ /** Prefix that identifies an API key. */
695
+ PREFIX: 'ship-',
696
+ /** Number of hex characters following the prefix. */
697
+ HEX_LENGTH: 64,
698
+ /** Total length of an API key including prefix (`PREFIX.length + HEX_LENGTH = 69`). */
699
+ TOTAL_LENGTH: 69,
700
+ /** Number of trailing characters used to display a redacted hint (e.g. last 4). */
701
+ HINT_LENGTH: 4,
702
+ } as const;
675
703
 
676
- // Deploy Token Configuration
677
- export const DEPLOY_TOKEN_PREFIX = 'token-';
678
- export const DEPLOY_TOKEN_HEX_LENGTH = 64;
679
- export const DEPLOY_TOKEN_TOTAL_LENGTH = DEPLOY_TOKEN_PREFIX.length + DEPLOY_TOKEN_HEX_LENGTH; // 70
704
+ /**
705
+ * Shape constants for deploy tokens (`token-{64 hex chars}`).
706
+ * Single source of truth used by validation utilities and auth middleware.
707
+ */
708
+ export const DEPLOY_TOKEN = {
709
+ /** Prefix that identifies a deploy token. */
710
+ PREFIX: 'token-',
711
+ /** Number of hex characters following the prefix. */
712
+ HEX_LENGTH: 64,
713
+ /** Total length of a deploy token including prefix (`PREFIX.length + HEX_LENGTH = 70`). */
714
+ TOTAL_LENGTH: 70,
715
+ } as const;
680
716
 
681
717
  // Authentication Method Constants
682
718
  export const AuthMethod = {
@@ -703,17 +739,17 @@ export const SPA_DEFAULT_CONFIG = { rewrites: [{ source: '/(.*)', destination: '
703
739
  * Validate API key format
704
740
  */
705
741
  export function validateApiKey(apiKey: string): void {
706
- if (!apiKey.startsWith(API_KEY_PREFIX)) {
707
- throw ShipError.validation(`API key must start with "${API_KEY_PREFIX}"`);
742
+ if (!apiKey.startsWith(API_KEY.PREFIX)) {
743
+ throw ShipError.validation(`API key must start with "${API_KEY.PREFIX}"`);
708
744
  }
709
745
 
710
- if (apiKey.length !== API_KEY_TOTAL_LENGTH) {
711
- throw ShipError.validation(`API key must be ${API_KEY_TOTAL_LENGTH} characters total (${API_KEY_PREFIX} + ${API_KEY_HEX_LENGTH} hex chars)`);
746
+ if (apiKey.length !== API_KEY.TOTAL_LENGTH) {
747
+ throw ShipError.validation(`API key must be ${API_KEY.TOTAL_LENGTH} characters total (${API_KEY.PREFIX} + ${API_KEY.HEX_LENGTH} hex chars)`);
712
748
  }
713
749
 
714
- const hexPart = apiKey.slice(API_KEY_PREFIX.length);
750
+ const hexPart = apiKey.slice(API_KEY.PREFIX.length);
715
751
  if (!/^[a-f0-9]{64}$/i.test(hexPart)) {
716
- throw ShipError.validation(`API key must contain ${API_KEY_HEX_LENGTH} hexadecimal characters after "${API_KEY_PREFIX}" prefix`);
752
+ throw ShipError.validation(`API key must contain ${API_KEY.HEX_LENGTH} hexadecimal characters after "${API_KEY.PREFIX}" prefix`);
717
753
  }
718
754
  }
719
755
 
@@ -721,17 +757,17 @@ export function validateApiKey(apiKey: string): void {
721
757
  * Validate deploy token format
722
758
  */
723
759
  export function validateDeployToken(deployToken: string): void {
724
- if (!deployToken.startsWith(DEPLOY_TOKEN_PREFIX)) {
725
- throw ShipError.validation(`Deploy token must start with "${DEPLOY_TOKEN_PREFIX}"`);
760
+ if (!deployToken.startsWith(DEPLOY_TOKEN.PREFIX)) {
761
+ throw ShipError.validation(`Deploy token must start with "${DEPLOY_TOKEN.PREFIX}"`);
726
762
  }
727
763
 
728
- if (deployToken.length !== DEPLOY_TOKEN_TOTAL_LENGTH) {
729
- throw ShipError.validation(`Deploy token must be ${DEPLOY_TOKEN_TOTAL_LENGTH} characters total (${DEPLOY_TOKEN_PREFIX} + ${DEPLOY_TOKEN_HEX_LENGTH} hex chars)`);
764
+ if (deployToken.length !== DEPLOY_TOKEN.TOTAL_LENGTH) {
765
+ throw ShipError.validation(`Deploy token must be ${DEPLOY_TOKEN.TOTAL_LENGTH} characters total (${DEPLOY_TOKEN.PREFIX} + ${DEPLOY_TOKEN.HEX_LENGTH} hex chars)`);
730
766
  }
731
767
 
732
- const hexPart = deployToken.slice(DEPLOY_TOKEN_PREFIX.length);
768
+ const hexPart = deployToken.slice(DEPLOY_TOKEN.PREFIX.length);
733
769
  if (!/^[a-f0-9]{64}$/i.test(hexPart)) {
734
- throw ShipError.validation(`Deploy token must contain ${DEPLOY_TOKEN_HEX_LENGTH} hexadecimal characters after "${DEPLOY_TOKEN_PREFIX}" prefix`);
770
+ throw ShipError.validation(`Deploy token must contain ${DEPLOY_TOKEN.HEX_LENGTH} hexadecimal characters after "${DEPLOY_TOKEN.PREFIX}" prefix`);
735
771
  }
736
772
  }
737
773
 
@@ -886,28 +922,16 @@ export const DEFAULT_API = 'https://api.shipstatic.com';
886
922
  // =============================================================================
887
923
 
888
924
  /**
889
- * Browser-specific deploy input — an array of `File` objects (typically from
890
- * `<input type="file">` or drag-and-drop). The Browser SDK rejects any other
891
- * shape at runtime.
892
- */
893
- export type BrowserDeployInput = File[];
894
-
895
- /**
896
- * Node-specific deploy input — file or directory path(s) on disk. A single
897
- * path or an array of paths; directories are walked recursively. The Node
898
- * SDK rejects any other shape at runtime.
899
- */
900
- export type NodeDeployInput = string | string[];
901
-
902
- /**
903
- * Universal deploy input — the union of every platform's accepted shape.
925
+ * Universal deploy input — the union of every shape the SDK accepts.
926
+ *
927
+ * - **Browser**: `File[]` (typically from `<input type="file">` or drag-and-drop)
928
+ * - **Node**: `string | string[]` (file or directory path(s) on disk; directories are walked)
904
929
  *
905
- * Prefer the platform-specific aliases (`BrowserDeployInput` /
906
- * `NodeDeployInput`) when writing platform-specific code; `DeployInput` is
907
- * the right type only for code that genuinely needs to accept either. Each
908
- * platform's SDK validates at runtime and throws on the wrong shape.
930
+ * Each platform's SDK narrows its `deploy()` signature to the relevant shape
931
+ * and rejects anything else at runtime. Use the structural types directly
932
+ * (`File[]`, `string | string[]`) when writing platform-specific code.
909
933
  */
910
- export type DeployInput = BrowserDeployInput | NodeDeployInput;
934
+ export type DeployInput = File[] | string | string[];
911
935
 
912
936
  /**
913
937
  * Options for deployment creation at the API contract level.
@@ -1010,34 +1034,6 @@ export interface CheckoutSession {
1010
1034
  url: string;
1011
1035
  }
1012
1036
 
1013
- /**
1014
- * Billing resource interface - the contract all implementations must follow
1015
- *
1016
- * IMPOSSIBLE SIMPLICITY: No sync() method needed!
1017
- * Webhooks are the single source of truth. Frontend just polls status().
1018
- */
1019
- export interface BillingResource {
1020
- /**
1021
- * Create a checkout session
1022
- * @returns Checkout session with URL to redirect user
1023
- */
1024
- checkout: () => Promise<CheckoutSession>;
1025
-
1026
- /**
1027
- * Get current billing status
1028
- * @returns Billing status and usage information
1029
- */
1030
- status: () => Promise<BillingStatus>;
1031
- }
1032
-
1033
-
1034
- /**
1035
- * Keys resource interface - the contract all implementations must follow
1036
- */
1037
- export interface KeysResource {
1038
- create: () => Promise<{ apiKey: string }>;
1039
- }
1040
-
1041
1037
  // =============================================================================
1042
1038
  // ACTIVITY TYPES
1043
1039
  // =============================================================================