@cstar.help/js 0.16.1 → 0.17.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.
@@ -0,0 +1,398 @@
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 const CStarErrorImpl: {
48
+ new (messageOrStatus: string | number, body?: ApiErrorBody): {
49
+ readonly type: string;
50
+ readonly code: string;
51
+ readonly param?: string;
52
+ readonly docUrl: string;
53
+ readonly requestId?: string;
54
+ readonly statusCode: number;
55
+ name: string;
56
+ message: string;
57
+ stack?: string;
58
+ };
59
+ captureStackTrace(targetObject: object, constructorOpt?: Function): void;
60
+ prepareStackTrace(err: Error, stackTraces: NodeJS.CallSite[]): any;
61
+ stackTraceLimit: number;
62
+ };
63
+ declare const CStarAuthenticationErrorImpl: {
64
+ new (messageOrStatus: string | number, body?: ApiErrorBody): {
65
+ readonly type: string;
66
+ readonly code: string;
67
+ readonly param?: string;
68
+ readonly docUrl: string;
69
+ readonly requestId?: string;
70
+ readonly statusCode: number;
71
+ name: string;
72
+ message: string;
73
+ stack?: string;
74
+ };
75
+ captureStackTrace(targetObject: object, constructorOpt?: Function): void;
76
+ prepareStackTrace(err: Error, stackTraces: NodeJS.CallSite[]): any;
77
+ stackTraceLimit: number;
78
+ };
79
+ declare const CStarRateLimitErrorImpl: {
80
+ new (messageOrStatus: string | number, body?: ApiErrorBody, retryAfter?: number): {
81
+ readonly retryAfter: number;
82
+ readonly type: string;
83
+ readonly code: string;
84
+ readonly param?: string;
85
+ readonly docUrl: string;
86
+ readonly requestId?: string;
87
+ readonly statusCode: number;
88
+ name: string;
89
+ message: string;
90
+ stack?: string;
91
+ };
92
+ captureStackTrace(targetObject: object, constructorOpt?: Function): void;
93
+ prepareStackTrace(err: Error, stackTraces: NodeJS.CallSite[]): any;
94
+ stackTraceLimit: number;
95
+ };
96
+ declare const CStarNotFoundErrorImpl: {
97
+ new (messageOrStatus: string | number, body?: ApiErrorBody): {
98
+ readonly type: string;
99
+ readonly code: string;
100
+ readonly param?: string;
101
+ readonly docUrl: string;
102
+ readonly requestId?: string;
103
+ readonly statusCode: number;
104
+ name: string;
105
+ message: string;
106
+ stack?: string;
107
+ };
108
+ captureStackTrace(targetObject: object, constructorOpt?: Function): void;
109
+ prepareStackTrace(err: Error, stackTraces: NodeJS.CallSite[]): any;
110
+ stackTraceLimit: number;
111
+ };
112
+ declare const CStarValidationErrorImpl: {
113
+ new (messageOrStatus: string | number, body?: ApiErrorBody): {
114
+ readonly type: string;
115
+ readonly code: string;
116
+ readonly param?: string;
117
+ readonly docUrl: string;
118
+ readonly requestId?: string;
119
+ readonly statusCode: number;
120
+ name: string;
121
+ message: string;
122
+ stack?: string;
123
+ };
124
+ captureStackTrace(targetObject: object, constructorOpt?: Function): void;
125
+ prepareStackTrace(err: Error, stackTraces: NodeJS.CallSite[]): any;
126
+ stackTraceLimit: number;
127
+ };
128
+ declare const CStarPermissionErrorImpl: {
129
+ new (messageOrStatus: string | number, body?: ApiErrorBody): {
130
+ readonly type: string;
131
+ readonly code: string;
132
+ readonly param?: string;
133
+ readonly docUrl: string;
134
+ readonly requestId?: string;
135
+ readonly statusCode: number;
136
+ name: string;
137
+ message: string;
138
+ stack?: string;
139
+ };
140
+ captureStackTrace(targetObject: object, constructorOpt?: Function): void;
141
+ prepareStackTrace(err: Error, stackTraces: NodeJS.CallSite[]): any;
142
+ stackTraceLimit: number;
143
+ };
144
+ declare const CStarConflictErrorImpl: {
145
+ new (messageOrStatus: string | number, body?: ApiErrorBody): {
146
+ readonly type: string;
147
+ readonly code: string;
148
+ readonly param?: string;
149
+ readonly docUrl: string;
150
+ readonly requestId?: string;
151
+ readonly statusCode: number;
152
+ name: string;
153
+ message: string;
154
+ stack?: string;
155
+ };
156
+ captureStackTrace(targetObject: object, constructorOpt?: Function): void;
157
+ prepareStackTrace(err: Error, stackTraces: NodeJS.CallSite[]): any;
158
+ stackTraceLimit: number;
159
+ };
160
+ declare const CStarServerErrorImpl: {
161
+ new (messageOrStatus: string | number, body?: ApiErrorBody): {
162
+ readonly type: string;
163
+ readonly code: string;
164
+ readonly param?: string;
165
+ readonly docUrl: string;
166
+ readonly requestId?: string;
167
+ readonly statusCode: number;
168
+ name: string;
169
+ message: string;
170
+ stack?: string;
171
+ };
172
+ captureStackTrace(targetObject: object, constructorOpt?: Function): void;
173
+ prepareStackTrace(err: Error, stackTraces: NodeJS.CallSite[]): any;
174
+ stackTraceLimit: number;
175
+ };
176
+ declare const CStarFeatureDisabledErrorImpl: {
177
+ new (messageOrStatus: string | number, body?: ApiErrorBody): {
178
+ readonly feature: string;
179
+ readonly enableUrl: string;
180
+ readonly type: string;
181
+ readonly code: string;
182
+ readonly param?: string;
183
+ readonly docUrl: string;
184
+ readonly requestId?: string;
185
+ readonly statusCode: number;
186
+ name: string;
187
+ message: string;
188
+ stack?: string;
189
+ };
190
+ captureStackTrace(targetObject: object, constructorOpt?: Function): void;
191
+ prepareStackTrace(err: Error, stackTraces: NodeJS.CallSite[]): any;
192
+ stackTraceLimit: number;
193
+ };
194
+ declare const CStarRealtimeUnavailableErrorImpl: {
195
+ new (message?: string): {
196
+ readonly type: string;
197
+ readonly code: string;
198
+ readonly param?: string;
199
+ readonly docUrl: string;
200
+ readonly requestId?: string;
201
+ readonly statusCode: number;
202
+ name: string;
203
+ message: string;
204
+ stack?: string;
205
+ };
206
+ captureStackTrace(targetObject: object, constructorOpt?: Function): void;
207
+ prepareStackTrace(err: Error, stackTraces: NodeJS.CallSite[]): any;
208
+ stackTraceLimit: number;
209
+ };
210
+ declare const CStarError: {
211
+ new (messageOrStatus: string | number, body?: ApiErrorBody): {
212
+ readonly type: string;
213
+ readonly code: string;
214
+ readonly param?: string;
215
+ readonly docUrl: string;
216
+ readonly requestId?: string;
217
+ readonly statusCode: number;
218
+ name: string;
219
+ message: string;
220
+ stack?: string;
221
+ };
222
+ captureStackTrace(targetObject: object, constructorOpt?: Function): void;
223
+ prepareStackTrace(err: Error, stackTraces: NodeJS.CallSite[]): any;
224
+ stackTraceLimit: number;
225
+ };
226
+ type CStarError = InstanceType<typeof CStarErrorImpl>;
227
+ declare const CStarAuthenticationError: {
228
+ new (messageOrStatus: string | number, body?: ApiErrorBody): {
229
+ readonly type: string;
230
+ readonly code: string;
231
+ readonly param?: string;
232
+ readonly docUrl: string;
233
+ readonly requestId?: string;
234
+ readonly statusCode: number;
235
+ name: string;
236
+ message: string;
237
+ stack?: string;
238
+ };
239
+ captureStackTrace(targetObject: object, constructorOpt?: Function): void;
240
+ prepareStackTrace(err: Error, stackTraces: NodeJS.CallSite[]): any;
241
+ stackTraceLimit: number;
242
+ };
243
+ type CStarAuthenticationError = InstanceType<typeof CStarAuthenticationErrorImpl>;
244
+ declare const CStarRateLimitError: {
245
+ new (messageOrStatus: string | number, body?: ApiErrorBody, retryAfter?: number): {
246
+ readonly retryAfter: number;
247
+ readonly type: string;
248
+ readonly code: string;
249
+ readonly param?: string;
250
+ readonly docUrl: string;
251
+ readonly requestId?: string;
252
+ readonly statusCode: number;
253
+ name: string;
254
+ message: string;
255
+ stack?: string;
256
+ };
257
+ captureStackTrace(targetObject: object, constructorOpt?: Function): void;
258
+ prepareStackTrace(err: Error, stackTraces: NodeJS.CallSite[]): any;
259
+ stackTraceLimit: number;
260
+ };
261
+ type CStarRateLimitError = InstanceType<typeof CStarRateLimitErrorImpl>;
262
+ declare const CStarNotFoundError: {
263
+ new (messageOrStatus: string | number, body?: ApiErrorBody): {
264
+ readonly type: string;
265
+ readonly code: string;
266
+ readonly param?: string;
267
+ readonly docUrl: string;
268
+ readonly requestId?: string;
269
+ readonly statusCode: number;
270
+ name: string;
271
+ message: string;
272
+ stack?: string;
273
+ };
274
+ captureStackTrace(targetObject: object, constructorOpt?: Function): void;
275
+ prepareStackTrace(err: Error, stackTraces: NodeJS.CallSite[]): any;
276
+ stackTraceLimit: number;
277
+ };
278
+ type CStarNotFoundError = InstanceType<typeof CStarNotFoundErrorImpl>;
279
+ declare const CStarValidationError: {
280
+ new (messageOrStatus: string | number, body?: ApiErrorBody): {
281
+ readonly type: string;
282
+ readonly code: string;
283
+ readonly param?: string;
284
+ readonly docUrl: string;
285
+ readonly requestId?: string;
286
+ readonly statusCode: number;
287
+ name: string;
288
+ message: string;
289
+ stack?: string;
290
+ };
291
+ captureStackTrace(targetObject: object, constructorOpt?: Function): void;
292
+ prepareStackTrace(err: Error, stackTraces: NodeJS.CallSite[]): any;
293
+ stackTraceLimit: number;
294
+ };
295
+ type CStarValidationError = InstanceType<typeof CStarValidationErrorImpl>;
296
+ declare const CStarPermissionError: {
297
+ new (messageOrStatus: string | number, body?: ApiErrorBody): {
298
+ readonly type: string;
299
+ readonly code: string;
300
+ readonly param?: string;
301
+ readonly docUrl: string;
302
+ readonly requestId?: string;
303
+ readonly statusCode: number;
304
+ name: string;
305
+ message: string;
306
+ stack?: string;
307
+ };
308
+ captureStackTrace(targetObject: object, constructorOpt?: Function): void;
309
+ prepareStackTrace(err: Error, stackTraces: NodeJS.CallSite[]): any;
310
+ stackTraceLimit: number;
311
+ };
312
+ type CStarPermissionError = InstanceType<typeof CStarPermissionErrorImpl>;
313
+ declare const CStarConflictError: {
314
+ new (messageOrStatus: string | number, body?: ApiErrorBody): {
315
+ readonly type: string;
316
+ readonly code: string;
317
+ readonly param?: string;
318
+ readonly docUrl: string;
319
+ readonly requestId?: string;
320
+ readonly statusCode: number;
321
+ name: string;
322
+ message: string;
323
+ stack?: string;
324
+ };
325
+ captureStackTrace(targetObject: object, constructorOpt?: Function): void;
326
+ prepareStackTrace(err: Error, stackTraces: NodeJS.CallSite[]): any;
327
+ stackTraceLimit: number;
328
+ };
329
+ type CStarConflictError = InstanceType<typeof CStarConflictErrorImpl>;
330
+ declare const CStarServerError: {
331
+ new (messageOrStatus: string | number, body?: ApiErrorBody): {
332
+ readonly type: string;
333
+ readonly code: string;
334
+ readonly param?: string;
335
+ readonly docUrl: string;
336
+ readonly requestId?: string;
337
+ readonly statusCode: number;
338
+ name: string;
339
+ message: string;
340
+ stack?: string;
341
+ };
342
+ captureStackTrace(targetObject: object, constructorOpt?: Function): void;
343
+ prepareStackTrace(err: Error, stackTraces: NodeJS.CallSite[]): any;
344
+ stackTraceLimit: number;
345
+ };
346
+ type CStarServerError = InstanceType<typeof CStarServerErrorImpl>;
347
+ declare const CStarFeatureDisabledError: {
348
+ new (messageOrStatus: string | number, body?: ApiErrorBody): {
349
+ readonly feature: string;
350
+ readonly enableUrl: string;
351
+ readonly type: string;
352
+ readonly code: string;
353
+ readonly param?: string;
354
+ readonly docUrl: string;
355
+ readonly requestId?: string;
356
+ readonly statusCode: number;
357
+ name: string;
358
+ message: string;
359
+ stack?: string;
360
+ };
361
+ captureStackTrace(targetObject: object, constructorOpt?: Function): void;
362
+ prepareStackTrace(err: Error, stackTraces: NodeJS.CallSite[]): any;
363
+ stackTraceLimit: number;
364
+ };
365
+ type CStarFeatureDisabledError = InstanceType<typeof CStarFeatureDisabledErrorImpl>;
366
+ declare const CStarRealtimeUnavailableError: {
367
+ new (message?: string): {
368
+ readonly type: string;
369
+ readonly code: string;
370
+ readonly param?: string;
371
+ readonly docUrl: string;
372
+ readonly requestId?: string;
373
+ readonly statusCode: number;
374
+ name: string;
375
+ message: string;
376
+ stack?: string;
377
+ };
378
+ captureStackTrace(targetObject: object, constructorOpt?: Function): void;
379
+ prepareStackTrace(err: Error, stackTraces: NodeJS.CallSite[]): any;
380
+ stackTraceLimit: number;
381
+ };
382
+ type CStarRealtimeUnavailableError = InstanceType<typeof CStarRealtimeUnavailableErrorImpl>;
383
+ /**
384
+ * Parse a public-route response (anonymous LibraryClient, CommunityClient,
385
+ * QuickHelpClient, AuthClient) into a typed `CStarError`.
386
+ *
387
+ * Public routes don't always emit the structured `{error: {type, code,
388
+ * doc_url, ...}}` envelope — many emit `{error: 'message string'}` or
389
+ * `{message: '...'}`. This helper normalizes both shapes and dispatches
390
+ * on HTTP status (closes F-026 and F-034 — Library/Auth used to throw
391
+ * plain `Error`).
392
+ */
393
+ declare function parsePublicError(status: number, body: unknown, fallbackMessage: string): CStarError;
394
+ declare function parseError(statusCode: number, body: {
395
+ error?: ApiErrorBody;
396
+ } | null, retryAfter?: number): CStarError;
397
+
398
+ 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 };
package/dist/index.cjs CHANGED
@@ -323,7 +323,8 @@ var HttpClient = class {
323
323
  }
