@rymi/node 1.0.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/LICENSE +21 -0
- package/README.md +40 -0
- package/dist/index.d.mts +763 -0
- package/dist/index.d.ts +763 -0
- package/dist/index.js +596 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +546 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +58 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,596 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
|
|
21
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
22
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
23
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
24
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
25
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
26
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
27
|
+
mod
|
|
28
|
+
));
|
|
29
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
30
|
+
|
|
31
|
+
// src/index.ts
|
|
32
|
+
var index_exports = {};
|
|
33
|
+
__export(index_exports, {
|
|
34
|
+
AgentsResource: () => AgentsResource,
|
|
35
|
+
BillingResource: () => BillingResource,
|
|
36
|
+
CallsResource: () => CallsResource,
|
|
37
|
+
DncResource: () => DncResource,
|
|
38
|
+
KeysResource: () => KeysResource,
|
|
39
|
+
NumbersResource: () => NumbersResource,
|
|
40
|
+
Rymi: () => Rymi,
|
|
41
|
+
RymiClient: () => RymiClient,
|
|
42
|
+
RymiError: () => RymiError,
|
|
43
|
+
TelephonyResource: () => TelephonyResource,
|
|
44
|
+
TemplatesResource: () => TemplatesResource,
|
|
45
|
+
WebhooksResource: () => WebhooksResource,
|
|
46
|
+
default: () => index_default
|
|
47
|
+
});
|
|
48
|
+
module.exports = __toCommonJS(index_exports);
|
|
49
|
+
|
|
50
|
+
// src/client.ts
|
|
51
|
+
var RymiError = class extends Error {
|
|
52
|
+
status;
|
|
53
|
+
code;
|
|
54
|
+
constructor(message, status, code) {
|
|
55
|
+
super(message);
|
|
56
|
+
this.name = "RymiError";
|
|
57
|
+
this.status = status;
|
|
58
|
+
this.code = code;
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
var RymiClient = class {
|
|
62
|
+
apiKey;
|
|
63
|
+
baseURL;
|
|
64
|
+
constructor(options) {
|
|
65
|
+
const key = options?.apiKey || (typeof process !== "undefined" ? process.env.RYMI_API_KEY : void 0);
|
|
66
|
+
if (!key) {
|
|
67
|
+
throw new Error("The Rymi API Key must be set either by passing `apiKey` to the client or setting the `RYMI_API_KEY` environment variable.");
|
|
68
|
+
}
|
|
69
|
+
this.apiKey = key;
|
|
70
|
+
this.baseURL = options?.baseURL || "https://api.rymi.live/v1";
|
|
71
|
+
if (this.baseURL.endsWith("/")) {
|
|
72
|
+
this.baseURL = this.baseURL.slice(0, -1);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
async request(method, path, body) {
|
|
76
|
+
const url = `${this.baseURL}${path.startsWith("/") ? path : `/${path}`}`;
|
|
77
|
+
const headers = {
|
|
78
|
+
"Authorization": `Bearer ${this.apiKey}`,
|
|
79
|
+
"Accept": "application/json",
|
|
80
|
+
"User-Agent": "rymi-node/1.0.0"
|
|
81
|
+
};
|
|
82
|
+
const init = {
|
|
83
|
+
method,
|
|
84
|
+
headers
|
|
85
|
+
};
|
|
86
|
+
if (body) {
|
|
87
|
+
headers["Content-Type"] = "application/json";
|
|
88
|
+
init.body = JSON.stringify(body);
|
|
89
|
+
}
|
|
90
|
+
try {
|
|
91
|
+
const response = await fetch(url, init);
|
|
92
|
+
const isJson = response.headers.get("content-type")?.includes("application/json");
|
|
93
|
+
const data = isJson ? await response.json() : await response.text();
|
|
94
|
+
if (!response.ok) {
|
|
95
|
+
const message = data && typeof data === "object" && "error" in data ? data.error : typeof data === "string" ? data : response.statusText;
|
|
96
|
+
throw new RymiError(message, response.status, data && typeof data === "object" && "code" in data ? data.code : void 0);
|
|
97
|
+
}
|
|
98
|
+
return data;
|
|
99
|
+
} catch (error) {
|
|
100
|
+
if (error instanceof RymiError) {
|
|
101
|
+
throw error;
|
|
102
|
+
}
|
|
103
|
+
throw new RymiError(`Network Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
get(path) {
|
|
107
|
+
return this.request("GET", path);
|
|
108
|
+
}
|
|
109
|
+
post(path, body) {
|
|
110
|
+
return this.request("POST", path, body);
|
|
111
|
+
}
|
|
112
|
+
put(path, body) {
|
|
113
|
+
return this.request("PUT", path, body);
|
|
114
|
+
}
|
|
115
|
+
patch(path, body) {
|
|
116
|
+
return this.request("PATCH", path, body);
|
|
117
|
+
}
|
|
118
|
+
delete(path) {
|
|
119
|
+
return this.request("DELETE", path);
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
// src/resources/agents.ts
|
|
124
|
+
function normalizeAgentPayload(data) {
|
|
125
|
+
const { prompt, ...rest } = data;
|
|
126
|
+
return {
|
|
127
|
+
...rest,
|
|
128
|
+
...!rest.system_prompt && prompt ? { system_prompt: prompt } : {}
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
var AgentsResource = class {
|
|
132
|
+
constructor(client) {
|
|
133
|
+
this.client = client;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Retrieve a list of all your AI Agents.
|
|
137
|
+
*/
|
|
138
|
+
async list(params = {}) {
|
|
139
|
+
const searchParams = new URLSearchParams();
|
|
140
|
+
if (params.limit !== void 0) searchParams.set("limit", String(params.limit));
|
|
141
|
+
if (params.offset !== void 0) searchParams.set("offset", String(params.offset));
|
|
142
|
+
const query = searchParams.toString();
|
|
143
|
+
return this.client.get(`/agents${query ? `?${query}` : ""}`);
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Retrieve a single AI Agent by its unique ID.
|
|
147
|
+
*/
|
|
148
|
+
async retrieve(agentId) {
|
|
149
|
+
return this.client.get(`/agents/${agentId}`);
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Create a new AI Agent with a complete system prompt and voice settings.
|
|
153
|
+
*/
|
|
154
|
+
async create(data) {
|
|
155
|
+
return this.client.post("/agents", normalizeAgentPayload(data));
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Update an existing AI Agent's persona or configuration.
|
|
159
|
+
*/
|
|
160
|
+
async update(agentId, data) {
|
|
161
|
+
return this.client.put(`/agents/${agentId}`, normalizeAgentPayload(data));
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Delete an AI Agent permanently.
|
|
165
|
+
*/
|
|
166
|
+
async delete(agentId) {
|
|
167
|
+
return this.client.delete(`/agents/${agentId}`);
|
|
168
|
+
}
|
|
169
|
+
async llmOptions() {
|
|
170
|
+
return this.client.get("/agents/llm-options");
|
|
171
|
+
}
|
|
172
|
+
async generate(data) {
|
|
173
|
+
return this.client.post("/agents/generate", data);
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* List calls made with a specific agent.
|
|
177
|
+
*/
|
|
178
|
+
async listCalls(agentId, params = {}) {
|
|
179
|
+
const searchParams = new URLSearchParams();
|
|
180
|
+
if (params.limit !== void 0) searchParams.set("limit", String(params.limit));
|
|
181
|
+
if (params.offset !== void 0) searchParams.set("offset", String(params.offset));
|
|
182
|
+
if (params.status) searchParams.set("status", params.status);
|
|
183
|
+
const query = searchParams.toString();
|
|
184
|
+
return this.client.get(`/agents/${agentId}/calls${query ? `?${query}` : ""}`);
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Duplicate an existing agent. The clone gets " (Copy)" appended to its name.
|
|
188
|
+
*/
|
|
189
|
+
async clone(agentId) {
|
|
190
|
+
return this.client.post(`/agents/${agentId}/clone`, {});
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Validate an agent's configuration before publishing.
|
|
194
|
+
* Pass agent_id to merge with an existing persisted agent, or supply fields directly.
|
|
195
|
+
*/
|
|
196
|
+
async validatePublish(params) {
|
|
197
|
+
return this.client.post("/agents/validate-publish", params);
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Validate and apply a flat-diff change-set against the AgentConfig field registry.
|
|
201
|
+
* Does NOT persist — callers must follow up with update().
|
|
202
|
+
*/
|
|
203
|
+
async applyChanges(params) {
|
|
204
|
+
return this.client.post("/agents/apply-changes", params);
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Use AI with Google Search grounding to generate a company description from a website URL.
|
|
208
|
+
*/
|
|
209
|
+
async enrichCompany(params) {
|
|
210
|
+
return this.client.post("/agents/enrich-company", params);
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Preview the resolved per-language model stack (STT/LLM/TTS), blockers,
|
|
214
|
+
* warnings, model diffs, and any required role upgrades for a set of
|
|
215
|
+
* supported languages — without persisting anything. Note: the concierge
|
|
216
|
+
* (realtime) role is not supported by this endpoint.
|
|
217
|
+
*/
|
|
218
|
+
async previewStack(params) {
|
|
219
|
+
return this.client.post("/agents/stack-preview", params);
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* List the knowledge sources (RAG context) attached to an agent.
|
|
223
|
+
*/
|
|
224
|
+
async listKnowledgeSources(agentId) {
|
|
225
|
+
return this.client.get(`/agents/${agentId}/knowledge-sources`);
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Add a knowledge source to an agent from raw text or a URL.
|
|
229
|
+
*/
|
|
230
|
+
async addKnowledgeSource(agentId, data) {
|
|
231
|
+
return this.client.post(`/agents/${agentId}/knowledge-sources`, data);
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Delete a knowledge source from an agent.
|
|
235
|
+
*/
|
|
236
|
+
async deleteKnowledgeSource(agentId, sourceId) {
|
|
237
|
+
return this.client.delete(`/agents/${agentId}/knowledge-sources/${sourceId}`);
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* List the recorded configuration changes for an agent (most recent first).
|
|
241
|
+
* Optionally pass an ISO timestamp to only return changes since then.
|
|
242
|
+
*/
|
|
243
|
+
async listChanges(agentId, params = {}) {
|
|
244
|
+
const query = params.since ? `?since=${encodeURIComponent(params.since)}` : "";
|
|
245
|
+
return this.client.get(`/agents/${agentId}/changes${query}`);
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Undo a single recorded configuration change, reverting that field to its
|
|
249
|
+
* previous value. Returns the resulting agent snapshot.
|
|
250
|
+
*/
|
|
251
|
+
async undoChange(agentId, changeId) {
|
|
252
|
+
return this.client.post(`/agents/${agentId}/changes/${changeId}/undo`, {});
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* Run the evaluation suite for an agent. mode="synthetic" (default) uses
|
|
256
|
+
* the offline scorer; mode="live" runs the model-driven runner.
|
|
257
|
+
*/
|
|
258
|
+
async runEvals(agentId, params = {}) {
|
|
259
|
+
const query = params.mode ? `?mode=${params.mode}` : "";
|
|
260
|
+
return this.client.post(`/agents/${agentId}/evals/run${query}`, {});
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* List previous evaluation runs for an agent.
|
|
264
|
+
*/
|
|
265
|
+
async listEvalRuns(agentId) {
|
|
266
|
+
return this.client.get(`/agents/${agentId}/evals/runs`);
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Retrieve a single evaluation run, including per-scenario scores.
|
|
270
|
+
*/
|
|
271
|
+
async getEvalRun(agentId, runId) {
|
|
272
|
+
return this.client.get(`/agents/${agentId}/evals/runs/${runId}`);
|
|
273
|
+
}
|
|
274
|
+
};
|
|
275
|
+
|
|
276
|
+
// src/resources/calls.ts
|
|
277
|
+
function buildQuery(params) {
|
|
278
|
+
const searchParams = new URLSearchParams();
|
|
279
|
+
for (const [key, value] of Object.entries(params)) {
|
|
280
|
+
if (value !== void 0 && value !== null) {
|
|
281
|
+
searchParams.set(key, String(value));
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
const query = searchParams.toString();
|
|
285
|
+
return query ? `?${query}` : "";
|
|
286
|
+
}
|
|
287
|
+
var CallsResource = class {
|
|
288
|
+
constructor(client) {
|
|
289
|
+
this.client = client;
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* Retrieve a list of all previous and active calls.
|
|
293
|
+
*/
|
|
294
|
+
async list(params = {}) {
|
|
295
|
+
return this.client.get(`/calls${buildQuery(params)}`);
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
298
|
+
* Retrieve calls currently in progress.
|
|
299
|
+
*/
|
|
300
|
+
async active(params = {}) {
|
|
301
|
+
return this.client.get(`/calls/active${buildQuery(params)}`);
|
|
302
|
+
}
|
|
303
|
+
/**
|
|
304
|
+
* Retrieve details, transcripts, and analysis of a single call by its unique ID.
|
|
305
|
+
*/
|
|
306
|
+
async retrieve(callId) {
|
|
307
|
+
return this.client.get(`/calls/${callId}`);
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* Dispatch an outbound phone call securely using your configured carrier.
|
|
311
|
+
*/
|
|
312
|
+
async create(data) {
|
|
313
|
+
return this.client.post("/calls", data);
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* Queue up to 500 outbound PSTN recipients in one request.
|
|
317
|
+
*/
|
|
318
|
+
async batch(data) {
|
|
319
|
+
return this.client.post("/calls/batch", data);
|
|
320
|
+
}
|
|
321
|
+
async summary(callId) {
|
|
322
|
+
return this.client.get(`/calls/${callId}/summary`);
|
|
323
|
+
}
|
|
324
|
+
async transcript(callId) {
|
|
325
|
+
return this.client.get(`/calls/${callId}/transcript`);
|
|
326
|
+
}
|
|
327
|
+
async recording(callId) {
|
|
328
|
+
return this.client.get(`/calls/${callId}/recording`);
|
|
329
|
+
}
|
|
330
|
+
async reprocess(callId) {
|
|
331
|
+
return this.client.post(`/calls/${callId}/reprocess`);
|
|
332
|
+
}
|
|
333
|
+
/** Force-end an active call. Irreversible — closes the LiveKit room and triggers post-call processing. */
|
|
334
|
+
async end(callId) {
|
|
335
|
+
return this.client.post(`/calls/${callId}/end`);
|
|
336
|
+
}
|
|
337
|
+
/** Add one or more participants to an in-progress call (warm transfer / conference). */
|
|
338
|
+
async addParticipants(callId, data) {
|
|
339
|
+
return this.client.post(`/calls/${callId}/participants`, data);
|
|
340
|
+
}
|
|
341
|
+
async queueStats() {
|
|
342
|
+
return this.client.get("/calls/queue/stats");
|
|
343
|
+
}
|
|
344
|
+
};
|
|
345
|
+
|
|
346
|
+
// src/resources/dnc.ts
|
|
347
|
+
function buildQuery2(params) {
|
|
348
|
+
const sp = new URLSearchParams();
|
|
349
|
+
for (const [k, v] of Object.entries(params)) {
|
|
350
|
+
if (v !== void 0 && v !== null) sp.set(k, String(v));
|
|
351
|
+
}
|
|
352
|
+
const q = sp.toString();
|
|
353
|
+
return q ? `?${q}` : "";
|
|
354
|
+
}
|
|
355
|
+
var DncResource = class {
|
|
356
|
+
constructor(client) {
|
|
357
|
+
this.client = client;
|
|
358
|
+
}
|
|
359
|
+
/** List all DNC entries for the tenant. */
|
|
360
|
+
async list(params = {}) {
|
|
361
|
+
return this.client.get(`/dnc${buildQuery2(params)}`);
|
|
362
|
+
}
|
|
363
|
+
/** Add a single number to the Do-Not-Call registry. */
|
|
364
|
+
async add(data) {
|
|
365
|
+
return this.client.post("/dnc", data);
|
|
366
|
+
}
|
|
367
|
+
/** Add up to 1000 numbers in one request. Invalid numbers are skipped and returned in `invalid`. */
|
|
368
|
+
async addBatch(data) {
|
|
369
|
+
return this.client.post("/dnc/batch", data);
|
|
370
|
+
}
|
|
371
|
+
/** Check up to 500 numbers without adding them. Read-only. */
|
|
372
|
+
async check(data) {
|
|
373
|
+
return this.client.post("/dnc/check", data);
|
|
374
|
+
}
|
|
375
|
+
/** Remove a number from the registry (re-enables outbound to it). */
|
|
376
|
+
async remove(phone) {
|
|
377
|
+
return this.client.delete(`/dnc/${encodeURIComponent(phone)}`);
|
|
378
|
+
}
|
|
379
|
+
};
|
|
380
|
+
|
|
381
|
+
// src/resources/numbers.ts
|
|
382
|
+
var NumbersResource = class {
|
|
383
|
+
constructor(client) {
|
|
384
|
+
this.client = client;
|
|
385
|
+
}
|
|
386
|
+
/**
|
|
387
|
+
* Retrieve a list of all phone numbers assigned to your Rymi account.
|
|
388
|
+
*/
|
|
389
|
+
async list(params = {}) {
|
|
390
|
+
const searchParams = new URLSearchParams();
|
|
391
|
+
if (params.limit !== void 0) searchParams.set("limit", String(params.limit));
|
|
392
|
+
if (params.offset !== void 0) searchParams.set("offset", String(params.offset));
|
|
393
|
+
const query = searchParams.toString();
|
|
394
|
+
return this.client.get(`/numbers${query ? `?${query}` : ""}`);
|
|
395
|
+
}
|
|
396
|
+
async register(number, params = {}) {
|
|
397
|
+
return this.client.post("/numbers", { number, ...params });
|
|
398
|
+
}
|
|
399
|
+
async attach(number, agentId) {
|
|
400
|
+
return this.client.post(`/numbers/${encodeURIComponent(number)}/attach`, { agent_id: agentId });
|
|
401
|
+
}
|
|
402
|
+
async remove(number) {
|
|
403
|
+
return this.client.delete(`/numbers/${encodeURIComponent(number)}`);
|
|
404
|
+
}
|
|
405
|
+
};
|
|
406
|
+
|
|
407
|
+
// src/resources/webhooks.ts
|
|
408
|
+
var crypto = __toESM(require("crypto"));
|
|
409
|
+
function buildQuery3(params) {
|
|
410
|
+
const sp = new URLSearchParams();
|
|
411
|
+
for (const [k, v] of Object.entries(params)) {
|
|
412
|
+
if (v !== void 0 && v !== null) sp.set(k, String(v));
|
|
413
|
+
}
|
|
414
|
+
const q = sp.toString();
|
|
415
|
+
return q ? `?${q}` : "";
|
|
416
|
+
}
|
|
417
|
+
var WebhooksResource = class {
|
|
418
|
+
constructor(client) {
|
|
419
|
+
this.client = client;
|
|
420
|
+
}
|
|
421
|
+
/** List registered webhook endpoints. The signing secret is never returned. */
|
|
422
|
+
async list(params = {}) {
|
|
423
|
+
return this.client.get(`/webhooks${buildQuery3(params)}`);
|
|
424
|
+
}
|
|
425
|
+
/** Register a webhook. `url` must be public https. `secret` must be 16–256 chars. */
|
|
426
|
+
async create(data) {
|
|
427
|
+
return this.client.post("/webhooks", data);
|
|
428
|
+
}
|
|
429
|
+
/** Update a webhook. Only provided fields change. Pass `secret` to rotate it. */
|
|
430
|
+
async update(id, data) {
|
|
431
|
+
return this.client.patch(`/webhooks/${id}`, data);
|
|
432
|
+
}
|
|
433
|
+
/** Delete a webhook endpoint. */
|
|
434
|
+
async delete(id) {
|
|
435
|
+
return this.client.delete(`/webhooks/${id}`);
|
|
436
|
+
}
|
|
437
|
+
/**
|
|
438
|
+
* Verifies that a webhook received by your backend was genuinely dispatched by Rymi.
|
|
439
|
+
*
|
|
440
|
+
* Rymi endpoints secure webhooks by computing an HMAC-SHA256 signature
|
|
441
|
+
* of the raw JSON body concatenated with the timestamp, using your Webhook Secret.
|
|
442
|
+
*
|
|
443
|
+
* @param payload The raw stringified JSON body of the webhook hook request.
|
|
444
|
+
* @param signatureHeader The value of the `X-Rymi-Signature` header from the request.
|
|
445
|
+
* @param timestampHeader The value of the `X-Rymi-Timestamp` header from the request.
|
|
446
|
+
* @param webhookSecret Your project's unique Webhook Signing Secret (starts with `whsec_`)
|
|
447
|
+
* @param toleranceMillis Allowed time difference in milliseconds to prevent replay attacks (default 5 mins)
|
|
448
|
+
*
|
|
449
|
+
* @throws {Error} if the signature is invalid or if the timestamp exceeds the tolerance.
|
|
450
|
+
*/
|
|
451
|
+
verifySignature(payload, signatureHeader, timestampHeader, webhookSecret, toleranceMillis = 3e5) {
|
|
452
|
+
const timestamp = parseInt(timestampHeader, 10);
|
|
453
|
+
if (isNaN(timestamp)) {
|
|
454
|
+
throw new Error("Invalid Rymi-Timestamp header");
|
|
455
|
+
}
|
|
456
|
+
const now = Date.now();
|
|
457
|
+
if (now - timestamp > toleranceMillis) {
|
|
458
|
+
throw new Error("Webhook timestamp is too old. Possible replay attack.");
|
|
459
|
+
}
|
|
460
|
+
const signaturePayload = `${timestamp}.${payload}`;
|
|
461
|
+
const expectedSignature = crypto.createHmac("sha256", webhookSecret).update(signaturePayload, "utf8").digest("hex");
|
|
462
|
+
try {
|
|
463
|
+
const isValid = crypto.timingSafeEqual(
|
|
464
|
+
Buffer.from(signatureHeader),
|
|
465
|
+
Buffer.from(expectedSignature)
|
|
466
|
+
);
|
|
467
|
+
if (!isValid) {
|
|
468
|
+
throw new Error("Invalid Webhook Signature. The secret might be incorrect.");
|
|
469
|
+
}
|
|
470
|
+
return true;
|
|
471
|
+
} catch (err) {
|
|
472
|
+
throw new Error("Invalid Webhook Signature. The secret might be incorrect.");
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
};
|
|
476
|
+
|
|
477
|
+
// src/resources/keys.ts
|
|
478
|
+
var KeysResource = class {
|
|
479
|
+
constructor(client) {
|
|
480
|
+
this.client = client;
|
|
481
|
+
}
|
|
482
|
+
async listPublishable() {
|
|
483
|
+
return this.client.get("/keys/publishable");
|
|
484
|
+
}
|
|
485
|
+
async createPublishable(data) {
|
|
486
|
+
return this.client.post("/keys/publishable", data);
|
|
487
|
+
}
|
|
488
|
+
async revokePublishable(id) {
|
|
489
|
+
return this.client.delete(`/keys/publishable/${id}`);
|
|
490
|
+
}
|
|
491
|
+
};
|
|
492
|
+
|
|
493
|
+
// src/resources/telephony.ts
|
|
494
|
+
var TelephonyResource = class {
|
|
495
|
+
constructor(client) {
|
|
496
|
+
this.client = client;
|
|
497
|
+
}
|
|
498
|
+
async connect(data) {
|
|
499
|
+
return this.client.post("/telephony/connect", data);
|
|
500
|
+
}
|
|
501
|
+
async disconnect() {
|
|
502
|
+
return this.client.post("/telephony/disconnect");
|
|
503
|
+
}
|
|
504
|
+
async status() {
|
|
505
|
+
return this.client.get("/telephony/status");
|
|
506
|
+
}
|
|
507
|
+
async numbers() {
|
|
508
|
+
return this.client.get("/telephony/numbers");
|
|
509
|
+
}
|
|
510
|
+
};
|
|
511
|
+
|
|
512
|
+
// src/resources/billing.ts
|
|
513
|
+
var BillingResource = class {
|
|
514
|
+
constructor(client) {
|
|
515
|
+
this.client = client;
|
|
516
|
+
}
|
|
517
|
+
/**
|
|
518
|
+
* Lane-aware usage summary: remaining voice-runtime minutes, Studio AI unit
|
|
519
|
+
* usage, and post-call intelligence usage. Voice balance is reported in
|
|
520
|
+
* MINUTES (the customer-facing unit), not dollars.
|
|
521
|
+
*/
|
|
522
|
+
async usageSummary() {
|
|
523
|
+
return this.client.get("/billing/usage-summary");
|
|
524
|
+
}
|
|
525
|
+
/** Estimate the cost of a call for a given tier and duration. */
|
|
526
|
+
async estimate(data = {}) {
|
|
527
|
+
return this.client.post("/billing/estimate", data);
|
|
528
|
+
}
|
|
529
|
+
/** Configure auto-recharge. Server rejects (400) if enabled && pack_usd <= threshold_usd. */
|
|
530
|
+
async setAutoRecharge(data) {
|
|
531
|
+
return this.client.put("/billing/auto-recharge", data);
|
|
532
|
+
}
|
|
533
|
+
/** Configure spend-alert preferences. */
|
|
534
|
+
async setAlerts(data) {
|
|
535
|
+
return this.client.put("/billing/alerts", data);
|
|
536
|
+
}
|
|
537
|
+
};
|
|
538
|
+
|
|
539
|
+
// src/resources/templates.ts
|
|
540
|
+
var TemplatesResource = class {
|
|
541
|
+
constructor(client) {
|
|
542
|
+
this.client = client;
|
|
543
|
+
}
|
|
544
|
+
/**
|
|
545
|
+
* List published agent templates available to the current tenant. Use a
|
|
546
|
+
* template's `defaults` as the starting config for create_agent.
|
|
547
|
+
*/
|
|
548
|
+
async list() {
|
|
549
|
+
return this.client.get("/agent-templates");
|
|
550
|
+
}
|
|
551
|
+
};
|
|
552
|
+
|
|
553
|
+
// src/index.ts
|
|
554
|
+
__reExport(index_exports, require("@rymi/sdk-types"), module.exports);
|
|
555
|
+
var Rymi = class {
|
|
556
|
+
client;
|
|
557
|
+
agents;
|
|
558
|
+
calls;
|
|
559
|
+
dnc;
|
|
560
|
+
numbers;
|
|
561
|
+
webhooks;
|
|
562
|
+
keys;
|
|
563
|
+
telephony;
|
|
564
|
+
billing;
|
|
565
|
+
templates;
|
|
566
|
+
constructor(options) {
|
|
567
|
+
this.client = new RymiClient(options);
|
|
568
|
+
this.agents = new AgentsResource(this.client);
|
|
569
|
+
this.calls = new CallsResource(this.client);
|
|
570
|
+
this.dnc = new DncResource(this.client);
|
|
571
|
+
this.numbers = new NumbersResource(this.client);
|
|
572
|
+
this.webhooks = new WebhooksResource(this.client);
|
|
573
|
+
this.keys = new KeysResource(this.client);
|
|
574
|
+
this.telephony = new TelephonyResource(this.client);
|
|
575
|
+
this.billing = new BillingResource(this.client);
|
|
576
|
+
this.templates = new TemplatesResource(this.client);
|
|
577
|
+
}
|
|
578
|
+
};
|
|
579
|
+
var index_default = Rymi;
|
|
580
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
581
|
+
0 && (module.exports = {
|
|
582
|
+
AgentsResource,
|
|
583
|
+
BillingResource,
|
|
584
|
+
CallsResource,
|
|
585
|
+
DncResource,
|
|
586
|
+
KeysResource,
|
|
587
|
+
NumbersResource,
|
|
588
|
+
Rymi,
|
|
589
|
+
RymiClient,
|
|
590
|
+
RymiError,
|
|
591
|
+
TelephonyResource,
|
|
592
|
+
TemplatesResource,
|
|
593
|
+
WebhooksResource,
|
|
594
|
+
...require("@rymi/sdk-types")
|
|
595
|
+
});
|
|
596
|
+
//# sourceMappingURL=index.js.map
|