@giveitsmaller/sdk 0.2.2 → 0.4.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 +57 -0
- package/dist/client.d.ts +181 -4
- package/dist/client.js +799 -55
- package/dist/errors.d.ts +66 -9
- package/dist/errors.js +69 -6
- package/dist/index.d.ts +13 -6
- package/dist/index.js +27 -3
- package/dist/types.d.ts +218 -37
- package/dist/types.js +28 -7
- package/package.json +5 -3
package/README.md
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# @giveitsmaller/sdk
|
|
2
|
+
|
|
3
|
+
TypeScript / Node.js SDK for the [GISL](https://giveitsmaller.com) (Give It Smaller) file compression and processing API.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @giveitsmaller/sdk
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Node.js 18+ required.
|
|
12
|
+
|
|
13
|
+
## Quickstart
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
import { GislClient, uploadSource, OperationType } from '@giveitsmaller/sdk';
|
|
17
|
+
|
|
18
|
+
const client = new GislClient({
|
|
19
|
+
baseUrl: 'https://api.giveitsmaller.com',
|
|
20
|
+
apiKey: 'REPLACE_ME_API_KEY',
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
const upload = await client.uploadFile('./photo.jpg');
|
|
24
|
+
|
|
25
|
+
const workflow = await client.createWorkflow({
|
|
26
|
+
jobs: [
|
|
27
|
+
{
|
|
28
|
+
id: 'compressed',
|
|
29
|
+
source: uploadSource(upload.fileId),
|
|
30
|
+
operations: [
|
|
31
|
+
{ type: OperationType.compress, options: { mode: 'lossy', quality: 80 } },
|
|
32
|
+
],
|
|
33
|
+
},
|
|
34
|
+
],
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
await client.waitForWorkflow(workflow.workflowId);
|
|
38
|
+
|
|
39
|
+
const dls = await client.getWorkflowDownloads(workflow.workflowId);
|
|
40
|
+
console.log('Compressed:', dls.downloads[0].files[0].downloadUrl);
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Full documentation
|
|
44
|
+
|
|
45
|
+
Docs are published in the [giveitsmaller-sdks](https://github.com/AntonioCS/giveitsmaller-sdks) repository — they are **not** shipped in the npm tarball (only `dist/` is published).
|
|
46
|
+
|
|
47
|
+
- **Getting started & concepts** — [`docs/typescript/index.md`](https://github.com/AntonioCS/giveitsmaller-sdks/blob/main/docs/typescript/index.md)
|
|
48
|
+
- **Client reference** (all `GislClient` methods + operation option list) — [`docs/typescript/client.md`](https://github.com/AntonioCS/giveitsmaller-sdks/blob/main/docs/typescript/client.md)
|
|
49
|
+
- **Types & authoring primitives** (config, payloads, job factories) — [`docs/typescript/types.md`](https://github.com/AntonioCS/giveitsmaller-sdks/blob/main/docs/typescript/types.md)
|
|
50
|
+
- **SSE / live progress** — [`docs/typescript/sse.md`](https://github.com/AntonioCS/giveitsmaller-sdks/blob/main/docs/typescript/sse.md)
|
|
51
|
+
- **Webhooks** — [`docs/typescript/webhook.md`](https://github.com/AntonioCS/giveitsmaller-sdks/blob/main/docs/typescript/webhook.md)
|
|
52
|
+
- **Errors & retry guidance** — [`docs/typescript/errors.md`](https://github.com/AntonioCS/giveitsmaller-sdks/blob/main/docs/typescript/errors.md)
|
|
53
|
+
- **Troubleshooting** — [`docs/typescript/troubleshooting.md`](https://github.com/AntonioCS/giveitsmaller-sdks/blob/main/docs/typescript/troubleshooting.md)
|
|
54
|
+
- **Examples** — compress, thumbnail, convert, merge, archive — [`docs/typescript/examples/`](https://github.com/AntonioCS/giveitsmaller-sdks/tree/main/docs/typescript/examples)
|
|
55
|
+
|
|
56
|
+
## License
|
|
57
|
+
|
|
58
|
+
MIT — see the [LICENSE](https://github.com/AntonioCS/giveitsmaller-sdks/blob/main/LICENSE) file.
|
package/dist/_audit.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function _runAudit(): void;
|
package/dist/_audit.js
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
// Per ticket J65ZERTi (T20) — public-API completeness audit gate.
|
|
2
|
+
//
|
|
3
|
+
// This file sits inside `src/` so it is type-checked by `tsc --noEmit`
|
|
4
|
+
// (the test directory is excluded from `tsconfig.json` so a test-side
|
|
5
|
+
// audit is dead — earlier follow-up review caught this). The list of
|
|
6
|
+
// type-only imports here IS the gate: if a regen drops or renames any
|
|
7
|
+
// symbol, `tsc` fails on the import line.
|
|
8
|
+
//
|
|
9
|
+
// Each `accept<T>()` call resolves the type parameter; the function
|
|
10
|
+
// itself is a no-op. The body is never invoked at runtime — only the
|
|
11
|
+
// import resolution matters.
|
|
12
|
+
function accept(_value) {
|
|
13
|
+
// intentionally empty — type-presence is the assertion
|
|
14
|
+
}
|
|
15
|
+
// One call per imported type. tsc resolves the type parameter against
|
|
16
|
+
// the import; if the import is broken, the call site fails to compile.
|
|
17
|
+
export function _runAudit() {
|
|
18
|
+
accept();
|
|
19
|
+
accept();
|
|
20
|
+
accept();
|
|
21
|
+
accept();
|
|
22
|
+
accept();
|
|
23
|
+
accept();
|
|
24
|
+
accept();
|
|
25
|
+
accept();
|
|
26
|
+
accept();
|
|
27
|
+
accept();
|
|
28
|
+
accept();
|
|
29
|
+
accept();
|
|
30
|
+
accept();
|
|
31
|
+
accept();
|
|
32
|
+
accept();
|
|
33
|
+
accept();
|
|
34
|
+
accept();
|
|
35
|
+
accept();
|
|
36
|
+
accept();
|
|
37
|
+
accept();
|
|
38
|
+
accept();
|
|
39
|
+
accept();
|
|
40
|
+
accept();
|
|
41
|
+
accept();
|
|
42
|
+
accept();
|
|
43
|
+
accept();
|
|
44
|
+
accept();
|
|
45
|
+
accept();
|
|
46
|
+
accept();
|
|
47
|
+
accept();
|
|
48
|
+
accept();
|
|
49
|
+
accept();
|
|
50
|
+
accept();
|
|
51
|
+
accept();
|
|
52
|
+
accept();
|
|
53
|
+
accept();
|
|
54
|
+
accept();
|
|
55
|
+
accept();
|
|
56
|
+
accept();
|
|
57
|
+
}
|
package/dist/client.d.ts
CHANGED
|
@@ -1,15 +1,29 @@
|
|
|
1
|
-
import type { UploadResponse, WorkflowCreateResponse, WorkflowStatusResponse, WorkflowDownloadResponse, MetadataResponse,
|
|
2
|
-
import type { GislClientConfig, GislSseEvent, UploadOptions, WaitOptions, WorkflowCreatePayload } from './types.js';
|
|
1
|
+
import type { AudioWatermarkDecodeRequest, AudioWatermarkDecodeResponse, ExternalImportCreatedResponse, ExternalImportRequest, LoginUserRequest, LoginUser200ResponseData, ContactRequest, CreditsBalanceResponse, CreditsUsageResponse, UploadResponse, UploadProbeResponse, WorkflowCancelResponse, WorkflowCreateResponse, WorkflowResumeResponse, WorkflowStatusResponse, WorkflowDownloadResponse, MetadataResponse, RetryResponse } from '@giveitsmaller/contracts/openapi';
|
|
2
|
+
import type { CreditsUsageOptions, GetSchemaOptions, GetSchemaResult, GislClientConfig, GislSseEvent, PreflightClipsResult, UploadOptions, WaitOptions, WorkflowCreatePayload } from './types.js';
|
|
3
|
+
export declare const MULTIPART_CONCURRENCY_DEFAULT: 4;
|
|
3
4
|
export declare const DEFAULT_MULTIPART_FIRST_CHUNK_SIZE: number;
|
|
5
|
+
export interface ValidationDetail {
|
|
6
|
+
message: string;
|
|
7
|
+
field?: string;
|
|
8
|
+
operation?: string;
|
|
9
|
+
option?: string;
|
|
10
|
+
messageKey?: string;
|
|
11
|
+
locale?: string;
|
|
12
|
+
messageParams?: Record<string, unknown>;
|
|
13
|
+
}
|
|
4
14
|
export declare class GislClient {
|
|
5
15
|
private readonly baseUrl;
|
|
6
16
|
private readonly headers;
|
|
7
17
|
private readonly timeoutMs;
|
|
8
18
|
private readonly multipartThreshold;
|
|
9
19
|
private readonly multipartConcurrency;
|
|
20
|
+
private readonly multipartMaxAttempts;
|
|
21
|
+
private readonly multipartRetryBaseMs;
|
|
22
|
+
private readonly useSessionCookie;
|
|
10
23
|
constructor(config: GislClientConfig);
|
|
11
24
|
private request;
|
|
12
25
|
private handleResponse;
|
|
26
|
+
private isAuthErrorType;
|
|
13
27
|
/**
|
|
14
28
|
* Upload a file. Automatically uses multipart upload for files exceeding
|
|
15
29
|
* the configured threshold (default 10 MB).
|
|
@@ -19,6 +33,17 @@ export declare class GislClient {
|
|
|
19
33
|
*/
|
|
20
34
|
uploadFile(file: string | Blob, options?: UploadOptions): Promise<UploadResponse>;
|
|
21
35
|
private singleUpload;
|
|
36
|
+
/**
|
|
37
|
+
* Direct-to-S3 multipart upload for files above the threshold.
|
|
38
|
+
*
|
|
39
|
+
* The /multipart/complete response (MultipartCompleteResponse) only carries
|
|
40
|
+
* { upload_id, status }. The server's upload_id is the same UUID callers
|
|
41
|
+
* pass as file_id to POST /api/workflows — so fileId is synthesised from
|
|
42
|
+
* upload_id and a full UploadResponse is returned to keep the public
|
|
43
|
+
* uploadFile() API uniform across single and multipart paths. The mimeType
|
|
44
|
+
* comes from the initiate response's first-chunk detection; for authoritative
|
|
45
|
+
* post-upload metadata callers should use getMetadata(fileId).
|
|
46
|
+
*/
|
|
22
47
|
private multipartUpload;
|
|
23
48
|
/**
|
|
24
49
|
* Create a new workflow.
|
|
@@ -32,6 +57,41 @@ export declare class GislClient {
|
|
|
32
57
|
* Poll until the workflow reaches a terminal status.
|
|
33
58
|
*/
|
|
34
59
|
waitForWorkflow(workflowId: string, options?: WaitOptions): Promise<WorkflowStatusResponse>;
|
|
60
|
+
/**
|
|
61
|
+
* Cancel a workflow. Idempotent — cancelling an already-cancelled
|
|
62
|
+
* workflow returns 200 with the same shape (and the original
|
|
63
|
+
* `cancelledAt`). Cancelling a `completed` / `failed` /
|
|
64
|
+
* `partially_failed` / `expired` workflow returns 409.
|
|
65
|
+
*
|
|
66
|
+
* The response's `billingEffect` field tells the caller what
|
|
67
|
+
* happened to outstanding reservations:
|
|
68
|
+
* - `unspent_reservation_released` — workflow was active or paused
|
|
69
|
+
* and the unspent portion of the reservation has been refunded.
|
|
70
|
+
* The refund appears as a separate `CreditTransaction` with
|
|
71
|
+
* `type: refund`.
|
|
72
|
+
* - `none` — no refund (all reserved credits were already consumed
|
|
73
|
+
* by completed jobs, or this is an idempotent re-cancel).
|
|
74
|
+
*
|
|
75
|
+
* In-flight operations may continue running briefly after the
|
|
76
|
+
* cancel response while their Lambda processes terminate; the
|
|
77
|
+
* response is the binding "no further reservations will be made"
|
|
78
|
+
* signal.
|
|
79
|
+
*/
|
|
80
|
+
cancelWorkflow(workflowId: string): Promise<WorkflowCancelResponse>;
|
|
81
|
+
/**
|
|
82
|
+
* Resume a workflow that is in `paused_insufficient_credits`.
|
|
83
|
+
*
|
|
84
|
+
* Resume succeeds only when `availableCredits` covers the next
|
|
85
|
+
* reservation. If the balance is still insufficient, throws
|
|
86
|
+
* `GislBalanceExhaustedError` (402, same envelope as the workflow-
|
|
87
|
+
* create 402 path) and the workflow stays paused. If the workflow
|
|
88
|
+
* is past its `expiresAt` (default 7-day TTL from `pausedAt`),
|
|
89
|
+
* throws `GislWorkflowExpiredError` (422) and the workflow has
|
|
90
|
+
* transitioned to `expired` — callers cannot un-expire a workflow.
|
|
91
|
+
* Resuming a workflow that is not in `paused_insufficient_credits`
|
|
92
|
+
* is a 409 (no-op).
|
|
93
|
+
*/
|
|
94
|
+
resumeWorkflow(workflowId: string): Promise<WorkflowResumeResponse>;
|
|
35
95
|
/**
|
|
36
96
|
* Get download URLs for a completed workflow.
|
|
37
97
|
*/
|
|
@@ -46,11 +106,128 @@ export declare class GislClient {
|
|
|
46
106
|
getMetadata(fileId: string): Promise<MetadataResponse>;
|
|
47
107
|
/**
|
|
48
108
|
* Get the operations schema (available types, options, constraints).
|
|
49
|
-
*
|
|
109
|
+
*
|
|
110
|
+
* Returns raw JSON (no envelope). The response is **per-tier private**
|
|
111
|
+
* (cache key includes the caller's `user_tier`); CDN-style public
|
|
112
|
+
* caching is not used. Pass `ifNoneMatch` / `ifModifiedSince` from a
|
|
113
|
+
* previous response to revalidate — a 304 surfaces as
|
|
114
|
+
* `{ notModified: true, etag, lastModified }` so callers can keep
|
|
115
|
+
* using their cached copy.
|
|
50
116
|
*/
|
|
51
|
-
getSchema(): Promise<
|
|
117
|
+
getSchema(options?: GetSchemaOptions): Promise<GetSchemaResult>;
|
|
52
118
|
/**
|
|
53
119
|
* Retry a failed operation.
|
|
54
120
|
*/
|
|
55
121
|
retryOperation(operationId: string): Promise<RetryResponse>;
|
|
122
|
+
/**
|
|
123
|
+
* Submit a contact-form message. The endpoint returns 204 No Content on
|
|
124
|
+
* success, so this method resolves to `void`.
|
|
125
|
+
*
|
|
126
|
+
* Validation errors (e.g. missing `email`, non-empty honeypot `website`)
|
|
127
|
+
* surface as `GislValidationError` from the standard error envelope.
|
|
128
|
+
*/
|
|
129
|
+
submitContact(payload: ContactRequest): Promise<void>;
|
|
130
|
+
/**
|
|
131
|
+
* Get a snapshot of the caller's current credit position. The canonical
|
|
132
|
+
* billing-state surface — `BalanceExhaustedResponse` (402) on workflow
|
|
133
|
+
* creation includes pre-error counters for context, but UIs should drive
|
|
134
|
+
* spend-now affordances and tier-upgrade prompts off this endpoint, not
|
|
135
|
+
* off the error envelope.
|
|
136
|
+
*/
|
|
137
|
+
getCreditsBalance(): Promise<CreditsBalanceResponse>;
|
|
138
|
+
/**
|
|
139
|
+
* Authenticate with email/password. On success the server issues a
|
|
140
|
+
* session cookie via `Set-Cookie`; subsequent requests authenticate
|
|
141
|
+
* via that cookie when the client is configured with
|
|
142
|
+
* `useSessionCookie: true`.
|
|
143
|
+
*
|
|
144
|
+
* Failure modes per ticket FX6mbTJD:
|
|
145
|
+
* - **401** `invalid_credentials` (collapsed with unverified
|
|
146
|
+
* accounts for anti-enumeration) → `GislAuthError`.
|
|
147
|
+
* - **403** account-state failures (`account_locked`,
|
|
148
|
+
* `account_disabled`, `account_deleted`,
|
|
149
|
+
* `account_deletion_expired`) → `GislAuthError`.
|
|
150
|
+
* - **429** infrastructure rate-limit → `GislApiError` with
|
|
151
|
+
* the `Retry-After` header echoed on the response.
|
|
152
|
+
*
|
|
153
|
+
* Node session persistence (cookie-jar across processes) is out of
|
|
154
|
+
* scope — this method only touches the request side.
|
|
155
|
+
*/
|
|
156
|
+
login(credentials: LoginUserRequest): Promise<LoginUser200ResponseData>;
|
|
157
|
+
/**
|
|
158
|
+
* Invalidate the current session.
|
|
159
|
+
*
|
|
160
|
+
* Idempotent: calling logout without an active session returns 401,
|
|
161
|
+
* but the SDK collapses both 200 and 401 into a single "logged out"
|
|
162
|
+
* outcome — `logout()` resolves to `void` in either case so caller
|
|
163
|
+
* cleanup code does not need to special-case the not-currently-
|
|
164
|
+
* authenticated path. Other errors (e.g. 500, network failures)
|
|
165
|
+
* still throw.
|
|
166
|
+
*/
|
|
167
|
+
logout(): Promise<void>;
|
|
168
|
+
/**
|
|
169
|
+
* Register a one-shot bearer URL (S3 presigned, GCS signed, Azure
|
|
170
|
+
* SAS, Dropbox shared link, public HTTPS) and receive an opaque
|
|
171
|
+
* `externalSourceId` handle. Subsequent workflows reference the
|
|
172
|
+
* handle via `WorkflowSource` of `type: external_import` —
|
|
173
|
+
* compose with the [`externalImportSource()`](./types.ts) factory.
|
|
174
|
+
*
|
|
175
|
+
* Per ADR-0005 §"SSRF posture": the server validates 8 rules at
|
|
176
|
+
* registration time AND again at fetch time. HTTPS-only;
|
|
177
|
+
* private/loopback/cloud-metadata IPs are rejected (403). The
|
|
178
|
+
* original URL + password are encrypted at rest and never
|
|
179
|
+
* returned in any response.
|
|
180
|
+
*
|
|
181
|
+
* Currently `availability: planned` — the runtime endpoint returns
|
|
182
|
+
* 422 `feature_not_available` (or 404, per the cross-repo rollout)
|
|
183
|
+
* until the external-import infrastructure ships. The method
|
|
184
|
+
* exists today so consumers can write the integration ahead of
|
|
185
|
+
* time.
|
|
186
|
+
*/
|
|
187
|
+
createExternalImport(payload: ExternalImportRequest): Promise<ExternalImportCreatedResponse>;
|
|
188
|
+
/**
|
|
189
|
+
* Decode a previously-embedded steganographic audio watermark
|
|
190
|
+
* (per ticket I20). Pairs with the `audio_watermark` operation —
|
|
191
|
+
* the operation embeds; this endpoint decodes.
|
|
192
|
+
*
|
|
193
|
+
* **Enterprise tier only.** Free / pro callers receive
|
|
194
|
+
* `GislFeatureTierRestrictedError` (403).
|
|
195
|
+
*
|
|
196
|
+
* **Own watermarks only.** The decoder will refuse to extract from
|
|
197
|
+
* media the caller did not mark themselves — mismatches return 404
|
|
198
|
+
* (rather than leaking that *some* watermark was detected).
|
|
199
|
+
*
|
|
200
|
+
* Currently `availability: planned` — calls return
|
|
201
|
+
* `GislFeatureNotAvailableError` (422) until the cross-repo Lambda
|
|
202
|
+
* support ships. Decode requests are rate-limited independently
|
|
203
|
+
* from workflow-create.
|
|
204
|
+
*/
|
|
205
|
+
decodeAudioWatermark(payload: AudioWatermarkDecodeRequest): Promise<AudioWatermarkDecodeResponse>;
|
|
206
|
+
/**
|
|
207
|
+
* Probe an uploaded file for workflow-readiness — detects corruption,
|
|
208
|
+
* unsupported codecs, and pre-assigns the processing class the server
|
|
209
|
+
* would route the file to. Designed for the long-form merge edge case
|
|
210
|
+
* where a single bad input would fail the whole workflow.
|
|
211
|
+
*
|
|
212
|
+
* Currently `availability: planned` — calls return
|
|
213
|
+
* `GislFeatureNotAvailableError` (422) until the cross-repo Lambda
|
|
214
|
+
* support ships. Idempotent: probing the same `fileId` twice returns
|
|
215
|
+
* the cached result.
|
|
216
|
+
*/
|
|
217
|
+
probeUpload(fileId: string): Promise<UploadProbeResponse>;
|
|
218
|
+
/**
|
|
219
|
+
* Probe N uploaded files in parallel and partition the results by
|
|
220
|
+
* outcome. Returns `{ ok, rejected, errors }` so the caller can
|
|
221
|
+
* cleanly drop bad clips before submitting a long-form merge
|
|
222
|
+
* workflow. Probe-call failures (including the
|
|
223
|
+
* `feature_not_available` 422 returned while the endpoint is
|
|
224
|
+
* `availability: planned`) land in `errors` rather than throwing,
|
|
225
|
+
* so a partially-successful batch still yields useful aggregation.
|
|
226
|
+
*/
|
|
227
|
+
preflightClips(fileIds: string[]): Promise<PreflightClipsResult>;
|
|
228
|
+
/**
|
|
229
|
+
* Get a paginated page of credit transaction history for the caller.
|
|
230
|
+
* Server defaults: `limit=20`, `offset=0`. Most-recent-first.
|
|
231
|
+
*/
|
|
232
|
+
getCreditsUsage(options?: CreditsUsageOptions): Promise<CreditsUsageResponse>;
|
|
56
233
|
}
|