@caitlyn-ai/sdk-core 0.0.2 → 0.1.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/README.md +39 -7
- package/dist-cjs/index.cjs +305 -172
- package/dist-cjs/index.cjs.map +3 -3
- package/dist-es/index.mjs +298 -167
- package/dist-es/index.mjs.map +3 -3
- package/dist-types/index.d.ts +3169 -12
- package/package.json +1 -2
- package/dist-types/auth.d.ts +0 -140
- package/dist-types/aws.d.ts +0 -43
- package/dist-types/client.d.ts +0 -62
- package/dist-types/endpoint.d.ts +0 -4
- package/dist-types/plugin.d.ts +0 -21
- package/dist-types/protocol.d.ts +0 -24
- package/dist-types/retry.d.ts +0 -11
- package/dist-types/sse.d.ts +0 -6
- package/dist-types/stream.d.ts +0 -34
- package/dist-types/telemetry.d.ts +0 -3
- package/dist-types/upload.d.ts +0 -12
- package/dist-types/waiter.d.ts +0 -30
package/dist-cjs/index.cjs
CHANGED
|
@@ -132,10 +132,12 @@ __export(src_exports, {
|
|
|
132
132
|
SseStream: () => SseStream,
|
|
133
133
|
WaiterError: () => WaiterError,
|
|
134
134
|
caitlynEndpointProvider: () => caitlynEndpointProvider,
|
|
135
|
+
caitlynTracer: () => caitlynTracer,
|
|
135
136
|
clientConfig: () => clientConfig,
|
|
136
137
|
createAuth: () => createAuth,
|
|
137
138
|
defaultAwsCredentials: () => defaultAwsCredentials,
|
|
138
139
|
getCaitlynAuthPlugin: () => getCaitlynAuthPlugin,
|
|
140
|
+
getCaitlynConnectionErrorPlugin: () => getCaitlynConnectionErrorPlugin,
|
|
139
141
|
getCaitlynSdkPlugin: () => getCaitlynSdkPlugin,
|
|
140
142
|
getCaitlynTelemetryPlugin: () => getCaitlynTelemetryPlugin,
|
|
141
143
|
getWebIdentityToken: () => getWebIdentityToken,
|
|
@@ -151,9 +153,184 @@ __export(src_exports, {
|
|
|
151
153
|
module.exports = __toCommonJS(src_exports);
|
|
152
154
|
|
|
153
155
|
// packages/sdk-core/src/protocol.ts
|
|
154
|
-
var
|
|
156
|
+
var import_protocols3 = require("@smithy/core/protocols");
|
|
155
157
|
var import_schema = require("@smithy/core/schema");
|
|
156
158
|
var import_client = require("@smithy/core/client");
|
|
159
|
+
|
|
160
|
+
// packages/sdk-core/src/plugin.ts
|
|
161
|
+
var import_retry = require("@smithy/core/retry");
|
|
162
|
+
var import_protocols = require("@smithy/core/protocols");
|
|
163
|
+
var import_protocols2 = require("@smithy/core/protocols");
|
|
164
|
+
|
|
165
|
+
// packages/sdk-core/src/retry.ts
|
|
166
|
+
var NO_RETRY = /* @__PURE__ */ Symbol.for("caitlyn.noRetry");
|
|
167
|
+
var Token = class {
|
|
168
|
+
constructor(count, delay) {
|
|
169
|
+
this.count = count;
|
|
170
|
+
this.delay = delay;
|
|
171
|
+
}
|
|
172
|
+
count;
|
|
173
|
+
delay;
|
|
174
|
+
getRetryCount() {
|
|
175
|
+
return this.count;
|
|
176
|
+
}
|
|
177
|
+
getRetryDelay() {
|
|
178
|
+
return this.delay;
|
|
179
|
+
}
|
|
180
|
+
};
|
|
181
|
+
var CaitlynRetryStrategy = class {
|
|
182
|
+
constructor(maxAttempts = 3, maxRetryDelayMs = 6e4) {
|
|
183
|
+
this.maxRetryDelayMs = maxRetryDelayMs;
|
|
184
|
+
this.maxAttempts = typeof maxAttempts === "number" ? async () => maxAttempts : maxAttempts;
|
|
185
|
+
}
|
|
186
|
+
maxRetryDelayMs;
|
|
187
|
+
mode = "standard";
|
|
188
|
+
maxAttempts;
|
|
189
|
+
async acquireInitialRetryToken() {
|
|
190
|
+
return new Token(0, 0);
|
|
191
|
+
}
|
|
192
|
+
async refreshRetryTokenForRetry(token, info) {
|
|
193
|
+
const count = token.getRetryCount();
|
|
194
|
+
const err = info.error;
|
|
195
|
+
if (count + 1 >= await this.maxAttempts()) throw new Error("retry: attempts exhausted");
|
|
196
|
+
if (!err || err[NO_RETRY]) throw new Error("retry: operation is not safe to retry");
|
|
197
|
+
const noResponse = err.$metadata?.httpStatusCode === void 0 && err.name !== "AbortError";
|
|
198
|
+
if (err.$retryable === void 0 && !noResponse) throw new Error("retry: error is not retryable");
|
|
199
|
+
let delay;
|
|
200
|
+
if (info.retryAfterHint instanceof Date) {
|
|
201
|
+
delay = Math.max(0, info.retryAfterHint.getTime() - Date.now());
|
|
202
|
+
if (delay > this.maxRetryDelayMs) throw new Error("retry: Retry-After exceeds maxRetryDelay");
|
|
203
|
+
} else {
|
|
204
|
+
delay = Math.random() * Math.min(8e3, 500 * 2 ** count);
|
|
205
|
+
}
|
|
206
|
+
return new Token(count + 1, delay);
|
|
207
|
+
}
|
|
208
|
+
recordSuccess() {
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
// packages/sdk-core/src/plugin.ts
|
|
213
|
+
var CAITLYN_SDK_USER_AGENT_PREFIX = "caitlyn-sdk-ts";
|
|
214
|
+
var NO_RESPONSE = /* @__PURE__ */ Symbol.for("caitlyn.noResponse");
|
|
215
|
+
function markNoResponse(err) {
|
|
216
|
+
if (err && typeof err === "object" && err.name !== "AbortError") Object.defineProperty(err, NO_RESPONSE, { value: true, configurable: true });
|
|
217
|
+
return err;
|
|
218
|
+
}
|
|
219
|
+
function getCaitlynConnectionErrorPlugin(toError) {
|
|
220
|
+
const mark = (next) => async (args) => {
|
|
221
|
+
try {
|
|
222
|
+
return await next(args);
|
|
223
|
+
} catch (err) {
|
|
224
|
+
const e = err;
|
|
225
|
+
if (!import_protocols2.HttpResponse.isInstance(e?.$response) && e?.$metadata?.httpStatusCode === void 0) markNoResponse(err);
|
|
226
|
+
throw err;
|
|
227
|
+
}
|
|
228
|
+
};
|
|
229
|
+
const wrap = (next, context2) => async (args) => {
|
|
230
|
+
try {
|
|
231
|
+
return await next(args);
|
|
232
|
+
} catch (err) {
|
|
233
|
+
if (err && typeof err === "object" && err[NO_RESPONSE]) {
|
|
234
|
+
throw toError(context2.commandName?.replace(/Command$/, "") ?? "call", err);
|
|
235
|
+
}
|
|
236
|
+
throw err;
|
|
237
|
+
}
|
|
238
|
+
};
|
|
239
|
+
return {
|
|
240
|
+
applyToStack(stack) {
|
|
241
|
+
stack.add(mark, { step: "deserialize", name: "caitlynNoResponse", priority: "low", override: true });
|
|
242
|
+
stack.add(wrap, { step: "initialize", name: "caitlynConnectionError", priority: "normal", override: true });
|
|
243
|
+
}
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
var NotSupportedByServer = class extends Error {
|
|
247
|
+
constructor(operation, requires, server) {
|
|
248
|
+
super(`NotSupportedByServer(${operation}, requires ${requires}, server is ${server})`);
|
|
249
|
+
this.operation = operation;
|
|
250
|
+
this.requires = requires;
|
|
251
|
+
this.server = server;
|
|
252
|
+
this.name = "NotSupportedByServer";
|
|
253
|
+
}
|
|
254
|
+
operation;
|
|
255
|
+
requires;
|
|
256
|
+
server;
|
|
257
|
+
};
|
|
258
|
+
var semver = (a, b) => {
|
|
259
|
+
const pa = a.split(".").map(Number);
|
|
260
|
+
const pb = b.split(".").map(Number);
|
|
261
|
+
for (let i = 0; i < 3; i++) if (pa[i] !== pb[i]) return (pa[i] ?? 0) - (pb[i] ?? 0);
|
|
262
|
+
return 0;
|
|
263
|
+
};
|
|
264
|
+
function runtime() {
|
|
265
|
+
const g = globalThis;
|
|
266
|
+
if (g.process?.versions?.bun) return `md/bun#${g.process.versions.bun}`;
|
|
267
|
+
if (g.Deno?.version?.deno) return `md/deno#${g.Deno.version.deno}`;
|
|
268
|
+
if (g.process?.versions?.node) return `md/nodejs#${g.process.versions.node}`;
|
|
269
|
+
return "md/browser";
|
|
270
|
+
}
|
|
271
|
+
function getCaitlynSdkPlugin(config, options) {
|
|
272
|
+
let server;
|
|
273
|
+
const since = new Map((options.since ?? []).map((e) => e.split("=")));
|
|
274
|
+
const sinceCheck = (next, context2) => async (args) => {
|
|
275
|
+
const op = context2.commandName?.replace(/Command$/, "");
|
|
276
|
+
if (op && server) {
|
|
277
|
+
const required = since.get(op);
|
|
278
|
+
if (required && semver(required, server) > 0) throw new NotSupportedByServer(op, required, server);
|
|
279
|
+
for (const [member, value] of Object.entries(args.input)) {
|
|
280
|
+
const memberSince = value === void 0 ? void 0 : since.get(`${op}.${member}`);
|
|
281
|
+
if (memberSince && semver(memberSince, server) > 0) throw new NotSupportedByServer(`${op}.${member}`, memberSince, server);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
return next(args);
|
|
285
|
+
};
|
|
286
|
+
const serverVersion = (next) => async (args) => {
|
|
287
|
+
try {
|
|
288
|
+
const out = await next(args);
|
|
289
|
+
if (import_protocols2.HttpResponse.isInstance(out.response)) server = out.response.headers["caitlyn-api-version"] ?? server;
|
|
290
|
+
return out;
|
|
291
|
+
} catch (err) {
|
|
292
|
+
const res = err.$response;
|
|
293
|
+
if (import_protocols2.HttpResponse.isInstance(res)) server = res.headers["caitlyn-api-version"] ?? server;
|
|
294
|
+
throw err;
|
|
295
|
+
}
|
|
296
|
+
};
|
|
297
|
+
const userAgent = [`${CAITLYN_SDK_USER_AGENT_PREFIX}/${config.caitlynSdkVersion ?? "0.0.0"}`, "lang/js", runtime(), config.customUserAgent].filter(Boolean).join(" ");
|
|
298
|
+
const identity = (next) => async (args) => {
|
|
299
|
+
if (import_protocols.HttpRequest.isInstance(args.request)) {
|
|
300
|
+
args.request.headers["user-agent"] = userAgent;
|
|
301
|
+
args.request.headers["caitlyn-sdk-model"] = options.sdkModel;
|
|
302
|
+
}
|
|
303
|
+
return next(args);
|
|
304
|
+
};
|
|
305
|
+
const safe = new Set(options.retrySafeOperations);
|
|
306
|
+
const retrySafety = (next, context2) => async (args) => {
|
|
307
|
+
try {
|
|
308
|
+
return await next(args);
|
|
309
|
+
} catch (err) {
|
|
310
|
+
const op = context2.commandName?.replace(/Command$/, "");
|
|
311
|
+
if (op && !safe.has(op) && err && typeof err === "object") Object.defineProperty(err, NO_RETRY, { value: true });
|
|
312
|
+
throw err;
|
|
313
|
+
}
|
|
314
|
+
};
|
|
315
|
+
return {
|
|
316
|
+
applyToStack(stack) {
|
|
317
|
+
stack.add(sinceCheck, { step: "initialize", name: "caitlynSinceCheck", priority: "high", override: true });
|
|
318
|
+
stack.add(serverVersion, { step: "deserialize", name: "caitlynServerVersion", priority: "low", override: true });
|
|
319
|
+
stack.add(identity, { step: "build", name: "caitlynSdkIdentity", priority: "low", override: true });
|
|
320
|
+
stack.addRelativeTo(retrySafety, { toMiddleware: "retryMiddleware", relation: "after", name: "caitlynRetrySafety" });
|
|
321
|
+
(0, import_retry.getOmitRetryHeadersPlugin)({}).applyToStack(stack);
|
|
322
|
+
}
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
// packages/sdk-core/src/protocol.ts
|
|
327
|
+
async function readBody(body, context2) {
|
|
328
|
+
try {
|
|
329
|
+
return await (0, import_protocols3.collectBody)(body, context2);
|
|
330
|
+
} catch (err) {
|
|
331
|
+
throw markNoResponse(err);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
157
334
|
var SETTINGS = {
|
|
158
335
|
timestampFormat: {
|
|
159
336
|
useTrait: true,
|
|
@@ -163,15 +340,15 @@ var SETTINGS = {
|
|
|
163
340
|
httpBindings: true,
|
|
164
341
|
jsonName: true
|
|
165
342
|
};
|
|
166
|
-
var CaitlynRestJsonProtocol = class extends
|
|
343
|
+
var CaitlynRestJsonProtocol = class extends import_protocols3.HttpBindingProtocol {
|
|
167
344
|
serializer;
|
|
168
345
|
deserializer;
|
|
169
346
|
codec;
|
|
170
347
|
constructor({ defaultNamespace, errorTypeRegistries }) {
|
|
171
348
|
super({ defaultNamespace, errorTypeRegistries });
|
|
172
|
-
this.codec = new
|
|
173
|
-
this.serializer = new
|
|
174
|
-
this.deserializer = new
|
|
349
|
+
this.codec = new import_protocols3.JsonCodec2(SETTINGS);
|
|
350
|
+
this.serializer = new import_protocols3.HttpInterceptingShapeSerializer(this.codec.createSerializer(), SETTINGS);
|
|
351
|
+
this.deserializer = new import_protocols3.HttpInterceptingShapeDeserializer(this.codec.createDeserializer(), SETTINGS);
|
|
175
352
|
}
|
|
176
353
|
getShapeId() {
|
|
177
354
|
return "ai.caitlyn.protocols#restJson";
|
|
@@ -205,7 +382,7 @@ var CaitlynRestJsonProtocol = class extends import_protocols.HttpBindingProtocol
|
|
|
205
382
|
const ns = import_schema.NormalizedSchema.of(operationSchema.output);
|
|
206
383
|
const streaming = [...ns.structIterator()].some(([, m]) => m.getMemberTraits().httpPayload && m.isStreaming());
|
|
207
384
|
if (response.statusCode >= 300) {
|
|
208
|
-
const bytes2 = await (
|
|
385
|
+
const bytes2 = await readBody(response.body, context2);
|
|
209
386
|
response.body = bytes2;
|
|
210
387
|
if (!isJsonObject(bytes2)) {
|
|
211
388
|
await this.handleError(operationSchema, context2, response, {}, this.deserializeMetadata(response));
|
|
@@ -213,7 +390,7 @@ var CaitlynRestJsonProtocol = class extends import_protocols.HttpBindingProtocol
|
|
|
213
390
|
return super.deserializeResponse(operationSchema, context2, response);
|
|
214
391
|
}
|
|
215
392
|
if (streaming) return super.deserializeResponse(operationSchema, context2, response);
|
|
216
|
-
const bytes = await (
|
|
393
|
+
const bytes = await readBody(response.body, context2);
|
|
217
394
|
response.body = bytes;
|
|
218
395
|
const output = await super.deserializeResponse(operationSchema, context2, response);
|
|
219
396
|
if (bytes.byteLength > 0) {
|
|
@@ -234,7 +411,7 @@ var CaitlynRestJsonProtocol = class extends import_protocols.HttpBindingProtocol
|
|
|
234
411
|
const registry = this.compositeErrorRegistry;
|
|
235
412
|
registry.copyFrom(import_schema.TypeRegistry.for(this.options.defaultNamespace));
|
|
236
413
|
const errorMetadata = { $metadata: metadata, $fault: response.statusCode < 500 ? "client" : "server" };
|
|
237
|
-
const rawBody = response.body instanceof Uint8Array ?
|
|
414
|
+
const { rawBody, rawBodyTruncated } = rawBodyOf(response.body instanceof Uint8Array ? response.body : new Uint8Array());
|
|
238
415
|
const body = {
|
|
239
416
|
...dataObject,
|
|
240
417
|
// Always the HTTP status: a body's `status` can be wrong (a proxy, a faulty handler), and the class is
|
|
@@ -242,7 +419,8 @@ var CaitlynRestJsonProtocol = class extends import_protocols.HttpBindingProtocol
|
|
|
242
419
|
status: response.statusCode,
|
|
243
420
|
code: typeof dataObject.code === "string" && dataObject.code ? dataObject.code : `HTTP_${response.statusCode}`,
|
|
244
421
|
requestId: dataObject.requestId ?? response.headers["caitlyn-request-id"],
|
|
245
|
-
rawBody
|
|
422
|
+
rawBody,
|
|
423
|
+
rawBodyTruncated
|
|
246
424
|
};
|
|
247
425
|
const message = body.detail ?? body.title ?? `HTTP ${response.statusCode}`;
|
|
248
426
|
const schema = registry.find((s) => {
|
|
@@ -253,7 +431,7 @@ var CaitlynRestJsonProtocol = class extends import_protocols.HttpBindingProtocol
|
|
|
253
431
|
if (!schema) {
|
|
254
432
|
const base = registry.getBaseException();
|
|
255
433
|
const Ctor2 = base && registry.getErrorCtor(base) || Error;
|
|
256
|
-
const name =
|
|
434
|
+
const name = "CaitlynError";
|
|
257
435
|
throw (0, import_client.decorateServiceException)(Object.assign(new Ctor2({ name, message }), errorMetadata), body);
|
|
258
436
|
}
|
|
259
437
|
const ns = import_schema.NormalizedSchema.of(schema);
|
|
@@ -270,6 +448,13 @@ var CaitlynRestJsonProtocol = class extends import_protocols.HttpBindingProtocol
|
|
|
270
448
|
throw (0, import_client.decorateServiceException)(Object.assign(exception, errorMetadata, { $fault: ns.getMergedTraits().error, message }, fields), body);
|
|
271
449
|
}
|
|
272
450
|
};
|
|
451
|
+
var RAW_BODY_LIMIT = 8192;
|
|
452
|
+
function rawBodyOf(bytes) {
|
|
453
|
+
if (bytes.byteLength <= RAW_BODY_LIMIT) return { rawBody: new TextDecoder().decode(bytes), rawBodyTruncated: false };
|
|
454
|
+
let end = RAW_BODY_LIMIT;
|
|
455
|
+
while (end > 0 && (bytes[end] & 192) === 128) end--;
|
|
456
|
+
return { rawBody: new TextDecoder().decode(bytes.subarray(0, end)), rawBodyTruncated: true };
|
|
457
|
+
}
|
|
273
458
|
function isJsonObject(bytes) {
|
|
274
459
|
if (bytes.byteLength === 0) return false;
|
|
275
460
|
try {
|
|
@@ -310,140 +495,6 @@ function resolveContentType(input) {
|
|
|
310
495
|
return hasBody ? "application/json" : void 0;
|
|
311
496
|
}
|
|
312
497
|
|
|
313
|
-
// packages/sdk-core/src/plugin.ts
|
|
314
|
-
var import_retry = require("@smithy/core/retry");
|
|
315
|
-
var import_protocols2 = require("@smithy/core/protocols");
|
|
316
|
-
var import_protocols3 = require("@smithy/core/protocols");
|
|
317
|
-
|
|
318
|
-
// packages/sdk-core/src/retry.ts
|
|
319
|
-
var NO_RETRY = /* @__PURE__ */ Symbol.for("caitlyn.noRetry");
|
|
320
|
-
var Token = class {
|
|
321
|
-
constructor(count, delay) {
|
|
322
|
-
this.count = count;
|
|
323
|
-
this.delay = delay;
|
|
324
|
-
}
|
|
325
|
-
count;
|
|
326
|
-
delay;
|
|
327
|
-
getRetryCount() {
|
|
328
|
-
return this.count;
|
|
329
|
-
}
|
|
330
|
-
getRetryDelay() {
|
|
331
|
-
return this.delay;
|
|
332
|
-
}
|
|
333
|
-
};
|
|
334
|
-
var CaitlynRetryStrategy = class {
|
|
335
|
-
constructor(maxAttempts = 3, maxRetryDelayMs = 6e4) {
|
|
336
|
-
this.maxRetryDelayMs = maxRetryDelayMs;
|
|
337
|
-
this.maxAttempts = typeof maxAttempts === "number" ? async () => maxAttempts : maxAttempts;
|
|
338
|
-
}
|
|
339
|
-
maxRetryDelayMs;
|
|
340
|
-
mode = "standard";
|
|
341
|
-
maxAttempts;
|
|
342
|
-
async acquireInitialRetryToken() {
|
|
343
|
-
return new Token(0, 0);
|
|
344
|
-
}
|
|
345
|
-
async refreshRetryTokenForRetry(token, info) {
|
|
346
|
-
const count = token.getRetryCount();
|
|
347
|
-
const err = info.error;
|
|
348
|
-
if (count + 1 >= await this.maxAttempts()) throw new Error("retry: attempts exhausted");
|
|
349
|
-
if (!err || err[NO_RETRY]) throw new Error("retry: operation is not safe to retry");
|
|
350
|
-
const noResponse = err.$metadata?.httpStatusCode === void 0 && err.name !== "AbortError";
|
|
351
|
-
if (err.$retryable === void 0 && !noResponse) throw new Error("retry: error is not retryable");
|
|
352
|
-
let delay;
|
|
353
|
-
if (info.retryAfterHint instanceof Date) {
|
|
354
|
-
delay = Math.max(0, info.retryAfterHint.getTime() - Date.now());
|
|
355
|
-
if (delay > this.maxRetryDelayMs) throw new Error("retry: Retry-After exceeds maxRetryDelay");
|
|
356
|
-
} else {
|
|
357
|
-
delay = Math.random() * Math.min(8e3, 500 * 2 ** count);
|
|
358
|
-
}
|
|
359
|
-
return new Token(count + 1, delay);
|
|
360
|
-
}
|
|
361
|
-
recordSuccess() {
|
|
362
|
-
}
|
|
363
|
-
};
|
|
364
|
-
|
|
365
|
-
// packages/sdk-core/src/plugin.ts
|
|
366
|
-
var CAITLYN_SDK_USER_AGENT_PREFIX = "caitlyn-sdk-ts";
|
|
367
|
-
var NotSupportedByServer = class extends Error {
|
|
368
|
-
constructor(operation, requires, server) {
|
|
369
|
-
super(`NotSupportedByServer(${operation}, requires ${requires}, server is ${server})`);
|
|
370
|
-
this.operation = operation;
|
|
371
|
-
this.requires = requires;
|
|
372
|
-
this.server = server;
|
|
373
|
-
this.name = "NotSupportedByServer";
|
|
374
|
-
}
|
|
375
|
-
operation;
|
|
376
|
-
requires;
|
|
377
|
-
server;
|
|
378
|
-
};
|
|
379
|
-
var semver = (a, b) => {
|
|
380
|
-
const pa = a.split(".").map(Number);
|
|
381
|
-
const pb = b.split(".").map(Number);
|
|
382
|
-
for (let i = 0; i < 3; i++) if (pa[i] !== pb[i]) return (pa[i] ?? 0) - (pb[i] ?? 0);
|
|
383
|
-
return 0;
|
|
384
|
-
};
|
|
385
|
-
function runtime() {
|
|
386
|
-
const g = globalThis;
|
|
387
|
-
if (g.process?.versions?.bun) return `md/bun#${g.process.versions.bun}`;
|
|
388
|
-
if (g.Deno?.version?.deno) return `md/deno#${g.Deno.version.deno}`;
|
|
389
|
-
if (g.process?.versions?.node) return `md/nodejs#${g.process.versions.node}`;
|
|
390
|
-
return "md/browser";
|
|
391
|
-
}
|
|
392
|
-
function getCaitlynSdkPlugin(config, options) {
|
|
393
|
-
let server;
|
|
394
|
-
const since = new Map((options.since ?? []).map((e) => e.split("=")));
|
|
395
|
-
const sinceCheck = (next, context2) => async (args) => {
|
|
396
|
-
const op = context2.commandName?.replace(/Command$/, "");
|
|
397
|
-
if (op && server) {
|
|
398
|
-
const required = since.get(op);
|
|
399
|
-
if (required && semver(required, server) > 0) throw new NotSupportedByServer(op, required, server);
|
|
400
|
-
for (const [member, value] of Object.entries(args.input)) {
|
|
401
|
-
const memberSince = value === void 0 ? void 0 : since.get(`${op}.${member}`);
|
|
402
|
-
if (memberSince && semver(memberSince, server) > 0) throw new NotSupportedByServer(`${op}.${member}`, memberSince, server);
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
return next(args);
|
|
406
|
-
};
|
|
407
|
-
const serverVersion = (next) => async (args) => {
|
|
408
|
-
try {
|
|
409
|
-
const out = await next(args);
|
|
410
|
-
if (import_protocols3.HttpResponse.isInstance(out.response)) server = out.response.headers["caitlyn-api-version"] ?? server;
|
|
411
|
-
return out;
|
|
412
|
-
} catch (err) {
|
|
413
|
-
const res = err.$response;
|
|
414
|
-
if (import_protocols3.HttpResponse.isInstance(res)) server = res.headers["caitlyn-api-version"] ?? server;
|
|
415
|
-
throw err;
|
|
416
|
-
}
|
|
417
|
-
};
|
|
418
|
-
const userAgent = [`${CAITLYN_SDK_USER_AGENT_PREFIX}/${config.caitlynSdkVersion ?? "0.0.0"}`, "lang/js", runtime(), config.customUserAgent].filter(Boolean).join(" ");
|
|
419
|
-
const identity = (next) => async (args) => {
|
|
420
|
-
if (import_protocols2.HttpRequest.isInstance(args.request)) {
|
|
421
|
-
args.request.headers["user-agent"] = userAgent;
|
|
422
|
-
args.request.headers["caitlyn-sdk-model"] = options.sdkModel;
|
|
423
|
-
}
|
|
424
|
-
return next(args);
|
|
425
|
-
};
|
|
426
|
-
const safe = new Set(options.retrySafeOperations);
|
|
427
|
-
const retrySafety = (next, context2) => async (args) => {
|
|
428
|
-
try {
|
|
429
|
-
return await next(args);
|
|
430
|
-
} catch (err) {
|
|
431
|
-
const op = context2.commandName?.replace(/Command$/, "");
|
|
432
|
-
if (op && !safe.has(op) && err && typeof err === "object") Object.defineProperty(err, NO_RETRY, { value: true });
|
|
433
|
-
throw err;
|
|
434
|
-
}
|
|
435
|
-
};
|
|
436
|
-
return {
|
|
437
|
-
applyToStack(stack) {
|
|
438
|
-
stack.add(sinceCheck, { step: "initialize", name: "caitlynSinceCheck", priority: "high", override: true });
|
|
439
|
-
stack.add(serverVersion, { step: "deserialize", name: "caitlynServerVersion", priority: "low", override: true });
|
|
440
|
-
stack.add(identity, { step: "build", name: "caitlynSdkIdentity", priority: "low", override: true });
|
|
441
|
-
stack.addRelativeTo(retrySafety, { toMiddleware: "retryMiddleware", relation: "after", name: "caitlynRetrySafety" });
|
|
442
|
-
(0, import_retry.getOmitRetryHeadersPlugin)({}).applyToStack(stack);
|
|
443
|
-
}
|
|
444
|
-
};
|
|
445
|
-
}
|
|
446
|
-
|
|
447
498
|
// packages/sdk-core/src/endpoint.ts
|
|
448
499
|
var caitlynEndpointProvider = (params) => {
|
|
449
500
|
if (!params.endpoint) throw new Error("Caitlyn: no endpoint. Pass `workspace` or `endpoint` when creating the client.");
|
|
@@ -453,23 +504,38 @@ var caitlynEndpointProvider = (params) => {
|
|
|
453
504
|
// packages/sdk-core/src/telemetry.ts
|
|
454
505
|
var import_protocols4 = require("@smithy/core/protocols");
|
|
455
506
|
var import_api = require("@opentelemetry/api");
|
|
507
|
+
function caitlynTracer(provider) {
|
|
508
|
+
return (provider ?? import_api.trace.getTracerProvider()).getTracer("@caitlyn-ai/sdk", "0.1.0");
|
|
509
|
+
}
|
|
510
|
+
function urlWithoutQuery(url) {
|
|
511
|
+
const u = new URL(url);
|
|
512
|
+
u.search = "";
|
|
513
|
+
u.hash = "";
|
|
514
|
+
u.username = "";
|
|
515
|
+
u.password = "";
|
|
516
|
+
return u.toString();
|
|
517
|
+
}
|
|
518
|
+
function recordFailure(span, err) {
|
|
519
|
+
const e = err;
|
|
520
|
+
span.recordException(err instanceof Error ? err : { name: String(e?.name ?? "Error"), message: String(e?.message ?? err) });
|
|
521
|
+
span.setStatus({ code: import_api.SpanStatusCode.ERROR, message: e?.message });
|
|
522
|
+
span.setAttribute("error.type", e?.name ?? "Error");
|
|
523
|
+
if (typeof e?.code === "string") span.setAttribute("caitlyn.error.code", e.code);
|
|
524
|
+
}
|
|
456
525
|
function getCaitlynTelemetryPlugin(provider) {
|
|
457
|
-
const tracer = (provider
|
|
526
|
+
const tracer = caitlynTracer(provider);
|
|
458
527
|
return {
|
|
459
528
|
applyToStack(stack) {
|
|
460
529
|
stack.add(
|
|
461
530
|
(next, ctx) => async (args) => {
|
|
462
531
|
const op = ctx.commandName?.replace(/Command$/, "") ?? "unknown";
|
|
463
|
-
return tracer.startActiveSpan(
|
|
532
|
+
return tracer.startActiveSpan("caitlyn.call", { kind: import_api.SpanKind.CLIENT, attributes: { "rpc.system": "caitlyn", "rpc.method": op } }, async (span) => {
|
|
464
533
|
ctx.__caitlynSpan = span;
|
|
465
534
|
ctx.__attempt = 0;
|
|
466
535
|
try {
|
|
467
|
-
|
|
468
|
-
return out;
|
|
536
|
+
return await next(args);
|
|
469
537
|
} catch (err) {
|
|
470
|
-
span
|
|
471
|
-
span.setStatus({ code: import_api.SpanStatusCode.ERROR });
|
|
472
|
-
span.setAttribute("error.type", err.name);
|
|
538
|
+
recordFailure(span, err);
|
|
473
539
|
throw err;
|
|
474
540
|
} finally {
|
|
475
541
|
span.end();
|
|
@@ -483,26 +549,34 @@ function getCaitlynTelemetryPlugin(provider) {
|
|
|
483
549
|
const attempt = ctx.__attempt ?? 0;
|
|
484
550
|
ctx.__attempt = attempt + 1;
|
|
485
551
|
const parent = ctx.__caitlynSpan ? import_api.trace.setSpan(import_api.context.active(), ctx.__caitlynSpan) : import_api.context.active();
|
|
486
|
-
const span = tracer.startSpan(
|
|
552
|
+
const span = tracer.startSpan("caitlyn.attempt", { kind: import_api.SpanKind.CLIENT, attributes: { "http.request.resend_count": attempt } }, parent);
|
|
487
553
|
const req = args.request;
|
|
488
554
|
if (import_protocols4.HttpRequest.isInstance(req)) {
|
|
489
|
-
span.
|
|
555
|
+
span.setAttributes({
|
|
556
|
+
"http.request.method": req.method,
|
|
557
|
+
"server.address": req.hostname,
|
|
558
|
+
"url.full": urlWithoutQuery(`${req.protocol}//${req.hostname}${req.port ? `:${req.port}` : ""}${req.path}`)
|
|
559
|
+
});
|
|
490
560
|
import_api.propagation.inject(import_api.trace.setSpan(parent, span), req.headers);
|
|
491
561
|
}
|
|
562
|
+
const response = (res) => {
|
|
563
|
+
if (!import_protocols4.HttpResponse.isInstance(res)) return;
|
|
564
|
+
span.setAttribute("http.response.status_code", res.statusCode);
|
|
565
|
+
const rid = res.headers["caitlyn-request-id"];
|
|
566
|
+
if (rid) {
|
|
567
|
+
span.setAttribute("caitlyn.request_id", rid);
|
|
568
|
+
ctx.__caitlynSpan?.setAttribute("caitlyn.request_id", rid);
|
|
569
|
+
}
|
|
570
|
+
const api = res.headers["caitlyn-api-version"];
|
|
571
|
+
if (api) span.setAttribute("caitlyn.server.api_version", api);
|
|
572
|
+
if (res.statusCode >= 400) span.setStatus({ code: import_api.SpanStatusCode.ERROR });
|
|
573
|
+
};
|
|
492
574
|
try {
|
|
493
575
|
const out = await next(args);
|
|
494
|
-
|
|
495
|
-
span.setAttribute("http.response.status_code", out.response.statusCode);
|
|
496
|
-
const rid = out.response.headers["caitlyn-request-id"];
|
|
497
|
-
if (rid) {
|
|
498
|
-
span.setAttribute("caitlyn.request_id", rid);
|
|
499
|
-
ctx.__caitlynSpan?.setAttribute("caitlyn.request_id", rid);
|
|
500
|
-
}
|
|
501
|
-
}
|
|
576
|
+
response(out.response);
|
|
502
577
|
return out;
|
|
503
578
|
} catch (err) {
|
|
504
|
-
|
|
505
|
-
if (import_protocols4.HttpResponse.isInstance(res)) span.setAttribute("http.response.status_code", res.statusCode);
|
|
579
|
+
response(err.$response);
|
|
506
580
|
span.setStatus({ code: import_api.SpanStatusCode.ERROR });
|
|
507
581
|
throw err;
|
|
508
582
|
} finally {
|
|
@@ -565,17 +639,23 @@ var SseStream = class {
|
|
|
565
639
|
seen = /* @__PURE__ */ new Set();
|
|
566
640
|
lastEventId;
|
|
567
641
|
reconnects = 0;
|
|
642
|
+
/** The Caitlyn-Request-Id of the response that opened the stream; set once iteration has started. */
|
|
643
|
+
requestId;
|
|
568
644
|
aborted() {
|
|
569
645
|
return this.signal?.reason ?? new DOMException("Aborted", "AbortError");
|
|
570
646
|
}
|
|
571
647
|
async *[Symbol.asyncIterator]() {
|
|
572
648
|
if (this.consumed) throw new Error("SseStream can only be iterated once");
|
|
573
649
|
this.consumed = true;
|
|
574
|
-
|
|
650
|
+
const opened = await this.open();
|
|
651
|
+
this.requestId = opened.$metadata?.requestId;
|
|
652
|
+
let body = opened.events;
|
|
575
653
|
for (; ; ) {
|
|
576
654
|
let ended = false;
|
|
655
|
+
let onResponse = 0;
|
|
577
656
|
try {
|
|
578
657
|
for await (const msg of parseSse(body)) {
|
|
658
|
+
onResponse++;
|
|
579
659
|
if (msg.id) {
|
|
580
660
|
if (this.seen.has(msg.id)) continue;
|
|
581
661
|
this.seen.add(msg.id);
|
|
@@ -592,7 +672,7 @@ var SseStream = class {
|
|
|
592
672
|
return;
|
|
593
673
|
}
|
|
594
674
|
}
|
|
595
|
-
if (!this.spec.final) return;
|
|
675
|
+
if (!this.spec.final || onResponse === 0) return;
|
|
596
676
|
} catch (err) {
|
|
597
677
|
if (this.signal?.aborted) throw this.aborted();
|
|
598
678
|
if (ended || err?.name === "AbortError" || err === void 0 || err.$fault || err instanceof SyntaxError) throw err;
|
|
@@ -600,7 +680,7 @@ var SseStream = class {
|
|
|
600
680
|
if (this.signal?.aborted) throw this.aborted();
|
|
601
681
|
if (!this.resume || ++this.reconnects > this.maxReconnects)
|
|
602
682
|
throw this.spec.toError({ status: 0, code: "STREAM_LOST", title: "The stream dropped and could not be resumed" });
|
|
603
|
-
body = await this.resume(this.lastEventId);
|
|
683
|
+
body = (await this.resume(this.lastEventId)).events;
|
|
604
684
|
}
|
|
605
685
|
}
|
|
606
686
|
/** Drains the stream if needed and returns the final event's member. */
|
|
@@ -612,15 +692,40 @@ var SseStream = class {
|
|
|
612
692
|
};
|
|
613
693
|
|
|
614
694
|
// packages/sdk-core/src/upload.ts
|
|
615
|
-
|
|
695
|
+
var import_api2 = require("@opentelemetry/api");
|
|
696
|
+
var STATUS = /* @__PURE__ */ Symbol("status");
|
|
697
|
+
async function uploadFile(file, fileName, reserve, toError, signal, tracer) {
|
|
616
698
|
const bytes = new Uint8Array(await file.arrayBuffer());
|
|
617
699
|
const digest = new Uint8Array(await crypto.subtle.digest("SHA-256", bytes));
|
|
618
700
|
let binary = "";
|
|
619
701
|
for (const b of digest) binary += String.fromCharCode(b);
|
|
620
702
|
const slot = await reserve({ fileName, contentType: file.type || "application/octet-stream", byteSize: bytes.byteLength, sha256: btoa(binary) });
|
|
621
|
-
const
|
|
622
|
-
|
|
623
|
-
|
|
703
|
+
const put = async () => {
|
|
704
|
+
const res = await fetch(slot.uploadUrl, { method: slot.uploadMethod, headers: slot.requiredHeaders, body: bytes, signal });
|
|
705
|
+
if (!res.ok) throw Object.assign(toError({ status: res.status, code: "UPLOAD_PUT_FAILED", title: "Uploading the bytes failed", detail: await res.text() }), { [STATUS]: res.status });
|
|
706
|
+
return res.status;
|
|
707
|
+
};
|
|
708
|
+
if (!tracer) {
|
|
709
|
+
await put();
|
|
710
|
+
return slot;
|
|
711
|
+
}
|
|
712
|
+
const url = new URL(slot.uploadUrl);
|
|
713
|
+
const span = tracer.startSpan("caitlyn.upload", {
|
|
714
|
+
kind: import_api2.SpanKind.CLIENT,
|
|
715
|
+
attributes: { "http.request.method": slot.uploadMethod || "PUT", "server.address": url.hostname, "url.full": urlWithoutQuery(slot.uploadUrl) }
|
|
716
|
+
});
|
|
717
|
+
try {
|
|
718
|
+
span.setAttribute("http.response.status_code", await put());
|
|
719
|
+
return slot;
|
|
720
|
+
} catch (err) {
|
|
721
|
+
const status = err[STATUS];
|
|
722
|
+
if (status !== void 0) span.setAttribute("http.response.status_code", status);
|
|
723
|
+
recordFailure(span, err);
|
|
724
|
+
span.setStatus({ code: import_api2.SpanStatusCode.ERROR });
|
|
725
|
+
throw err;
|
|
726
|
+
} finally {
|
|
727
|
+
span.end();
|
|
728
|
+
}
|
|
624
729
|
}
|
|
625
730
|
|
|
626
731
|
// packages/sdk-core/src/auth.ts
|
|
@@ -644,8 +749,30 @@ var SESSION_PLACEHOLDER = "session";
|
|
|
644
749
|
var refreshAt = (t) => t.expiresAt === void 0 ? void 0 : t.expiresAt - Math.min(REFRESH_EARLY_MS, (t.expiresAt - Date.now()) / 2);
|
|
645
750
|
var b64url = (bytes) => btoa(String.fromCharCode(...new Uint8Array(bytes))).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
646
751
|
var randomString = (n = 32) => b64url(crypto.getRandomValues(new Uint8Array(n)));
|
|
647
|
-
var workspaceAudience = (workspace) => `https://${workspaceHost(workspace)}/api
|
|
752
|
+
var workspaceAudience = (workspace) => `https://${workspaceHost(workspace)}/api`;
|
|
648
753
|
var workspaceHost = (workspace) => workspace.replace(/^https?:\/\//, "").replace(/\/.*$/, "");
|
|
754
|
+
var isBrowser = () => {
|
|
755
|
+
const g = globalThis;
|
|
756
|
+
return typeof g.window !== "undefined" && typeof g.document !== "undefined";
|
|
757
|
+
};
|
|
758
|
+
var IN_BROWSER = "not_allowed_in_browser";
|
|
759
|
+
function guardBrowser(o) {
|
|
760
|
+
if (!isBrowser()) return;
|
|
761
|
+
if (o.mode === "clientCredentials" || o.mode === "oauth" && o.clientSecret) {
|
|
762
|
+
throw new CaitlynAuthError(
|
|
763
|
+
`${o.mode === "oauth" ? "oauth with a clientSecret" : "clientCredentials"} cannot be used in a browser: a client secret in a browser is visible to everyone who loads the page. Use oauth without a clientSecret (authorisation code with PKCE), or sign in on your server.`,
|
|
764
|
+
IN_BROWSER
|
|
765
|
+
);
|
|
766
|
+
}
|
|
767
|
+
if (o.mode === "awsIam" || o.mode === "workloadIdentity") {
|
|
768
|
+
throw new CaitlynAuthError(`${o.mode} cannot be used in a browser: it signs in a server workload with that workload's own identity. Use oauth in a browser.`, IN_BROWSER);
|
|
769
|
+
}
|
|
770
|
+
if (o.mode === "token" && !o.allowBrowserToken) {
|
|
771
|
+
console.warn(
|
|
772
|
+
"Caitlyn: a long-lived token in a browser is exposed to anyone who can run script on the page. token mode in a browser is for local testing; use oauth instead. Set auth.allowBrowserToken: true to silence this warning."
|
|
773
|
+
);
|
|
774
|
+
}
|
|
775
|
+
}
|
|
649
776
|
var AuthSession = class {
|
|
650
777
|
constructor(options, endpoint, workspace, fetchFn = (...a) => fetch(...a)) {
|
|
651
778
|
this.options = options;
|
|
@@ -656,6 +783,7 @@ var AuthSession = class {
|
|
|
656
783
|
this.authorizationEndpoint = `${endpoint}/oauth/authorize`;
|
|
657
784
|
this.workspaceUrl = `https://${workspace}`;
|
|
658
785
|
this.resource = "resource" in options && options.resource || workspaceAudience(workspace);
|
|
786
|
+
guardBrowser(options);
|
|
659
787
|
}
|
|
660
788
|
options;
|
|
661
789
|
endpoint;
|
|
@@ -668,7 +796,7 @@ var AuthSession = class {
|
|
|
668
796
|
memoryTokens;
|
|
669
797
|
tokenEndpoint;
|
|
670
798
|
authorizationEndpoint;
|
|
671
|
-
/** The workspace's resource URL, https://<workspace>/api
|
|
799
|
+
/** The workspace's resource URL, https://<workspace>/api: the audience every token is bound to. */
|
|
672
800
|
resource;
|
|
673
801
|
/** https://<workspace>: the default Origin for session writes. */
|
|
674
802
|
workspaceUrl;
|
|
@@ -892,6 +1020,9 @@ function clientConfig(opts, auth = createAuth(opts)) {
|
|
|
892
1020
|
workspace: workspaceHost(opts.workspace),
|
|
893
1021
|
endpoint: opts.endpoint ?? workspaceEndpoint(opts.workspace),
|
|
894
1022
|
token: tokenIdentityProvider(auth),
|
|
1023
|
+
/** The tracer upload helpers record the byte transfer with (PROTOCOL.md 13); absent with telemetry off. */
|
|
1024
|
+
caitlynTracer: opts.telemetry?.enabled === false ? void 0 : caitlynTracer(opts.telemetry?.tracerProvider),
|
|
1025
|
+
...opts.requestHandler !== void 0 ? { requestHandler: opts.requestHandler } : {},
|
|
895
1026
|
...opts.maxAttempts !== void 0 ? { maxAttempts: opts.maxAttempts } : {},
|
|
896
1027
|
...opts.maxRetryDelayMs !== void 0 ? { retryStrategy: new CaitlynRetryStrategy(opts.maxAttempts ?? 3, opts.maxRetryDelayMs) } : {}
|
|
897
1028
|
};
|
|
@@ -965,10 +1096,12 @@ async function waitUntil(name, read, accept, opts = {}) {
|
|
|
965
1096
|
SseStream,
|
|
966
1097
|
WaiterError,
|
|
967
1098
|
caitlynEndpointProvider,
|
|
1099
|
+
caitlynTracer,
|
|
968
1100
|
clientConfig,
|
|
969
1101
|
createAuth,
|
|
970
1102
|
defaultAwsCredentials,
|
|
971
1103
|
getCaitlynAuthPlugin,
|
|
1104
|
+
getCaitlynConnectionErrorPlugin,
|
|
972
1105
|
getCaitlynSdkPlugin,
|
|
973
1106
|
getCaitlynTelemetryPlugin,
|
|
974
1107
|
getWebIdentityToken,
|