@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/index.d.ts CHANGED
@@ -4,15 +4,22 @@ export { parseSseStream } from './sse.js';
4
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
5
  export { uploadSource, jobOutputSource, externalImportSource, connectionSource, } from './types.js';
6
6
  export type { GislConfigErrorMetadata } from './errors.js';
7
- export { GislError, GislApiError, GislValidationError, GislBalanceExhaustedError, GislTierRestrictedError, GislFeatureTierRestrictedError, GislFeatureNotAvailableError, GislWorkflowExpiredError, GislProbePendingError, GislAuthError, GislUploadCapExceededError, GislMultipartPartError, GislMultipartPartCountError, GislMultipartSessionNotFoundError, GislMultipartSessionOwnershipError, GislMultipartSessionAuthRequiredError, GislTimeoutError, GislAbortError, GislConfigError, GislMissingCredentialsError, GislFeatureRequiresAuthError, GislUndeclaredAssetError, GislUnusedAssetError, GislPerInputOptionsNotSupportedError, GislChainCardinalityMismatchError, } from './errors.js';
7
+ export { GislError, GislApiError, GislValidationError, GislBalanceExhaustedError, GislTierRestrictedError, GislFeatureTierRestrictedError, GislFeatureNotAvailableError, GislWorkflowExpiredError, GislProbePendingError, GislAuthError, GislUploadCapExceededError, GislMultipartPartError, GislMultipartPartCountError, GislMultipartSessionNotFoundError, GislMultipartSessionOwnershipError, GislMultipartSessionAuthRequiredError, GislTimeoutError, GislAbortError, GislNetworkError, GislConfigError, GislMissingCredentialsError, GislFeatureRequiresAuthError, GislUndeclaredAssetError, GislUnusedAssetError, GislPerInputOptionsNotSupportedError, GislChainCardinalityMismatchError, GislNoSuchKeyError, GislSinkError, GislResultNotReadyError, } from './errors.js';
8
8
  export type { GislApiErrorOptions, GislUploadCapKind } from './errors.js';
9
+ export { RunResult } from './file-first.js';
10
+ export type { OutputFile, ItemResult, ItemFailure, Manifest, Downloader, } from './file-first.js';
11
+ export { Recipe, fileInput } from './file-first.js';
12
+ export type { FileInput } from './file-first.js';
13
+ export { FilesRecipe } from './file-first.js';
14
+ export { HttpDownloader } from './http-downloader.js';
15
+ export { Handle, StatusSnapshot } from './handle.js';
9
16
  export { gisl, create } from './gisl.js';
10
17
  export type { GislCreateOptions, Environment, ErgonomicClient } from './gisl.js';
11
18
  export { presetDefaults, PresetDefaults, type PresetMedia, type PresetOp, type AnyPresetOptions, ImageCompressPresetOptions, type ImageCompressPresetOptionsInput, AudioCompressPresetOptions, type AudioCompressPresetOptionsInput, VideoCompressPresetOptions, type VideoCompressPresetOptionsInput, DocumentPdfCompressPresetOptions, type DocumentPdfCompressPresetOptionsInput, DocumentOfficeCompressPresetOptions, type DocumentOfficeCompressPresetOptionsInput, DocumentOdfCompressPresetOptions, type DocumentOdfCompressPresetOptionsInput, DocumentEpubCompressPresetOptions, type DocumentEpubCompressPresetOptionsInput, OptimizeFor, ImageMode, ImageFit, ImageMetadataPolicy, IccProfilePolicy, ImageFormat, VideoCodec, VideoPreset, VideoFit, AudioBitrate, AudioCodec, AudioSampleRate, PdfProfile, PdfColorspace, } from './ergonomic/presets/index.js';
12
19
  export { OperationBuilder, MapEachBuilder } from './builder.js';
13
20
  export { MergeBuilder, asset, handle, clip } from './merge.js';
14
21
  export type { Asset, ClipEntry, ClipOptions, MergeMediaKind, MergeOptions, SequenceEntry, } from './merge.js';
