@giveitsmaller/sdk 0.7.0 → 0.9.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/dist/_audit.js +16 -0
- package/dist/builder.d.ts +1 -8
- package/dist/builder.js +7 -5
- package/dist/client.js +14 -4
- package/dist/errors.d.ts +65 -0
- package/dist/errors.js +77 -0
- package/dist/file-first.d.ts +503 -0
- package/dist/file-first.js +840 -0
- package/dist/generated/sdk_spec/errors.d.ts +1 -1
- package/dist/generated/sdk_spec/errors.js +50 -0
- package/dist/generated/sdk_spec/version.d.ts +1 -1
- package/dist/generated/sdk_spec/version.js +1 -1
- package/dist/gisl.d.ts +31 -0
- package/dist/gisl.js +47 -0
- package/dist/handle.d.ts +153 -0
- package/dist/handle.js +253 -0
- package/dist/http-downloader.d.ts +9 -0
- package/dist/http-downloader.js +55 -0
- package/dist/index.d.ts +9 -2
- package/dist/index.js +30 -1
- package/dist/merge.d.ts +2 -1
- package/dist/merge.js +43 -11
- package/package.json +3 -3
package/dist/_audit.js
CHANGED
|
@@ -121,4 +121,20 @@ export function _runAudit() {
|
|
|
121
121
|
accept();
|
|
122
122
|
accept();
|
|
123
123
|
accept();
|
|
124
|
+
// FF1 / 3BIxEnfR — file-first result surface + sink errors.
|
|
125
|
+
accept();
|
|
126
|
+
accept();
|
|
127
|
+
accept();
|
|
128
|
+
accept();
|
|
129
|
+
accept();
|
|
130
|
+
accept();
|
|
131
|
+
accept();
|
|
132
|
+
// FF3a / u0hBt6fl — homogeneous fan-out builder surface.
|
|
133
|
+
accept();
|
|
134
|
+
accept();
|
|
135
|
+
accept();
|
|
136
|
+
accept();
|
|
137
|
+
// FF5a / Ao8RPVxD — file-first Handle reattach surface.
|
|
138
|
+
accept();
|
|
139
|
+
accept();
|
|
124
140
|
}
|
package/dist/builder.d.ts
CHANGED
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
*/
|
|
27
27
|
import type { GislClient } from './client.js';
|
|
28
28
|
import type { OperationDownload, WorkflowStatusResponse, SseOperationProgressDataStatusEnum } from '@giveitsmaller/contracts/openapi';
|
|
29
|
+
import { Handle } from './handle.js';
|
|
29
30
|
import type { PresetDefaults, PresetMedia } from './ergonomic/presets/index.js';
|
|
30
31
|
/**
|
|
31
32
|
* Best-effort detection of the compress-operation media from the
|
|
@@ -183,14 +184,6 @@ export interface Result {
|
|
|
183
184
|
*/
|
|
184
185
|
readonly resolvedOptions: ResolvedOptions;
|
|
185
186
|
}
|
|
186
|
-
/**
|
|
187
|
-
* Lighter return value from `.submit({webhook})` — no SSE/poll wait,
|
|
188
|
-
* caller reconciles completion via the webhook.
|
|
189
|
-
*/
|
|
190
|
-
export interface Handle {
|
|
191
|
-
readonly workflowId: string;
|
|
192
|
-
readonly webhookSecret?: string;
|
|
193
|
-
}
|
|
194
187
|
/**
|
|
195
188
|
* Upload-phase progress event. The byte counter comes from
|
|
196
189
|
* `UploadOptions.onProgress` — there is no `phase` field on the wire.
|
package/dist/builder.js
CHANGED
|
@@ -27,6 +27,10 @@
|
|
|
27
27
|
import { SseEventType, SseOperationProgressDataFromJSON, } from '@giveitsmaller/contracts/openapi';
|
|
28
28
|
import { uploadSource } from './types.js';
|
|
29
29
|
import { GislTimeoutError } from './errors.js';
|
|
30
|
+
// Deferred-usage-only import: `Handle` is constructed inside submit() at call
|
|
31
|
+
// time, not at module load, so the builder.ts <-> handle.ts cycle is safe
|
|
32
|
+
// under ESM (handle.ts imports the await-primitives from this module).
|
|
33
|
+
import { Handle } from './handle.js';
|
|
30
34
|
import { resolveCompressOptions, } from './ergonomic/preset_resolver.js';
|
|
31
35
|
/**
|
|
32
36
|
* Best-effort detection of the compress-operation media from the
|
|
@@ -264,11 +268,9 @@ export class OperationBuilder {
|
|
|
264
268
|
callback_url: options.webhook,
|
|
265
269
|
};
|
|
266
270
|
const created = await this.client.createWorkflow(payload);
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
};
|
|
271
|
-
return handle;
|
|
271
|
+
// No client passed → the returned Handle's status()/wait()/result()
|
|
272
|
+
// throw `no_client`; the operation-first submit reconciles via webhook.
|
|
273
|
+
return new Handle(created.workflowId, created.webhookSecret != null ? created.webhookSecret : undefined);
|
|
272
274
|
}
|
|
273
275
|
/**
|
|
274
276
|
* Fan-out chain: run this builder to completion, then for each artifact
|
package/dist/client.js
CHANGED
|
@@ -399,10 +399,19 @@ export class GislClient {
|
|
|
399
399
|
locale: json.locale,
|
|
400
400
|
messageParams: json.message_params,
|
|
401
401
|
};
|
|
402
|
+
// Human-readable text comes from `message` (the I26 localised field).
|
|
403
|
+
// `error` is the stable, never-localised SCREAMING_SNAKE machine code —
|
|
404
|
+
// NOT display text. Surfacing `error` as the thrown error's `.message`
|
|
405
|
+
// regressed consumers that render the human string (x9Lbf6uy). Fall back
|
|
406
|
+
// to `error` when `message` is absent (deployed contract guarantees
|
|
407
|
+
// `message` on conforming error envelopes). Machine dispatch keys off
|
|
408
|
+
// `error_type` (below), unchanged.
|
|
409
|
+
const status = response.status;
|
|
410
|
+
const errorMessage = json.message ?? json.error ?? 'Unknown error';
|
|
402
411
|
// Validation-details branch first — preserve existing shape so callers
|
|
403
412
|
// matching on `instanceof GislValidationError` keep working.
|
|
404
413
|
if (isValidationDetails(json.details)) {
|
|
405
|
-
throw new GislValidationError(response.status,
|
|
414
|
+
throw new GislValidationError(response.status, errorMessage, json.details, path, i18n);
|
|
406
415
|
}
|
|
407
416
|
// Dispatch by (status, error_type) onto the structured envelope shapes
|
|
408
417
|
// emitted by the v2 contracts. Each branch builds the typed payload via
|
|
@@ -416,8 +425,6 @@ export class GislClient {
|
|
|
416
425
|
// fall through to the base `GislApiError` rather than handing the
|
|
417
426
|
// caller silently-corrupted typed metadata.
|
|
418
427
|
const errorType = json.error_type;
|
|
419
|
-
const status = response.status;
|
|
420
|
-
const errorMessage = json.error ?? 'Unknown error';
|
|
421
428
|
// Build the typed payload via FromJSON, then validate that all
|
|
422
429
|
// required typed fields are well-formed. FromJSON does not throw on
|
|
423
430
|
// missing required fields — for example `workflow_expired` without
|
|
@@ -1740,7 +1747,10 @@ export class GislClient {
|
|
|
1740
1747
|
let errorMessage = 'Unknown error';
|
|
1741
1748
|
try {
|
|
1742
1749
|
const errJson = (await response.json());
|
|
1743
|
-
|
|
1750
|
+
// Prefer the human `message`; `error` is the machine code (x9Lbf6uy).
|
|
1751
|
+
if (errJson.message)
|
|
1752
|
+
errorMessage = errJson.message;
|
|
1753
|
+
else if (errJson.error)
|
|
1744
1754
|
errorMessage = errJson.error;
|
|
1745
1755
|
}
|
|
1746
1756
|
catch {
|
package/dist/errors.d.ts
CHANGED
|
@@ -300,6 +300,18 @@ export declare class GislChainCardinalityMismatchError extends GislConfigError {
|
|
|
300
300
|
export declare class GislTimeoutError extends GislError {
|
|
301
301
|
constructor(message: string);
|
|
302
302
|
}
|
|
303
|
+
/**
|
|
304
|
+
* Transport-level failure: the underlying `fetch` (or other transport) could
|
|
305
|
+
* not produce a usable response — DNS, TCP, TLS, a mid-stream disconnect, or a
|
|
306
|
+
* non-ok status / empty body when fetching a result download. Mirrors the PHP
|
|
307
|
+
* `Gisl\Sdk\Errors\GislNetworkError`. Subclasses `GislError` (not
|
|
308
|
+
* `GislApiError`) because it carries no contract error envelope. The concrete
|
|
309
|
+
* file-first {@link Downloader} raises this when the output URL cannot be read
|
|
310
|
+
* (a destination-WRITE failure is `GislSinkError` reason `write_failed`).
|
|
311
|
+
*/
|
|
312
|
+
export declare class GislNetworkError extends GislError {
|
|
313
|
+
constructor(message: string);
|
|
314
|
+
}
|
|
303
315
|
export declare class GislAbortError extends GislError {
|
|
304
316
|
constructor(message: string);
|
|
305
317
|
}
|
|
@@ -326,3 +338,56 @@ export declare class GislMultipartPartCountError extends GislError {
|
|
|
326
338
|
readonly maxParts: number;
|
|
327
339
|
constructor(message: string, requiredParts: number, maxParts: number);
|
|
328
340
|
}
|
|
341
|
+
/**
|
|
342
|
+
* Thrown by the file-first `RunResult.byKey()` (FF1) when no result entry
|
|
343
|
+
* matches the requested key. A keyless run (no `key:` supplied to `file()`)
|
|
344
|
+
* is addressable positionally only — `byKey()` always throws.
|
|
345
|
+
*
|
|
346
|
+
* Mirrors the PHP `Gisl\Sdk\Errors\GislNoSuchKeyError`.
|
|
347
|
+
*/
|
|
348
|
+
export declare class GislNoSuchKeyError extends GislError {
|
|
349
|
+
constructor(message: string);
|
|
350
|
+
}
|
|
351
|
+
/**
|
|
352
|
+
* Thrown by the file-first `Handle.result()` (FF5a) when the workflow has not
|
|
353
|
+
* yet reached a terminal state. `result()` is the NON-blocking accessor: it
|
|
354
|
+
* fetches the current status once and, if the workflow is still
|
|
355
|
+
* `pending`/`in_progress`, throws this rather than waiting. Use `Handle.wait()`
|
|
356
|
+
* to block until terminal instead.
|
|
357
|
+
*
|
|
358
|
+
* Carries the `workflowId` and the current (non-terminal) `state`.
|
|
359
|
+
*
|
|
360
|
+
* Mirrors the PHP `Gisl\Sdk\Errors\GislResultNotReadyError`.
|
|
361
|
+
*/
|
|
362
|
+
export declare class GislResultNotReadyError extends GislError {
|
|
363
|
+
readonly workflowId: string;
|
|
364
|
+
readonly state: string;
|
|
365
|
+
constructor(workflowId: string, state: string);
|
|
366
|
+
}
|
|
367
|
+
/** Machine-readable cause carried by {@link GislSinkError}. */
|
|
368
|
+
export type GislSinkErrorReason = 'not_single_output' | 'downloader_unavailable' | 'partial_failure' | 'duplicate_filename' | 'invalid_directory' | 'write_failed';
|
|
369
|
+
/**
|
|
370
|
+
* Thrown by the file-first `RunResult` sinks (`toFile()` / `downloadTo()`,
|
|
371
|
+
* FF1) when they cannot deliver. The machine-readable `reason` discriminates
|
|
372
|
+
* the three cases, mirroring the `reason`-bag convention on
|
|
373
|
+
* {@link GislConfigError}:
|
|
374
|
+
*
|
|
375
|
+
* - `not_single_output` — `toFile()` requires exactly one output but the
|
|
376
|
+
* run produced zero or more than one.
|
|
377
|
+
* - `downloader_unavailable` — the `RunResult` has no downloader bound (e.g. a
|
|
378
|
+
* browser / no-I/O context).
|
|
379
|
+
* - `partial_failure` — `downloadTo({ failOnPartial: true })` and the
|
|
380
|
+
* run had at least one failed input.
|
|
381
|
+
* - `duplicate_filename` — two outputs share a destination filename in one
|
|
382
|
+
* `downloadTo(dir)`, which would silently overwrite.
|
|
383
|
+
* - `write_failed` — a concrete {@link Downloader} could not open or
|
|
384
|
+
* stream to the destination path.
|
|
385
|
+
*
|
|
386
|
+
* Mirrors the PHP `Gisl\Sdk\Errors\GislSinkError`.
|
|
387
|
+
*/
|
|
388
|
+
export declare class GislSinkError extends GislError {
|
|
389
|
+
readonly reason: GislSinkErrorReason;
|
|
390
|
+
constructor(message: string, options: {
|
|
391
|
+
readonly reason: GislSinkErrorReason;
|
|
392
|
+
});
|
|
393
|
+
}
|
package/dist/errors.js
CHANGED
|
@@ -320,6 +320,21 @@ export class GislTimeoutError extends GislError {
|
|
|
320
320
|
this.name = 'GislTimeoutError';
|
|
321
321
|
}
|
|
322
322
|
}
|
|
323
|
+
/**
|
|
324
|
+
* Transport-level failure: the underlying `fetch` (or other transport) could
|
|
325
|
+
* not produce a usable response — DNS, TCP, TLS, a mid-stream disconnect, or a
|
|
326
|
+
* non-ok status / empty body when fetching a result download. Mirrors the PHP
|
|
327
|
+
* `Gisl\Sdk\Errors\GislNetworkError`. Subclasses `GislError` (not
|
|
328
|
+
* `GislApiError`) because it carries no contract error envelope. The concrete
|
|
329
|
+
* file-first {@link Downloader} raises this when the output URL cannot be read
|
|
330
|
+
* (a destination-WRITE failure is `GislSinkError` reason `write_failed`).
|
|
331
|
+
*/
|
|
332
|
+
export class GislNetworkError extends GislError {
|
|
333
|
+
constructor(message) {
|
|
334
|
+
super(message);
|
|
335
|
+
this.name = 'GislNetworkError';
|
|
336
|
+
}
|
|
337
|
+
}
|
|
323
338
|
export class GislAbortError extends GislError {
|
|
324
339
|
constructor(message) {
|
|
325
340
|
super(message);
|
|
@@ -359,3 +374,65 @@ export class GislMultipartPartCountError extends GislError {
|
|
|
359
374
|
this.maxParts = maxParts;
|
|
360
375
|
}
|
|
361
376
|
}
|
|
377
|
+
/**
|
|
378
|
+
* Thrown by the file-first `RunResult.byKey()` (FF1) when no result entry
|
|
379
|
+
* matches the requested key. A keyless run (no `key:` supplied to `file()`)
|
|
380
|
+
* is addressable positionally only — `byKey()` always throws.
|
|
381
|
+
*
|
|
382
|
+
* Mirrors the PHP `Gisl\Sdk\Errors\GislNoSuchKeyError`.
|
|
383
|
+
*/
|
|
384
|
+
export class GislNoSuchKeyError extends GislError {
|
|
385
|
+
constructor(message) {
|
|
386
|
+
super(message);
|
|
387
|
+
this.name = 'GislNoSuchKeyError';
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
/**
|
|
391
|
+
* Thrown by the file-first `Handle.result()` (FF5a) when the workflow has not
|
|
392
|
+
* yet reached a terminal state. `result()` is the NON-blocking accessor: it
|
|
393
|
+
* fetches the current status once and, if the workflow is still
|
|
394
|
+
* `pending`/`in_progress`, throws this rather than waiting. Use `Handle.wait()`
|
|
395
|
+
* to block until terminal instead.
|
|
396
|
+
*
|
|
397
|
+
* Carries the `workflowId` and the current (non-terminal) `state`.
|
|
398
|
+
*
|
|
399
|
+
* Mirrors the PHP `Gisl\Sdk\Errors\GislResultNotReadyError`.
|
|
400
|
+
*/
|
|
401
|
+
export class GislResultNotReadyError extends GislError {
|
|
402
|
+
workflowId;
|
|
403
|
+
state;
|
|
404
|
+
constructor(workflowId, state) {
|
|
405
|
+
super(`Workflow ${workflowId} is not ready (state '${state}'); its result is not available yet. ` +
|
|
406
|
+
'Call wait() to block until it reaches a terminal state, or poll result() again later.');
|
|
407
|
+
this.name = 'GislResultNotReadyError';
|
|
408
|
+
this.workflowId = workflowId;
|
|
409
|
+
this.state = state;
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
/**
|
|
413
|
+
* Thrown by the file-first `RunResult` sinks (`toFile()` / `downloadTo()`,
|
|
414
|
+
* FF1) when they cannot deliver. The machine-readable `reason` discriminates
|
|
415
|
+
* the three cases, mirroring the `reason`-bag convention on
|
|
416
|
+
* {@link GislConfigError}:
|
|
417
|
+
*
|
|
418
|
+
* - `not_single_output` — `toFile()` requires exactly one output but the
|
|
419
|
+
* run produced zero or more than one.
|
|
420
|
+
* - `downloader_unavailable` — the `RunResult` has no downloader bound (e.g. a
|
|
421
|
+
* browser / no-I/O context).
|
|
422
|
+
* - `partial_failure` — `downloadTo({ failOnPartial: true })` and the
|
|
423
|
+
* run had at least one failed input.
|
|
424
|
+
* - `duplicate_filename` — two outputs share a destination filename in one
|
|
425
|
+
* `downloadTo(dir)`, which would silently overwrite.
|
|
426
|
+
* - `write_failed` — a concrete {@link Downloader} could not open or
|
|
427
|
+
* stream to the destination path.
|
|
428
|
+
*
|
|
429
|
+
* Mirrors the PHP `Gisl\Sdk\Errors\GislSinkError`.
|
|
430
|
+
*/
|
|
431
|
+
export class GislSinkError extends GislError {
|
|
432
|
+
reason;
|
|
433
|
+
constructor(message, options) {
|
|
434
|
+
super(message);
|
|
435
|
+
this.name = 'GislSinkError';
|
|
436
|
+
this.reason = options.reason;
|
|
437
|
+
}
|
|
438
|
+
}
|