@teamlearners/clawops 0.15.0 → 0.16.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.cjs CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- var chunkENZ4B3I7_cjs = require('./chunk-ENZ4B3I7.cjs');
5
+ var chunkD25IRY5V_cjs = require('./chunk-D25IRY5V.cjs');
6
6
  var zod = require('zod');
7
7
  var crypto = require('crypto');
8
8
 
@@ -13,11 +13,11 @@ function validateBaseUrl(url) {
13
13
  try {
14
14
  parsed = new URL(url);
15
15
  } catch {
16
- throw new chunkENZ4B3I7_cjs.ClawOpsError(`Invalid base_url: ${url}`);
16
+ throw new chunkD25IRY5V_cjs.ClawOpsError(`Invalid base_url: ${url}`);
17
17
  }
18
18
  if (parsed.protocol === "https:") return url;
19
19
  if (parsed.protocol === "http:" && LOCALHOST_HOSTS.has(parsed.hostname)) return url;
20
- throw new chunkENZ4B3I7_cjs.ClawOpsError(
20
+ throw new chunkD25IRY5V_cjs.ClawOpsError(
21
21
  `base_url\uC740 HTTPS\uB97C \uC0AC\uC6A9\uD574\uC57C \uD569\uB2C8\uB2E4 (\uBC1B\uC740 \uAC12: '${url}'). \uB85C\uCEEC \uAC1C\uBC1C \uC2DC\uC5D0\uB294 http://localhost\uB97C \uC0AC\uC6A9\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4.`
22
22
  );
23
23
  }
@@ -30,9 +30,9 @@ var APIClient = class {
30
30
  _defaultHeaders;
31
31
  constructor(options) {
32
32
  this._apiKey = options.apiKey;
33
- this._baseURL = validateBaseUrl((options.baseURL ?? chunkENZ4B3I7_cjs.DEFAULT_BASE_URL).replace(/\/+$/, ""));
34
- this._maxRetries = options.maxRetries ?? chunkENZ4B3I7_cjs.DEFAULT_MAX_RETRIES;
35
- this._timeout = options.timeout ?? chunkENZ4B3I7_cjs.DEFAULT_TIMEOUT;
33
+ this._baseURL = validateBaseUrl((options.baseURL ?? chunkD25IRY5V_cjs.DEFAULT_BASE_URL).replace(/\/+$/, ""));
34
+ this._maxRetries = options.maxRetries ?? chunkD25IRY5V_cjs.DEFAULT_MAX_RETRIES;
35
+ this._timeout = options.timeout ?? chunkD25IRY5V_cjs.DEFAULT_TIMEOUT;
36
36
  this._fetch = options.fetch ?? globalThis.fetch;
37
37
  this._defaultHeaders = options.defaultHeaders ?? {};
38
38
  }
@@ -41,13 +41,13 @@ var APIClient = class {
41
41
  Authorization: `Bearer ${this._apiKey}`,
42
42
  "Content-Type": "application/json",
43
43
  Accept: "application/json",
44
- "User-Agent": `claw-ops-node/${chunkENZ4B3I7_cjs.VERSION}`,
44
+ "User-Agent": `claw-ops-node/${chunkD25IRY5V_cjs.VERSION}`,
45
45
  ...this._defaultHeaders
46
46
  };
47
47
  if (extra) Object.assign(headers, extra);
48
48
  return headers;
49
49
  }
50
- async _request(method2, path, options = {}) {
50
+ async _send(method2, path, options = {}) {
51
51
  const headers = this._buildHeaders(options.extraHeaders);
52
52
  const params = new URLSearchParams();
53
53
  const queryObj = { ...options.query, ...options.extraQuery };
@@ -77,33 +77,18 @@ var APIClient = class {
77
77
  await this._sleep(this._retryDelay(this._maxRetries - retriesLeft));
78
78
  continue;
79
79
  }
80
- throw new chunkENZ4B3I7_cjs.APITimeoutError({ method: method2, url });
80
+ throw new chunkD25IRY5V_cjs.APITimeoutError({ method: method2, url });
81
81
  }
82
82
  if (retriesLeft > 0) {
83
83
  retriesLeft--;
84
84
  await this._sleep(this._retryDelay(this._maxRetries - retriesLeft));
85
85
  continue;
86
86
  }
87
- throw new chunkENZ4B3I7_cjs.APIConnectionError({ method: method2, url });
87
+ throw new chunkD25IRY5V_cjs.APIConnectionError({ method: method2, url });
88
88
  } finally {
89
89
  clearTimeout(timeoutId);
90
90
  }
91
- if (response.ok) {
92
- if (response.status === 204 || !options.castTo) {
93
- return null;
94
- }
95
- let json;
96
- try {
97
- json = await response.json();
98
- } catch {
99
- throw new chunkENZ4B3I7_cjs.APIResponseValidationError({ status: response.status }, { method: method2, url });
100
- }
101
- const parsed = options.castTo.safeParse(json);
102
- if (!parsed.success) {
103
- throw new chunkENZ4B3I7_cjs.APIResponseValidationError({ status: response.status }, { method: method2, url });
104
- }
105
- return parsed.data;
106
- }
91
+ if (response.ok) return response;
107
92
  if (retriesLeft > 0 && this._shouldRetry(response.status)) {
108
93
  retriesLeft--;
109
94
  await this._sleep(this._retryDelay(this._maxRetries - retriesLeft));
@@ -115,14 +100,30 @@ var APIClient = class {
115
100
  } catch {
116
101
  body = null;
117
102
  }
118
- throw chunkENZ4B3I7_cjs.makeStatusError(response.status, body, response.headers, { method: method2, url });
103
+ throw chunkD25IRY5V_cjs.makeStatusError(response.status, body, response.headers, { method: method2, url });
119
104
  }
120
105
  }