324
324
  /**
325
325
  * Make an authenticated request to the cStar API.
326
- * Automatically retries on 5xx errors and rate limits.
326
+ * Automatically retries rate limits and retry-safe failures. POST/PATCH
327
+ * network and 5xx failures require an idempotency key to avoid duplicate writes.
327
328
  */
328
329
  async request(method, path, options) {
329
330
  return this._sendRequest(method, this.buildUrl(path, options?.query), options);
@@ -354,6 +355,7 @@ var HttpClient = class {
354
355
  async _sendRequest(method, url, options) {
355
356
  const headers = this.buildHeaders(options?.idempotencyKey);
356
357
  const body = options?.body ? JSON.stringify(options.body) : void 0;
358
+ const canRetryAmbiguousFailure = !["POST", "PATCH"].includes(method.toUpperCase()) || !!options?.idempotencyKey;
357
359
  let lastError = null;
358
360
  for (let attempt = 0; attempt <= this.config.maxRetries; attempt++) {
359
361
  if (attempt > 0 && lastError) {
@@ -377,7 +379,7 @@ var HttpClient = class {
377
379
  message: `Network request failed: ${networkErr.message}`,
378
380
  doc_url: "https://www.cstar.help/developers/errors#connection-errors"
379
381
  });
380
- if (attempt < this.config.maxRetries) continue;
382
+ if (canRetryAmbiguousFailure && attempt < this.config.maxRetries) continue;
381
383
  throw lastError;
382
384
  }
383
385
  if (response.ok) {
@@ -402,7 +404,7 @@ var HttpClient = class {
402
404
  throw lastError;
403
405
  }
404
406
  lastError = parseError(response.status, errorBody);
405
- if (attempt < this.config.maxRetries) continue;
407
+ if (canRetryAmbiguousFailure && attempt < this.config.maxRetries) continue;
406
408
  throw lastError;
407
409
  }
408
410
  throw lastError ?? new Error("Request failed after retries");
@@ -609,9 +611,13 @@ var CStarRealtime = class {
609
611
  this.exchangeToken().then(() => {
610
612
  this.connecting = false;
611
613
  this.connect();
612
- }).catch(() => {
614
+ }).catch((err) => {
613
615
  this.connecting = false;
614
- this.connectWithToken(rawKey);
616
+ if (this.destroyed) return;
617
+ this.emitError(err instanceof Error ? err : new Error(String(err)));
618
+ if (this.autoReconnect && this.retryCount < this.maxRetries) {
619
+ this.scheduleReconnect();
620
+ }
615
621
  });
616
622
  return;
617
623
  }
@@ -620,9 +626,10 @@ var CStarRealtime = class {
620
626
  }
621
627
  /**
622
628
  * Open the EventSource with the given auth token.
623
- * Extracted so both the happy path and the fallback path share logic.
629
+ * Secret keys reach this method only after exchanging for an SSE token.
624
630
  */
625
631
  connectWithToken(authToken) {
632
+ if (this.destroyed) return;
626
633
  const baseUrl = this.httpClient.getBaseUrl();
627
634
  const params = new URLSearchParams();
628
635
  if (this.types && this.types.length > 0) {
@@ -633,11 +640,6 @@ var CStarRealtime = class {
633
640
  }
634
641
  const qs = params.toString();
635
642
  const url = `${baseUrl}/events/stream${qs ? `?${qs}` : ""}`;
636
- if (authToken.startsWith("sk_") && typeof globalThis !== "undefined" && typeof globalThis.window !== "undefined") {
637
- console.warn(
638
- "[cStar] Secret API key is being passed via SSE query parameter. Query strings may be logged by proxies and CDNs. For production, use a server-side proxy to add the Authorization header."
639
- );
640
- }
641
643
  const separator = qs ? "&" : "?";
642
644
  const authenticatedUrl = authToken ? `${url}${separator}token=${authToken}` : url;
643
645
  const Ctor = this.resolveEventSource();
@@ -809,9 +811,14 @@ var CStarRealtime = class {
809
811
  */
810
812
  async exchangeToken() {
811
813
  const response = await this.httpClient.request("POST", "/events/token");
812
- const { token, expiresAt, expiresIn } = response.data;
814
+ if (this.destroyed) return;
815
+ const { token, expiresAt, expiresIn } = response;
816
+ const expiry = new Date(expiresAt).getTime();
817
+ if (typeof token !== "string" || !token || token.startsWith("sk_") || !Number.isFinite(expiry) || expiry <= Date.now() || !Number.isFinite(expiresIn) || expiresIn <= 0) {
818
+ throw new Error("SSE token exchange returned an invalid token or expiry");
819
+ }
813
820
  this.sseToken = token;
814
- this.sseTokenExpiresAt = new Date(expiresAt).getTime();
821
+ this.sseTokenExpiresAt = expiry;
815
822
  const refreshIn = Math.max((expiresIn - 30) * 1e3, expiresIn / 2 * 1e3);
816
823
  this.scheduleTokenRefresh(refreshIn);
817
824
  }
@@ -875,6 +882,8 @@ var Subscription = class {
875
882
  this.destroyed = false;
876
883
  /** Generation counter to prevent stale refresh() from overwriting SSE updates. */
877
884
  this.generation = 0;
885
+ /** Replay events against the initial snapshot instead of discarding that snapshot. */
886
+ this.initialEvents = [];
878
887
  this.init();
879
888
  }
880
889
  /** Current data array (updated in real-time). */
@@ -902,12 +911,12 @@ var Subscription = class {
902
911
  const gen = ++this.generation;
903
912
  try {
904
913
  const response = await this.fetchFn();
905
- if (gen !== this.generation) return;
914
+ if (this.destroyed || gen !== this.generation) return;
906
915
  this._data = response.data;
907
916
  this._error = null;
908
917
  this.emitChange();
909
918
  } catch (err) {
910
- if (gen !== this.generation) return;
919
+ if (this.destroyed || gen !== this.generation) return;
911
920
  this._error = err instanceof Error ? err : new Error(String(err));
912
921
  this.emitError(this._error);
913
922
  }
@@ -934,6 +943,7 @@ var Subscription = class {
934
943
  /** Stop the subscription and clean up all listeners. */
935
944
  unsubscribe() {
936
945
  this.destroyed = true;
946
+ this.initialEvents = [];
937
947
  if (this.boundEventHandler) {
938
948
  this.realtime.offAny(this.boundEventHandler);
939
949
  this.boundEventHandler = null;
@@ -948,14 +958,18 @@ var Subscription = class {
948
958
  const gen = ++this.generation;
949
959
  try {
950
960
  const response = await this.fetchFn();
951
- if (gen !== this.generation) return;
961
+ if (this.destroyed || gen !== this.generation) return;
952
962
  this._data = response.data;
953
963
  this._loading = false;
954
964
  this._error = null;
965
+ const events = this.initialEvents;
966
+ this.initialEvents = [];
967
+ for (const event of events) this.handleEvent(event);
955
968
  this.emitChange();
956
969
  } catch (err) {
957
- if (gen !== this.generation) return;
970
+ if (this.destroyed || gen !== this.generation) return;
958
971
  this._loading = false;
972
+ this.initialEvents = [];
959
973
  this._error = err instanceof Error ? err : new Error(String(err));
960
974
  this.emitError(this._error);
961
975
  }
@@ -977,6 +991,10 @@ var Subscription = class {
977
991
  }
978
992
  const entityData = this.extractEntity(event);
979
993
  if (!entityData || !getEntityId(entityData)) return;
994
+ if (this._loading) {
995
+ this.initialEvents.push(event);
996
+ return;
997
+ }
980
998
  this.generation++;
981
999
  if (event.type.endsWith(".created")) {
982
1000
  this.handleCreated(entityData);
@@ -2364,13 +2382,13 @@ var PreferencesResource = class {
2364
2382
  };
2365
2383
 
2366
2384
  // src/offline.ts
2367
- var STORAGE_KEY = "cstar_offline_queue";
2368
2385
  var OfflineQueue = class {
2369
2386
  constructor(httpClient, options) {
2370
2387
  this.httpClient = httpClient;
2371
2388
  this.items = [];
2372
2389
  this.autoFlushEnabled = false;
2373
2390
  this.onlineHandler = null;
2391
+ this.storageKey = `cstar_offline_queue:${httpClient.getBaseUrl()}:${httpClient.environment}`;
2374
2392
  this.useLocalStorage = options?.storage === "localStorage" && typeof globalThis !== "undefined" && typeof globalThis.localStorage !== "undefined";
2375
2393
  if (this.useLocalStorage) {
2376
2394
  this.loadFromStorage();
@@ -2411,7 +2429,7 @@ var OfflineQueue = class {
2411
2429
  const message = err instanceof Error ? err.message : String(err);
2412
2430
  results.push({ id: item.id, success: false, error: message });
2413
2431
  const statusCode = err.statusCode;
2414
- const isRetryable = !statusCode || statusCode >= 500;
2432
+ const isRetryable = !statusCode || statusCode === 429 || statusCode >= 500;
2415
2433
  if (isRetryable) {
2416
2434
  failedItems.push(item);
2417
2435
  }
@@ -2464,15 +2482,16 @@ var OfflineQueue = class {
2464
2482
  saveToStorage() {
2465
2483
  if (!this.useLocalStorage) return;
2466
2484
  try {
2467
- localStorage.setItem(STORAGE_KEY, JSON.stringify(this.items));
2485
+ localStorage.setItem(this.storageKey, JSON.stringify(this.items));
2468
2486
  } catch {
2469
2487
  }
2470
2488
  }
2471
2489
  loadFromStorage() {
2472
2490
  try {
2473
- const raw = localStorage.getItem(STORAGE_KEY);
2491
+ const raw = localStorage.getItem(this.storageKey);
2474
2492
  if (raw) {
2475
- this.items = JSON.parse(raw);
2493
+ const stored = JSON.parse(raw);
2494
+ this.items = Array.isArray(stored) ? stored : [];
2476
2495
  }
2477
2496
  } catch {
2478
2497
  this.items = [];