15
- export type { Artifact, ArtifactRef, Handle, JobBreakdown, OperationBreakdown, ProcessingProgressEvent, ProgressEvent, ResolvedOptions, ResolvedOptionsSources, Result, RunOptions, SubmitOptions, UploadProgressEvent, } from './builder.js';
22
+ export type { Artifact, ArtifactRef, JobBreakdown, OperationBreakdown, ProcessingProgressEvent, ProgressEvent, ResolvedOptions, ResolvedOptionsSources, Result, RunOptions, SubmitOptions, UploadProgressEvent, } from './builder.js';
16
23
  export { PRESET_VERSION, resolveCompressOptions } from './ergonomic/preset_resolver.js';
17
24
  export type { ResolveCompressOptionsInput, ResolveCompressOptionsOutput, } from './ergonomic/preset_resolver.js';
18
25
  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, PerRoleCardinalityEntry, 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, ProbePendingResponse, AuthErrorResponse, } from '@giveitsmaller/contracts/openapi';
package/dist/index.js CHANGED
@@ -7,6 +7,9 @@ export { uploadSource, jobOutputSource, externalImportSource, connectionSource,
7
7
  export { GislError, GislApiError, GislValidationError, GislBalanceExhaustedError, GislTierRestrictedError, GislFeatureTierRestrictedError, GislFeatureNotAvailableError, GislWorkflowExpiredError, GislProbePendingError, GislAuthError, GislUploadCapExceededError, GislMultipartPartError, GislMultipartPartCountError,
8
8
  // SDK-3 (Wb6ebOMM) — typed errors for the 3 resume-support endpoints.
9
9
  GislMultipartSessionNotFoundError, GislMultipartSessionOwnershipError, GislMultipartSessionAuthRequiredError, GislTimeoutError, GislAbortError,
10
+ // FF2b / tywwynmN — transport-level failure (mirrors PHP GislNetworkError);
11
+ // raised by the file-first HttpDownloader when an output URL cannot be read.
12
+ GislNetworkError,
10
13
  // T1 / wVU4xHx3 — local config-error tree (pre-I/O; sibling of GislApiError).
11
14
  GislConfigError, GislMissingCredentialsError, GislFeatureRequiresAuthError,
12
15
  // T3 / cuecCmb5 — merge-compose local validation errors.
@@ -14,7 +17,33 @@ GislUndeclaredAssetError, GislUnusedAssetError, GislPerInputOptionsNotSupportedE
14
17
  // T6 / aDR1jnyZ — chain-cardinality validation (dormant until chain
15
18
  // methods on OperationBuilder ship; type + audit registration land
16
19
  // here so the future chain-method PR is a pure addition).
17
- GislChainCardinalityMismatchError, } from './errors.js';
20
+ GislChainCardinalityMismatchError,
21
+ // FF1 / 3BIxEnfR — file-first result sink errors.
22
+ GislNoSuchKeyError, GislSinkError,
23
+ // FF5a / Ao8RPVxD — thrown by the file-first Handle.result() when the
24
+ // workflow is not yet terminal (the non-blocking accessor).
25
+ GislResultNotReadyError, } from './errors.js';
26
+ // File-first result surface (FF1 / 3BIxEnfR) — coexists with the
27
+ // operation-first `Result`/`Artifact` until FF6 removes the old layer.
28
+ export { RunResult } from './file-first.js';
29
+ // File-first builder (FF2a / MfV0PDok) — `client.file(path).op()...` lowering.
30
+ export { Recipe, fileInput } from './file-first.js';
31
+ // File-first homogeneous fan-out (FF3a / u0hBt6fl) — `client.files([...]).op()...`
32
+ // applies one recipe to many inputs in one workflow; run() partitions per input.
33
+ // `projectMultiJobToRunResult` is intentionally NOT re-exported — it is the
34
+ // @internal per-job producer consumed only by FilesRecipe.run (codex).
35
+ export { FilesRecipe } from './file-first.js';
36
+ // File-first execution (FF2b / MfV0PDok) — Node streaming downloader bound by
37
+ // `Recipe.run()` to write pre-signed output URLs to disk.
38
+ export { HttpDownloader } from './http-downloader.js';
39
+ // `projectDownloadsToRunResult` is intentionally NOT re-exported here — it is an
40
+ // @internal helper shared between `file-first.ts` (Recipe.run) and `handle.ts`
41
+ // (Handle.wait/result) via direct intra-package import, not public API (codex).
42
+ // File-first Handle + StatusSnapshot (FF5a / Ao8RPVxD) — method-bearing,
43
+ // client-bound value objects. `Handle` is the return of `submit()` (no client)
44
+ // AND `client.workflow(id)` (client-bound, reattach). Exported as VALUES (the
45
+ // prior `export type { Handle }` is replaced) because `Handle` is now a class.
46
+ export { Handle, StatusSnapshot } from './handle.js';
18
47
  // Ergonomic-layer entrypoint (T1 / wVU4xHx3) — `gisl.create()` factory +
