@shipstatic/ship 0.3.15 → 0.4.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
@@ -1,821 +1,209 @@
1
- # 🚢 Ship CLI & SDK
1
+ # @shipstatic/ship
2
2
 
3
- A modern, lightweight SDK and CLI for deploying static files, designed for both **Node.js** and **Browser** environments with a clean resource-based API and comprehensive event system for observability.
4
-
5
- ## Features
6
-
7
- - **🚀 Modern Resource API**: Clean `ship.deployments.create()` interface - no legacy wrappers
8
- - **🌍 Universal**: Automatic environment detection (Node.js/Browser) with optimized implementations
9
- - **📡 Event System**: Complete observability with request, response, and error events
10
- - **🔧 Dynamic Configuration**: Automatically fetches platform limits from API
11
- - **✅ Client-Side Validation**: Validate files before upload (size, count, MIME types)
12
- - **📁 Flexible Input**: File paths (Node.js) or File objects (Browser/drag-drop)
13
- - **🔐 Secure**: MD5 checksums and data integrity validation
14
- - **📊 Progress Tracking**: Real-time deployment progress and statistics
15
- - **⚡ Cancellable**: AbortSignal support for deployment cancellation
16
- - **🛠️ CLI Ready**: Command-line interface for automation and CI/CD
17
- - **📦 Bundle Optimized**: Lightweight builds (21KB Node, 185KB Browser)
18
- - **🎯 Unified Error System**: Consistent `ShipError` handling across all components
3
+ Universal SDK and CLI for deploying static files to Shipstatic.
19
4
 
20
5
  ## Installation
21
6
 
22
- ### CLI Usage
23
-
24
7
  ```bash
8
+ # CLI (global)
25
9
  npm install -g @shipstatic/ship
26
- ```
27
10
 
28
- ### SDK Usage
29
-
30
- ```bash
11
+ # SDK (project dependency)
31
12
  npm install @shipstatic/ship
32
13
  ```
33
14
 
34
- ## Import Patterns
35
-
36
- ### Default Import (Main Class)
37
- ```javascript
38
- // ES Modules
39
- import Ship from '@shipstatic/ship';
40
-
41
- // CommonJS
42
- const Ship = require('@shipstatic/ship');
43
- ```
44
-
45
- ### Named Imports (Utilities)
46
- ```javascript
47
- // ES Modules
48
- import { ShipError } from '@shipstatic/ship';
49
-
50
- // CommonJS
51
- const { ShipError } = require('@shipstatic/ship');
52
- ```
53
-
54
- ## Quick Start
55
-
56
- ### SDK Usage
57
-
58
- ```javascript
59
- // ES Modules
60
- import Ship from '@shipstatic/ship';
61
-
62
- // CommonJS
63
- const Ship = require('@shipstatic/ship');
64
-
65
- // Authenticated deployments with API key
66
- const ship = new Ship({
67
- apiUrl: 'https://api.shipstatic.com',
68
- apiKey: 'ship-your-64-char-hex-string' // API key: ship- prefix + 64-char hex (69 chars total)
69
- });
70
-
71
- // OR single-use deployments with deploy token
72
- const ship = new Ship({
73
- apiUrl: 'https://api.shipstatic.com',
74
- deployToken: 'token-your-64-char-hex-string' // Deploy token: token- prefix + 64-char hex (70 chars total)
75
- });
76
-
77
- // Deploy project - SDK automatically fetches platform configuration
78
- const result = await ship.deployments.create(['./dist'], {
79
- onProgress: ({ percent }) => console.log(`${percent}%`)
80
- });
81
-
82
- console.log(`Deployed: ${result.deployment}`);
83
- ```
84
-
85
- ### CLI Usage
15
+ ## CLI Usage
86
16
 
