@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.
@@ -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/community/index.ts
2
215
  var DEFAULT_BASE_URL = "https://www.cstar.help";
3
216
  var CommunityClient = class {
@@ -6,6 +219,13 @@ var CommunityClient = class {
6
219
  this.teamId = null;
7
220
  this.baseUrl = (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
8
221
  this.teamSlug = config.teamSlug;
222
+ this.publishableKey = config.publishableKey ?? null;
223
+ this.mode = this.publishableKey?.startsWith("pk_test_") ? "test" : "live";
224
+ if (this.publishableKey && !/^pk_(test|live)_/.test(this.publishableKey)) {
225
+ throw new Error(
226
+ "[cStar] CommunityClient: publishableKey must start with `pk_test_` or `pk_live_`. Secret keys (`sk_*`) cannot be used in browser/anonymous contexts."
227
+ );
228
+ }
9
229
  }
10
230
  /**
11
231
  * Set a session token from identity verification.
@@ -222,13 +442,13 @@ var CommunityClient = class {
222
442
  */
223
443
  resolveTeamId() {
224
444
  if (this.teamId) return this.teamId;
225
- throw new Error(
445
+ throw new CStarValidationError(
226
446
  "Team ID is required for authenticated operations. Pass it via setSessionToken(token, teamId) or use ChatClient.identify() which provides it automatically."
227
447
  );
228
448
  }
229
449
  async authenticatedFetch(path, options) {
230
450
  if (!this.sessionToken) {
231
- throw new Error(
451
+ throw new CStarValidationError(
232
452
  "Session token required. Call setSessionToken() or use ChatClient.identify() first."
233
453
  );
234
454
  }
@@ -251,9 +471,8 @@ var CommunityClient = class {
251
471
  body: options.body ? JSON.stringify(options.body) : void 0
252
472
  });
253
473
  if (!response.ok) {
254
- const errorBody = await response.json().catch(() => ({ error: { message: "Request failed" } }));
255
- const message = typeof errorBody.error === "string" ? errorBody.error : errorBody.error?.message ?? `Community API error: ${response.status}`;
256
- throw new Error(message);
474
+ const errorBody = await response.json().catch(() => null);
475
+ throw parsePublicError(response.status, errorBody, `Community API error: ${response.status}`);
257
476
  }
258
477
  return response.json();
259
478
  }
@@ -267,14 +486,17 @@ var CommunityClient = class {
267
486
  const qs = params.toString();
268
487
  if (qs) url += `?${qs}`;
269
488
  }
489
+ const headers = { "Content-Type": "application/json" };
490
+ if (this.publishableKey) {
491
+ headers["Authorization"] = `Bearer ${this.publishableKey}`;
492
+ }
270
493
  const response = await globalThis.fetch(url, {
271
494
  method: "GET",
272
- headers: { "Content-Type": "application/json" }
495
+ headers
273
496
  });
274
497
  if (!response.ok) {
275
- const errorBody = await response.json().catch(() => ({ error: { message: "Request failed" } }));
276
- const message = typeof errorBody.error === "string" ? errorBody.error : errorBody.error?.message ?? `Community API error: ${response.status}`;
277
- throw new Error(message);
498
+ const errorBody = await response.json().catch(() => null);
499
+ throw parsePublicError(response.status, errorBody, `Community API error: ${response.status}`);
278
500
  }
279
501
  return response.json();
280
502
  }