19
48
  // credential-chain types. `gisl.anonymous()` (public export) lands once
20
49
  // the anonymous-capable operation allowlist is non-empty (plan §12).
package/dist/merge.d.ts CHANGED
@@ -26,7 +26,8 @@
26
26
  * assets both fail fast so the caller saves bandwidth on typo'd composes.
27
27
  */
28
28
  import type { GislClient } from './client.js';
29
- import { type Handle, type Result, type RunOptions, type SubmitOptions } from './builder.js';
29
+ import { type Result, type RunOptions, type SubmitOptions } from './builder.js';
30
+ import { Handle } from './handle.js';
30
31
  /**
31
32
  * A declared merge asset. `path` carries a string or Blob (deduped by
32
33
  * normalised source key); `handle` wraps an already-uploaded file (deduped
package/dist/merge.js CHANGED
@@ -25,9 +25,10 @@
25
25
  * Local validation runs BEFORE any upload — undeclared refs and unused
26
26
  * assets both fail fast so the caller saves bandwidth on typo'd composes.
27
27
  */
28
- import { uploadSource } from './types.js';
28
+ import { uploadSource, jobOutputSource } from './types.js';
29
29
  import { GislConfigError, GislPerInputOptionsNotSupportedError, GislTimeoutError, GislUndeclaredAssetError, GislUnusedAssetError, } from './errors.js';
30
30
  import { _checkAborted, _consumeSseToTerminal, _parseMaxWait, _pollToTerminal, _projectResult, } from './builder.js';