87
17
  ```bash
88
- # Deploy shortcut - deploy a directory
18
+ # Deploy a directory
89
19
  ship ./dist
90
20
 
91
- # Or deploy current directory
92
- ship
93
-
94
21
  # Deploy with tags
95
- ship deployments create ./dist --tag production --tag v1.0.0
96
-
97
- # Explicit commands
98
- ship deploy ./build # Deploy project from path
99
- ship list # List deployments
100
- ship get abc123 # Get deployment details
101
- ship remove abc123 # Remove deployment
102
-
103
- # Manage domains
104
- ship domains list # List domains
105
- ship domains set staging abc123 # Set domain to deployment
106
- ship domains set prod abc123 --tag production # Set domain with tag
107
- ship domains set prod abc123 --tag prod --tag v1 # Set domain with multiple tags
108
- ship domains verify www.example.com # Trigger DNS verification
109
- ship domains remove staging # Remove domain
22
+ ship ./dist --tag production --tag v1.0.0
23
+
24
+ # Deployments
25
+ ship deployments list
26
+ ship deployments get <id>
27
+ ship deployments set <id> --tag production # Update tags
28
+ ship deployments remove <id>
29
+
30
+ # Domains
31
+ ship domains list
32
+ ship domains set staging <deployment-id> # Point domain to deployment
33
+ ship domains set staging --tag production # Update domain tags
34
+ ship domains get staging
35
+ ship domains verify www.example.com
36
+ ship domains remove staging
37
+
38
+ # Tokens
39
+ ship tokens list
40
+ ship tokens create --ttl 3600 --tag ci
41
+ ship tokens remove <token>
110
42
 
111
43
  # Account
112
- ship account # Get account details
113
-
114
- # Connectivity
115
- ship ping # Check API connectivity
116
- ```
117
-
118
- ## Dynamic Platform Configuration
119
-
120
- Ship SDK automatically fetches platform configuration from the API on initialization:
121
-
122
- ```typescript
123
- // SDK automatically calls GET /config and applies limits
124
- const ship = new Ship({ apiKey: 'ship-your-key' });
125
-
126
- // Platform limits are available for validation:
127
- // - maxFileSize: Dynamic file size limit
128
- // - maxFilesCount: Dynamic file count limit
129
- // - maxTotalSize: Dynamic total size limit
130
- ```
131
-
132
- **Benefits:**
133
- - **Single source of truth** - Limits only need to be changed on the API side
134
- - **Always current** - SDK always uses current platform limits
135
- - **Fail fast** - SDK fails if unable to fetch valid configuration
136
-
137
- ## Client-Side File Validation
138
-
139
- Ship SDK provides utilities for validating files before upload. Validation is **atomic** - if any file is invalid, the entire upload is rejected.
140
-
141
- ```typescript
142
- import { validateFiles, formatFileSize } from '@shipstatic/ship';
143
-
144
- // Get platform configuration
145
- const config = await ship.getConfig();
146
-
147
- // Validate files before upload
148
- const result = validateFiles(files, config);
149
-
150
- if (result.error) {
151
- // Global summary
152
- console.error(result.error.details); // "2 files failed validation"
153
-
154
- // All specific errors
155
- result.error.errors.forEach(err => console.error(err));
156
- // "file1.wasm: File type 'application/wasm' is not allowed"
157
- // "file2.txt: File size (10 MB) exceeds limit of 5 MB"
158
-
159
- // Per-file status (all files marked failed in atomic validation)
160
- result.files.forEach(f => {
161
- console.log(`${f.name}: ${f.statusMessage}`);
162
- });
163
- } else {
164
- console.log(`${result.validFiles.length} files ready to upload`);
165
- await ship.deployments.create(result.validFiles);
166
- }
44
+ ship whoami
167
45
  ```
168
46
 
169
- **Validation checks:**
170
- - File count limit
171
- - Individual file size limit
172
- - Total deployment size limit
173
- - MIME type validation (against allowed categories)
174
- - Empty file detection
175
-
176
- **Error handling:**
177
- - `error.details` - Human-readable summary ("2 files failed validation")
178
- - `error.errors` - Array of all validation errors for detailed display
179
- - `file.statusMessage` - Individual file status for UI highlighting
180
-
181
- **Utilities:**
182
- - `validateFiles(files, config)` - Validate files against config limits
183
- - `formatFileSize(bytes, decimals?)` - Format bytes to human-readable string
184
- - `getValidFiles(files)` - Filter files with `READY` status
185
- - `FILE_VALIDATION_STATUS` - Status constants for file processing
186
-
187
- ## API Reference
188
-
189
- ### Ship Class
47
+ ## SDK Usage
190
48
 
