@shipstatic/ship 0.3.16 → 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 +115 -727
- package/dist/browser.d.ts +15 -29
- package/dist/browser.js +5 -5
- package/dist/browser.js.map +1 -1
- package/dist/cli.cjs +25 -25
- package/dist/cli.cjs.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +15 -29
- package/dist/index.d.ts +15 -29
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -1,821 +1,209 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @shipstatic/ship
|
|
2
2
|
|
|
3
|
-
|
|
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
|
-
|
|
29
|
-
|
|
30
|
-
```bash
|
|
11
|
+
# SDK (project dependency)
|
|
31
12
|
npm install @shipstatic/ship
|
|
32
13
|
```
|
|
33
14
|
|
|
34
|
-
##
|
|
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
|
|
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
|
|
96
|
-
|
|
97
|
-
#
|
|
98
|
-
ship
|
|
99
|
-
ship
|
|
100
|
-
ship
|
|
101
|
-
ship remove
|
|
102
|
-
|
|
103
|
-
#
|
|
104
|
-
ship domains list
|
|
105
|
-
ship domains set staging
|
|
106
|
-
ship domains set
|
|
107
|
-
ship domains
|
|
108
|
-
ship domains verify www.example.com
|
|
109
|
-
ship domains remove staging
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
317
|
-
apiKey: process.env.SHIP_API_KEY // ship-abc123...
|
|
53
|
+
apiKey: 'ship-your-api-key'
|
|
318
54
|
});
|
|
319
55
|
|
|
320
|
-
// Deploy
|
|
321
|
-
const result = await ship.deployments.create(
|
|
322
|
-
|
|
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(
|
|
333
|
-
```
|
|
334
|
-
|
|
335
|
-
#### Browser File Upload
|
|
61
|
+
console.log(`Deployed: ${result.url}`);
|
|
336
62
|
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
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
|
-
//
|
|
349
|
-
|
|
350
|
-
|
|
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
|
-
##
|
|
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
|
-
//
|
|
378
|
-
|
|
379
|
-
|
|
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
|
-
|
|
84
|
+
## Authentication
|
|
397
85
|
|
|
398
|
-
#### Request/Response Logging
|
|
399
86
|
```javascript
|
|
400
|
-
//
|
|
401
|
-
ship
|
|
402
|
-
|
|
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
|
-
|
|
409
|
-
|
|
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
|
-
|
|
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
|
-
|
|
100
|
+
**Constructor options** (highest priority):
|
|
428
101
|
```javascript
|
|
429
|
-
|
|
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
|
-
|
|
446
|
-
```
|
|
447
|
-
|
|
448
|
-
ship
|
|
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
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
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
|
-
|
|
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
|
-
###
|
|
119
|
+
### Resources
|
|
485
120
|
|
|
486
121
|
```typescript
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
//
|
|
492
|
-
ship.
|
|
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
|
-
|
|
497
|
-
|
|
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
|
-
|
|
501
|
-
|
|
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
|
-
//
|
|
522
|
-
|
|
141
|
+
// Account
|
|
142
|
+
ship.whoami() // Get current account
|
|
523
143
|
|
|
524
|
-
|
|
525
|
-
|
|
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
|
-
###
|
|
148
|
+
### domains.set() Behavior
|
|
545
149
|
|
|
546
150
|
```typescript
|
|
547
|
-
//
|
|
548
|
-
|
|
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
|
-
|
|
154
|
+
// Point domain to deployment with tags
|
|
155
|
+
ship.domains.set('staging', { deployment: 'abc123', tags: ['prod'] });
|
|
570
156
|
|
|
571
|
-
|
|
572
|
-
|
|
157
|
+
// Update tags only (domain must exist)
|
|
158
|
+
ship.domains.set('staging', { tags: ['prod', 'v2'] });
|
|
573
159
|
|
|
574
|
-
|
|
575
|
-
|
|
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
|
-
###
|
|
164
|
+
### Events
|
|
590
165
|
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
617
|
-
|
|
618
|
-
{
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
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
|
-
**
|
|
672
|
-
- **
|
|
673
|
-
- **
|
|
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
|
|
194
|
+
## TypeScript
|
|
685
195
|
|
|
686
|
-
Full TypeScript support with exported types
|
|
196
|
+
Full TypeScript support with exported types:
|
|
687
197
|
|
|
688
198
|
```typescript
|
|
689
|
-
|
|
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
|
-
|
|
209
|
+
Part of the [Shipstatic](https://shipstatic.com) platform.
|