@wokuapp/sdk 0.2.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.js ADDED
@@ -0,0 +1,1121 @@
1
+ // src/core/errors.ts
2
+ var WokuError = class extends Error {
3
+ constructor(message, options) {
4
+ super(message);
5
+ this.name = "WokuError";
6
+ this.code = options?.code;
7
+ if (options?.cause !== void 0) {
8
+ this.cause = options.cause;
9
+ }
10
+ }
11
+ };
12
+ var WokuConnectionError = class extends WokuError {
13
+ constructor(message, options) {
14
+ super(message, {
15
+ code: options?.code ?? "connection_error",
16
+ cause: options?.cause
17
+ });
18
+ this.name = "WokuConnectionError";
19
+ }
20
+ };
21
+ var WokuTimeoutError = class extends WokuConnectionError {
22
+ constructor(message = "Request timed out") {
23
+ super(message, { code: "timeout" });
24
+ this.name = "WokuTimeoutError";
25
+ }
26
+ };
27
+ var WokuAPIError = class _WokuAPIError extends WokuError {
28
+ constructor(status, body, message, requestId, code, retryAfterSeconds) {
29
+ super(message, { code: code ?? codeForStatus(status) });
30
+ this.name = "WokuAPIError";
31
+ this.status = status;
32
+ this.body = body;
33
+ this.requestId = requestId;
34
+ this.retryAfterSeconds = retryAfterSeconds ?? retryAfterFromBody(body);
35
+ }
36
+ /** Build the most specific error subclass for a status + body. */
37
+ static from(status, body, requestId, retryAfterSeconds) {
38
+ const message = messageFrom(status, body, requestId);
39
+ const ra = retryAfterSeconds;
40
+ switch (true) {
41
+ case status === 400:
42
+ return new BadRequestError(status, body, message, requestId, void 0, ra);
43
+ case status === 401:
44
+ return new AuthenticationError(status, body, message, requestId, void 0, ra);
45
+ case status === 403:
46
+ return new PermissionDeniedError(status, body, message, requestId, void 0, ra);
47
+ case status === 404:
48
+ return new NotFoundError(status, body, message, requestId, void 0, ra);
49
+ case status === 409:
50
+ return new ConflictError(status, body, message, requestId, void 0, ra);
51
+ case status === 422:
52
+ return new UnprocessableEntityError(status, body, message, requestId, void 0, ra);
53
+ case status === 429:
54
+ return new RateLimitError(status, body, message, requestId, void 0, ra);
55
+ case status >= 500:
56
+ return new InternalServerError(status, body, message, requestId, void 0, ra);
57
+ default:
58
+ return new _WokuAPIError(status, body, message, requestId, void 0, ra);
59
+ }
60
+ }
61
+ };
62
+ var BadRequestError = class extends WokuAPIError {
63
+ constructor(...args) {
64
+ super(...args);
65
+ this.name = "BadRequestError";
66
+ }
67
+ };
68
+ var AuthenticationError = class extends WokuAPIError {
69
+ constructor(...args) {
70
+ super(...args);
71
+ this.name = "AuthenticationError";
72
+ }
73
+ };
74
+ var PermissionDeniedError = class extends WokuAPIError {
75
+ constructor(...args) {
76
+ super(...args);
77
+ this.name = "PermissionDeniedError";
78
+ }
79
+ };
80
+ var NotFoundError = class extends WokuAPIError {
81
+ constructor(...args) {
82
+ super(...args);
83
+ this.name = "NotFoundError";
84
+ }
85
+ };
86
+ var ConflictError = class extends WokuAPIError {
87
+ constructor(...args) {
88
+ super(...args);
89
+ this.name = "ConflictError";
90
+ }
91
+ };
92
+ var UnprocessableEntityError = class extends WokuAPIError {
93
+ constructor(...args) {
94
+ super(...args);
95
+ this.name = "UnprocessableEntityError";
96
+ }
97
+ };
98
+ var RateLimitError = class extends WokuAPIError {
99
+ constructor(...args) {
100
+ super(...args);
101
+ this.name = "RateLimitError";
102
+ }
103
+ };
104
+ var InternalServerError = class extends WokuAPIError {
105
+ constructor(...args) {
106
+ super(...args);
107
+ this.name = "InternalServerError";
108
+ }
109
+ };
110
+ var retryAfterFromBody = (body) => body && typeof body === "object" && typeof body.retryAfter === "number" ? body.retryAfter : void 0;
111
+ var codeForStatus = (status) => {
112
+ const map = {
113
+ 400: "bad_request",
114
+ 401: "authentication_error",
115
+ 403: "permission_denied",
116
+ 404: "not_found",
117
+ 409: "conflict",
118
+ 422: "unprocessable_entity",
119
+ 429: "rate_limited"
120
+ };
121
+ return map[status] ?? (status >= 500 ? "internal_server_error" : "api_error");
122
+ };
123
+ var messageFrom = (status, body, requestId) => {
124
+ let detail = `HTTP ${status}`;
125
+ if (typeof body === "string" && body.trim()) {
126
+ detail = body.trim();
127
+ } else if (body && typeof body === "object") {
128
+ const { message } = body;
129
+ if (Array.isArray(message)) detail = message.join(", ");
130
+ else if (typeof message === "string" && message) detail = message;
131
+ else if (typeof body.error === "string") detail = body.error;
132
+ }
133
+ return requestId ? `${status} ${detail} (request_id: ${requestId})` : `${status} ${detail}`;
134
+ };
135
+
136
+ // src/core/pagination.ts
137
+ var isPageResponse = (value) => typeof value === "object" && value !== null && Array.isArray(value.data) && typeof value.total === "number";
138
+ var Page = class {
139
+ constructor(response, fetchPage, options) {
140
+ this.fetchPage = fetchPage;
141
+ this.options = options;
142
+ this.data = response.data;
143
+ this.total = response.total;
144
+ this.page = response.page;
145
+ this.limit = response.limit;
146
+ }
147
+ /** Whether another page exists after this one. */
148
+ hasNextPage() {
149
+ if (this.limit <= 0) return false;
150
+ return this.page * this.limit < this.total;
151
+ }
152
+ /** Fetch the next page (throws if there is none — guard with hasNextPage). */
153
+ getNextPage() {
154
+ if (!this.hasNextPage()) {
155
+ throw new RangeError("No next page");
156
+ }
157
+ return this.fetchPage(this.page + 1, this.options);
158
+ }
159
+ /** Yield every item across all pages, fetching lazily as needed. */
160
+ async *[Symbol.asyncIterator]() {
161
+ for await (const page of walkPages(this)) {
162
+ for (const item of page.data) yield item;
163
+ }
164
+ }
165
+ /** Yield each Page, fetching lazily as needed. */
166
+ iterPages() {
167
+ return walkPages(this);
168
+ }
169
+ };
170
+ async function* walkPages(start) {
171
+ let current = start;
172
+ for (; ; ) {
173
+ yield current;
174
+ if (!current.hasNextPage()) return;
175
+ current = await current.getNextPage();
176
+ }
177
+ }
178
+
179
+ // src/core/client.ts
180
+ var DEFAULT_BASE_URL = "https://clientapi.woku.app";
181
+ var DEFAULT_TIMEOUT = 6e4;
182
+ var DEFAULT_MAX_RETRIES = 2;
183
+ var RETRY_BASE_MS = 500;
184
+ var RETRY_CAP_MS = 8e3;
185
+ var RETRYABLE_STATUS = /* @__PURE__ */ new Set([408, 429, 500, 502, 503, 504]);
186
+ var SDK_VERSION = "0.1.0";
187
+ var randomId = () => {
188
+ const c = globalThis.crypto;
189
+ if (c?.randomUUID) return c.randomUUID();
190
+ return `idmp_${Date.now().toString(36)}${Math.random().toString(36).slice(2, 12)}`;
191
+ };
192
+ var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
193
+ var WokuClient = class {
194
+ constructor(options = {}) {
195
+ const apiKey = options.apiKey ?? globalThis.process?.env?.WOKU_API_KEY;
196
+ if (!apiKey) {
197
+ throw new WokuError(
198
+ "Missing API key: pass { apiKey } or set WOKU_API_KEY.",
199
+ { code: "config_error" }
200
+ );
201
+ }
202
+ if (!options.dangerouslyAllowBrowser && isBrowser()) {
203
+ throw new WokuError(
204
+ "The Woku SDK is server-only: the secret key must not run in a browser. Pass { dangerouslyAllowBrowser: true } only if you fully control the runtime.",
205
+ { code: "config_error" }
206
+ );
207
+ }
208
+ const fetchImpl = options.fetch ?? globalThis.fetch;
209
+ if (!fetchImpl) {
210
+ throw new WokuError(
211
+ "No fetch implementation available; pass { fetch }.",
212
+ {
213
+ code: "config_error"
214
+ }
215
+ );
216
+ }
217
+ this.apiKey = apiKey;
218
+ this.baseURL = (options.baseURL ?? DEFAULT_BASE_URL).replace(/\/$/, "");
219
+ this.timeout = options.timeout ?? DEFAULT_TIMEOUT;
220
+ this.maxRetries = options.maxRetries ?? DEFAULT_MAX_RETRIES;
221
+ this.fetch = fetchImpl;
222
+ this.defaultHeaders = options.defaultHeaders ?? {};
223
+ }
224
+ /** Issue one request and return the parsed JSON body typed as `T`. */
225
+ async request(method, path, args = {}) {
226
+ const url = this.buildUrl(path, args.query);
227
+ const idempotencyKey = args.idempotencyKey ?? (args.idempotent && method.toUpperCase() === "POST" ? randomId() : void 0);
228
+ const headers = this.buildHeaders(method, { ...args, idempotencyKey });
229
+ const bodyText = args.body === void 0 ? void 0 : JSON.stringify(args.body);
230
+ const maxRetries = args.maxRetries ?? this.maxRetries;
231
+ const timeout = args.timeout ?? this.timeout;
232
+ const retryable = method.toUpperCase() === "GET" || Boolean(headers["X-Woku-Idempotency-Key"]);
233
+ let attempt = 0;
234
+ for (; ; ) {
235
+ try {
236
+ const { status, body, requestId, retryAfterSeconds } = await this.send(
237
+ url,
238
+ method,
239
+ headers,
240
+ bodyText,
241
+ timeout,
242
+ args.signal
243
+ );
244
+ if (status >= 200 && status < 300) {
245
+ return body;
246
+ }
247
+ const apiError = WokuAPIError.from(
248
+ status,
249
+ body,
250
+ requestId,
251
+ retryAfterSeconds
252
+ );
253
+ if (retryable && attempt < maxRetries && RETRYABLE_STATUS.has(status)) {
254
+ await sleep(this.backoff(attempt, apiError));
255
+ attempt += 1;
256
+ continue;
257
+ }
258
+ throw apiError;
259
+ } catch (error) {
260
+ if (error instanceof WokuAPIError) throw error;
261
+ const connError = toConnectionError(error);
262
+ if (connError.code === "aborted") throw connError;
263
+ if (retryable && attempt < maxRetries) {
264
+ await sleep(this.backoff(attempt));
265
+ attempt += 1;
266
+ continue;
267
+ }
268
+ throw connError;
269
+ }
270
+ }
271
+ }
272
+ /**
273
+ * Issue a GET that returns a paginated envelope and wrap it as a {@link Page}.
274
+ * `params` accepts any plain object (a resource's typed params interface).
275
+ */
276
+ async getPage(path, params, opts) {
277
+ const base = params ?? {};
278
+ const query = { ...base, ...opts?.query };
279
+ const response = await this.request("get", path, {
280
+ ...opts,
281
+ query
282
+ });
283
+ const envelope = isPageResponse(response) ? response : {
284
+ data: response ?? [],
285
+ total: Array.isArray(response) ? response.length : 0,
286
+ page: 1,
287
+ limit: Array.isArray(response) ? response.length : 0
288
+ };
289
+ return new Page(
290
+ envelope,
291
+ (page, pageOpts) => this.getPage(path, { ...base, page }, { ...opts, ...pageOpts }),
292
+ opts
293
+ );
294
+ }
295
+ buildUrl(path, query) {
296
+ const url = `${this.baseURL}${path.startsWith("/") ? path : `/${path}`}`;
297
+ if (!query) return url;
298
+ const search = new URLSearchParams();
299
+ for (const [key, value] of Object.entries(query)) {
300
+ if (value === void 0 || value === null) continue;
301
+ if (Array.isArray(value)) {
302
+ for (const item of value) search.append(key, String(item));
303
+ } else {
304
+ search.append(key, String(value));
305
+ }
306
+ }
307
+ const qs = search.toString();
308
+ return qs ? `${url}?${qs}` : url;
309
+ }
310
+ buildHeaders(method, args) {
311
+ const headers = {
312
+ Accept: "application/json",
313
+ "User-Agent": `woku-sdk-js/${SDK_VERSION}`,
314
+ ...this.defaultHeaders,
315
+ ...args.headers
316
+ };
317
+ headers["Authorization"] = `Bearer ${this.apiKey}`;
318
+ if (args.body !== void 0) {
319
+ headers["Content-Type"] = "application/json";
320
+ }
321
+ if (args.idempotencyKey !== void 0 && method.toUpperCase() === "POST") {
322
+ headers["X-Woku-Idempotency-Key"] = args.idempotencyKey;
323
+ }
324
+ return headers;
325
+ }
326
+ async send(url, method, headers, body, timeout, signal) {
327
+ const controller = new AbortController();
328
+ let timedOut = false;
329
+ const timer = setTimeout(() => {
330
+ timedOut = true;
331
+ controller.abort();
332
+ }, timeout);
333
+ const onExternalAbort = () => controller.abort();
334
+ if (signal) {
335
+ if (signal.aborted) controller.abort();
336
+ else signal.addEventListener("abort", onExternalAbort);
337
+ }
338
+ try {
339
+ const response = await this.fetch(url, {
340
+ method: method.toUpperCase(),
341
+ headers,
342
+ body,
343
+ signal: controller.signal
344
+ });
345
+ const text = await response.text();
346
+ return {
347
+ status: response.status,
348
+ body: parseBody(text),
349
+ requestId: requestIdFrom(response.headers),
350
+ retryAfterSeconds: retryAfterFromHeaders(response.headers)
351
+ };
352
+ } catch (error) {
353
+ if (timedOut) throw new WokuTimeoutError();
354
+ if (signal?.aborted) {
355
+ throw new WokuConnectionError("Request aborted", { code: "aborted" });
356
+ }
357
+ throw error;
358
+ } finally {
359
+ clearTimeout(timer);
360
+ if (signal) signal.removeEventListener("abort", onExternalAbort);
361
+ }
362
+ }
363
+ backoff(attempt, apiError) {
364
+ const retryAfter = apiError && typeof apiError.retryAfterSeconds === "number" ? apiError.retryAfterSeconds * 1e3 : void 0;
365
+ if (retryAfter !== void 0) return Math.min(retryAfter, RETRY_CAP_MS);
366
+ const ceiling = Math.min(RETRY_CAP_MS, RETRY_BASE_MS * 2 ** attempt);
367
+ return Math.random() * ceiling;
368
+ }
369
+ };
370
+ var isBrowser = () => typeof globalThis.document !== "undefined";
371
+ var parseBody = (text) => {
372
+ if (!text) return void 0;
373
+ try {
374
+ return JSON.parse(text);
375
+ } catch {
376
+ return text;
377
+ }
378
+ };
379
+ var requestIdFrom = (headers) => headers.get("x-request-id") ?? headers.get("request-id") ?? headers.get("x-woku-request-id") ?? void 0;
380
+ var retryAfterFromHeaders = (headers) => {
381
+ const raw = headers.get("retry-after");
382
+ if (!raw) return void 0;
383
+ const seconds = Number(raw);
384
+ if (Number.isFinite(seconds)) return Math.max(0, seconds);
385
+ const when = Date.parse(raw);
386
+ if (!Number.isNaN(when)) return Math.max(0, (when - Date.now()) / 1e3);
387
+ return void 0;
388
+ };
389
+ var toConnectionError = (error) => {
390
+ if (error instanceof WokuConnectionError) return error;
391
+ const message = error instanceof Error ? error.message : "Network request failed";
392
+ return new WokuConnectionError(message, { cause: error });
393
+ };
394
+
395
+ // src/resources/trackers.ts
396
+ var Trackers = class {
397
+ constructor(client) {
398
+ this.client = client;
399
+ }
400
+ /** List the company tracker definitions (paginated). */
401
+ list(params, opts) {
402
+ return this.client.getPage("/v1/external-trackers", params, opts);
403
+ }
404
+ /** Create a tracker definition (idempotent). */
405
+ create(body, opts) {
406
+ return this.client.request("post", "/v1/external-trackers", {
407
+ ...opts,
408
+ body,
409
+ idempotent: true
410
+ });
411
+ }
412
+ /** Get one tracker definition. */
413
+ get(id, opts) {
414
+ return this.client.request(
415
+ "get",
416
+ `/v1/external-trackers/${id}`,
417
+ opts
418
+ );
419
+ }
420
+ /** Update a tracker definition. */
421
+ update(id, body, opts) {
422
+ return this.client.request(
423
+ "patch",
424
+ `/v1/external-trackers/${id}`,
425
+ { ...opts, body }
426
+ );
427
+ }
428
+ /** Activate a tracker definition. */
429
+ activate(id, opts) {
430
+ return this.client.request(
431
+ "patch",
432
+ `/v1/external-trackers/${id}/activate`,
433
+ opts
434
+ );
435
+ }
436
+ /** Deactivate a tracker definition. */
437
+ deactivate(id, opts) {
438
+ return this.client.request(
439
+ "patch",
440
+ `/v1/external-trackers/${id}/deactivate`,
441
+ opts
442
+ );
443
+ }
444
+ /** Search VoC entities whose trackers match every filter (AND). */
445
+ searchEntities(body, opts) {
446
+ return this.client.request(
447
+ "post",
448
+ "/v1/external-trackers/search-entities",
449
+ { ...opts, body }
450
+ );
451
+ }
452
+ /** List the tracker values assigned to a woku. */
453
+ listWokuValues(wokuId, opts) {
454
+ return this.client.request(
455
+ "get",
456
+ `/v1/external-trackers/wokus/${wokuId}`,
457
+ opts
458
+ );
459
+ }
460
+ /** Assign (upsert) a tracker value to a woku by tracker name. */
461
+ assignToWoku(wokuId, body, opts) {
462
+ return this.client.request(
463
+ "post",
464
+ `/v1/external-trackers/wokus/${wokuId}`,
465
+ { ...opts, body, idempotent: true }
466
+ );
467
+ }
468
+ /** Remove a tracker value from a woku by tracker name. */
469
+ removeFromWoku(wokuId, trackerName, opts) {
470
+ return this.client.request(
471
+ "delete",
472
+ `/v1/external-trackers/wokus/${wokuId}/${encodeURIComponent(trackerName)}`,
473
+ opts
474
+ );
475
+ }
476
+ /** Search wokus by an exact `(tracker name, value)` pair (paginated). */
477
+ searchWokus(params, opts) {
478
+ return this.client.getPage(
479
+ "/v1/external-trackers/search",
480
+ params,
481
+ opts
482
+ );
483
+ }
484
+ /** List the tracker values assigned to a VoC entity (nps/csat/ces/form/flow). */
485
+ listEntityValues(entityType, id, opts) {
486
+ return this.client.request(
487
+ "get",
488
+ `/v1/external-trackers/${entityType}/${id}`,
489
+ opts
490
+ );
491
+ }
492
+ /** Assign (upsert) a tracker value to a VoC entity by tracker name. */
493
+ assignToEntity(entityType, id, body, opts) {
494
+ return this.client.request(
495
+ "post",
496
+ `/v1/external-trackers/${entityType}/${id}`,
497
+ { ...opts, body, idempotent: true }
498
+ );
499
+ }
500
+ /** Remove a tracker value from a VoC entity by tracker name. */
501
+ removeFromEntity(entityType, id, trackerName, opts) {
502
+ return this.client.request(
503
+ "delete",
504
+ `/v1/external-trackers/${entityType}/${id}/${encodeURIComponent(trackerName)}`,
505
+ opts
506
+ );
507
+ }
508
+ };
509
+
510
+ // src/resources/voc-tools.ts
511
+ var NpsTools = class {
512
+ constructor(client) {
513
+ this.client = client;
514
+ }
515
+ list(params, opts) {
516
+ return this.client.getPage("/v1/nps-tools", params, opts);
517
+ }
518
+ create(body, opts) {
519
+ return this.client.request("post", "/v1/nps-tools", {
520
+ ...opts,
521
+ body,
522
+ idempotent: true
523
+ });
524
+ }
525
+ get(id, opts) {
526
+ return this.client.request("get", `/v1/nps-tool/${id}`, opts);
527
+ }
528
+ update(id, body, opts) {
529
+ return this.client.request("patch", `/v1/nps-tools/${id}`, {
530
+ ...opts,
531
+ body
532
+ });
533
+ }
534
+ delete(id, opts) {
535
+ return this.client.request(
536
+ "delete",
537
+ `/v1/nps-tools/${id}`,
538
+ opts
539
+ );
540
+ }
541
+ };
542
+ var CsatTools = class {
543
+ constructor(client) {
544
+ this.client = client;
545
+ }
546
+ list(params, opts) {
547
+ return this.client.getPage("/v1/csat-tools", params, opts);
548
+ }
549
+ create(body, opts) {
550
+ return this.client.request("post", "/v1/csat-tools", {
551
+ ...opts,
552
+ body,
553
+ idempotent: true
554
+ });
555
+ }
556
+ get(id, opts) {
557
+ return this.client.request("get", `/v1/csat-tool/${id}`, opts);
558
+ }
559
+ update(id, body, opts) {
560
+ return this.client.request("patch", `/v1/csat-tools/${id}`, {
561
+ ...opts,
562
+ body
563
+ });
564
+ }
565
+ delete(id, opts) {
566
+ return this.client.request(
567
+ "delete",
568
+ `/v1/csat-tools/${id}`,
569
+ opts
570
+ );
571
+ }
572
+ };
573
+ var CesTools = class {
574
+ constructor(client) {
575
+ this.client = client;
576
+ }
577
+ list(params, opts) {
578
+ return this.client.getPage("/v1/ces-tools", params, opts);
579
+ }
580
+ create(body, opts) {
581
+ return this.client.request("post", "/v1/ces-tools", {
582
+ ...opts,
583
+ body,
584
+ idempotent: true
585
+ });
586
+ }
587
+ get(id, opts) {
588
+ return this.client.request("get", `/v1/ces-tool/${id}`, opts);
589
+ }
590
+ update(id, body, opts) {
591
+ return this.client.request("patch", `/v1/ces-tools/${id}`, {
592
+ ...opts,
593
+ body
594
+ });
595
+ }
596
+ delete(id, opts) {
597
+ return this.client.request(
598
+ "delete",
599
+ `/v1/ces-tools/${id}`,
600
+ opts
601
+ );
602
+ }
603
+ };
604
+
605
+ // src/resources/surveys.ts
606
+ var Nps = class {
607
+ constructor(client) {
608
+ this.client = client;
609
+ }
610
+ /** Send the NPS survey by email or WhatsApp (idempotent). */
611
+ sendInvitations(body, opts) {
612
+ return this.client.request(
613
+ "post",
614
+ "/v1/nps/invitations",
615
+ {
616
+ ...opts,
617
+ body,
618
+ idempotent: true
619
+ }
620
+ );
621
+ }
622
+ /** List NPS responses (paginated). */
623
+ listResponses(params, opts) {
624
+ return this.client.getPage("/v1/nps", params, opts);
625
+ }
626
+ /** Get one NPS response. */
627
+ getResponse(id, opts) {
628
+ return this.client.request("get", `/v1/nps/${id}`, opts);
629
+ }
630
+ };
631
+ var Csat = class {
632
+ constructor(client) {
633
+ this.client = client;
634
+ }
635
+ sendInvitations(body, opts) {
636
+ return this.client.request(
637
+ "post",
638
+ "/v1/csat/invitations",
639
+ { ...opts, body, idempotent: true }
640
+ );
641
+ }
642
+ listResponses(params, opts) {
643
+ return this.client.getPage("/v1/csat", params, opts);
644
+ }
645
+ getResponse(id, opts) {
646
+ return this.client.request("get", `/v1/csat/${id}`, opts);
647
+ }
648
+ };
649
+ var Ces = class {
650
+ constructor(client) {
651
+ this.client = client;
652
+ }
653
+ sendInvitations(body, opts) {
654
+ return this.client.request(
655
+ "post",
656
+ "/v1/ces/invitations",
657
+ {
658
+ ...opts,
659
+ body,
660
+ idempotent: true
661
+ }
662
+ );
663
+ }
664
+ listResponses(params, opts) {
665
+ return this.client.getPage("/v1/ces", params, opts);
666
+ }
667
+ getResponse(id, opts) {
668
+ return this.client.request("get", `/v1/ces/${id}`, opts);
669
+ }
670
+ };
671
+
672
+ // src/resources/wokus.ts
673
+ var Wokus = class {
674
+ constructor(client) {
675
+ this.client = client;
676
+ }
677
+ list(params, opts) {
678
+ return this.client.getPage("/v1/wokus", params, opts);
679
+ }
680
+ create(body, opts) {
681
+ return this.client.request("post", "/v1/wokus", {
682
+ ...opts,
683
+ body,
684
+ idempotent: true
685
+ });
686
+ }
687
+ /** Get one woku with aggregated review stats. */
688
+ get(id, opts) {
689
+ return this.client.request("get", `/v1/wokus/${id}`, opts);
690
+ }
691
+ update(id, body, opts) {
692
+ return this.client.request("patch", `/v1/wokus/${id}`, {
693
+ ...opts,
694
+ body
695
+ });
696
+ }
697
+ delete(id, opts) {
698
+ return this.client.request(
699
+ "delete",
700
+ `/v1/wokus/${id}`,
701
+ opts
702
+ );
703
+ }
704
+ /** Apply the boolean settings idempotently (closed/reviewsDisabled/...). */
705
+ updateSettings(id, body, opts) {
706
+ return this.client.request("patch", `/v1/wokus/${id}/settings`, {
707
+ ...opts,
708
+ body
709
+ });
710
+ }
711
+ /** Move the woku into a folder, or to the root with `{ folderId: null }`. */
712
+ move(id, body, opts) {
713
+ return this.client.request("patch", `/v1/wokus/${id}/move`, {
714
+ ...opts,
715
+ body
716
+ });
717
+ }
718
+ /** List the reviews of a woku (paginated). */
719
+ listReviews(id, params, opts) {
720
+ return this.client.getPage(
721
+ `/v1/wokus/${id}/reviews`,
722
+ params,
723
+ opts
724
+ );
725
+ }
726
+ /** Send a woku review invitation by email or WhatsApp (idempotent). */
727
+ sendInvitations(id, body, opts) {
728
+ return this.client.request(
729
+ "post",
730
+ `/v1/wokus/${id}/invitations`,
731
+ { ...opts, body, idempotent: true }
732
+ );
733
+ }
734
+ /** Share a woku review link by email. */
735
+ share(id, body, opts) {
736
+ return this.client.request("post", `/v1/wokus/${id}/share`, {
737
+ ...opts,
738
+ body
739
+ });
740
+ }
741
+ };
742
+
743
+ // src/resources/forms.ts
744
+ var Forms = class {
745
+ constructor(client) {
746
+ this.client = client;
747
+ }
748
+ list(params, opts) {
749
+ return this.client.getPage("/v1/forms", params, opts);
750
+ }
751
+ get(id, opts) {
752
+ return this.client.request("get", `/v1/forms/${id}`, opts);
753
+ }
754
+ /** List the responses of a form (paginated). */
755
+ listResponses(id, params, opts) {
756
+ return this.client.getPage(
757
+ `/v1/forms/${id}/responses`,
758
+ params,
759
+ opts
760
+ );
761
+ }
762
+ /** Send a form by email or WhatsApp (idempotent). */
763
+ sendInvitations(id, body, opts) {
764
+ return this.client.request(
765
+ "post",
766
+ `/v1/forms/${id}/invitations`,
767
+ { ...opts, body, idempotent: true }
768
+ );
769
+ }
770
+ };
771
+
772
+ // src/resources/flows.ts
773
+ var Flows = class {
774
+ constructor(client) {
775
+ this.client = client;
776
+ }
777
+ list(params, opts) {
778
+ return this.client.getPage("/v1/flows", params, opts);
779
+ }
780
+ get(id, opts) {
781
+ return this.client.request("get", `/v1/flows/${id}`, opts);
782
+ }
783
+ };
784
+
785
+ // src/resources/action-plans.ts
786
+ var ActionPlans = class {
787
+ constructor(client) {
788
+ this.client = client;
789
+ }
790
+ list(params, opts) {
791
+ return this.client.getPage("/v1/action-plans", params, opts);
792
+ }
793
+ get(id, opts) {
794
+ return this.client.request(
795
+ "get",
796
+ `/v1/action-plans/${id}`,
797
+ opts
798
+ );
799
+ }
800
+ /** The plan timeline (events, oldest first). */
801
+ events(id, opts) {
802
+ return this.client.request(
803
+ "get",
804
+ `/v1/action-plans/${id}/events`,
805
+ opts
806
+ );
807
+ }
808
+ /** The plan AI conversation (read-only). */
809
+ getConversation(id, opts) {
810
+ return this.client.request(
811
+ "get",
812
+ `/v1/action-plans/${id}/conversation`,
813
+ opts
814
+ );
815
+ }
816
+ /**
817
+ * Reply to the plan AI agent. Each reply is a paid AI turn (`confirm:true` is
818
+ * sent automatically); the reply is composed asynchronously, so poll
819
+ * {@link getConversation} until `busy` is false.
820
+ */
821
+ reply(id, text, opts) {
822
+ return this.client.request(
823
+ "post",
824
+ `/v1/action-plans/${id}/conversation`,
825
+ { ...opts, body: { text, confirm: true } }
826
+ );
827
+ }
828
+ /** Send an approved plan to a destination (jira/monday/clickup/notion/internal). */
829
+ send(id, body, opts) {
830
+ return this.client.request(
831
+ "post",
832
+ `/v1/action-plans/${id}/send`,
833
+ { ...opts, body }
834
+ );
835
+ }
836
+ createTask(id, body, opts) {
837
+ return this.client.request(
838
+ "post",
839
+ `/v1/action-plans/${id}/tasks`,
840
+ { ...opts, body, idempotent: true }
841
+ );
842
+ }
843
+ updateTask(id, taskId, body, opts) {
844
+ return this.client.request(
845
+ "patch",
846
+ `/v1/action-plans/${id}/tasks/${taskId}`,
847
+ { ...opts, body }
848
+ );
849
+ }
850
+ reorderTasks(id, body, opts) {
851
+ return this.client.request(
852
+ "patch",
853
+ `/v1/action-plans/${id}/tasks/reorder`,
854
+ { ...opts, body }
855
+ );
856
+ }
857
+ deleteTask(id, taskId, opts) {
858
+ return this.client.request(
859
+ "delete",
860
+ `/v1/action-plans/${id}/tasks/${taskId}`,
861
+ opts
862
+ );
863
+ }
864
+ approve(id, opts) {
865
+ return this.status(id, "approve", opts);
866
+ }
867
+ reopen(id, opts) {
868
+ return this.status(id, "reopen", opts);
869
+ }
870
+ cancel(id, opts) {
871
+ return this.status(id, "cancel", opts);
872
+ }
873
+ complete(id, opts) {
874
+ return this.status(id, "complete", opts);
875
+ }
876
+ resume(id, opts) {
877
+ return this.status(id, "resume", opts);
878
+ }
879
+ status(id, action, opts) {
880
+ return this.client.request(
881
+ "post",
882
+ `/v1/action-plans/${id}/${action}`,
883
+ opts
884
+ );
885
+ }
886
+ };
887
+ var ActionPlanGroups = class {
888
+ constructor(client) {
889
+ this.client = client;
890
+ }
891
+ list(params, opts) {
892
+ return this.client.request("get", "/v1/action-plan-groups", {
893
+ ...opts,
894
+ query: { ...params, ...opts?.query }
895
+ });
896
+ }
897
+ /** Get one group with its embedded stats. */
898
+ get(id, opts) {
899
+ return this.client.request(
900
+ "get",
901
+ `/v1/action-plan-groups/${id}`,
902
+ opts
903
+ );
904
+ }
905
+ create(body, opts) {
906
+ return this.client.request("post", "/v1/action-plan-groups", {
907
+ ...opts,
908
+ body,
909
+ idempotent: true
910
+ });
911
+ }
912
+ update(id, body, opts) {
913
+ return this.client.request(
914
+ "patch",
915
+ `/v1/action-plan-groups/${id}`,
916
+ { ...opts, body }
917
+ );
918
+ }
919
+ setEnabled(id, enabled, opts) {
920
+ return this.client.request(
921
+ "patch",
922
+ `/v1/action-plan-groups/${id}/enabled`,
923
+ { ...opts, body: { enabled } }
924
+ );
925
+ }
926
+ delete(id, opts) {
927
+ return this.client.request(
928
+ "delete",
929
+ `/v1/action-plan-groups/${id}`,
930
+ opts
931
+ );
932
+ }
933
+ };
934
+
935
+ // src/resources/tickets.ts
936
+ var Tickets = class {
937
+ constructor(client) {
938
+ this.client = client;
939
+ }
940
+ list(params, opts) {
941
+ return this.client.getPage("/v1/tickets", params, opts);
942
+ }
943
+ /** Aggregate counts by tool and by SAC destination. */
944
+ stats(params, opts) {
945
+ return this.client.request("get", "/v1/tickets/stats", {
946
+ ...opts,
947
+ query: { ...params, ...opts?.query }
948
+ });
949
+ }
950
+ get(id, opts) {
951
+ return this.client.request("get", `/v1/tickets/${id}`, opts);
952
+ }
953
+ update(id, body, opts) {
954
+ return this.client.request("patch", `/v1/tickets/${id}`, {
955
+ ...opts,
956
+ body
957
+ });
958
+ }
959
+ };
960
+ var TicketDestinations = class {
961
+ constructor(client) {
962
+ this.client = client;
963
+ }
964
+ list(opts) {
965
+ return this.client.request(
966
+ "get",
967
+ "/v1/ticket-destinations",
968
+ opts
969
+ );
970
+ }
971
+ get(id, opts) {
972
+ return this.client.request(
973
+ "get",
974
+ `/v1/ticket-destinations/${id}`,
975
+ opts
976
+ );
977
+ }
978
+ create(body, opts) {
979
+ return this.client.request("post", "/v1/ticket-destinations", {
980
+ ...opts,
981
+ body,
982
+ idempotent: true
983
+ });
984
+ }
985
+ update(id, body, opts) {
986
+ return this.client.request(
987
+ "patch",
988
+ `/v1/ticket-destinations/${id}`,
989
+ { ...opts, body }
990
+ );
991
+ }
992
+ delete(id, opts) {
993
+ return this.client.request(
994
+ "delete",
995
+ `/v1/ticket-destinations/${id}`,
996
+ opts
997
+ );
998
+ }
999
+ /**
1000
+ * Send a real connectivity test to a saved destination. Requires
1001
+ * `confirm: true` (the test reaches the live destination).
1002
+ */
1003
+ test(id, opts) {
1004
+ return this.client.request(
1005
+ "post",
1006
+ `/v1/ticket-destinations/${id}/test`,
1007
+ { ...opts, body: { confirm: true } }
1008
+ );
1009
+ }
1010
+ };
1011
+
1012
+ // src/resources/dispatches.ts
1013
+ var Dispatches = class {
1014
+ constructor(client) {
1015
+ this.client = client;
1016
+ }
1017
+ /** List the invitation dispatches (delivery status, no recipient PII). */
1018
+ list(params, opts) {
1019
+ return this.client.getPage("/v1/dispatches", params, opts);
1020
+ }
1021
+ /** Response-rate metrics over the dispatches. */
1022
+ stats(params, opts) {
1023
+ return this.client.request("get", "/v1/dispatches/stats", {
1024
+ ...opts,
1025
+ query: { ...params, ...opts?.query }
1026
+ });
1027
+ }
1028
+ };
1029
+
1030
+ // src/resources/reports.ts
1031
+ var Reports = class {
1032
+ constructor(client) {
1033
+ this.client = client;
1034
+ }
1035
+ /** Company-level NPS report. */
1036
+ companyNps(params, opts) {
1037
+ return this.client.request("get", "/v1/reports/company-nps", {
1038
+ ...opts,
1039
+ query: { ...params, ...opts?.query }
1040
+ });
1041
+ }
1042
+ /** NPS report for one tool. */
1043
+ npsTool(npsToolId, params, opts) {
1044
+ return this.client.request(
1045
+ "get",
1046
+ `/v1/reports/nps-tool/${npsToolId}`,
1047
+ { ...opts, query: { ...params, ...opts?.query } }
1048
+ );
1049
+ }
1050
+ };
1051
+
1052
+ // src/resources/company.ts
1053
+ var Company = class {
1054
+ constructor(client) {
1055
+ this.client = client;
1056
+ }
1057
+ /** Get the caller company. */
1058
+ me(opts) {
1059
+ return this.client.request("get", "/v1/companies/me", opts);
1060
+ }
1061
+ /** Rotate the secret key. The returned key replaces the current one. */
1062
+ rotateKey(opts) {
1063
+ return this.client.request(
1064
+ "post",
1065
+ "/v1/companies/me/rotate-key",
1066
+ opts
1067
+ );
1068
+ }
1069
+ /** Revoke the secret key (all subsequent requests will be unauthorized). */
1070
+ revokeKey(opts) {
1071
+ return this.client.request(
1072
+ "post",
1073
+ "/v1/companies/me/revoke-key",
1074
+ opts
1075
+ );
1076
+ }
1077
+ };
1078
+
1079
+ // src/resources/quarantines.ts
1080
+ var Quarantines = class {
1081
+ constructor(client) {
1082
+ this.client = client;
1083
+ }
1084
+ /** Check whether a contact is quarantined. */
1085
+ check(params, opts) {
1086
+ return this.client.request("get", "/v1/quarantines/check", {
1087
+ ...opts,
1088
+ query: { ...params, ...opts?.query }
1089
+ });
1090
+ }
1091
+ };
1092
+
1093
+ // src/woku.ts
1094
+ var Woku = class {
1095
+ constructor(options) {
1096
+ const opts = typeof options === "string" ? { apiKey: options } : options ?? {};
1097
+ this.client = new WokuClient(opts);
1098
+ this.trackers = new Trackers(this.client);
1099
+ this.npsTools = new NpsTools(this.client);
1100
+ this.csatTools = new CsatTools(this.client);
1101
+ this.cesTools = new CesTools(this.client);
1102
+ this.nps = new Nps(this.client);
1103
+ this.csat = new Csat(this.client);
1104
+ this.ces = new Ces(this.client);
1105
+ this.wokus = new Wokus(this.client);
1106
+ this.forms = new Forms(this.client);
1107
+ this.flows = new Flows(this.client);
1108
+ this.actionPlans = new ActionPlans(this.client);
1109
+ this.actionPlanGroups = new ActionPlanGroups(this.client);
1110
+ this.tickets = new Tickets(this.client);
1111
+ this.ticketDestinations = new TicketDestinations(this.client);
1112
+ this.dispatches = new Dispatches(this.client);
1113
+ this.reports = new Reports(this.client);
1114
+ this.company = new Company(this.client);
1115
+ this.quarantines = new Quarantines(this.client);
1116
+ }
1117
+ };
1118
+
1119
+ export { AuthenticationError, BadRequestError, ConflictError, InternalServerError, NotFoundError, Page, PermissionDeniedError, RateLimitError, UnprocessableEntityError, Woku, WokuAPIError, WokuClient, WokuConnectionError, WokuError, WokuTimeoutError };
1120
+ //# sourceMappingURL=index.js.map
1121
+ //# sourceMappingURL=index.js.map