191
- ```typescript
192
- const ship = new Ship(options?: ShipOptions)
193
- ```
194
-
195
- #### Options
196
-
197
- ```typescript
198
- // TypeScript types available for both import styles
199
- interface ShipOptions {
200
- apiUrl?: string; // API endpoint (default: https://api.shipstatic.com)
201
- apiKey?: string; // API key: ship- prefix + 64-char hex (69 chars total)
202
- deployToken?: string; // Deploy token: token- prefix + 64-char hex (70 chars total)
203
- timeout?: number; // Request timeout (ms)
204
- useCredentials?: boolean; // Use HTTP-only cookies for auth (skips token check)
205
- caller?: string; // Identifier for multi-tenant deployments (e.g., CI system name)
206
- }
207
- ```
208
-
209
- #### Methods
210
-
211
- - `ship.ping()` - Check API connectivity
212
- - `ship.deployments` - Access deployment resource
213
- - `ship.domains` - Access domain resource
214
- - `ship.account` - Access account resource
215
- - `ship.on(event, handler)` - Add event listener for API observability
216
- - `ship.off(event, handler)` - Remove event listener
217
-
218
- ### Deployments Resource
219
-
220
- ```typescript
221
- // Deploy project
222
- await ship.deployments.create(input, options?)
223
-
224
- // List deployments
225
- await ship.deployments.list()
226
-
227
- // Remove deployment
228
- await ship.deployments.remove(id)
229
-
230
- // Get deployment details
231
- await ship.deployments.get(id)
232
- ```
233
-
234
- #### Deploy Input Types
235
-
236
- ```typescript
237
- type DeployInput = File[] | string | string[];
238
- ```
239
-
240
- **Node.js Environment:**
241
- - `string` - Single file or directory path
242
- - `string[]` - Multiple file/directory paths
243
-
244
- **Browser Environment:**
245
- - `File[]` - Array of File objects
246
-
247
- **Note:** For `<input type="file">` elements, convert FileList to File[]:
248
- ```typescript
249
- const files = Array.from(fileInput.files);
250
- await ship.deploy(files);
251
- ```
252
-
253
- #### Deploy Options
254
-
255
- ```typescript
256
- interface DeployOptions {
257
- apiUrl?: string;
258
- apiKey?: string; // API key: ship- prefix + 64-char hex (69 chars total)
259
- deployToken?: string; // Deploy token: token- prefix + 64-char hex (70 chars total)
260
- tags?: string[]; // Optional array of tags for categorization
261
- signal?: AbortSignal; // Cancellation
262
- subdomain?: string; // Custom subdomain
263
- onCancel?: () => void;
264
- onProgress?: (info: ProgressInfo) => void; // Progress with percent (0-100), loaded, total bytes
265
- maxConcurrency?: number;
266
- timeout?: number;
267
- stripCommonPrefix?: boolean; // Remove common path prefix
268
- via?: string; // Client identifier (auto-set: 'sdk' for SDK, 'cli' for CLI)
269
- caller?: string; // Multi-tenant identifier (e.g., 'github-actions', 'jenkins')
270
- }
271
- ```
272
-
273
- ### Domains Resource
274
-
275
- ```typescript
276
- // Set or update a domain (with optional tags)
277
- await ship.domains.set(domainName, deploymentId, tags?)
278
-
279
- // Get domain details
280
- await ship.domains.get(domainName)
281
-
282
- // List all domains
283
- await ship.domains.list()
284
-
285
- // Remove domain
286
- await ship.domains.remove(domainName)
287
-
288
- // Trigger DNS verification for external domain
289
- await ship.domains.verify(domainName)
290
- ```
291
-
292
- **Examples:**
293
49
  ```javascript
294
- // Set domain without tags
295
- await ship.domains.set('staging', 'dep_abc123');
296
-
297
- // Set domain with tags
298
- await ship.domains.set('production', 'dep_xyz789', ['prod', 'v1.0.0']);
299
-
300
- // Verify DNS for external domain
301
- await ship.domains.verify('www.example.com');
302
- ```
303
-
304
- ### Environment-Specific Examples
305
-
306
- #### Node.js File Deployment
307
-
308
- ```javascript
309
- // ES Modules
310
50
  import Ship from '@shipstatic/ship';
311
51
 
312
- // CommonJS
313
- const Ship = require('@shipstatic/ship');
314
-
315
52
  const ship = new Ship({
316
- apiUrl: 'https://api.shipstatic.com',
317
- apiKey: process.env.SHIP_API_KEY // ship-abc123...
53
+ apiKey: 'ship-your-api-key'
318
54
  });
319
55
 
320
- // Deploy project and directories
321
- const result = await ship.deployments.create([
322
- './dist/index.html',
323
- './dist/assets',
324
- './public'
325
- ], {
326
- stripCommonPrefix: true,
327
- onProgress: ({ percent }) => {
328
- console.log(`Deployment: ${percent}% complete`);
329
- }
56
+ // Deploy
57
+ const result = await ship.deployments.create('./dist', {
58
+ onProgress: ({ percent }) => console.log(`${percent}%`)
330
59
  });
331
60
 
332
- console.log(`✅ Deployed: ${result.deployment}`);
333
- ```
334
-
335
- #### Browser File Upload
61
+ console.log(`Deployed: ${result.url}`);
336
62
 