31
+ import { Handle } from './handle.js';
31
32
  /**
32
33
  * Construct a path-asset. Bare-string arguments to `merge(...)` are
33
34
  * implicitly wrapped via this helper.
@@ -117,7 +118,14 @@ export class MergeBuilder {
117
118
  throw new GislTimeoutError(`Merge workflow ${created.workflowId} reached terminal status but maxWait elapsed before downloads could be fetched`);
118
119
  }
119
120
  const downloads = await this.client.getWorkflowDownloads(created.workflowId);
120
- return _projectResult(finalStatus, downloads.downloads, this.opOptionsForResolved());
121
+ // p0SuJEeK — project ONLY the merge job's output. getWorkflowDownloads
122
+ // returns a download group per terminal job, which now INCLUDES the
123
+ // `passthrough` source jobs (their output is the unchanged upload). Those
124
+ // are plumbing, not the merge deliverable — surfacing them as artifacts
125
+ // would pollute the Result with the raw inputs. The merge job's ref is
126
+ // 'merge' (see buildPayload); the source jobs are 'src_N'.
127
+ const mergeDownloads = downloads.downloads.filter((d) => d.ref === 'merge');
128
+ return _projectResult(finalStatus, mergeDownloads, this.opOptionsForResolved());
121
129
  }
122
130
  async submit(options) {
123
131
  const plan = this.planSequence();
@@ -125,11 +133,9 @@ export class MergeBuilder {
125
133
  const payload = this.buildPayload(plan, uploadedByAssetId);
126
134
  payload.callback_url = options.webhook;
127
135
  const created = await this.client.createWorkflow(payload);
128
- const handle = {
129
- workflowId: created.workflowId,
130
- ...(created.webhookSecret != null ? { webhookSecret: created.webhookSecret } : {}),
131
- };
132
- return handle;
136
+ // No client passed → the returned Handle's status()/wait()/result()
137
+ // throw `no_client`; the merge submit reconciles via webhook.
138
+ return new Handle(created.workflowId, created.webhookSecret != null ? created.webhookSecret : undefined);
133
139
  }
134
140
  // ---------------------------------------------------------------------------
135
141
  /**
@@ -247,12 +253,38 @@ export class MergeBuilder {
247
253
  return uploaded;
248
254
  }
249
255
  buildPayload(plan, uploadedByAssetId) {
250
- const inputs = plan.positions.map((pos) => {
256
+ // p0SuJEeK the API rejects upload-direct multi-input
257
+ // (`MultiInputSource` excludes the `upload` leaf: "use type=job_output").
258
+ // So each uploaded asset is wrapped in its OWN single-input `passthrough`
259
+ // source job, and the merge job references those via `job_output` — the
260
+ // shape the v2.35.0 `v2_merge_two_uploads` example prescribes. One source
261
+ // job per UNIQUE asset (in first-seen position order); a repeated asset
262
+ // re-uses its src job. `passthrough` is a lossless inert op (it does NOT
263
+ // get the implicit compress an empty `operations: []` job would).
264
+ const srcIdByAsset = new Map();
265
+ const sourceJobs = [];
266
+ for (const pos of plan.positions) {
267
+ if (srcIdByAsset.has(pos.assetId))
268
+ continue;
251
269
  const fileId = uploadedByAssetId.get(pos.assetId);
252
270
  if (fileId === undefined) {
253
271
  // Defensive — planSequence should have rejected this.
254
272
  throw new Error(`Asset '${pos.assetId}' was never uploaded — internal builder bug`);
255
273
  }
274
+ const srcId = `src_${sourceJobs.length}`;
275
+ srcIdByAsset.set(pos.assetId, srcId);
276
+ sourceJobs.push({
277
+ id: srcId,
278
+ source: uploadSource(fileId),
279
+ operations: [{ type: 'passthrough' }],
280
+ });
281
+ }
282
+ const inputs = plan.positions.map((pos) => {
283
+ // Defensive — srcIdByAsset was populated for every position's asset above.
284
+ const srcId = srcIdByAsset.get(pos.assetId);
285
+ if (srcId === undefined) {
286
+ throw new Error(`Asset '${pos.assetId}' has no source job — internal builder bug`);
287
+ }
256
288
  // Codex r1 HIGH 502c6bf232c2 — per_input_options goes on EACH
257
289
  // JobInputV2Payload (per-input entry), NOT on operations[0].options.
258
290
  // Skip emission for image merges (planSequence already rejects opts
@@ -261,7 +293,7 @@ export class MergeBuilder {
261
293
  const wireOpts = plan.mediaKind === 'image'
262
294
  ? {}
263
295
  : wirePerInputOptions(pos.options, plan.mediaKind);
264
- const input = { source: uploadSource(fileId) };
296
+ const input = { source: jobOutputSource(srcId) };
265
297
  if (Object.keys(wireOpts).length > 0) {
266
298
  input.per_input_options = wireOpts;
267
299
  }
@@ -269,12 +301,12 @@ export class MergeBuilder {
269
301
  });
270
302
  // Merge-level options (excluding the SDK-side mediaKind/allowUnusedAssets).
271
303
  const mergeOpts = wireMergeOptions(this.opOptions, plan.mediaKind);
272
- const job = {
304
+ const mergeJob = {
273
305
  id: 'merge',
274
306
  inputs,
275
307
  operations: [{ type: 'merge', options: mergeOpts }],
276
308
  };
277
- return { jobs: [job] };
309
+ return { jobs: [...sourceJobs, mergeJob] };
278
310
  }
279
311
  opOptionsForResolved() {
280
312
  // Strip the SDK-only fields before exposing on resolvedOptions.applied.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@giveitsmaller/sdk",
3
- "version": "0.7.0",
3
+ "version": "0.9.0",
4
4
  "description": "Node.js SDK for the GISL (Give It Smaller) file compression and processing API",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -19,12 +19,12 @@
19
19
  "node": ">=18"
20
20
  },
21
21
  "dependencies": {
22
- "@giveitsmaller/contracts": "^0.8.0"
22
+ "@giveitsmaller/contracts": "^0.9.0"
23
23
  },
24
24
  "devDependencies": {
25
25
  "@types/node": "^22",
26
26
  "typescript": "^5.7",
27
- "vitest": "^3.1",
27
+ "vitest": "^3.1 <3.2.5",
28
28
  "yaml": "^2.6"
29
29
  },
30
30
  "scripts": {