Skip to content

Commit 8fbef7f

Browse files
committed
Expand API SDK surface
1 parent 4bd7010 commit 8fbef7f

13 files changed

Lines changed: 528 additions & 15 deletions

File tree

README.md

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ const project = await client.createProject({
5858

5959
const generation = await client.createGeneration({
6060
apiProjectId: project.apiProjectId,
61-
model: "diffio-2",
61+
model: "diffio-3.5",
6262
sampling: { steps: 12, guidance: 1.5 }
6363
});
6464

@@ -73,7 +73,7 @@ import { DiffioClient } from "diffio";
7373
const client = new DiffioClient({ apiKey: "diffio_live_..." });
7474
const result = await client.audioIsolation.isolate({
7575
filePath: "sample.wav",
76-
model: "diffio-2",
76+
model: "diffio-3.5",
7777
sampling: { steps: 12, guidance: 1.5 }
7878
});
7979

@@ -91,7 +91,7 @@ import { DiffioClient } from "diffio";
9191
const client = new DiffioClient({ apiKey: "diffio_live_..." });
9292
const [audioBytes, info] = await client.restoreAudio({
9393
filePath: "sample.wav",
94-
model: "diffio-2",
94+
model: "diffio-3.5",
9595
sampling: { steps: 12, guidance: 1.5 },
9696
onProgress: (progress) => console.log(progress.status)
9797
});
@@ -134,6 +134,35 @@ const download = await client.generations.getDownload({
134134
console.log(download.downloadUrl);
135135
```
136136

137+
Set `downloadType` to `"transcript"` to fetch the transcript JSON artifact when the generation has one.
138+
139+
```ts
140+
const transcript = await client.generations.getDownload({
141+
generationId: "gen_123",
142+
apiProjectId: "proj_123",
143+
downloadType: "transcript"
144+
});
145+
```
146+
147+
## Account, keys, usage, and webhook configuration
148+
149+
Agent keys can manage account settings, scoped keys, usage, and webhook endpoints.
150+
151+
```ts
152+
const settings = await client.account.getSettings();
153+
const key = await client.apiKeys.create({
154+
label: "Backend worker",
155+
scopes: ["projects:read", "projects:write", "generations:read", "generations:write", "artifacts:read"]
156+
});
157+
const usage = await client.usage.summary({ apiKeyId: key.keyId });
158+
const webhook = await client.webhooks.configure({
159+
mode: "live",
160+
url: "https://example.com/webhooks/diffio",
161+
eventTypes: ["generation.completed", "generation.failed"],
162+
apiKeyId: key.keyId
163+
});
164+
```
165+
137166
## List projects
138167

139168
```ts

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "diffio",
3-
"version": "0.1.3",
3+
"version": "0.1.7",
44
"description": "Diffio API client for Node.js",
55
"repository": {
66
"type": "git",

src/Client.ts

Lines changed: 143 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,23 @@ import { requestWithRetries } from "./core/retry";
77
import { DiffioApiError, DiffioTimeoutError } from "./errors";
88
import {
99
createAudioIsolationResult,
10+
parseAccountSettingsResponse,
11+
parseApiKeyResponse,
12+
parseApiKeysListResponse,
1013
parseCreateGenerationResponse,
1114
parseCreateProjectResponse,
1215
parseGenerationDownloadResponse,
1316
parseGenerationProgressResponse,
1417
parseListProjectGenerationsResponse,
1518
parseListProjectsResponse,
19+
parseUsageSummaryResponse,
20+
parseWebhookConfigureResponse,
1621
parseWebhookTestEventResponse
1722
} from "./api/serialization";
1823
import type {
24+
AccountSettingsResponse,
25+
ApiKeyResponse,
26+
ApiKeysListResponse,
1927
AudioIsolationResult,
2028
CreateGenerationResponse,
2129
CreateProjectResponse,
@@ -24,17 +32,29 @@ import type {
2432
ListProjectGenerationsResponse,
2533
ListProjectsResponse,
2634
RestoreMetadata,
35+
UsageSummaryResponse,
36+
WebhookConfigureResponse,
2737
WebhookTestEventResponse
2838
} from "./api/types";
29-
import { AudioIsolationClient, GenerationsClient, ProjectsClient, WebhooksClient } from "./api/resources";
39+
import {
40+
AccountClient,
41+
ApiKeysClient,
42+
AudioIsolationClient,
43+
GenerationsClient,
44+
ProjectsClient,
45+
UsageClient,
46+
WebhooksClient
47+
} from "./api/resources";
3048
import { lookup as lookupMimeType } from "mime-types";
3149

3250
const DEFAULT_BASE_URL = "https://api.diffio.ai";
3351
const API_PREFIX = "v1";
3452
const MODEL_ENDPOINTS: Record<string, string> = {
3553
"diffio-2": "diffio-2.0-generation",
3654
"diffio-2-flash": "diffio-2.0-flash-generation",
37-
"diffio-3": "diffio-3.0-generation"
55+
"diffio-3": "diffio-3.0-generation",
56+
"diffio-3.4": "diffio-3.4-generation",
57+
"diffio-3.5": "diffio-3.5-generation"
3858
};
3959
const DEFAULT_RETRY_STATUS_CODES = [408, 429, 500, 502, 503, 504];
4060
const DEFAULT_RETRY_BACKOFF = 0.5;
@@ -58,6 +78,9 @@ export class DiffioClient {
5878
public readonly audioIsolation: AudioIsolationClient;
5979
public readonly generations: GenerationsClient;
6080
public readonly projects: ProjectsClient;
81+
public readonly account: AccountClient;
82+
public readonly apiKeys: ApiKeysClient;
83+
public readonly usage: UsageClient;
6184
public readonly webhooks: WebhooksClient;
6285

6386
constructor(options: DiffioClient.Options = {}) {
@@ -71,6 +94,9 @@ export class DiffioClient {
7194
this.audioIsolation = new AudioIsolationClient(this);
7295
this.generations = new GenerationsClient(this);
7396
this.projects = new ProjectsClient(this);
97+
this.account = new AccountClient(this);
98+
this.apiKeys = new ApiKeysClient(this);
99+
this.usage = new UsageClient(this);
74100
this.webhooks = new WebhooksClient(this);
75101
}
76102

@@ -279,15 +305,122 @@ export class DiffioClient {
279305
const { generationId, apiProjectId, downloadType, requestOptions } = options;
280306
const payload: Record<string, unknown> = { generationId, apiProjectId };
281307
if (downloadType != null) {
282-
if (downloadType !== "audio" && downloadType !== "video") {
283-
throw new DiffioApiError("downloadType must be audio or video");
308+
if (downloadType !== "audio" && downloadType !== "video" && downloadType !== "transcript") {
309+
throw new DiffioApiError("downloadType must be audio, video, or transcript");
284310
}
285311
payload.downloadType = downloadType;
286312
}
287313
const response = await this._requestJson("POST", "get_generation_download", payload, requestOptions);
288314
return parseGenerationDownloadResponse(response);
289315
}
290316

317+
async getAccountSettings(options: {
318+
requestOptions?: DiffioClient.RequestOptions;
319+
} = {}): Promise<AccountSettingsResponse> {
320+
const response = await this._requestJson("POST", "account/settings/get", {}, options.requestOptions);
321+
return parseAccountSettingsResponse(response);
322+
}
323+
324+
async updateAccountSettings(options: {
325+
billingPolicy: Record<string, unknown>;
326+
requestOptions?: DiffioClient.RequestOptions;
327+
}): Promise<AccountSettingsResponse> {
328+
const { billingPolicy, requestOptions } = options;
329+
if (!billingPolicy || typeof billingPolicy !== "object" || Array.isArray(billingPolicy)) {
330+
throw new DiffioApiError("billingPolicy must be an object");
331+
}
332+
const response = await this._requestJson("POST", "account/settings/update", { billingPolicy }, requestOptions);
333+
return parseAccountSettingsResponse(response);
334+
}
335+
336+
async createApiKey(options: {
337+
label: string;
338+
scopes: string[];
339+
resourceBounds?: Record<string, unknown>;
340+
requestOptions?: DiffioClient.RequestOptions;
341+
}): Promise<ApiKeyResponse> {
342+
const { label, scopes, resourceBounds, requestOptions } = options;
343+
if (!label) {
344+
throw new DiffioApiError("label is required");
345+
}
346+
if (!Array.isArray(scopes)) {
347+
throw new DiffioApiError("scopes must be an array");
348+
}
349+
const response = await this._requestJson(
350+
"POST",
351+
"api_keys/create",
352+
{ label, scopes, resourceBounds: resourceBounds ?? {} },
353+
requestOptions
354+
);
355+
return parseApiKeyResponse(response);
356+
}
357+
358+
async listApiKeys(options: { requestOptions?: DiffioClient.RequestOptions } = {}): Promise<ApiKeysListResponse> {
359+
const response = await this._requestJson("POST", "api_keys/list", {}, options.requestOptions);
360+
return parseApiKeysListResponse(response);
361+
}
362+
363+
async rotateApiKey(options: {
364+
keyId: string;
365+
requestOptions?: DiffioClient.RequestOptions;
366+
}): Promise<ApiKeyResponse> {
367+
const { keyId, requestOptions } = options;
368+
if (!keyId) {
369+
throw new DiffioApiError("keyId is required");
370+
}
371+
const response = await this._requestJson("POST", "api_keys/rotate", { keyId }, requestOptions);
372+
return parseApiKeyResponse(response);
373+
}
374+
375+
async revokeApiKey(options: {
376+
keyId: string;
377+
requestOptions?: DiffioClient.RequestOptions;
378+
}): Promise<ApiKeyResponse> {
379+
const { keyId, requestOptions } = options;
380+
if (!keyId) {
381+
throw new DiffioApiError("keyId is required");
382+
}
383+
const response = await this._requestJson("POST", "api_keys/revoke", { keyId }, requestOptions);
384+
return parseApiKeyResponse(response);
385+
}
386+
387+
async getUsageSummary(options: {
388+
apiKeyId?: string;
389+
requestOptions?: DiffioClient.RequestOptions;
390+
} = {}): Promise<UsageSummaryResponse> {
391+
const payload: Record<string, unknown> = {};
392+
if (options.apiKeyId != null) {
393+
payload.apiKeyId = options.apiKeyId;
394+
}
395+
const response = await this._requestJson("POST", "usage/summary", payload, options.requestOptions);
396+
return parseUsageSummaryResponse(response);
397+
}
398+
399+
async configureWebhook(options: {
400+
mode: string;
401+
url: string;
402+
eventTypes: string[];
403+
apiKeyId?: string;
404+
requestOptions?: DiffioClient.RequestOptions;
405+
}): Promise<WebhookConfigureResponse> {
406+
const { mode, url, eventTypes, apiKeyId, requestOptions } = options;
407+
if (!WEBHOOK_MODES.includes(mode)) {
408+
throw new DiffioApiError("mode must be test or live");
409+
}
410+
if (!url) {
411+
throw new DiffioApiError("url is required");
412+
}
413+
if (!Array.isArray(eventTypes) || eventTypes.length === 0) {
414+
throw new DiffioApiError("eventTypes must be a non-empty array");
415+
}
416+
const payload: Record<string, unknown> = { mode, url, eventTypes };
417+
if (apiKeyId != null) {
418+
payload.apiKeyId = apiKeyId;
419+
}
420+
const response = await this._requestJson("POST", "webhooks/configure", payload, requestOptions);
421+
return parseWebhookConfigureResponse(response);
422+
}
423+
291424
async sendWebhookTestEvent(options: {
292425
eventType: string;
293426
mode: string;
@@ -817,7 +950,12 @@ function isNodeReadable(value: unknown): value is NodeJS.ReadableStream {
817950

818951
async function createFileReadStream(filePath: string): Promise<NodeJS.ReadableStream> {
819952
const fs = await import("node:fs");
820-
return fs.createReadStream(filePath);
953+
const stream = fs.createReadStream(filePath);
954+
await new Promise<void>((resolve, reject) => {
955+
stream.once("open", () => resolve());
956+
stream.once("error", reject);
957+
});
958+
return stream;
821959
}
822960

823961
function getFileSize(filePath: string): number {
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import type { DiffioClient } from "../../../../Client";
2+
import type { AccountSettingsResponse } from "../../../types";
3+
4+
export interface AccountGetSettingsOptions {
5+
requestOptions?: DiffioClient.RequestOptions;
6+
}
7+
8+
export interface AccountUpdateSettingsOptions {
9+
billingPolicy: Record<string, unknown>;
10+
requestOptions?: DiffioClient.RequestOptions;
11+
}
12+
13+
export class AccountClient {
14+
private _parent: DiffioClient;
15+
16+
constructor(parent: DiffioClient) {
17+
this._parent = parent;
18+
}
19+
20+
async getSettings(options: AccountGetSettingsOptions = {}): Promise<AccountSettingsResponse> {
21+
return this._parent.getAccountSettings(options);
22+
}
23+
24+
async updateSettings(options: AccountUpdateSettingsOptions): Promise<AccountSettingsResponse> {
25+
return this._parent.updateAccountSettings(options);
26+
}
27+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import type { DiffioClient } from "../../../../Client";
2+
import type { ApiKeyResponse, ApiKeysListResponse } from "../../../types";
3+
4+
export interface ApiKeysCreateOptions {
5+
label: string;
6+
scopes: string[];
7+
resourceBounds?: Record<string, unknown>;
8+
requestOptions?: DiffioClient.RequestOptions;
9+
}
10+
11+
export interface ApiKeysListOptions {
12+
requestOptions?: DiffioClient.RequestOptions;
13+
}
14+
15+
export interface ApiKeysRotateOptions {
16+
keyId: string;
17+
requestOptions?: DiffioClient.RequestOptions;
18+
}
19+
20+
export interface ApiKeysRevokeOptions {
21+
keyId: string;
22+
requestOptions?: DiffioClient.RequestOptions;
23+
}
24+
25+
export class ApiKeysClient {
26+
private _parent: DiffioClient;
27+
28+
constructor(parent: DiffioClient) {
29+
this._parent = parent;
30+
}
31+
32+
async create(options: ApiKeysCreateOptions): Promise<ApiKeyResponse> {
33+
return this._parent.createApiKey(options);
34+
}
35+
36+
async list(options: ApiKeysListOptions = {}): Promise<ApiKeysListResponse> {
37+
return this._parent.listApiKeys(options);
38+
}
39+
40+
async rotate(options: ApiKeysRotateOptions): Promise<ApiKeyResponse> {
41+
return this._parent.rotateApiKey(options);
42+
}
43+
44+
async revoke(options: ApiKeysRevokeOptions): Promise<ApiKeyResponse> {
45+
return this._parent.revokeApiKey(options);
46+
}
47+
}

src/api/resources/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1+
export { AccountClient } from "./account/client/Client";
2+
export { ApiKeysClient } from "./apiKeys/client/Client";
13
export { AudioIsolationClient } from "./audioIsolation/client/Client";
24
export { GenerationsClient } from "./generations/client/Client";
35
export { ProjectsClient } from "./projects/client/Client";
6+
export { UsageClient } from "./usage/client/Client";
47
export { WebhooksClient } from "./webhooks/client/Client";

0 commit comments

Comments
 (0)