337
- ```javascript
338
- // ES Modules
339
- import Ship from '@shipstatic/ship';
340
-
341
- // Browser (ES Modules only)
342
-
343
- const ship = new Ship({
344
- apiUrl: 'https://api.shipstatic.com',
345
- apiKey: 'ship-your-64-char-hex-string' // 69 chars total
346
- });
63
+ // Manage domains
64
+ await ship.domains.set('staging', { deployment: result.deployment });
65
+ await ship.domains.list();
347
66
 
348
- // From file input - convert FileList to File[]
349
- const fileInput = document.getElementById('fileInput') as HTMLInputElement;
350
- const files: File[] = Array.from(fileInput.files || []);
351
- const result = await ship.deployments.create(files, {
352
- onProgress: ({ percent }) => {
353
- document.getElementById('progress').textContent = `${percent}%`;
354
- }
355
- });
67
+ // Update tags
68
+ await ship.deployments.set(result.deployment, { tags: ['production', 'v1.0'] });
69
+ await ship.domains.set('staging', { tags: ['live'] });
356
70
  ```
357
71
 
358
- ## Event System
359
-
360
- Ship SDK provides a comprehensive event system for complete observability of all API operations. The event system is lightweight, reliable, and provides detailed insights into requests, responses, and errors.
361
-
362
- ### Event Types
363
-
364
- The SDK emits three core events:
365
-
366
- - **`request`** - Emitted before each API request
367
- - **`response`** - Emitted after successful API responses
368
- - **`error`** - Emitted when API requests fail
369
-
370
- ### Basic Event Usage
72
+ ## Browser Usage
371
73
 
372
74
  ```javascript
373
75
  import Ship from '@shipstatic/ship';
374
76
 
375
77
  const ship = new Ship({ apiKey: 'ship-your-api-key' });
376
78
 
377
- // Listen to all API requests
378
- ship.on('request', (url, requestInit) => {
379
- console.log(`→ ${requestInit.method} ${url}`);
380
- });
381
-
382
- // Listen to all API responses
383
- ship.on('response', (response, url) => {
384
- console.log(`← ${response.status} ${url}`);
385
- });
386
-
387
- // Listen to all API errors
388
- ship.on('error', (error, url) => {
389
- console.error(`✗ Error at ${url}:`, error.message);
390
- });
391
-
392
- // Deploy with events
393
- const result = await ship.deployments.create('./dist');
79
+ // From file input
80
+ const files = Array.from(fileInput.files);
81
+ const result = await ship.deployments.create(files);
394
82
  ```
395
83
 
396
- ### Advanced Event Patterns
84
+ ## Authentication
397
85
 
398
- #### Request/Response Logging
399
86
  ```javascript
400
- // Log all API traffic
401
- ship.on('request', (url, init) => {
402
- console.log(`[${new Date().toISOString()}] ${init.method} ${url}`);
403
- if (init.body) {
404
- console.log(` Body: ${init.body instanceof FormData ? '[FormData]' : init.body}`);
405
- }
87
+ // API key (persistent access)
88
+ const ship = new Ship({
89
+ apiKey: 'ship-...' // 69 chars: ship- + 64 hex
406
90
  });
407
91
 
408
- ship.on('response', (response, url) => {
409
- console.log(`[${new Date().toISOString()}] ${response.status} ${response.statusText} ${url}`);
92
+ // Deploy token (single-use)
93
+ const ship = new Ship({
94
+ deployToken: 'token-...' // 70 chars: token- + 64 hex
410
95
  });
411
96
  ```
412
97
 
413
- #### Error Monitoring
414
- ```javascript
415
- // Comprehensive error tracking
416
- ship.on('error', (error, url) => {
417
- // Send to monitoring service
418
- analytics.track('ship_api_error', {
419
- url,
420
- error: error.message,
421
- type: error.constructor.name,
422
- timestamp: Date.now()
423
- });
424
- });
425
- ```
98
+ ## Configuration
426
99
 
