@cstar.help/js 0.17.4 → 0.18.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/README.md +45 -26
- package/dist/auth/index.cjs +220 -21
- package/dist/auth/index.d.cts +84 -32
- package/dist/auth/index.d.ts +84 -32
- package/dist/auth/index.js +210 -21
- package/dist/chat/index.cjs +131 -20
- package/dist/chat/index.d.cts +32 -4
- package/dist/chat/index.d.ts +32 -4
- package/dist/chat/index.js +131 -20
- package/dist/community/index.d.cts +1 -1
- package/dist/community/index.d.ts +1 -1
- package/dist/errors-bW8CwTn4.d.cts +121 -0
- package/dist/errors-bW8CwTn4.d.ts +121 -0
- package/dist/index.cjs +94 -41
- package/dist/index.d.cts +454 -153
- package/dist/index.d.ts +454 -153
- package/dist/index.js +94 -41
- package/dist/library/index.d.cts +1 -1
- package/dist/library/index.d.ts +1 -1
- package/dist/proactive/index.cjs +46 -33
- package/dist/proactive/index.js +45 -34
- package/dist/quickhelp/index.d.cts +1 -1
- package/dist/quickhelp/index.d.ts +1 -1
- 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/errors-b5A4wfAg.d.cts +0 -398
- package/dist/errors-b5A4wfAg.d.ts +0 -398
package/dist/chat/index.d.cts
CHANGED
|
@@ -28,6 +28,11 @@ type ChatAuthMode = 'hmac' | 'session';
|
|
|
28
28
|
interface LoginWithSessionParams {
|
|
29
29
|
/** Supabase access token (JWT). Used as Bearer for every subsequent call. */
|
|
30
30
|
accessToken: string;
|
|
31
|
+
/**
|
|
32
|
+
* Optional: the matching refresh token. When supplied, the client renews
|
|
33
|
+
* an expired access token through `/api/widget/auth/refresh` on a 401.
|
|
34
|
+
*/
|
|
35
|
+
refreshToken?: string;
|
|
31
36
|
/** Optional: the team UUID. If omitted, derived server-side from the token. */
|
|
32
37
|
teamId?: string;
|
|
33
38
|
/** Optional: a hint for the customer name (UI only — server stays authoritative). */
|
|
@@ -132,6 +137,8 @@ interface TicketListResponse {
|
|
|
132
137
|
/** A message on a ticket. */
|
|
133
138
|
interface Message {
|
|
134
139
|
id: string;
|
|
140
|
+
/** Opaque send identity, used to reconcile a reply after an uncertain response. */
|
|
141
|
+
client_request_key?: string | null;
|
|
135
142
|
content: string;
|
|
136
143
|
sender: 'customer' | 'agent';
|
|
137
144
|
sender_name: string;
|
|
@@ -144,6 +151,12 @@ interface Message {
|
|
|
144
151
|
/** Whether this message was sent by an AI agent. */
|
|
145
152
|
is_bot?: boolean;
|
|
146
153
|
}
|
|
154
|
+
/** Options for one logical customer reply, including any retries. */
|
|
155
|
+
interface MessageSendOptions {
|
|
156
|
+
/** Retain for a manual retry of the same ticket, content and attachments. Use a new key for each intentional send. Receipts last 24 hours. */
|
|
157
|
+
idempotencyKey?: string;
|
|
158
|
+
signal?: AbortSignal;
|
|
159
|
+
}
|
|
147
160
|
/** A confirmed customer's message attachment. Never a Storage path or URL. */
|
|
148
161
|
interface CustomerAttachmentReference {
|
|
149
162
|
readonly ticketId: string;
|
|
@@ -170,6 +183,7 @@ interface TicketListParams {
|
|
|
170
183
|
}
|
|
171
184
|
/** Parameters for creating a new ticket. */
|
|
172
185
|
interface TicketCreateParams {
|
|
186
|
+
/** Conversation subject. Subjects over 255 characters are shortened with an ellipsis, never rejected. */
|
|
173
187
|
subject: string;
|
|
174
188
|
message?: string;
|
|
175
189
|
}
|
|
@@ -231,6 +245,8 @@ declare class ChatClientError extends Error {
|
|
|
231
245
|
readonly code: string;
|
|
232
246
|
readonly statusCode: number;
|
|
233
247
|
readonly requestId: string | null;
|
|
248
|
+
/** Customer message send key retained for a manual retry after an uncertain outcome. */
|
|
249
|
+
idempotencyKey?: string;
|
|
234
250
|
constructor(arg: ChatErrorOpts | string);
|
|
235
251
|
}
|
|
236
252
|
/** 401 / 403 — auth failed (bad/expired token, wrong team, etc.). */
|
|
@@ -316,6 +332,8 @@ declare class ChatClient {
|
|
|
316
332
|
private readonly pollingInterval;
|
|
317
333
|
private readonly realtimeEnabled;
|
|
318
334
|
private sessionToken;
|
|
335
|
+
private refreshToken;
|
|
336
|
+
private refreshPromise;
|
|
319
337
|
private teamId;
|
|
320
338
|
private customerId;
|
|
321
339
|
private authMode;
|
|
@@ -429,7 +447,14 @@ declare class ChatClient {
|
|
|
429
447
|
signal?: AbortSignal;
|
|
430
448
|
cache?: RequestCache;
|
|
431
449
|
readBody?: (response: Response) => Promise<T>;
|
|
432
|
-
|
|
450
|
+
idempotencyKey?: string;
|
|
451
|
+
}, retriedAfterRefresh?: boolean): Promise<T>;
|
|
452
|
+
/**
|
|
453
|
+
* Renew the access token with the stored refresh token. Concurrent 401s
|
|
454
|
+
* share one refresh. Resolves true when a newer token is in place.
|
|
455
|
+
*/
|
|
456
|
+
private refreshSession;
|
|
457
|
+
private requestRefresh;
|
|
433
458
|
/**
|
|
434
459
|
* Look up the team UUID from the configured `teamSlug`. Used by
|
|
435
460
|
* `loginWithCredentials`. HMAC integrators (`identify()`) never hit
|
|
@@ -501,8 +526,11 @@ declare class MessagesApi {
|
|
|
501
526
|
constructor(chat: ChatClient);
|
|
502
527
|
/** List messages for a ticket. */
|
|
503
528
|
list(ticketId: string): Promise<Message[]>;
|
|
504
|
-
/**
|
|
505
|
-
|
|
529
|
+
/**
|
|
530
|
+
* Send one logical reply. Network and server failures retry twice with the
|
|
531
|
+
* same key. A separate send call is a new intent unless a retained key is supplied.
|
|
532
|
+
*/
|
|
533
|
+
send(ticketId: string, content: string, options?: MessageSendOptions): Promise<Message>;
|
|
506
534
|
}
|
|
507
535
|
|
|
508
|
-
export { type AttachmentDownloadOptions, type ChatAuthMode, ChatClient, ChatClientAuthError, ChatClientError, ChatClientNetworkError, ChatClientRateLimitError, ChatClientServerError, type ChatConfig, type ChatStateListener, type CustomerAttachmentReference, type DownloadedAttachment, type IdentifyParams, type IdentifyResult, type LoginWithCredentialsParams, type LoginWithCredentialsResult, type LoginWithSessionParams, type Message, type MessageCallback, type RealtimeTokenResponse, type Ticket, type TicketCreateParams, type TicketListParams, type TicketListResponse, type TypingCallback, type TypingPayload };
|
|
536
|
+
export { type AttachmentDownloadOptions, type ChatAuthMode, ChatClient, ChatClientAuthError, ChatClientError, ChatClientNetworkError, ChatClientRateLimitError, ChatClientServerError, type ChatConfig, type ChatStateListener, type CustomerAttachmentReference, type DownloadedAttachment, type IdentifyParams, type IdentifyResult, type LoginWithCredentialsParams, type LoginWithCredentialsResult, type LoginWithSessionParams, type Message, type MessageCallback, type MessageSendOptions, type RealtimeTokenResponse, type Ticket, type TicketCreateParams, type TicketListParams, type TicketListResponse, type TypingCallback, type TypingPayload };
|
package/dist/chat/index.d.ts
CHANGED
|
@@ -28,6 +28,11 @@ type ChatAuthMode = 'hmac' | 'session';
|
|
|
28
28
|
interface LoginWithSessionParams {
|
|
29
29
|
/** Supabase access token (JWT). Used as Bearer for every subsequent call. */
|
|
30
30
|
accessToken: string;
|
|
31
|
+
/**
|
|
32
|
+
* Optional: the matching refresh token. When supplied, the client renews
|
|
33
|
+
* an expired access token through `/api/widget/auth/refresh` on a 401.
|
|
34
|
+
*/
|
|
35
|
+
refreshToken?: string;
|
|
31
36
|
/** Optional: the team UUID. If omitted, derived server-side from the token. */
|
|
32
37
|
teamId?: string;
|
|
33
38
|
/** Optional: a hint for the customer name (UI only — server stays authoritative). */
|
|
@@ -132,6 +137,8 @@ interface TicketListResponse {
|
|
|
132
137
|
/** A message on a ticket. */
|
|
133
138
|
interface Message {
|
|
134
139
|
id: string;
|
|
140
|
+
/** Opaque send identity, used to reconcile a reply after an uncertain response. */
|
|
141
|
+
client_request_key?: string | null;
|
|
135
142
|
content: string;
|
|
136
143
|
sender: 'customer' | 'agent';
|
|
137
144
|
sender_name: string;
|
|
@@ -144,6 +151,12 @@ interface Message {
|
|
|
144
151
|
/** Whether this message was sent by an AI agent. */
|
|
145
152
|
is_bot?: boolean;
|
|
146
153
|
}
|
|
154
|
+
/** Options for one logical customer reply, including any retries. */
|
|
155
|
+
interface MessageSendOptions {
|
|
156
|
+
/** Retain for a manual retry of the same ticket, content and attachments. Use a new key for each intentional send. Receipts last 24 hours. */
|
|
157
|
+
idempotencyKey?: string;
|
|
158
|
+
signal?: AbortSignal;
|
|
159
|
+
}
|
|
147
160
|
/** A confirmed customer's message attachment. Never a Storage path or URL. */
|
|
148
161
|
interface CustomerAttachmentReference {
|
|
149
162
|
readonly ticketId: string;
|
|
@@ -170,6 +183,7 @@ interface TicketListParams {
|
|
|
170
183
|
}
|
|
171
184
|
/** Parameters for creating a new ticket. */
|
|
172
185
|
interface TicketCreateParams {
|
|
186
|
+
/** Conversation subject. Subjects over 255 characters are shortened with an ellipsis, never rejected. */
|
|
173
187
|
subject: string;
|
|
174
188
|
message?: string;
|
|
175
189
|
}
|
|
@@ -231,6 +245,8 @@ declare class ChatClientError extends Error {
|
|
|
231
245
|
readonly code: string;
|
|
232
246
|
readonly statusCode: number;
|
|
233
247
|
readonly requestId: string | null;
|
|
248
|
+
/** Customer message send key retained for a manual retry after an uncertain outcome. */
|
|
249
|
+
idempotencyKey?: string;
|
|
234
250
|
constructor(arg: ChatErrorOpts | string);
|
|
235
251
|
}
|
|
236
252
|
/** 401 / 403 — auth failed (bad/expired token, wrong team, etc.). */
|
|
@@ -316,6 +332,8 @@ declare class ChatClient {
|
|
|
316
332
|
private readonly pollingInterval;
|
|
317
333
|
private readonly realtimeEnabled;
|
|
318
334
|
private sessionToken;
|
|
335
|
+
private refreshToken;
|
|
336
|
+
private refreshPromise;
|
|
319
337
|
private teamId;
|
|
320
338
|
private customerId;
|
|
321
339
|
private authMode;
|
|
@@ -429,7 +447,14 @@ declare class ChatClient {
|
|
|
429
447
|
signal?: AbortSignal;
|
|
430
448
|
cache?: RequestCache;
|
|
431
449
|
readBody?: (response: Response) => Promise<T>;
|
|
432
|
-
|
|
450
|
+
idempotencyKey?: string;
|
|
451
|
+
}, retriedAfterRefresh?: boolean): Promise<T>;
|
|
452
|
+
/**
|
|
453
|
+
* Renew the access token with the stored refresh token. Concurrent 401s
|
|
454
|
+
* share one refresh. Resolves true when a newer token is in place.
|
|
455
|
+
*/
|
|
456
|
+
private refreshSession;
|
|
457
|
+
private requestRefresh;
|
|
433
458
|
/**
|
|
434
459
|
* Look up the team UUID from the configured `teamSlug`. Used by
|
|
435
460
|
* `loginWithCredentials`. HMAC integrators (`identify()`) never hit
|
|
@@ -501,8 +526,11 @@ declare class MessagesApi {
|
|
|
501
526
|
constructor(chat: ChatClient);
|
|
502
527
|
/** List messages for a ticket. */
|
|
503
528
|
list(ticketId: string): Promise<Message[]>;
|
|
504
|
-
/**
|
|
505
|
-
|
|
529
|
+
/**
|
|
530
|
+
* Send one logical reply. Network and server failures retry twice with the
|
|
531
|
+
* same key. A separate send call is a new intent unless a retained key is supplied.
|
|
532
|
+
*/
|
|
533
|
+
send(ticketId: string, content: string, options?: MessageSendOptions): Promise<Message>;
|
|
506
534
|
}
|
|
507
535
|
|
|
508
|
-
export { type AttachmentDownloadOptions, type ChatAuthMode, ChatClient, ChatClientAuthError, ChatClientError, ChatClientNetworkError, ChatClientRateLimitError, ChatClientServerError, type ChatConfig, type ChatStateListener, type CustomerAttachmentReference, type DownloadedAttachment, type IdentifyParams, type IdentifyResult, type LoginWithCredentialsParams, type LoginWithCredentialsResult, type LoginWithSessionParams, type Message, type MessageCallback, type RealtimeTokenResponse, type Ticket, type TicketCreateParams, type TicketListParams, type TicketListResponse, type TypingCallback, type TypingPayload };
|
|
536
|
+
export { type AttachmentDownloadOptions, type ChatAuthMode, ChatClient, ChatClientAuthError, ChatClientError, ChatClientNetworkError, ChatClientRateLimitError, ChatClientServerError, type ChatConfig, type ChatStateListener, type CustomerAttachmentReference, type DownloadedAttachment, type IdentifyParams, type IdentifyResult, type LoginWithCredentialsParams, type LoginWithCredentialsResult, type LoginWithSessionParams, type Message, type MessageCallback, type MessageSendOptions, type RealtimeTokenResponse, type Ticket, type TicketCreateParams, type TicketListParams, type TicketListResponse, type TypingCallback, type TypingPayload };
|
package/dist/chat/index.js
CHANGED
|
@@ -434,6 +434,8 @@ var DEFAULT_POLLING_INTERVAL = 3e3;
|
|
|
434
434
|
var ChatClient = class {
|
|
435
435
|
constructor(config) {
|
|
436
436
|
this.sessionToken = null;
|
|
437
|
+
this.refreshToken = null;
|
|
438
|
+
this.refreshPromise = null;
|
|
437
439
|
this.teamId = null;
|
|
438
440
|
this.customerId = null;
|
|
439
441
|
this.authMode = null;
|
|
@@ -526,6 +528,7 @@ var ChatClient = class {
|
|
|
526
528
|
this.applySession(
|
|
527
529
|
{
|
|
528
530
|
accessToken: response.accessToken,
|
|
531
|
+
refreshToken: response.refreshToken ?? void 0,
|
|
529
532
|
teamId,
|
|
530
533
|
customerName: response.customer.name ?? response.customer.email
|
|
531
534
|
},
|
|
@@ -556,6 +559,7 @@ var ChatClient = class {
|
|
|
556
559
|
applySession(params, generation) {
|
|
557
560
|
this.assertSession(generation);
|
|
558
561
|
this.sessionToken = params.accessToken;
|
|
562
|
+
this.refreshToken = params.refreshToken ?? null;
|
|
559
563
|
if (params.teamId) {
|
|
560
564
|
this.teamId = params.teamId;
|
|
561
565
|
}
|
|
@@ -665,6 +669,8 @@ var ChatClient = class {
|
|
|
665
669
|
this.pollingSubscriptions.clear();
|
|
666
670
|
this.realtimeMessageSubscriptions.clear();
|
|
667
671
|
this.sessionToken = null;
|
|
672
|
+
this.refreshToken = null;
|
|
673
|
+
this.refreshPromise = null;
|
|
668
674
|
this.teamId = null;
|
|
669
675
|
this.customerId = null;
|
|
670
676
|
this.authMode = null;
|
|
@@ -696,7 +702,7 @@ var ChatClient = class {
|
|
|
696
702
|
* the first authenticated round-trip, `getAuthMode()` returns the
|
|
697
703
|
* server-confirmed mode.
|
|
698
704
|
*/
|
|
699
|
-
async fetch(path, options) {
|
|
705
|
+
async fetch(path, options, retriedAfterRefresh = false) {
|
|
700
706
|
const generation = this.sessionGeneration;
|
|
701
707
|
const assertRequest = () => {
|
|
702
708
|
this.assertSession(generation);
|
|
@@ -707,8 +713,10 @@ var ChatClient = class {
|
|
|
707
713
|
const headers = {
|
|
708
714
|
"Content-Type": "application/json"
|
|
709
715
|
};
|
|
710
|
-
if (
|
|
711
|
-
|
|
716
|
+
if (options.idempotencyKey) headers["Idempotency-Key"] = options.idempotencyKey;
|
|
717
|
+
const sentToken = this.sessionToken;
|
|
718
|
+
if (sentToken) {
|
|
719
|
+
headers["Authorization"] = `Bearer ${sentToken}`;
|
|
712
720
|
}
|
|
713
721
|
let response;
|
|
714
722
|
try {
|
|
@@ -736,11 +744,17 @@ var ChatClient = class {
|
|
|
736
744
|
}
|
|
737
745
|
assertRequest();
|
|
738
746
|
const requestId = responseHeaders?.get("X-Request-Id") ?? null;
|
|
747
|
+
if (response.status === 401 && sentToken && this.refreshToken && !retriedAfterRefresh) {
|
|
748
|
+
const refreshed = await this.refreshSession(sentToken);
|
|
749
|
+
assertRequest();
|
|
750
|
+
if (refreshed) return this.fetch(path, options, true);
|
|
751
|
+
}
|
|
739
752
|
if (!response.ok) {
|
|
740
|
-
const errorBody = await response.json().catch(() =>
|
|
753
|
+
const errorBody = await response.json().catch(() => null);
|
|
741
754
|
assertRequest();
|
|
742
|
-
const
|
|
743
|
-
const
|
|
755
|
+
const structured = errorBody?.error && typeof errorBody.error === "object" ? errorBody.error : null;
|
|
756
|
+
const code = structured?.code ?? "UNKNOWN";
|
|
757
|
+
const message = structured?.message ?? (typeof errorBody?.error === "string" ? errorBody.error : null) ?? (typeof errorBody?.message === "string" ? errorBody.message : null) ?? `Widget API error: ${response.status}`;
|
|
744
758
|
if (response.status === 401 || response.status === 403) {
|
|
745
759
|
throw new ChatClientAuthError({
|
|
746
760
|
message,
|
|
@@ -781,9 +795,52 @@ var ChatClient = class {
|
|
|
781
795
|
return body;
|
|
782
796
|
} catch (error) {
|
|
783
797
|
assertRequest();
|
|
798
|
+
if (options.idempotencyKey)
|
|
799
|
+
throw new ChatClientNetworkError({
|
|
800
|
+
message: "Could not read the message acknowledgment",
|
|
801
|
+
originalError: error
|
|
802
|
+
});
|
|
784
803
|
throw error;
|
|
785
804
|
}
|
|
786
805
|
}
|
|
806
|
+
/**
|
|
807
|
+
* Renew the access token with the stored refresh token. Concurrent 401s
|
|
808
|
+
* share one refresh. Resolves true when a newer token is in place.
|
|
809
|
+
*/
|
|
810
|
+
refreshSession(rejectedToken) {
|
|
811
|
+
if (this.sessionToken && this.sessionToken !== rejectedToken) return Promise.resolve(true);
|
|
812
|
+
if (!this.refreshPromise) {
|
|
813
|
+
const pending = this.requestRefresh().finally(() => {
|
|
814
|
+
if (this.refreshPromise === pending) this.refreshPromise = null;
|
|
815
|
+
});
|
|
816
|
+
this.refreshPromise = pending;
|
|
817
|
+
}
|
|
818
|
+
return this.refreshPromise;
|
|
819
|
+
}
|
|
820
|
+
async requestRefresh() {
|
|
821
|
+
const generation = this.sessionGeneration;
|
|
822
|
+
const refreshToken = this.refreshToken;
|
|
823
|
+
if (!refreshToken) return false;
|
|
824
|
+
try {
|
|
825
|
+
const response = await globalThis.fetch(`${this.baseUrl}/api/widget/auth/refresh`, {
|
|
826
|
+
method: "POST",
|
|
827
|
+
headers: { "Content-Type": "application/json" },
|
|
828
|
+
body: JSON.stringify({ refreshToken })
|
|
829
|
+
});
|
|
830
|
+
if (generation !== this.sessionGeneration) return false;
|
|
831
|
+
if (!response.ok) {
|
|
832
|
+
if (response.status === 401) this.refreshToken = null;
|
|
833
|
+
return false;
|
|
834
|
+
}
|
|
835
|
+
const body = await response.json();
|
|
836
|
+
if (generation !== this.sessionGeneration || !body.accessToken) return false;
|
|
837
|
+
this.sessionToken = body.accessToken;
|
|
838
|
+
this.refreshToken = body.refreshToken ?? refreshToken;
|
|
839
|
+
return true;
|
|
840
|
+
} catch {
|
|
841
|
+
return false;
|
|
842
|
+
}
|
|
843
|
+
}
|
|
787
844
|
/**
|
|
788
845
|
* Look up the team UUID from the configured `teamSlug`. Used by
|
|
789
846
|
* `loginWithCredentials`. HMAC integrators (`identify()`) never hit
|
|
@@ -1256,26 +1313,80 @@ var MessagesApi = class {
|
|
|
1256
1313
|
assertCurrent();
|
|
1257
1314
|
return response.data.messages;
|
|
1258
1315
|
}
|
|
1259
|
-
/**
|
|
1260
|
-
|
|
1316
|
+
/**
|
|
1317
|
+
* Send one logical reply. Network and server failures retry twice with the
|
|
1318
|
+
* same key. A separate send call is a new intent unless a retained key is supplied.
|
|
1319
|
+
*/
|
|
1320
|
+
async send(ticketId, content, options = {}) {
|
|
1261
1321
|
const assertCurrent = this.chat.captureSession();
|
|
1322
|
+
options.signal?.throwIfAborted();
|
|
1323
|
+
const key = options.idempotencyKey ?? createMessageRequestKey();
|
|
1324
|
+
if (!key || key.length > 250 || key.trim() !== key || /[^\x20-\x7e]/.test(key))
|
|
1325
|
+
throw new ChatClientError({
|
|
1326
|
+
code: "INVALID_IDEMPOTENCY_KEY",
|
|
1327
|
+
message: "Idempotency-Key must contain 1 to 250 printable characters, without surrounding whitespace."
|
|
1328
|
+
});
|
|
1262
1329
|
const teamId = await this.chat.ensureTeamId();
|
|
1263
1330
|
assertCurrent();
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1331
|
+
for (let attempt = 0; ; attempt++) {
|
|
1332
|
+
assertCurrent();
|
|
1333
|
+
options.signal?.throwIfAborted();
|
|
1334
|
+
try {
|
|
1335
|
+
const response = await this.chat.fetch(
|
|
1336
|
+
"/api/widget/messages",
|
|
1337
|
+
{
|
|
1338
|
+
method: "POST",
|
|
1339
|
+
body: { teamId, ticketId, content },
|
|
1340
|
+
idempotencyKey: key,
|
|
1341
|
+
signal: options.signal
|
|
1342
|
+
}
|
|
1343
|
+
);
|
|
1344
|
+
assertCurrent();
|
|
1345
|
+
if (typeof response?.data?.message?.id !== "string" || !response.data.message.id)
|
|
1346
|
+
throw new ChatClientNetworkError({
|
|
1347
|
+
message: "Message acknowledgment was incomplete",
|
|
1348
|
+
originalError: new Error(
|
|
1349
|
+
"The reply may already be saved. Retry with the same send identity."
|
|
1350
|
+
)
|
|
1351
|
+
});
|
|
1352
|
+
return response.data.message;
|
|
1353
|
+
} catch (error) {
|
|
1354
|
+
assertCurrent();
|
|
1355
|
+
options.signal?.throwIfAborted();
|
|
1356
|
+
if (error instanceof ChatClientError) error.idempotencyKey = key;
|
|
1357
|
+
if (attempt >= 2 || !(error instanceof ChatClientNetworkError || error instanceof ChatClientServerError))
|
|
1358
|
+
throw error;
|
|
1359
|
+
await waitForMessageRetry(250 * 2 ** attempt, options.signal);
|
|
1273
1360
|
}
|
|
1274
|
-
|
|
1275
|
-
assertCurrent();
|
|
1276
|
-
return response.data.message;
|
|
1361
|
+
}
|
|
1277
1362
|
}
|
|
1278
1363
|
};
|
|
1364
|
+
function createMessageRequestKey() {
|
|
1365
|
+
if (typeof globalThis.crypto?.randomUUID === "function") return globalThis.crypto.randomUUID();
|
|
1366
|
+
if (typeof globalThis.crypto?.getRandomValues !== "function")
|
|
1367
|
+
throw new ChatClientError({
|
|
1368
|
+
code: "RANDOM_UNAVAILABLE",
|
|
1369
|
+
message: "Secure random values are required to send a message safely."
|
|
1370
|
+
});
|
|
1371
|
+
const bytes = globalThis.crypto.getRandomValues(new Uint8Array(16));
|
|
1372
|
+
return Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
1373
|
+
}
|
|
1374
|
+
function waitForMessageRetry(delay, signal) {
|
|
1375
|
+
signal?.throwIfAborted();
|
|
1376
|
+
return new Promise((resolve, reject) => {
|
|
1377
|
+
const finish = () => {
|
|
1378
|
+
signal?.removeEventListener("abort", abort);
|
|
1379
|
+
resolve();
|
|
1380
|
+
};
|
|
1381
|
+
const timer = setTimeout(finish, delay);
|
|
1382
|
+
const abort = () => {
|
|
1383
|
+
clearTimeout(timer);
|
|
1384
|
+
signal?.removeEventListener("abort", abort);
|
|
1385
|
+
reject(signal?.reason);
|
|
1386
|
+
};
|
|
1387
|
+
signal?.addEventListener("abort", abort, { once: true });
|
|
1388
|
+
});
|
|
1389
|
+
}
|
|
1279
1390
|
function decodeJwtSub(jwt) {
|
|
1280
1391
|
try {
|
|
1281
1392
|
const parts = jwt.split(".");
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { h as CommunityConfig, i as CommunityTopic, j as CommunityPostListParams, k as CommunityPost, l as CommunityPostDetail, m as CommunitySearchResult, C as CommunityCreatePostParams, a as CommunityCreatedPost, b as CommunityUpdatePostParams, c as CommunityUpdateCommentParams, d as CommunityCreatedComment, e as CommunityVoteResult, f as CommunityCreateCommentParams, g as CommunityFollowResult } from '../types-DF7GprCV.cjs';
|
|
2
2
|
export { n as CommunityComment } from '../types-DF7GprCV.cjs';
|
|
3
|
-
export { A as ApiErrorBody, C as CStarAuthenticationError, a as CStarConflictError, b as CStarError, c as CStarFeatureDisabledError, d as CStarNotFoundError, e as CStarPermissionError, f as CStarRateLimitError, g as CStarRealtimeUnavailableError, h as CStarServerError, i as CStarValidationError, E as ErrorType, p as parseError, j as parsePublicError } from '../errors-
|
|
3
|
+
export { A as ApiErrorBody, C as CStarAuthenticationError, a as CStarConflictError, b as CStarError, c as CStarFeatureDisabledError, d as CStarNotFoundError, e as CStarPermissionError, f as CStarRateLimitError, g as CStarRealtimeUnavailableError, h as CStarServerError, i as CStarValidationError, E as ErrorType, p as parseError, j as parsePublicError } from '../errors-bW8CwTn4.cjs';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Public community client. No authentication required.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { h as CommunityConfig, i as CommunityTopic, j as CommunityPostListParams, k as CommunityPost, l as CommunityPostDetail, m as CommunitySearchResult, C as CommunityCreatePostParams, a as CommunityCreatedPost, b as CommunityUpdatePostParams, c as CommunityUpdateCommentParams, d as CommunityCreatedComment, e as CommunityVoteResult, f as CommunityCreateCommentParams, g as CommunityFollowResult } from '../types-DF7GprCV.js';
|
|
2
2
|
export { n as CommunityComment } from '../types-DF7GprCV.js';
|
|
3
|
-
export { A as ApiErrorBody, C as CStarAuthenticationError, a as CStarConflictError, b as CStarError, c as CStarFeatureDisabledError, d as CStarNotFoundError, e as CStarPermissionError, f as CStarRateLimitError, g as CStarRealtimeUnavailableError, h as CStarServerError, i as CStarValidationError, E as ErrorType, p as parseError, j as parsePublicError } from '../errors-
|
|
3
|
+
export { A as ApiErrorBody, C as CStarAuthenticationError, a as CStarConflictError, b as CStarError, c as CStarFeatureDisabledError, d as CStarNotFoundError, e as CStarPermissionError, f as CStarRateLimitError, g as CStarRealtimeUnavailableError, h as CStarServerError, i as CStarValidationError, E as ErrorType, p as parseError, j as parsePublicError } from '../errors-bW8CwTn4.js';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Public community client. No authentication required.
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error classes for the cStar SDK.
|
|
3
|
+
*
|
|
4
|
+
* NEW-v3-01 — Cross-subpath instanceof identity.
|
|
5
|
+
*
|
|
6
|
+
* Each public subpath (`/library`, `/auth`, `/community`, `/quickhelp`, ...)
|
|
7
|
+
* is bundled as a separate tsup entry with `splitting: false`, so each one
|
|
8
|
+
* carries its own copy of this module. Without deduplication, errors thrown
|
|
9
|
+
* by `LibraryClient` carry the LibraryClient-bundled `CStarError` class —
|
|
10
|
+
* not the one a consumer imports from `@cstar.help/js`. That makes
|
|
11
|
+
* `instanceof CStarError` checks fail silently, invalidating every "did the
|
|
12
|
+
* SDK throw a typed cStar error?" branch in user code.
|
|
13
|
+
*
|
|
14
|
+
* Fix: register each class on a `Symbol.for(...)` slot of `globalThis`. The
|
|
15
|
+
* symbol is realm-shared, so every bundled copy of this module resolves to
|
|
16
|
+
* the SAME class identity at runtime — the first copy to load wins, and all
|
|
17
|
+
* subsequent copies surface the canonical class via the same slot. The
|
|
18
|
+
* inline `Impl` definitions are only used as the seed for the very first
|
|
19
|
+
* copy to register. Internal `parseError` / `parsePublicError` reference the
|
|
20
|
+
* EXPORTED canonical names so instances they construct also land on the
|
|
21
|
+
* canonical class.
|
|
22
|
+
*/
|
|
23
|
+
/** Error type constants matching the cStar API. */
|
|
24
|
+
declare const ErrorType: {
|
|
25
|
+
readonly AUTHENTICATION_ERROR: "authentication_error";
|
|
26
|
+
readonly PERMISSION_ERROR: "permission_error";
|
|
27
|
+
readonly INVALID_REQUEST_ERROR: "invalid_request_error";
|
|
28
|
+
readonly NOT_FOUND_ERROR: "not_found_error";
|
|
29
|
+
readonly CONFLICT_ERROR: "conflict_error";
|
|
30
|
+
readonly RATE_LIMIT_ERROR: "rate_limit_error";
|
|
31
|
+
readonly FEATURE_NOT_CONFIGURED: "feature_not_configured";
|
|
32
|
+
readonly API_ERROR: "api_error";
|
|
33
|
+
readonly SERVER_ERROR: "server_error";
|
|
34
|
+
};
|
|
35
|
+
/** Shape of the error object returned by the cStar API. */
|
|
36
|
+
interface ApiErrorBody {
|
|
37
|
+
type: string;
|
|
38
|
+
code: string;
|
|
39
|
+
message: string;
|
|
40
|
+
param?: string;
|
|
41
|
+
doc_url: string;
|
|
42
|
+
request_id?: string;
|
|
43
|
+
feature?: string;
|
|
44
|
+
enable_url?: string;
|
|
45
|
+
}
|
|
46
|
+
/** Base error class for all cStar API errors. */
|
|
47
|
+
declare class CStarErrorImpl extends Error {
|
|
48
|
+
readonly type: string;
|
|
49
|
+
readonly code: string;
|
|
50
|
+
readonly param?: string;
|
|
51
|
+
readonly docUrl: string;
|
|
52
|
+
readonly requestId?: string;
|
|
53
|
+
readonly statusCode: number;
|
|
54
|
+
constructor(messageOrStatus: string | number, body?: ApiErrorBody);
|
|
55
|
+
}
|
|
56
|
+
declare class CStarAuthenticationErrorImpl extends CStarErrorImpl {
|
|
57
|
+
constructor(messageOrStatus: string | number, body?: ApiErrorBody);
|
|
58
|
+
}
|
|
59
|
+
declare class CStarRateLimitErrorImpl extends CStarErrorImpl {
|
|
60
|
+
readonly retryAfter: number;
|
|
61
|
+
constructor(messageOrStatus: string | number, body?: ApiErrorBody, retryAfter?: number);
|
|
62
|
+
}
|
|
63
|
+
declare class CStarNotFoundErrorImpl extends CStarErrorImpl {
|
|
64
|
+
constructor(messageOrStatus: string | number, body?: ApiErrorBody);
|
|
65
|
+
}
|
|
66
|
+
declare class CStarValidationErrorImpl extends CStarErrorImpl {
|
|
67
|
+
constructor(messageOrStatus: string | number, body?: ApiErrorBody);
|
|
68
|
+
}
|
|
69
|
+
declare class CStarPermissionErrorImpl extends CStarErrorImpl {
|
|
70
|
+
constructor(messageOrStatus: string | number, body?: ApiErrorBody);
|
|
71
|
+
}
|
|
72
|
+
declare class CStarConflictErrorImpl extends CStarErrorImpl {
|
|
73
|
+
constructor(messageOrStatus: string | number, body?: ApiErrorBody);
|
|
74
|
+
}
|
|
75
|
+
declare class CStarServerErrorImpl extends CStarErrorImpl {
|
|
76
|
+
constructor(messageOrStatus: string | number, body?: ApiErrorBody);
|
|
77
|
+
}
|
|
78
|
+
declare class CStarFeatureDisabledErrorImpl extends CStarErrorImpl {
|
|
79
|
+
readonly feature: string;
|
|
80
|
+
readonly enableUrl: string;
|
|
81
|
+
constructor(messageOrStatus: string | number, body?: ApiErrorBody);
|
|
82
|
+
}
|
|
83
|
+
declare class CStarRealtimeUnavailableErrorImpl extends CStarErrorImpl {
|
|
84
|
+
constructor(message?: string);
|
|
85
|
+
}
|
|
86
|
+
declare const CStarError: typeof CStarErrorImpl;
|
|
87
|
+
type CStarError = InstanceType<typeof CStarErrorImpl>;
|
|
88
|
+
declare const CStarAuthenticationError: typeof CStarAuthenticationErrorImpl;
|
|
89
|
+
type CStarAuthenticationError = InstanceType<typeof CStarAuthenticationErrorImpl>;
|
|
90
|
+
declare const CStarRateLimitError: typeof CStarRateLimitErrorImpl;
|
|
91
|
+
type CStarRateLimitError = InstanceType<typeof CStarRateLimitErrorImpl>;
|
|
92
|
+
declare const CStarNotFoundError: typeof CStarNotFoundErrorImpl;
|
|
93
|
+
type CStarNotFoundError = InstanceType<typeof CStarNotFoundErrorImpl>;
|
|
94
|
+
declare const CStarValidationError: typeof CStarValidationErrorImpl;
|
|
95
|
+
type CStarValidationError = InstanceType<typeof CStarValidationErrorImpl>;
|
|
96
|
+
declare const CStarPermissionError: typeof CStarPermissionErrorImpl;
|
|
97
|
+
type CStarPermissionError = InstanceType<typeof CStarPermissionErrorImpl>;
|
|
98
|
+
declare const CStarConflictError: typeof CStarConflictErrorImpl;
|
|
99
|
+
type CStarConflictError = InstanceType<typeof CStarConflictErrorImpl>;
|
|
100
|
+
declare const CStarServerError: typeof CStarServerErrorImpl;
|
|
101
|
+
type CStarServerError = InstanceType<typeof CStarServerErrorImpl>;
|
|
102
|
+
declare const CStarFeatureDisabledError: typeof CStarFeatureDisabledErrorImpl;
|
|
103
|
+
type CStarFeatureDisabledError = InstanceType<typeof CStarFeatureDisabledErrorImpl>;
|
|
104
|
+
declare const CStarRealtimeUnavailableError: typeof CStarRealtimeUnavailableErrorImpl;
|
|
105
|
+
type CStarRealtimeUnavailableError = InstanceType<typeof CStarRealtimeUnavailableErrorImpl>;
|
|
106
|
+
/**
|
|
107
|
+
* Parse a public-route response (anonymous LibraryClient, CommunityClient,
|
|
108
|
+
* QuickHelpClient, AuthClient) into a typed `CStarError`.
|
|
109
|
+
*
|
|
110
|
+
* Public routes don't always emit the structured `{error: {type, code,
|
|
111
|
+
* doc_url, ...}}` envelope — many emit `{error: 'message string'}` or
|
|
112
|
+
* `{message: '...'}`. This helper normalizes both shapes and dispatches
|
|
113
|
+
* on HTTP status (closes F-026 and F-034 — Library/Auth used to throw
|
|
114
|
+
* plain `Error`).
|
|
115
|
+
*/
|
|
116
|
+
declare function parsePublicError(status: number, body: unknown, fallbackMessage: string): CStarError;
|
|
117
|
+
declare function parseError(statusCode: number, body: {
|
|
118
|
+
error?: ApiErrorBody;
|
|
119
|
+
} | null, retryAfter?: number): CStarError;
|
|
120
|
+
|
|
121
|
+
export { type ApiErrorBody as A, CStarAuthenticationError as C, ErrorType as E, CStarConflictError as a, CStarError as b, CStarFeatureDisabledError as c, CStarNotFoundError as d, CStarPermissionError as e, CStarRateLimitError as f, CStarRealtimeUnavailableError as g, CStarServerError as h, CStarValidationError as i, parsePublicError as j, parseError as p };
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error classes for the cStar SDK.
|
|
3
|
+
*
|
|
4
|
+
* NEW-v3-01 — Cross-subpath instanceof identity.
|
|
5
|
+
*
|
|
6
|
+
* Each public subpath (`/library`, `/auth`, `/community`, `/quickhelp`, ...)
|
|
7
|
+
* is bundled as a separate tsup entry with `splitting: false`, so each one
|
|
8
|
+
* carries its own copy of this module. Without deduplication, errors thrown
|
|
9
|
+
* by `LibraryClient` carry the LibraryClient-bundled `CStarError` class —
|
|
10
|
+
* not the one a consumer imports from `@cstar.help/js`. That makes
|
|
11
|
+
* `instanceof CStarError` checks fail silently, invalidating every "did the
|
|
12
|
+
* SDK throw a typed cStar error?" branch in user code.
|
|
13
|
+
*
|
|
14
|
+
* Fix: register each class on a `Symbol.for(...)` slot of `globalThis`. The
|
|
15
|
+
* symbol is realm-shared, so every bundled copy of this module resolves to
|
|
16
|
+
* the SAME class identity at runtime — the first copy to load wins, and all
|
|
17
|
+
* subsequent copies surface the canonical class via the same slot. The
|
|
18
|
+
* inline `Impl` definitions are only used as the seed for the very first
|
|
19
|
+
* copy to register. Internal `parseError` / `parsePublicError` reference the
|
|
20
|
+
* EXPORTED canonical names so instances they construct also land on the
|
|
21
|
+
* canonical class.
|
|
22
|
+
*/
|
|
23
|
+
/** Error type constants matching the cStar API. */
|
|
24
|
+
declare const ErrorType: {
|
|
25
|
+
readonly AUTHENTICATION_ERROR: "authentication_error";
|
|
26
|
+
readonly PERMISSION_ERROR: "permission_error";
|
|
27
|
+
readonly INVALID_REQUEST_ERROR: "invalid_request_error";
|
|
28
|
+
readonly NOT_FOUND_ERROR: "not_found_error";
|
|
29
|
+
readonly CONFLICT_ERROR: "conflict_error";
|
|
30
|
+
readonly RATE_LIMIT_ERROR: "rate_limit_error";
|
|
31
|
+
readonly FEATURE_NOT_CONFIGURED: "feature_not_configured";
|
|
32
|
+
readonly API_ERROR: "api_error";
|
|
33
|
+
readonly SERVER_ERROR: "server_error";
|
|
34
|
+
};
|
|
35
|
+
/** Shape of the error object returned by the cStar API. */
|
|
36
|
+
interface ApiErrorBody {
|
|
37
|
+
type: string;
|
|
38
|
+
code: string;
|
|
39
|
+
message: string;
|
|
40
|
+
param?: string;
|
|
41
|
+
doc_url: string;
|
|
42
|
+
request_id?: string;
|
|
43
|
+
feature?: string;
|
|
44
|
+
enable_url?: string;
|
|
45
|
+
}
|
|
46
|
+
/** Base error class for all cStar API errors. */
|
|
47
|
+
declare class CStarErrorImpl extends Error {
|
|
48
|
+
readonly type: string;
|
|
49
|
+
readonly code: string;
|
|
50
|
+
readonly param?: string;
|
|
51
|
+
readonly docUrl: string;
|
|
52
|
+
readonly requestId?: string;
|
|
53
|
+
readonly statusCode: number;
|
|
54
|
+
constructor(messageOrStatus: string | number, body?: ApiErrorBody);
|
|
55
|
+
}
|
|
56
|
+
declare class CStarAuthenticationErrorImpl extends CStarErrorImpl {
|
|
57
|
+
constructor(messageOrStatus: string | number, body?: ApiErrorBody);
|
|
58
|
+
}
|
|
59
|
+
declare class CStarRateLimitErrorImpl extends CStarErrorImpl {
|
|
60
|
+
readonly retryAfter: number;
|
|
61
|
+
constructor(messageOrStatus: string | number, body?: ApiErrorBody, retryAfter?: number);
|
|
62
|
+
}
|
|
63
|
+
declare class CStarNotFoundErrorImpl extends CStarErrorImpl {
|
|
64
|
+
constructor(messageOrStatus: string | number, body?: ApiErrorBody);
|
|
65
|
+
}
|
|
66
|
+
declare class CStarValidationErrorImpl extends CStarErrorImpl {
|
|
67
|
+
constructor(messageOrStatus: string | number, body?: ApiErrorBody);
|
|
68
|
+
}
|
|
69
|
+
declare class CStarPermissionErrorImpl extends CStarErrorImpl {
|
|
70
|
+
constructor(messageOrStatus: string | number, body?: ApiErrorBody);
|
|
71
|
+
}
|
|
72
|
+
declare class CStarConflictErrorImpl extends CStarErrorImpl {
|
|
73
|
+
constructor(messageOrStatus: string | number, body?: ApiErrorBody);
|
|
74
|
+
}
|
|
75
|
+
declare class CStarServerErrorImpl extends CStarErrorImpl {
|
|
76
|
+
constructor(messageOrStatus: string | number, body?: ApiErrorBody);
|
|
77
|
+
}
|
|
78
|
+
declare class CStarFeatureDisabledErrorImpl extends CStarErrorImpl {
|
|
79
|
+
readonly feature: string;
|
|
80
|
+
readonly enableUrl: string;
|
|
81
|
+
constructor(messageOrStatus: string | number, body?: ApiErrorBody);
|
|
82
|
+
}
|
|
83
|
+
declare class CStarRealtimeUnavailableErrorImpl extends CStarErrorImpl {
|
|
84
|
+
constructor(message?: string);
|
|
85
|
+
}
|
|
86
|
+
declare const CStarError: typeof CStarErrorImpl;
|
|
87
|
+
type CStarError = InstanceType<typeof CStarErrorImpl>;
|
|
88
|
+
declare const CStarAuthenticationError: typeof CStarAuthenticationErrorImpl;
|
|
89
|
+
type CStarAuthenticationError = InstanceType<typeof CStarAuthenticationErrorImpl>;
|
|
90
|
+
declare const CStarRateLimitError: typeof CStarRateLimitErrorImpl;
|
|
91
|
+
type CStarRateLimitError = InstanceType<typeof CStarRateLimitErrorImpl>;
|
|
92
|
+
declare const CStarNotFoundError: typeof CStarNotFoundErrorImpl;
|
|
93
|
+
type CStarNotFoundError = InstanceType<typeof CStarNotFoundErrorImpl>;
|
|
94
|
+
declare const CStarValidationError: typeof CStarValidationErrorImpl;
|
|
95
|
+
type CStarValidationError = InstanceType<typeof CStarValidationErrorImpl>;
|
|
96
|
+
declare const CStarPermissionError: typeof CStarPermissionErrorImpl;
|
|
97
|
+
type CStarPermissionError = InstanceType<typeof CStarPermissionErrorImpl>;
|
|
98
|
+
declare const CStarConflictError: typeof CStarConflictErrorImpl;
|
|
99
|
+
type CStarConflictError = InstanceType<typeof CStarConflictErrorImpl>;
|
|
100
|
+
declare const CStarServerError: typeof CStarServerErrorImpl;
|
|
101
|
+
type CStarServerError = InstanceType<typeof CStarServerErrorImpl>;
|
|
102
|
+
declare const CStarFeatureDisabledError: typeof CStarFeatureDisabledErrorImpl;
|
|
103
|
+
type CStarFeatureDisabledError = InstanceType<typeof CStarFeatureDisabledErrorImpl>;
|
|
104
|
+
declare const CStarRealtimeUnavailableError: typeof CStarRealtimeUnavailableErrorImpl;
|
|
105
|
+
type CStarRealtimeUnavailableError = InstanceType<typeof CStarRealtimeUnavailableErrorImpl>;
|
|
106
|
+
/**
|
|
107
|
+
* Parse a public-route response (anonymous LibraryClient, CommunityClient,
|
|
108
|
+
* QuickHelpClient, AuthClient) into a typed `CStarError`.
|
|
109
|
+
*
|
|
110
|
+
* Public routes don't always emit the structured `{error: {type, code,
|
|
111
|
+
* doc_url, ...}}` envelope — many emit `{error: 'message string'}` or
|
|
112
|
+
* `{message: '...'}`. This helper normalizes both shapes and dispatches
|
|
113
|
+
* on HTTP status (closes F-026 and F-034 — Library/Auth used to throw
|
|
114
|
+
* plain `Error`).
|
|
115
|
+
*/
|
|
116
|
+
declare function parsePublicError(status: number, body: unknown, fallbackMessage: string): CStarError;
|
|
117
|
+
declare function parseError(statusCode: number, body: {
|
|
118
|
+
error?: ApiErrorBody;
|
|
119
|
+
} | null, retryAfter?: number): CStarError;
|
|
120
|
+
|
|
121
|
+
export { type ApiErrorBody as A, CStarAuthenticationError as C, ErrorType as E, CStarConflictError as a, CStarError as b, CStarFeatureDisabledError as c, CStarNotFoundError as d, CStarPermissionError as e, CStarRateLimitError as f, CStarRealtimeUnavailableError as g, CStarServerError as h, CStarValidationError as i, parsePublicError as j, parseError as p };
|