@gebsecure01/sdk 0.2.1

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.js ADDED
@@ -0,0 +1,1218 @@
1
+ // src/clock.ts
2
+ function abortReason(signal) {
3
+ return signal.reason ?? new DOMException("The operation was aborted", "AbortError");
4
+ }
5
+ var systemClock = {
6
+ now: () => Date.now(),
7
+ sleep: (ms2, signal) => new Promise((resolve, reject) => {
8
+ if (signal?.aborted) return reject(abortReason(signal));
9
+ const onAbort = () => {
10
+ clearTimeout(timer);
11
+ reject(abortReason(signal));
12
+ };
13
+ const timer = setTimeout(() => {
14
+ signal?.removeEventListener("abort", onAbort);
15
+ resolve();
16
+ }, Math.max(0, ms2));
17
+ signal?.addEventListener("abort", onAbort, { once: true });
18
+ })
19
+ };
20
+
21
+ // src/errors.ts
22
+ var GebSecureError = class extends Error {
23
+ /** HTTP status, or 0 for client-side errors (network, timeouts, approval waits). */
24
+ status;
25
+ /** Machine-readable error code, e.g. `policy_denied`, `rate_limited`, `connection_error`. */
26
+ code;
27
+ /** Human-readable detail from the server (or the SDK). */
28
+ detail;
29
+ /** Server request id (`x-request-id`), when known. */
30
+ requestId;
31
+ /** W3C trace id of the request, when known. */
32
+ traceId;
33
+ /** Structured problem details (e.g. validation issues), when provided. */
34
+ details;
35
+ /** Problem type URI, when provided. */
36
+ type;
37
+ constructor(init) {
38
+ const detail = init.detail ?? init.code;
39
+ super(`${init.code}: ${detail}${init.requestId ? ` (request ${init.requestId})` : ""}`, init.cause !== void 0 ? { cause: init.cause } : void 0);
40
+ this.name = new.target.name;
41
+ this.status = init.status ?? 0;
42
+ this.code = init.code;
43
+ this.detail = detail;
44
+ this.requestId = init.requestId ?? null;
45
+ this.traceId = init.traceId ?? null;
46
+ this.details = init.details ?? null;
47
+ this.type = init.type ?? null;
48
+ }
49
+ };
50
+ var ApiError = class extends GebSecureError {
51
+ };
52
+ var AuthenticationError = class extends ApiError {
53
+ };
54
+ var PermissionDeniedError = class extends ApiError {
55
+ };
56
+ var PolicyDeniedError = class extends ApiError {
57
+ };
58
+ var ApprovalRequiredError = class extends ApiError {
59
+ };
60
+ var ValidationError = class extends ApiError {
61
+ };
62
+ var NotFoundError = class extends ApiError {
63
+ };
64
+ var ConflictError = class extends ApiError {
65
+ };
66
+ var UpstreamError = class extends ApiError {
67
+ };
68
+ var TimeoutError = class extends ApiError {
69
+ };
70
+ var UnavailableError = class extends ApiError {
71
+ };
72
+ var InternalError = class extends ApiError {
73
+ };
74
+ var RateLimitError = class extends ApiError {
75
+ /** Server-requested wait before retrying, in milliseconds (from `Retry-After`), if any. */
76
+ retryAfterMs;
77
+ constructor(init) {
78
+ super(init);
79
+ this.retryAfterMs = init.retryAfterMs ?? null;
80
+ }
81
+ };
82
+ var ConnectionError = class extends GebSecureError {
83
+ constructor(detail, cause) {
84
+ super({ code: "connection_error", detail, cause });
85
+ }
86
+ };
87
+ var ApprovalTimeoutError = class extends GebSecureError {
88
+ approvalId;
89
+ constructor(approvalId, timeoutMs) {
90
+ super({ code: "approval_timeout", detail: `Approval ${approvalId} still pending after ${timeoutMs} ms` });
91
+ this.approvalId = approvalId;
92
+ }
93
+ };
94
+ var ApprovalNotGrantedError = class extends GebSecureError {
95
+ approval;
96
+ constructor(approval) {
97
+ super({ code: "approval_not_granted", detail: `Approval ${approval.id} was ${approval.status}${approval.resolutionComment ? `: ${approval.resolutionComment}` : ""}` });
98
+ this.approval = approval;
99
+ }
100
+ };
101
+ var SimulationFailedError = class extends ApiError {
102
+ run;
103
+ constructor(run, meta = {}) {
104
+ const s = run.summary;
105
+ super({
106
+ status: 422,
107
+ code: "simulation_failed",
108
+ detail: `Simulation ${run.id ?? run.name ?? ""} ${run.status}: ${s?.failed ?? 0} failed, ${s?.errors ?? 0} errors`.replace(" ", " "),
109
+ requestId: meta.requestId ?? null,
110
+ traceId: meta.traceId ?? null
111
+ });
112
+ this.run = run;
113
+ }
114
+ };
115
+ var ConfigurationError = class extends GebSecureError {
116
+ constructor(detail) {
117
+ super({ code: "invalid_configuration", detail });
118
+ }
119
+ };
120
+ var STATUS_CODES = {
121
+ 400: "bad_request",
122
+ 401: "unauthenticated",
123
+ 403: "forbidden",
124
+ 404: "not_found",
125
+ 409: "conflict",
126
+ 412: "precondition_failed",
127
+ 422: "validation_failed",
128
+ 429: "rate_limited",
129
+ 502: "upstream_error",
130
+ 503: "unavailable",
131
+ 504: "timeout"
132
+ };
133
+ var CODE_CLASSES = {
134
+ unauthenticated: AuthenticationError,
135
+ forbidden: PermissionDeniedError,
136
+ policy_denied: PolicyDeniedError,
137
+ approval_required: ApprovalRequiredError,
138
+ validation_failed: ValidationError,
139
+ bad_request: ValidationError,
140
+ not_found: NotFoundError,
141
+ conflict: ConflictError,
142
+ precondition_failed: ConflictError,
143
+ upstream_error: UpstreamError,
144
+ timeout: TimeoutError,
145
+ unavailable: UnavailableError,
146
+ internal: InternalError
147
+ };
148
+ function codeForStatus(status) {
149
+ return STATUS_CODES[status] ?? (status >= 500 ? "internal" : "bad_request");
150
+ }
151
+ function errorFromResponse(args) {
152
+ const p = args.body && typeof args.body === "object" ? args.body : {};
153
+ const str = (v) => typeof v === "string" && v ? v : void 0;
154
+ const typeUri = str(p.type);
155
+ const code = str(p.title) ?? (typeUri ? typeUri.split("/").pop() : void 0) ?? codeForStatus(args.status);
156
+ const init = {
157
+ status: args.status,
158
+ code,
159
+ detail: str(p.detail) ?? (args.text ? args.text.slice(0, 500) : `HTTP ${args.status}`),
160
+ requestId: str(p.requestId) ?? args.requestId,
161
+ traceId: str(p.traceId) ?? args.traceId,
162
+ details: p.details && typeof p.details === "object" ? p.details : null,
163
+ type: typeUri ?? null,
164
+ retryAfterMs: args.retryAfterMs
165
+ };
166
+ if (code === "rate_limited" || code === "quota_exceeded") return new RateLimitError(init);
167
+ const Cls = CODE_CLASSES[code] ?? (args.status >= 500 ? InternalError : ApiError);
168
+ return new Cls(init);
169
+ }
170
+
171
+ // src/auth.ts
172
+ var StaticTokenProvider = class {
173
+ constructor(token) {
174
+ this.token = token;
175
+ if (!token) throw new ConfigurationError("Token must be a non-empty string");
176
+ }
177
+ token;
178
+ refreshable = false;
179
+ async getToken() {
180
+ return this.token;
181
+ }
182
+ invalidate() {
183
+ }
184
+ };
185
+ var UnauthenticatedProvider = class {
186
+ refreshable = false;
187
+ async getToken() {
188
+ throw new ConfigurationError("This client is unauthenticated: only login() and refreshSession() are available. Create a client with credentials (e.g. staticToken(loginResult.accessToken)).");
189
+ }
190
+ invalidate() {
191
+ }
192
+ };
193
+ function unauthenticated() {
194
+ return new UnauthenticatedProvider();
195
+ }
196
+ function apiKey(key) {
197
+ return new StaticTokenProvider(key);
198
+ }
199
+ function staticToken(token) {
200
+ return new StaticTokenProvider(token);
201
+ }
202
+ var OAuthTokenProvider = class {
203
+ refreshable = true;
204
+ cached = null;
205
+ inflight = null;
206
+ generation = 0;
207
+ /** Whether the grant may be retried on 5xx/network errors. */
208
+ idempotentGrant = true;
209
+ async getToken(ctx, signal) {
210
+ const now = ctx.clock.now();
211
+ if (this.cached && now < this.cached.refreshAt) return this.cached.accessToken;
212
+ if (!this.inflight) {
213
+ const gen = this.generation;
214
+ const p = this.fetchToken(ctx).then((t) => {
215
+ if (gen === this.generation) this.cached = t;
216
+ return t;
217
+ }).finally(() => {
218
+ if (this.inflight === p) this.inflight = null;
219
+ });
220
+ this.inflight = p;
221
+ }
222
+ const token = await raceAbort(this.inflight, signal);
223
+ return token.accessToken;
224
+ }
225
+ invalidate() {
226
+ this.generation++;
227
+ this.cached = null;
228
+ this.inflight = null;
229
+ }
230
+ async fetchToken(ctx) {
231
+ const started = ctx.clock.now();
232
+ const r = await ctx.requestToken(() => this.grant(ctx), { idempotent: this.idempotentGrant });
233
+ const ttlMs = Math.max(0, Number(r.expires_in ?? 0) * 1e3);
234
+ const skew = Math.min(6e4, ttlMs / 2);
235
+ return { accessToken: r.access_token, refreshAt: started + ttlMs - skew, scope: r.scope };
236
+ }
237
+ };
238
+ function raceAbort(p, signal) {
239
+ if (!signal) return p;
240
+ if (signal.aborted) return Promise.reject(abortReason(signal));
241
+ return new Promise((resolve, reject) => {
242
+ const onAbort = () => reject(abortReason(signal));
243
+ signal.addEventListener("abort", onAbort, { once: true });
244
+ p.then(
245
+ (v) => {
246
+ signal.removeEventListener("abort", onAbort);
247
+ resolve(v);
248
+ },
249
+ (e) => {
250
+ signal.removeEventListener("abort", onAbort);
251
+ reject(e);
252
+ }
253
+ );
254
+ });
255
+ }
256
+ var ClientSecretProvider = class extends OAuthTokenProvider {
257
+ constructor(o) {
258
+ super();
259
+ this.o = o;
260
+ if (!o.clientSecret) throw new ConfigurationError("clientSecret is required");
261
+ }
262
+ o;
263
+ async grant() {
264
+ return {
265
+ grant_type: "client_credentials",
266
+ client_secret: this.o.clientSecret,
267
+ ...this.o.clientId ? { client_id: this.o.clientId } : {},
268
+ ...this.o.scope ? { scope: this.o.scope } : {}
269
+ };
270
+ }
271
+ };
272
+ function clientSecret(options) {
273
+ return new ClientSecretProvider(options);
274
+ }
275
+ var OID_ED25519 = [6, 3, 43, 101, 112];
276
+ var OID_EC_PUBLIC_KEY = [6, 7, 42, 134, 72, 206, 61, 2, 1];
277
+ var OID_P256 = [6, 8, 42, 134, 72, 206, 61, 3, 1, 7];
278
+ var OID_RSA = [6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 1];
279
+ function contains(hay, needle) {
280
+ outer: for (let i = 0; i + needle.length <= hay.length; i++) {
281
+ for (let j = 0; j < needle.length; j++) if (hay[i + j] !== needle[j]) continue outer;
282
+ return true;
283
+ }
284
+ return false;
285
+ }
286
+ function pemToDer(pem) {
287
+ if (/BEGIN (EC |RSA |ENCRYPTED )PRIVATE KEY/.test(pem)) throw new ConfigurationError('Private key must be an unencrypted PKCS#8 PEM ("BEGIN PRIVATE KEY"); convert with `openssl pkcs8 -topk8 -nocrypt`');
288
+ const m = /-----BEGIN PRIVATE KEY-----([\s\S]+?)-----END PRIVATE KEY-----/.exec(pem);
289
+ if (!m) throw new ConfigurationError('Private key must be a PKCS#8 PEM ("BEGIN PRIVATE KEY") or a private JWK');
290
+ return base64Decode(m[1].replace(/\s+/g, ""));
291
+ }
292
+ function base64Decode(b64) {
293
+ const bin = atob(b64);
294
+ const out = new Uint8Array(bin.length);
295
+ for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i);
296
+ return out;
297
+ }
298
+ function base64url(data) {
299
+ const bytes = typeof data === "string" ? new TextEncoder().encode(data) : data;
300
+ let bin = "";
301
+ for (const b of bytes) bin += String.fromCharCode(b);
302
+ return btoa(bin).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
303
+ }
304
+ var ALGS = {
305
+ EdDSA: { importParams: { name: "Ed25519" }, signParams: { name: "Ed25519" } },
306
+ ES256: { importParams: { name: "ECDSA", namedCurve: "P-256" }, signParams: { name: "ECDSA", hash: "SHA-256" } },
307
+ RS256: { importParams: { name: "RSASSA-PKCS1-v1_5", hash: "SHA-256" }, signParams: { name: "RSASSA-PKCS1-v1_5" } }
308
+ };
309
+ function inferAlgorithm(key) {
310
+ if (typeof key === "string") {
311
+ const der = pemToDer(key);
312
+ if (contains(der, OID_ED25519)) return "EdDSA";
313
+ if (contains(der, OID_EC_PUBLIC_KEY)) {
314
+ if (!contains(der, OID_P256)) throw new ConfigurationError("Only the P-256 curve is supported for EC keys");
315
+ return "ES256";
316
+ }
317
+ if (contains(der, OID_RSA)) return "RS256";
318
+ throw new ConfigurationError("Unsupported private key type (use Ed25519, P-256 or RSA)");
319
+ }
320
+ if (key.kty === "OKP" && key.crv === "Ed25519") return "EdDSA";
321
+ if (key.kty === "EC" && key.crv === "P-256") return "ES256";
322
+ if (key.kty === "RSA") return "RS256";
323
+ throw new ConfigurationError("Unsupported JWK (use OKP/Ed25519, EC/P-256 or RSA)");
324
+ }
325
+ async function importSigningKey(key, alg) {
326
+ const subtle = globalThis.crypto?.subtle;
327
+ if (!subtle) throw new ConfigurationError("WebCrypto (globalThis.crypto.subtle) is required for private_key_jwt");
328
+ if (typeof key === "string") return subtle.importKey("pkcs8", pemToDer(key), ALGS[alg].importParams, false, ["sign"]);
329
+ if (!key.d) throw new ConfigurationError('JWK must contain the private key ("d")');
330
+ const { kty, crv, x, y, d, n, e, p, q, dp, dq, qi } = key;
331
+ const jwk = Object.fromEntries(Object.entries({ kty, crv, x, y, d, n, e, p, q, dp, dq, qi }).filter(([, v]) => v !== void 0));
332
+ return subtle.importKey("jwk", jwk, ALGS[alg].importParams, false, ["sign"]);
333
+ }
334
+ async function createClientAssertion(args) {
335
+ const lifetime = args.lifetimeSeconds ?? 60;
336
+ if (!(lifetime > 0 && lifetime <= 300)) throw new ConfigurationError("Assertion lifetime must be between 1 and 300 seconds");
337
+ const iat = Math.floor(args.nowMs / 1e3);
338
+ const header = { alg: args.algorithm, typ: "JWT", kid: args.credentialId };
339
+ const claims = { iss: args.credentialId, sub: args.credentialId, aud: args.audience, iat, exp: iat + lifetime, jti: globalThis.crypto.randomUUID() };
340
+ const signingInput = `${base64url(JSON.stringify(header))}.${base64url(JSON.stringify(claims))}`;
341
+ const sig = await args.sign(new TextEncoder().encode(signingInput));
342
+ return `${signingInput}.${base64url(sig)}`;
343
+ }
344
+ var PrivateKeyJwtProvider = class extends OAuthTokenProvider {
345
+ constructor(o) {
346
+ super();
347
+ this.o = o;
348
+ if (!o.credentialId) throw new ConfigurationError("credentialId is required");
349
+ const lifetime = o.lifetimeSeconds ?? 60;
350
+ if (!(lifetime > 0 && lifetime <= 300)) throw new ConfigurationError("lifetimeSeconds must be between 1 and 300 (server maximum is 5 minutes)");
351
+ if (o.signer) {
352
+ if (!o.algorithm) throw new ConfigurationError("algorithm is required with a custom signer");
353
+ this.alg = o.algorithm;
354
+ this.signer = o.signer;
355
+ return;
356
+ }
357
+ const key = o.privateKey;
358
+ if (!key) throw new ConfigurationError("privateKey or signer is required");
359
+ if (typeof key === "string" || !("type" in key && "algorithm" in key)) this.alg = o.algorithm ?? inferAlgorithm(key);
360
+ else {
361
+ const name = key.algorithm.name;
362
+ this.alg = o.algorithm ?? (name === "Ed25519" ? "EdDSA" : name === "ECDSA" ? "ES256" : "RS256");
363
+ }
364
+ let imported = null;
365
+ this.signer = async (data) => {
366
+ const k = typeof key === "string" || !("algorithm" in key) ? await (imported ??= importSigningKey(key, this.alg)) : key;
367
+ return new Uint8Array(await globalThis.crypto.subtle.sign(ALGS[this.alg].signParams, k, data));
368
+ };
369
+ }
370
+ o;
371
+ alg;
372
+ signer;
373
+ async grant(ctx) {
374
+ const assertion = await createClientAssertion({
375
+ credentialId: this.o.credentialId,
376
+ audience: this.o.audience ?? ctx.tokenUrl,
377
+ algorithm: this.alg,
378
+ sign: this.signer,
379
+ nowMs: ctx.clock.now(),
380
+ ...this.o.lifetimeSeconds ? { lifetimeSeconds: this.o.lifetimeSeconds } : {}
381
+ });
382
+ return {
383
+ grant_type: "client_credentials",
384
+ client_assertion_type: "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
385
+ client_assertion: assertion,
386
+ ...this.o.scope ? { scope: this.o.scope } : {}
387
+ };
388
+ }
389
+ };
390
+ function privateKeyJwt(options) {
391
+ return new PrivateKeyJwtProvider(options);
392
+ }
393
+ var DelegationProvider = class extends OAuthTokenProvider {
394
+ constructor(o) {
395
+ super();
396
+ this.o = o;
397
+ if (!o.subjectToken) throw new ConfigurationError("subjectToken is required");
398
+ }
399
+ o;
400
+ async grant(ctx, signal) {
401
+ return {
402
+ grant_type: "urn:ietf:params:oauth:grant-type:token-exchange",
403
+ subject_token: this.o.subjectToken,
404
+ actor_token: await this.o.actor.getToken(ctx, signal),
405
+ ...this.o.scope ? { scope: this.o.scope } : {}
406
+ };
407
+ }
408
+ };
409
+ function delegation(options) {
410
+ return new DelegationProvider(options);
411
+ }
412
+
413
+ // src/version.ts
414
+ var VERSION = "0.2.1";
415
+
416
+ // src/http.ts
417
+ var hex = (bytes) => {
418
+ const b = new Uint8Array(bytes);
419
+ globalThis.crypto.getRandomValues(b);
420
+ return Array.from(b, (x) => x.toString(16).padStart(2, "0")).join("");
421
+ };
422
+ var TRACEPARENT = /^[0-9a-f]{2}-([0-9a-f]{32})-[0-9a-f]{16}-[0-9a-f]{2}$/;
423
+ function parseRetryAfter(value, now) {
424
+ if (!value) return null;
425
+ const v = value.trim();
426
+ if (/^\d+(\.\d+)?$/.test(v)) return Math.round(Number(v) * 1e3);
427
+ const at = Date.parse(v);
428
+ return Number.isNaN(at) ? null : Math.max(0, at - now);
429
+ }
430
+ function backoffDelay(attempt, o, random) {
431
+ const d = Math.min(o.maxDelayMs, o.baseDelayMs * 2 ** attempt);
432
+ return d / 2 + random() * (d / 2);
433
+ }
434
+ function joinUrl(base, path, query) {
435
+ let url = base.replace(/\/+$/, "") + path;
436
+ if (query) {
437
+ const qs = new URLSearchParams();
438
+ for (const [k, v] of Object.entries(query)) if (v !== void 0 && v !== null) qs.set(k, String(v));
439
+ const s = qs.toString();
440
+ if (s) url += `?${s}`;
441
+ }
442
+ return url;
443
+ }
444
+ var HttpCore = class {
445
+ constructor(o) {
446
+ this.o = o;
447
+ this.authContext = {
448
+ tokenUrl: o.tokenUrl,
449
+ clock: o.clock,
450
+ requestToken: async (buildBody, opts) => (await this.request({
451
+ method: "POST",
452
+ base: "api",
453
+ path: "",
454
+ url: o.tokenUrl,
455
+ idempotent: opts.idempotent,
456
+ buildBody,
457
+ ...opts.signal ? { signal: opts.signal } : {}
458
+ })).body
459
+ };
460
+ }
461
+ o;
462
+ authContext;
463
+ async request(spec) {
464
+ const url = spec.url ?? joinUrl(spec.base === "gateway" ? this.o.gatewayUrl : this.o.apiUrl, spec.path, spec.query);
465
+ const maxRetries = spec.maxRetries ?? this.o.maxRetries;
466
+ const incoming = spec.traceparent ? TRACEPARENT.exec(spec.traceparent) : null;
467
+ const traceId = incoming?.[1] ?? hex(16);
468
+ const idempotent = !spec.neverRetry && (spec.idempotent || !!spec.idempotencyKey);
469
+ let attempt = 0;
470
+ let replayed401 = false;
471
+ for (; ; ) {
472
+ if (spec.signal?.aborted) throw abortReason(spec.signal);
473
+ const headers = { accept: "application/json", ...this.o.headers, ...spec.headers, traceparent: `00-${traceId}-${hex(8)}-01` };
474
+ if (spec.idempotencyKey) headers["idempotency-key"] = spec.idempotencyKey;
475
+ if (this.o.userAgent) headers["user-agent"] = this.o.userAgent;
476
+ if (spec.auth) headers.authorization = `Bearer ${await spec.auth.getToken(this.authContext, spec.signal)}`;
477
+ const payload = spec.buildBody ? await spec.buildBody() : spec.body;
478
+ if (payload !== void 0) headers["content-type"] = "application/json";
479
+ let res;
480
+ try {
481
+ res = await this.fetchAttempt(url, spec.method, headers, payload === void 0 ? void 0 : JSON.stringify(payload), spec.timeoutMs ?? this.o.timeoutMs, spec.signal);
482
+ } catch (err) {
483
+ if (spec.signal?.aborted) throw abortReason(spec.signal);
484
+ if (idempotent && attempt < maxRetries) {
485
+ await this.o.clock.sleep(backoffDelay(attempt++, this.o, this.o.random), spec.signal);
486
+ continue;
487
+ }
488
+ throw err;
489
+ }
490
+ const text = await res.text().catch(() => "");
491
+ let body = void 0;
492
+ if (text && /json/i.test(res.headers.get("content-type") ?? "")) {
493
+ try {
494
+ body = JSON.parse(text);
495
+ } catch {
496
+ body = void 0;
497
+ }
498
+ }
499
+ if (res.ok && spec.responseType === "text") return { status: res.status, body: text, headers: res.headers };
500
+ if (res.ok || body !== void 0 && spec.terminalBody?.(res.status, body)) return { status: res.status, body, headers: res.headers };
501
+ if (res.status === 401 && spec.auth?.refreshable && !replayed401) {
502
+ spec.auth.invalidate();
503
+ replayed401 = true;
504
+ continue;
505
+ }
506
+ const retryAfterMs = parseRetryAfter(res.headers.get("retry-after"), this.o.clock.now());
507
+ const respTrace = TRACEPARENT.exec(res.headers.get("traceparent") ?? "");
508
+ const special = body !== void 0 ? spec.bodyError?.(res.status, body, { requestId: res.headers.get("x-request-id"), traceId: respTrace?.[1] ?? null }) : void 0;
509
+ if (special) throw special;
510
+ const error = errorFromResponse({ status: res.status, body, text, requestId: res.headers.get("x-request-id"), traceId: respTrace?.[1] ?? null, retryAfterMs });
511
+ const retryable = res.status === 429 || idempotent && (res.status === 502 || res.status === 503 || res.status === 504);
512
+ if (!retryable || attempt >= maxRetries) throw error;
513
+ if (retryAfterMs !== null && retryAfterMs > this.o.maxRetryAfterMs) throw error;
514
+ await this.o.clock.sleep(retryAfterMs ?? backoffDelay(attempt, this.o, this.o.random), spec.signal);
515
+ attempt++;
516
+ }
517
+ }
518
+ async fetchAttempt(url, method, headers, body, timeoutMs, signal) {
519
+ const ctrl = new AbortController();
520
+ let timedOut = false;
521
+ const timer = setTimeout(() => {
522
+ timedOut = true;
523
+ ctrl.abort();
524
+ }, timeoutMs);
525
+ const onAbort = () => ctrl.abort(signal.reason);
526
+ signal?.addEventListener("abort", onAbort, { once: true });
527
+ try {
528
+ const res = await this.o.fetch(url, { method, headers, ...body !== void 0 ? { body } : {}, signal: ctrl.signal });
529
+ return res;
530
+ } catch (err) {
531
+ if (signal?.aborted) throw abortReason(signal);
532
+ if (timedOut) throw new TimeoutError({ status: 0, code: "timeout", detail: `No response within ${timeoutMs} ms`, cause: err });
533
+ if (err instanceof GebSecureError) throw err;
534
+ throw new ConnectionError(err instanceof Error ? err.message : String(err), err);
535
+ } finally {
536
+ clearTimeout(timer);
537
+ signal?.removeEventListener("abort", onAbort);
538
+ }
539
+ }
540
+ };
541
+ var DEFAULT_USER_AGENT = `gebsecure-typescript/${VERSION}`;
542
+
543
+ // src/client.ts
544
+ var env = (name) => {
545
+ const p = globalThis.process;
546
+ return p?.env?.[name] || void 0;
547
+ };
548
+ var isNode = () => typeof globalThis.process?.versions?.node === "string";
549
+ var seg = (id) => {
550
+ if (!id) throw new ConfigurationError("id must be a non-empty string");
551
+ return encodeURIComponent(id);
552
+ };
553
+ var ACTIVE_EXECUTION = /* @__PURE__ */ new Set(["awaiting_approval", "pending", "running", "cancelling"]);
554
+ var GRANTED_APPROVAL = /* @__PURE__ */ new Set(["approved", "consumed"]);
555
+ var isExecuteResult = (_status, body) => !!body && typeof body === "object" && typeof body.status === "string" && "decision" in body;
556
+ var newIdempotencyKey = () => `sdk-${globalThis.crypto.randomUUID()}`;
557
+ var isObject = (v) => !!v && typeof v === "object" && !Array.isArray(v);
558
+ var isDeployReport = (status, body) => status === 412 && isObject(body) && typeof body.deployed === "boolean";
559
+ var simulationFailure = (status, body, meta) => status === 422 && isObject(body) && typeof body.status === "string" && isObject(body.summary) && Array.isArray(body.results) ? new SimulationFailedError(body, meta) : void 0;
560
+ var GebSecure = class _GebSecure {
561
+ gatewayUrl;
562
+ apiUrl;
563
+ core;
564
+ auth;
565
+ clock;
566
+ maxRetries;
567
+ options;
568
+ constructor(options = {}) {
569
+ this.options = options;
570
+ this.gatewayUrl = (options.gatewayUrl ?? env("GEBSECURE_GATEWAY_URL") ?? "https://gateway.gebsecure.dev").replace(/\/+$/, "");
571
+ this.apiUrl = (options.apiUrl ?? env("GEBSECURE_API_URL") ?? "https://api.gebsecure.dev").replace(/\/+$/, "");
572
+ const key = options.apiKey ?? (options.auth ? void 0 : env("GEBSECURE_API_KEY"));
573
+ const secret = options.auth || key ? void 0 : env("GEBSECURE_CLIENT_SECRET");
574
+ const auth = options.auth ?? (key ? apiKey(key) : secret ? clientSecret({ clientSecret: secret }) : void 0);
575
+ if (!auth) throw new ConfigurationError("No credentials: pass `auth` or `apiKey`, or set GEBSECURE_API_KEY / GEBSECURE_CLIENT_SECRET");
576
+ this.auth = auth;
577
+ this.clock = options.clock ?? systemClock;
578
+ this.maxRetries = options.maxRetries ?? 3;
579
+ const fetchImpl = options.fetch ?? globalThis.fetch?.bind(globalThis);
580
+ if (!fetchImpl) throw new ConfigurationError("No fetch implementation available; pass `fetch`");
581
+ this.core = new HttpCore({
582
+ gatewayUrl: this.gatewayUrl,
583
+ apiUrl: this.apiUrl,
584
+ tokenUrl: options.tokenUrl ?? `${this.apiUrl}/v1/auth/token`,
585
+ timeoutMs: options.timeoutMs ?? 3e4,
586
+ maxRetries: this.maxRetries,
587
+ baseDelayMs: options.baseDelayMs ?? 500,
588
+ maxDelayMs: options.maxDelayMs ?? 8e3,
589
+ maxRetryAfterMs: options.maxRetryAfterMs ?? 6e4,
590
+ fetch: fetchImpl,
591
+ clock: this.clock,
592
+ // eslint-disable-next-line no-restricted-properties -- retry jitter only; never security-relevant
593
+ random: options.random ?? Math.random,
594
+ userAgent: options.userAgent ?? (isNode() ? DEFAULT_USER_AGENT : ""),
595
+ headers: options.headers ?? {}
596
+ });
597
+ }
598
+ /** A client with the same configuration acting under a delegation token (RFC 8693 exchange). */
599
+ withDelegation(subjectToken, opts = {}) {
600
+ return new _GebSecure({ ...this.options, gatewayUrl: this.gatewayUrl, apiUrl: this.apiUrl, auth: delegation({ subjectToken, actor: this.auth, ...opts }) });
601
+ }
602
+ /** Returns a valid access token (cached/refreshed), e.g. to call GebSecure APIs not wrapped by the SDK. */
603
+ getAccessToken(opts = {}) {
604
+ return this.auth.getToken(this.core.authContext, opts.signal);
605
+ }
606
+ async call(spec, opts = {}) {
607
+ return (await this.core.request({ ...opts, ...spec, auth: this.auth })).body;
608
+ }
609
+ /** Calls an operation that returns no body (204); resolves to `undefined`. */
610
+ async callVoid(spec, opts = {}) {
611
+ await this.core.request({ ...opts, ...spec, auth: this.auth });
612
+ }
613
+ /** Unauthenticated session endpoints (login/refresh): no Authorization header. */
614
+ async callAnonymous(spec, opts = {}) {
615
+ return (await this.core.request({ ...opts, ...spec })).body;
616
+ }
617
+ // ─── Decisions ──────────────────────────────────────────────────────────────
618
+ /** Decides whether the principal may perform an action. DENY / APPROVAL_REQUIRED are results, not errors. */
619
+ authorize(request, opts) {
620
+ return this.call({ method: "POST", base: "gateway", path: "/v1/authorize", body: request, idempotent: request.dryRun === true }, opts);
621
+ }
622
+ /** Evaluates up to 100 requests in one call. */
623
+ authorizeBatch(request, opts) {
624
+ const idempotent = request.requests.length > 0 && request.requests.every((r) => r.dryRun === true);
625
+ return this.call({ method: "POST", base: "gateway", path: "/v1/authorize/batch", body: request, idempotent }, opts);
626
+ }
627
+ /** Convenience around `authorize`: `allowed` is true only for ALLOW. Never throws on DENY. */
628
+ async guard(action, resource, context, opts) {
629
+ const { signal, traceparent, timeoutMs, maxRetries, headers, ...rest } = opts ?? {};
630
+ const decision = await this.authorize({ ...rest, action, resource, ...context ? { context } : {} }, { signal, traceparent, timeoutMs, maxRetries, headers });
631
+ return { allowed: decision.decision === "ALLOW", decision };
632
+ }
633
+ // ─── Execution ──────────────────────────────────────────────────────────────
634
+ /**
635
+ * Authorizes and executes a connector action. Returns an `ExecuteResult` for succeeded, simulated,
636
+ * awaiting_approval, running, denied (HTTP 403) and failed (HTTP 502/504) outcomes; problem+json errors throw.
637
+ * With retries enabled, an idempotency key is generated when none is given.
638
+ */
639
+ execute(request, opts = {}) {
640
+ const retries = opts.maxRetries ?? this.maxRetries;
641
+ const body = !request.idempotencyKey && retries > 0 && !request.dryRun ? { ...request, idempotencyKey: newIdempotencyKey() } : request;
642
+ return this.call({ method: "POST", base: "gateway", path: "/v1/execute", body, idempotent: !!body.idempotencyKey || body.dryRun === true, terminalBody: isExecuteResult }, opts);
643
+ }
644
+ /** Execution status, result and step logs. */
645
+ getExecution(id, opts) {
646
+ return this.call({ method: "GET", base: "gateway", path: `/v1/executions/${seg(id)}`, idempotent: true }, opts);
647
+ }
648
+ /** Lists executions visible to the caller. */
649
+ listExecutions(params = {}, opts) {
650
+ return this.call({ method: "GET", base: "gateway", path: "/v1/executions", query: { ...params }, idempotent: true }, opts);
651
+ }
652
+ /** Cancels a pending, awaiting-approval or running execution. */
653
+ cancelExecution(id, opts) {
654
+ return this.call({ method: "POST", base: "gateway", path: `/v1/executions/${seg(id)}/cancel`, idempotent: true }, opts);
655
+ }
656
+ // ─── Approvals ──────────────────────────────────────────────────────────────
657
+ /** Status of an approval request (agent-facing, via the gateway). */
658
+ getApproval(id, opts) {
659
+ return this.call({ method: "GET", base: "gateway", path: `/v1/approvals/${seg(id)}`, idempotent: true }, opts);
660
+ }
661
+ /** Polls an approval until it leaves `pending`; returns it in its terminal state. */
662
+ async waitForApproval(id, opts = {}) {
663
+ const { timeoutMs = 6e5, pollIntervalMs = 2e3, ...req } = opts;
664
+ const deadline = this.clock.now() + timeoutMs;
665
+ for (; ; ) {
666
+ const a = await this.getApproval(id, req);
667
+ if (a.status !== "pending") return a;
668
+ const remaining = deadline - this.clock.now();
669
+ if (remaining <= 0) throw new ApprovalTimeoutError(id, timeoutMs);
670
+ await this.clock.sleep(Math.min(pollIntervalMs, remaining), req.signal);
671
+ }
672
+ }
673
+ /**
674
+ * Executes; if human approval is required, waits for it and then follows the execution until it is
675
+ * terminal. Once the approval is granted the platform resumes the stored execution itself (and consumes
676
+ * the single-use approval), so this helper never re-executes (conformance §5).
677
+ * Throws `ApprovalNotGrantedError` when the approval is rejected/expired/cancelled,
678
+ * `ApprovalTimeoutError` when it stays pending past `timeoutMs`, and `TimeoutError` when the approved
679
+ * execution has not finished by then. A resumed execution that fails is returned with `status: 'failed'`.
680
+ */
681
+ async executeWithApproval(request, opts = {}) {
682
+ const { timeoutMs = 6e5, pollIntervalMs = 2e3, ...req } = opts;
683
+ const deadline = this.clock.now() + timeoutMs;
684
+ const base = request.idempotencyKey || request.dryRun ? request : { ...request, idempotencyKey: newIdempotencyKey() };
685
+ const first = await this.execute(base, req);
686
+ if (first.status !== "awaiting_approval" || !first.approval || !first.executionId) return first;
687
+ const approval = await this.waitForApproval(first.approval.id, { ...req, timeoutMs: Math.max(0, deadline - this.clock.now()), pollIntervalMs });
688
+ if (!GRANTED_APPROVAL.has(approval.status)) throw new ApprovalNotGrantedError(approval);
689
+ for (; ; ) {
690
+ const e = await this.getExecution(first.executionId, req);
691
+ if (!ACTIVE_EXECUTION.has(e.status)) {
692
+ return {
693
+ executionId: e.id,
694
+ status: e.status,
695
+ decision: e.decision ?? first.decision,
696
+ reason: e.error?.message ?? first.reason ?? "",
697
+ output: e.output,
698
+ outputTruncated: e.outputTruncated ?? false,
699
+ error: e.error ?? null,
700
+ approval: first.approval,
701
+ risk: first.risk,
702
+ durationMs: e.durationMs ?? 0,
703
+ replayed: true
704
+ };
705
+ }
706
+ const remaining = deadline - this.clock.now();
707
+ if (remaining <= 0) throw new TimeoutError({ status: 0, code: "timeout", detail: `Execution ${first.executionId} still ${e.status} after ${timeoutMs} ms` });
708
+ await this.clock.sleep(Math.min(pollIntervalMs, remaining), req.signal);
709
+ }
710
+ }
711
+ // ─── Control plane ──────────────────────────────────────────────────────────
712
+ /** Agent directory. */
713
+ listAgents(params = {}, opts) {
714
+ return this.call({ method: "GET", base: "api", path: "/v1/agents", query: { ...params }, idempotent: true }, opts);
715
+ }
716
+ /** One agent, including credential metadata. */
717
+ getAgent(id, opts) {
718
+ return this.call({ method: "GET", base: "api", path: `/v1/agents/${seg(id)}`, idempotent: true }, opts);
719
+ }
720
+ /** Policies. */
721
+ listPolicies(params = {}, opts) {
722
+ return this.call({ method: "GET", base: "api", path: "/v1/policies", query: { ...params }, idempotent: true }, opts);
723
+ }
724
+ /** Approval requests (`inbox: true` = those the caller can act on). */
725
+ listApprovals(params = {}, opts) {
726
+ return this.call({ method: "GET", base: "api", path: "/v1/approvals", query: { ...params }, idempotent: true }, opts);
727
+ }
728
+ /** Delegates a subset of authority to another agent. The returned `token` (gsd_…) is shown once. */
729
+ createDelegation(request, opts) {
730
+ return this.call({ method: "POST", base: "api", path: "/v1/delegations", body: request, idempotent: false }, opts);
731
+ }
732
+ // ─── Runtime: inspection, DLP, agent spans, simulation ──────────────────────
733
+ /**
734
+ * Inspects untrusted content (web page, email, RAG chunk, tool output) before the agent reads it:
735
+ * prompt-injection score/level/action, a sanitized form, and inbound DLP. Hand `result.content`
736
+ * (null when blocked) to the model instead of the original.
737
+ */
738
+ inspect(request, opts) {
739
+ return this.call({ method: "POST", base: "gateway", path: "/v1/inspect", body: request, idempotent: false }, opts);
740
+ }
741
+ /** Scans a payload for sensitive data and applies DLP rules. Retried like a read only when `dryRun` is true. */
742
+ dlpScan(request, opts) {
743
+ return this.call({ method: "POST", base: "gateway", path: "/v1/dlp/scan", body: request, idempotent: request.dryRun === true }, opts);
744
+ }
745
+ /** Reports agent-side spans (see `buildSpan`) into the shared trace. Safe to retry: duplicates are ignored. */
746
+ reportSpans(spans, opts) {
747
+ const body = Array.isArray(spans) ? { spans } : spans;
748
+ return this.call({ method: "POST", base: "gateway", path: "/v1/traces/spans", body, idempotent: true }, opts);
749
+ }
750
+ /**
751
+ * Runs simulation scenarios (nothing is executed). With `failOnMismatch: true`, a failed or errored run
752
+ * throws `SimulationFailedError` whose `run` is the full typed result.
753
+ */
754
+ runSimulation(request, opts) {
755
+ return this.call({ method: "POST", base: "api", path: "/v1/simulations/run", body: request, idempotent: request.persist === false, bodyError: simulationFailure }, opts);
756
+ }
757
+ // ─── Session auth (users) ───────────────────────────────────────────────────
758
+ /** Logs a user in (works on an `unauthenticated()` client). The refresh token is returned in the body. */
759
+ login(request, opts) {
760
+ return this.callAnonymous({ method: "POST", base: "api", path: "/v1/auth/login", body: { ...request, refreshTokenDelivery: "body" }, idempotent: false }, opts);
761
+ }
762
+ /** Exchanges a refresh token for new tokens. The refresh token rotates: persist the returned one. Never retried (except 429). */
763
+ refreshSession(refreshToken, opts) {
764
+ return this.callAnonymous({ method: "POST", base: "api", path: "/v1/auth/refresh", body: { refreshToken }, idempotent: false, neverRetry: true }, opts);
765
+ }
766
+ /** Revokes the current user session. */
767
+ logout(opts) {
768
+ return this.callVoid({ method: "POST", base: "api", path: "/v1/auth/logout", idempotent: false }, opts);
769
+ }
770
+ /** The authenticated principal, its organizations and effective permissions. */
771
+ me(opts) {
772
+ return this.call({ method: "GET", base: "api", path: "/v1/auth/me", idempotent: true }, opts);
773
+ }
774
+ // ─── Policies ───────────────────────────────────────────────────────────────
775
+ /** A policy with its versions, latest version and tests. */
776
+ getPolicy(id, opts) {
777
+ return this.call({ method: "GET", base: "api", path: `/v1/policies/${seg(id)}`, idempotent: true }, opts);
778
+ }
779
+ /** Creates a policy (draft version 1) from GSL source or a template. */
780
+ createPolicy(request, opts) {
781
+ return this.call({ method: "POST", base: "api", path: "/v1/policies", body: request, idempotent: false }, opts);
782
+ }
783
+ /** Saves a new version. Not retried on 5xx/network errors: every call appends a version. */
784
+ updatePolicy(id, request, opts) {
785
+ return this.call({ method: "PUT", base: "api", path: `/v1/policies/${seg(id)}`, body: request, idempotent: false }, opts);
786
+ }
787
+ /** Archives a policy (stops enforcing it). */
788
+ deletePolicy(id, opts) {
789
+ return this.callVoid({ method: "DELETE", base: "api", path: `/v1/policies/${seg(id)}`, idempotent: true }, opts);
790
+ }
791
+ /** Validates, lints and formats GSL source. */
792
+ validatePolicy(source, opts) {
793
+ return this.call({ method: "POST", base: "api", path: "/v1/policies/validate", body: { source }, idempotent: true }, opts);
794
+ }
795
+ /** One immutable policy version. */
796
+ getPolicyVersion(id, versionId, opts) {
797
+ return this.call({ method: "GET", base: "api", path: `/v1/policies/${seg(id)}/versions/${seg(versionId)}`, idempotent: true }, opts);
798
+ }
799
+ /** Semantic and unified diff between two versions. */
800
+ diffPolicyVersions(id, from, to, opts) {
801
+ return this.call({ method: "GET", base: "api", path: `/v1/policies/${seg(id)}/diff`, query: { from, to }, idempotent: true }, opts);
802
+ }
803
+ /** Deploy and rollback history. */
804
+ listPolicyDeployments(id, opts) {
805
+ return this.call({ method: "GET", base: "api", path: `/v1/policies/${seg(id)}/deployments`, idempotent: true }, opts);
806
+ }
807
+ /**
808
+ * Deploys a version (default: latest). When tests fail or blocking conflicts exist the server answers
809
+ * 412 with the deploy report; it is returned as a result with `deployed: false`.
810
+ */
811
+ deployPolicy(id, request = {}, opts) {
812
+ return this.call({ method: "POST", base: "api", path: `/v1/policies/${seg(id)}/deploy`, body: request, idempotent: false, terminalBody: isDeployReport }, opts);
813
+ }
814
+ /** Rolls back to a version (default: the previously deployed one). */
815
+ rollbackPolicy(id, request = {}, opts) {
816
+ return this.call({ method: "POST", base: "api", path: `/v1/policies/${seg(id)}/rollback`, body: request, idempotent: false }, opts);
817
+ }
818
+ /** Adds one test case. */
819
+ addPolicyTest(id, test, opts) {
820
+ return this.call({ method: "POST", base: "api", path: `/v1/policies/${seg(id)}/tests`, body: test, idempotent: false }, opts);
821
+ }
822
+ /** Replaces the whole test suite atomically (policy-as-code sync). */
823
+ replacePolicyTests(id, tests, opts) {
824
+ return this.call({ method: "PUT", base: "api", path: `/v1/policies/${seg(id)}/tests`, body: { tests }, idempotent: true }, opts);
825
+ }
826
+ /** Deletes one test case. */
827
+ deletePolicyTest(id, testId, opts) {
828
+ return this.callVoid({ method: "DELETE", base: "api", path: `/v1/policies/${seg(id)}/tests/${seg(testId)}`, idempotent: true }, opts);
829
+ }
830
+ /** Runs the policy's tests against a version (default: latest). */
831
+ runPolicyTests(id, versionId, opts) {
832
+ return this.call({ method: "POST", base: "api", path: `/v1/policies/${seg(id)}/tests/run`, body: versionId ? { versionId } : {}, idempotent: true }, opts);
833
+ }
834
+ /** Evaluates requests against deployed vs candidate policies. */
835
+ simulatePolicies(request, opts) {
836
+ return this.call({ method: "POST", base: "api", path: "/v1/policies/simulate", body: request, idempotent: true }, opts);
837
+ }
838
+ // ─── Agents & credentials ───────────────────────────────────────────────────
839
+ /** Registers an agent; with `credential`, its client secret is returned once in `credential.clientSecret`. */
840
+ createAgent(request, opts) {
841
+ return this.call({ method: "POST", base: "api", path: "/v1/agents", body: request, idempotent: false }, opts);
842
+ }
843
+ /** Updates agent metadata. */
844
+ updateAgent(id, request, opts) {
845
+ return this.call({ method: "PATCH", base: "api", path: `/v1/agents/${seg(id)}`, body: request, idempotent: false }, opts);
846
+ }
847
+ /** Activates, suspends, disables or quarantines an agent. */
848
+ setAgentStatus(id, request, opts) {
849
+ return this.call({ method: "POST", base: "api", path: `/v1/agents/${seg(id)}/status`, body: request, idempotent: false }, opts);
850
+ }
851
+ /** Deletes an agent. */
852
+ deleteAgent(id, opts) {
853
+ return this.callVoid({ method: "DELETE", base: "api", path: `/v1/agents/${seg(id)}`, idempotent: true }, opts);
854
+ }
855
+ /** Credential metadata of an agent (never secrets). */
856
+ listAgentCredentials(id, opts) {
857
+ return this.call({ method: "GET", base: "api", path: `/v1/agents/${seg(id)}/credentials`, idempotent: true }, opts);
858
+ }
859
+ /** Issues an agent credential; the client secret is returned once. */
860
+ createAgentCredential(id, request = {}, opts) {
861
+ return this.call({ method: "POST", base: "api", path: `/v1/agents/${seg(id)}/credentials`, body: request, idempotent: false }, opts);
862
+ }
863
+ /** Rotates a credential; the previous one keeps working until `previous.graceUntil`. */
864
+ rotateCredential(credentialId, request = {}, opts) {
865
+ return this.call({ method: "POST", base: "api", path: `/v1/credentials/${seg(credentialId)}/rotate`, body: request, idempotent: false }, opts);
866
+ }
867
+ /** Revokes a credential immediately (idempotent). */
868
+ revokeCredential(credentialId, reason, opts) {
869
+ return this.call({ method: "POST", base: "api", path: `/v1/credentials/${seg(credentialId)}/revoke`, body: reason !== void 0 ? { reason } : {}, idempotent: true }, opts);
870
+ }
871
+ // ─── Secrets (values are write-only) ────────────────────────────────────────
872
+ /** Stores a secret. The value is never returned by the API and never logged by the SDK. */
873
+ createSecret(request, opts) {
874
+ return this.call({ method: "POST", base: "api", path: "/v1/secrets", body: request, idempotent: false }, opts);
875
+ }
876
+ /** Secret metadata and masks. */
877
+ listSecrets(params = {}, opts) {
878
+ return this.call({ method: "GET", base: "api", path: "/v1/secrets", query: { ...params }, idempotent: true }, opts);
879
+ }
880
+ /** One secret's metadata and version history (never the value). */
881
+ getSecret(id, opts) {
882
+ return this.call({ method: "GET", base: "api", path: `/v1/secrets/${seg(id)}`, idempotent: true }, opts);
883
+ }
884
+ /** Updates secret metadata, access policy, expiry, rotation policy or status. */
885
+ updateSecret(id, request, opts) {
886
+ return this.call({ method: "PATCH", base: "api", path: `/v1/secrets/${seg(id)}`, body: request, idempotent: false }, opts);
887
+ }
888
+ /** Writes a new version (a value, or `generate`). */
889
+ rotateSecret(id, request, opts) {
890
+ return this.call({ method: "POST", base: "api", path: `/v1/secrets/${seg(id)}/rotate`, body: request, idempotent: false }, opts);
891
+ }
892
+ /** Revokes one version or the whole secret. */
893
+ revokeSecret(id, request = {}, opts) {
894
+ return this.call({ method: "POST", base: "api", path: `/v1/secrets/${seg(id)}/revoke`, body: request, idempotent: false }, opts);
895
+ }
896
+ /** Deletes a secret. */
897
+ deleteSecret(id, opts) {
898
+ return this.callVoid({ method: "DELETE", base: "api", path: `/v1/secrets/${seg(id)}`, idempotent: true }, opts);
899
+ }
900
+ // ─── Connectors & connections ───────────────────────────────────────────────
901
+ /** The connector catalog (actions, schemas, risk metadata, auth methods). */
902
+ listConnectors(opts) {
903
+ return this.call({ method: "GET", base: "api", path: "/v1/connectors", idempotent: true }, opts);
904
+ }
905
+ /** One connector of the catalog. */
906
+ getConnector(key, opts) {
907
+ return this.call({ method: "GET", base: "api", path: `/v1/connectors/${seg(key)}`, idempotent: true }, opts);
908
+ }
909
+ /** Installed connections. */
910
+ listConnections(params = {}, opts) {
911
+ return this.call({ method: "GET", base: "api", path: "/v1/connections", query: { ...params }, idempotent: true }, opts);
912
+ }
913
+ /** One connection with its connector description and effective allowed hosts. */
914
+ getConnection(id, opts) {
915
+ return this.call({ method: "GET", base: "api", path: `/v1/connections/${seg(id)}`, idempotent: true }, opts);
916
+ }
917
+ /** Installs a connector into a project. */
918
+ createConnection(request, opts) {
919
+ return this.call({ method: "POST", base: "api", path: "/v1/connections", body: request, idempotent: false }, opts);
920
+ }
921
+ /** Updates a connection. */
922
+ updateConnection(id, request, opts) {
923
+ return this.call({ method: "PATCH", base: "api", path: `/v1/connections/${seg(id)}`, body: request, idempotent: false }, opts);
924
+ }
925
+ /** Deletes a connection. */
926
+ deleteConnection(id, opts) {
927
+ return this.callVoid({ method: "DELETE", base: "api", path: `/v1/connections/${seg(id)}`, idempotent: true }, opts);
928
+ }
929
+ /** Runs the connection health check. */
930
+ checkConnectionHealth(id, opts) {
931
+ return this.call({ method: "POST", base: "api", path: `/v1/connections/${seg(id)}/health`, idempotent: true }, opts);
932
+ }
933
+ /** Begins an OAuth installation (authorization code + PKCE); redirect the user to `authorizationUrl`. */
934
+ startConnectionOAuth(id, request, opts) {
935
+ return this.call({ method: "POST", base: "api", path: `/v1/connections/${seg(id)}/oauth/start`, body: request, idempotent: false }, opts);
936
+ }
937
+ /** Completes an OAuth installation with the `state` and `code` from the redirect. */
938
+ completeConnectionOAuth(request, opts) {
939
+ return this.call({ method: "POST", base: "api", path: "/v1/connections/oauth/callback", body: request, idempotent: false }, opts);
940
+ }
941
+ /** Installs with the OAuth client-credentials grant (machine-to-machine). */
942
+ installClientCredentials(id, request, opts) {
943
+ return this.call({ method: "POST", base: "api", path: `/v1/connections/${seg(id)}/oauth/client-credentials`, body: request, idempotent: false }, opts);
944
+ }
945
+ /** Installs with the RFC 7523 JWT-bearer grant (e.g. a Google service account). */
946
+ installJwtBearer(id, request, opts) {
947
+ return this.call({ method: "POST", base: "api", path: `/v1/connections/${seg(id)}/oauth/jwt-bearer`, body: request, idempotent: false }, opts);
948
+ }
949
+ // ─── Audit ──────────────────────────────────────────────────────────────────
950
+ /** Searches audit events (newest first); with `afterSeq`, tails the events after that sequence number (oldest first). */
951
+ searchAudit(params = {}, opts) {
952
+ return this.call({ method: "GET", base: "api", path: "/v1/audit/events", query: { ...params }, idempotent: true }, opts);
953
+ }
954
+ /** One audit event. */
955
+ getAuditEvent(id, opts) {
956
+ return this.call({ method: "GET", base: "api", path: `/v1/audit/events/${seg(id)}`, idempotent: true }, opts);
957
+ }
958
+ /** Exports audit events; resolves to the raw body (ndjson by default, csv or json). */
959
+ exportAudit(params = {}, opts) {
960
+ return this.call({ method: "GET", base: "api", path: "/v1/audit/export", query: { ...params }, idempotent: true, responseType: "text" }, opts);
961
+ }
962
+ /** Verifies the integrity of the audit hash chain. */
963
+ verifyAudit(request = {}, opts) {
964
+ return this.call({ method: "POST", base: "api", path: "/v1/audit/verify", body: request, idempotent: true }, opts);
965
+ }
966
+ // ─── Approvals (reviewers) ──────────────────────────────────────────────────
967
+ /** Full approval record (control plane): steps, decisions, comments, history and `canDecide`. */
968
+ getApprovalDetails(id, opts) {
969
+ return this.call({ method: "GET", base: "api", path: `/v1/approvals/${seg(id)}`, idempotent: true }, opts);
970
+ }
971
+ /** Approves or rejects; `snapshotHash` must be the hash of the request snapshot the reviewer saw. */
972
+ decideApproval(id, request, opts) {
973
+ return this.call({ method: "POST", base: "api", path: `/v1/approvals/${seg(id)}/decision`, body: request, idempotent: false }, opts);
974
+ }
975
+ // ─── Alerts ─────────────────────────────────────────────────────────────────
976
+ /** Security alerts. */
977
+ listAlerts(params = {}, opts) {
978
+ return this.call({ method: "GET", base: "api", path: "/v1/alerts", query: { ...params }, idempotent: true }, opts);
979
+ }
980
+ /** One alert with its investigation context. */
981
+ getAlert(id, opts) {
982
+ return this.call({ method: "GET", base: "api", path: `/v1/alerts/${seg(id)}`, idempotent: true }, opts);
983
+ }
984
+ /** Acknowledges, assigns, annotates, resolves or dismisses an alert. */
985
+ updateAlert(id, request, opts) {
986
+ return this.call({ method: "PATCH", base: "api", path: `/v1/alerts/${seg(id)}`, body: request, idempotent: false }, opts);
987
+ }
988
+ // ─── Traces & session replay ────────────────────────────────────────────────
989
+ /** Searches traces. */
990
+ searchTraces(params = {}, opts) {
991
+ return this.call({ method: "GET", base: "api", path: "/v1/traces", query: { ...params }, idempotent: true }, opts);
992
+ }
993
+ /** One trace: platform and agent spans, correlated records, timeline and performance breakdown. */
994
+ getTrace(traceId, opts) {
995
+ return this.call({ method: "GET", base: "api", path: `/v1/traces/${seg(traceId)}`, idempotent: true }, opts);
996
+ }
997
+ /** Everything a principal (agent or user) did in a window, step by step. */
998
+ replaySession(principalId, params = {}, opts) {
999
+ return this.call({ method: "GET", base: "api", path: `/v1/replay/${seg(principalId)}`, query: { ...params }, idempotent: true }, opts);
1000
+ }
1001
+ };
1002
+
1003
+ // src/spans.ts
1004
+ var TRACEPARENT2 = /^[0-9a-f]{2}-([0-9a-f]{32})-([0-9a-f]{16})-[0-9a-f]{2}$/;
1005
+ var randomHex = (bytes) => {
1006
+ const b = new Uint8Array(bytes);
1007
+ globalThis.crypto.getRandomValues(b);
1008
+ return Array.from(b, (x) => x.toString(16).padStart(2, "0")).join("");
1009
+ };
1010
+ var ms = (t) => t instanceof Date ? t.getTime() : t;
1011
+ function buildSpan(name, start, end, options = {}) {
1012
+ const parent = options.traceparent ? TRACEPARENT2.exec(options.traceparent) : null;
1013
+ const startMs = ms(start);
1014
+ const span = {
1015
+ traceId: parent?.[1] ?? randomHex(16),
1016
+ spanId: options.spanId ?? randomHex(8),
1017
+ name,
1018
+ startTime: new Date(startMs).toISOString(),
1019
+ durationMs: Math.max(0, ms(end) - startMs)
1020
+ };
1021
+ const parentSpanId = options.parentSpanId ?? parent?.[2];
1022
+ if (parentSpanId) span.parentSpanId = parentSpanId;
1023
+ if (options.kind) span.kind = options.kind;
1024
+ if (options.status) span.status = options.status;
1025
+ if (options.statusMessage !== void 0) span.statusMessage = options.statusMessage;
1026
+ if (options.attributes) span.attributes = options.attributes;
1027
+ if (options.events) span.events = options.events;
1028
+ return span;
1029
+ }
1030
+ function traceparentOf(span) {
1031
+ return `00-${span.traceId}-${span.spanId}-01`;
1032
+ }
1033
+
1034
+ // src/generated/models.ts
1035
+ var AgentStatus = {
1036
+ ACTIVE: "active",
1037
+ SUSPENDED: "suspended",
1038
+ DISABLED: "disabled",
1039
+ QUARANTINED: "quarantined"
1040
+ };
1041
+ var AlertStatus = {
1042
+ OPEN: "open",
1043
+ ACKNOWLEDGED: "acknowledged",
1044
+ INVESTIGATING: "investigating",
1045
+ RESOLVED: "resolved",
1046
+ DISMISSED: "dismissed"
1047
+ };
1048
+ var ApprovalStatus = {
1049
+ PENDING: "pending",
1050
+ APPROVED: "approved",
1051
+ REJECTED: "rejected",
1052
+ EXPIRED: "expired",
1053
+ CANCELLED: "cancelled",
1054
+ CONSUMED: "consumed"
1055
+ };
1056
+ var ApprovalVerdict = {
1057
+ APPROVE: "approve",
1058
+ REJECT: "reject"
1059
+ };
1060
+ var ContentSource = {
1061
+ PROMPT: "prompt",
1062
+ WEB: "web",
1063
+ EMAIL: "email",
1064
+ DOCUMENT: "document",
1065
+ RAG: "rag",
1066
+ MCP_RESPONSE: "mcp_response",
1067
+ TOOL_OUTPUT: "tool_output"
1068
+ };
1069
+ var Decision = {
1070
+ ALLOW: "ALLOW",
1071
+ DENY: "DENY",
1072
+ APPROVAL_REQUIRED: "APPROVAL_REQUIRED"
1073
+ };
1074
+ var DelegationScope = {
1075
+ AUTHORIZE: "authorize",
1076
+ EXECUTE: "execute",
1077
+ MCP_CONNECT: "mcp:connect",
1078
+ SECRETS_USE: "secrets:use",
1079
+ BROWSER_USE: "browser:use",
1080
+ DATABASE_USE: "database:use",
1081
+ DELEGATIONS_MANAGE: "delegations:manage"
1082
+ };
1083
+ var DlpAction = {
1084
+ ALLOW: "ALLOW",
1085
+ MASK: "MASK",
1086
+ REDACT: "REDACT",
1087
+ BLOCK: "BLOCK",
1088
+ REQUIRE_APPROVAL: "REQUIRE_APPROVAL"
1089
+ };
1090
+ var DlpDirection = {
1091
+ INBOUND: "inbound",
1092
+ OUTBOUND: "outbound"
1093
+ };
1094
+ var ExecuteMode = {
1095
+ SYNC: "sync",
1096
+ ASYNC: "async"
1097
+ };
1098
+ var ExecutionStatus = {
1099
+ PENDING: "pending",
1100
+ RUNNING: "running",
1101
+ SUCCEEDED: "succeeded",
1102
+ FAILED: "failed",
1103
+ DENIED: "denied",
1104
+ AWAITING_APPROVAL: "awaiting_approval",
1105
+ CANCELLED: "cancelled",
1106
+ CANCELLING: "cancelling",
1107
+ SIMULATED: "simulated"
1108
+ };
1109
+ var InjectionLevel = {
1110
+ NONE: "none",
1111
+ LOW: "low",
1112
+ MEDIUM: "medium",
1113
+ HIGH: "high",
1114
+ CRITICAL: "critical"
1115
+ };
1116
+ var RiskLevel = {
1117
+ LOW: "low",
1118
+ MEDIUM: "medium",
1119
+ HIGH: "high",
1120
+ CRITICAL: "critical"
1121
+ };
1122
+ var RiskRecommendation = {
1123
+ ALLOW: "allow",
1124
+ APPROVAL_REQUIRED: "approval_required",
1125
+ DENY: "deny"
1126
+ };
1127
+ var RiskTier = {
1128
+ LOW: "low",
1129
+ STANDARD: "standard",
1130
+ ELEVATED: "elevated",
1131
+ CRITICAL: "critical"
1132
+ };
1133
+ var SecretType = {
1134
+ API_KEY: "api_key",
1135
+ OAUTH_TOKEN: "oauth_token",
1136
+ DATABASE: "database",
1137
+ CERTIFICATE: "certificate",
1138
+ CLOUD: "cloud",
1139
+ SSH_KEY: "ssh_key",
1140
+ GENERIC: "generic"
1141
+ };
1142
+ var SimulationStatus = {
1143
+ PASSED: "passed",
1144
+ FAILED: "failed",
1145
+ ERROR: "error"
1146
+ };
1147
+ var SpanKind = {
1148
+ SERVER: "server",
1149
+ CLIENT: "client",
1150
+ INTERNAL: "internal",
1151
+ PRODUCER: "producer",
1152
+ CONSUMER: "consumer"
1153
+ };
1154
+ var SpanStatus = {
1155
+ UNSET: "unset",
1156
+ OK: "ok",
1157
+ ERROR: "error"
1158
+ };
1159
+ export {
1160
+ AgentStatus,
1161
+ AlertStatus,
1162
+ ApiError,
1163
+ ApprovalNotGrantedError,
1164
+ ApprovalRequiredError,
1165
+ ApprovalStatus,
1166
+ ApprovalTimeoutError,
1167
+ ApprovalVerdict,
1168
+ AuthenticationError,
1169
+ ConfigurationError,
1170
+ ConflictError,
1171
+ ConnectionError,
1172
+ ContentSource,
1173
+ Decision,
1174
+ DelegationScope,
1175
+ DlpAction,
1176
+ DlpDirection,
1177
+ ExecuteMode,
1178
+ ExecutionStatus,
1179
+ GebSecure,
1180
+ GebSecureError,
1181
+ InjectionLevel,
1182
+ InternalError,
1183
+ NotFoundError,
1184
+ OAuthTokenProvider,
1185
+ PermissionDeniedError,
1186
+ PolicyDeniedError,
1187
+ RateLimitError,
1188
+ RiskLevel,
1189
+ RiskRecommendation,
1190
+ RiskTier,
1191
+ SecretType,
1192
+ SimulationFailedError,
1193
+ SimulationStatus,
1194
+ SpanKind,
1195
+ SpanStatus,
1196
+ TimeoutError,
1197
+ UnavailableError,
1198
+ UpstreamError,
1199
+ VERSION,
1200
+ ValidationError,
1201
+ apiKey,
1202
+ backoffDelay,
1203
+ buildSpan,
1204
+ clientSecret,
1205
+ codeForStatus,
1206
+ createClientAssertion,
1207
+ delegation,
1208
+ errorFromResponse,
1209
+ importSigningKey,
1210
+ inferAlgorithm,
1211
+ parseRetryAfter,
1212
+ privateKeyJwt,
1213
+ staticToken,
1214
+ systemClock,
1215
+ traceparentOf,
1216
+ unauthenticated
1217
+ };
1218
+ //# sourceMappingURL=index.js.map