427
- #### Performance Monitoring
100
+ **Constructor options** (highest priority):
428
101
  ```javascript
429
- const requestTimes = new Map();
430
-
431
- ship.on('request', (url, init) => {
432
- requestTimes.set(url, Date.now());
433
- });
434
-
435
- ship.on('response', (response, url) => {
436
- const startTime = requestTimes.get(url);
437
- if (startTime) {
438
- const duration = Date.now() - startTime;
439
- console.log(`${url} took ${duration}ms`);
440
- requestTimes.delete(url);
441
- }
442
- });
102
+ new Ship({ apiUrl: '...', apiKey: '...' })
443
103
  ```
444
104
 
445
- #### Custom Analytics Integration
446
- ```javascript
447
- // Google Analytics integration
448
- ship.on('request', (url, init) => {
449
- gtag('event', 'api_request', {
450
- 'custom_url': url,
451
- 'method': init.method
452
- });
453
- });
454
-
455
- ship.on('response', (response, url) => {
456
- gtag('event', 'api_response', {
457
- 'custom_url': url,
458
- 'status_code': response.status
459
- });
460
- });
105
+ **Environment variables** (Node.js):
106
+ ```bash
107
+ SHIP_API_URL=https://api.shipstatic.com
108
+ SHIP_API_KEY=ship-your-api-key
461
109
  ```
462
110
 
463
- ### Event Handler Management
464
-
465
- ```javascript
466
- // Add event handlers
467
- const requestHandler = (url, init) => console.log(`Request: ${url}`);
468
- ship.on('request', requestHandler);
469
-
470
- // Remove specific handlers
471
- ship.off('request', requestHandler);
472
-
473
- // Event handlers are automatically cleaned up when ship instance is garbage collected
111
+ **Config files** (Node.js):
112
+ ```json
113
+ // .shiprc or package.json "ship" key
114
+ { "apiUrl": "...", "apiKey": "..." }
474
115
  ```
475
116
 
476
- ### Event System Features
477
-
478
- - **Reliable**: Handlers that throw errors are automatically removed to prevent cascading failures
479
- - **Safe**: Response objects are safely cloned for event handlers to prevent body consumption conflicts
480
- - **Lightweight**: Minimal overhead - only 70 lines of code
481
- - **Type Safe**: Full TypeScript support with proper event argument typing
482
- - **Clean**: Automatic cleanup prevents memory leaks
117
+ ## API Reference
483
118
 
484
- ### TypeScript Event Types
119
+ ### Resources
485
120
 
486
121
  ```typescript
487
- import Ship from '@shipstatic/ship';
488
-
489
- const ship = new Ship({ apiKey: 'ship-your-api-key' });
490
-
491
- // Fully typed event handlers
492
- ship.on('request', (url: string, init: RequestInit) => {
493
- console.log(`Request to ${url}`);
494
- });
122
+ // Deployments
123
+ ship.deployments.create(input, options?) // Create new deployment
124
+ ship.deployments.list() // List all deployments
125
+ ship.deployments.get(id) // Get deployment details
126
+ ship.deployments.set(id, { tags }) // Update deployment tags
127
+ ship.deployments.remove(id) // Delete deployment
495
128
 
496
- ship.on('response', (response: Response, url: string) => {
497
- console.log(`Response from ${url}: ${response.status}`);
498
- });
129
+ // Domains
130
+ ship.domains.set(name, { deployment?, tags? }) // Create/update domain (see below)
131
+ ship.domains.get(name) // Get domain details
132
+ ship.domains.list() // List all domains
133
+ ship.domains.remove(name) // Delete domain
134
+ ship.domains.verify(name) // Trigger DNS verification
499
135
 
500
- ship.on('error', (error: Error, url: string) => {
501
- console.error(`Error at ${url}:`, error);
502
- });
503
- ```
504
-
505
- ### Event System Architecture
506
-
507
- The event system is built directly into the HTTP client with:
508
- - **Direct Integration**: Events are emitted from the core HTTP operations
509
- - **Error Boundaries**: Failed event handlers don't crash API operations
510
- - **Response Cloning**: Dedicated response clones for events and parsing
511
- - **Graceful Degradation**: Event system failures don't affect core functionality
512
-
513
- ## Unified Error Handling
514
-
515
- The Ship SDK uses a unified error system with a single `ShipError` class:
516
-
517
- ```javascript
518
- // ES Modules
519
- import { ShipError } from '@shipstatic/ship';
136
+ // Tokens
137
+ ship.tokens.create({ ttl?, tags? }) // Create deploy token
138
+ ship.tokens.list() // List all tokens
139
+ ship.tokens.remove(token) // Revoke token
520
140
 
521
- // CommonJS
522
- const { ShipError } = require('@shipstatic/ship');
141
+ // Account
142
+ ship.whoami() // Get current account
523
143
 
524
- try {
525
- await ship.deployments.create(['./dist']);
526
- } catch (error) {
527
- if (error instanceof ShipError) {
528
- console.error(`Ship Error: ${error.message}`);
529
-
530
- // Type-safe error checking
531
- if (error.isClientError()) {
532
- console.error(`Client Error: ${error.message}`);
533
- } else if (error.isNetworkError()) {
534
- console.error(`Network Error: ${error.message}`);
535
- } else if (error.isAuthError()) {
536
- console.error(`Auth Error: ${error.message}`);
537
- } else if (error.isValidationError()) {
538
- console.error(`Validation Error: ${error.message}`);
539
- }
540
- }
541
- }
144
+ // Connectivity
145
+ ship.ping() // Check API connectivity
542
146
  ```
