@shipstatic/types 0.9.1 → 0.9.3
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 +15 -1
- package/dist/index.d.ts +17 -4
- package/dist/index.js +57 -9
- package/package.json +1 -1
- package/src/index.ts +62 -11
package/README.md
CHANGED
|
@@ -46,6 +46,20 @@ if (error.isClientError()) { /* Business | Config | File | Validation */ }
|
|
|
46
46
|
if (error.isAuthError()) { /* handle auth */ }
|
|
47
47
|
```
|
|
48
48
|
|
|
49
|
+
**HTTP client integration.** Both producer and consumer sides of the wire have first-class helpers, so every HTTP client across the platform reconstructs the same `ShipError` shape:
|
|
50
|
+
|
|
51
|
+
```typescript
|
|
52
|
+
// Producer side (API workers): serialize a ShipError to JSON
|
|
53
|
+
return c.json(error.toResponse(), error.status ?? 500);
|
|
54
|
+
|
|
55
|
+
// Consumer side (SDK, web app): rehydrate from any error Response
|
|
56
|
+
if (!response.ok) {
|
|
57
|
+
throw await ShipError.fromHttpResponse(response, 'Get account failed');
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
`fromHttpResponse` trusts the body's `error` field when it's a known `ErrorType` — so a server's `ShipError.validation(...)` round-trips back to `ErrorType.Validation` on the client. For non-API responses (CDN errors, intermediaries) or malformed bodies it falls back to status-derived (401 → `Authentication`, 429 → `RateLimit`, else → `Api`). Body's `message` and `details` are preserved best-effort. The optional second arg is a fallback message used when the body has nothing usable.
|
|
62
|
+
|
|
49
63
|
### Status Constants
|
|
50
64
|
|
|
51
65
|
```typescript
|
|
@@ -62,7 +76,7 @@ import {
|
|
|
62
76
|
|
|
63
77
|
```typescript
|
|
64
78
|
import type {
|
|
65
|
-
PlatformLimits, // plan-based caps from /
|
|
79
|
+
PlatformLimits, // plan-based caps from /limits (file size, file count, total size)
|
|
66
80
|
BillingStatus,
|
|
67
81
|
CheckoutSession,
|
|
68
82
|
ActivityListResponse,
|
package/dist/index.d.ts
CHANGED
|
@@ -350,8 +350,23 @@ export declare class ShipError extends Error {
|
|
|
350
350
|
constructor(type: ErrorType, message: string, status?: number | undefined, details?: any | undefined);
|
|
351
351
|
/** Convert to wire format */
|
|
352
352
|
toResponse(): ErrorResponse;
|
|
353
|
-
/**
|
|
354
|
-
|
|
353
|
+
/**
|
|
354
|
+
* Construct a `ShipError` from an HTTP error response.
|
|
355
|
+
*
|
|
356
|
+
* Best-effort body parse for `{ message, error?, details? }`. Message
|
|
357
|
+
* resolution: `body.message` → `body.error` → `fallbackMessage` →
|
|
358
|
+
* `Request failed with status N`.
|
|
359
|
+
*
|
|
360
|
+
* Type resolution: trusts `body.error` when it's a known `ErrorType`
|
|
361
|
+
* (preserves the wire's intent — server's `ShipError.validation(...)`
|
|
362
|
+
* round-trips back to `ErrorType.Validation` on the client). Falls back to
|
|
363
|
+
* status-derived (401 → Authentication, 429 → RateLimit, else → Api) for
|
|
364
|
+
* non-API responses (CDN errors, intermediaries) or malformed bodies.
|
|
365
|
+
*
|
|
366
|
+
* Async because it reads the response body. Returns rather than throws so
|
|
367
|
+
* callers can compose; most will `throw await ShipError.fromHttpResponse(...)`.
|
|
368
|
+
*/
|
|
369
|
+
static fromHttpResponse(response: Response, fallbackMessage?: string): Promise<ShipError>;
|
|
355
370
|
static validation(message: string, details?: any): ShipError;
|
|
356
371
|
static notFound(resource: string, id?: string): ShipError;
|
|
357
372
|
static rateLimit(message?: string): ShipError;
|
|
@@ -362,8 +377,6 @@ export declare class ShipError extends Error {
|
|
|
362
377
|
static file(message: string, filePath?: string): ShipError;
|
|
363
378
|
static config(message: string, details?: any): ShipError;
|
|
364
379
|
static api(message: string, status?: number): ShipError;
|
|
365
|
-
static database(message: string, status?: number): ShipError;
|
|
366
|
-
static storage(message: string, status?: number): ShipError;
|
|
367
380
|
get filePath(): string | undefined;
|
|
368
381
|
isClientError(): boolean;
|
|
369
382
|
isNetworkError(): boolean;
|
package/dist/index.js
CHANGED
|
@@ -90,6 +90,13 @@ const ERROR_CATEGORIES = {
|
|
|
90
90
|
network: new Set([ErrorType.Network]),
|
|
91
91
|
auth: new Set([ErrorType.Authentication]),
|
|
92
92
|
};
|
|
93
|
+
/**
|
|
94
|
+
* Lookup set of known wire-format error type strings. Used by
|
|
95
|
+
* `ShipError.fromHttpResponse` to validate the body's `error` field before
|
|
96
|
+
* trusting it as an `ErrorType`. Defensive against malformed/unknown values
|
|
97
|
+
* that could otherwise leak into the typed `ShipError.type` field.
|
|
98
|
+
*/
|
|
99
|
+
const KNOWN_ERROR_TYPES = new Set(Object.values(ErrorType));
|
|
93
100
|
/**
|
|
94
101
|
* Simple unified error class for both API and SDK
|
|
95
102
|
*/
|
|
@@ -117,9 +124,56 @@ export class ShipError extends Error {
|
|
|
117
124
|
details
|
|
118
125
|
};
|
|
119
126
|
}
|
|
120
|
-
/**
|
|
121
|
-
|
|
122
|
-
|
|
127
|
+
/**
|
|
128
|
+
* Construct a `ShipError` from an HTTP error response.
|
|
129
|
+
*
|
|
130
|
+
* Best-effort body parse for `{ message, error?, details? }`. Message
|
|
131
|
+
* resolution: `body.message` → `body.error` → `fallbackMessage` →
|
|
132
|
+
* `Request failed with status N`.
|
|
133
|
+
*
|
|
134
|
+
* Type resolution: trusts `body.error` when it's a known `ErrorType`
|
|
135
|
+
* (preserves the wire's intent — server's `ShipError.validation(...)`
|
|
136
|
+
* round-trips back to `ErrorType.Validation` on the client). Falls back to
|
|
137
|
+
* status-derived (401 → Authentication, 429 → RateLimit, else → Api) for
|
|
138
|
+
* non-API responses (CDN errors, intermediaries) or malformed bodies.
|
|
139
|
+
*
|
|
140
|
+
* Async because it reads the response body. Returns rather than throws so
|
|
141
|
+
* callers can compose; most will `throw await ShipError.fromHttpResponse(...)`.
|
|
142
|
+
*/
|
|
143
|
+
static async fromHttpResponse(response, fallbackMessage) {
|
|
144
|
+
let message;
|
|
145
|
+
let details;
|
|
146
|
+
let bodyType;
|
|
147
|
+
try {
|
|
148
|
+
const contentType = response.headers.get('content-type');
|
|
149
|
+
if (contentType?.includes('application/json')) {
|
|
150
|
+
const json = await response.json();
|
|
151
|
+
if (json && typeof json === 'object') {
|
|
152
|
+
const obj = json;
|
|
153
|
+
if (typeof obj.message === 'string')
|
|
154
|
+
message = obj.message;
|
|
155
|
+
else if (typeof obj.error === 'string')
|
|
156
|
+
message = obj.error;
|
|
157
|
+
details = obj.details;
|
|
158
|
+
if (typeof obj.error === 'string' && KNOWN_ERROR_TYPES.has(obj.error)) {
|
|
159
|
+
bodyType = obj.error;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
const text = await response.text();
|
|
165
|
+
if (text)
|
|
166
|
+
message = text;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
catch {
|
|
170
|
+
// Body unreadable; fall through to fallback.
|
|
171
|
+
}
|
|
172
|
+
message = message || fallbackMessage || `Request failed with status ${response.status}`;
|
|
173
|
+
const type = bodyType ?? (response.status === 401 ? ErrorType.Authentication :
|
|
174
|
+
response.status === 429 ? ErrorType.RateLimit :
|
|
175
|
+
ErrorType.Api);
|
|
176
|
+
return new ShipError(type, message, response.status, details);
|
|
123
177
|
}
|
|
124
178
|
// Factory methods for common errors
|
|
125
179
|
static validation(message, details) {
|
|
@@ -153,12 +207,6 @@ export class ShipError extends Error {
|
|
|
153
207
|
static api(message, status = 500) {
|
|
154
208
|
return new ShipError(ErrorType.Api, message, status);
|
|
155
209
|
}
|
|
156
|
-
static database(message, status = 500) {
|
|
157
|
-
return new ShipError(ErrorType.Api, message, status);
|
|
158
|
-
}
|
|
159
|
-
static storage(message, status = 500) {
|
|
160
|
-
return new ShipError(ErrorType.Api, message, status);
|
|
161
|
-
}
|
|
162
210
|
// Helper getter for accessing file path from details
|
|
163
211
|
get filePath() {
|
|
164
212
|
return this.details?.filePath;
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -385,6 +385,14 @@ const ERROR_CATEGORIES = {
|
|
|
385
385
|
auth: new Set<ErrorType>([ErrorType.Authentication]),
|
|
386
386
|
} as const;
|
|
387
387
|
|
|
388
|
+
/**
|
|
389
|
+
* Lookup set of known wire-format error type strings. Used by
|
|
390
|
+
* `ShipError.fromHttpResponse` to validate the body's `error` field before
|
|
391
|
+
* trusting it as an `ErrorType`. Defensive against malformed/unknown values
|
|
392
|
+
* that could otherwise leak into the typed `ShipError.type` field.
|
|
393
|
+
*/
|
|
394
|
+
const KNOWN_ERROR_TYPES = new Set<string>(Object.values(ErrorType));
|
|
395
|
+
|
|
388
396
|
/**
|
|
389
397
|
* Standard error response format used everywhere
|
|
390
398
|
*/
|
|
@@ -428,9 +436,60 @@ export class ShipError extends Error {
|
|
|
428
436
|
};
|
|
429
437
|
}
|
|
430
438
|
|
|
431
|
-
/**
|
|
432
|
-
|
|
433
|
-
|
|
439
|
+
/**
|
|
440
|
+
* Construct a `ShipError` from an HTTP error response.
|
|
441
|
+
*
|
|
442
|
+
* Best-effort body parse for `{ message, error?, details? }`. Message
|
|
443
|
+
* resolution: `body.message` → `body.error` → `fallbackMessage` →
|
|
444
|
+
* `Request failed with status N`.
|
|
445
|
+
*
|
|
446
|
+
* Type resolution: trusts `body.error` when it's a known `ErrorType`
|
|
447
|
+
* (preserves the wire's intent — server's `ShipError.validation(...)`
|
|
448
|
+
* round-trips back to `ErrorType.Validation` on the client). Falls back to
|
|
449
|
+
* status-derived (401 → Authentication, 429 → RateLimit, else → Api) for
|
|
450
|
+
* non-API responses (CDN errors, intermediaries) or malformed bodies.
|
|
451
|
+
*
|
|
452
|
+
* Async because it reads the response body. Returns rather than throws so
|
|
453
|
+
* callers can compose; most will `throw await ShipError.fromHttpResponse(...)`.
|
|
454
|
+
*/
|
|
455
|
+
static async fromHttpResponse(
|
|
456
|
+
response: Response,
|
|
457
|
+
fallbackMessage?: string,
|
|
458
|
+
): Promise<ShipError> {
|
|
459
|
+
let message: string | undefined;
|
|
460
|
+
let details: unknown;
|
|
461
|
+
let bodyType: ErrorType | undefined;
|
|
462
|
+
|
|
463
|
+
try {
|
|
464
|
+
const contentType = response.headers.get('content-type');
|
|
465
|
+
if (contentType?.includes('application/json')) {
|
|
466
|
+
const json: unknown = await response.json();
|
|
467
|
+
if (json && typeof json === 'object') {
|
|
468
|
+
const obj = json as Record<string, unknown>;
|
|
469
|
+
if (typeof obj.message === 'string') message = obj.message;
|
|
470
|
+
else if (typeof obj.error === 'string') message = obj.error;
|
|
471
|
+
details = obj.details;
|
|
472
|
+
if (typeof obj.error === 'string' && KNOWN_ERROR_TYPES.has(obj.error)) {
|
|
473
|
+
bodyType = obj.error as ErrorType;
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
} else {
|
|
477
|
+
const text = await response.text();
|
|
478
|
+
if (text) message = text;
|
|
479
|
+
}
|
|
480
|
+
} catch {
|
|
481
|
+
// Body unreadable; fall through to fallback.
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
message = message || fallbackMessage || `Request failed with status ${response.status}`;
|
|
485
|
+
|
|
486
|
+
const type = bodyType ?? (
|
|
487
|
+
response.status === 401 ? ErrorType.Authentication :
|
|
488
|
+
response.status === 429 ? ErrorType.RateLimit :
|
|
489
|
+
ErrorType.Api
|
|
490
|
+
);
|
|
491
|
+
|
|
492
|
+
return new ShipError(type, message, response.status, details);
|
|
434
493
|
}
|
|
435
494
|
|
|
436
495
|
// Factory methods for common errors
|
|
@@ -475,14 +534,6 @@ export class ShipError extends Error {
|
|
|
475
534
|
return new ShipError(ErrorType.Api, message, status);
|
|
476
535
|
}
|
|
477
536
|
|
|
478
|
-
static database(message: string, status: number = 500): ShipError {
|
|
479
|
-
return new ShipError(ErrorType.Api, message, status);
|
|
480
|
-
}
|
|
481
|
-
|
|
482
|
-
static storage(message: string, status: number = 500): ShipError {
|
|
483
|
-
return new ShipError(ErrorType.Api, message, status);
|
|
484
|
-
}
|
|
485
|
-
|
|
486
537
|
// Helper getter for accessing file path from details
|
|
487
538
|
get filePath(): string | undefined {
|
|
488
539
|
return this.details?.filePath;
|