@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/index.cjs CHANGED
@@ -24,6 +24,7 @@ __export(src_exports, {
24
24
  CStarClient: () => CStarClient,
25
25
  CStarConflictError: () => CStarConflictError,
26
26
  CStarError: () => CStarError,
27
+ CStarFeatureDisabledError: () => CStarFeatureDisabledError,
27
28
  CStarNotFoundError: () => CStarNotFoundError,
28
29
  CStarPermissionError: () => CStarPermissionError,
29
30
  CStarRateLimitError: () => CStarRateLimitError,
@@ -44,102 +45,211 @@ var ErrorType = {
44
45
  NOT_FOUND_ERROR: "not_found_error",
45
46
  CONFLICT_ERROR: "conflict_error",
46
47
  RATE_LIMIT_ERROR: "rate_limit_error",
48
+ FEATURE_NOT_CONFIGURED: "feature_not_configured",
47
49
  API_ERROR: "api_error",
48
50
  SERVER_ERROR: "server_error"
49
51
  };
52
+ var DEFAULT_DOC_URL = "https://cstar.help/developers/api/errors";
53
+ function normalizeArgs(messageOrStatus, maybeBody, defaults) {
54
+ if (typeof messageOrStatus === "string") {
55
+ return {
56
+ statusCode: defaults?.code === "rate_limit_error" ? 429 : 0,
57
+ body: {
58
+ type: defaults?.type ?? ErrorType.API_ERROR,
59
+ code: defaults?.code ?? "sdk_error",
60
+ message: messageOrStatus,
61
+ doc_url: defaults?.doc_url ?? DEFAULT_DOC_URL,
62
+ ...defaults?.feature ? { feature: defaults.feature } : {},
63
+ ...defaults?.enable_url ? { enable_url: defaults.enable_url } : {}
64
+ }
65
+ };
66
+ }
67
+ return {
68
+ statusCode: messageOrStatus,
69
+ body: maybeBody ?? {
70
+ type: defaults?.type ?? ErrorType.API_ERROR,
71
+ code: defaults?.code ?? "unknown_error",
72
+ message: defaults?.message ?? `Request failed with status ${messageOrStatus}`,
73
+ doc_url: defaults?.doc_url ?? DEFAULT_DOC_URL
74
+ }
75
+ };
76
+ }
50
77
  var CStarError = class extends Error {
51
- constructor(statusCode, body) {
52
- super(body.message);
78
+ constructor(messageOrStatus, body) {
79
+ const { statusCode, body: resolved } = normalizeArgs(messageOrStatus, body);
80
+ super(resolved.message);
53
81
  this.name = "CStarError";
54
- this.type = body.type;
55
- this.code = body.code;
56
- this.param = body.param;
57
- this.docUrl = body.doc_url;
58
- this.requestId = body.request_id;
82
+ this.type = resolved.type;
83
+ this.code = resolved.code;
84
+ this.param = resolved.param;
85
+ this.docUrl = resolved.doc_url;
86
+ this.requestId = resolved.request_id;
59
87
  this.statusCode = statusCode;
60
88
  }
61
89
  };
62
90
  var CStarAuthenticationError = class extends CStarError {
63
- constructor(statusCode, body) {
64
- super(statusCode, body);
91
+ constructor(messageOrStatus, body) {
92
+ const { statusCode, body: resolved } = normalizeArgs(messageOrStatus, body, {
93
+ type: ErrorType.AUTHENTICATION_ERROR,
94
+ code: "authentication_failed",
95
+ doc_url: `${DEFAULT_DOC_URL}#authentication-error`
96
+ });
97
+ super(statusCode, resolved);
65
98
  this.name = "CStarAuthenticationError";
66
99
  }
67
100
  };
68
101
  var CStarRateLimitError = class extends CStarError {
69
- constructor(statusCode, body, retryAfter) {
70
- super(statusCode, body);
102
+ constructor(messageOrStatus, body, retryAfter) {
103
+ const { statusCode, body: resolved } = normalizeArgs(messageOrStatus, body, {
104
+ type: ErrorType.RATE_LIMIT_ERROR,
105
+ code: "rate_limit_exceeded",
106
+ doc_url: `${DEFAULT_DOC_URL}#rate-limit-error`
107
+ });
108
+ super(statusCode === 0 ? 429 : statusCode, resolved);
71
109
  this.name = "CStarRateLimitError";
72
- this.retryAfter = retryAfter;
110
+ this.retryAfter = retryAfter ?? 60;
73
111
  }
74
112
  };
75
113
  var CStarNotFoundError = class extends CStarError {
76
- constructor(statusCode, body) {
77
- super(statusCode, body);
114
+ constructor(messageOrStatus, body) {
115
+ const { statusCode, body: resolved } = normalizeArgs(messageOrStatus, body, {
116
+ type: ErrorType.NOT_FOUND_ERROR,
117
+ code: "resource_not_found",
118
+ doc_url: `${DEFAULT_DOC_URL}#not-found-error`
119
+ });
120
+ super(statusCode, resolved);
78
121
  this.name = "CStarNotFoundError";
79
122
  }
80
123
  };
81
124
  var CStarValidationError = class extends CStarError {
82
- constructor(statusCode, body) {
83
- super(statusCode, body);
125
+ constructor(messageOrStatus, body) {
126
+ const { statusCode, body: resolved } = normalizeArgs(messageOrStatus, body, {
127
+ type: ErrorType.INVALID_REQUEST_ERROR,
128
+ code: "validation_error",
129
+ doc_url: `${DEFAULT_DOC_URL}#validation-error`
130
+ });
131
+ super(statusCode, resolved);
84
132
  this.name = "CStarValidationError";
85
133
  }
86
134
  };
87
135
  var CStarPermissionError = class extends CStarError {
88
- constructor(statusCode, body) {
89
- super(statusCode, body);
136
+ constructor(messageOrStatus, body) {
137
+ const { statusCode, body: resolved } = normalizeArgs(messageOrStatus, body, {
138
+ type: ErrorType.PERMISSION_ERROR,
139
+ code: "permission_denied",
140
+ doc_url: `${DEFAULT_DOC_URL}#permission-error`
141
+ });
142
+ super(statusCode, resolved);
90
143
  this.name = "CStarPermissionError";
91
144
  }
92
145
  };
93
146
  var CStarConflictError = class extends CStarError {
94
- constructor(statusCode, body) {
95
- super(statusCode, body);
147
+ constructor(messageOrStatus, body) {
148
+ const { statusCode, body: resolved } = normalizeArgs(messageOrStatus, body, {
149
+ type: ErrorType.CONFLICT_ERROR,
150
+ code: "conflict",
151
+ doc_url: `${DEFAULT_DOC_URL}#conflict-error`
152
+ });
153
+ super(statusCode, resolved);
96
154
  this.name = "CStarConflictError";
97
155
  }
98
156
  };
99
157
  var CStarServerError = class extends CStarError {
100
- constructor(statusCode, body) {
101
- super(statusCode, body);
158
+ constructor(messageOrStatus, body) {
159
+ const { statusCode, body: resolved } = normalizeArgs(messageOrStatus, body, {
160
+ type: ErrorType.SERVER_ERROR,
161
+ code: "server_error",
162
+ doc_url: `${DEFAULT_DOC_URL}#server-error`
163
+ });
164
+ super(statusCode, resolved);
102
165
  this.name = "CStarServerError";
103
166
  }
104
167
  };
168
+ var CStarFeatureDisabledError = class extends CStarError {
169
+ constructor(messageOrStatus, body) {
170
+ const { statusCode, body: resolved } = normalizeArgs(messageOrStatus, body, {
171
+ type: ErrorType.FEATURE_NOT_CONFIGURED,
172
+ code: "feature_not_configured",
173
+ doc_url: `${DEFAULT_DOC_URL}#feature-not-configured`
174
+ });
175
+ super(statusCode, resolved);
176
+ this.name = "CStarFeatureDisabledError";
177
+ this.feature = resolved.feature ?? "unknown";
178
+ this.enableUrl = resolved.enable_url ?? "";
179
+ }
180
+ };
181
+ var CStarRealtimeUnavailableError = class extends CStarError {
182
+ constructor(message) {
183
+ const resolved = message ?? "EventSource is not available in this environment. Real-time subscriptions only work in the browser. Move the call to a client-only path (`useEffect` / `onMount`), or pass an `eventSource` polyfill via the realtime options. See https://cstar.help/developers/sdk/realtime#ssr";
184
+ super(0, {
185
+ type: ErrorType.API_ERROR,
186
+ code: "realtime_unavailable",
187
+ message: resolved,
188
+ doc_url: "https://cstar.help/developers/sdk/realtime#ssr"
189
+ });
190
+ this.name = "CStarRealtimeUnavailableError";
191
+ }
192
+ };
193
+ var STATUS_TO_CLASS = {
194
+ 400: CStarValidationError,
195
+ 401: CStarAuthenticationError,
196
+ 403: CStarPermissionError,
197
+ 404: CStarNotFoundError,
198
+ 409: CStarConflictError,
199
+ 422: CStarValidationError,
200
+ 429: CStarRateLimitError
201
+ };
202
+ var TYPE_TO_CLASS = {
203
+ [ErrorType.AUTHENTICATION_ERROR]: CStarAuthenticationError,
204
+ [ErrorType.PERMISSION_ERROR]: CStarPermissionError,
205
+ [ErrorType.RATE_LIMIT_ERROR]: CStarRateLimitError,
206
+ [ErrorType.NOT_FOUND_ERROR]: CStarNotFoundError,
207
+ [ErrorType.INVALID_REQUEST_ERROR]: CStarValidationError,
208
+ [ErrorType.CONFLICT_ERROR]: CStarConflictError,
209
+ [ErrorType.SERVER_ERROR]: CStarServerError,
210
+ [ErrorType.FEATURE_NOT_CONFIGURED]: CStarFeatureDisabledError
211
+ };
105
212
  function parseError(statusCode, body, retryAfter) {
106
213
  const errorBody = body?.error ?? {
107
214
  type: ErrorType.API_ERROR,
108
215
  code: "unknown_error",
109
216
  message: `Request failed with status ${statusCode}`,
110
- doc_url: "https://cstar.help/developers/api/errors"
217
+ doc_url: DEFAULT_DOC_URL
111
218
  };
112
- switch (errorBody.type) {
113
- case ErrorType.AUTHENTICATION_ERROR:
114
- return new CStarAuthenticationError(statusCode, errorBody);
115
- case ErrorType.PERMISSION_ERROR:
116
- return new CStarPermissionError(statusCode, errorBody);
117
- case ErrorType.RATE_LIMIT_ERROR:
118
- return new CStarRateLimitError(statusCode, errorBody, retryAfter ?? 60);
119
- case ErrorType.NOT_FOUND_ERROR:
120
- return new CStarNotFoundError(statusCode, errorBody);
121
- case ErrorType.INVALID_REQUEST_ERROR:
122
- return new CStarValidationError(statusCode, errorBody);
123
- case ErrorType.CONFLICT_ERROR:
124
- return new CStarConflictError(statusCode, errorBody);
125
- case ErrorType.SERVER_ERROR:
126
- return new CStarServerError(statusCode, errorBody);
127
- default:
128
- if (statusCode === 403) return new CStarPermissionError(statusCode, errorBody);
129
- if (statusCode === 409) return new CStarConflictError(statusCode, errorBody);
130
- if (statusCode >= 500) return new CStarServerError(statusCode, errorBody);
131
- return new CStarError(statusCode, errorBody);
219
+ if (statusCode === 429) {
220
+ return new CStarRateLimitError(statusCode, errorBody, retryAfter ?? 60);
221
+ }
222
+ const StatusCls = STATUS_TO_CLASS[statusCode];
223
+ if (StatusCls) {
224
+ return new StatusCls(statusCode, errorBody);
132
225
  }
226
+ const TypeCls = TYPE_TO_CLASS[errorBody.type];
227
+ if (TypeCls) {
228
+ return new TypeCls(statusCode, errorBody);
229
+ }
230
+ if (statusCode >= 500) return new CStarServerError(statusCode, errorBody);
231
+ return new CStarError(statusCode, errorBody);
133
232
  }
134
233
 
135
234
  // src/client.ts
136
- var SDK_VERSION = "0.5.2";
235
+ var SDK_VERSION = "0.14.0";
137
236
  var DEFAULT_BASE_URL = "https://www.cstar.help";
138
237
  var DEFAULT_API_VERSION = "2026-03-01";
139
238
  var DEFAULT_MAX_RETRIES = 3;
140
239
  var DEFAULT_TIMEOUT = 3e4;
141
240
  var HttpClient = class {
142
241
  constructor(config) {
242
+ /**
243
+ * Side-channel metadata from the most recent response. Holds the server
244
+ * `requestId`, `timestamp`, and (for list endpoints) `pagination`. Mutable
245
+ * per-call — read it immediately after awaiting the call.
246
+ *
247
+ * ```ts
248
+ * const ticket = await cstar.tickets.create({...});
249
+ * console.error('Created ticket', ticket.id, 'request:', cstar.lastMeta.requestId);
250
+ * ```
251
+ */
252
+ this.lastMeta = { requestId: null, timestamp: null, pagination: null };
143
253
  if (!config || typeof config.apiKey !== "string" || config.apiKey.length === 0) {
144
254
  throw new Error(
145
255
  "[cStar] CStarClient: apiKey is required. Pass a secret key (sk_live_... / sk_test_...) or a publishable key (pk_live_... / pk_test_...). See https://cstar.help/developers/quickstart"
@@ -170,7 +280,32 @@ var HttpClient = class {
170
280
  * Automatically retries on 5xx errors and rate limits.
171
281
  */
172
282
  async request(method, path, options) {
173
- const url = this.buildUrl(path, options?.query);
283
+ return this._sendRequest(method, this.buildUrl(path, options?.query), options);
284
+ }
285
+ /**
286
+ * Like `request()` but skips the `/api/v1/teams/{teamId}` prefix. Used for
287
+ * the small set of non-team-scoped endpoints (`/auth/whoami`, etc).
288
+ *
289
+ * @internal — exposed to CStarClient for `whoami()` and similar; not part
290
+ * of the documented public surface.
291
+ */
292
+ async requestUnscoped(method, path, options) {
293
+ const baseUrl = this.config.baseUrl + "/api/v1" + path;
294
+ const finalUrl = this.appendQuery(baseUrl, options?.query);
295
+ return this._sendRequest(method, finalUrl, options);
296
+ }
297
+ appendQuery(url, query) {
298
+ if (!query) return url;
299
+ const params = new URLSearchParams();
300
+ for (const [key, value] of Object.entries(query)) {
301
+ if (value === void 0 || value === null) continue;
302
+ if (Array.isArray(value)) for (const v of value) params.append(`${key}[]`, v);
303
+ else params.set(key, String(value));
304
+ }
305
+ const qs = params.toString();
306
+ return qs ? `${url}?${qs}` : url;
307
+ }
308
+ async _sendRequest(method, url, options) {
174
309
  const headers = this.buildHeaders(options?.idempotencyKey);
175
310
  const body = options?.body ? JSON.stringify(options.body) : void 0;
176
311
  let lastError = null;
@@ -201,13 +336,9 @@ var HttpClient = class {
201
336
  if (response.ok) {
202
337
  if (response.status === 204) return void 0;
203
338
  const json = await response.json();
204
- const requestId2 = response.headers.get("x-request-id") ?? response.headers.get("x-cstar-request-id");
205
- if (requestId2 && json && typeof json === "object" && "meta" in json) {
206
- const existing = json.meta;
207
- const metaBase = existing && typeof existing === "object" && !Array.isArray(existing) ? existing : {};
208
- json.meta = { ...metaBase, requestId: requestId2 };
209
- }
210
- return json;
339
+ const headerRequestId = response.headers.get("x-request-id") ?? response.headers.get("x-cstar-request-id");
340
+ this.captureMeta(json, headerRequestId);
341
+ return this.unwrapEnvelope(json);
211
342
  }
212
343
  const errorBody = await response.json().catch(() => null);
213
344
  const retryAfter = parseInt(response.headers.get("Retry-After") ?? "", 10) || void 0;
@@ -229,6 +360,51 @@ var HttpClient = class {
229
360
  }
230
361
  throw lastError ?? new Error("Request failed after retries");
231
362
  }
363
+ /**
364
+ * Capture `meta`, `requestId`, and `pagination` from the raw response
365
+ * into `this.lastMeta` before unwrapping the envelope.
366
+ */
367
+ captureMeta(body, headerRequestId) {
368
+ if (body && typeof body === "object" && !Array.isArray(body)) {
369
+ const obj = body;
370
+ const meta = obj.meta && typeof obj.meta === "object" ? obj.meta : null;
371
+ const pagination = obj.pagination && typeof obj.pagination === "object" ? obj.pagination : null;
372
+ this.lastMeta = {
373
+ requestId: headerRequestId ?? (typeof meta?.requestId === "string" ? meta.requestId : null),
374
+ timestamp: typeof meta?.timestamp === "string" ? meta.timestamp : null,
375
+ pagination
376
+ };
377
+ return;
378
+ }
379
+ this.lastMeta = { requestId: headerRequestId, timestamp: null, pagination: null };
380
+ }
381
+ /**
382
+ * Unwrap the legacy `{success, data, meta, pagination?}` envelope.
383
+ * - `{success:true, data: array, pagination}` → `{data, pagination, hasMore}`
384
+ * - `{success:true, data: object}` → `data` (bare resource)
385
+ * - other shapes pass through unchanged so subpath SDKs (chat, library) keep
386
+ * their bespoke shapes for now.
387
+ */
388
+ unwrapEnvelope(body) {
389
+ if (!body || typeof body !== "object" || Array.isArray(body)) return body;
390
+ const obj = body;
391
+ if (obj.success !== true || !("data" in obj)) return body;
392
+ const data = obj.data;
393
+ if (Array.isArray(data)) {
394
+ const pagination = obj.pagination ?? null;
395
+ return {
396
+ data,
397
+ pagination: pagination ?? {
398
+ total: data.length,
399
+ page: 1,
400
+ pageSize: data.length,
401
+ hasMore: false
402
+ },
403
+ hasMore: pagination?.hasMore ?? false
404
+ };
405
+ }
406
+ return data;
407
+ }
232
408
  buildUrl(path, query) {
233
409
  const base = `${this.config.baseUrl}/api/v1/teams/${this.config.teamId}${path}`;
234
410
  if (!query) return base;
@@ -301,6 +477,18 @@ var CStarRealtime = class {
301
477
  this.autoReconnect = options?.autoReconnect ?? true;
302
478
  this.maxRetries = options?.maxRetries ?? 10;
303
479
  this.types = options?.types;
480
+ this.eventSourceCtor = options?.eventSource;
481
+ }
482
+ /**
483
+ * Resolve the EventSource constructor to use for this connection.
484
+ * Returns the explicit polyfill when one was injected, otherwise the
485
+ * global. Returns `undefined` when neither is available — callers must
486
+ * convert to `CStarRealtimeUnavailableError` before touching it.
487
+ */
488
+ resolveEventSource() {
489
+ if (this.eventSourceCtor) return this.eventSourceCtor;
490
+ const fromGlobal = globalThis.EventSource;
491
+ return typeof fromGlobal === "function" ? fromGlobal : void 0;
304
492
  }
305
493
  /** Subscribe to a specific event type. Supports wildcards (e.g., 'ticket.*'). Returns an unsubscribe function. */
306
494
  on(eventType, handler) {
@@ -355,6 +543,9 @@ var CStarRealtime = class {
355
543
  /** Start the SSE connection. Called automatically on first handler registration. */
356
544
  connect() {
357
545
  if (this.eventSource || this.destroyed || this.connecting) return;
546
+ if (!this.resolveEventSource()) {
547
+ throw new CStarRealtimeUnavailableError();
548
+ }
358
549
  this.connecting = true;
359
550
  const headers = this.httpClient.getAuthHeaders();
360
551
  const rawKey = headers.Authorization?.replace("Bearer ", "") ?? "";
@@ -393,7 +584,12 @@ var CStarRealtime = class {
393
584
  }
394
585
  const separator = qs ? "&" : "?";
395
586
  const authenticatedUrl = authToken ? `${url}${separator}token=${authToken}` : url;
396
- this.eventSource = new EventSource(authenticatedUrl);
587
+ const Ctor = this.resolveEventSource();
588
+ if (!Ctor) {
589
+ this.connecting = false;
590
+ throw new CStarRealtimeUnavailableError();
591
+ }
592
+ this.eventSource = new Ctor(authenticatedUrl);
397
593
  this.eventSource.onopen = () => {
398
594
  this.connecting = false;
399
595
  this.retryCount = 0;
@@ -812,6 +1008,14 @@ var BaseResource = class {
812
1008
  async del(id) {
813
1009
  return this.client.request("DELETE", `${this.basePath}/${id}`);
814
1010
  }
1011
+ /**
1012
+ * Delete a resource by ID. Alias for `del()` — kept because IDE
1013
+ * auto-complete and documentation both surface `delete` first. Closes
1014
+ * NEW-v2-06.
1015
+ */
1016
+ async delete(id) {
1017
+ return this.del(id);
1018
+ }
815
1019
  /**
816
1020
  * Auto-paginating async iterator that yields every item across all pages.
817
1021
  *
@@ -1910,7 +2114,12 @@ var GameResource = class {
1910
2114
  async getPlayer(memberId) {
1911
2115
  return this.client.request("GET", `/game/player/${memberId}`);
1912
2116
  }
1913
- /** Get the team leaderboard. */
2117
+ /**
2118
+ * Get the team leaderboard. Returns the unwrapped envelope from the
2119
+ * `/game/leaderboard` endpoint (`{entries, totalParticipants, period, ...}`)
2120
+ * — wider than a flat array because the server includes the period and
2121
+ * a participant count alongside the entries.
2122
+ */
1914
2123
  async leaderboard(params) {
1915
2124
  return this.client.request("GET", "/game/leaderboard", {
1916
2125
  query: params
@@ -1933,12 +2142,12 @@ var GameResource = class {
1933
2142
  */
1934
2143
  subscribeBoss(realtime) {
1935
2144
  const fetchFn = async () => {
1936
- const res = await this.boss.current();
2145
+ const boss = await this.boss.current();
2146
+ const list = boss.active ? [boss] : [];
1937
2147
  return {
1938
- success: true,
1939
- data: res.data.active ? [res.data] : [],
1940
- pagination: { total: res.data.active ? 1 : 0, page: 1, pageSize: 1, hasMore: false },
1941
- meta: { requestId: "", timestamp: (/* @__PURE__ */ new Date()).toISOString() }
2148
+ data: list,
2149
+ pagination: { total: list.length, page: 1, pageSize: 1, hasMore: false },
2150
+ hasMore: false
1942
2151
  };
1943
2152
  };
1944
2153
  return new Subscription(realtime, fetchFn, "/game/boss");
@@ -1949,12 +2158,11 @@ var GameResource = class {
1949
2158
  */
1950
2159
  subscribePlayer(realtime, userId) {
1951
2160
  const fetchFn = async () => {
1952
- const res = await this.player({ userId });
2161
+ const player = await this.player({ userId });
1953
2162
  return {
1954
- success: true,
1955
- data: [res.data],
2163
+ data: [player],
1956
2164
  pagination: { total: 1, page: 1, pageSize: 1, hasMore: false },
1957
- meta: { requestId: "", timestamp: (/* @__PURE__ */ new Date()).toISOString() }
2165
+ hasMore: false
1958
2166
  };
1959
2167
  };
1960
2168
  return new Subscription(realtime, fetchFn, "/game/player");
@@ -1965,14 +2173,12 @@ var GameResource = class {
1965
2173
  */
1966
2174
  subscribeLeaderboard(realtime, params) {
1967
2175
  const fetchFn = async () => {
1968
- const res = await this.leaderboard(params);
1969
- const envelope = res.data;
1970
- const entries = Array.isArray(envelope) ? envelope : envelope?.entries ?? [];
2176
+ const board = await this.leaderboard(params);
2177
+ const entries = board.entries ?? [];
1971
2178
  return {
1972
- success: true,
1973
2179
  data: entries,
1974
2180
  pagination: { total: entries.length, page: 1, pageSize: 100, hasMore: false },
1975
- meta: { requestId: "", timestamp: (/* @__PURE__ */ new Date()).toISOString() }
2181
+ hasMore: false
1976
2182
  };
1977
2183
  };
1978
2184
  return new Subscription(realtime, fetchFn, "/game/leaderboard");
@@ -1983,13 +2189,12 @@ var GameResource = class {
1983
2189
  */
1984
2190
  subscribeActivity(realtime) {
1985
2191
  const fetchFn = async () => {
1986
- const res = await this.activity.list({ limit: 50 });
1987
- const data = res.data.data || [];
2192
+ const feed = await this.activity.list({ limit: 50 });
2193
+ const items = feed.data ?? [];
1988
2194
  return {
1989
- success: true,
1990
- data,
1991
- pagination: { total: data.length, page: 1, pageSize: 50, hasMore: false },
1992
- meta: { requestId: "", timestamp: (/* @__PURE__ */ new Date()).toISOString() }
2195
+ data: items,
2196
+ pagination: { total: items.length, page: 1, pageSize: 50, hasMore: false },
2197
+ hasMore: false
1993
2198
  };
1994
2199
  };
1995
2200
  return new Subscription(realtime, fetchFn, "/game/activity");
@@ -2227,6 +2432,35 @@ var CStarClient = class {
2227
2432
  get isTestMode() {
2228
2433
  return this._httpClient.environment === "test";
2229
2434
  }
2435
+ /**
2436
+ * Validate the configured API key and return the team + key metadata it
2437
+ * resolves to. Useful for confirming the key is wired up correctly during
2438
+ * onboarding (and for AI assistants that want a one-call sanity check).
2439
+ *
2440
+ * Closes F-018.
2441
+ *
2442
+ * ```ts
2443
+ * const me = await cstar.whoami();
2444
+ * console.log(me.teamSlug, me.environment); // 'acme', 'test'
2445
+ * ```
2446
+ */
2447
+ async whoami() {
2448
+ return this._httpClient.requestUnscoped("GET", "/auth/whoami");
2449
+ }
2450
+ /**
2451
+ * Side-channel metadata from the most recent HTTP response. Holds the
2452
+ * server `requestId` (for support escalations), `timestamp`, and the
2453
+ * `pagination` info from list endpoints. Reset on every call — read it
2454
+ * immediately after awaiting the call you care about.
2455
+ *
2456
+ * ```ts
2457
+ * const ticket = await cstar.tickets.create({...});
2458
+ * console.error('Created', ticket.id, 'request:', cstar.lastMeta.requestId);
2459
+ * ```
2460
+ */
2461
+ get lastMeta() {
2462
+ return this._httpClient.lastMeta;
2463
+ }
2230
2464
  };
2231
2465
  // Annotate the CommonJS export names for ESM import in node:
2232
2466
  0 && (module.exports = {
@@ -2234,6 +2468,7 @@ var CStarClient = class {
2234
2468
  CStarClient,
2235
2469
  CStarConflictError,
2236
2470
  CStarError,
2471
+ CStarFeatureDisabledError,
2237
2472
  CStarNotFoundError,
2238
2473
  CStarPermissionError,
2239
2474
  CStarRateLimitError,