543
147
 
544
- ### Error Types
148
+ ### domains.set() Behavior
545
149
 
546
150
  ```typescript
547
- // Factory methods for creating errors
548
- ShipError.validation(message, details) // Validation failed (400)
549
- ShipError.notFound(resource, id) // Resource not found (404)
550
- ShipError.rateLimit(message) // Rate limit exceeded (429)
551
- ShipError.authentication(message) // Authentication required (401)
552
- ShipError.business(message, status) // Business logic error (400)
553
- ShipError.network(message, cause) // Network/connection error
554
- ShipError.cancelled(message) // Operation was cancelled
555
- ShipError.file(message, filePath) // File operation error
556
- ShipError.config(message) // Configuration error
557
-
558
- // Type checking methods
559
- error.isClientError() // Client-side errors
560
- error.isNetworkError() // Network/connection issues
561
- error.isAuthError() // Authentication problems
562
- error.isValidationError() // Input validation failures
563
- error.isFileError() // File operation errors
564
- error.isConfigError() // Configuration problems
565
- ```
566
-
567
- ## Authentication
151
+ // Point domain to deployment
152
+ ship.domains.set('staging', { deployment: 'abc123' });
568
153
 
569
- The Ship SDK supports two authentication methods:
154
+ // Point domain to deployment with tags
155
+ ship.domains.set('staging', { deployment: 'abc123', tags: ['prod'] });
570
156
 
571
- ### API Keys (Authenticated Deployments)
572
- For persistent authentication with full account access:
157
+ // Update tags only (domain must exist)
158
+ ship.domains.set('staging', { tags: ['prod', 'v2'] });
573
159
 
574
- ```typescript
575
- const ship = new Ship({
576
- apiKey: 'ship-1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef'
577
- });
578
- ```
579
-
580
- ### Deploy Tokens (Single-Use Deployments)
581
- For temporary, single-use deployments:
582
-
583
- ```typescript
584
- const ship = new Ship({
585
- deployToken: 'token-1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef'
586
- });
160
+ // Error: must provide deployment or tags
161
+ ship.domains.set('staging', {}); // throws validation error
587
162
  ```
588
163
 
589
- ### API Requests
164
+ ### Events
590
165
 
591
- The SDK automatically sends credentials using standard Bearer token format:
592
-
593
- ```
594
- Authorization: Bearer ship-your-64-char-hex-string // API key (69 chars total)
595
- Authorization: Bearer token-your-64-char-hex-string // Deploy token (70 chars total)
166
+ ```javascript
167
+ ship.on('request', (url, init) => console.log(`→ ${url}`));
168
+ ship.on('response', (response, url) => console.log(`← ${response.status}`));
169
+ ship.on('error', (error, url) => console.error(error));
596
170
  ```
597
171
 
598
- ## Configuration
599
-
600
- Configuration is loaded hierarchically (highest precedence first):
601
-
602
- 1. **Constructor options** - Direct parameters to `new Ship()`
603
- 2. **Environment variables** - `SHIP_API_URL`, `SHIP_API_KEY` (Node.js only)
604
- 3. **Config files** - `.shiprc` or `package.json` (ship key) in project directory (Node.js only)
172
+ ### Error Handling
605
173
 
606
- ### Config File Format
607
-
608
- **.shiprc:**
609
- ```json
610
- {
611
- "apiUrl": "https://api.shipstatic.com",
612
- "apiKey": "ship-your-api-key"
613
- }
614
- ```
174
+ ```javascript
175
+ import { ShipError } from '@shipstatic/ship';
615
176
 
