pgbeam 0.4.1 → 0.4.3

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.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { o as operationsByPath, a as operationsByTag } from './operations-map.gen-g44nmkz5.js';
1
+ import { o as operationsByPath, a as operationsByTag } from './operations-map.gen-g1lyg7rw.js';
2
2
 
3
3
  class ApiError extends Error {
4
4
  constructor(status, statusText, body){
@@ -144,6 +144,58 @@ function isMutatingMethod(method) {
144
144
  const upper = method.toUpperCase();
145
145
  return upper === "POST" || upper === "PATCH";
146
146
  }
147
+ /**
148
+ * Resolve a lazy token, or give up once `timeoutMs` has passed without it.
149
+ *
150
+ * A token function is a network call in disguise. Both browser clients resolve
151
+ * a JWT from an auth endpoint (`authClient.token()`), so an auth endpoint that
152
+ * accepts the request and never answers is a stall like any other. It just
153
+ * happened before the attempt loop, where none of this module's bounds reach:
154
+ * `AbortSignal.timeout` is attached to the fetch, `totalBudgetMs` is measured
155
+ * from the first attempt, and neither exists yet. A `try`/`catch` in the token
156
+ * function does not cover it either, because a call that never answers never
157
+ * rejects. The result was a request with no ceiling of any kind, which is
158
+ * exactly what every other bound in this file was written to rule out.
159
+ *
160
+ * The failure is reported as a timed-out `NetworkError`, the same shape a
161
+ * stalled attempt produces, because it is the same event to a caller: the
162
+ * request never got an answer and a second try tests the same thing again.
163
+ * `lib/query-provider.tsx` in the dashboard already withholds its retry on
164
+ * `timedOut`, so it gets the right behaviour here for free.
165
+ *
166
+ * The bound is `timeoutMs`, the per-attempt ceiling, because the token round
167
+ * trip is an attempt. A call whose token stalls and whose request then stalls
168
+ * costs two of them, which is the honest cost of two sequential round trips and
169
+ * still finite, where before it was unbounded.
170
+ *
171
+ * `timeoutMs` of 0 disables the fetch timeout by documented contract, so it
172
+ * disables this one too rather than inventing a ceiling the caller turned off.
173
+ */ async function resolveToken(token, ctx) {
174
+ if (typeof token !== "function") return token;
175
+ if (ctx.timeoutMs <= 0) return token();
176
+ const stalled = Symbol("token-timeout");
177
+ let timer;
178
+ const deadline = new Promise((resolve)=>{
179
+ timer = setTimeout(()=>resolve(stalled), ctx.timeoutMs);
180
+ });
181
+ // A rejection from `token()` wins the race and propagates unchanged: the
182
+ // function decided it had failed, and relabelling that as a network timeout
183
+ // would lose the reason.
184
+ const resolved = await Promise.race([
185
+ token(),
186
+ deadline
187
+ ]).finally(()=>clearTimeout(timer));
188
+ if (resolved !== stalled) return resolved;
189
+ throw new NetworkError({
190
+ method: ctx.method,
191
+ url: ctx.url,
192
+ attempts: 0,
193
+ elapsedMs: Date.now() - ctx.startedAt,
194
+ timedOut: true,
195
+ timeoutMs: ctx.timeoutMs,
196
+ cause: new Error("token resolution did not settle")
197
+ });
198
+ }
147
199
  async function fetcher(options) {
148
200
  let url = options.path;
149
201
  if (options.pathParams) {
@@ -159,19 +211,27 @@ async function fetcher(options) {
159
211
  }
160
212
  }
161
213
  }
162
- const headers = {};
163
- if (options.token) {
164
- headers.Authorization = `Bearer ${options.token}`;
165
- }
166
- if (options.body !== undefined) {
167
- headers["Content-Type"] = "application/json";
168
- }
169
214
  const fetchFn = options.fetchImpl ?? globalThis.fetch;
170
215
  const retry = resolveRetry(options.retry);
171
216
  const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
172
217
  const startedAt = Date.now();
173
218
  const urlStr = fullUrl.toString();
174
219
  const fetchBody = options.body !== undefined ? JSON.stringify(options.body) : undefined;
220
+ // Resolved once, before the attempt loop, so retries reuse one token rather
221
+ // than paying for a fresh auth round trip each time.
222
+ const token = await resolveToken(options.token, {
223
+ method: options.method,
224
+ url: urlStr,
225
+ startedAt,
226
+ timeoutMs
227
+ });
228
+ const headers = {};
229
+ if (token) {
230
+ headers.Authorization = `Bearer ${token}`;
231
+ }
232
+ if (options.body !== undefined) {
233
+ headers["Content-Type"] = "application/json";
234
+ }
175
235
  // Generate idempotency key once, reused across all retry attempts.
176
236
  const idempotencyKey = retry.maxRetries > 0 && retry.idempotencyKeys && isMutatingMethod(options.method) ? generateUUID() : undefined;
177
237
  for(let attempt = 0; attempt <= retry.maxRetries; attempt++){
@@ -274,14 +334,16 @@ class PgBeamClient {
274
334
  this._timeoutMs = options.timeoutMs;
275
335
  this._operations = options.operations ?? publicRegistry;
276
336
  }
277
- async _resolveToken() {
278
- if (typeof this._tokenOrFn === "function") {
279
- return this._tokenOrFn();
280
- }
281
- return this._tokenOrFn;
282
- }
283
- async _send(meta, params) {
284
- const token = await this._resolveToken();
337
+ /**
338
+ * `token` is handed to the fetcher unresolved on purpose.
339
+ *
340
+ * Awaiting a token function here put the auth round trip outside every bound
341
+ * the fetcher applies, so a token endpoint that accepted the request and never
342
+ * answered left the call outstanding with no ceiling at all: not `timeoutMs`,
343
+ * not the retry budget, and with no `timedOut` signal for a caller to branch
344
+ * on. The fetcher resolves it under the same per-attempt timeout as the
345
+ * request it authenticates.
346
+ */ async _send(meta, params) {
285
347
  return fetcher({
286
348
  method: meta.method,
287
349
  path: meta.path,
@@ -289,7 +351,7 @@ class PgBeamClient {
289
351
  queryParams: params.queryParams,
290
352
  body: params.body,
291
353
  baseUrl: this._baseUrl,
292
- token,
354
+ token: this._tokenOrFn,
293
355
  fetchImpl: this._fetchImpl,
294
356
  onResponse: this._onResponse,
295
357
  retry: this._retry,
@@ -53,6 +53,10 @@
53
53
  method: "GET",
54
54
  path: "/v1/projects/{project_id}/audit-logs/export"
55
55
  },
56
+ getAuditSessionSummary: {
57
+ method: "GET",
58
+ path: "/v1/projects/{project_id}/audit-logs/sessions/{session_id}"
59
+ },
56
60
  verifyAuditChain: {
57
61
  method: "GET",
58
62
  path: "/v1/projects/{project_id}/audit-logs/verify"
@@ -455,6 +459,11 @@ const operationsByPath = {
455
459
  path: "/v1/projects/{project_id}/audit-logs/export",
456
460
  operationId: "exportAuditLogs"
457
461
  },
462
+ "GET /v1/projects/{project_id}/audit-logs/sessions/{session_id}": {
463
+ method: "GET",
464
+ path: "/v1/projects/{project_id}/audit-logs/sessions/{session_id}",
465
+ operationId: "getAuditSessionSummary"
466
+ },
458
467
  "GET /v1/projects/{project_id}/audit-logs/verify": {
459
468
  method: "GET",
460
469
  path: "/v1/projects/{project_id}/audit-logs/verify",
@@ -53,6 +53,10 @@
53
53
  method: "GET",
54
54
  path: "/v1/projects/{project_id}/audit-logs/export"
55
55
  },
56
+ getAuditSessionSummary: {
57
+ method: "GET",
58
+ path: "/v1/projects/{project_id}/audit-logs/sessions/{session_id}"
59
+ },
56
60
  verifyAuditChain: {
57
61
  method: "GET",
58
62
  path: "/v1/projects/{project_id}/audit-logs/verify"
@@ -455,6 +459,11 @@ const operationsByPath = {
455
459
  path: "/v1/projects/{project_id}/audit-logs/export",
456
460
  operationId: "exportAuditLogs"
457
461
  },
462
+ "GET /v1/projects/{project_id}/audit-logs/sessions/{session_id}": {
463
+ method: "GET",
464
+ path: "/v1/projects/{project_id}/audit-logs/sessions/{session_id}",
465
+ operationId: "getAuditSessionSummary"
466
+ },
458
467
  "GET /v1/projects/{project_id}/audit-logs/verify": {
459
468
  method: "GET",
460
469
  path: "/v1/projects/{project_id}/audit-logs/verify",