106
+ async _request(method2, path, options = {}) {
107
+ const response = await this._send(method2, path, options);
108
+ if (response.status === 204 || !options.castTo) return null;
109
+ const url = `${this._baseURL}${path}`;
110
+ let json;
111
+ try {
112
+ json = await response.json();
113
+ } catch {
114
+ throw new chunkD25IRY5V_cjs.APIResponseValidationError({ status: response.status }, { method: method2, url });
115
+ }
116
+ const parsed = options.castTo.safeParse(json);
117
+ if (!parsed.success) {
118
+ throw new chunkD25IRY5V_cjs.APIResponseValidationError({ status: response.status }, { method: method2, url });
119
+ }
120
+ return parsed.data;
121
+ }
121
122
  _shouldRetry(status) {
122
123
  return status === 408 || status === 409 || status === 429 || status >= 500;
123
124
  }
124
125
  _retryDelay(retriesTaken) {
125
- const delay = Math.min(chunkENZ4B3I7_cjs.INITIAL_RETRY_DELAY * 2 ** retriesTaken, chunkENZ4B3I7_cjs.MAX_RETRY_DELAY);
126
+ const delay = Math.min(chunkD25IRY5V_cjs.INITIAL_RETRY_DELAY * 2 ** retriesTaken, chunkD25IRY5V_cjs.MAX_RETRY_DELAY);
126
127
  return delay * (1 + Math.random());
127
128
  }
128
129
  _sleep(ms) {
@@ -140,6 +141,9 @@ var APIClient = class {
140
141
  const result = await this._request("PUT", path, options);
141
142
  return result;
142
143
  }
144
+ async _getRaw(path, options = {}) {
145
+ return this._send("GET", path, options);
146
+ }
143
147
  async _delete(path, options = {}) {
144
148
  await this._request("DELETE", path, options);
145
149
  }
@@ -236,6 +240,74 @@ var Page = class _Page {
236
240
  }
237
241
  }
238
242
  };