616
- **package.json:**
617
- ```json
618
- {
619
- "ship": {
620
- "apiUrl": "https://api.shipstatic.com",
621
- "apiKey": "ship-your-api-key"
177
+ try {
178
+ await ship.deployments.create('./dist');
179
+ } catch (error) {
180
+ if (error instanceof ShipError) {
181
+ if (error.isAuthError()) { /* ... */ }
182
+ if (error.isValidationError()) { /* ... */ }
183
+ if (error.isNetworkError()) { /* ... */ }
622
184
  }
623
185
  }
624
186
  ```
625
187
 
626
- ### Environment Variables
627
-
628
- ```bash
629
- export SHIP_API_URL="https://api.shipstatic.com"
630
- export SHIP_API_KEY="ship-your-api-key"
631
- export SHIP_DEPLOY_TOKEN="token-your-deploy-token"
632
- ```
633
-
634
- ## CLI Commands
635
-
636
- ### Deployment Commands
637
-
638
- ```bash
639
- ship # List deployments (no args)
640
- ship ./dist # Deploy specific directory
641
- ship deploy ./build # Explicit deploy command
642
- ship list # List deployments
643
- ship get abc123 # Get deployment details
644
- ship remove abc123 # Remove deployment
645
- ```
646
-
647
- ### Domain Commands
648
-
649
- ```bash
650
- ship domains # List domains
651
- ship domains set staging abc123 # Set domain to deployment
652
- ```
653
-
654
- ### Account Commands
655
-
656
- ```bash
657
- ship account # Get account details
658
- ```
659
-
660
- ### Global Options
661
-
662
- ```bash
663
- --api-url <URL> # API endpoint
664
- --api-key <KEY> # API key for authenticated deployments
665
- --deploy-token <TOKEN> # Deploy token for single-use deployments
666
- --json # JSON output
667
- ```
668
-
669
188
  ## Bundle Sizes
670
189
 
671
- **Optimized for production:**
672
- - **Node.js**: 21KB (ESM), 21KB (CJS)
673
- - **Browser**: 185KB (ESM with dependencies)
674
- - **CLI**: 38KB (CJS)
675
-
676
- **Key Optimizations:**
677
- - ✅ **Unified error system** - Single `ShipError` class for all components
678
- - ✅ **Dynamic platform configuration** - Fetches limits from API
679
- - ✅ **Replaced axios with native fetch** - Bundle size reduction
680
- - ✅ **Simplified configuration loading** - Removed async complexity
681
- - ✅ **Streamlined multipart uploads** - `files[]` + JSON checksums format
682
- - ✅ **Direct validation throwing** - Eliminated verbose ValidationResult pattern
190
+ - **Node.js**: 21KB
191
+ - **Browser**: 185KB
192
+ - **CLI**: 38KB
683
193
 
684
- ## TypeScript Support
194
+ ## TypeScript
685
195
 
686
- Full TypeScript support with exported types from shared `@shipstatic/types`:
196
+ Full TypeScript support with exported types:
687
197
 
688
198
  ```typescript
689
- // TypeScript - works with both import styles
690
- import type {
199
+ import type {
691
200
  ShipOptions,
692
- ShipEvents,
693
- NodeDeployInput,
694
- BrowserDeployInput,
695
201
  DeployOptions,
696
202
  DeploySuccessResponse,
697
- ProgressInfo,
698
- StaticFile,
699
- ShipError,
700
- ErrorType
203
+ ProgressInfo
701
204
  } from '@shipstatic/ship';
702
205
  ```
703
206
 
