@curviate/sdk 0.37.0 → 0.38.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 CHANGED
@@ -259,8 +259,11 @@ function defaultSleep(ms) {
259
259
  }
260
260
  function parseRetryAfterMs(header) {
261
261
  if (header == null) return void 0;
262
- const seconds = Number(header);
263
- if (Number.isFinite(seconds) && seconds >= 0) return seconds * 1e3;
262
+ const trimmed = header.trim();
263
+ if (trimmed !== "") {
264
+ const seconds = Number(trimmed);
265
+ if (Number.isFinite(seconds) && seconds >= 0) return seconds * 1e3;
266
+ }
264
267
  return 3e4;
265
268
  }
266
269
  function backoffDelay(n, jitter) {
@@ -404,7 +407,8 @@ async function execute(method, path, opts) {
404
407
  }
405
408
  const err = await errorFromResponse(res);
406
409
  const namesBudgetRow = err.budgetRow !== void 0;
407
- const retryable = !isWrite && !namesBudgetRow && RETRYABLE_CODES.has(err.code) && attempt < opts.maxRetries;
410
+ const neverRetry = err.retryHint?.kind === "never";
411
+ const retryable = !isWrite && !namesBudgetRow && !neverRetry && RETRYABLE_CODES.has(err.code) && attempt < opts.maxRetries;
408
412
  if (retryable) {
409
413
  await sleep(retryDelay(err, attempt + 1, jitterFn()));
410
414
  attempt += 1;
@@ -498,12 +502,19 @@ var AccountsResource = class {
498
502
  * `signatures`, `groups`) populated by an async background enrichment,
499
503
  * `null`/`[]` until the account's first enrichment pass completes.
500
504
  *
501
- * @param params - optional `limit` (1-250) and `cursor` (from a prior page).
505
+ * Each item carries `external_id` (your own id for the account's end user,
506
+ * set on `auth.intent` or `update`) and `metadata`, both `null` when unset.
507
+ *
508
+ * @param params - optional `limit` (1-250), `cursor` (from a prior page), and
509
+ * `external_id` (exact match: only that end user's accounts).
502
510
  * @returns a page of accounts and the next-page `cursor` (null when exhausted).
503
511
  *
504
512
  * @example
505
513
  * const page = await curviate.accounts.list({ limit: 50 });
506
514
  * for (const acc of page.items ?? []) console.log(acc.account_id);
515
+ *
516
+ * @example
517
+ * const { items } = await curviate.accounts.list({ external_id: "usr_42" });
507
518
  */
508
519
  list(params) {
509
520
  return this.ctx.request({
@@ -578,11 +589,18 @@ var AccountsResource = class {
578
589
  /**
579
590
  * Update an account's configuration.
580
591
  *
581
- * `metadata` is a flat string->string map that **replaces** the account's
582
- * custom-data store wholesale (keys not provided are removed). `proxy` sets a
583
- * custom egress proxy, or clears it (reverting to automatic proxy protection)
584
- * when passed as `null`. The `proxy.password`, if given, is stored securely
585
- * and never returned.
592
+ * `external_id` is your own id for the account's end user (1-255 chars, not
593
+ * unique, `null` clears it); treat it as an opaque id, not an email.
594
+ * `metadata` is a flat string->string map (at most 16 keys, key 40 chars,
595
+ * value 500) that **replaces** the stored map wholesale; `null` clears it.
596
+ * Both are stored by Curviate, read back on `get`/`list`, and a PATCH
597
+ * carrying only them makes no LinkedIn call. `proxy` sets a custom egress
598
+ * proxy, or clears it (reverting to automatic proxy protection) when passed
599
+ * as `null`. The `proxy.password`, if given, is stored securely and never
600
+ * returned.
601
+ *
602
+ * @example
603
+ * await curviate.accounts.update("acc_123", { external_id: "usr_42", metadata: { plan: "pro" } });
586
604
  */
587
605
  update(accountId, body) {
588
606
  return this.ctx.request({
@@ -600,6 +618,63 @@ var AccountsResource = class {
600
618
  path: apiPath`/v1/accounts/${accountId}`
601
619
  });
602
620
  }
621
+ /**
622
+ * Buy seats on the workspace's active subscription. Returns the new
623
+ * `seat_ids`; connect an account into one with `auth.intent({ seat_id })`.
624
+ *
625
+ * Every call buys the `qty` it asks for, so a repeated call buys again.
626
+ * The SDK never retries it for you. A
627
+ * `CurviateError(code: "SUBSCRIPTION_BUSY")` (503) means the purchase could
628
+ * not be confirmed while another change was in progress: check the seat
629
+ * count with `listSeats()` before trying again. A trialing workspace
630
+ * throws `CurviateError(code: "TRIAL_ACTIVE_SEAT_LIMIT")`: buy a seat to
631
+ * convert first.
632
+ *
633
+ * @param body - `{ qty }`, 1-50.
634
+ *
635
+ * @example
636
+ * const { seat_ids } = await curviate.accounts.addSeats({ qty: 1 });
637
+ */
638
+ addSeats(body) {
639
+ return this.ctx.request({ method: "POST", path: "/v1/billing/seats/add", body });
640
+ }
641
+ /**
642
+ * Schedule a seat's cancellation at the end of the current period.
643
+ * `effective_at` is when access ends; until then the seat keeps working
644
+ * and `revertSeatCancellation()` can undo it. Repeating the call on an
645
+ * already-scheduled seat returns the same `effective_at`; a seat whose
646
+ * cancellation already took effect throws
647
+ * `CurviateError(code: "ALREADY_CANCELLED")`.
648
+ *
649
+ * @param seatId - a `seat_...` id from `listSeats()`.
650
+ *
651
+ * @example
652
+ * const { effective_at } = await curviate.accounts.cancelSeat("seat_123");
653
+ */
654
+ cancelSeat(seatId) {
655
+ return this.ctx.request({
656
+ method: "POST",
657
+ path: apiPath`/v1/billing/seats/${seatId}/cancel`
658
+ });
659
+ }
660
+ /**
661
+ * Undo a scheduled seat cancellation before it takes effect. A seat with
662
+ * nothing scheduled (never cancelled, already reverted, or already
663
+ * effective) throws `CurviateError(code: "CANCELLATION_ALREADY_EFFECTIVE")`;
664
+ * a seat covered by a whole-subscription cancellation throws
665
+ * `CurviateError(code: "INVALID_CANCELLATION_SOURCE")`.
666
+ *
667
+ * @param seatId - the `seat_...` id passed to `cancelSeat()`.
668
+ *
669
+ * @example
670
+ * await curviate.accounts.revertSeatCancellation("seat_123");
671
+ */
672
+ revertSeatCancellation(seatId) {
673
+ return this.ctx.request({
674
+ method: "POST",
675
+ path: apiPath`/v1/billing/seats/${seatId}/cancel/revert`
676
+ });
677
+ }
603
678
  };
604
679
 
605
680
  // src/resources/auth.ts
@@ -679,20 +754,36 @@ var AuthResource = class {
679
754
  });
680
755
  }
681
756
  /**
682
- * Re-request the pending checkpoint notification (OTP / 2FA / mobile-app
683
- * push). `resent` is honest: `true` once the notification was actually
684
- * re-sent, `false` when there was nothing to re-send for that challenge
685
- * type (e.g. an authenticator-app code); this call never throws just
757
+ * Re-send the pending checkpoint code, or switch its verification method.
758
+ *
759
+ * Without `body`: re-requests the pending notification (OTP / 2FA /
760
+ * mobile-app push) and returns 200 `{ resent }`. `resent` is honest: `true`
761
+ * once the notification was actually re-sent, `false` when there was
762
+ * nothing to re-send for that challenge type (e.g. an authenticator-app
763
+ * code, or a `challenge_selection` checkpoint); this call never throws just
686
764
  * because a re-send wasn't applicable. Does not reset the checkpoint's
687
765
  * expiry.
688
766
  *
767
+ * With `{ challenge }`: answers a `challenge_selection` checkpoint. Pass one
768
+ * `id` from its `challenges` list (`email`, `sms` or `whatsapp`); the
769
+ * response is the next checkpoint (202), which you then solve as usual. An
770
+ * id the checkpoint did not offer throws `CurviateError(code:
771
+ * "INVALID_REQUEST")`.
772
+ *
689
773
  * @param accountId - the (provisional) `account_id` from the 202 response.
774
+ * @param body - optional `{ challenge }` for a `challenge_selection` checkpoint.
775
+ *
776
+ * @example
777
+ * const cp = await curviate.auth.intent({ seat_id, auth_method: "credentials", credentials });
778
+ * if (cp.object === "checkpoint" && cp.challenge_type === "challenge_selection") {
779
+ * const next = await curviate.auth.requestCheckpoint(cp.account_id!, { challenge: cp.challenges![0]!.id });
780
+ * }
690
781
  */
691
- requestCheckpoint(accountId) {
782
+ requestCheckpoint(accountId, body) {
692
783
  return this.ctx.request({
693
784
  method: "POST",
694
785
  path: "/v1/auth/checkpoint/request",
695
- body: { account_id: accountId }
786
+ body: { account_id: accountId, ...body }
696
787
  });
697
788
  }
698
789
  /**
@@ -2865,7 +2956,14 @@ var WebhooksResource = class {
2865
2956
  * Register a new webhook endpoint to receive real-time events.
2866
2957
  * `POST /v1/webhooks`
2867
2958
  * The HMAC signing secret is returned exactly once in the 201 response.
2868
- * `account_ids` is required (each webhook is scoped to specific accounts).
2959
+ * `account_ids` scopes a webhook to specific accounts (`acc_` ids you own)
2960
+ * and is required for `messaging` and `user`. For `account_status` it is
2961
+ * optional: omit it to receive status events for every current and future
2962
+ * account of the workspace (reads then return `account_ids: null`). An
2963
+ * explicit `[]` is rejected.
2964
+ *
2965
+ * @example
2966
+ * await curviate.webhooks.create({ source: "account_status", request_url: "https://example.com/hooks" });
2869
2967
  */
2870
2968
  create(body) {
2871
2969
  return this.ctx.request({
@@ -2911,6 +3009,8 @@ var WebhooksResource = class {
2911
3009
  /**
2912
3010
  * Update a webhook in place. `source` is immutable.
2913
3011
  * `PATCH /v1/webhooks/{id}`
3012
+ * `account_ids: null` switches an `account_status` webhook to every current
3013
+ * and future account.
2914
3014
  */
2915
3015
  update(id, body) {
2916
3016
  return this.ctx.request({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@curviate/sdk",
3
- "version": "0.37.0",
3
+ "version": "0.38.0",
4
4
  "private": false,
5
5
  "description": "TypeScript SDK for the Curviate API.",
6
6
  "license": "MIT",