diffio 0.1.42 → 0.1.43

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 CHANGED
@@ -59,12 +59,16 @@ const project = await client.createProject({
59
59
  const generation = await client.createGeneration({
60
60
  apiProjectId: project.apiProjectId,
61
61
  model: "diffio-3.5",
62
- sampling: { steps: 12, guidance: 1.5 }
62
+ sampling: { steps: 12, guidance: 1.5 },
63
+ idempotencyKey: "restore-sample-001"
63
64
  });
64
65
 
65
- console.log(generation.generationId);
66
+ console.log(generation.generationId, generation.idempotentReplay ?? false);
66
67
  ```
67
68
 
69
+ Reuse the same `idempotencyKey` when retrying generation creation for a project. The API then
70
+ returns the existing generation with `idempotentReplay: true` instead of creating another generation.
71
+
68
72
  ## Audio isolation helper
69
73
 
70
74
  ```ts
@@ -74,12 +78,16 @@ const client = new DiffioClient({ apiKey: "diffio_live_..." });
74
78
  const result = await client.audioIsolation.isolate({
75
79
  filePath: "sample.wav",
76
80
  model: "diffio-3.5",
77
- sampling: { steps: 12, guidance: 1.5 }
81
+ sampling: { steps: 12, guidance: 1.5 },
82
+ idempotencyKey: "restore-sample-001"
78
83
  });
79
84
 
80
85
  console.log(result.generation.generationId);
81
86
  ```
82
87
 
88
+ The isolation helpers create a new project before creating its generation. Their `idempotencyKey`
89
+ protects retries of that generation request; it does not deduplicate a separate helper call or upload.
90
+
83
91
  ## Restore audio in one call
84
92
 
85
93
  This helper runs the full flow and returns the downloaded bytes plus a metadata object.
@@ -93,6 +101,7 @@ const [audioBytes, info] = await client.restoreAudio({
93
101
  filePath: "sample.wav",
94
102
  model: "diffio-3.5",
95
103
  sampling: { steps: 12, guidance: 1.5 },
104
+ idempotencyKey: "restore-sample-001",
96
105
  onProgress: (progress) => console.log(progress.status)
97
106
  });
98
107
 
package/dist/Client.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { BaseClientOptions, BaseRequestOptions, NormalizedClientOptions } from "./BaseClient";
2
- import type { AccountSettingsResponse, ApiKeyResponse, ApiKeysListResponse, AudioIsolationResult, CreateGenerationResponse, CreateProjectResponse, GenerationDownloadResponse, GenerationProgressResponse, ListProjectGenerationsResponse, ListProjectsResponse, RestoreMetadata, UsageSummaryResponse, WebhookConfigureResponse, WebhookTestEventResponse } from "./api/types";
2
+ import type { AccountSettingsResponse, ApiKeyResponse, ApiKeysListResponse, AudioIsolationResult, CreateGenerationResponse, CreateProjectResponse, GenerationDownloadResponse, GenerationProgressResponse, ListProjectGenerationsResponse, ListProjectsResponse, ModelKey, RestoreMetadata, UsageSummaryResponse, WebhookConfigureResponse, WebhookTestEventResponse } from "./api/types";
3
3
  import { AccountClient, ApiKeysClient, AudioIsolationClient, GenerationsClient, ProjectsClient, UsageClient, WebhooksClient } from "./api/resources";
4
4
  export declare namespace DiffioClient {
5
5
  type Options = BaseClientOptions;
@@ -28,9 +28,10 @@ export declare class DiffioClient {
28
28
  private _uploadFile;
29
29
  createGeneration(options: {
30
30
  apiProjectId: string;
31
- model?: string;
31
+ model?: ModelKey;
32
32
  sampling?: Record<string, unknown>;
33
33
  params?: Record<string, unknown>;
34
+ idempotencyKey?: string;
34
35
  requestOptions?: DiffioClient.RequestOptions;
35
36
  }): Promise<CreateGenerationResponse>;
36
37
  listProjects(options?: {
@@ -108,10 +109,11 @@ export declare class DiffioClient {
108
109
  contentType?: string;
109
110
  contentLength?: number;
110
111
  fileFormat?: string;
111
- model?: string;
112
+ model?: ModelKey;
112
113
  sampling?: Record<string, unknown>;
113
114
  projectParams?: Record<string, unknown>;
114
115
  generationParams?: Record<string, unknown>;
116
+ idempotencyKey?: string;
115
117
  downloadType?: string;
116
118
  pollInterval?: number;
117
119
  timeout?: number;
@@ -129,10 +131,11 @@ export declare class DiffioClient {
129
131
  contentType?: string;
130
132
  contentLength?: number;
131
133
  fileFormat?: string;
132
- model?: string;
134
+ model?: ModelKey;
133
135
  sampling?: Record<string, unknown>;
134
136
  projectParams?: Record<string, unknown>;
135
137
  generationParams?: Record<string, unknown>;
138
+ idempotencyKey?: string;
136
139
  requestOptions?: DiffioClient.RequestOptions;
137
140
  }): Promise<AudioIsolationResult>;
138
141
  private _downloadBinary;
package/dist/Client.js CHANGED
@@ -48,7 +48,6 @@ const API_PREFIX = "v1";
48
48
  const MODEL_ENDPOINTS = {
49
49
  "diffio-2": "diffio-2.0-generation",
50
50
  "diffio-2-flash": "diffio-2.0-flash-generation",
51
- "diffio-3": "diffio-3.0-generation",
52
51
  "diffio-3.4": "diffio-3.4-generation",
53
52
  "diffio-3.5": "diffio-3.5-generation"
54
53
  };
@@ -136,11 +135,11 @@ class DiffioClient {
136
135
  if (isStorageEmulatorUrl(uploadUrl)) {
137
136
  extraHeaders.Authorization = "Bearer owner";
138
137
  }
139
- const body = filePath ? await createFileReadStream(filePath) : data;
140
- await this._requestBinary(method, uploadUrl, body, requestOptions, extraHeaders, true);
138
+ const bodyFactory = filePath ? () => createFileReadStream(filePath) : () => data;
139
+ await this._requestBinary(method, uploadUrl, bodyFactory, requestOptions, extraHeaders, true);
141
140
  }
142
141
  async createGeneration(options) {
143
- const { apiProjectId, model = "diffio-2", sampling, params, requestOptions } = options;
142
+ const { apiProjectId, model = "diffio-2", sampling, params, idempotencyKey, requestOptions } = options;
144
143
  const endpoint = MODEL_ENDPOINTS[model];
145
144
  if (!endpoint) {
146
145
  throw new errors_1.DiffioApiError(`Unsupported model: ${model}`);
@@ -152,6 +151,9 @@ class DiffioClient {
152
151
  if (params) {
153
152
  payload.params = params;
154
153
  }
154
+ if (idempotencyKey != null) {
155
+ payload.idempotencyKey = idempotencyKey;
156
+ }
155
157
  const response = await this._requestJson("POST", endpoint, payload, requestOptions);
156
158
  return (0, serialization_1.parseCreateGenerationResponse)(response);
157
159
  }
@@ -318,6 +320,7 @@ class DiffioClient {
318
320
  sampling: options.sampling,
319
321
  projectParams: options.projectParams,
320
322
  generationParams: options.generationParams,
323
+ idempotencyKey: options.idempotencyKey,
321
324
  requestOptions: options.requestOptions
322
325
  });
323
326
  }
@@ -434,6 +437,7 @@ class DiffioClient {
434
437
  model: options.model,
435
438
  sampling: options.sampling,
436
439
  params: options.generationParams,
440
+ idempotencyKey: options.idempotencyKey,
437
441
  requestOptions: options.requestOptions
438
442
  });
439
443
  return (0, serialization_1.createAudioIsolationResult)(project, generation);
@@ -443,7 +447,7 @@ class DiffioClient {
443
447
  if (isStorageEmulatorUrl(downloadUrl)) {
444
448
  extraHeaders.Authorization = "Bearer owner";
445
449
  }
446
- const response = await this._requestBinary("GET", downloadUrl, undefined, requestOptions, extraHeaders, true);
450
+ const response = await this._requestBinary("GET", downloadUrl, () => undefined, requestOptions, extraHeaders, true);
447
451
  return response;
448
452
  }
449
453
  async _requestJson(method, path, payload, requestOptions) {
@@ -459,18 +463,26 @@ class DiffioClient {
459
463
  const response = await (0, retry_1.requestWithRetries)(makeRequest, { maxRetries, retryBackoff, retryStatusCodes });
460
464
  return parseJsonResponse(response);
461
465
  }
462
- async _requestBinary(method, urlOrPath, body, requestOptions, extraHeaders, isAbsoluteUrl = false) {
466
+ async _requestBinary(method, urlOrPath, bodyFactory, requestOptions, extraHeaders, isAbsoluteUrl = false) {
463
467
  const { url, headers, timeoutMs, maxRetries, retryBackoff, retryStatusCodes, fetchFn, abortSignal } = await this._buildRequest(method, urlOrPath, requestOptions, extraHeaders, isAbsoluteUrl);
464
- const requestInit = {
465
- method,
466
- headers,
467
- body: body,
468
- signal: abortSignal
468
+ const makeRequest = async () => {
469
+ const body = await bodyFactory();
470
+ const requestInit = {
471
+ method,
472
+ headers,
473
+ body: body,
474
+ signal: abortSignal
475
+ };
476
+ if (body && isNodeReadable(body)) {
477
+ requestInit.duplex = "half";
478
+ }
479
+ try {
480
+ return await fetchWithTimeout(fetchFn, url, requestInit, timeoutMs, abortSignal);
481
+ }
482
+ finally {
483
+ destroyNodeReadable(body);
484
+ }
469
485
  };
470
- if (body && isNodeReadable(body)) {
471
- requestInit.duplex = "half";
472
- }
473
- const makeRequest = () => fetchWithTimeout(fetchFn, url, requestInit, timeoutMs, abortSignal);
474
486
  const response = await (0, retry_1.requestWithRetries)(makeRequest, { maxRetries, retryBackoff, retryStatusCodes });
475
487
  if (method === "GET") {
476
488
  return parseBinaryResponse(response);
@@ -671,6 +683,14 @@ function isStorageEmulatorUrl(url) {
671
683
  function isNodeReadable(value) {
672
684
  return Boolean(value) && typeof value === "object" && typeof value.pipe === "function";
673
685
  }
686
+ function destroyNodeReadable(value) {
687
+ const destroy = isNodeReadable(value)
688
+ ? value.destroy
689
+ : undefined;
690
+ if (destroy) {
691
+ destroy.call(value);
692
+ }
693
+ }
674
694
  async function createFileReadStream(filePath) {
675
695
  const fs = await Promise.resolve().then(() => __importStar(require("node:fs")));
676
696
  const stream = fs.createReadStream(filePath);
@@ -1,14 +1,15 @@
1
1
  import type { DiffioClient } from "../../../../Client";
2
- import type { AudioIsolationResult, RestoreMetadata } from "../../../types";
2
+ import type { AudioIsolationResult, ModelKey, RestoreMetadata } from "../../../types";
3
3
  export interface AudioIsolationRestoreOptions {
4
4
  filePath: string;
5
5
  contentType?: string;
6
6
  contentLength?: number;
7
7
  fileFormat?: string;
8
- model?: string;
8
+ model?: ModelKey;
9
9
  sampling?: Record<string, unknown>;
10
10
  projectParams?: Record<string, unknown>;
11
11
  generationParams?: Record<string, unknown>;
12
+ idempotencyKey?: string;
12
13
  downloadType?: string;
13
14
  pollInterval?: number;
14
15
  timeout?: number;
@@ -25,10 +26,11 @@ export interface AudioIsolationIsolateOptions {
25
26
  contentType?: string;
26
27
  contentLength?: number;
27
28
  fileFormat?: string;
28
- model?: string;
29
+ model?: ModelKey;
29
30
  sampling?: Record<string, unknown>;
30
31
  projectParams?: Record<string, unknown>;
31
32
  generationParams?: Record<string, unknown>;
33
+ idempotencyKey?: string;
32
34
  requestOptions?: DiffioClient.RequestOptions;
33
35
  }
34
36
  export declare class AudioIsolationClient {
@@ -9,7 +9,7 @@ class AudioIsolationClient {
9
9
  return this.isolate(options);
10
10
  }
11
11
  async isolate(options) {
12
- const { filePath, contentType, contentLength, fileFormat, model, sampling, projectParams, generationParams, requestOptions } = options;
12
+ const { filePath, contentType, contentLength, fileFormat, model, sampling, projectParams, generationParams, idempotencyKey, requestOptions } = options;
13
13
  return this._parent.audioIsolationIsolate({
14
14
  filePath,
15
15
  contentType,
@@ -19,6 +19,7 @@ class AudioIsolationClient {
19
19
  sampling,
20
20
  projectParams,
21
21
  generationParams,
22
+ idempotencyKey,
22
23
  requestOptions
23
24
  });
24
25
  }
@@ -1,10 +1,11 @@
1
1
  import type { DiffioClient } from "../../../../Client";
2
- import type { CreateGenerationResponse, GenerationDownloadResponse, GenerationProgressResponse } from "../../../types";
2
+ import type { CreateGenerationResponse, GenerationDownloadResponse, GenerationProgressResponse, ModelKey } from "../../../types";
3
3
  export interface GenerationCreateOptions {
4
4
  apiProjectId: string;
5
- model?: string;
5
+ model?: ModelKey;
6
6
  sampling?: Record<string, unknown>;
7
7
  params?: Record<string, unknown>;
8
+ idempotencyKey?: string;
8
9
  requestOptions?: DiffioClient.RequestOptions;
9
10
  }
10
11
  export interface GenerationProgressOptions {
@@ -48,7 +48,10 @@ function parseCreateGenerationResponse(data) {
48
48
  generationId: data.generationId,
49
49
  apiProjectId: data.apiProjectId,
50
50
  modelKey: data.modelKey,
51
- status: data.status
51
+ status: data.status,
52
+ ...(data.idempotentReplay == null
53
+ ? {}
54
+ : { idempotentReplay: Boolean(data.idempotentReplay) })
52
55
  };
53
56
  }
54
57
  function parseProjectGenerationSummary(data) {
@@ -1,4 +1,4 @@
1
- export type ModelKey = "diffio-2" | "diffio-2-flash" | "diffio-3" | "diffio-3.4" | "diffio-3.5";
1
+ export type ModelKey = "diffio-2" | "diffio-2-flash" | "diffio-3.4" | "diffio-3.5";
2
2
  export type DownloadType = "audio" | "video" | "transcript";
3
3
  export type WebhookMode = "test" | "live";
4
4
  export type WebhookEventType = "generation.queued" | "generation.processing" | "generation.failed" | "generation.completed";
@@ -29,6 +29,7 @@ export interface CreateGenerationResponse {
29
29
  apiProjectId: string;
30
30
  modelKey: ModelKey | string;
31
31
  status: string;
32
+ idempotentReplay?: boolean;
32
33
  }
33
34
  export interface ProjectGenerationSummary {
34
35
  generationId: string;
package/dist/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const DIFFIO_SDK_VERSION = "0.1.42";
1
+ export declare const DIFFIO_SDK_VERSION = "0.1.43";
package/dist/version.js CHANGED
@@ -1,4 +1,4 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.DIFFIO_SDK_VERSION = void 0;
4
- exports.DIFFIO_SDK_VERSION = "0.1.42";
4
+ exports.DIFFIO_SDK_VERSION = "0.1.43";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "diffio",
3
- "version": "0.1.42",
3
+ "version": "0.1.43",
4
4
  "description": "Diffio API client for Node.js",
5
5
  "repository": {
6
6
  "type": "git",