704
- ## Architecture
705
-
706
- ### Modern SDK Design
707
- - **Class-based API**: `new Ship()` with resource properties
708
- - **Environment detection**: Automatic Node.js/Browser optimizations
709
- - **Native dependencies**: Uses built-in `fetch`, `crypto`, and `fs` APIs
710
- - **Event system**: Comprehensive observability with lightweight, reliable events
711
- - **Type safety**: Strict TypeScript with comprehensive error types
712
- - **Dynamic configuration**: Platform limits fetched from API
713
- - **Unified DTOs**: Shared type definitions from `@shipstatic/types`
714
-
715
- ### Codebase Organization
716
- ```
717
- src/
718
- ├── browser/ # Browser-specific implementations
719
- │ ├── core/ # Browser configuration and setup
720
- │ ├── index.ts # Browser SDK exports
721
- │ └── lib/ # Browser file handling
722
- ├── node/ # Node.js-specific implementations
723
- │ ├── cli/ # CLI command implementations
724
- │ ├── completions/ # Shell completion scripts
725
- │ ├── core/ # Node.js configuration and file handling
726
- │ └── index.ts # Node.js SDK exports
727
- ├── shared/ # Cross-platform shared code
728
- │ ├── api/ # HTTP client and API communication
729
- │ ├── base-ship.ts # Base Ship class implementation
730
- │ ├── core/ # Configuration and constants
731
- │ ├── events.ts # Event system implementation
732
- │ ├── lib/ # Utility libraries
733
- │ ├── resources.ts # Resource implementations
734
- │ └── types.ts # Shared type definitions
735
- └── index.ts # Main SDK exports with environment detection
736
-
737
- ### File Processing Pipeline
738
- **Node.js:**
739
- ```
740
- File Paths → Discovery → Junk Filtering → Base Directory → Content Processing → StaticFile[]
741
- ```
742
-
743
- **Browser:**
744
- ```
745
- File Objects → Path Extraction → Junk Filtering → Content Processing → StaticFile[]
746
- ```
747
-
748
- ### Configuration System
749
- - **Synchronous loading**: No async complexity for file config
750
- - **Dynamic platform config**: Fetched from API on first use
751
- - **Minimal search**: Only `.shiprc` and `package.json`
752
- - **Simple validation**: Native type checking
753
- - **Environment variables**: `SHIP_*` prefix for clarity
754
-
755
- ### Error System Architecture
756
- - **Single source of truth**: All errors use `ShipError` from `@shipstatic/types`
757
- - **Type-safe factories**: Specific factory methods for each error type
758
- - **Wire format support**: Automatic serialization/deserialization
759
- - **Helper methods**: Easy type checking with `is*Error()` methods
760
-
761
- ## Features & Capabilities
762
-
763
- Ship SDK provides comprehensive deployment functionality:
764
-
765
- - **Deployment Resource**: Complete operations (create, list, get, remove)
766
- - **Domain Resource**: Complete operations (set, get, list, remove)
767
- - **Account Resource**: Account information retrieval
768
- - **Event System**: Comprehensive observability with request, response, error events
769
- - **Unified Error System**: Single `ShipError` class with factory methods
770
- - **Dynamic Platform Config**: Automatic limit fetching from API
771
- - **Simple CLI**: Deploy shortcut + explicit commands
772
- - **Streamlined Multipart**: `files[]` array + JSON checksums format
773
- - **Direct Validation**: Functions throw errors for immediate feedback
774
- - **Shared DTOs**: All types from `@shipstatic/types` package
775
- - **Tree-shakeable**: `"sideEffects": false` for optimal bundling
776
- - **Production Ready**: Clean, reliable implementation with comprehensive test coverage
777
- - **Native APIs**: Built on `fetch`, `crypto`, and `fs` for optimal performance
778
- - **Modern TypeScript**: Full type safety with ESM modules
779
-
780
- ## Testing
781
-
782
- Comprehensive test coverage with modern tooling:
783
-
784
- ```bash
785
- # Run all tests
786
- pnpm test --run
787
-
788
- # Run specific test suites
789
- pnpm test tests/utils/node-files.test.ts --run
790
- pnpm test tests/api/http.test.ts --run
791
-
792
- # Build and test
793
- pnpm build && pnpm test --run
794
- ```
795
-
796
- **Test Organization:**
797
- - **Unit tests**: Pure function testing
798
- - **Integration tests**: Component interaction testing
799
- - **Edge case tests**: Boundary condition testing
800
- - **Browser tests**: FileList and File object handling
801
- - **Node.js tests**: Filesystem and path manipulation
802
- - **Error tests**: Unified error handling patterns
803
-
804
- **Current Status:** 1006 tests passing (1006 total) ✅
805
-
806
- ## Contributing
807
-
808
- The codebase prioritizes simplicity and maintainability:
809
-
810
- - **"Do More with Less"** - Built-in over dependencies
811
- - **No backward compatibility** constraints
812
- - **Modern ES modules** and TypeScript
813
- - **Comprehensive test coverage**
814
- - **Clean resource-based** architecture
815
- - **Unified error handling** across all components
816
- - **Shared type system** via `@shipstatic/types`
817
- - **Declarative code patterns** over imperative complexity
818
-
819
207
  ---
820
208
 
821
- **Ship** - Deploy static files with modern tooling ⚡
209
+ Part of the [Shipstatic](https://shipstatic.com) platform.