@cstar.help/js 0.17.5 → 0.18.1
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 +43 -25
- package/dist/auth/index.cjs +220 -21
- package/dist/auth/index.d.cts +83 -31
- package/dist/auth/index.d.ts +83 -31
- package/dist/auth/index.js +210 -21
- package/dist/chat/index.cjs +134 -22
- package/dist/chat/index.d.cts +32 -4
- package/dist/chat/index.d.ts +32 -4
- package/dist/chat/index.js +134 -22
- package/dist/index.cjs +101 -40
- package/dist/index.d.cts +477 -157
- package/dist/index.d.ts +477 -157
- package/dist/index.js +101 -40
- package/dist/proactive/index.cjs +46 -33
- package/dist/proactive/index.js +45 -34
- package/dist/webhook/index.d.cts +1 -1
- package/dist/webhook/index.d.ts +1 -1
- package/dist/webhook/node.d.cts +1 -1
- package/dist/webhook/node.d.ts +1 -1
- package/dist/{webhookEvents-1N2i2GcQ.d.cts → webhookEvents-Lqpsj935.d.cts} +0 -1
- package/dist/{webhookEvents-1N2i2GcQ.d.ts → webhookEvents-Lqpsj935.d.ts} +0 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -278,7 +278,7 @@ function parseError(statusCode, body, retryAfter) {
|
|
|
278
278
|
}
|
|
279
279
|
|
|
280
280
|
// src/client.ts
|
|
281
|
-
var SDK_VERSION = "0.
|
|
281
|
+
var SDK_VERSION = "0.18.1";
|
|
282
282
|
var DEFAULT_BASE_URL = "https://www.cstar.help";
|
|
283
283
|
var DEFAULT_API_VERSION = "2026-03-01";
|
|
284
284
|
var DEFAULT_MAX_RETRIES = 3;
|
|
@@ -298,7 +298,7 @@ var HttpClient = class {
|
|
|
298
298
|
this.lastMeta = { requestId: null, timestamp: null, pagination: null };
|
|
299
299
|
if (!config || typeof config.apiKey !== "string" || config.apiKey.length === 0) {
|
|
300
300
|
throw new Error(
|
|
301
|
-
"[cStar] CStarClient: apiKey is required. Pass a secret key (sk_live_... / sk_test_...)
|
|
301
|
+
"[cStar] CStarClient: apiKey is required. Pass a secret key (sk_live_... / sk_test_...). Publishable keys (pk_...) cannot read team endpoints; use them with LibraryClient or CommunityClient. See https://cstar.help/developers/quickstart"
|
|
302
302
|
);
|
|
303
303
|
}
|
|
304
304
|
if (typeof config.teamId !== "string" || config.teamId.length === 0) {
|
|
@@ -357,10 +357,12 @@ var HttpClient = class {
|
|
|
357
357
|
const body = options?.body ? JSON.stringify(options.body) : void 0;
|
|
358
358
|
const canRetryAmbiguousFailure = !["POST", "PATCH"].includes(method.toUpperCase()) || !!options?.idempotencyKey;
|
|
359
359
|
let lastError = null;
|
|
360
|
+
const RATE_LIMIT_RETRY_CAP_MS = 6e4;
|
|
361
|
+
let inProgressWaitMs = null;
|
|
360
362
|
for (let attempt = 0; attempt <= this.config.maxRetries; attempt++) {
|
|
361
363
|
if (attempt > 0 && lastError) {
|
|
362
|
-
const
|
|
363
|
-
|
|
364
|
+
const delay = inProgressWaitMs ?? (lastError instanceof CStarRateLimitError ? Math.min(lastError.retryAfter * 1e3, RATE_LIMIT_RETRY_CAP_MS) : this.getBackoffDelay(attempt));
|
|
365
|
+
inProgressWaitMs = null;
|
|
364
366
|
await this.sleep(delay);
|
|
365
367
|
}
|
|
366
368
|
let response;
|
|
@@ -400,6 +402,14 @@ var HttpClient = class {
|
|
|
400
402
|
if (requestId && errorBody?.error) {
|
|
401
403
|
errorBody.error.request_id = requestId;
|
|
402
404
|
}
|
|
405
|
+
if (response.status === 409 && options?.idempotencyKey && errorBody?.error?.code === "idempotency_key_in_use" && retryAfter !== void 0) {
|
|
406
|
+
lastError = parseError(409, errorBody, retryAfter);
|
|
407
|
+
if (attempt < this.config.maxRetries) {
|
|
408
|
+
inProgressWaitMs = Math.min(retryAfter * 1e3, RATE_LIMIT_RETRY_CAP_MS);
|
|
409
|
+
continue;
|
|
410
|
+
}
|
|
411
|
+
throw lastError;
|
|
412
|
+
}
|
|
403
413
|
if (response.status < 500 && response.status !== 429) {
|
|
404
414
|
throw parseError(response.status, errorBody, retryAfter);
|
|
405
415
|
}
|
|
@@ -530,6 +540,8 @@ var CStarRealtime = class {
|
|
|
530
540
|
this.retryTimer = null;
|
|
531
541
|
this._connected = false;
|
|
532
542
|
this.destroyed = false;
|
|
543
|
+
/** The server closed the stream because the API key was revoked or expired. */
|
|
544
|
+
this.revoked = false;
|
|
533
545
|
this.connecting = false;
|
|
534
546
|
/** Short-lived SSE token (exchanged from secret key). */
|
|
535
547
|
this.sseToken = null;
|
|
@@ -605,7 +617,7 @@ var CStarRealtime = class {
|
|
|
605
617
|
}
|
|
606
618
|
/** Start the SSE connection. Called automatically on first handler registration. */
|
|
607
619
|
connect() {
|
|
608
|
-
if (this.eventSource || this.destroyed || this.connecting) return;
|
|
620
|
+
if (this.eventSource || this.destroyed || this.revoked || this.connecting) return;
|
|
609
621
|
if (!this.resolveEventSource()) {
|
|
610
622
|
throw new CStarRealtimeUnavailableError();
|
|
611
623
|
}
|
|
@@ -665,6 +677,7 @@ var CStarRealtime = class {
|
|
|
665
677
|
this.eventSource.close();
|
|
666
678
|
this.eventSource = null;
|
|
667
679
|
}
|
|
680
|
+
if (this.revoked) return;
|
|
668
681
|
if (this.autoReconnect && !this.destroyed && this.retryCount < this.maxRetries) {
|
|
669
682
|
this.scheduleReconnect();
|
|
670
683
|
} else if (this.retryCount >= this.maxRetries) {
|
|
@@ -674,6 +687,9 @@ var CStarRealtime = class {
|
|
|
674
687
|
this.eventSource.onmessage = (event) => {
|
|
675
688
|
this.handleMessage(event);
|
|
676
689
|
};
|
|
690
|
+
this.eventSource.addEventListener("revoked", (event) => {
|
|
691
|
+
this.handleRevoked(event);
|
|
692
|
+
});
|
|
677
693
|
const knownTypes = [
|
|
678
694
|
"ticket.created",
|
|
679
695
|
"ticket.updated",
|
|
@@ -802,6 +818,40 @@ var CStarRealtime = class {
|
|
|
802
818
|
for (const handler of this.connectionHandlers) handler(value);
|
|
803
819
|
}
|
|
804
820
|
}
|
|
821
|
+
handleRevoked(event) {
|
|
822
|
+
if (this.revoked || this.destroyed) return;
|
|
823
|
+
this.revoked = true;
|
|
824
|
+
let body = {};
|
|
825
|
+
try {
|
|
826
|
+
body = JSON.parse(event.data).error ?? {};
|
|
827
|
+
} catch {
|
|
828
|
+
}
|
|
829
|
+
if (this.retryTimer) {
|
|
830
|
+
clearTimeout(this.retryTimer);
|
|
831
|
+
this.retryTimer = null;
|
|
832
|
+
}
|
|
833
|
+
if (this.tokenRefreshTimer) {
|
|
834
|
+
clearTimeout(this.tokenRefreshTimer);
|
|
835
|
+
this.tokenRefreshTimer = null;
|
|
836
|
+
}
|
|
837
|
+
if (this.eventSource) {
|
|
838
|
+
this.eventSource.close();
|
|
839
|
+
this.eventSource = null;
|
|
840
|
+
}
|
|
841
|
+
this.sseToken = null;
|
|
842
|
+
this.sseTokenExpiresAt = 0;
|
|
843
|
+
this.connecting = false;
|
|
844
|
+
this.setConnected(false);
|
|
845
|
+
this.emitError(
|
|
846
|
+
new CStarAuthenticationError(401, {
|
|
847
|
+
type: body.type ?? "authentication_error",
|
|
848
|
+
code: body.code ?? "invalid_api_key",
|
|
849
|
+
message: body.message ?? "This API key was revoked or has expired, so the stream is closed.",
|
|
850
|
+
doc_url: body.doc_url ?? "https://www.cstar.help/developers/errors#invalid_api_key",
|
|
851
|
+
...body.request_id ? { request_id: body.request_id } : {}
|
|
852
|
+
})
|
|
853
|
+
);
|
|
854
|
+
}
|
|
805
855
|
emitError(error) {
|
|
806
856
|
for (const handler of this.errorHandlers) handler(error);
|
|
807
857
|
}
|
|
@@ -1521,11 +1571,17 @@ var SettingsResource = class {
|
|
|
1521
1571
|
async update(params) {
|
|
1522
1572
|
return this.client.request("PATCH", "/settings", { body: params });
|
|
1523
1573
|
}
|
|
1524
|
-
/**
|
|
1574
|
+
/**
|
|
1575
|
+
* Get the chat widget's online hours (outside them the widget shows its
|
|
1576
|
+
* offline message). Not the SLA working hours that SLA deadlines use.
|
|
1577
|
+
*/
|
|
1525
1578
|
async getBusinessHours() {
|
|
1526
1579
|
return this.client.request("GET", "/settings/business-hours");
|
|
1527
1580
|
}
|
|
1528
|
-
/**
|
|
1581
|
+
/**
|
|
1582
|
+
* Update the chat widget's online hours. SLA deadlines don't change:
|
|
1583
|
+
* they follow the SLA working hours in Settings > Business Hours.
|
|
1584
|
+
*/
|
|
1529
1585
|
async updateBusinessHours(params) {
|
|
1530
1586
|
return this.client.request("PATCH", "/settings/business-hours", {
|
|
1531
1587
|
body: params
|
|
@@ -1550,8 +1606,10 @@ var NotificationsResource = class {
|
|
|
1550
1606
|
}
|
|
1551
1607
|
/** List notifications for a user. */
|
|
1552
1608
|
async list(params) {
|
|
1609
|
+
const { unreadOnly, ...query } = params;
|
|
1610
|
+
if (unreadOnly && query.isRead === void 0) query.isRead = false;
|
|
1553
1611
|
return this.client.request("GET", "/notifications", {
|
|
1554
|
-
query
|
|
1612
|
+
query
|
|
1555
1613
|
});
|
|
1556
1614
|
}
|
|
1557
1615
|
/** Get unread notification count for a user. */
|
|
@@ -1625,15 +1683,22 @@ var AttachmentsResource = class {
|
|
|
1625
1683
|
constructor(client) {
|
|
1626
1684
|
this.client = client;
|
|
1627
1685
|
}
|
|
1628
|
-
/** List
|
|
1686
|
+
/** List message files, each with a short-lived signed `url`. */
|
|
1629
1687
|
async list(params) {
|
|
1630
1688
|
return this.client.request("GET", "/attachments", {
|
|
1631
1689
|
query: params
|
|
1632
1690
|
});
|
|
1633
1691
|
}
|
|
1634
|
-
/**
|
|
1635
|
-
|
|
1636
|
-
|
|
1692
|
+
/**
|
|
1693
|
+
* Get a signed download URL, valid for `expiresIn` seconds, for a stored
|
|
1694
|
+
* file. Pass `storagePath` and `bucket` from `list()`.
|
|
1695
|
+
*/
|
|
1696
|
+
async get(storagePath, params) {
|
|
1697
|
+
return this.client.request(
|
|
1698
|
+
"GET",
|
|
1699
|
+
`/attachments/${storagePath}`,
|
|
1700
|
+
params?.bucket ? { query: { bucket: params.bucket } } : void 0
|
|
1701
|
+
);
|
|
1637
1702
|
}
|
|
1638
1703
|
/** Delete an attachment. */
|
|
1639
1704
|
async del(attachmentId) {
|
|
@@ -1649,16 +1714,12 @@ var CustomFieldsResource = class {
|
|
|
1649
1714
|
constructor(client) {
|
|
1650
1715
|
this.client = client;
|
|
1651
1716
|
}
|
|
1652
|
-
/** List custom
|
|
1717
|
+
/** List custom field definitions, optionally for one record type. There is no single-field GET. */
|
|
1653
1718
|
async list(params) {
|
|
1654
1719
|
return this.client.request("GET", "/custom-fields", {
|
|
1655
1720
|
query: params
|
|
1656
1721
|
});
|
|
1657
1722
|
}
|
|
1658
|
-
/** Get a single custom field. */
|
|
1659
|
-
async get(fieldId) {
|
|
1660
|
-
return this.client.request("GET", `/custom-fields/${fieldId}`);
|
|
1661
|
-
}
|
|
1662
1723
|
/** Create a custom field. */
|
|
1663
1724
|
async create(params, options) {
|
|
1664
1725
|
return this.client.request("POST", "/custom-fields", {
|
|
@@ -1693,11 +1754,9 @@ var SlaResource = class {
|
|
|
1693
1754
|
constructor(client) {
|
|
1694
1755
|
this.client = client;
|
|
1695
1756
|
}
|
|
1696
|
-
/** List SLA rules. */
|
|
1697
|
-
async list(
|
|
1698
|
-
return this.client.request("GET", "/sla/rules"
|
|
1699
|
-
query: params
|
|
1700
|
-
});
|
|
1757
|
+
/** List SLA rules in evaluation order. */
|
|
1758
|
+
async list() {
|
|
1759
|
+
return this.client.request("GET", "/sla/rules");
|
|
1701
1760
|
}
|
|
1702
1761
|
/** Create an SLA rule. */
|
|
1703
1762
|
async create(params, options) {
|
|
@@ -1886,25 +1945,28 @@ var TagsResource = class {
|
|
|
1886
1945
|
constructor(client) {
|
|
1887
1946
|
this.client = client;
|
|
1888
1947
|
}
|
|
1889
|
-
/** List
|
|
1948
|
+
/** List tags with usage counts, one row per tag and entity type. */
|
|
1890
1949
|
async list(params) {
|
|
1891
1950
|
return this.client.request("GET", "/tags", {
|
|
1892
1951
|
query: params
|
|
1893
1952
|
});
|
|
1894
1953
|
}
|
|
1895
|
-
/**
|
|
1896
|
-
async
|
|
1954
|
+
/** Replace `fromTag` with `toTag` on every record that carries it. */
|
|
1955
|
+
async merge(params, options) {
|
|
1897
1956
|
return this.client.request("POST", "/tags", {
|
|
1898
|
-
body: {
|
|
1957
|
+
body: { action: "merge", ...params },
|
|
1899
1958
|
idempotencyKey: options?.idempotencyKey
|
|
1900
1959
|
});
|
|
1901
1960
|
}
|
|
1902
|
-
/**
|
|
1903
|
-
async
|
|
1904
|
-
return this.client.request(
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1961
|
+
/** Remove a tag from every record that carries it. */
|
|
1962
|
+
async remove(tag, params) {
|
|
1963
|
+
return this.client.request("DELETE", "/tags", {
|
|
1964
|
+
body: { tag, ...params }
|
|
1965
|
+
});
|
|
1966
|
+
}
|
|
1967
|
+
/** @deprecated Use `remove()`. */
|
|
1968
|
+
async del(tag, params) {
|
|
1969
|
+
return this.remove(tag, params);
|
|
1908
1970
|
}
|
|
1909
1971
|
};
|
|
1910
1972
|
|
|
@@ -2350,7 +2412,7 @@ var ViewsResource = class extends BaseResource {
|
|
|
2350
2412
|
constructor(client) {
|
|
2351
2413
|
super(client, "/views");
|
|
2352
2414
|
}
|
|
2353
|
-
/** Execute a view
|
|
2415
|
+
/** Execute a view and return the filtered results. The server uses the view's entity_type to determine which table to query. */
|
|
2354
2416
|
async execute(viewId, params) {
|
|
2355
2417
|
return this.client.request("GET", `/views/${viewId}/execute`, {
|
|
2356
2418
|
query: params
|
|
@@ -2586,7 +2648,7 @@ var WEBHOOK_EVENT_SAMPLES = {
|
|
|
2586
2648
|
"comment": {
|
|
2587
2649
|
"id": "cmt_01H8X9YZ7E0J3K4M5N6X",
|
|
2588
2650
|
"post_id": "post_01H8X9YZ7E0J3K4M5N6W",
|
|
2589
|
-
"content": "I would love this
|
|
2651
|
+
"content": "I would love this. Bumping for visibility.",
|
|
2590
2652
|
"author_id": "cus_01H8X9YZ7E0J3K4M5N6Q",
|
|
2591
2653
|
"created_at": "2026-04-27T18:55:02.000Z"
|
|
2592
2654
|
}
|
|
@@ -2806,15 +2868,14 @@ var WEBHOOK_EVENT_SAMPLES = {
|
|
|
2806
2868
|
"id": "tkt_01H8X9YZ7E0J3K4M5N6P",
|
|
2807
2869
|
"prefixed_id": "CST-1024",
|
|
2808
2870
|
"title": "Cannot reset password",
|
|
2809
|
-
"status": "
|
|
2871
|
+
"status": "closed",
|
|
2810
2872
|
"priority": "normal",
|
|
2811
|
-
"channel": "widget"
|
|
2812
|
-
"resolved_at": "2026-04-27T19:08:43.000Z"
|
|
2873
|
+
"channel": "widget"
|
|
2813
2874
|
},
|
|
2814
2875
|
"changes": {
|
|
2815
2876
|
"status": {
|
|
2816
2877
|
"from": "open",
|
|
2817
|
-
"to": "
|
|
2878
|
+
"to": "closed"
|
|
2818
2879
|
}
|
|
2819
2880
|
}
|
|
2820
2881
|
},
|
|
@@ -2847,7 +2908,7 @@ var WEBHOOK_EVENT_SAMPLES = {
|
|
|
2847
2908
|
"id": "msg_01H8X9YZ7E0J3K4M5N6R",
|
|
2848
2909
|
"sender": "agent",
|
|
2849
2910
|
"sender_name": "Riley",
|
|
2850
|
-
"content": "I just sent a reset link to your inbox
|
|
2911
|
+
"content": "I just sent a reset link to your inbox. Let me know if it lands.",
|
|
2851
2912
|
"created_at": "2026-04-27T18:55:02.000Z"
|
|
2852
2913
|
},
|
|
2853
2914
|
"customer": {
|
|
@@ -2913,7 +2974,7 @@ var WEBHOOK_EVENT_CATALOG = {
|
|
|
2913
2974
|
"survey.submitted": { label: "Customer Feedback Received", description: "Fired when a customer submits a CSAT survey response", category: "csat" },
|
|
2914
2975
|
"team.preferences_updated": { label: "Team Preferences Updated", description: "Fired when team-wide UX preferences change (e.g., bossBattlesEnabled toggled)", category: "team" },
|
|
2915
2976
|
"ticket.assigned": { label: "Ticket Assigned", description: "Fired when a ticket is assigned to an agent", category: "tickets" },
|
|
2916
|
-
"ticket.closed": { label: "Ticket Closed
|
|
2977
|
+
"ticket.closed": { label: "Ticket Closed", description: "Fired when a ticket's status changes to Closed. Moving a ticket to Resolved sends ticket.updated instead.", category: "tickets" },
|
|
2917
2978
|
"ticket.created": { label: "New Ticket Created", description: "Fired when a new ticket is created via app, widget, API, or email", category: "tickets" },
|
|
2918
2979
|
"ticket.deleted": { label: "Ticket Deleted", description: "Fired when a ticket is deleted via app or API", category: "tickets" },
|
|
2919
2980
|
"ticket.message_added": { label: "New Message on Ticket", description: "Fired when a new message is added to a ticket", category: "tickets" },
|