@cstar.help/js 0.12.1 → 0.14.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/auth/index.cjs +217 -3
- package/dist/auth/index.js +215 -3
- package/dist/chat/index.cjs +84 -29
- package/dist/chat/index.d.cts +72 -27
- package/dist/chat/index.d.ts +72 -27
- package/dist/chat/index.js +84 -29
- package/dist/community/index.cjs +233 -9
- package/dist/community/index.d.cts +11 -0
- package/dist/community/index.d.ts +11 -0
- package/dist/community/index.js +231 -9
- package/dist/index.cjs +309 -74
- package/dist/index.d.cts +3287 -0
- package/dist/index.d.ts +3287 -0
- package/dist/index.js +308 -74
- package/dist/library/index.cjs +254 -9
- package/dist/library/index.d.cts +26 -3
- package/dist/library/index.d.ts +26 -3
- package/dist/library/index.js +252 -9
- package/dist/quickhelp/index.cjs +220 -7
- package/dist/quickhelp/index.d.cts +37 -4
- package/dist/quickhelp/index.d.ts +37 -4
- package/dist/quickhelp/index.js +218 -7
- package/dist/webhook/index.cjs +0 -18
- package/dist/webhook/index.d.cts +440 -0
- package/dist/webhook/index.d.ts +440 -0
- package/dist/webhook/index.js +0 -23
- package/dist/webhook/node.cjs +57 -0
- package/dist/webhook/node.d.cts +440 -0
- package/dist/webhook/node.d.ts +440 -0
- package/dist/webhook/node.js +30 -0
- package/package.json +14 -2
package/dist/library/index.js
CHANGED
|
@@ -1,3 +1,216 @@
|
|
|
1
|
+
// src/errors.ts
|
|
2
|
+
var ErrorType = {
|
|
3
|
+
AUTHENTICATION_ERROR: "authentication_error",
|
|
4
|
+
PERMISSION_ERROR: "permission_error",
|
|
5
|
+
INVALID_REQUEST_ERROR: "invalid_request_error",
|
|
6
|
+
NOT_FOUND_ERROR: "not_found_error",
|
|
7
|
+
CONFLICT_ERROR: "conflict_error",
|
|
8
|
+
RATE_LIMIT_ERROR: "rate_limit_error",
|
|
9
|
+
FEATURE_NOT_CONFIGURED: "feature_not_configured",
|
|
10
|
+
API_ERROR: "api_error",
|
|
11
|
+
SERVER_ERROR: "server_error"
|
|
12
|
+
};
|
|
13
|
+
var DEFAULT_DOC_URL = "https://cstar.help/developers/api/errors";
|
|
14
|
+
function normalizeArgs(messageOrStatus, maybeBody, defaults) {
|
|
15
|
+
if (typeof messageOrStatus === "string") {
|
|
16
|
+
return {
|
|
17
|
+
statusCode: defaults?.code === "rate_limit_error" ? 429 : 0,
|
|
18
|
+
body: {
|
|
19
|
+
type: defaults?.type ?? ErrorType.API_ERROR,
|
|
20
|
+
code: defaults?.code ?? "sdk_error",
|
|
21
|
+
message: messageOrStatus,
|
|
22
|
+
doc_url: defaults?.doc_url ?? DEFAULT_DOC_URL,
|
|
23
|
+
...defaults?.feature ? { feature: defaults.feature } : {},
|
|
24
|
+
...defaults?.enable_url ? { enable_url: defaults.enable_url } : {}
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
return {
|
|
29
|
+
statusCode: messageOrStatus,
|
|
30
|
+
body: maybeBody ?? {
|
|
31
|
+
type: defaults?.type ?? ErrorType.API_ERROR,
|
|
32
|
+
code: defaults?.code ?? "unknown_error",
|
|
33
|
+
message: defaults?.message ?? `Request failed with status ${messageOrStatus}`,
|
|
34
|
+
doc_url: defaults?.doc_url ?? DEFAULT_DOC_URL
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
var CStarError = class extends Error {
|
|
39
|
+
constructor(messageOrStatus, body) {
|
|
40
|
+
const { statusCode, body: resolved } = normalizeArgs(messageOrStatus, body);
|
|
41
|
+
super(resolved.message);
|
|
42
|
+
this.name = "CStarError";
|
|
43
|
+
this.type = resolved.type;
|
|
44
|
+
this.code = resolved.code;
|
|
45
|
+
this.param = resolved.param;
|
|
46
|
+
this.docUrl = resolved.doc_url;
|
|
47
|
+
this.requestId = resolved.request_id;
|
|
48
|
+
this.statusCode = statusCode;
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
var CStarAuthenticationError = class extends CStarError {
|
|
52
|
+
constructor(messageOrStatus, body) {
|
|
53
|
+
const { statusCode, body: resolved } = normalizeArgs(messageOrStatus, body, {
|
|
54
|
+
type: ErrorType.AUTHENTICATION_ERROR,
|
|
55
|
+
code: "authentication_failed",
|
|
56
|
+
doc_url: `${DEFAULT_DOC_URL}#authentication-error`
|
|
57
|
+
});
|
|
58
|
+
super(statusCode, resolved);
|
|
59
|
+
this.name = "CStarAuthenticationError";
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
var CStarRateLimitError = class extends CStarError {
|
|
63
|
+
constructor(messageOrStatus, body, retryAfter) {
|
|
64
|
+
const { statusCode, body: resolved } = normalizeArgs(messageOrStatus, body, {
|
|
65
|
+
type: ErrorType.RATE_LIMIT_ERROR,
|
|
66
|
+
code: "rate_limit_exceeded",
|
|
67
|
+
doc_url: `${DEFAULT_DOC_URL}#rate-limit-error`
|
|
68
|
+
});
|
|
69
|
+
super(statusCode === 0 ? 429 : statusCode, resolved);
|
|
70
|
+
this.name = "CStarRateLimitError";
|
|
71
|
+
this.retryAfter = retryAfter ?? 60;
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
var CStarNotFoundError = class extends CStarError {
|
|
75
|
+
constructor(messageOrStatus, body) {
|
|
76
|
+
const { statusCode, body: resolved } = normalizeArgs(messageOrStatus, body, {
|
|
77
|
+
type: ErrorType.NOT_FOUND_ERROR,
|
|
78
|
+
code: "resource_not_found",
|
|
79
|
+
doc_url: `${DEFAULT_DOC_URL}#not-found-error`
|
|
80
|
+
});
|
|
81
|
+
super(statusCode, resolved);
|
|
82
|
+
this.name = "CStarNotFoundError";
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
var CStarValidationError = class extends CStarError {
|
|
86
|
+
constructor(messageOrStatus, body) {
|
|
87
|
+
const { statusCode, body: resolved } = normalizeArgs(messageOrStatus, body, {
|
|
88
|
+
type: ErrorType.INVALID_REQUEST_ERROR,
|
|
89
|
+
code: "validation_error",
|
|
90
|
+
doc_url: `${DEFAULT_DOC_URL}#validation-error`
|
|
91
|
+
});
|
|
92
|
+
super(statusCode, resolved);
|
|
93
|
+
this.name = "CStarValidationError";
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
var CStarPermissionError = class extends CStarError {
|
|
97
|
+
constructor(messageOrStatus, body) {
|
|
98
|
+
const { statusCode, body: resolved } = normalizeArgs(messageOrStatus, body, {
|
|
99
|
+
type: ErrorType.PERMISSION_ERROR,
|
|
100
|
+
code: "permission_denied",
|
|
101
|
+
doc_url: `${DEFAULT_DOC_URL}#permission-error`
|
|
102
|
+
});
|
|
103
|
+
super(statusCode, resolved);
|
|
104
|
+
this.name = "CStarPermissionError";
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
var CStarConflictError = class extends CStarError {
|
|
108
|
+
constructor(messageOrStatus, body) {
|
|
109
|
+
const { statusCode, body: resolved } = normalizeArgs(messageOrStatus, body, {
|
|
110
|
+
type: ErrorType.CONFLICT_ERROR,
|
|
111
|
+
code: "conflict",
|
|
112
|
+
doc_url: `${DEFAULT_DOC_URL}#conflict-error`
|
|
113
|
+
});
|
|
114
|
+
super(statusCode, resolved);
|
|
115
|
+
this.name = "CStarConflictError";
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
var CStarServerError = class extends CStarError {
|
|
119
|
+
constructor(messageOrStatus, body) {
|
|
120
|
+
const { statusCode, body: resolved } = normalizeArgs(messageOrStatus, body, {
|
|
121
|
+
type: ErrorType.SERVER_ERROR,
|
|
122
|
+
code: "server_error",
|
|
123
|
+
doc_url: `${DEFAULT_DOC_URL}#server-error`
|
|
124
|
+
});
|
|
125
|
+
super(statusCode, resolved);
|
|
126
|
+
this.name = "CStarServerError";
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
var CStarFeatureDisabledError = class extends CStarError {
|
|
130
|
+
constructor(messageOrStatus, body) {
|
|
131
|
+
const { statusCode, body: resolved } = normalizeArgs(messageOrStatus, body, {
|
|
132
|
+
type: ErrorType.FEATURE_NOT_CONFIGURED,
|
|
133
|
+
code: "feature_not_configured",
|
|
134
|
+
doc_url: `${DEFAULT_DOC_URL}#feature-not-configured`
|
|
135
|
+
});
|
|
136
|
+
super(statusCode, resolved);
|
|
137
|
+
this.name = "CStarFeatureDisabledError";
|
|
138
|
+
this.feature = resolved.feature ?? "unknown";
|
|
139
|
+
this.enableUrl = resolved.enable_url ?? "";
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
function parsePublicError(status, body, fallbackMessage) {
|
|
143
|
+
const obj = body && typeof body === "object" ? body : null;
|
|
144
|
+
const errVal = obj?.error;
|
|
145
|
+
let message = fallbackMessage;
|
|
146
|
+
let structured = null;
|
|
147
|
+
if (typeof errVal === "string") {
|
|
148
|
+
message = errVal;
|
|
149
|
+
} else if (errVal && typeof errVal === "object") {
|
|
150
|
+
const e = errVal;
|
|
151
|
+
if (typeof e.message === "string") message = e.message;
|
|
152
|
+
structured = {
|
|
153
|
+
type: typeof e.type === "string" ? e.type : ErrorType.API_ERROR,
|
|
154
|
+
code: typeof e.code === "string" ? e.code : "api_error",
|
|
155
|
+
message,
|
|
156
|
+
param: typeof e.param === "string" ? e.param : void 0,
|
|
157
|
+
doc_url: typeof e.doc_url === "string" ? e.doc_url : DEFAULT_DOC_URL,
|
|
158
|
+
request_id: typeof e.request_id === "string" ? e.request_id : void 0,
|
|
159
|
+
feature: typeof e.feature === "string" ? e.feature : void 0,
|
|
160
|
+
enable_url: typeof e.enable_url === "string" ? e.enable_url : void 0
|
|
161
|
+
};
|
|
162
|
+
} else if (typeof obj?.message === "string") {
|
|
163
|
+
message = obj.message;
|
|
164
|
+
}
|
|
165
|
+
const errorBody = structured ?? {
|
|
166
|
+
type: ErrorType.API_ERROR,
|
|
167
|
+
code: status >= 500 ? "server_error" : "request_failed",
|
|
168
|
+
message,
|
|
169
|
+
doc_url: DEFAULT_DOC_URL
|
|
170
|
+
};
|
|
171
|
+
return parseError(status, { error: errorBody });
|
|
172
|
+
}
|
|
173
|
+
var STATUS_TO_CLASS = {
|
|
174
|
+
400: CStarValidationError,
|
|
175
|
+
401: CStarAuthenticationError,
|
|
176
|
+
403: CStarPermissionError,
|
|
177
|
+
404: CStarNotFoundError,
|
|
178
|
+
409: CStarConflictError,
|
|
179
|
+
422: CStarValidationError,
|
|
180
|
+
429: CStarRateLimitError
|
|
181
|
+
};
|
|
182
|
+
var TYPE_TO_CLASS = {
|
|
183
|
+
[ErrorType.AUTHENTICATION_ERROR]: CStarAuthenticationError,
|
|
184
|
+
[ErrorType.PERMISSION_ERROR]: CStarPermissionError,
|
|
185
|
+
[ErrorType.RATE_LIMIT_ERROR]: CStarRateLimitError,
|
|
186
|
+
[ErrorType.NOT_FOUND_ERROR]: CStarNotFoundError,
|
|
187
|
+
[ErrorType.INVALID_REQUEST_ERROR]: CStarValidationError,
|
|
188
|
+
[ErrorType.CONFLICT_ERROR]: CStarConflictError,
|
|
189
|
+
[ErrorType.SERVER_ERROR]: CStarServerError,
|
|
190
|
+
[ErrorType.FEATURE_NOT_CONFIGURED]: CStarFeatureDisabledError
|
|
191
|
+
};
|
|
192
|
+
function parseError(statusCode, body, retryAfter) {
|
|
193
|
+
const errorBody = body?.error ?? {
|
|
194
|
+
type: ErrorType.API_ERROR,
|
|
195
|
+
code: "unknown_error",
|
|
196
|
+
message: `Request failed with status ${statusCode}`,
|
|
197
|
+
doc_url: DEFAULT_DOC_URL
|
|
198
|
+
};
|
|
199
|
+
if (statusCode === 429) {
|
|
200
|
+
return new CStarRateLimitError(statusCode, errorBody, retryAfter ?? 60);
|
|
201
|
+
}
|
|
202
|
+
const StatusCls = STATUS_TO_CLASS[statusCode];
|
|
203
|
+
if (StatusCls) {
|
|
204
|
+
return new StatusCls(statusCode, errorBody);
|
|
205
|
+
}
|
|
206
|
+
const TypeCls = TYPE_TO_CLASS[errorBody.type];
|
|
207
|
+
if (TypeCls) {
|
|
208
|
+
return new TypeCls(statusCode, errorBody);
|
|
209
|
+
}
|
|
210
|
+
if (statusCode >= 500) return new CStarServerError(statusCode, errorBody);
|
|
211
|
+
return new CStarError(statusCode, errorBody);
|
|
212
|
+
}
|
|
213
|
+
|
|
1
214
|
// src/library/index.ts
|
|
2
215
|
var DEFAULT_BASE_URL = "https://www.cstar.help";
|
|
3
216
|
var LibraryClient = class {
|
|
@@ -5,6 +218,13 @@ var LibraryClient = class {
|
|
|
5
218
|
this.resolvedTeamId = null;
|
|
6
219
|
this.baseUrl = (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
|
|
7
220
|
this.teamSlug = config.teamSlug;
|
|
221
|
+
this.publishableKey = config.publishableKey ?? null;
|
|
222
|
+
this.mode = this.publishableKey?.startsWith("pk_test_") ? "test" : "live";
|
|
223
|
+
if (this.publishableKey && !/^pk_(test|live)_/.test(this.publishableKey)) {
|
|
224
|
+
throw new Error(
|
|
225
|
+
"[cStar] LibraryClient: publishableKey must start with `pk_test_` or `pk_live_`. Secret keys (`sk_*`) cannot be used in browser/anonymous contexts."
|
|
226
|
+
);
|
|
227
|
+
}
|
|
8
228
|
}
|
|
9
229
|
/** List all public categories with article counts. */
|
|
10
230
|
async categories() {
|
|
@@ -54,13 +274,19 @@ var LibraryClient = class {
|
|
|
54
274
|
*/
|
|
55
275
|
async recordView(slug) {
|
|
56
276
|
const url = `${this.baseUrl}/api/library/${this.teamSlug}/articles/${slug}/view`;
|
|
277
|
+
const headers = { "Content-Type": "application/json" };
|
|
278
|
+
if (this.publishableKey) headers["Authorization"] = `Bearer ${this.publishableKey}`;
|
|
57
279
|
const response = await globalThis.fetch(url, {
|
|
58
280
|
method: "POST",
|
|
59
|
-
headers
|
|
281
|
+
headers
|
|
60
282
|
});
|
|
61
283
|
if (!response.ok) {
|
|
62
|
-
const errorBody = await response.json().catch(() =>
|
|
63
|
-
throw
|
|
284
|
+
const errorBody = await response.json().catch(() => null);
|
|
285
|
+
throw parsePublicError(
|
|
286
|
+
response.status,
|
|
287
|
+
errorBody,
|
|
288
|
+
`View tracking failed: ${response.status}`
|
|
289
|
+
);
|
|
64
290
|
}
|
|
65
291
|
const body = await response.json();
|
|
66
292
|
return { viewCount: body.viewCount };
|
|
@@ -82,14 +308,27 @@ var LibraryClient = class {
|
|
|
82
308
|
*/
|
|
83
309
|
async submitFeedback(slug, params) {
|
|
84
310
|
const url = `${this.baseUrl}/api/library/${this.teamSlug}/articles/${slug}/feedback`;
|
|
311
|
+
const headers = { "Content-Type": "application/json" };
|
|
312
|
+
if (this.publishableKey) headers["Authorization"] = `Bearer ${this.publishableKey}`;
|
|
85
313
|
const response = await globalThis.fetch(url, {
|
|
86
314
|
method: "POST",
|
|
87
|
-
headers
|
|
315
|
+
headers,
|
|
88
316
|
body: JSON.stringify(params)
|
|
89
317
|
});
|
|
90
|
-
const body = await response.json();
|
|
318
|
+
const body = await response.json().catch(() => null);
|
|
91
319
|
if (!response.ok) {
|
|
92
|
-
throw
|
|
320
|
+
throw parsePublicError(
|
|
321
|
+
response.status,
|
|
322
|
+
body,
|
|
323
|
+
body?.error ?? `Feedback submission failed: ${response.status}`
|
|
324
|
+
);
|
|
325
|
+
}
|
|
326
|
+
if (body === null) {
|
|
327
|
+
throw parsePublicError(
|
|
328
|
+
response.status,
|
|
329
|
+
null,
|
|
330
|
+
`Feedback submission returned an invalid JSON response (status ${response.status})`
|
|
331
|
+
);
|
|
93
332
|
}
|
|
94
333
|
return body;
|
|
95
334
|
}
|
|
@@ -120,13 +359,17 @@ var LibraryClient = class {
|
|
|
120
359
|
const qs = params.toString();
|
|
121
360
|
if (qs) url += `?${qs}`;
|
|
122
361
|
}
|
|
362
|
+
const headers = { "Content-Type": "application/json" };
|
|
363
|
+
if (this.publishableKey) {
|
|
364
|
+
headers["Authorization"] = `Bearer ${this.publishableKey}`;
|
|
365
|
+
}
|
|
123
366
|
const response = await globalThis.fetch(url, {
|
|
124
367
|
method: "GET",
|
|
125
|
-
headers
|
|
368
|
+
headers
|
|
126
369
|
});
|
|
127
370
|
if (!response.ok) {
|
|
128
|
-
const errorBody = await response.json().catch(() =>
|
|
129
|
-
throw
|
|
371
|
+
const errorBody = await response.json().catch(() => null);
|
|
372
|
+
throw parsePublicError(response.status, errorBody, `Library API error: ${response.status}`);
|
|
130
373
|
}
|
|
131
374
|
return response.json();
|
|
132
375
|
}
|
package/dist/quickhelp/index.cjs
CHANGED
|
@@ -24,14 +24,215 @@ __export(quickhelp_exports, {
|
|
|
24
24
|
QuickHelpError: () => QuickHelpError
|
|
25
25
|
});
|
|
26
26
|
module.exports = __toCommonJS(quickhelp_exports);
|
|
27
|
+
|
|
28
|
+
// src/errors.ts
|
|
29
|
+
var ErrorType = {
|
|
30
|
+
AUTHENTICATION_ERROR: "authentication_error",
|
|
31
|
+
PERMISSION_ERROR: "permission_error",
|
|
32
|
+
INVALID_REQUEST_ERROR: "invalid_request_error",
|
|
33
|
+
NOT_FOUND_ERROR: "not_found_error",
|
|
34
|
+
CONFLICT_ERROR: "conflict_error",
|
|
35
|
+
RATE_LIMIT_ERROR: "rate_limit_error",
|
|
36
|
+
FEATURE_NOT_CONFIGURED: "feature_not_configured",
|
|
37
|
+
API_ERROR: "api_error",
|
|
38
|
+
SERVER_ERROR: "server_error"
|
|
39
|
+
};
|
|
40
|
+
var DEFAULT_DOC_URL = "https://cstar.help/developers/api/errors";
|
|
41
|
+
function normalizeArgs(messageOrStatus, maybeBody, defaults) {
|
|
42
|
+
if (typeof messageOrStatus === "string") {
|
|
43
|
+
return {
|
|
44
|
+
statusCode: defaults?.code === "rate_limit_error" ? 429 : 0,
|
|
45
|
+
body: {
|
|
46
|
+
type: defaults?.type ?? ErrorType.API_ERROR,
|
|
47
|
+
code: defaults?.code ?? "sdk_error",
|
|
48
|
+
message: messageOrStatus,
|
|
49
|
+
doc_url: defaults?.doc_url ?? DEFAULT_DOC_URL,
|
|
50
|
+
...defaults?.feature ? { feature: defaults.feature } : {},
|
|
51
|
+
...defaults?.enable_url ? { enable_url: defaults.enable_url } : {}
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
return {
|
|
56
|
+
statusCode: messageOrStatus,
|
|
57
|
+
body: maybeBody ?? {
|
|
58
|
+
type: defaults?.type ?? ErrorType.API_ERROR,
|
|
59
|
+
code: defaults?.code ?? "unknown_error",
|
|
60
|
+
message: defaults?.message ?? `Request failed with status ${messageOrStatus}`,
|
|
61
|
+
doc_url: defaults?.doc_url ?? DEFAULT_DOC_URL
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
var CStarError = class extends Error {
|
|
66
|
+
constructor(messageOrStatus, body) {
|
|
67
|
+
const { statusCode, body: resolved } = normalizeArgs(messageOrStatus, body);
|
|
68
|
+
super(resolved.message);
|
|
69
|
+
this.name = "CStarError";
|
|
70
|
+
this.type = resolved.type;
|
|
71
|
+
this.code = resolved.code;
|
|
72
|
+
this.param = resolved.param;
|
|
73
|
+
this.docUrl = resolved.doc_url;
|
|
74
|
+
this.requestId = resolved.request_id;
|
|
75
|
+
this.statusCode = statusCode;
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
var CStarAuthenticationError = class extends CStarError {
|
|
79
|
+
constructor(messageOrStatus, body) {
|
|
80
|
+
const { statusCode, body: resolved } = normalizeArgs(messageOrStatus, body, {
|
|
81
|
+
type: ErrorType.AUTHENTICATION_ERROR,
|
|
82
|
+
code: "authentication_failed",
|
|
83
|
+
doc_url: `${DEFAULT_DOC_URL}#authentication-error`
|
|
84
|
+
});
|
|
85
|
+
super(statusCode, resolved);
|
|
86
|
+
this.name = "CStarAuthenticationError";
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
var CStarRateLimitError = class extends CStarError {
|
|
90
|
+
constructor(messageOrStatus, body, retryAfter) {
|
|
91
|
+
const { statusCode, body: resolved } = normalizeArgs(messageOrStatus, body, {
|
|
92
|
+
type: ErrorType.RATE_LIMIT_ERROR,
|
|
93
|
+
code: "rate_limit_exceeded",
|
|
94
|
+
doc_url: `${DEFAULT_DOC_URL}#rate-limit-error`
|
|
95
|
+
});
|
|
96
|
+
super(statusCode === 0 ? 429 : statusCode, resolved);
|
|
97
|
+
this.name = "CStarRateLimitError";
|
|
98
|
+
this.retryAfter = retryAfter ?? 60;
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
var CStarNotFoundError = class extends CStarError {
|
|
102
|
+
constructor(messageOrStatus, body) {
|
|
103
|
+
const { statusCode, body: resolved } = normalizeArgs(messageOrStatus, body, {
|
|
104
|
+
type: ErrorType.NOT_FOUND_ERROR,
|
|
105
|
+
code: "resource_not_found",
|
|
106
|
+
doc_url: `${DEFAULT_DOC_URL}#not-found-error`
|
|
107
|
+
});
|
|
108
|
+
super(statusCode, resolved);
|
|
109
|
+
this.name = "CStarNotFoundError";
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
var CStarValidationError = class extends CStarError {
|
|
113
|
+
constructor(messageOrStatus, body) {
|
|
114
|
+
const { statusCode, body: resolved } = normalizeArgs(messageOrStatus, body, {
|
|
115
|
+
type: ErrorType.INVALID_REQUEST_ERROR,
|
|
116
|
+
code: "validation_error",
|
|
117
|
+
doc_url: `${DEFAULT_DOC_URL}#validation-error`
|
|
118
|
+
});
|
|
119
|
+
super(statusCode, resolved);
|
|
120
|
+
this.name = "CStarValidationError";
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
var CStarPermissionError = class extends CStarError {
|
|
124
|
+
constructor(messageOrStatus, body) {
|
|
125
|
+
const { statusCode, body: resolved } = normalizeArgs(messageOrStatus, body, {
|
|
126
|
+
type: ErrorType.PERMISSION_ERROR,
|
|
127
|
+
code: "permission_denied",
|
|
128
|
+
doc_url: `${DEFAULT_DOC_URL}#permission-error`
|
|
129
|
+
});
|
|
130
|
+
super(statusCode, resolved);
|
|
131
|
+
this.name = "CStarPermissionError";
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
var CStarConflictError = class extends CStarError {
|
|
135
|
+
constructor(messageOrStatus, body) {
|
|
136
|
+
const { statusCode, body: resolved } = normalizeArgs(messageOrStatus, body, {
|
|
137
|
+
type: ErrorType.CONFLICT_ERROR,
|
|
138
|
+
code: "conflict",
|
|
139
|
+
doc_url: `${DEFAULT_DOC_URL}#conflict-error`
|
|
140
|
+
});
|
|
141
|
+
super(statusCode, resolved);
|
|
142
|
+
this.name = "CStarConflictError";
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
var CStarServerError = class extends CStarError {
|
|
146
|
+
constructor(messageOrStatus, body) {
|
|
147
|
+
const { statusCode, body: resolved } = normalizeArgs(messageOrStatus, body, {
|
|
148
|
+
type: ErrorType.SERVER_ERROR,
|
|
149
|
+
code: "server_error",
|
|
150
|
+
doc_url: `${DEFAULT_DOC_URL}#server-error`
|
|
151
|
+
});
|
|
152
|
+
super(statusCode, resolved);
|
|
153
|
+
this.name = "CStarServerError";
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
var CStarFeatureDisabledError = class extends CStarError {
|
|
157
|
+
constructor(messageOrStatus, body) {
|
|
158
|
+
const { statusCode, body: resolved } = normalizeArgs(messageOrStatus, body, {
|
|
159
|
+
type: ErrorType.FEATURE_NOT_CONFIGURED,
|
|
160
|
+
code: "feature_not_configured",
|
|
161
|
+
doc_url: `${DEFAULT_DOC_URL}#feature-not-configured`
|
|
162
|
+
});
|
|
163
|
+
super(statusCode, resolved);
|
|
164
|
+
this.name = "CStarFeatureDisabledError";
|
|
165
|
+
this.feature = resolved.feature ?? "unknown";
|
|
166
|
+
this.enableUrl = resolved.enable_url ?? "";
|
|
167
|
+
}
|
|
168
|
+
};
|
|
169
|
+
var TYPE_TO_CLASS = {
|
|
170
|
+
[ErrorType.AUTHENTICATION_ERROR]: CStarAuthenticationError,
|
|
171
|
+
[ErrorType.PERMISSION_ERROR]: CStarPermissionError,
|
|
172
|
+
[ErrorType.RATE_LIMIT_ERROR]: CStarRateLimitError,
|
|
173
|
+
[ErrorType.NOT_FOUND_ERROR]: CStarNotFoundError,
|
|
174
|
+
[ErrorType.INVALID_REQUEST_ERROR]: CStarValidationError,
|
|
175
|
+
[ErrorType.CONFLICT_ERROR]: CStarConflictError,
|
|
176
|
+
[ErrorType.SERVER_ERROR]: CStarServerError,
|
|
177
|
+
[ErrorType.FEATURE_NOT_CONFIGURED]: CStarFeatureDisabledError
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
// src/quickhelp/index.ts
|
|
27
181
|
var DEFAULT_BASE_URL = "https://www.cstar.help";
|
|
28
182
|
var QuickHelpClient = class {
|
|
29
183
|
constructor(config) {
|
|
30
|
-
|
|
31
|
-
|
|
184
|
+
this.resolveTeamIdPromise = null;
|
|
185
|
+
if (!config?.teamId && !config?.teamSlug) {
|
|
186
|
+
throw new Error(
|
|
187
|
+
'QuickHelpClient: either `teamId` or `teamSlug` is required. Pass `teamSlug` (e.g. "acme") for the easiest setup.'
|
|
188
|
+
);
|
|
32
189
|
}
|
|
33
190
|
this.baseUrl = (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
|
|
34
|
-
this.teamId = config.teamId;
|
|
191
|
+
this.teamId = config.teamId ?? null;
|
|
192
|
+
this.teamSlug = config.teamSlug ?? null;
|
|
193
|
+
this.publishableKey = config.publishableKey ?? null;
|
|
194
|
+
this.mode = this.publishableKey?.startsWith("pk_test_") ? "test" : "live";
|
|
195
|
+
if (this.publishableKey && !/^pk_(test|live)_/.test(this.publishableKey)) {
|
|
196
|
+
throw new Error(
|
|
197
|
+
"[cStar] QuickHelpClient: publishableKey must start with `pk_test_` or `pk_live_`. Secret keys (`sk_*`) cannot be used in browser/anonymous contexts."
|
|
198
|
+
);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
authHeaders() {
|
|
202
|
+
return this.publishableKey ? { Authorization: `Bearer ${this.publishableKey}` } : {};
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Resolve `teamSlug` → `teamId` lazily on the first call that needs it.
|
|
206
|
+
* Cached for the life of the client. NEW-v2-05.
|
|
207
|
+
*/
|
|
208
|
+
async resolveTeamId() {
|
|
209
|
+
if (this.teamId) return this.teamId;
|
|
210
|
+
if (!this.teamSlug) throw new Error("QuickHelpClient: no teamId or teamSlug set");
|
|
211
|
+
if (this.resolveTeamIdPromise) return this.resolveTeamIdPromise;
|
|
212
|
+
this.resolveTeamIdPromise = (async () => {
|
|
213
|
+
const url = `${this.baseUrl}/api/widget/team-by-slug?teamSlug=${encodeURIComponent(this.teamSlug)}`;
|
|
214
|
+
const res = await globalThis.fetch(url, { method: "GET", headers: this.authHeaders() });
|
|
215
|
+
if (!res.ok) {
|
|
216
|
+
throw new Error(
|
|
217
|
+
`QuickHelpClient: could not resolve teamSlug "${this.teamSlug}" (HTTP ${res.status}).`
|
|
218
|
+
);
|
|
219
|
+
}
|
|
220
|
+
const body = await res.json();
|
|
221
|
+
const id = body?.data?.teamId;
|
|
222
|
+
if (!id) {
|
|
223
|
+
throw new Error(
|
|
224
|
+
`QuickHelpClient: lookup for teamSlug "${this.teamSlug}" returned no teamId.`
|
|
225
|
+
);
|
|
226
|
+
}
|
|
227
|
+
this.teamId = id;
|
|
228
|
+
return id;
|
|
229
|
+
})();
|
|
230
|
+
try {
|
|
231
|
+
return await this.resolveTeamIdPromise;
|
|
232
|
+
} catch (err) {
|
|
233
|
+
this.resolveTeamIdPromise = null;
|
|
234
|
+
throw err;
|
|
235
|
+
}
|
|
35
236
|
}
|
|
36
237
|
/**
|
|
37
238
|
* Fetch the sanitized public config (title, subtitle, placeholder,
|
|
@@ -41,8 +242,9 @@ var QuickHelpClient = class {
|
|
|
41
242
|
* Returns `null` if Quick Help is disabled on the team (404).
|
|
42
243
|
*/
|
|
43
244
|
async config() {
|
|
44
|
-
const
|
|
45
|
-
const
|
|
245
|
+
const teamId = await this.resolveTeamId();
|
|
246
|
+
const url = `${this.baseUrl}/api/quickhelp/config/${encodeURIComponent(teamId)}`;
|
|
247
|
+
const res = await globalThis.fetch(url, { method: "GET", headers: this.authHeaders() });
|
|
46
248
|
if (res.status === 404) return null;
|
|
47
249
|
if (!res.ok) {
|
|
48
250
|
const body2 = await res.json().catch(() => null);
|
|
@@ -58,18 +260,29 @@ var QuickHelpClient = class {
|
|
|
58
260
|
* property set from the response body.
|
|
59
261
|
*/
|
|
60
262
|
async ask(params) {
|
|
263
|
+
const teamId = await this.resolveTeamId();
|
|
61
264
|
const url = `${this.baseUrl}/api/quickhelp/ask`;
|
|
62
265
|
const res = await globalThis.fetch(url, {
|
|
63
266
|
method: "POST",
|
|
64
|
-
headers: { "Content-Type": "application/json" },
|
|
267
|
+
headers: { "Content-Type": "application/json", ...this.authHeaders() },
|
|
65
268
|
body: JSON.stringify({
|
|
66
|
-
team_id:
|
|
269
|
+
team_id: teamId,
|
|
67
270
|
session_id: params.sessionId ?? null,
|
|
68
271
|
question: params.question
|
|
69
272
|
})
|
|
70
273
|
});
|
|
71
274
|
const body = await res.json().catch(() => null);
|
|
72
275
|
if (!res.ok || !body?.success || !body.data) {
|
|
276
|
+
if (res.status === 503 || body?.error?.code === "feature_not_configured") {
|
|
277
|
+
throw new CStarFeatureDisabledError(res.status, {
|
|
278
|
+
type: "feature_not_configured",
|
|
279
|
+
code: "feature_not_configured",
|
|
280
|
+
message: body?.error?.message ?? "Quick Help is not available on this team. Enable an AI Agent (Settings \u2192 AI Agents) and configure Quick Help (Settings \u2192 Quick Help) before calling .ask().",
|
|
281
|
+
doc_url: "https://cstar.help/developers/api/errors#feature-not-configured",
|
|
282
|
+
feature: "quickHelp",
|
|
283
|
+
enable_url: `${this.baseUrl}/team/${encodeURIComponent(teamId)}/settings?section=quickHelp`
|
|
284
|
+
});
|
|
285
|
+
}
|
|
73
286
|
const message = body?.error?.message ?? `Quick Help ask failed: ${res.status}`;
|
|
74
287
|
const err = new QuickHelpError(message, {
|
|
75
288
|
status: res.status,
|
|
@@ -1,7 +1,28 @@
|
|
|
1
|
-
/**
|
|
1
|
+
/**
|
|
2
|
+
* Options for the QuickHelpClient. No auth — Quick Help is anonymous by
|
|
3
|
+
* design.
|
|
4
|
+
*
|
|
5
|
+
* NEW-v2-05: pass either `teamId` (UUID, fastest — no roundtrip) or the
|
|
6
|
+
* easier-to-discover `teamSlug`. The slug is resolved to a UUID on the
|
|
7
|
+
* first network call and cached for the life of the client. At least one
|
|
8
|
+
* is required.
|
|
9
|
+
*/
|
|
2
10
|
interface QuickHelpConfig {
|
|
3
|
-
/** Your team's UUID.
|
|
4
|
-
teamId
|
|
11
|
+
/** Your team's UUID. Either this or `teamSlug` is required. */
|
|
12
|
+
teamId?: string;
|
|
13
|
+
/**
|
|
14
|
+
* Your team's slug (e.g. `acme`). Resolved to `teamId` lazily via the
|
|
15
|
+
* public `/api/widget/team-by-slug` endpoint on the first call. Cached
|
|
16
|
+
* thereafter. Either this or `teamId` is required.
|
|
17
|
+
*/
|
|
18
|
+
teamSlug?: string;
|
|
19
|
+
/**
|
|
20
|
+
* Optional publishable key (`pk_test_*` or `pk_live_*`). Sent as
|
|
21
|
+
* `Authorization: Bearer` so test-mode dev sessions can be scoped
|
|
22
|
+
* separately from live customer sessions in your analytics. Backwards-
|
|
23
|
+
* compatible: omit and the client behaves exactly as before.
|
|
24
|
+
*/
|
|
25
|
+
publishableKey?: string;
|
|
5
26
|
/** Override the base URL (defaults to https://www.cstar.help). */
|
|
6
27
|
baseUrl?: string;
|
|
7
28
|
}
|
|
@@ -60,8 +81,20 @@ interface QuickHelpAskResult {
|
|
|
60
81
|
*/
|
|
61
82
|
declare class QuickHelpClient {
|
|
62
83
|
private readonly baseUrl;
|
|
63
|
-
|
|
84
|
+
/** Cached resolved teamId. `null` until the first lookup completes. */
|
|
85
|
+
private teamId;
|
|
86
|
+
private readonly teamSlug;
|
|
87
|
+
private resolveTeamIdPromise;
|
|
88
|
+
private readonly publishableKey;
|
|
89
|
+
/** Resolved mode based on the publishable-key prefix. */
|
|
90
|
+
readonly mode: 'live' | 'test';
|
|
64
91
|
constructor(config: QuickHelpConfig);
|
|
92
|
+
private authHeaders;
|
|
93
|
+
/**
|
|
94
|
+
* Resolve `teamSlug` → `teamId` lazily on the first call that needs it.
|
|
95
|
+
* Cached for the life of the client. NEW-v2-05.
|
|
96
|
+
*/
|
|
97
|
+
private resolveTeamId;
|
|
65
98
|
/**
|
|
66
99
|
* Fetch the sanitized public config (title, subtitle, placeholder,
|
|
67
100
|
* theme overrides). Never includes agent id or escalation contact
|
|
@@ -1,7 +1,28 @@
|
|
|
1
|
-
/**
|
|
1
|
+
/**
|
|
2
|
+
* Options for the QuickHelpClient. No auth — Quick Help is anonymous by
|
|
3
|
+
* design.
|
|
4
|
+
*
|
|
5
|
+
* NEW-v2-05: pass either `teamId` (UUID, fastest — no roundtrip) or the
|
|
6
|
+
* easier-to-discover `teamSlug`. The slug is resolved to a UUID on the
|
|
7
|
+
* first network call and cached for the life of the client. At least one
|
|
8
|
+
* is required.
|
|
9
|
+
*/
|
|
2
10
|
interface QuickHelpConfig {
|
|
3
|
-
/** Your team's UUID.
|
|
4
|
-
teamId
|
|
11
|
+
/** Your team's UUID. Either this or `teamSlug` is required. */
|
|
12
|
+
teamId?: string;
|
|
13
|
+
/**
|
|
14
|
+
* Your team's slug (e.g. `acme`). Resolved to `teamId` lazily via the
|
|
15
|
+
* public `/api/widget/team-by-slug` endpoint on the first call. Cached
|
|
16
|
+
* thereafter. Either this or `teamId` is required.
|
|
17
|
+
*/
|
|
18
|
+
teamSlug?: string;
|
|
19
|
+
/**
|
|
20
|
+
* Optional publishable key (`pk_test_*` or `pk_live_*`). Sent as
|
|
21
|
+
* `Authorization: Bearer` so test-mode dev sessions can be scoped
|
|
22
|
+
* separately from live customer sessions in your analytics. Backwards-
|
|
23
|
+
* compatible: omit and the client behaves exactly as before.
|
|
24
|
+
*/
|
|
25
|
+
publishableKey?: string;
|
|
5
26
|
/** Override the base URL (defaults to https://www.cstar.help). */
|
|
6
27
|
baseUrl?: string;
|
|
7
28
|
}
|
|
@@ -60,8 +81,20 @@ interface QuickHelpAskResult {
|
|
|
60
81
|
*/
|
|
61
82
|
declare class QuickHelpClient {
|
|
62
83
|
private readonly baseUrl;
|
|
63
|
-
|
|
84
|
+
/** Cached resolved teamId. `null` until the first lookup completes. */
|
|
85
|
+
private teamId;
|
|
86
|
+
private readonly teamSlug;
|
|
87
|
+
private resolveTeamIdPromise;
|
|
88
|
+
private readonly publishableKey;
|
|
89
|
+
/** Resolved mode based on the publishable-key prefix. */
|
|
90
|
+
readonly mode: 'live' | 'test';
|
|
64
91
|
constructor(config: QuickHelpConfig);
|
|
92
|
+
private authHeaders;
|
|
93
|
+
/**
|
|
94
|
+
* Resolve `teamSlug` → `teamId` lazily on the first call that needs it.
|
|
95
|
+
* Cached for the life of the client. NEW-v2-05.
|
|
96
|
+
*/
|
|
97
|
+
private resolveTeamId;
|
|
65
98
|
/**
|
|
66
99
|
* Fetch the sanitized public config (title, subtitle, placeholder,
|
|
67
100
|
* theme overrides). Never includes agent id or escalation contact
|