@shipstatic/types 0.9.1 → 0.9.2
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 +14 -2
- package/dist/index.js +43 -3
- package/package.json +1 -1
- package/src/index.ts +46 -3
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` derives the error type from HTTP status (401 → `Authentication`, 429 → `RateLimit`, else → `Api`), preserving the body's `message`, `error`, and `details` 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,20 @@ 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`. Status drives the error type — same
|
|
359
|
+
* convention used by the SDK and web console — so `error.status === 429`
|
|
360
|
+
* always lines up with `ErrorType.RateLimit`, etc., regardless of what the
|
|
361
|
+
* body's `error` field claims.
|
|
362
|
+
*
|
|
363
|
+
* Async because it reads the response body. Returns rather than throws so
|
|
364
|
+
* callers can compose; most will `throw await ShipError.fromHttpResponse(...)`.
|
|
365
|
+
*/
|
|
366
|
+
static fromHttpResponse(response: Response, fallbackMessage?: string): Promise<ShipError>;
|
|
355
367
|
static validation(message: string, details?: any): ShipError;
|
|
356
368
|
static notFound(resource: string, id?: string): ShipError;
|
|
357
369
|
static rateLimit(message?: string): ShipError;
|
package/dist/index.js
CHANGED
|
@@ -117,9 +117,49 @@ export class ShipError extends Error {
|
|
|
117
117
|
details
|
|
118
118
|
};
|
|
119
119
|
}
|
|
120
|
-
/**
|
|
121
|
-
|
|
122
|
-
|
|
120
|
+
/**
|
|
121
|
+
* Construct a `ShipError` from an HTTP error response.
|
|
122
|
+
*
|
|
123
|
+
* Best-effort body parse for `{ message, error?, details? }`. Message
|
|
124
|
+
* resolution: `body.message` → `body.error` → `fallbackMessage` →
|
|
125
|
+
* `Request failed with status N`. Status drives the error type — same
|
|
126
|
+
* convention used by the SDK and web console — so `error.status === 429`
|
|
127
|
+
* always lines up with `ErrorType.RateLimit`, etc., regardless of what the
|
|
128
|
+
* body's `error` field claims.
|
|
129
|
+
*
|
|
130
|
+
* Async because it reads the response body. Returns rather than throws so
|
|
131
|
+
* callers can compose; most will `throw await ShipError.fromHttpResponse(...)`.
|
|
132
|
+
*/
|
|
133
|
+
static async fromHttpResponse(response, fallbackMessage) {
|
|
134
|
+
let message;
|
|
135
|
+
let details;
|
|
136
|
+
try {
|
|
137
|
+
const contentType = response.headers.get('content-type');
|
|
138
|
+
if (contentType?.includes('application/json')) {
|
|
139
|
+
const json = await response.json();
|
|
140
|
+
if (json && typeof json === 'object') {
|
|
141
|
+
const obj = json;
|
|
142
|
+
if (typeof obj.message === 'string')
|
|
143
|
+
message = obj.message;
|
|
144
|
+
else if (typeof obj.error === 'string')
|
|
145
|
+
message = obj.error;
|
|
146
|
+
details = obj.details;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
const text = await response.text();
|
|
151
|
+
if (text)
|
|
152
|
+
message = text;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
catch {
|
|
156
|
+
// Body unreadable; fall through to fallback.
|
|
157
|
+
}
|
|
158
|
+
message = message || fallbackMessage || `Request failed with status ${response.status}`;
|
|
159
|
+
const type = response.status === 401 ? ErrorType.Authentication :
|
|
160
|
+
response.status === 429 ? ErrorType.RateLimit :
|
|
161
|
+
ErrorType.Api;
|
|
162
|
+
return new ShipError(type, message, response.status, details);
|
|
123
163
|
}
|
|
124
164
|
// Factory methods for common errors
|
|
125
165
|
static validation(message, details) {
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -428,9 +428,52 @@ export class ShipError extends Error {
|
|
|
428
428
|
};
|
|
429
429
|
}
|
|
430
430
|
|
|
431
|
-
/**
|
|
432
|
-
|
|
433
|
-
|
|
431
|
+
/**
|
|
432
|
+
* Construct a `ShipError` from an HTTP error response.
|
|
433
|
+
*
|
|
434
|
+
* Best-effort body parse for `{ message, error?, details? }`. Message
|
|
435
|
+
* resolution: `body.message` → `body.error` → `fallbackMessage` →
|
|
436
|
+
* `Request failed with status N`. Status drives the error type — same
|
|
437
|
+
* convention used by the SDK and web console — so `error.status === 429`
|
|
438
|
+
* always lines up with `ErrorType.RateLimit`, etc., regardless of what the
|
|
439
|
+
* body's `error` field claims.
|
|
440
|
+
*
|
|
441
|
+
* Async because it reads the response body. Returns rather than throws so
|
|
442
|
+
* callers can compose; most will `throw await ShipError.fromHttpResponse(...)`.
|
|
443
|
+
*/
|
|
444
|
+
static async fromHttpResponse(
|
|
445
|
+
response: Response,
|
|
446
|
+
fallbackMessage?: string,
|
|
447
|
+
): Promise<ShipError> {
|
|
448
|
+
let message: string | undefined;
|
|
449
|
+
let details: unknown;
|
|
450
|
+
|
|
451
|
+
try {
|
|
452
|
+
const contentType = response.headers.get('content-type');
|
|
453
|
+
if (contentType?.includes('application/json')) {
|
|
454
|
+
const json: unknown = await response.json();
|
|
455
|
+
if (json && typeof json === 'object') {
|
|
456
|
+
const obj = json as Record<string, unknown>;
|
|
457
|
+
if (typeof obj.message === 'string') message = obj.message;
|
|
458
|
+
else if (typeof obj.error === 'string') message = obj.error;
|
|
459
|
+
details = obj.details;
|
|
460
|
+
}
|
|
461
|
+
} else {
|
|
462
|
+
const text = await response.text();
|
|
463
|
+
if (text) message = text;
|
|
464
|
+
}
|
|
465
|
+
} catch {
|
|
466
|
+
// Body unreadable; fall through to fallback.
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
message = message || fallbackMessage || `Request failed with status ${response.status}`;
|
|
470
|
+
|
|
471
|
+
const type =
|
|
472
|
+
response.status === 401 ? ErrorType.Authentication :
|
|
473
|
+
response.status === 429 ? ErrorType.RateLimit :
|
|
474
|
+
ErrorType.Api;
|
|
475
|
+
|
|
476
|
+
return new ShipError(type, message, response.status, details);
|
|
434
477
|
}
|
|
435
478
|
|
|
436
479
|
// Factory methods for common errors
|