diffio 0.1.0 → 0.1.2

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
@@ -17,17 +17,11 @@ npm install
17
17
 
18
18
  ## Configuration
19
19
 
20
- Set the API key with `DIFFIO_API_KEY`. You can also override the base URL with `DIFFIO_API_BASE_URL`.
20
+ Set the API key with `DIFFIO_API_KEY`. If you need to set the base URL explicitly, use the production endpoint with `DIFFIO_API_BASE_URL`.
21
21
 
22
22
  ```bash
23
23
  export DIFFIO_API_KEY="diffio_live_..."
24
- export DIFFIO_API_BASE_URL="https://us-central1-diffioai.cloudfunctions.net"
25
- ```
26
-
27
- For emulators, set the base URL to the Functions emulator host.
28
-
29
- ```bash
30
- export DIFFIO_API_BASE_URL="http://127.0.0.1:5001/diffioai/us-central1"
24
+ export DIFFIO_API_BASE_URL="https://us-central1-diffioai.cloudfunctions.net/v1"
31
25
  ```
32
26
 
33
27
  ## Request options
@@ -166,16 +160,6 @@ for (const generation of generations.generations) {
166
160
  }
167
161
  ```
168
162
 
169
- ## Webhooks portal access
170
-
171
- ```ts
172
- import { DiffioClient } from "diffio";
173
-
174
- const client = new DiffioClient({ apiKey: "diffio_live_..." });
175
- const portal = await client.webhooks.getPortalAccess({ mode: "test" });
176
- console.log(portal.portalUrl);
177
- ```
178
-
179
163
  ## Send a test webhook event
180
164
 
181
165
  ```ts
@@ -184,13 +168,46 @@ import { DiffioClient } from "diffio";
184
168
  const client = new DiffioClient({ apiKey: "diffio_live_..." });
185
169
  const event = await client.webhooks.sendTestEvent({
186
170
  eventType: "generation.completed",
187
- mode: "test",
171
+ mode: "live",
188
172
  samplePayload: { apiProjectId: "proj_123" }
189
173
  });
190
174
 
191
175
  console.log(event.svixMessageId);