243
+ var AssignmentLinkAssignmentSchema = zod.z.object({
244
+ number: zod.z.string(),
245
+ name: zod.z.string().nullable().optional(),
246
+ consumedAt: zod.z.string(),
247
+ releasedAt: zod.z.string().nullable().optional()
248
+ }).passthrough();
249
+ var AssignmentLinkSchema = zod.z.object({
250
+ linkId: zod.z.string(),
251
+ url: zod.z.string(),
252
+ status: zod.z.enum(["pending", "consumed", "expired", "revoked"]),
253
+ createdAt: zod.z.string(),
254
+ expiresAt: zod.z.string(),
255
+ consumedAt: zod.z.string().nullable().optional(),
256
+ webhookUrl: zod.z.string().nullable().optional(),
257
+ webhookMethod: zod.z.enum(["POST", "GET"]).nullable().optional(),
258
+ note: zod.z.string().nullable().optional(),
259
+ assignment: AssignmentLinkAssignmentSchema.nullable().optional()
260
+ }).passthrough();
261
+ var AssignmentLinkCreateResponseSchema = zod.z.object({
262
+ token: zod.z.string(),
263
+ url: zod.z.string(),
264
+ expiresAt: zod.z.string()
265
+ }).passthrough();
266
+
267
+ // src/resources/assignment-links.ts
268
+ var AssignmentLinks = class extends APIResource {
269
+ async create(params = {}, options = {}) {
270
+ const body = stripNotGiven({
271
+ webhookUrl: params.webhookUrl,
272
+ webhookMethod: params.webhookMethod,
273
+ note: params.note
274
+ });
275
+ return this._client._post(`${this._basePath}/assignment-links`, {
276
+ body: Object.keys(body).length ? body : void 0,
277
+ castTo: AssignmentLinkCreateResponseSchema,
278
+ ...options
279
+ });
280
+ }
281
+ async list(params = {}, options = {}) {
282
+ const query = stripNotGiven({
283
+ status: params.status,
284
+ page: params.page,
285
+ pageSize: params.pageSize
286
+ });
287
+ const path = `${this._basePath}/assignment-links`;
288
+ const schema = PageSchema(AssignmentLinkSchema);
289
+ const raw = await this._client._get(path, {
290
+ castTo: schema,
291
+ query: Object.keys(query).length ? query : void 0,
292
+ ...options
293
+ });
294
+ const page = new Page(raw.data, raw.meta);
295
+ page._setClient(this._client, path, AssignmentLinkSchema, query);
296
+ return page;
297
+ }
298
+ async retrieve(linkId, options = {}) {
299
+ return this._client._get(`${this._basePath}/assignment-links/${linkId}`, {
300
+ castTo: AssignmentLinkSchema,
301
+ ...options
302
+ });
303
+ }
304
+ async revoke(linkId, options = {}) {
305
+ await this._client._delete(
306
+ `${this._basePath}/assignment-links/${linkId}`,
307
+ options
308
+ );
309
+ }
310
+ };
239
311
  var CallSchema = zod.z.object({
240
312
  callId: zod.z.string(),
241
313
  status: zod.z.enum(["queued", "ringing", "in-progress", "completed", "failed"]),
@@ -243,6 +315,7 @@ var CallSchema = zod.z.object({
243
315
  from: zod.z.string(),
244
316
  direction: zod.z.enum(["outbound", "inbound"]),
245
317
  duration: zod.z.number().nullable().optional(),
318
+ recordingUrl: zod.z.string().nullable().optional(),
246
319
  accountId: zod.z.string(),
247
320
  dateCreated: zod.z.string(),
248
321
  dateUpdated: zod.z.string().nullable().optional()
@@ -487,6 +560,44 @@ var Numbers = class extends APIResource {
487
560
  await this._client._delete(`${this._basePath}/numbers/${number}`, options);
488
561
  }
489
562
  };
563
+
564
+ // src/resources/recordings.ts
565
+ function parseFilename(disposition) {
566
+ if (!disposition) return null;
567
+ const star = disposition.match(/filename\*=(?:[\w-]+'[^']*')?([^;]+)/i);
568
+ if (star) {
569
+ try {
570
+ return decodeURIComponent(star[1].trim());
571
+ } catch {
572
+ }
573
+ }
574
+ const quoted = disposition.match(/filename="([^"]+)"/i);
575
+ if (quoted) return quoted[1].trim();
576
+ const bare = disposition.match(/filename=([^;]+)/i);
577
+ return bare ? bare[1].trim() : null;
578
+ }
579
+ var Recordings = class extends APIResource {
580
+ /**
581
+ * 통화 녹음(WAV)을 다운로드합니다.
582
+ *
583
+ * 콘솔과 동일한 서버측 MixMonitor 원본 (PCM 16bit mono 8kHz).
584
+ *
585
+ * @throws NotFoundError (404) — 통화가 없거나 녹음이 없음(`recordingUrl: null`).
586
+ * @throws PermissionDeniedError (403) — accountId 불일치.
587
+ */
588
+ async download(callId, options = {}) {
589
+ const response = await this._client._getRaw(
590
+ `${this._basePath}/recordings/${callId}`,
591
+ options
592
+ );
593
+ const data = await response.arrayBuffer();
594
+ return {
595
+ data,
596
+ contentType: response.headers.get("content-type") ?? "audio/wav",
597
+ filename: parseFilename(response.headers.get("content-disposition"))
598
+ };
599
+ }
600
+ };
490
601
  var WebhookLogSchema = zod.z.object({
491
602
  id: zod.z.string(),
492
603
  webhookId: zod.z.string(),
@@ -537,11 +648,17 @@ var AccountContext = class {
537
648
  get numbers() {
538
649
  return new Numbers(this._client, this._accountId);
539
650
  }
651
+ get recordings() {
652
+ return new Recordings(this._client, this._accountId);
653
+ }
540
654
  get webhookLogs() {
541
655
  return new WebhookLogs(this._client, this._accountId);
542
656
  }
657
+ get assignmentLinks() {
658
+ return new AssignmentLinks(this._client, this._accountId);
659
+ }
543
660
  };
544
- var WebhookVerificationError = class extends chunkENZ4B3I7_cjs.ClawOpsError {
661
+ var WebhookVerificationError = class extends chunkD25IRY5V_cjs.ClawOpsError {
545
662
  constructor(message = "Webhook \uC11C\uBA85\uC774 \uC77C\uCE58\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.") {
546
663
  super(message);
547
664
  this.name = "WebhookVerificationError";
@@ -571,13 +688,13 @@ var ClawOps = class extends APIClient {
571
688
  constructor(options = {}) {
572
689
  let apiKey = options.apiKey ?? process.env.CLAWOPS_API_KEY;
573
690
  if (!apiKey) {
574
- throw new chunkENZ4B3I7_cjs.ClawOpsError("apiKey\uB97C \uC9C0\uC815\uD558\uAC70\uB098 CLAWOPS_API_KEY \uD658\uACBD\uBCC0\uC218\uB97C \uC124\uC815\uD558\uC138\uC694.");
691
+ throw new chunkD25IRY5V_cjs.ClawOpsError("apiKey\uB97C \uC9C0\uC815\uD558\uAC70\uB098 CLAWOPS_API_KEY \uD658\uACBD\uBCC0\uC218\uB97C \uC124\uC815\uD558\uC138\uC694.");
575
692
  }
576
693
  let accountId = options.accountId ?? process.env.CLAWOPS_ACCOUNT_ID;
577
694
  if (!accountId) {
578
- throw new chunkENZ4B3I7_cjs.ClawOpsError("accountId\uB97C \uC9C0\uC815\uD558\uAC70\uB098 CLAWOPS_ACCOUNT_ID \uD658\uACBD\uBCC0\uC218\uB97C \uC124\uC815\uD558\uC138\uC694.");
695
+ throw new chunkD25IRY5V_cjs.ClawOpsError("accountId\uB97C \uC9C0\uC815\uD558\uAC70\uB098 CLAWOPS_ACCOUNT_ID \uD658\uACBD\uBCC0\uC218\uB97C \uC124\uC815\uD558\uC138\uC694.");
579
696
  }
580
- const baseURL = options.baseURL ?? process.env.CLAWOPS_BASE_URL ?? chunkENZ4B3I7_cjs.DEFAULT_BASE_URL;
697
+ const baseURL = options.baseURL ?? process.env.CLAWOPS_BASE_URL ?? chunkD25IRY5V_cjs.DEFAULT_BASE_URL;
581
698
  super({
582
699
  apiKey,
583
700
  baseURL,
@@ -597,9 +714,15 @@ var ClawOps = class extends APIClient {
597
714
  get numbers() {
598
715
  return new Numbers(this, this._defaultAccountId);
599
716
  }
717
+ get recordings() {
718
+ return new Recordings(this, this._defaultAccountId);
719
+ }
600
720
  get webhookLogs() {
601
721
  return new WebhookLogs(this, this._defaultAccountId);
602
722
  }
723
+ get assignmentLinks() {
724
+ return new AssignmentLinks(this, this._defaultAccountId);
725
+ }
603
726
  get webhooks() {
604
727
  return new Webhooks();
605
728
  }
@@ -613,83 +736,85 @@ var client_default_default = ClawOps;
613
736
 
614
737
  Object.defineProperty(exports, "APIConnectionError", {
615
738
  enumerable: true,
616
- get: function () { return chunkENZ4B3I7_cjs.APIConnectionError; }
739
+ get: function () { return chunkD25IRY5V_cjs.APIConnectionError; }
617
740
  });
618
741
  Object.defineProperty(exports, "APIError", {
619
742
  enumerable: true,
620
- get: function () { return chunkENZ4B3I7_cjs.APIError; }
743
+ get: function () { return chunkD25IRY5V_cjs.APIError; }
621
744
  });
622
745
  Object.defineProperty(exports, "APIResponseValidationError", {
623
746
  enumerable: true,
624
- get: function () { return chunkENZ4B3I7_cjs.APIResponseValidationError; }
747
+ get: function () { return chunkD25IRY5V_cjs.APIResponseValidationError; }
625
748
  });
626
749
  Object.defineProperty(exports, "APIStatusError", {
627
750
  enumerable: true,
628
- get: function () { return chunkENZ4B3I7_cjs.APIStatusError; }
751
+ get: function () { return chunkD25IRY5V_cjs.APIStatusError; }
629
752
  });
630
753
  Object.defineProperty(exports, "APITimeoutError", {
631
754
  enumerable: true,
632
- get: function () { return chunkENZ4B3I7_cjs.APITimeoutError; }
755
+ get: function () { return chunkD25IRY5V_cjs.APITimeoutError; }
633
756
  });
634
757
  Object.defineProperty(exports, "AgentConnectionError", {
635
758
  enumerable: true,
636
- get: function () { return chunkENZ4B3I7_cjs.AgentConnectionError; }
759
+ get: function () { return chunkD25IRY5V_cjs.AgentConnectionError; }
637
760
  });
638
761
  Object.defineProperty(exports, "AgentError", {
639
762
  enumerable: true,
640
- get: function () { return chunkENZ4B3I7_cjs.AgentError; }
763
+ get: function () { return chunkD25IRY5V_cjs.AgentError; }
641
764
  });
642
765
  Object.defineProperty(exports, "AuthenticationError", {
643
766
  enumerable: true,
644
- get: function () { return chunkENZ4B3I7_cjs.AuthenticationError; }
767
+ get: function () { return chunkD25IRY5V_cjs.AuthenticationError; }
645
768
  });
646
769
  Object.defineProperty(exports, "BadRequestError", {
647
770
  enumerable: true,
648
- get: function () { return chunkENZ4B3I7_cjs.BadRequestError; }
771
+ get: function () { return chunkD25IRY5V_cjs.BadRequestError; }
649
772
  });
650
773
  Object.defineProperty(exports, "ClawOpsError", {
651
774
  enumerable: true,
652
- get: function () { return chunkENZ4B3I7_cjs.ClawOpsError; }
775
+ get: function () { return chunkD25IRY5V_cjs.ClawOpsError; }
653
776
  });
654
777
  Object.defineProperty(exports, "ConflictError", {
655
778
  enumerable: true,
656
- get: function () { return chunkENZ4B3I7_cjs.ConflictError; }
779
+ get: function () { return chunkD25IRY5V_cjs.ConflictError; }
657
780
  });
658
781
  Object.defineProperty(exports, "InternalServerError", {
659
782
  enumerable: true,
660
- get: function () { return chunkENZ4B3I7_cjs.InternalServerError; }
783
+ get: function () { return chunkD25IRY5V_cjs.InternalServerError; }
661
784
  });
662
785
  Object.defineProperty(exports, "NotFoundError", {
663
786
  enumerable: true,
664
- get: function () { return chunkENZ4B3I7_cjs.NotFoundError; }
787
+ get: function () { return chunkD25IRY5V_cjs.NotFoundError; }
665
788
  });
666
789
  Object.defineProperty(exports, "PermissionDeniedError", {
667
790
  enumerable: true,
668
- get: function () { return chunkENZ4B3I7_cjs.PermissionDeniedError; }
791
+ get: function () { return chunkD25IRY5V_cjs.PermissionDeniedError; }
669
792
  });
670
793
  Object.defineProperty(exports, "RateLimitError", {
671
794
  enumerable: true,
672
- get: function () { return chunkENZ4B3I7_cjs.RateLimitError; }
795
+ get: function () { return chunkD25IRY5V_cjs.RateLimitError; }
673
796
  });
674
797
  Object.defineProperty(exports, "ServiceUnavailableError", {
675
798
  enumerable: true,
676
- get: function () { return chunkENZ4B3I7_cjs.ServiceUnavailableError; }
799
+ get: function () { return chunkD25IRY5V_cjs.ServiceUnavailableError; }
677
800
  });
678
801
  Object.defineProperty(exports, "UnprocessableEntityError", {
679
802
  enumerable: true,
680
- get: function () { return chunkENZ4B3I7_cjs.UnprocessableEntityError; }
803
+ get: function () { return chunkD25IRY5V_cjs.UnprocessableEntityError; }
681
804
  });
682
805
  Object.defineProperty(exports, "VERSION", {
683
806
  enumerable: true,
684
- get: function () { return chunkENZ4B3I7_cjs.VERSION; }
807
+ get: function () { return chunkD25IRY5V_cjs.VERSION; }
685
808
  });
686
809
  exports.APIClient = APIClient;
687
810
  exports.AccountContext = AccountContext;
811
+ exports.AssignmentLinks = AssignmentLinks;
688
812
  exports.Calls = Calls;
689
813
  exports.ClawOps = ClawOps;
690
814
  exports.Messages = Messages;
691
815
  exports.Numbers = Numbers;
692
816
  exports.Page = Page;
817
+ exports.Recordings = Recordings;
693
818
  exports.WebhookLogs = WebhookLogs;
694
819
  exports.WebhookVerificationError = WebhookVerificationError;
695
820
  exports.Webhooks = Webhooks;