@giveitsmaller/sdk 0.2.3 → 0.6.0
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 +58 -0
- package/dist/_audit.d.ts +1 -0
- package/dist/_audit.js +64 -0
- package/dist/client.d.ts +255 -5
- package/dist/client.js +1681 -66
- package/dist/errors.d.ts +168 -9
- package/dist/errors.js +168 -3
- package/dist/index.d.ts +13 -6
- package/dist/index.js +29 -3
- package/dist/sse.d.ts +20 -1
- package/dist/sse.js +62 -3
- package/dist/types.d.ts +350 -37
- package/dist/types.js +28 -7
- package/package.json +5 -3
package/dist/errors.d.ts
CHANGED
|
@@ -1,23 +1,182 @@
|
|
|
1
|
+
import type { AuthErrorResponse, BalanceExhaustedResponse, FeatureNotAvailableResponse, FeatureTierRestrictedResponse, TierRestrictionResponse, UploadDurationExceedsTierResponse, UploadSizeExceedsTierResponse, WorkflowExpiredResponse } from '@giveitsmaller/contracts/openapi';
|
|
1
2
|
export declare class GislError extends Error {
|
|
2
3
|
constructor(message: string);
|
|
3
4
|
}
|
|
5
|
+
/**
|
|
6
|
+
* Optional structured fields carried alongside a typed API error. The
|
|
7
|
+
* localisation triple (`messageKey`, `locale`, `messageParams`) mirrors the
|
|
8
|
+
* `ErrorEnvelope` localisation contract from `compression_contracts`
|
|
9
|
+
* (ticket I26). `payload` carries the full typed response envelope for the
|
|
10
|
+
* structured error subclasses that have one.
|
|
11
|
+
*/
|
|
12
|
+
export interface GislApiErrorOptions {
|
|
13
|
+
readonly messageKey?: string;
|
|
14
|
+
readonly locale?: string;
|
|
15
|
+
readonly messageParams?: Record<string, unknown>;
|
|
16
|
+
readonly payload?: unknown;
|
|
17
|
+
}
|
|
4
18
|
export declare class GislApiError extends GislError {
|
|
5
19
|
readonly statusCode: number;
|
|
6
20
|
readonly errorMessage: string;
|
|
7
21
|
readonly path?: string;
|
|
8
22
|
readonly details?: unknown;
|
|
9
|
-
|
|
23
|
+
readonly messageKey?: string;
|
|
24
|
+
readonly locale?: string;
|
|
25
|
+
readonly messageParams?: Record<string, unknown>;
|
|
26
|
+
readonly payload?: unknown;
|
|
27
|
+
constructor(statusCode: number, errorMessage: string, path?: string, details?: unknown, options?: GislApiErrorOptions);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Shape of a single validation detail entry. Mirrors the v2
|
|
31
|
+
* `ValidationErrorEnvelopeDetailsInner` contract: only `message` is required;
|
|
32
|
+
* `field` / `operation` / `option` are mutually-permissive identifiers (a
|
|
33
|
+
* given detail may carry one, two, or all three depending on whether the
|
|
34
|
+
* violation is single-field, per-option, or cross-field).
|
|
35
|
+
*/
|
|
36
|
+
export interface GislValidationDetail {
|
|
37
|
+
readonly message: string;
|
|
38
|
+
readonly field?: string;
|
|
39
|
+
readonly operation?: string;
|
|
40
|
+
readonly option?: string;
|
|
41
|
+
readonly messageKey?: string;
|
|
42
|
+
readonly locale?: string;
|
|
43
|
+
readonly messageParams?: Record<string, unknown>;
|
|
10
44
|
}
|
|
11
45
|
export declare class GislValidationError extends GislApiError {
|
|
12
|
-
readonly details:
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
46
|
+
readonly details: GislValidationDetail[];
|
|
47
|
+
constructor(statusCode: number, errorMessage: string, details: GislValidationDetail[], path?: string, options?: GislApiErrorOptions);
|
|
48
|
+
}
|
|
49
|
+
export declare class GislBalanceExhaustedError extends GislApiError {
|
|
50
|
+
readonly payload: BalanceExhaustedResponse;
|
|
51
|
+
constructor(statusCode: number, errorMessage: string, payload: BalanceExhaustedResponse, path?: string, extra?: Omit<GislApiErrorOptions, 'payload'>);
|
|
52
|
+
}
|
|
53
|
+
export declare class GislTierRestrictedError extends GislApiError {
|
|
54
|
+
readonly payload: TierRestrictionResponse;
|
|
55
|
+
constructor(statusCode: number, errorMessage: string, payload: TierRestrictionResponse, path?: string, extra?: Omit<GislApiErrorOptions, 'payload'>);
|
|
56
|
+
}
|
|
57
|
+
export declare class GislFeatureTierRestrictedError extends GislApiError {
|
|
58
|
+
readonly payload: FeatureTierRestrictedResponse;
|
|
59
|
+
constructor(statusCode: number, errorMessage: string, payload: FeatureTierRestrictedResponse, path?: string, extra?: Omit<GislApiErrorOptions, 'payload'>);
|
|
60
|
+
}
|
|
61
|
+
export declare class GislFeatureNotAvailableError extends GislApiError {
|
|
62
|
+
readonly payload: FeatureNotAvailableResponse;
|
|
63
|
+
constructor(statusCode: number, errorMessage: string, payload: FeatureNotAvailableResponse, path?: string, extra?: Omit<GislApiErrorOptions, 'payload'>);
|
|
64
|
+
}
|
|
65
|
+
export declare class GislWorkflowExpiredError extends GislApiError {
|
|
66
|
+
readonly payload: WorkflowExpiredResponse;
|
|
67
|
+
constructor(statusCode: number, errorMessage: string, payload: WorkflowExpiredResponse, path?: string, extra?: Omit<GislApiErrorOptions, 'payload'>);
|
|
68
|
+
}
|
|
69
|
+
export declare class GislAuthError extends GislApiError {
|
|
70
|
+
readonly payload: AuthErrorResponse;
|
|
71
|
+
constructor(statusCode: number, errorMessage: string, payload: AuthErrorResponse, path?: string, extra?: Omit<GislApiErrorOptions, 'payload'>);
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Discriminates the four upload-too-big shapes the server can return:
|
|
75
|
+
* - `size_tier` — 422 `upload_size_exceeds_tier` (typed payload present)
|
|
76
|
+
* - `duration_tier` — 422 `upload_duration_exceeds_tier` (typed payload present)
|
|
77
|
+
* - `absolute_413` — 413, the absolute across-tier cap. The contract models
|
|
78
|
+
* 413 as a plain `ErrorEnvelope` with NO `error_type`
|
|
79
|
+
* discriminator, so there is NO typed payload for it.
|
|
80
|
+
* - `cap_v2_multipart` — 422 `FILE_TOO_LARGE_FOR_MULTIPART` (SDK-3 / Wb6ebOMM,
|
|
81
|
+
* pre-S3 capacity reject on the resume-support endpoints).
|
|
82
|
+
* The contract carries no structured payload for this
|
|
83
|
+
* code today — `payload` is undefined for this kind.
|
|
84
|
+
*
|
|
85
|
+
* **Caveat for exhaustive-narrowing consumers.** The `cap_v2_multipart` value
|
|
86
|
+
* was added in TS SDK 0.5.0 / PHP SDK 0.3.0. A consumer writing
|
|
87
|
+
* `switch (e.kind) { case 'size_tier': ... case 'duration_tier': ... default:
|
|
88
|
+
* absurd(e.kind); }` against the prior 3-value union now sees a non-exhaustive
|
|
89
|
+
* switch and must add the new arm. The bump is logged in CHANGELOG.md.
|
|
90
|
+
*/
|
|
91
|
+
export type GislUploadCapKind = 'size_tier' | 'duration_tier' | 'absolute_413' | 'cap_v2_multipart';
|
|
92
|
+
/**
|
|
93
|
+
* A single class covering all three "upload exceeds a size/duration cap"
|
|
94
|
+
* responses (422 size-tier, 422 duration-tier, 413 absolute).
|
|
95
|
+
*
|
|
96
|
+
* CONSCIOUS DEVIATION from the one-typed-payload-per-class invariant that the
|
|
97
|
+
* other structured subclasses follow (`GislBalanceExhaustedError`,
|
|
98
|
+
* `GislWorkflowExpiredError`, …). Justification: the card mandates this single
|
|
99
|
+
* `GislUploadCapExceededError` name and SDK-3 / E2E-1 are blocked-on it, so
|
|
100
|
+
* splitting into size/duration subclasses would break a cross-ticket naming
|
|
101
|
+
* contract; and 413 carries no typed envelope at all (plain `ErrorEnvelope`),
|
|
102
|
+
* so a one-payload-per-class split could not cover it uniformly anyway. The
|
|
103
|
+
* `kind` discriminant + a union-typed (possibly absent) `payload` is the
|
|
104
|
+
* deliberate trade-off. This is the only structured error in the tree that
|
|
105
|
+
* does not bind exactly one payload type — documented here in the same spirit
|
|
106
|
+
* as the inline PHP↔TS divergence notes.
|
|
107
|
+
*
|
|
108
|
+
* The two multipart-part errors below are deliberately NOT folded in with a
|
|
109
|
+
* `kind`: they carry different fields (`partNumber`/`uploadId` for an instance
|
|
110
|
+
* PUT failure vs `requiredParts`/`maxParts` for the count-ceiling guard) and
|
|
111
|
+
* are thrown from the multipart path, not the response handler.
|
|
112
|
+
*/
|
|
113
|
+
export declare class GislUploadCapExceededError extends GislApiError {
|
|
114
|
+
readonly kind: GislUploadCapKind;
|
|
115
|
+
readonly payload: UploadSizeExceedsTierResponse | UploadDurationExceedsTierResponse | undefined;
|
|
116
|
+
constructor(statusCode: number, errorMessage: string, kind: GislUploadCapKind, payload: UploadSizeExceedsTierResponse | UploadDurationExceedsTierResponse | undefined, path?: string, extra?: Omit<GislApiErrorOptions, 'payload'>);
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* 404 `MULTIPART_SESSION_NOT_FOUND` — the durable multipart session referenced
|
|
120
|
+
* by a resume / status / presign / keepalive call cannot be located (expired
|
|
121
|
+
* past its 48h manifest TTL, deleted, or never existed). Thrown by the SDK-3
|
|
122
|
+
* resume-support endpoints (`getUploadStatus`, `presignParts`,
|
|
123
|
+
* `keepaliveUpload`, and the resume branch of `uploadFile`).
|
|
124
|
+
*
|
|
125
|
+
* Carries no typed structured payload — the contract for the 3 resume-support
|
|
126
|
+
* endpoints models this code as a plain `ErrorEnvelope`. Consumers should
|
|
127
|
+
* detect via `instanceof` and abandon the resume; a fresh `uploadFile()` call
|
|
128
|
+
* (without `resumeUploadId`) will start a new session.
|
|
129
|
+
*/
|
|
130
|
+
export declare class GislMultipartSessionNotFoundError extends GislApiError {
|
|
131
|
+
constructor(statusCode: number, errorMessage: string, path?: string, options?: GislApiErrorOptions);
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* 403 `MULTIPART_SESSION_OWNERSHIP` — the caller is authenticated but the
|
|
135
|
+
* multipart session belongs to a different user. Thrown by the SDK-3
|
|
136
|
+
* resume-support endpoints. The session itself exists (otherwise the server
|
|
137
|
+
* would return 404 NOT_FOUND); the caller's identity simply doesn't match
|
|
138
|
+
* `manifest.userId`. Consumers should abandon the resume.
|
|
139
|
+
*/
|
|
140
|
+
export declare class GislMultipartSessionOwnershipError extends GislApiError {
|
|
141
|
+
constructor(statusCode: number, errorMessage: string, path?: string, options?: GislApiErrorOptions);
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* 403 `MULTIPART_SESSION_AUTH_REQUIRED` — the multipart session was initiated
|
|
145
|
+
* anonymously (no `manifest.userId`) and the SDK-3 resume-support endpoints
|
|
146
|
+
* refuse to serve it on an authed caller. There is no "claim" workflow today
|
|
147
|
+
* to bind an authed identity to an anonymously-started session; that is the
|
|
148
|
+
* future flip tracked at upstream ticket 8LABloaz. Consumers hitting this on
|
|
149
|
+
* resume should abandon and re-upload from scratch under the authed identity.
|
|
150
|
+
*/
|
|
151
|
+
export declare class GislMultipartSessionAuthRequiredError extends GislApiError {
|
|
152
|
+
constructor(statusCode: number, errorMessage: string, path?: string, options?: GislApiErrorOptions);
|
|
20
153
|
}
|
|
21
154
|
export declare class GislTimeoutError extends GislError {
|
|
22
155
|
constructor(message: string);
|
|
23
156
|
}
|
|
157
|
+
export declare class GislAbortError extends GislError {
|
|
158
|
+
constructor(message: string);
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* A single S3 multipart part PUT failed terminally (after the configured
|
|
162
|
+
* retry attempts) or could not be read. Subclasses `GislError` — NOT
|
|
163
|
+
* `GislApiError` — because it carries no contract error envelope and is
|
|
164
|
+
* thrown from the multipart upload path, never from the response handler.
|
|
165
|
+
* Mirrors the `GislAbortError` shape, plus the failing part's identifiers.
|
|
166
|
+
*/
|
|
167
|
+
export declare class GislMultipartPartError extends GislError {
|
|
168
|
+
readonly partNumber: number;
|
|
169
|
+
readonly uploadId: string;
|
|
170
|
+
constructor(message: string, partNumber: number, uploadId: string);
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* The upload would require more than the S3 hard limit of 10 000 multipart
|
|
174
|
+
* parts at the server-provided chunk size. Client-side guard (Model A: the
|
|
175
|
+
* server computes the part plan; the SDK asserts the ceiling). Subclasses
|
|
176
|
+
* `GislError` for the same reason as `GislMultipartPartError`.
|
|
177
|
+
*/
|
|
178
|
+
export declare class GislMultipartPartCountError extends GislError {
|
|
179
|
+
readonly requiredParts: number;
|
|
180
|
+
readonly maxParts: number;
|
|
181
|
+
constructor(message: string, requiredParts: number, maxParts: number);
|
|
182
|
+
}
|
package/dist/errors.js
CHANGED
|
@@ -9,7 +9,11 @@ export class GislApiError extends GislError {
|
|
|
9
9
|
errorMessage;
|
|
10
10
|
path;
|
|
11
11
|
details;
|
|
12
|
-
|
|
12
|
+
messageKey;
|
|
13
|
+
locale;
|
|
14
|
+
messageParams;
|
|
15
|
+
payload;
|
|
16
|
+
constructor(statusCode, errorMessage, path, details, options) {
|
|
13
17
|
const prefix = path
|
|
14
18
|
? `API error ${statusCode} at ${path}`
|
|
15
19
|
: `API error ${statusCode}`;
|
|
@@ -19,17 +23,178 @@ export class GislApiError extends GislError {
|
|
|
19
23
|
this.errorMessage = errorMessage;
|
|
20
24
|
this.path = path;
|
|
21
25
|
this.details = details;
|
|
26
|
+
if (options) {
|
|
27
|
+
this.messageKey = options.messageKey;
|
|
28
|
+
this.locale = options.locale;
|
|
29
|
+
this.messageParams = options.messageParams;
|
|
30
|
+
this.payload = options.payload;
|
|
31
|
+
}
|
|
22
32
|
}
|
|
23
33
|
}
|
|
24
34
|
export class GislValidationError extends GislApiError {
|
|
25
|
-
constructor(statusCode, errorMessage, details, path) {
|
|
26
|
-
super(statusCode, errorMessage, path, details);
|
|
35
|
+
constructor(statusCode, errorMessage, details, path, options) {
|
|
36
|
+
super(statusCode, errorMessage, path, details, options);
|
|
27
37
|
this.name = 'GislValidationError';
|
|
28
38
|
}
|
|
29
39
|
}
|
|
40
|
+
// Shared constructor body for the structured-payload subclasses. Five of the
|
|
41
|
+
// six subclasses below differ only in their typed `payload` and `name` —
|
|
42
|
+
// factor the common construction here so each subclass remains a one-liner.
|
|
43
|
+
function buildOptionsWithPayload(payload, extra) {
|
|
44
|
+
return { ...extra, payload };
|
|
45
|
+
}
|
|
46
|
+
export class GislBalanceExhaustedError extends GislApiError {
|
|
47
|
+
constructor(statusCode, errorMessage, payload, path, extra) {
|
|
48
|
+
super(statusCode, errorMessage, path, undefined, buildOptionsWithPayload(payload, extra));
|
|
49
|
+
this.name = 'GislBalanceExhaustedError';
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
export class GislTierRestrictedError extends GislApiError {
|
|
53
|
+
constructor(statusCode, errorMessage, payload, path, extra) {
|
|
54
|
+
super(statusCode, errorMessage, path, undefined, buildOptionsWithPayload(payload, extra));
|
|
55
|
+
this.name = 'GislTierRestrictedError';
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
export class GislFeatureTierRestrictedError extends GislApiError {
|
|
59
|
+
constructor(statusCode, errorMessage, payload, path, extra) {
|
|
60
|
+
super(statusCode, errorMessage, path, undefined, buildOptionsWithPayload(payload, extra));
|
|
61
|
+
this.name = 'GislFeatureTierRestrictedError';
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
export class GislFeatureNotAvailableError extends GislApiError {
|
|
65
|
+
constructor(statusCode, errorMessage, payload, path, extra) {
|
|
66
|
+
super(statusCode, errorMessage, path, undefined, buildOptionsWithPayload(payload, extra));
|
|
67
|
+
this.name = 'GislFeatureNotAvailableError';
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
export class GislWorkflowExpiredError extends GislApiError {
|
|
71
|
+
constructor(statusCode, errorMessage, payload, path, extra) {
|
|
72
|
+
super(statusCode, errorMessage, path, undefined, buildOptionsWithPayload(payload, extra));
|
|
73
|
+
this.name = 'GislWorkflowExpiredError';
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
export class GislAuthError extends GislApiError {
|
|
77
|
+
constructor(statusCode, errorMessage, payload, path, extra) {
|
|
78
|
+
super(statusCode, errorMessage, path, undefined, buildOptionsWithPayload(payload, extra));
|
|
79
|
+
this.name = 'GislAuthError';
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* A single class covering all three "upload exceeds a size/duration cap"
|
|
84
|
+
* responses (422 size-tier, 422 duration-tier, 413 absolute).
|
|
85
|
+
*
|
|
86
|
+
* CONSCIOUS DEVIATION from the one-typed-payload-per-class invariant that the
|
|
87
|
+
* other structured subclasses follow (`GislBalanceExhaustedError`,
|
|
88
|
+
* `GislWorkflowExpiredError`, …). Justification: the card mandates this single
|
|
89
|
+
* `GislUploadCapExceededError` name and SDK-3 / E2E-1 are blocked-on it, so
|
|
90
|
+
* splitting into size/duration subclasses would break a cross-ticket naming
|
|
91
|
+
* contract; and 413 carries no typed envelope at all (plain `ErrorEnvelope`),
|
|
92
|
+
* so a one-payload-per-class split could not cover it uniformly anyway. The
|
|
93
|
+
* `kind` discriminant + a union-typed (possibly absent) `payload` is the
|
|
94
|
+
* deliberate trade-off. This is the only structured error in the tree that
|
|
95
|
+
* does not bind exactly one payload type — documented here in the same spirit
|
|
96
|
+
* as the inline PHP↔TS divergence notes.
|
|
97
|
+
*
|
|
98
|
+
* The two multipart-part errors below are deliberately NOT folded in with a
|
|
99
|
+
* `kind`: they carry different fields (`partNumber`/`uploadId` for an instance
|
|
100
|
+
* PUT failure vs `requiredParts`/`maxParts` for the count-ceiling guard) and
|
|
101
|
+
* are thrown from the multipart path, not the response handler.
|
|
102
|
+
*/
|
|
103
|
+
export class GislUploadCapExceededError extends GislApiError {
|
|
104
|
+
kind;
|
|
105
|
+
constructor(statusCode, errorMessage, kind, payload, path, extra) {
|
|
106
|
+
super(statusCode, errorMessage, path, undefined, buildOptionsWithPayload(payload, extra));
|
|
107
|
+
this.name = 'GislUploadCapExceededError';
|
|
108
|
+
this.kind = kind;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* 404 `MULTIPART_SESSION_NOT_FOUND` — the durable multipart session referenced
|
|
113
|
+
* by a resume / status / presign / keepalive call cannot be located (expired
|
|
114
|
+
* past its 48h manifest TTL, deleted, or never existed). Thrown by the SDK-3
|
|
115
|
+
* resume-support endpoints (`getUploadStatus`, `presignParts`,
|
|
116
|
+
* `keepaliveUpload`, and the resume branch of `uploadFile`).
|
|
117
|
+
*
|
|
118
|
+
* Carries no typed structured payload — the contract for the 3 resume-support
|
|
119
|
+
* endpoints models this code as a plain `ErrorEnvelope`. Consumers should
|
|
120
|
+
* detect via `instanceof` and abandon the resume; a fresh `uploadFile()` call
|
|
121
|
+
* (without `resumeUploadId`) will start a new session.
|
|
122
|
+
*/
|
|
123
|
+
export class GislMultipartSessionNotFoundError extends GislApiError {
|
|
124
|
+
constructor(statusCode, errorMessage, path, options) {
|
|
125
|
+
super(statusCode, errorMessage, path, undefined, options);
|
|
126
|
+
this.name = 'GislMultipartSessionNotFoundError';
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* 403 `MULTIPART_SESSION_OWNERSHIP` — the caller is authenticated but the
|
|
131
|
+
* multipart session belongs to a different user. Thrown by the SDK-3
|
|
132
|
+
* resume-support endpoints. The session itself exists (otherwise the server
|
|
133
|
+
* would return 404 NOT_FOUND); the caller's identity simply doesn't match
|
|
134
|
+
* `manifest.userId`. Consumers should abandon the resume.
|
|
135
|
+
*/
|
|
136
|
+
export class GislMultipartSessionOwnershipError extends GislApiError {
|
|
137
|
+
constructor(statusCode, errorMessage, path, options) {
|
|
138
|
+
super(statusCode, errorMessage, path, undefined, options);
|
|
139
|
+
this.name = 'GislMultipartSessionOwnershipError';
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* 403 `MULTIPART_SESSION_AUTH_REQUIRED` — the multipart session was initiated
|
|
144
|
+
* anonymously (no `manifest.userId`) and the SDK-3 resume-support endpoints
|
|
145
|
+
* refuse to serve it on an authed caller. There is no "claim" workflow today
|
|
146
|
+
* to bind an authed identity to an anonymously-started session; that is the
|
|
147
|
+
* future flip tracked at upstream ticket 8LABloaz. Consumers hitting this on
|
|
148
|
+
* resume should abandon and re-upload from scratch under the authed identity.
|
|
149
|
+
*/
|
|
150
|
+
export class GislMultipartSessionAuthRequiredError extends GislApiError {
|
|
151
|
+
constructor(statusCode, errorMessage, path, options) {
|
|
152
|
+
super(statusCode, errorMessage, path, undefined, options);
|
|
153
|
+
this.name = 'GislMultipartSessionAuthRequiredError';
|
|
154
|
+
}
|
|
155
|
+
}
|
|
30
156
|
export class GislTimeoutError extends GislError {
|
|
31
157
|
constructor(message) {
|
|
32
158
|
super(message);
|
|
33
159
|
this.name = 'GislTimeoutError';
|
|
34
160
|
}
|
|
35
161
|
}
|
|
162
|
+
export class GislAbortError extends GislError {
|
|
163
|
+
constructor(message) {
|
|
164
|
+
super(message);
|
|
165
|
+
this.name = 'GislAbortError';
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* A single S3 multipart part PUT failed terminally (after the configured
|
|
170
|
+
* retry attempts) or could not be read. Subclasses `GislError` — NOT
|
|
171
|
+
* `GislApiError` — because it carries no contract error envelope and is
|
|
172
|
+
* thrown from the multipart upload path, never from the response handler.
|
|
173
|
+
* Mirrors the `GislAbortError` shape, plus the failing part's identifiers.
|
|
174
|
+
*/
|
|
175
|
+
export class GislMultipartPartError extends GislError {
|
|
176
|
+
partNumber;
|
|
177
|
+
uploadId;
|
|
178
|
+
constructor(message, partNumber, uploadId) {
|
|
179
|
+
super(message);
|
|
180
|
+
this.name = 'GislMultipartPartError';
|
|
181
|
+
this.partNumber = partNumber;
|
|
182
|
+
this.uploadId = uploadId;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* The upload would require more than the S3 hard limit of 10 000 multipart
|
|
187
|
+
* parts at the server-provided chunk size. Client-side guard (Model A: the
|
|
188
|
+
* server computes the part plan; the SDK asserts the ceiling). Subclasses
|
|
189
|
+
* `GislError` for the same reason as `GislMultipartPartError`.
|
|
190
|
+
*/
|
|
191
|
+
export class GislMultipartPartCountError extends GislError {
|
|
192
|
+
requiredParts;
|
|
193
|
+
maxParts;
|
|
194
|
+
constructor(message, requiredParts, maxParts) {
|
|
195
|
+
super(message);
|
|
196
|
+
this.name = 'GislMultipartPartCountError';
|
|
197
|
+
this.requiredParts = requiredParts;
|
|
198
|
+
this.maxParts = maxParts;
|
|
199
|
+
}
|
|
200
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,17 @@
|
|
|
1
1
|
export { GislClient, DEFAULT_MULTIPART_FIRST_CHUNK_SIZE } from './client.js';
|
|
2
2
|
export { verifyWebhook } from './webhook.js';
|
|
3
3
|
export { parseSseStream } from './sse.js';
|
|
4
|
-
export type { GislClientConfig, GislSseEvent, UploadOptions, WaitOptions, WorkflowCreatePayload, OperationDef,
|
|
5
|
-
export {
|
|
6
|
-
export { GislError, GislApiError, GislValidationError, GislTimeoutError, } from './errors.js';
|
|
7
|
-
export type {
|
|
8
|
-
export {
|
|
4
|
+
export type { CreditsUsageOptions, GetSchemaOptions, GetSchemaResult, PreflightClipError, PreflightClipsResult, GislClientConfig, GislSseEvent, UploadOptions, WaitOptions, WorkflowCreatePayload, OperationDef, WorkflowSourcePayload, UploadSourcePayload, JobOutputSourcePayload, ExternalImportSourcePayload, ConnectionSourcePayload, JobInputV2Payload, JobDefinitionPayload, ExternalDestinationPayload, DeliveryPayload, DeliveryModePayload, DeliveryBundleFormatPayload, DeliverySelectionPayload, DeliverySelectionTypePayload, DeliveryOutputRefPayload, WorkflowProcessingPayload, ProcessingClassHintPayload, MultipartCheckpointState, _Sdk3HandCodedUploadedPart, _Sdk3HandCodedMultipartStatusResult, _Sdk3HandCodedPresignedPart, _Sdk3HandCodedPresignPartsResult, _Sdk3HandCodedKeepaliveResult, } from './types.js';
|
|
5
|
+
export { uploadSource, jobOutputSource, externalImportSource, connectionSource, } from './types.js';
|
|
6
|
+
export { GislError, GislApiError, GislValidationError, GislBalanceExhaustedError, GislTierRestrictedError, GislFeatureTierRestrictedError, GislFeatureNotAvailableError, GislWorkflowExpiredError, GislAuthError, GislUploadCapExceededError, GislMultipartPartError, GislMultipartPartCountError, GislMultipartSessionNotFoundError, GislMultipartSessionOwnershipError, GislMultipartSessionAuthRequiredError, GislTimeoutError, GislAbortError, } from './errors.js';
|
|
7
|
+
export type { GislApiErrorOptions, GislUploadCapKind } from './errors.js';
|
|
8
|
+
export type { AudioWatermarkDecodeRequest, AudioWatermarkDecodeResponse, ContactRequest, CreditsBalanceResponse, CreditsUsageResponse, CreditTransaction, ExternalImportCreatedResponse, ExternalImportRequest, LoginUserRequest, LoginUser200ResponseData, LoginUser200ResponseDataUser, WorkflowCancelResponse, WorkflowResumeResponse, WorkflowPausedDetail, WorkflowPausedDetailLinks, UploadResponse, UploadConstraintsApplied, UploadProbeResponse, UploadProbeMediaMetadata, MultipartInitiateRequestMetadataHint, WorkflowCreateResponse, WorkflowStatusResponse, WorkflowDownloadResponse, MetadataResponse, MetadataResponseDimensions, MetadataResponseExif, MetadataResponseExifGps, OperationsSchemaResponse, OperationSchemaDefinition, MimeGroupSchema, OptionSchema, PerValueAvailabilityEntry, RetryResponse, JobDownload, OperationDownload, WebhookPayload, WebhookOperationContext, JobResponse, OperationResponse, OperationResult, OperationResultMetrics, ExternalDestination, Delivery, DeliveryPlan, DeliveryPlanOutput, WorkflowProcessing, ProcessingPlan, ProcessingPlanJob, WorkflowEdge, WorkflowWarning, JobInputV2, WorkflowSource, UploadSource, JobOutputSource, ConnectionSource, ExternalImportToken, BalanceExhaustedResponse, BalanceExhaustedResponseAllOfLinks, TierRestrictionResponse, FeatureTierRestrictedResponse, FeatureNotAvailableResponse, FeatureViolation, WorkflowExpiredResponse, AuthErrorResponse, } from '@giveitsmaller/contracts/openapi';
|
|
9
|
+
export { AudioWatermarkDecodeRequestMethodHintEnum, AudioWatermarkDecodeResponseMethodEnum, OperationInputModel, ExternalImportRequestProviderHintEnum, ContactSubject, CreditTransactionSourceBucket, UploadProbeStatus, UploadProbeProcessingClass, WorkflowCancelBillingEffect, WorkflowPauseRequiredAction, WorkflowStatus, WarningType, WorkflowWarningSeverity, OperationType, SseEventType, CallbackEventType, OperationStatus, JobStatus, JobInputV2RoleEnum, AuthErrorType, TierRestrictionKind, BalanceExhaustedResponseRequiredActionEnum, ProcessingClassReason, DeliveryPlanReason, UserTier, ProcessingClass, } from '@giveitsmaller/contracts/openapi';
|
|
9
10
|
export type { SseOperationProgressData, SseOperationCompletedData, SseOperationFailedData, SseJobCompletedData, SseJobFailedData, SseWorkflowTerminalData, } from '@giveitsmaller/contracts/openapi';
|
|
10
|
-
export type {
|
|
11
|
+
export type { MultiOutputCompletion, PageIndexed, PositionIndexed, Unindexed, } from '@giveitsmaller/contracts/asyncapi';
|
|
12
|
+
import type { MultiOutputCompletion as _MultiOutputCompletion } from '@giveitsmaller/contracts/asyncapi';
|
|
13
|
+
export type OperationResultOutputEntry = _MultiOutputCompletion['outputs'][number];
|
|
14
|
+
export type { CompressImageOptions, CompressVideoOptions, CompressAudioOptions, CompressDocumentPdfOptions, CompressDocumentOfficeOptions, CompressDocumentOdfOptions, CompressDocumentEpubOptions, ThumbnailImageOptions, ThumbnailVideoOptions, ThumbnailDocumentOptions, ConvertImageOptions, ConvertVideoOptions, ConvertAudioOptions, ConvertDocumentPdfOptions, MergeImageOptions, MergeVideoOptions, MergeVideoPerInputOptions, MergeAudioOptions, MergeAudioPerInputOptions, ArchiveOptions, ImageWatermarkImageOptions, ImageWatermarkImageGifOptions, ImageWatermarkVideoOptions, TextWatermarkImageOptions, CustomLumaVideoOptions, AudioOverlayAudioOptions, AudioOverlayVideoOptions, AudioWatermarkAudioOptions, AudioWatermarkVideoOptions, } from '@giveitsmaller/contracts/operations';
|
|
15
|
+
export { ImageWatermarkImageAnchor, ImageWatermarkImageGifAnchor, ImageWatermarkVideoAnchor, TextWatermarkImageAnchor, TextWatermarkImageFontFamily, TextWatermarkImageWatermarkMode, AudioOverlayAudioMode, AudioOverlayVideoMode, AudioOverlayVideoNoAudioTrackBehaviour, AudioWatermarkAudioMethod, AudioWatermarkAudioRobustness, AudioWatermarkAudioDensity, AudioWatermarkVideoMethod, AudioWatermarkVideoRobustness, AudioWatermarkVideoDensity, } from '@giveitsmaller/contracts/operations';
|
|
16
|
+
export { archiveMetadata, audioOverlayMetadata, audioWatermarkMetadata, compressMetadata, convertMetadata, customLumaMetadata, imageWatermarkMetadata, mergeMetadata, textWatermarkMetadata, thumbnailMetadata, } from '@giveitsmaller/contracts/operations';
|
|
17
|
+
export type { OperationMetadata, AvailabilityValue, AvailabilityEntry, FeatureEntry, MimeGroupMetadata, OptionMetadata, ProcessingClassConstraints, } from '@giveitsmaller/contracts/operations';
|
package/dist/index.js
CHANGED
|
@@ -2,7 +2,33 @@
|
|
|
2
2
|
export { GislClient, DEFAULT_MULTIPART_FIRST_CHUNK_SIZE } from './client.js';
|
|
3
3
|
export { verifyWebhook } from './webhook.js';
|
|
4
4
|
export { parseSseStream } from './sse.js';
|
|
5
|
-
export {
|
|
5
|
+
export { uploadSource, jobOutputSource, externalImportSource, connectionSource, } from './types.js';
|
|
6
6
|
// Errors
|
|
7
|
-
export { GislError, GislApiError, GislValidationError,
|
|
8
|
-
|
|
7
|
+
export { GislError, GislApiError, GislValidationError, GislBalanceExhaustedError, GislTierRestrictedError, GislFeatureTierRestrictedError, GislFeatureNotAvailableError, GislWorkflowExpiredError, GislAuthError, GislUploadCapExceededError, GislMultipartPartError, GislMultipartPartCountError,
|
|
8
|
+
// SDK-3 (Wb6ebOMM) — typed errors for the 3 resume-support endpoints.
|
|
9
|
+
GislMultipartSessionNotFoundError, GislMultipartSessionOwnershipError, GislMultipartSessionAuthRequiredError, GislTimeoutError, GislAbortError, } from './errors.js';
|
|
10
|
+
export { AudioWatermarkDecodeRequestMethodHintEnum, AudioWatermarkDecodeResponseMethodEnum,
|
|
11
|
+
// OperationInputModel — value-bearing enum (`single` | `multi`).
|
|
12
|
+
// Surfaced on OperationSchemaDefinition.inputModel so form-renderers
|
|
13
|
+
// can decide whether to render a single-file picker or a multi-file
|
|
14
|
+
// input list.
|
|
15
|
+
OperationInputModel, ExternalImportRequestProviderHintEnum, ContactSubject, CreditTransactionSourceBucket, UploadProbeStatus, UploadProbeProcessingClass, WorkflowCancelBillingEffect, WorkflowPauseRequiredAction, WorkflowStatus, WarningType, WorkflowWarningSeverity, OperationType, SseEventType, CallbackEventType, OperationStatus, JobStatus, JobInputV2RoleEnum,
|
|
16
|
+
// Error-payload discriminator enums — pair with the typed payload
|
|
17
|
+
// types above for narrowing inside `error instanceof Gisl<X>Error`
|
|
18
|
+
// branches.
|
|
19
|
+
AuthErrorType, TierRestrictionKind, BalanceExhaustedResponseRequiredActionEnum, ProcessingClassReason, DeliveryPlanReason,
|
|
20
|
+
// UserTier + ProcessingClass — value-bearing forms (typeof const +
|
|
21
|
+
// type alias). Sourced from openapi so consumers can do
|
|
22
|
+
// `Object.values(UserTier)` for tier dropdowns or
|
|
23
|
+
// `if (tier === UserTier.enterprise)` for narrowing typed error
|
|
24
|
+
// payloads. The operations metadata-types versions are pure type
|
|
25
|
+
// aliases (no runtime value); the openapi versions carry both the
|
|
26
|
+
// string-union type and a const map. Per audit follow-up.
|
|
27
|
+
UserTier, ProcessingClass, } from '@giveitsmaller/contracts/openapi';
|
|
28
|
+
export { ImageWatermarkImageAnchor, ImageWatermarkImageGifAnchor, ImageWatermarkVideoAnchor, TextWatermarkImageAnchor, TextWatermarkImageFontFamily, TextWatermarkImageWatermarkMode, AudioOverlayAudioMode, AudioOverlayVideoMode, AudioOverlayVideoNoAudioTrackBehaviour, AudioWatermarkAudioMethod, AudioWatermarkAudioRobustness, AudioWatermarkAudioDensity, AudioWatermarkVideoMethod, AudioWatermarkVideoRobustness, AudioWatermarkVideoDensity, } from '@giveitsmaller/contracts/operations';
|
|
29
|
+
// Per-operation metadata sidecars. Inspect `availability`,
|
|
30
|
+
// `required_tier`, per-value gating, mime-group availability and
|
|
31
|
+
// per-feature flags before submitting a workflow — the API will
|
|
32
|
+
// otherwise reject planned ops with `feature_not_available` (422,
|
|
33
|
+
// surfaces as `GislFeatureNotAvailableError`).
|
|
34
|
+
export { archiveMetadata, audioOverlayMetadata, audioWatermarkMetadata, compressMetadata, convertMetadata, customLumaMetadata, imageWatermarkMetadata, mergeMetadata, textWatermarkMetadata, thumbnailMetadata, } from '@giveitsmaller/contracts/operations';
|
package/dist/sse.d.ts
CHANGED
|
@@ -7,5 +7,24 @@ import type { GislSseEvent } from './types.js';
|
|
|
7
7
|
* - Multi-line `data:` fields (concatenated with newlines)
|
|
8
8
|
* - Comment lines (`:` prefix) used as keep-alives
|
|
9
9
|
* - `retry:` field (ignored, SDK manages its own reconnection)
|
|
10
|
+
*
|
|
11
|
+
* `opts.signal` (optional): when it aborts, the underlying body reader is
|
|
12
|
+
* cancelled. This is the ONLY way to promptly stop a stream parked on a
|
|
13
|
+
* quiet socket: `reader.read()` is suspended, so the generator's `finally`
|
|
14
|
+
* cannot run until that read settles — calling `reader.cancel()` from the
|
|
15
|
+
* abort listener settles it (`{ done: true }`) and runs the stream's cancel
|
|
16
|
+
* algorithm, freeing the connection. (MDN/TC39: an async generator's
|
|
17
|
+
* `return()` is itself unreachable while suspended at `await`; cancellation
|
|
18
|
+
* must be driven externally via an AbortSignal.) `GislClient.streamEvents`
|
|
19
|
+
* owns the controller and wires `return()`/`throw()` → `abort()`.
|
|
20
|
+
*
|
|
21
|
+
* By-design limitation: when called WITHOUT `opts.signal`, there is no
|
|
22
|
+
* cancellation path while `reader.read()` is suspended — a consumer that
|
|
23
|
+
* `break`s / `gen.return()`s on a quiet socket stays stuck until the
|
|
24
|
+
* server sends data or closes (an inherent JS async-generator constraint,
|
|
25
|
+
* not a defect). Pass `opts.signal`, or prefer `GislClient.streamEvents`
|
|
26
|
+
* (which always wires one), whenever early termination must be prompt.
|
|
10
27
|
*/
|
|
11
|
-
export declare function parseSseStream(response: Response
|
|
28
|
+
export declare function parseSseStream(response: Response, opts?: {
|
|
29
|
+
signal?: AbortSignal;
|
|
30
|
+
}): AsyncGenerator<GislSseEvent>;
|
package/dist/sse.js
CHANGED
|
@@ -6,13 +6,51 @@
|
|
|
6
6
|
* - Multi-line `data:` fields (concatenated with newlines)
|
|
7
7
|
* - Comment lines (`:` prefix) used as keep-alives
|
|
8
8
|
* - `retry:` field (ignored, SDK manages its own reconnection)
|
|
9
|
+
*
|
|
10
|
+
* `opts.signal` (optional): when it aborts, the underlying body reader is
|
|
11
|
+
* cancelled. This is the ONLY way to promptly stop a stream parked on a
|
|
12
|
+
* quiet socket: `reader.read()` is suspended, so the generator's `finally`
|
|
13
|
+
* cannot run until that read settles — calling `reader.cancel()` from the
|
|
14
|
+
* abort listener settles it (`{ done: true }`) and runs the stream's cancel
|
|
15
|
+
* algorithm, freeing the connection. (MDN/TC39: an async generator's
|
|
16
|
+
* `return()` is itself unreachable while suspended at `await`; cancellation
|
|
17
|
+
* must be driven externally via an AbortSignal.) `GislClient.streamEvents`
|
|
18
|
+
* owns the controller and wires `return()`/`throw()` → `abort()`.
|
|
19
|
+
*
|
|
20
|
+
* By-design limitation: when called WITHOUT `opts.signal`, there is no
|
|
21
|
+
* cancellation path while `reader.read()` is suspended — a consumer that
|
|
22
|
+
* `break`s / `gen.return()`s on a quiet socket stays stuck until the
|
|
23
|
+
* server sends data or closes (an inherent JS async-generator constraint,
|
|
24
|
+
* not a defect). Pass `opts.signal`, or prefer `GislClient.streamEvents`
|
|
25
|
+
* (which always wires one), whenever early termination must be prompt.
|
|
9
26
|
*/
|
|
10
|
-
export async function* parseSseStream(response) {
|
|
27
|
+
export async function* parseSseStream(response, opts = {}) {
|
|
11
28
|
const body = response.body;
|
|
12
29
|
if (!body) {
|
|
13
30
|
return;
|
|
14
31
|
}
|
|
32
|
+
const signal = opts.signal;
|
|
33
|
+
if (signal?.aborted) {
|
|
34
|
+
// Pre-aborted: the body is still unlocked (no reader yet), so cancel it
|
|
35
|
+
// directly to free the connection, then yield nothing.
|
|
36
|
+
await body.cancel().catch(() => { });
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
15
39
|
const reader = body.getReader();
|
|
40
|
+
// `reader.cancel()` is valid while the reader holds the lock (unlike
|
|
41
|
+
// `body.cancel()`, which throws "Cannot cancel a locked stream"). It
|
|
42
|
+
// settles the in-flight `reader.read()` with `{ done: true }` and runs
|
|
43
|
+
// the stream's cancel algorithm. We track `aborted` so the post-loop
|
|
44
|
+
// trailing flush below does NOT emit a partial, never-terminated event
|
|
45
|
+
// once the consumer has abandoned the stream (the cancelled read looks
|
|
46
|
+
// exactly like a clean EOF — `{ done: true }` — but a buffered
|
|
47
|
+
// unterminated `data:` run after an abort is garbage, not an event).
|
|
48
|
+
let aborted = false;
|
|
49
|
+
const onAbort = () => {
|
|
50
|
+
aborted = true;
|
|
51
|
+
void reader.cancel().catch(() => { });
|
|
52
|
+
};
|
|
53
|
+
signal?.addEventListener('abort', onAbort, { once: true });
|
|
16
54
|
const decoder = new TextDecoder();
|
|
17
55
|
let buffer = '';
|
|
18
56
|
let eventType = '';
|
|
@@ -28,6 +66,12 @@ export async function* parseSseStream(response) {
|
|
|
28
66
|
// Keep the last (potentially incomplete) line in the buffer
|
|
29
67
|
buffer = lines.pop() ?? '';
|
|
30
68
|
for (const line of lines) {
|
|
69
|
+
// If a single read delivered multiple complete events and the
|
|
70
|
+
// consumer aborted after receiving an earlier one (we were
|
|
71
|
+
// suspended at `yield`), do NOT keep emitting the remaining
|
|
72
|
+
// buffered events on resume — stop processing this batch.
|
|
73
|
+
if (aborted)
|
|
74
|
+
break;
|
|
31
75
|
if (line === '') {
|
|
32
76
|
// Empty line = end of event
|
|
33
77
|
if (dataLines.length > 0) {
|
|
@@ -73,8 +117,12 @@ export async function* parseSseStream(response) {
|
|
|
73
117
|
}
|
|
74
118
|
}
|
|
75
119
|
}
|
|
76
|
-
// Flush any remaining buffered event
|
|
77
|
-
|
|
120
|
+
// Flush any remaining buffered event — but ONLY on a genuine
|
|
121
|
+
// end-of-stream (server closed without a final blank line). After an
|
|
122
|
+
// abort, the cancelled read also surfaces as `{ done: true }`, yet a
|
|
123
|
+
// partial unterminated `data:` buffer is not a real event and must
|
|
124
|
+
// not be yielded once the consumer has abandoned the stream.
|
|
125
|
+
if (!aborted && dataLines.length > 0) {
|
|
78
126
|
const rawData = dataLines.join('\n');
|
|
79
127
|
let parsed;
|
|
80
128
|
try {
|
|
@@ -90,6 +138,17 @@ export async function* parseSseStream(response) {
|
|
|
90
138
|
}
|
|
91
139
|
}
|
|
92
140
|
finally {
|
|
141
|
+
signal?.removeEventListener('abort', onAbort);
|
|
142
|
+
// Cancel the body so the underlying HTTP connection is released on
|
|
143
|
+
// EVERY exit path (early `return()`/abort AND normal completion) — a
|
|
144
|
+
// bare `releaseLock()` leaves the socket open until GC. Cancelling an
|
|
145
|
+
// already-closed/cancelled stream is a harmless no-op that resolves.
|
|
146
|
+
try {
|
|
147
|
+
await reader.cancel();
|
|
148
|
+
}
|
|
149
|
+
catch {
|
|
150
|
+
/* stream already errored/closed — nothing to release */
|
|
151
|
+
}
|
|
93
152
|
reader.releaseLock();
|
|
94
153
|
}
|
|
95
154
|
}
|