192
176
  ```
193
177
 
178
+ ## Verify webhook signatures
179
+
180
+ Use the raw request body (not parsed JSON) plus the `svix-*` headers and your webhook signing secret.
181
+
182
+ ```ts
183
+ import express from "express";
184
+ import { DiffioClient } from "diffio";
185
+
186
+ const app = express();
187
+ const client = new DiffioClient({ apiKey: process.env.DIFFIO_API_KEY });
188
+
189
+ app.post("/webhooks/diffio", express.raw({ type: "application/json" }), (req, res) => {
190
+ const payload = req.body;
191
+ const headers = {
192
+ "svix-id": req.header("svix-id"),
193
+ "svix-timestamp": req.header("svix-timestamp"),
194
+ "svix-signature": req.header("svix-signature")
195
+ };
196
+
197
+ try {
198
+ const event = client.webhooks.verifySignature({
199
+ payload,
200
+ headers,
201
+ secret: process.env.DIFFIO_WEBHOOK_SECRET
202
+ });
203
+ console.log("Webhook received", event.eventType);
204
+ res.status(200).send("ok");
205
+ } catch (err) {
206
+ res.status(400).send("Invalid signature");
207
+ }
208
+ });
209
+ ```
210
+
194
211
  ## Runtime compatibility
195
212
 
196
213
  Use Node 18 or later so `fetch` is available without extra packages.
package/dist/Client.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { BaseClientOptions, BaseRequestOptions, NormalizedClientOptions } from "./BaseClient";
2
- import type { AudioIsolationResult, CreateGenerationResponse, CreateProjectResponse, GenerationDownloadResponse, GenerationProgressResponse, ListProjectGenerationsResponse, ListProjectsResponse, RestoreMetadata, WebhookPortalResponse, WebhookTestEventResponse } from "./api/types";
2
+ import type { AudioIsolationResult, CreateGenerationResponse, CreateProjectResponse, GenerationDownloadResponse, GenerationProgressResponse, ListProjectGenerationsResponse, ListProjectsResponse, RestoreMetadata, WebhookTestEventResponse } from "./api/types";
3
3
  import { AudioIsolationClient, GenerationsClient, ProjectsClient, WebhooksClient } from "./api/resources";
4
4
  export declare namespace DiffioClient {
5
5
  type Options = BaseClientOptions;
@@ -58,11 +58,6 @@ export declare class DiffioClient {
58
58
  downloadType?: string;
59
59
  requestOptions?: DiffioClient.RequestOptions;
60
60
  }): Promise<GenerationDownloadResponse>;
61
- getWebhooksPortalAccess(options: {
62
- mode: string;
63
- apiKeyId?: string;
64
- requestOptions?: DiffioClient.RequestOptions;
65
- }): Promise<WebhookPortalResponse>;
66
61
  sendWebhookTestEvent(options: {
67
62
  eventType: string;
68
63
  mode: string;
package/dist/Client.js CHANGED
@@ -207,18 +207,6 @@ class DiffioClient {
207
207
  const response = await this._requestJson("POST", "get_generation_download", payload, requestOptions);
208
208
  return (0, serialization_1.parseGenerationDownloadResponse)(response);
209
209
  }
210
- async getWebhooksPortalAccess(options) {
211
- const { mode, apiKeyId, requestOptions } = options;
212
- if (!WEBHOOK_MODES.includes(mode)) {
213
- throw new errors_1.DiffioApiError("mode must be test or live");
214
- }
215
- const payload = { mode };
216
- if (apiKeyId != null) {
217
- payload.apiKeyId = apiKeyId;
218
- }
219
- const response = await this._requestJson("POST", "webhooks/app_portal_access", payload, requestOptions);
220
- return (0, serialization_1.parseWebhookPortalResponse)(response);
221
- }
222
210
  async sendWebhookTestEvent(options) {
223
211
  const { eventType, mode, apiKeyId, samplePayload, requestOptions } = options;
224
212
  if (!WEBHOOK_EVENT_TYPES.includes(eventType)) {
@@ -1,10 +1,5 @@
1
1
  import type { DiffioClient } from "../../../../Client";
2
- import type { WebhookPortalResponse, WebhookTestEventResponse } from "../../../types";
3
- export interface WebhookPortalAccessOptions {
4
- mode: string;
5
- apiKeyId?: string;
6
- requestOptions?: DiffioClient.RequestOptions;
7
- }
2
+ import type { GenerationWebhookEvent, WebhookTestEventResponse } from "../../../types";
8
3
  export interface WebhookTestEventOptions {
9
4
  eventType: string;
10
5
  mode: string;
@@ -12,9 +7,15 @@ export interface WebhookTestEventOptions {
12
7
  samplePayload?: Record<string, unknown>;
13
8
  requestOptions?: DiffioClient.RequestOptions;
14
9
  }
10
+ export type WebhookHeaders = Record<string, string | string[] | undefined> | Headers;
11
+ export interface WebhookVerifyOptions {
12
+ payload: string | Uint8Array;
13
+ headers: WebhookHeaders;
14
+ secret: string;
15
+ }
15
16
  export declare class WebhooksClient {
16
17
  private _parent;
17
18
  constructor(parent: DiffioClient);
18
- getPortalAccess(options: WebhookPortalAccessOptions): Promise<WebhookPortalResponse>;
19
19
  sendTestEvent(options: WebhookTestEventOptions): Promise<WebhookTestEventResponse>;
20
+ verifySignature(options: WebhookVerifyOptions): GenerationWebhookEvent;
20
21
  }
@@ -1,15 +1,73 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.WebhooksClient = void 0;
4
+ const errors_1 = require("../../../../errors");
5
+ const serialization_1 = require("../../../serialization");
6
+ const svix_1 = require("svix");
4
7
  class WebhooksClient {
5
8
  constructor(parent) {
6
9
  this._parent = parent;
7
10
  }
8
- async getPortalAccess(options) {
9
- return this._parent.getWebhooksPortalAccess(options);
10
- }
11
11
  async sendTestEvent(options) {
12
12
  return this._parent.sendWebhookTestEvent(options);
13
13
  }
14
+ verifySignature(options) {
15
+ const { payload, headers, secret } = options;
16
+ if (!secret) {
17
+ throw new errors_1.DiffioApiError("secret is required");
18
+ }
19
+ const normalizedHeaders = normalizeSvixHeaders(headers);
20
+ const body = normalizePayload(payload);
21
+ const webhook = new svix_1.Webhook(secret);
22
+ try {
23
+ const event = webhook.verify(body, normalizedHeaders);
24
+ if (!event || typeof event !== "object") {
25
+ throw new errors_1.DiffioApiError("Webhook payload must be an object");
26
+ }
27
+ return (0, serialization_1.parseGenerationWebhookEvent)(event);
28
+ }
29
+ catch (error) {
30
+ if (error instanceof errors_1.DiffioApiError) {
31
+ throw error;
32
+ }
33
+ const message = error instanceof Error ? error.message : "Webhook signature verification failed";
34
+ throw new errors_1.DiffioApiError(message);
35
+ }
36
+ }
14
37
  }
15
38
  exports.WebhooksClient = WebhooksClient;
39
+ function normalizePayload(payload) {
40
+ if (typeof payload === "string") {
41
+ return payload;
42
+ }
43
+ if (typeof Buffer !== "undefined") {
44
+ return Buffer.from(payload).toString("utf8");
45
+ }
46
+ return new TextDecoder().decode(payload);
47
+ }
48
+ function normalizeSvixHeaders(headers) {
49
+ const normalized = {};
50
+ if (typeof Headers !== "undefined" && headers instanceof Headers) {
51
+ for (const [key, value] of headers.entries()) {
52
+ normalized[key.toLowerCase()] = value;
53
+ }
54
+ }
55
+ else {
56
+ for (const [key, value] of Object.entries(headers)) {
57
+ if (value == null) {
58
+ continue;
59
+ }
60
+ normalized[key.toLowerCase()] = Array.isArray(value) ? value.join(",") : String(value);
61
+ }
62
+ }
63
+ const required = ["svix-id", "svix-timestamp", "svix-signature"];
64
+ const missing = required.filter((header) => !normalized[header]);
65
+ if (missing.length > 0) {
66
+ throw new errors_1.DiffioApiError(`Missing webhook headers: ${missing.join(", ")}`);
67
+ }
68
+ return {
69
+ "svix-id": normalized["svix-id"],
70
+ "svix-timestamp": normalized["svix-timestamp"],
71
+ "svix-signature": normalized["svix-signature"]
72
+ };
73
+ }
@@ -1,4 +1,4 @@
1
- import type { AudioIsolationResult, CreateGenerationResponse, CreateProjectResponse, GenerationWebhookEvent, GenerationDownloadResponse, GenerationProgressResponse, GenerationProgressStage, ListProjectGenerationsResponse, ListProjectsResponse, ProjectGenerationSummary, ProjectSummary, WebhookPortalResponse, WebhookTestEventResponse } from "./types";
1
+ import type { AudioIsolationResult, CreateGenerationResponse, CreateProjectResponse, GenerationWebhookEvent, GenerationDownloadResponse, GenerationProgressResponse, GenerationProgressStage, ListProjectGenerationsResponse, ListProjectsResponse, ProjectGenerationSummary, ProjectSummary, WebhookTestEventResponse } from "./types";
2
2
  export declare function parseCreateProjectResponse(data: any): CreateProjectResponse;
3
3
  export declare function parseProjectSummary(data: any): ProjectSummary;
4
4
  export declare function parseListProjectsResponse(data: any): ListProjectsResponse;
@@ -8,7 +8,6 @@ export declare function parseListProjectGenerationsResponse(data: any): ListProj
8
8
  export declare function parseGenerationProgressStage(data: any): GenerationProgressStage;
9
9
  export declare function parseGenerationProgressResponse(data: any): GenerationProgressResponse;
10
10
  export declare function parseGenerationDownloadResponse(data: any): GenerationDownloadResponse;
11
- export declare function parseWebhookPortalResponse(data: any): WebhookPortalResponse;
12
11
  export declare function parseWebhookTestEventResponse(data: any): WebhookTestEventResponse;
13
12
  export declare function parseGenerationWebhookEvent(data: any): GenerationWebhookEvent;
14
13
  export declare function createAudioIsolationResult(project: CreateProjectResponse, generation: CreateGenerationResponse): AudioIsolationResult;
@@ -9,7 +9,6 @@ exports.parseListProjectGenerationsResponse = parseListProjectGenerationsRespons
9
9
  exports.parseGenerationProgressStage = parseGenerationProgressStage;
10
10
  exports.parseGenerationProgressResponse = parseGenerationProgressResponse;
11
11
  exports.parseGenerationDownloadResponse = parseGenerationDownloadResponse;
12
- exports.parseWebhookPortalResponse = parseWebhookPortalResponse;
13
12
  exports.parseWebhookTestEventResponse = parseWebhookTestEventResponse;
14
13
  exports.parseGenerationWebhookEvent = parseGenerationWebhookEvent;
15
14
  exports.createAudioIsolationResult = createAudioIsolationResult;
@@ -102,13 +101,6 @@ function parseGenerationDownloadResponse(data) {
102
101
  mimeType: data.mimeType
103
102
  };
104
103
  }
105
- function parseWebhookPortalResponse(data) {
106
- return {
107
- portalUrl: data.portalUrl,
108
- mode: data.mode ?? null,
109
- apiKeyId: data.apiKeyId ?? null
110
- };
111
- }
112
104
  function parseWebhookTestEventResponse(data) {
113
105
  return {
114
106
  svixMessageId: data.svixMessageId,
@@ -76,11 +76,6 @@ export interface AudioIsolationResult {
76
76
  project: CreateProjectResponse;
77
77
  generation: CreateGenerationResponse;
78
78
  }
79
- export interface WebhookPortalResponse {
80
- portalUrl: string;
81
- mode?: WebhookMode | string | null;
82
- apiKeyId?: string | null;
83
- }
84
79
  export interface WebhookTestEventResponse {
85
80
  svixMessageId: string;
86
81
  eventId: string;
package/dist/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const DIFFIO_SDK_VERSION = "0.1.0";
1
+ export declare const DIFFIO_SDK_VERSION = "0.1.2";
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.0";
4
+ exports.DIFFIO_SDK_VERSION = "0.1.2";
package/package.json CHANGED
@@ -1,7 +1,11 @@
1
1
  {
2
2
  "name": "diffio",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Diffio API client for Node.js",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "https://github.com/Diffio-AI/diffio-js"
8
+ },
5
9
  "license": "MIT",
6
10
  "main": "./dist/index.js",
7
11
  "types": "./dist/index.d.ts",
@@ -18,7 +22,8 @@
18
22
  "test:wire": "jest --selectProjects wire"
19
23
  },
20
24
  "dependencies": {
21
- "mime-types": "^2.1.35"
25
+ "mime-types": "^2.1.35",
26
+ "svix": "^1.84.1"
22
27
  },
23
28
  "devDependencies": {
24
29
  "@types/jest": "^29.5.14",