@caitlyn-ai/sdk-core 0.0.2 → 0.1.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/README.md +39 -7
- package/dist-cjs/index.cjs +309 -173
- package/dist-cjs/index.cjs.map +3 -3
- package/dist-es/index.mjs +302 -168
- 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,42 @@ 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.1");
|
|
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
|
+
const noResponse = !!e?.[NO_RESPONSE];
|
|
521
|
+
const name = noResponse ? "CaitlynConnectionError" : e?.name ?? "Error";
|
|
522
|
+
const message = String(e?.message ?? err);
|
|
523
|
+
span.recordException({ name, message, stack: err instanceof Error ? err.stack : void 0 });
|
|
524
|
+
span.setStatus({ code: import_api.SpanStatusCode.ERROR, message });
|
|
525
|
+
span.setAttribute("error.type", name);
|
|
526
|
+
const code = noResponse ? "CONNECTION_ERROR" : e?.code;
|
|
527
|
+
if (typeof code === "string") span.setAttribute("caitlyn.error.code", code);
|
|
528
|
+
}
|
|
456
529
|
function getCaitlynTelemetryPlugin(provider) {
|
|
457
|
-
const tracer = (provider
|
|
530
|
+
const tracer = caitlynTracer(provider);
|
|
458
531
|
return {
|
|
459
532
|
applyToStack(stack) {
|
|
460
533
|
stack.add(
|
|
461
534
|
(next, ctx) => async (args) => {
|
|
462
535
|
const op = ctx.commandName?.replace(/Command$/, "") ?? "unknown";
|
|
463
|
-
return tracer.startActiveSpan(
|
|
536
|
+
return tracer.startActiveSpan("caitlyn.call", { kind: import_api.SpanKind.CLIENT, attributes: { "rpc.system": "caitlyn", "rpc.method": op } }, async (span) => {
|
|
464
537
|
ctx.__caitlynSpan = span;
|
|
465
538
|
ctx.__attempt = 0;
|
|
466
539
|
try {
|
|
467
|
-
|
|
468
|
-
return out;
|
|
540
|
+
return await next(args);
|
|
469
541
|
} catch (err) {
|
|
470
|
-
span
|
|
471
|
-
span.setStatus({ code: import_api.SpanStatusCode.ERROR });
|
|
472
|
-
span.setAttribute("error.type", err.name);
|
|
542
|
+
recordFailure(span, err);
|
|
473
543
|
throw err;
|
|
474
544
|
} finally {
|
|
475
545
|
span.end();
|
|
@@ -483,27 +553,34 @@ function getCaitlynTelemetryPlugin(provider) {
|
|
|
483
553
|
const attempt = ctx.__attempt ?? 0;
|
|
484
554
|
ctx.__attempt = attempt + 1;
|
|
485
555
|
const parent = ctx.__caitlynSpan ? import_api.trace.setSpan(import_api.context.active(), ctx.__caitlynSpan) : import_api.context.active();
|
|
486
|
-
const span = tracer.startSpan(
|
|
556
|
+
const span = tracer.startSpan("caitlyn.attempt", { kind: import_api.SpanKind.CLIENT, attributes: { "http.request.resend_count": attempt } }, parent);
|
|
487
557
|
const req = args.request;
|
|
488
558
|
if (import_protocols4.HttpRequest.isInstance(req)) {
|
|
489
|
-
span.
|
|
559
|
+
span.setAttributes({
|
|
560
|
+
"http.request.method": req.method,
|
|
561
|
+
"server.address": req.hostname,
|
|
562
|
+
"url.full": urlWithoutQuery(`${req.protocol}//${req.hostname}${req.port ? `:${req.port}` : ""}${req.path}`)
|
|
563
|
+
});
|
|
490
564
|
import_api.propagation.inject(import_api.trace.setSpan(parent, span), req.headers);
|
|
491
565
|
}
|
|
566
|
+
const response = (res) => {
|
|
567
|
+
if (!import_protocols4.HttpResponse.isInstance(res)) return;
|
|
568
|
+
span.setAttribute("http.response.status_code", res.statusCode);
|
|
569
|
+
const rid = res.headers["caitlyn-request-id"];
|
|
570
|
+
if (rid) {
|
|
571
|
+
span.setAttribute("caitlyn.request_id", rid);
|
|
572
|
+
ctx.__caitlynSpan?.setAttribute("caitlyn.request_id", rid);
|
|
573
|
+
}
|
|
574
|
+
const api = res.headers["caitlyn-api-version"];
|
|
575
|
+
if (api) span.setAttribute("caitlyn.server.api_version", api);
|
|
576
|
+
};
|
|
492
577
|
try {
|
|
493
578
|
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
|
-
}
|
|
579
|
+
response(out.response);
|
|
502
580
|
return out;
|
|
503
581
|
} catch (err) {
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
span.setStatus({ code: import_api.SpanStatusCode.ERROR });
|
|
582
|
+
response(err.$response);
|
|
583
|
+
recordFailure(span, err);
|
|
507
584
|
throw err;
|
|
508
585
|
} finally {
|
|
509
586
|
span.end();
|
|
@@ -565,17 +642,23 @@ var SseStream = class {
|
|
|
565
642
|
seen = /* @__PURE__ */ new Set();
|
|
566
643
|
lastEventId;
|
|
567
644
|
reconnects = 0;
|
|
645
|
+
/** The Caitlyn-Request-Id of the response that opened the stream; set once iteration has started. */
|
|
646
|
+
requestId;
|
|
568
647
|
aborted() {
|
|
569
648
|
return this.signal?.reason ?? new DOMException("Aborted", "AbortError");
|
|
570
649
|
}
|
|
571
650
|
async *[Symbol.asyncIterator]() {
|
|
572
651
|
if (this.consumed) throw new Error("SseStream can only be iterated once");
|
|
573
652
|
this.consumed = true;
|
|
574
|
-
|
|
653
|
+
const opened = await this.open();
|
|
654
|
+
this.requestId = opened.$metadata?.requestId;
|
|
655
|
+
let body = opened.events;
|
|
575
656
|
for (; ; ) {
|
|
576
657
|
let ended = false;
|
|
658
|
+
let onResponse = 0;
|
|
577
659
|
try {
|
|
578
660
|
for await (const msg of parseSse(body)) {
|
|
661
|
+
onResponse++;
|
|
579
662
|
if (msg.id) {
|
|
580
663
|
if (this.seen.has(msg.id)) continue;
|
|
581
664
|
this.seen.add(msg.id);
|
|
@@ -592,7 +675,7 @@ var SseStream = class {
|
|
|
592
675
|
return;
|
|
593
676
|
}
|
|
594
677
|
}
|
|
595
|
-
if (!this.spec.final) return;
|
|
678
|
+
if (!this.spec.final || onResponse === 0) return;
|
|
596
679
|
} catch (err) {
|
|
597
680
|
if (this.signal?.aborted) throw this.aborted();
|
|
598
681
|
if (ended || err?.name === "AbortError" || err === void 0 || err.$fault || err instanceof SyntaxError) throw err;
|
|
@@ -600,7 +683,7 @@ var SseStream = class {
|
|
|
600
683
|
if (this.signal?.aborted) throw this.aborted();
|
|
601
684
|
if (!this.resume || ++this.reconnects > this.maxReconnects)
|
|
602
685
|
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);
|
|
686
|
+
body = (await this.resume(this.lastEventId)).events;
|
|
604
687
|
}
|
|
605
688
|
}
|
|
606
689
|
/** Drains the stream if needed and returns the final event's member. */
|
|
@@ -612,15 +695,40 @@ var SseStream = class {
|
|
|
612
695
|
};
|
|
613
696
|
|
|
614
697
|
// packages/sdk-core/src/upload.ts
|
|
615
|
-
|
|
698
|
+
var import_api2 = require("@opentelemetry/api");
|
|
699
|
+
var STATUS = /* @__PURE__ */ Symbol("status");
|
|
700
|
+
async function uploadFile(file, fileName, reserve, toError, signal, tracer) {
|
|
616
701
|
const bytes = new Uint8Array(await file.arrayBuffer());
|
|
617
702
|
const digest = new Uint8Array(await crypto.subtle.digest("SHA-256", bytes));
|
|
618
703
|
let binary = "";
|
|
619
704
|
for (const b of digest) binary += String.fromCharCode(b);
|
|
620
705
|
const slot = await reserve({ fileName, contentType: file.type || "application/octet-stream", byteSize: bytes.byteLength, sha256: btoa(binary) });
|
|
621
|
-
const
|
|
622
|
-
|
|
623
|
-
|
|
706
|
+
const put = async () => {
|
|
707
|
+
const res = await fetch(slot.uploadUrl, { method: slot.uploadMethod, headers: slot.requiredHeaders, body: bytes, signal });
|
|
708
|
+
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 });
|
|
709
|
+
return res.status;
|
|
710
|
+
};
|
|
711
|
+
if (!tracer) {
|
|
712
|
+
await put();
|
|
713
|
+
return slot;
|
|
714
|
+
}
|
|
715
|
+
const url = new URL(slot.uploadUrl);
|
|
716
|
+
const span = tracer.startSpan("caitlyn.upload", {
|
|
717
|
+
kind: import_api2.SpanKind.CLIENT,
|
|
718
|
+
attributes: { "http.request.method": slot.uploadMethod || "PUT", "server.address": url.hostname, "url.full": urlWithoutQuery(slot.uploadUrl) }
|
|
719
|
+
});
|
|
720
|
+
try {
|
|
721
|
+
span.setAttribute("http.response.status_code", await put());
|
|
722
|
+
return slot;
|
|
723
|
+
} catch (err) {
|
|
724
|
+
const status = err[STATUS];
|
|
725
|
+
if (status !== void 0) span.setAttribute("http.response.status_code", status);
|
|
726
|
+
recordFailure(span, err);
|
|
727
|
+
span.setStatus({ code: import_api2.SpanStatusCode.ERROR });
|
|
728
|
+
throw err;
|
|
729
|
+
} finally {
|
|
730
|
+
span.end();
|
|
731
|
+
}
|
|
624
732
|
}
|
|
625
733
|
|
|
626
734
|
// packages/sdk-core/src/auth.ts
|
|
@@ -644,8 +752,30 @@ var SESSION_PLACEHOLDER = "session";
|
|
|
644
752
|
var refreshAt = (t) => t.expiresAt === void 0 ? void 0 : t.expiresAt - Math.min(REFRESH_EARLY_MS, (t.expiresAt - Date.now()) / 2);
|
|
645
753
|
var b64url = (bytes) => btoa(String.fromCharCode(...new Uint8Array(bytes))).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
646
754
|
var randomString = (n = 32) => b64url(crypto.getRandomValues(new Uint8Array(n)));
|
|
647
|
-
var workspaceAudience = (workspace) => `https://${workspaceHost(workspace)}/api
|
|
755
|
+
var workspaceAudience = (workspace) => `https://${workspaceHost(workspace)}/api`;
|
|
648
756
|
var workspaceHost = (workspace) => workspace.replace(/^https?:\/\//, "").replace(/\/.*$/, "");
|
|
757
|
+
var isBrowser = () => {
|
|
758
|
+
const g = globalThis;
|
|
759
|
+
return typeof g.window !== "undefined" && typeof g.document !== "undefined";
|
|
760
|
+
};
|
|
761
|
+
var IN_BROWSER = "not_allowed_in_browser";
|
|
762
|
+
function guardBrowser(o) {
|
|
763
|
+
if (!isBrowser()) return;
|
|
764
|
+
if (o.mode === "clientCredentials" || o.mode === "oauth" && o.clientSecret) {
|
|
765
|
+
throw new CaitlynAuthError(
|
|
766
|
+
`${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.`,
|
|
767
|
+
IN_BROWSER
|
|
768
|
+
);
|
|
769
|
+
}
|
|
770
|
+
if (o.mode === "awsIam" || o.mode === "workloadIdentity") {
|
|
771
|
+
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);
|
|
772
|
+
}
|
|
773
|
+
if (o.mode === "token" && !o.allowBrowserToken) {
|
|
774
|
+
console.warn(
|
|
775
|
+
"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."
|
|
776
|
+
);
|
|
777
|
+
}
|
|
778
|
+
}
|
|
649
779
|
var AuthSession = class {
|
|
650
780
|
constructor(options, endpoint, workspace, fetchFn = (...a) => fetch(...a)) {
|
|
651
781
|
this.options = options;
|
|
@@ -656,6 +786,7 @@ var AuthSession = class {
|
|
|
656
786
|
this.authorizationEndpoint = `${endpoint}/oauth/authorize`;
|
|
657
787
|
this.workspaceUrl = `https://${workspace}`;
|
|
658
788
|
this.resource = "resource" in options && options.resource || workspaceAudience(workspace);
|
|
789
|
+
guardBrowser(options);
|
|
659
790
|
}
|
|
660
791
|
options;
|
|
661
792
|
endpoint;
|
|
@@ -668,7 +799,7 @@ var AuthSession = class {
|
|
|
668
799
|
memoryTokens;
|
|
669
800
|
tokenEndpoint;
|
|
670
801
|
authorizationEndpoint;
|
|
671
|
-
/** The workspace's resource URL, https://<workspace>/api
|
|
802
|
+
/** The workspace's resource URL, https://<workspace>/api: the audience every token is bound to. */
|
|
672
803
|
resource;
|
|
673
804
|
/** https://<workspace>: the default Origin for session writes. */
|
|
674
805
|
workspaceUrl;
|
|
@@ -892,6 +1023,9 @@ function clientConfig(opts, auth = createAuth(opts)) {
|
|
|
892
1023
|
workspace: workspaceHost(opts.workspace),
|
|
893
1024
|
endpoint: opts.endpoint ?? workspaceEndpoint(opts.workspace),
|
|
894
1025
|
token: tokenIdentityProvider(auth),
|
|
1026
|
+
/** The tracer upload helpers record the byte transfer with (PROTOCOL.md 13); absent with telemetry off. */
|
|
1027
|
+
caitlynTracer: opts.telemetry?.enabled === false ? void 0 : caitlynTracer(opts.telemetry?.tracerProvider),
|
|
1028
|
+
...opts.requestHandler !== void 0 ? { requestHandler: opts.requestHandler } : {},
|
|
895
1029
|
...opts.maxAttempts !== void 0 ? { maxAttempts: opts.maxAttempts } : {},
|
|
896
1030
|
...opts.maxRetryDelayMs !== void 0 ? { retryStrategy: new CaitlynRetryStrategy(opts.maxAttempts ?? 3, opts.maxRetryDelayMs) } : {}
|
|
897
1031
|
};
|
|
@@ -965,10 +1099,12 @@ async function waitUntil(name, read, accept, opts = {}) {
|
|
|
965
1099
|
SseStream,
|
|
966
1100
|
WaiterError,
|
|
967
1101
|
caitlynEndpointProvider,
|
|
1102
|
+
caitlynTracer,
|
|
968
1103
|
clientConfig,
|
|
969
1104
|
createAuth,
|
|
970
1105
|
defaultAwsCredentials,
|
|
971
1106
|
getCaitlynAuthPlugin,
|
|
1107
|
+
getCaitlynConnectionErrorPlugin,
|
|
972
1108
|
getCaitlynSdkPlugin,
|
|
973
1109
|
getCaitlynTelemetryPlugin,
|
|
974
1110
|
getWebIdentityToken,
|