@raindrop-ai/openai-managed-agents 0.0.4 → 0.0.5
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 +26 -0
- package/dist/index.d.mts +276 -27
- package/dist/index.d.ts +276 -27
- package/dist/index.js +1507 -296
- package/dist/index.mjs +1507 -296
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,33 @@
|
|
|
1
|
-
// ../core/dist/chunk-
|
|
1
|
+
// ../core/dist/chunk-ZCB62SIO.js
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __commonJS = (cb, mod) => function __require() {
|
|
9
|
+
try {
|
|
10
|
+
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
11
|
+
} catch (e) {
|
|
12
|
+
throw mod = 0, e;
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
var __copyProps = (to, from, except, desc) => {
|
|
16
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
17
|
+
for (let key of __getOwnPropNames(from))
|
|
18
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
19
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
20
|
+
}
|
|
21
|
+
return to;
|
|
22
|
+
};
|
|
23
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
24
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
25
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
26
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
27
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
28
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
29
|
+
mod
|
|
30
|
+
));
|
|
2
31
|
var EVAL_CORRELATION_ID_ATTRIBUTE = "raindrop.eval_correlation_id";
|
|
3
32
|
var PROBE_SCOPE = { correlationId: "" };
|
|
4
33
|
var EvalScopeStorage = class {
|
|
@@ -60,21 +89,246 @@ function evalScopeAttributes() {
|
|
|
60
89
|
return { [EVAL_CORRELATION_ID_ATTRIBUTE]: scope.correlationId };
|
|
61
90
|
}
|
|
62
91
|
|
|
63
|
-
// ../core/dist/chunk-
|
|
92
|
+
// ../core/dist/chunk-AX36JKJL.js
|
|
93
|
+
var require_NameRedactor = __commonJS({
|
|
94
|
+
"../redact-pii/dist/built-ins/NameRedactor.js"(exports) {
|
|
95
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
96
|
+
exports.NameRedactor = void 0;
|
|
97
|
+
var greetingRegex = /(^|\.\s+)(dear|hi|hello|greetings|hey|hey there)/gi;
|
|
98
|
+
var closingRegex = /(thx|thanks|thank you|regards|best|[a-z]{1,30}ly|[a-z]{1,30} regards|all the best|happy [a-z]{1,30}ing|take care|have a [a-z]{1,30} (weekend|night|day))/gi;
|
|
99
|
+
var greetingOrClosing = new RegExp("(((" + greetingRegex.source + ")|(" + closingRegex.source + "\\s*[,.!]*))[\\s-]*)", "gi");
|
|
100
|
+
var genericName = new RegExp("( ?(([A-Z][a-z]{1,30})|([A-Z]\\.))){1,10}([,.]|[,.]?$)", "my");
|
|
101
|
+
var NameRedactor = class {
|
|
102
|
+
constructor(replaceWith = "PERSON_NAME") {
|
|
103
|
+
this.replaceWith = replaceWith;
|
|
104
|
+
}
|
|
105
|
+
redact(textToRedact) {
|
|
106
|
+
var _a;
|
|
107
|
+
greetingOrClosing.lastIndex = 0;
|
|
108
|
+
genericName.lastIndex = 0;
|
|
109
|
+
const pieces = [];
|
|
110
|
+
let copiedThrough = 0;
|
|
111
|
+
let changed = false;
|
|
112
|
+
let greetingOrClosingMatch = greetingOrClosing.exec(textToRedact);
|
|
113
|
+
while (greetingOrClosingMatch !== null) {
|
|
114
|
+
genericName.lastIndex = greetingOrClosing.lastIndex;
|
|
115
|
+
const genericNameMatch = genericName.exec(textToRedact);
|
|
116
|
+
if (genericNameMatch !== null && genericNameMatch.index === greetingOrClosing.lastIndex) {
|
|
117
|
+
const suffix = (_a = genericNameMatch[5]) !== null && _a !== void 0 ? _a : "";
|
|
118
|
+
const end = genericNameMatch.index + genericNameMatch[0].length;
|
|
119
|
+
pieces.push(textToRedact.slice(copiedThrough, genericNameMatch.index), this.replaceWith, suffix);
|
|
120
|
+
copiedThrough = end;
|
|
121
|
+
changed = true;
|
|
122
|
+
greetingOrClosing.lastIndex = end - suffix.length;
|
|
123
|
+
}
|
|
124
|
+
greetingOrClosingMatch = greetingOrClosing.exec(textToRedact);
|
|
125
|
+
}
|
|
126
|
+
if (!changed)
|
|
127
|
+
return textToRedact;
|
|
128
|
+
pieces.push(textToRedact.slice(copiedThrough));
|
|
129
|
+
return pieces.join("");
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
exports.NameRedactor = NameRedactor;
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
var require_simple_regexp_patterns = __commonJS({
|
|
136
|
+
"../redact-pii/dist/built-ins/simple-regexp-patterns.js"(exports) {
|
|
137
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
138
|
+
exports.url = exports.digits = exports.credentials = exports.password = exports.username = exports.emailAddress = exports.usSocialSecurityNumber = exports.ipAddress = exports.phoneNumber = exports.zipcode = exports.streetAddress = exports.creditCardNumber = void 0;
|
|
139
|
+
var aptRegex = /(apt|bldg|dept|fl|hngr|lot|pier|rm|ste|slip|trlr|unit|#)\.? *[a-z0-9-]+\b/gi;
|
|
140
|
+
var poBoxRegex = /P\.? ?O\.? *Box +\d+/gi;
|
|
141
|
+
var roadRegex = /(street|st|road|rd|avenue|ave|drive|dr|loop|court|ct|circle|cir|lane|ln|boulevard|blvd|way)\.?\b/gi;
|
|
142
|
+
exports.creditCardNumber = /\d{4}[ -]?\d{4}[ -]?\d{4}[ -]?\d{4}|\d{4}[ -]?\d{6}[ -]?\d{4}\d?/g;
|
|
143
|
+
exports.streetAddress = new RegExp("(\\d{1,10}\\s*(\\w{1,30} ){1,2}" + roadRegex.source + "(\\s+" + aptRegex.source + ")?)|(" + poBoxRegex.source + ")", "gi");
|
|
144
|
+
exports.zipcode = /\b\d{5}\b(-\d{4})?\b/g;
|
|
145
|
+
exports.phoneNumber = /(\(?\+?[0-9]{1,2}\)?[-. ]?)?(\(?[0-9]{3}\)?|[0-9]{3})[-. ]?([0-9]{3}[-. ]?[0-9]{4}|\b[A-Z0-9]{7}\b)/g;
|
|
146
|
+
exports.ipAddress = /(\d{1,3}(\.\d{1,3}){3}|[0-9A-F]{4}(:[0-9A-F]{4}){5}(::|(:0000)+))/gi;
|
|
147
|
+
exports.usSocialSecurityNumber = /\b\d{3}[ -.]\d{2}[ -.]\d{4}\b/g;
|
|
148
|
+
exports.emailAddress = /([a-z0-9_\-.+]{1,64})@\w+(\.\w+)*/gi;
|
|
149
|
+
exports.username = /(user( ?name)?|login): \S+/gi;
|
|
150
|
+
exports.password = /(pass(word|phrase)?|secret): \S+/gi;
|
|
151
|
+
exports.credentials = /(login( cred(ential)?s| info(rmation)?)?|cred(ential)?s) ?:\s*\S+\s+\/?\s*\S+/gi;
|
|
152
|
+
exports.digits = /\b\d{4,}\b/g;
|
|
153
|
+
exports.url = /([^\s:/?#]{1,64}):\/\/([^/?#\s]*)([^?#\s]*)(\?([^#\s]*))?(#([^\s]*))?/g;
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
var require_utils = __commonJS({
|
|
157
|
+
"../redact-pii/dist/utils.js"(exports) {
|
|
158
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
159
|
+
exports.snakeCase = exports.isSyncRedactor = exports.isSimpleRegexpCustomRedactorConfig = void 0;
|
|
160
|
+
function isSimpleRegexpCustomRedactorConfig(redactor2) {
|
|
161
|
+
return typeof redactor2.regexpPattern !== "undefined";
|
|
162
|
+
}
|
|
163
|
+
exports.isSimpleRegexpCustomRedactorConfig = isSimpleRegexpCustomRedactorConfig;
|
|
164
|
+
function isSyncRedactor(redactor2) {
|
|
165
|
+
return typeof redactor2.redact === "function";
|
|
166
|
+
}
|
|
167
|
+
exports.isSyncRedactor = isSyncRedactor;
|
|
168
|
+
function snakeCase(input = "") {
|
|
169
|
+
var _a;
|
|
170
|
+
const words = (_a = input.match(/[A-Z]{2,}(?=[A-Z][a-z]|[0-9]|\b)|[A-Z]?[a-z]+|[A-Z]+|[0-9]+/g)) !== null && _a !== void 0 ? _a : [];
|
|
171
|
+
return words.map((word) => word.toLowerCase()).join("_");
|
|
172
|
+
}
|
|
173
|
+
exports.snakeCase = snakeCase;
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
var require_SimpleRegexpRedactor = __commonJS({
|
|
177
|
+
"../redact-pii/dist/built-ins/SimpleRegexpRedactor.js"(exports) {
|
|
178
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
179
|
+
exports.SimpleRegexpRedactor = void 0;
|
|
180
|
+
var utils_1 = require_utils();
|
|
181
|
+
var SimpleRegexpRedactor = class {
|
|
182
|
+
constructor({ replaceWith = (0, utils_1.snakeCase)().toUpperCase(), regexpPattern: regexpMatcher }) {
|
|
183
|
+
this.replaceWith = replaceWith;
|
|
184
|
+
this.regexpMatcher = regexpMatcher;
|
|
185
|
+
}
|
|
186
|
+
redact(textToRedact) {
|
|
187
|
+
return textToRedact.replace(this.regexpMatcher, this.replaceWith);
|
|
188
|
+
}
|
|
189
|
+
};
|
|
190
|
+
exports.SimpleRegexpRedactor = SimpleRegexpRedactor;
|
|
191
|
+
}
|
|
192
|
+
});
|
|
193
|
+
var require_composition = __commonJS({
|
|
194
|
+
"../redact-pii/dist/composition.js"(exports) {
|
|
195
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
196
|
+
exports.composeChildRedactors = void 0;
|
|
197
|
+
var NameRedactor_1 = require_NameRedactor();
|
|
198
|
+
var simpleRegexpBuiltIns = require_simple_regexp_patterns();
|
|
199
|
+
var SimpleRegexpRedactor_1 = require_SimpleRegexpRedactor();
|
|
200
|
+
var utils_1 = require_utils();
|
|
201
|
+
function normalizeCustomRedactorConfig(redactorConfig) {
|
|
202
|
+
return (0, utils_1.isSimpleRegexpCustomRedactorConfig)(redactorConfig) ? new SimpleRegexpRedactor_1.SimpleRegexpRedactor({
|
|
203
|
+
regexpPattern: redactorConfig.regexpPattern,
|
|
204
|
+
replaceWith: redactorConfig.replaceWith
|
|
205
|
+
}) : redactorConfig;
|
|
206
|
+
}
|
|
207
|
+
function composeChildRedactors(opts = {}) {
|
|
208
|
+
var _a, _b, _c, _d;
|
|
209
|
+
const childRedactors = [];
|
|
210
|
+
if (opts.customRedactors && opts.customRedactors.before) {
|
|
211
|
+
opts.customRedactors.before.map(normalizeCustomRedactorConfig).forEach((redactor2) => childRedactors.push(redactor2));
|
|
212
|
+
}
|
|
213
|
+
for (const regexpName of Object.keys(simpleRegexpBuiltIns)) {
|
|
214
|
+
if (!opts.builtInRedactors || !opts.builtInRedactors[regexpName] || opts.builtInRedactors[regexpName].enabled !== false) {
|
|
215
|
+
childRedactors.push(new SimpleRegexpRedactor_1.SimpleRegexpRedactor({
|
|
216
|
+
regexpPattern: simpleRegexpBuiltIns[regexpName],
|
|
217
|
+
replaceWith: ((_b = (_a = opts.builtInRedactors) === null || _a === void 0 ? void 0 : _a[regexpName]) === null || _b === void 0 ? void 0 : _b.replaceWith) || opts.globalReplaceWith || (0, utils_1.snakeCase)(regexpName).toUpperCase()
|
|
218
|
+
}));
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
if (!opts.builtInRedactors || !opts.builtInRedactors.names || opts.builtInRedactors.names.enabled !== false) {
|
|
222
|
+
childRedactors.push(new NameRedactor_1.NameRedactor(((_d = (_c = opts.builtInRedactors) === null || _c === void 0 ? void 0 : _c.names) === null || _d === void 0 ? void 0 : _d.replaceWith) || opts.globalReplaceWith));
|
|
223
|
+
}
|
|
224
|
+
if (opts.customRedactors && opts.customRedactors.after) {
|
|
225
|
+
opts.customRedactors.after.map(normalizeCustomRedactorConfig).forEach((redactor2) => childRedactors.push(redactor2));
|
|
226
|
+
}
|
|
227
|
+
return childRedactors;
|
|
228
|
+
}
|
|
229
|
+
exports.composeChildRedactors = composeChildRedactors;
|
|
230
|
+
}
|
|
231
|
+
});
|
|
232
|
+
var require_AsyncCompositeRedactor = __commonJS({
|
|
233
|
+
"../redact-pii/dist/AsyncCompositeRedactor.js"(exports) {
|
|
234
|
+
var __awaiter = exports && exports.__awaiter || function(thisArg, _arguments, P, generator) {
|
|
235
|
+
function adopt(value) {
|
|
236
|
+
return value instanceof P ? value : new P(function(resolve2) {
|
|
237
|
+
resolve2(value);
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
return new (P || (P = Promise))(function(resolve2, reject) {
|
|
241
|
+
function fulfilled(value) {
|
|
242
|
+
try {
|
|
243
|
+
step(generator.next(value));
|
|
244
|
+
} catch (e) {
|
|
245
|
+
reject(e);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
function rejected(value) {
|
|
249
|
+
try {
|
|
250
|
+
step(generator["throw"](value));
|
|
251
|
+
} catch (e) {
|
|
252
|
+
reject(e);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
function step(result) {
|
|
256
|
+
result.done ? resolve2(result.value) : adopt(result.value).then(fulfilled, rejected);
|
|
257
|
+
}
|
|
258
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
259
|
+
});
|
|
260
|
+
};
|
|
261
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
262
|
+
exports.AsyncCompositeRedactor = void 0;
|
|
263
|
+
var composition_1 = require_composition();
|
|
264
|
+
var utils_1 = require_utils();
|
|
265
|
+
var AsyncCompositeRedactor = class {
|
|
266
|
+
constructor(opts) {
|
|
267
|
+
this.childRedactors = [];
|
|
268
|
+
this.redactAsync = (textToRedact) => __awaiter(this, void 0, void 0, function* () {
|
|
269
|
+
for (const redactor2 of this.childRedactors) {
|
|
270
|
+
if ((0, utils_1.isSyncRedactor)(redactor2)) {
|
|
271
|
+
textToRedact = redactor2.redact(textToRedact);
|
|
272
|
+
} else {
|
|
273
|
+
textToRedact = yield redactor2.redactAsync(textToRedact);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
return textToRedact;
|
|
277
|
+
});
|
|
278
|
+
this.childRedactors = (0, composition_1.composeChildRedactors)(opts);
|
|
279
|
+
}
|
|
280
|
+
};
|
|
281
|
+
exports.AsyncCompositeRedactor = AsyncCompositeRedactor;
|
|
282
|
+
}
|
|
283
|
+
});
|
|
284
|
+
var require_SyncCompositeRedactor = __commonJS({
|
|
285
|
+
"../redact-pii/dist/SyncCompositeRedactor.js"(exports) {
|
|
286
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
287
|
+
exports.SyncCompositeRedactor = void 0;
|
|
288
|
+
var composition_1 = require_composition();
|
|
289
|
+
var SyncCompositeRedactor = class {
|
|
290
|
+
constructor(opts) {
|
|
291
|
+
this.childRedactors = [];
|
|
292
|
+
this.redact = (textToRedact) => {
|
|
293
|
+
for (const redactor2 of this.childRedactors) {
|
|
294
|
+
textToRedact = redactor2.redact(textToRedact);
|
|
295
|
+
}
|
|
296
|
+
return textToRedact;
|
|
297
|
+
};
|
|
298
|
+
this.childRedactors = (0, composition_1.composeChildRedactors)(opts);
|
|
299
|
+
}
|
|
300
|
+
};
|
|
301
|
+
exports.SyncCompositeRedactor = SyncCompositeRedactor;
|
|
302
|
+
}
|
|
303
|
+
});
|
|
304
|
+
var require_dist = __commonJS({
|
|
305
|
+
"../redact-pii/dist/index.js"(exports) {
|
|
306
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
307
|
+
exports.SyncRedactor = exports.AsyncRedactor = void 0;
|
|
308
|
+
var AsyncCompositeRedactor_1 = require_AsyncCompositeRedactor();
|
|
309
|
+
Object.defineProperty(exports, "AsyncRedactor", { enumerable: true, get: function() {
|
|
310
|
+
return AsyncCompositeRedactor_1.AsyncCompositeRedactor;
|
|
311
|
+
} });
|
|
312
|
+
var SyncCompositeRedactor_1 = require_SyncCompositeRedactor();
|
|
313
|
+
Object.defineProperty(exports, "SyncRedactor", { enumerable: true, get: function() {
|
|
314
|
+
return SyncCompositeRedactor_1.SyncCompositeRedactor;
|
|
315
|
+
} });
|
|
316
|
+
}
|
|
317
|
+
});
|
|
64
318
|
var STATE_KEY = /* @__PURE__ */ Symbol.for("raindrop.tracing.replayTraceRoutingState");
|
|
65
319
|
function state() {
|
|
66
320
|
const holder = globalThis;
|
|
67
321
|
let current = holder[STATE_KEY];
|
|
68
322
|
if (!current) {
|
|
69
|
-
let
|
|
323
|
+
let storage2 = null;
|
|
70
324
|
try {
|
|
71
325
|
const Ctor = globalThis.RAINDROP_ASYNC_LOCAL_STORAGE;
|
|
72
|
-
if (Ctor)
|
|
326
|
+
if (Ctor) storage2 = new Ctor();
|
|
73
327
|
} catch (e) {
|
|
74
|
-
|
|
328
|
+
storage2 = null;
|
|
75
329
|
}
|
|
76
330
|
current = {
|
|
77
|
-
storage,
|
|
331
|
+
storage: storage2,
|
|
78
332
|
syncDestination: void 0,
|
|
79
333
|
spanDestinations: /* @__PURE__ */ new WeakMap()
|
|
80
334
|
};
|
|
@@ -222,12 +476,12 @@ var NO_AMBIENT_ROUTING_BIND_WARNING = "[raindrop] This runtime's AsyncLocalStora
|
|
|
222
476
|
var ROUTING_STORAGE_KEY = /* @__PURE__ */ Symbol.for("raindrop.tracing.routingContextStorage");
|
|
223
477
|
function routingStorage() {
|
|
224
478
|
const holder = globalThis;
|
|
225
|
-
let
|
|
226
|
-
if (!
|
|
227
|
-
|
|
228
|
-
holder[ROUTING_STORAGE_KEY] =
|
|
479
|
+
let storage2 = holder[ROUTING_STORAGE_KEY];
|
|
480
|
+
if (!storage2) {
|
|
481
|
+
storage2 = new ContextStackStorage(NO_AMBIENT_ROUTING_BIND_WARNING);
|
|
482
|
+
holder[ROUTING_STORAGE_KEY] = storage2;
|
|
229
483
|
}
|
|
230
|
-
return
|
|
484
|
+
return storage2;
|
|
231
485
|
}
|
|
232
486
|
function currentRoutingBinding() {
|
|
233
487
|
const bound = routingStorage().current();
|
|
@@ -513,6 +767,14 @@ function appGitPropertiesFromAttributes(attributes) {
|
|
|
513
767
|
}
|
|
514
768
|
return properties;
|
|
515
769
|
}
|
|
770
|
+
function normalizeFeatureFlags(input) {
|
|
771
|
+
if (Array.isArray(input)) {
|
|
772
|
+
return Object.fromEntries(input.map((name) => [name, "true"]));
|
|
773
|
+
}
|
|
774
|
+
return Object.fromEntries(
|
|
775
|
+
Object.entries(input).map(([k, v]) => [k, String(v)])
|
|
776
|
+
);
|
|
777
|
+
}
|
|
516
778
|
function getCrypto() {
|
|
517
779
|
const c = globalThis.crypto;
|
|
518
780
|
return c;
|
|
@@ -614,11 +876,91 @@ function runWithTracingSuppressed(fn) {
|
|
|
614
876
|
return fn();
|
|
615
877
|
}
|
|
616
878
|
}
|
|
879
|
+
var MAX_QUOTED_ITEMS = 3;
|
|
880
|
+
function isRecord(value) {
|
|
881
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
882
|
+
}
|
|
883
|
+
function itemLabel(item) {
|
|
884
|
+
if (typeof item.event_id === "string" && item.event_id) return `event ${item.event_id}`;
|
|
885
|
+
if (typeof item.index === "number") return `item ${item.index}`;
|
|
886
|
+
return "item";
|
|
887
|
+
}
|
|
888
|
+
function describeRejected(item) {
|
|
889
|
+
const issues = Array.isArray(item.issues) ? item.issues : [];
|
|
890
|
+
const text = issues.filter(isRecord).map((issue) => {
|
|
891
|
+
const path = typeof issue.path === "string" && issue.path ? `${issue.path}: ` : "";
|
|
892
|
+
return `${path}${typeof issue.message === "string" ? issue.message : "invalid"}`;
|
|
893
|
+
}).join("; ");
|
|
894
|
+
return `${itemLabel(item)} (${text || "invalid"})`;
|
|
895
|
+
}
|
|
896
|
+
function describeWarning(item) {
|
|
897
|
+
if (typeof item.message === "string" && item.message) return `${itemLabel(item)}: ${item.message}`;
|
|
898
|
+
const fields = Array.isArray(item.fields) ? item.fields.filter((f) => typeof f === "string") : [];
|
|
899
|
+
return `${itemLabel(item)}: ignored ${fields.join(", ") || "input"}`;
|
|
900
|
+
}
|
|
901
|
+
function summarize(items, describe) {
|
|
902
|
+
const quoted = items.slice(0, MAX_QUOTED_ITEMS).map(describe).join(" | ");
|
|
903
|
+
const more = items.length > MAX_QUOTED_ITEMS ? ` (+${items.length - MAX_QUOTED_ITEMS} more)` : "";
|
|
904
|
+
return `${quoted}${more}`;
|
|
905
|
+
}
|
|
906
|
+
function reportIngestResponse(bodyText, prefix, opName) {
|
|
907
|
+
if (!bodyText) return;
|
|
908
|
+
let body;
|
|
909
|
+
try {
|
|
910
|
+
body = JSON.parse(bodyText);
|
|
911
|
+
} catch (e) {
|
|
912
|
+
return;
|
|
913
|
+
}
|
|
914
|
+
if (!isRecord(body)) return;
|
|
915
|
+
const rejected = Array.isArray(body.rejected) ? body.rejected.filter(isRecord) : [];
|
|
916
|
+
if (rejected.length > 0) {
|
|
917
|
+
rateLimitedLog(
|
|
918
|
+
`${prefix}.ingest_rejected`,
|
|
919
|
+
() => console.warn(
|
|
920
|
+
`${prefix} ${opName}: ingest rejected ${rejected.length} item(s), which were not stored: ${summarize(rejected, describeRejected)}`
|
|
921
|
+
)
|
|
922
|
+
);
|
|
923
|
+
}
|
|
924
|
+
const warnings = Array.isArray(body.warnings) ? body.warnings.filter(isRecord) : [];
|
|
925
|
+
if (warnings.length > 0) {
|
|
926
|
+
rateLimitedLog(
|
|
927
|
+
`${prefix}.ingest_warnings`,
|
|
928
|
+
() => console.warn(
|
|
929
|
+
`${prefix} ${opName}: ingest accepted ${warnings.length} item(s) with changes: ${summarize(warnings, describeWarning)}`
|
|
930
|
+
)
|
|
931
|
+
);
|
|
932
|
+
}
|
|
933
|
+
}
|
|
934
|
+
var DEFAULT_FLUSH_TIMEOUT_MS = 1e4;
|
|
617
935
|
var DEFAULT_REQUEST_TIMEOUT_MS = 3e4;
|
|
618
936
|
var MAX_RETRY_DELAY_MS = 3e4;
|
|
619
937
|
function wait(ms) {
|
|
620
938
|
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
621
939
|
}
|
|
940
|
+
function waitUnlessAborted(ms, signal) {
|
|
941
|
+
if (!signal) return wait(ms);
|
|
942
|
+
if (signal.aborted) return Promise.resolve();
|
|
943
|
+
return new Promise((resolve2) => {
|
|
944
|
+
const done = () => {
|
|
945
|
+
clearTimeout(timer);
|
|
946
|
+
signal.removeEventListener("abort", done);
|
|
947
|
+
resolve2();
|
|
948
|
+
};
|
|
949
|
+
const timer = setTimeout(done, ms);
|
|
950
|
+
signal.addEventListener("abort", done, { once: true });
|
|
951
|
+
});
|
|
952
|
+
}
|
|
953
|
+
function eitherSignal(a, b) {
|
|
954
|
+
if (!b) return a;
|
|
955
|
+
const any = AbortSignal.any;
|
|
956
|
+
if (typeof any === "function") return any([a, b]);
|
|
957
|
+
const controller = new AbortController();
|
|
958
|
+
const abort = () => controller.abort();
|
|
959
|
+
if (a.aborted || b.aborted) abort();
|
|
960
|
+
a.addEventListener("abort", abort, { once: true });
|
|
961
|
+
b.addEventListener("abort", abort, { once: true });
|
|
962
|
+
return controller.signal;
|
|
963
|
+
}
|
|
622
964
|
function formatEndpoint(endpoint) {
|
|
623
965
|
if (!endpoint) return void 0;
|
|
624
966
|
return endpoint.endsWith("/") ? endpoint : `${endpoint}/`;
|
|
@@ -663,6 +1005,26 @@ async function raceWithTimeout(promise, timeoutMs) {
|
|
|
663
1005
|
if (timer) clearTimeout(timer);
|
|
664
1006
|
return settledInTime;
|
|
665
1007
|
}
|
|
1008
|
+
var InFlightCutOff = class {
|
|
1009
|
+
constructor() {
|
|
1010
|
+
this.controller = new AbortController();
|
|
1011
|
+
}
|
|
1012
|
+
get signal() {
|
|
1013
|
+
return this.controller.signal;
|
|
1014
|
+
}
|
|
1015
|
+
cut() {
|
|
1016
|
+
this.controller.abort();
|
|
1017
|
+
this.controller = new AbortController();
|
|
1018
|
+
}
|
|
1019
|
+
};
|
|
1020
|
+
async function awaitEarlierSends(earlier, deadlineAt, cutOff, isRunning) {
|
|
1021
|
+
if (earlier.length === 0) return { settled: true, stillRunning: 0 };
|
|
1022
|
+
const settled = await raceWithTimeout(Promise.allSettled(earlier), deadlineAt - Date.now());
|
|
1023
|
+
if (settled) return { settled, stillRunning: 0 };
|
|
1024
|
+
const stillRunning = earlier.filter(isRunning).length;
|
|
1025
|
+
if (stillRunning > 0) cutOff.cut();
|
|
1026
|
+
return { settled: stillRunning === 0, stillRunning };
|
|
1027
|
+
}
|
|
666
1028
|
function parseRetryAfter(headers) {
|
|
667
1029
|
var _a;
|
|
668
1030
|
const value = (_a = headers.get("Retry-After")) != null ? _a : headers.get("retry-after");
|
|
@@ -686,45 +1048,80 @@ function getRetryDelayMs(attemptNumber, previousError) {
|
|
|
686
1048
|
const factor = Math.pow(2, attemptNumber - 2);
|
|
687
1049
|
return Math.min(base * factor, MAX_RETRY_DELAY_MS);
|
|
688
1050
|
}
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
if (opts.debug) {
|
|
696
|
-
console.warn(
|
|
697
|
-
`${prefix} ${opName} retry ${attemptNumber}/${opts.maxAttempts} in ${delay}ms`
|
|
698
|
-
);
|
|
699
|
-
}
|
|
700
|
-
if (delay > 0) await wait(delay);
|
|
701
|
-
} else if (opts.debug) {
|
|
702
|
-
console.log(`${prefix} ${opName} attempt ${attemptNumber}/${opts.maxAttempts}`);
|
|
703
|
-
}
|
|
704
|
-
try {
|
|
705
|
-
return await operation();
|
|
706
|
-
} catch (err) {
|
|
707
|
-
lastError = err;
|
|
708
|
-
if (opts.debug) {
|
|
709
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
710
|
-
console.warn(
|
|
711
|
-
`${prefix} ${opName} attempt ${attemptNumber} failed: ${msg}${attemptNumber === opts.maxAttempts ? " (no more retries)" : ""}`
|
|
712
|
-
);
|
|
713
|
-
}
|
|
714
|
-
if (lastError && typeof lastError === "object" && "retryable" in lastError && !lastError.retryable)
|
|
715
|
-
break;
|
|
716
|
-
if (attemptNumber === opts.maxAttempts) break;
|
|
717
|
-
}
|
|
1051
|
+
var sendPausedUntil = /* @__PURE__ */ new Map();
|
|
1052
|
+
function originOf(url) {
|
|
1053
|
+
try {
|
|
1054
|
+
return new URL(url).origin;
|
|
1055
|
+
} catch (e) {
|
|
1056
|
+
return url;
|
|
718
1057
|
}
|
|
719
|
-
|
|
1058
|
+
}
|
|
1059
|
+
function noteSendPause(url, status, retryAfterMs) {
|
|
1060
|
+
var _a;
|
|
1061
|
+
if (status !== 429 && status !== 503 || typeof retryAfterMs !== "number") return;
|
|
1062
|
+
const until = Date.now() + Math.min(Math.max(0, retryAfterMs), MAX_RETRY_DELAY_MS);
|
|
1063
|
+
const origin = originOf(url);
|
|
1064
|
+
sendPausedUntil.set(origin, Math.max((_a = sendPausedUntil.get(origin)) != null ? _a : 0, until));
|
|
1065
|
+
}
|
|
1066
|
+
function pausedUntil(url) {
|
|
1067
|
+
const until = sendPausedUntil.get(originOf(url));
|
|
1068
|
+
if (until === void 0) return void 0;
|
|
1069
|
+
if (until <= Date.now()) {
|
|
1070
|
+
sendPausedUntil.delete(originOf(url));
|
|
1071
|
+
return void 0;
|
|
1072
|
+
}
|
|
1073
|
+
return Math.min(until, Date.now() + MAX_RETRY_DELAY_MS);
|
|
1074
|
+
}
|
|
1075
|
+
function prefixFor(opts) {
|
|
1076
|
+
return opts.sdkName ? `[raindrop-ai/${opts.sdkName}]` : "[raindrop-ai/core]";
|
|
720
1077
|
}
|
|
721
1078
|
async function postJson(url, body, headers, opts) {
|
|
1079
|
+
var _a;
|
|
1080
|
+
const outcome = await sendJson(url, body, headers, { ...opts, deadlineAt: void 0 });
|
|
1081
|
+
if (outcome.status === "delivered") return;
|
|
1082
|
+
throw (_a = outcome.error) != null ? _a : new Error(`${redactUrlForLog(url)}: not sent (${outcome.status})`);
|
|
1083
|
+
}
|
|
1084
|
+
async function sendJson(url, body, headers, opts) {
|
|
722
1085
|
var _a;
|
|
723
1086
|
const opName = `POST ${redactUrlForLog(url)}`;
|
|
1087
|
+
const prefix = prefixFor(opts);
|
|
724
1088
|
const timeoutMs = (_a = opts.timeoutMs) != null ? _a : DEFAULT_REQUEST_TIMEOUT_MS;
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
1089
|
+
const deadlineAt = opts.deadlineAt;
|
|
1090
|
+
const remaining = () => deadlineAt === void 0 ? Infinity : deadlineAt - Date.now();
|
|
1091
|
+
let lastError;
|
|
1092
|
+
const cutOff = opts.cutOff;
|
|
1093
|
+
for (let attempt = 1; attempt <= opts.maxAttempts; attempt++) {
|
|
1094
|
+
if (cutOff == null ? void 0 : cutOff.aborted) return { status: "deferred", error: lastError };
|
|
1095
|
+
if (attempt > 1) {
|
|
1096
|
+
const delay = getRetryDelayMs(attempt, lastError);
|
|
1097
|
+
if (delay >= remaining()) {
|
|
1098
|
+
return { status: "deferred", retryAtMs: Date.now() + delay, error: lastError };
|
|
1099
|
+
}
|
|
1100
|
+
if (opts.debug) {
|
|
1101
|
+
console.warn(`${prefix} ${opName} retry ${attempt}/${opts.maxAttempts} in ${delay}ms`);
|
|
1102
|
+
}
|
|
1103
|
+
if (delay > 0) await waitUnlessAborted(delay, cutOff);
|
|
1104
|
+
if (cutOff == null ? void 0 : cutOff.aborted) return { status: "deferred", error: lastError };
|
|
1105
|
+
} else if (opts.debug) {
|
|
1106
|
+
console.log(`${prefix} ${opName} attempt ${attempt}/${opts.maxAttempts}`);
|
|
1107
|
+
}
|
|
1108
|
+
const pauseEnd = pausedUntil(url);
|
|
1109
|
+
if (pauseEnd !== void 0) {
|
|
1110
|
+
if (deadlineAt !== void 0 && pauseEnd >= deadlineAt) {
|
|
1111
|
+
return { status: "deferred", retryAtMs: pauseEnd, error: lastError };
|
|
1112
|
+
}
|
|
1113
|
+
await waitUnlessAborted(Math.max(0, pauseEnd - Date.now()), cutOff);
|
|
1114
|
+
if (cutOff == null ? void 0 : cutOff.aborted) return { status: "deferred", retryAtMs: pauseEnd, error: lastError };
|
|
1115
|
+
}
|
|
1116
|
+
const left = remaining();
|
|
1117
|
+
if (left <= 0) return { status: "deferred", error: lastError };
|
|
1118
|
+
const attemptTimeoutMs = Math.min(timeoutMs, left);
|
|
1119
|
+
const clampedByDeadline = attemptTimeoutMs < timeoutMs;
|
|
1120
|
+
const timeoutSignal = AbortSignal.timeout(attemptTimeoutMs);
|
|
1121
|
+
const signal = eitherSignal(timeoutSignal, cutOff);
|
|
1122
|
+
let resp;
|
|
1123
|
+
try {
|
|
1124
|
+
resp = await runWithTracingSuppressed(
|
|
728
1125
|
() => fetch(url, {
|
|
729
1126
|
method: "POST",
|
|
730
1127
|
redirect: headers["X-Raindrop-Replay-Id"] !== void 0 ? "error" : "follow",
|
|
@@ -733,24 +1130,98 @@ async function postJson(url, body, headers, opts) {
|
|
|
733
1130
|
...headers
|
|
734
1131
|
},
|
|
735
1132
|
body: JSON.stringify(body),
|
|
736
|
-
signal
|
|
1133
|
+
signal
|
|
737
1134
|
})
|
|
738
1135
|
);
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
);
|
|
744
|
-
const retryAfterMs = parseRetryAfter(resp.headers);
|
|
745
|
-
if (typeof retryAfterMs === "number") err.retryAfterMs = retryAfterMs;
|
|
746
|
-
err.retryable = resp.status === 429 || resp.status >= 500;
|
|
747
|
-
throw err;
|
|
1136
|
+
} catch (err) {
|
|
1137
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
1138
|
+
if ((cutOff == null ? void 0 : cutOff.aborted) || timeoutSignal.aborted && clampedByDeadline) {
|
|
1139
|
+
return { status: "cut_off", error };
|
|
748
1140
|
}
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
1141
|
+
lastError = error;
|
|
1142
|
+
logAttemptFailure(opts, prefix, opName, attempt, error);
|
|
1143
|
+
continue;
|
|
1144
|
+
}
|
|
1145
|
+
if (!resp.ok) {
|
|
1146
|
+
const text = await resp.text().catch(() => "");
|
|
1147
|
+
const error = new Error(
|
|
1148
|
+
`HTTP ${resp.status} ${resp.statusText}${text ? `: ${text}` : ""}`
|
|
1149
|
+
);
|
|
1150
|
+
const retryAfterMs = parseRetryAfter(resp.headers);
|
|
1151
|
+
if (typeof retryAfterMs === "number") error.retryAfterMs = retryAfterMs;
|
|
1152
|
+
noteSendPause(url, resp.status, retryAfterMs);
|
|
1153
|
+
error.retryable = resp.status === 408 || resp.status === 429 || resp.status >= 500;
|
|
1154
|
+
if (!error.retryable) return { status: "rejected", error };
|
|
1155
|
+
lastError = error;
|
|
1156
|
+
logAttemptFailure(opts, prefix, opName, attempt, error);
|
|
1157
|
+
continue;
|
|
1158
|
+
}
|
|
1159
|
+
try {
|
|
1160
|
+
reportIngestResponse(await resp.text(), prefix, opName);
|
|
1161
|
+
} catch (e) {
|
|
1162
|
+
}
|
|
1163
|
+
return { status: "delivered" };
|
|
1164
|
+
}
|
|
1165
|
+
return { status: "failed", error: lastError != null ? lastError : new Error(`${opName}: no attempts`) };
|
|
1166
|
+
}
|
|
1167
|
+
function logAttemptFailure(opts, prefix, opName, attempt, error) {
|
|
1168
|
+
if (!opts.debug) return;
|
|
1169
|
+
console.warn(
|
|
1170
|
+
`${prefix} ${opName} attempt ${attempt} failed: ${error.message}${attempt === opts.maxAttempts ? " (no more retries)" : ""}`
|
|
1171
|
+
);
|
|
1172
|
+
}
|
|
1173
|
+
function asCompat(result) {
|
|
1174
|
+
return result;
|
|
1175
|
+
}
|
|
1176
|
+
var DELIVERED = Object.freeze({
|
|
1177
|
+
delivered: true,
|
|
1178
|
+
timedOut: false,
|
|
1179
|
+
dropped: 0,
|
|
1180
|
+
queued: 0,
|
|
1181
|
+
inFlight: 0
|
|
1182
|
+
});
|
|
1183
|
+
function fateOf(outcome, shuttingDown) {
|
|
1184
|
+
switch (outcome.status) {
|
|
1185
|
+
case "delivered":
|
|
1186
|
+
case "rejected":
|
|
1187
|
+
return "delivered";
|
|
1188
|
+
case "deferred":
|
|
1189
|
+
return shuttingDown ? "dropped" : "queued";
|
|
1190
|
+
default:
|
|
1191
|
+
return "dropped";
|
|
1192
|
+
}
|
|
1193
|
+
}
|
|
1194
|
+
function summarize2(fates, inFlight, timedOut) {
|
|
1195
|
+
const dropped = fates.filter((fate) => fate === "dropped").length;
|
|
1196
|
+
const queued = fates.filter((fate) => fate === "queued").length;
|
|
1197
|
+
return {
|
|
1198
|
+
delivered: dropped === 0 && queued === 0 && inFlight === 0,
|
|
1199
|
+
timedOut: timedOut || queued > 0 || inFlight > 0,
|
|
1200
|
+
dropped,
|
|
1201
|
+
queued,
|
|
1202
|
+
inFlight
|
|
1203
|
+
};
|
|
1204
|
+
}
|
|
1205
|
+
function combineResults(...results) {
|
|
1206
|
+
return results.reduce(
|
|
1207
|
+
(acc, r) => ({
|
|
1208
|
+
delivered: acc.delivered && r.delivered,
|
|
1209
|
+
timedOut: acc.timedOut || r.timedOut,
|
|
1210
|
+
dropped: acc.dropped + r.dropped,
|
|
1211
|
+
queued: acc.queued + r.queued,
|
|
1212
|
+
inFlight: acc.inFlight + r.inFlight
|
|
1213
|
+
}),
|
|
1214
|
+
{ ...DELIVERED }
|
|
752
1215
|
);
|
|
753
1216
|
}
|
|
1217
|
+
function describeUndelivered(what, result) {
|
|
1218
|
+
const parts = [
|
|
1219
|
+
result.dropped > 0 ? `${result.dropped} dropped` : "",
|
|
1220
|
+
result.queued > 0 ? `${result.queued} still queued` : "",
|
|
1221
|
+
result.inFlight > 0 ? `${result.inFlight} still sending` : ""
|
|
1222
|
+
].filter(Boolean);
|
|
1223
|
+
return `${what} returned before everything was delivered: ${parts.join(", ")}`;
|
|
1224
|
+
}
|
|
754
1225
|
var DEFAULT_MAX_TEXT_FIELD_CHARS = 1e6;
|
|
755
1226
|
var TRUNCATION_MARKER = "...[truncated by raindrop]";
|
|
756
1227
|
var BOUNDED_CLONE_MAX_DEPTH = 12;
|
|
@@ -1017,7 +1488,245 @@ function normalizeProjectId(raw, opts) {
|
|
|
1017
1488
|
function projectIdHeaders(projectId) {
|
|
1018
1489
|
return projectId ? { [PROJECT_ID_HEADER]: projectId } : {};
|
|
1019
1490
|
}
|
|
1020
|
-
var
|
|
1491
|
+
var import_redact_pii = __toESM(require_dist(), 1);
|
|
1492
|
+
var DEFAULT_PII_REDACTION_OPTIONS = {
|
|
1493
|
+
builtInRedactors: {
|
|
1494
|
+
credentials: { replaceWith: "<REDACTED CREDENTIALS>" },
|
|
1495
|
+
creditCardNumber: { replaceWith: "<REDACTED CREDIT CARD NUMBER>" },
|
|
1496
|
+
// Any run of 4+ digits: too broad.
|
|
1497
|
+
digits: { enabled: false },
|
|
1498
|
+
emailAddress: { replaceWith: "<REDACTED EMAIL>" },
|
|
1499
|
+
ipAddress: { enabled: false },
|
|
1500
|
+
names: { enabled: false },
|
|
1501
|
+
// Matches (pass(word|phrase)|secret): \S+
|
|
1502
|
+
password: { replaceWith: "<REDACTED SECRET>" },
|
|
1503
|
+
phoneNumber: { replaceWith: "<REDACTED PHONE NUMBER>" },
|
|
1504
|
+
streetAddress: { replaceWith: "<REDACTED ADDRESS>" },
|
|
1505
|
+
url: { enabled: false },
|
|
1506
|
+
username: { enabled: false },
|
|
1507
|
+
usSocialSecurityNumber: { replaceWith: "<REDACTED SOCIAL SECURITY NUMBER>" },
|
|
1508
|
+
zipcode: { enabled: false }
|
|
1509
|
+
}
|
|
1510
|
+
};
|
|
1511
|
+
var redactor;
|
|
1512
|
+
function redactPiiText(text) {
|
|
1513
|
+
redactor != null ? redactor : redactor = new import_redact_pii.SyncRedactor(DEFAULT_PII_REDACTION_OPTIONS);
|
|
1514
|
+
return redactor.redact(text);
|
|
1515
|
+
}
|
|
1516
|
+
var KINDS = ["event", "signal", "identify"];
|
|
1517
|
+
var DEFAULT_PII_FIELDS = {
|
|
1518
|
+
event: ["ai_data.input", "ai_data.output"],
|
|
1519
|
+
signal: [],
|
|
1520
|
+
identify: []
|
|
1521
|
+
};
|
|
1522
|
+
var PROTECTED_LOCATIONS = new Set(
|
|
1523
|
+
[
|
|
1524
|
+
["event_id"],
|
|
1525
|
+
["user_id"],
|
|
1526
|
+
["ai_data", "convo_id"],
|
|
1527
|
+
["event"],
|
|
1528
|
+
["timestamp"],
|
|
1529
|
+
["is_pending"],
|
|
1530
|
+
["signal_name"],
|
|
1531
|
+
["signal_type"]
|
|
1532
|
+
].map((keys) => JSON.stringify(keys))
|
|
1533
|
+
);
|
|
1534
|
+
var SIGNAL_PATH_ALIASES = {
|
|
1535
|
+
comment: "properties.comment",
|
|
1536
|
+
after: "properties.after"
|
|
1537
|
+
};
|
|
1538
|
+
function parsePiiFieldPath(path) {
|
|
1539
|
+
if (typeof path !== "string") return null;
|
|
1540
|
+
const segments = [];
|
|
1541
|
+
let i = 0;
|
|
1542
|
+
const n = path.length;
|
|
1543
|
+
let expectSeparator = false;
|
|
1544
|
+
while (i < n) {
|
|
1545
|
+
const ch = path[i];
|
|
1546
|
+
if (ch === "[") {
|
|
1547
|
+
const close = path.indexOf("]", i);
|
|
1548
|
+
if (path[i + 1] === '"') {
|
|
1549
|
+
let j2 = i + 2;
|
|
1550
|
+
let key = "";
|
|
1551
|
+
while (j2 < n && path[j2] !== '"') {
|
|
1552
|
+
if (path[j2] === "\\" && j2 + 1 < n) {
|
|
1553
|
+
key += path[j2 + 1];
|
|
1554
|
+
j2 += 2;
|
|
1555
|
+
} else {
|
|
1556
|
+
key += path[j2];
|
|
1557
|
+
j2 += 1;
|
|
1558
|
+
}
|
|
1559
|
+
}
|
|
1560
|
+
if (j2 >= n || path[j2 + 1] !== "]" || key === "") return null;
|
|
1561
|
+
segments.push({ kind: "key", key });
|
|
1562
|
+
i = j2 + 2;
|
|
1563
|
+
} else {
|
|
1564
|
+
if (close === -1) return null;
|
|
1565
|
+
const inner = path.slice(i + 1, close);
|
|
1566
|
+
if (inner === "") segments.push({ kind: "every" });
|
|
1567
|
+
else if (/^(0|[1-9]\d*)$/.test(inner))
|
|
1568
|
+
segments.push({ kind: "index", index: Number(inner) });
|
|
1569
|
+
else return null;
|
|
1570
|
+
i = close + 1;
|
|
1571
|
+
}
|
|
1572
|
+
expectSeparator = true;
|
|
1573
|
+
continue;
|
|
1574
|
+
}
|
|
1575
|
+
if (ch === ".") {
|
|
1576
|
+
if (!expectSeparator) return null;
|
|
1577
|
+
i += 1;
|
|
1578
|
+
expectSeparator = false;
|
|
1579
|
+
if (i >= n || path[i] === ".") return null;
|
|
1580
|
+
continue;
|
|
1581
|
+
}
|
|
1582
|
+
if (expectSeparator) return null;
|
|
1583
|
+
let j = i;
|
|
1584
|
+
while (j < n && path[j] !== "." && path[j] !== "[") j += 1;
|
|
1585
|
+
const token = path.slice(i, j);
|
|
1586
|
+
if (token === "*") segments.push({ kind: "any_key" });
|
|
1587
|
+
else if (token === "" || /[\]*"\s]/.test(token)) return null;
|
|
1588
|
+
else segments.push({ kind: "key", key: token });
|
|
1589
|
+
i = j;
|
|
1590
|
+
expectSeparator = true;
|
|
1591
|
+
}
|
|
1592
|
+
return segments.length > 0 && expectSeparator ? segments : null;
|
|
1593
|
+
}
|
|
1594
|
+
function mergePiiFieldMaps(...maps) {
|
|
1595
|
+
const out = { event: [], signal: [], identify: [] };
|
|
1596
|
+
for (const kind of KINDS) {
|
|
1597
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1598
|
+
for (const map of maps) {
|
|
1599
|
+
const paths = map == null ? void 0 : map[kind];
|
|
1600
|
+
if (!Array.isArray(paths)) continue;
|
|
1601
|
+
for (const path of paths) {
|
|
1602
|
+
if (typeof path !== "string" || seen.has(path)) continue;
|
|
1603
|
+
seen.add(path);
|
|
1604
|
+
out[kind].push(path);
|
|
1605
|
+
}
|
|
1606
|
+
}
|
|
1607
|
+
}
|
|
1608
|
+
return out;
|
|
1609
|
+
}
|
|
1610
|
+
function isPlainObject(value) {
|
|
1611
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) return false;
|
|
1612
|
+
const proto = Object.getPrototypeOf(value);
|
|
1613
|
+
return proto === Object.prototype || proto === null;
|
|
1614
|
+
}
|
|
1615
|
+
function isProtected(location) {
|
|
1616
|
+
return PROTECTED_LOCATIONS.has(JSON.stringify(location));
|
|
1617
|
+
}
|
|
1618
|
+
function redactAll(value, location) {
|
|
1619
|
+
if (location !== null && isProtected(location)) return value;
|
|
1620
|
+
if (typeof value === "string") return redactPiiText(value);
|
|
1621
|
+
if (Array.isArray(value)) return value.map((item) => redactAll(item, null));
|
|
1622
|
+
if (isPlainObject(value)) {
|
|
1623
|
+
const out = {};
|
|
1624
|
+
for (const [key, child] of Object.entries(value)) {
|
|
1625
|
+
out[key] = redactAll(child, location === null ? null : [...location, key]);
|
|
1626
|
+
}
|
|
1627
|
+
return out;
|
|
1628
|
+
}
|
|
1629
|
+
return value;
|
|
1630
|
+
}
|
|
1631
|
+
function applyPath(value, segments, location) {
|
|
1632
|
+
if (segments.length === 0) return redactAll(value, location);
|
|
1633
|
+
const [head, ...rest] = segments;
|
|
1634
|
+
if (head.kind === "key" || head.kind === "any_key") {
|
|
1635
|
+
if (!isPlainObject(value)) return value;
|
|
1636
|
+
const keys = head.kind === "key" ? [head.key] : Object.keys(value);
|
|
1637
|
+
let out2;
|
|
1638
|
+
for (const key of keys) {
|
|
1639
|
+
if (!Object.prototype.hasOwnProperty.call(value, key)) continue;
|
|
1640
|
+
const child = value[key];
|
|
1641
|
+
const next = applyPath(child, rest, location === null ? null : [...location, key]);
|
|
1642
|
+
if (next !== child) {
|
|
1643
|
+
out2 != null ? out2 : out2 = { ...value };
|
|
1644
|
+
out2[key] = next;
|
|
1645
|
+
}
|
|
1646
|
+
}
|
|
1647
|
+
return out2 != null ? out2 : value;
|
|
1648
|
+
}
|
|
1649
|
+
if (!Array.isArray(value)) return value;
|
|
1650
|
+
const indices = head.kind === "index" ? head.index < value.length ? [head.index] : [] : value.keys();
|
|
1651
|
+
let out;
|
|
1652
|
+
for (const index of indices) {
|
|
1653
|
+
const child = value[index];
|
|
1654
|
+
const next = applyPath(child, rest, null);
|
|
1655
|
+
if (next !== child) {
|
|
1656
|
+
out != null ? out : out = [...value];
|
|
1657
|
+
out[index] = next;
|
|
1658
|
+
}
|
|
1659
|
+
}
|
|
1660
|
+
return out != null ? out : value;
|
|
1661
|
+
}
|
|
1662
|
+
var PiiFieldRedactor = class {
|
|
1663
|
+
constructor(options = {}) {
|
|
1664
|
+
var _a;
|
|
1665
|
+
this.startupMap = options.startupFieldMap;
|
|
1666
|
+
this.prefix = (_a = options.logPrefix) != null ? _a : "[raindrop-ai/core]";
|
|
1667
|
+
}
|
|
1668
|
+
/** Replace the server-provided layer (CONTRACT 11.2). Additive: it can only add fields. */
|
|
1669
|
+
setServerFieldMap(map) {
|
|
1670
|
+
this.serverMap = map;
|
|
1671
|
+
this.compiled = void 0;
|
|
1672
|
+
}
|
|
1673
|
+
/** The paths in effect for a kind, defaults first. */
|
|
1674
|
+
effectivePaths(kind) {
|
|
1675
|
+
return mergePiiFieldMaps(DEFAULT_PII_FIELDS, this.startupMap, this.serverMap)[kind];
|
|
1676
|
+
}
|
|
1677
|
+
compile() {
|
|
1678
|
+
if (this.compiled) return this.compiled;
|
|
1679
|
+
const out = { event: [], signal: [], identify: [] };
|
|
1680
|
+
for (const kind of KINDS) {
|
|
1681
|
+
for (const path of this.effectivePaths(kind)) {
|
|
1682
|
+
const variants = [path];
|
|
1683
|
+
if (kind === "signal" && SIGNAL_PATH_ALIASES[path])
|
|
1684
|
+
variants.push(SIGNAL_PATH_ALIASES[path]);
|
|
1685
|
+
for (const variant of variants) {
|
|
1686
|
+
const segments = parsePiiFieldPath(variant);
|
|
1687
|
+
if (segments) {
|
|
1688
|
+
out[kind].push(segments);
|
|
1689
|
+
} else {
|
|
1690
|
+
rateLimitedLog(
|
|
1691
|
+
`${this.prefix}.pii_field_path_invalid`,
|
|
1692
|
+
() => console.warn(
|
|
1693
|
+
`${this.prefix} redactPiiFields: ignoring invalid ${kind} path ${JSON.stringify(variant)}`
|
|
1694
|
+
)
|
|
1695
|
+
);
|
|
1696
|
+
}
|
|
1697
|
+
}
|
|
1698
|
+
}
|
|
1699
|
+
}
|
|
1700
|
+
this.compiled = out;
|
|
1701
|
+
return out;
|
|
1702
|
+
}
|
|
1703
|
+
/** The payload with every selected field redacted (a copy where changed). */
|
|
1704
|
+
redact(kind, payload) {
|
|
1705
|
+
let out = payload;
|
|
1706
|
+
for (const segments of this.compile()[kind]) out = applyPath(out, segments, []);
|
|
1707
|
+
return out;
|
|
1708
|
+
}
|
|
1709
|
+
};
|
|
1710
|
+
function detectRuntime() {
|
|
1711
|
+
if (typeof process === "object" && process && typeof process.env === "object" && process.env && typeof process.version === "string") {
|
|
1712
|
+
return "node";
|
|
1713
|
+
}
|
|
1714
|
+
if (typeof window === "object") return "browser";
|
|
1715
|
+
if (typeof WebSocketPair !== "undefined") return "cloudflare-worker";
|
|
1716
|
+
if (typeof EdgeRuntime === "string") return "vercel-edge";
|
|
1717
|
+
if (typeof WorkerGlobalScope !== "undefined" && typeof importScripts === "function") {
|
|
1718
|
+
return "web-worker";
|
|
1719
|
+
}
|
|
1720
|
+
return "unknown";
|
|
1721
|
+
}
|
|
1722
|
+
var PLACEHOLDER_USER_IDS = /* @__PURE__ */ new Set(["null", "undefined"]);
|
|
1723
|
+
function isMissingUserId(value) {
|
|
1724
|
+
if (value === void 0 || value === null) return true;
|
|
1725
|
+
if (typeof value !== "string") return false;
|
|
1726
|
+
const trimmed = value.trim();
|
|
1727
|
+
return trimmed === "" || PLACEHOLDER_USER_IDS.has(trimmed);
|
|
1728
|
+
}
|
|
1729
|
+
var MAX_DEFERRED_SENDS = 1e3;
|
|
1021
1730
|
var POST_SHUTDOWN_TIMEOUT_MS = 5e3;
|
|
1022
1731
|
function appGitOwnerId(prefix) {
|
|
1023
1732
|
try {
|
|
@@ -1026,18 +1735,52 @@ function appGitOwnerId(prefix) {
|
|
|
1026
1735
|
return `${prefix}:${Date.now().toString(36)}:${Math.random().toString(36).slice(2)}`;
|
|
1027
1736
|
}
|
|
1028
1737
|
}
|
|
1738
|
+
function earliestIsoTimestamp(...values) {
|
|
1739
|
+
let earliest;
|
|
1740
|
+
for (const value of values) {
|
|
1741
|
+
if (value === void 0) continue;
|
|
1742
|
+
const date = new Date(value);
|
|
1743
|
+
if (Number.isNaN(date.getTime())) continue;
|
|
1744
|
+
if (earliest === void 0 || date < earliest) earliest = date;
|
|
1745
|
+
}
|
|
1746
|
+
return earliest == null ? void 0 : earliest.toISOString();
|
|
1747
|
+
}
|
|
1748
|
+
function isPlainObject2(value) {
|
|
1749
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) return false;
|
|
1750
|
+
const proto = Object.getPrototypeOf(value);
|
|
1751
|
+
return proto === Object.prototype || proto === null;
|
|
1752
|
+
}
|
|
1753
|
+
var UNSAFE_MERGE_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
1754
|
+
function deepMergeProperties(target, source) {
|
|
1755
|
+
const out = { ...target };
|
|
1756
|
+
for (const [key, value] of Object.entries(source)) {
|
|
1757
|
+
if (value === void 0 || UNSAFE_MERGE_KEYS.has(key)) continue;
|
|
1758
|
+
const existing = out[key];
|
|
1759
|
+
out[key] = isPlainObject2(existing) && isPlainObject2(value) ? deepMergeProperties(existing, value) : value;
|
|
1760
|
+
}
|
|
1761
|
+
return out;
|
|
1762
|
+
}
|
|
1029
1763
|
function mergePatches(target, source) {
|
|
1030
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _i;
|
|
1031
|
-
const
|
|
1764
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
|
|
1765
|
+
const defined2 = Object.fromEntries(
|
|
1766
|
+
Object.entries(source).filter(([, value]) => value !== void 0)
|
|
1767
|
+
);
|
|
1768
|
+
const out = { ...target, ...defined2 };
|
|
1032
1769
|
if (target.properties || source.properties) {
|
|
1033
|
-
out.properties =
|
|
1770
|
+
out.properties = deepMergeProperties((_a = target.properties) != null ? _a : {}, (_b = source.properties) != null ? _b : {});
|
|
1771
|
+
}
|
|
1772
|
+
if (target.callerProperties || source.callerProperties) {
|
|
1773
|
+
out.callerProperties = deepMergeProperties(
|
|
1774
|
+
(_c = target.callerProperties) != null ? _c : {},
|
|
1775
|
+
(_d = source.callerProperties) != null ? _d : {}
|
|
1776
|
+
);
|
|
1034
1777
|
}
|
|
1035
1778
|
if (target.usage || source.usage) {
|
|
1036
|
-
out.usage = { ...(
|
|
1037
|
-
if (((
|
|
1779
|
+
out.usage = { ...(_e = target.usage) != null ? _e : {} };
|
|
1780
|
+
if (((_f = source.usage) == null ? void 0 : _f.promptTokens) !== void 0) {
|
|
1038
1781
|
out.usage.promptTokens = source.usage.promptTokens;
|
|
1039
1782
|
}
|
|
1040
|
-
if (((
|
|
1783
|
+
if (((_g = source.usage) == null ? void 0 : _g.completionTokens) !== void 0) {
|
|
1041
1784
|
out.usage.completionTokens = source.usage.completionTokens;
|
|
1042
1785
|
}
|
|
1043
1786
|
}
|
|
@@ -1045,10 +1788,10 @@ function mergePatches(target, source) {
|
|
|
1045
1788
|
out.error = target.error;
|
|
1046
1789
|
}
|
|
1047
1790
|
if (target.featureFlags || source.featureFlags) {
|
|
1048
|
-
out.featureFlags = { ...(
|
|
1791
|
+
out.featureFlags = { ...(_h = target.featureFlags) != null ? _h : {}, ...(_i = source.featureFlags) != null ? _i : {} };
|
|
1049
1792
|
}
|
|
1050
1793
|
if (target.attachments || source.attachments) {
|
|
1051
|
-
out.attachments = [...(
|
|
1794
|
+
out.attachments = [...(_j = target.attachments) != null ? _j : [], ...(_k = source.attachments) != null ? _k : []];
|
|
1052
1795
|
}
|
|
1053
1796
|
return out;
|
|
1054
1797
|
}
|
|
@@ -1073,6 +1816,15 @@ function eventTelemetryProperties(patch) {
|
|
|
1073
1816
|
}
|
|
1074
1817
|
return properties;
|
|
1075
1818
|
}
|
|
1819
|
+
var FINISHED_EVENT_MEMORY = 1e4;
|
|
1820
|
+
var MANUAL_UPDATES = /* @__PURE__ */ new WeakSet();
|
|
1821
|
+
function markManualUpdate(patch) {
|
|
1822
|
+
try {
|
|
1823
|
+
MANUAL_UPDATES.add(patch);
|
|
1824
|
+
} catch (e) {
|
|
1825
|
+
}
|
|
1826
|
+
return patch;
|
|
1827
|
+
}
|
|
1076
1828
|
var EventShipper = class {
|
|
1077
1829
|
constructor(opts) {
|
|
1078
1830
|
this.appGitOwner = appGitOwnerId("event");
|
|
@@ -1080,6 +1832,12 @@ var EventShipper = class {
|
|
|
1080
1832
|
this.sticky = /* @__PURE__ */ new Map();
|
|
1081
1833
|
this.timers = /* @__PURE__ */ new Map();
|
|
1082
1834
|
this.inFlight = /* @__PURE__ */ new Set();
|
|
1835
|
+
this.background = /* @__PURE__ */ new Set();
|
|
1836
|
+
this.backgroundDrops = 0;
|
|
1837
|
+
this.cutOff = new InFlightCutOff();
|
|
1838
|
+
this.finishedEventIds = /* @__PURE__ */ new Set();
|
|
1839
|
+
this.sendChains = /* @__PURE__ */ new Map();
|
|
1840
|
+
this.deferredSends = /* @__PURE__ */ new Set();
|
|
1083
1841
|
this.hasShutdown = false;
|
|
1084
1842
|
var _a, _b, _c, _d, _e, _f, _g, _h, _i;
|
|
1085
1843
|
this.appGitContext = (_a = opts.appGitContext) != null ? _a : createAppGitContext(opts.appGit);
|
|
@@ -1093,6 +1851,7 @@ var EventShipper = class {
|
|
|
1093
1851
|
this.prefix = `[raindrop-ai/${this.sdkName}]`;
|
|
1094
1852
|
this.defaultEventName = (_f = opts.defaultEventName) != null ? _f : "ai_generation";
|
|
1095
1853
|
this.maxTextFieldCharsOpt = opts.maxTextFieldChars;
|
|
1854
|
+
this.flushTimeoutMs = resolveFlushTimeoutMs(opts.flushTimeoutMs);
|
|
1096
1855
|
this.localDebuggerUrl = (_g = resolveLocalDebuggerBaseUrl(opts.localDebuggerUrl)) != null ? _g : void 0;
|
|
1097
1856
|
if (this.debug && this.localDebuggerUrl) {
|
|
1098
1857
|
console.log(`${this.prefix} Local debugger mirroring: ${this.localDebuggerUrl}`);
|
|
@@ -1101,15 +1860,29 @@ var EventShipper = class {
|
|
|
1101
1860
|
debug: this.debug,
|
|
1102
1861
|
prefix: this.prefix
|
|
1103
1862
|
});
|
|
1104
|
-
|
|
1863
|
+
this.redactPii = opts.redactPii === true;
|
|
1864
|
+
this.piiFields = new PiiFieldRedactor({
|
|
1865
|
+
startupFieldMap: opts.redactPiiFields,
|
|
1866
|
+
logPrefix: this.prefix
|
|
1867
|
+
});
|
|
1868
|
+
if (opts.redactPiiFields && !this.redactPii) {
|
|
1869
|
+
rateLimitedLog(
|
|
1870
|
+
`${this.prefix}.pii_fields_without_redaction`,
|
|
1871
|
+
() => console.warn(
|
|
1872
|
+
`${this.prefix} redactPiiFields is set but redactPii is off; nothing is redacted. Set redactPii: true to use it.`
|
|
1873
|
+
)
|
|
1874
|
+
);
|
|
1875
|
+
}
|
|
1876
|
+
this.wizardSession = opts.wizardSession || void 0;
|
|
1877
|
+
const runtime = detectRuntime();
|
|
1105
1878
|
this.context = {
|
|
1106
1879
|
library: {
|
|
1107
1880
|
name: (_h = opts.libraryName) != null ? _h : "@raindrop-ai/core",
|
|
1108
1881
|
version: (_i = opts.libraryVersion) != null ? _i : "0.0.0"
|
|
1109
1882
|
},
|
|
1110
1883
|
metadata: {
|
|
1111
|
-
jsRuntime:
|
|
1112
|
-
...
|
|
1884
|
+
jsRuntime: runtime,
|
|
1885
|
+
...runtime === "node" ? { nodeVersion: process.version } : {}
|
|
1113
1886
|
}
|
|
1114
1887
|
};
|
|
1115
1888
|
}
|
|
@@ -1126,28 +1899,21 @@ var EventShipper = class {
|
|
|
1126
1899
|
return { ...this.authHeaders(), ...projectIdHeaders(this.projectId) };
|
|
1127
1900
|
}
|
|
1128
1901
|
/**
|
|
1129
|
-
*
|
|
1130
|
-
*
|
|
1131
|
-
*
|
|
1132
|
-
*
|
|
1133
|
-
*
|
|
1134
|
-
* Checked fresh on EVERY send, so a shutdown that begins while the flush
|
|
1135
|
-
* path is mid-drain takes effect immediately: no further retries, and the
|
|
1136
|
-
* per-attempt timeout is clamped to the remaining window. After
|
|
1137
|
-
* `shutdown()` returns (deadline cleared, `hasShutdown` still set),
|
|
1138
|
-
* sends — late callers, or flush work the deadline abandoned mid-drain —
|
|
1139
|
-
* run as a single short attempt rather than regaining the full retry
|
|
1140
|
-
* schedule.
|
|
1902
|
+
* Retry/timeout options for one POST. While `shutdown()` drains, sends retry
|
|
1903
|
+
* within its window (deadline = the shutdown deadline); a flush passes its
|
|
1904
|
+
* own deadline. `null` when the shutdown window is spent: the caller drops
|
|
1905
|
+
* the payload with a warning. After `shutdown()` returns, late sends get a
|
|
1906
|
+
* single short attempt rather than the full retry schedule.
|
|
1141
1907
|
*/
|
|
1142
|
-
requestOpts() {
|
|
1908
|
+
requestOpts(deadlineAt) {
|
|
1143
1909
|
if (this.shutdownDeadlineAt !== void 0) {
|
|
1144
|
-
|
|
1145
|
-
if (remainingMs <= 0) return null;
|
|
1910
|
+
if (this.shutdownDeadlineAt - Date.now() <= 0) return null;
|
|
1146
1911
|
return {
|
|
1147
|
-
maxAttempts:
|
|
1912
|
+
maxAttempts: 3,
|
|
1148
1913
|
debug: this.debug,
|
|
1149
1914
|
sdkName: this.sdkName,
|
|
1150
|
-
|
|
1915
|
+
deadlineAt: Math.min(this.shutdownDeadlineAt, deadlineAt != null ? deadlineAt : Infinity),
|
|
1916
|
+
cutOff: this.cutOff.signal
|
|
1151
1917
|
};
|
|
1152
1918
|
}
|
|
1153
1919
|
if (this.hasShutdown) {
|
|
@@ -1155,15 +1921,94 @@ var EventShipper = class {
|
|
|
1155
1921
|
maxAttempts: 1,
|
|
1156
1922
|
debug: this.debug,
|
|
1157
1923
|
sdkName: this.sdkName,
|
|
1158
|
-
timeoutMs: POST_SHUTDOWN_TIMEOUT_MS
|
|
1924
|
+
timeoutMs: POST_SHUTDOWN_TIMEOUT_MS,
|
|
1925
|
+
cutOff: this.cutOff.signal
|
|
1159
1926
|
};
|
|
1160
1927
|
}
|
|
1161
|
-
return {
|
|
1928
|
+
return {
|
|
1929
|
+
maxAttempts: 3,
|
|
1930
|
+
debug: this.debug,
|
|
1931
|
+
sdkName: this.sdkName,
|
|
1932
|
+
deadlineAt,
|
|
1933
|
+
cutOff: this.cutOff.signal
|
|
1934
|
+
};
|
|
1935
|
+
}
|
|
1936
|
+
shuttingDown() {
|
|
1937
|
+
return this.shutdownDeadlineAt !== void 0 || this.hasShutdown;
|
|
1162
1938
|
}
|
|
1163
1939
|
async patch(eventId, patch) {
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1940
|
+
await this.patchWithFate(eventId, patch);
|
|
1941
|
+
}
|
|
1942
|
+
/**
|
|
1943
|
+
* Queue an update without waiting for any network send: for integrations,
|
|
1944
|
+
* whose captured call must return as soon as the update is queued (rule C9,
|
|
1945
|
+
* hot path). A finishing update starts its send in the background; `flush()`
|
|
1946
|
+
* and `shutdown()` wait for it within their deadline and count it in their
|
|
1947
|
+
* result. Never throws or rejects.
|
|
1948
|
+
*/
|
|
1949
|
+
enqueue(eventId, patch) {
|
|
1950
|
+
let op;
|
|
1951
|
+
try {
|
|
1952
|
+
op = this.patchWithFate(eventId, patch).catch((err) => {
|
|
1953
|
+
this.warnBackgroundFailure(eventId, err);
|
|
1954
|
+
return "dropped";
|
|
1955
|
+
}).then((fate) => {
|
|
1956
|
+
if (fate === "dropped") this.backgroundDrops += 1;
|
|
1957
|
+
return fate;
|
|
1958
|
+
});
|
|
1959
|
+
} catch (err) {
|
|
1960
|
+
this.warnBackgroundFailure(eventId, err);
|
|
1961
|
+
return;
|
|
1962
|
+
}
|
|
1963
|
+
this.background.add(op);
|
|
1964
|
+
void op.finally(() => this.background.delete(op));
|
|
1965
|
+
}
|
|
1966
|
+
/** `finish()` without waiting for the send; see `enqueue`. */
|
|
1967
|
+
enqueueFinish(eventId, patch = {}) {
|
|
1968
|
+
this.enqueue(eventId, { ...patch, isPending: false });
|
|
1969
|
+
}
|
|
1970
|
+
/**
|
|
1971
|
+
* Caller properties win over everything the integration derived (W6). A
|
|
1972
|
+
* clash is intended by the caller, so it is only logged in debug mode.
|
|
1973
|
+
*/
|
|
1974
|
+
withCallerProperties(eventId, derived, caller) {
|
|
1975
|
+
if (!caller || Object.keys(caller).length === 0) return derived;
|
|
1976
|
+
if (this.debug) {
|
|
1977
|
+
try {
|
|
1978
|
+
const keys = overriddenKeys(derived, caller);
|
|
1979
|
+
if (keys.length > 0) {
|
|
1980
|
+
console.log(
|
|
1981
|
+
`${this.prefix} event ${eventId}: caller properties override the integration's value for ${keys.map((k) => `"${k}"`).join(", ")}`
|
|
1982
|
+
);
|
|
1983
|
+
}
|
|
1984
|
+
} catch (e) {
|
|
1985
|
+
}
|
|
1986
|
+
}
|
|
1987
|
+
return deepMergeProperties(derived, caller);
|
|
1988
|
+
}
|
|
1989
|
+
warnBackgroundFailure(eventId, err) {
|
|
1990
|
+
rateLimitedLog(
|
|
1991
|
+
`${this.prefix}.background_update`,
|
|
1992
|
+
() => console.warn(`${this.prefix} update for event ${eventId} failed:`, err)
|
|
1993
|
+
);
|
|
1994
|
+
}
|
|
1995
|
+
/**
|
|
1996
|
+
* Id of the last event an integration finished in this process (manual
|
|
1997
|
+
* events API finishes excluded): what integrations expose as `lastEventId`
|
|
1998
|
+
* (wrapper profile W10).
|
|
1999
|
+
*/
|
|
2000
|
+
get lastFinishedEventId() {
|
|
2001
|
+
return this.lastFinished;
|
|
2002
|
+
}
|
|
2003
|
+
async patchWithFate(eventId, patch) {
|
|
2004
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m;
|
|
2005
|
+
const manual = MANUAL_UPDATES.has(patch);
|
|
2006
|
+
if (!this.enabled) return void 0;
|
|
2007
|
+
if (!eventId || !eventId.trim()) return void 0;
|
|
2008
|
+
if (patch.userId !== void 0 && isMissingUserId(patch.userId)) {
|
|
2009
|
+
const { userId: _placeholder, ...rest } = patch;
|
|
2010
|
+
patch = rest;
|
|
2011
|
+
}
|
|
1167
2012
|
const capturedSticky = this.sticky.get(eventId);
|
|
1168
2013
|
const eventAlreadyKnown = capturedSticky !== void 0 || this.buffers.has(eventId);
|
|
1169
2014
|
const destination = currentReplayTraceDestination();
|
|
@@ -1171,7 +2016,7 @@ var EventShipper = class {
|
|
|
1171
2016
|
if ((capturedSticky == null ? void 0 : capturedSticky.replayOnly) === true || !eventAlreadyKnown && cloudReplay) {
|
|
1172
2017
|
if (patch.isPending === false) this.sticky.delete(eventId);
|
|
1173
2018
|
else this.sticky.set(eventId, { ...capturedSticky, replayOnly: true });
|
|
1174
|
-
return;
|
|
2019
|
+
return void 0;
|
|
1175
2020
|
}
|
|
1176
2021
|
const maxChars = resolveMaxTextFieldChars(this.maxTextFieldCharsOpt);
|
|
1177
2022
|
if (typeof patch.input === "string" && patch.input.length > maxChars) {
|
|
@@ -1194,11 +2039,12 @@ var EventShipper = class {
|
|
|
1194
2039
|
}
|
|
1195
2040
|
const sticky = (_c = this.sticky.get(eventId)) != null ? _c : {};
|
|
1196
2041
|
const existing = (_d = this.buffers.get(eventId)) != null ? _d : {};
|
|
2042
|
+
const explicitProperties = patch.callerProperties !== void 0 ? { ...patch.properties, ...patch.callerProperties } : patch.properties;
|
|
1197
2043
|
patch = {
|
|
1198
2044
|
...patch,
|
|
1199
2045
|
properties: withAppGitProperties(
|
|
1200
2046
|
patch.properties,
|
|
1201
|
-
this.appGitContext.forOperation(eventId,
|
|
2047
|
+
this.appGitContext.forOperation(eventId, explicitProperties, this.appGitOwner)
|
|
1202
2048
|
)
|
|
1203
2049
|
};
|
|
1204
2050
|
const merged = mergePatches(existing, patch);
|
|
@@ -1208,47 +2054,165 @@ var EventShipper = class {
|
|
|
1208
2054
|
userId: (_h = merged.userId) != null ? _h : sticky.userId,
|
|
1209
2055
|
convoId: (_i = merged.convoId) != null ? _i : sticky.convoId,
|
|
1210
2056
|
eventName: (_j = merged.eventName) != null ? _j : sticky.eventName,
|
|
1211
|
-
isPending: (_k = merged.isPending) != null ? _k : sticky.isPending
|
|
2057
|
+
isPending: (_k = merged.isPending) != null ? _k : sticky.isPending,
|
|
2058
|
+
startedAt: (_l = earliestIsoTimestamp(sticky.startedAt, patch.timestamp)) != null ? _l : (/* @__PURE__ */ new Date()).toISOString(),
|
|
2059
|
+
resumed: sticky.resumed,
|
|
2060
|
+
hasContent: sticky.hasContent === true || patchHasContent(patch),
|
|
2061
|
+
callerProperties: patch.callerProperties !== void 0 ? deepMergeProperties((_m = sticky.callerProperties) != null ? _m : {}, patch.callerProperties) : sticky.callerProperties
|
|
1212
2062
|
});
|
|
1213
2063
|
const t = this.timers.get(eventId);
|
|
1214
2064
|
if (t) clearTimeout(t);
|
|
1215
2065
|
if (merged.isPending === false) {
|
|
1216
|
-
|
|
2066
|
+
if (!manual) this.lastFinished = eventId;
|
|
2067
|
+
this.noteFinish(eventId);
|
|
2068
|
+
this.noteEmptyFinish(eventId);
|
|
2069
|
+
const fate = await this.flushOne(eventId);
|
|
1217
2070
|
if (this.appGitContext.releaseOperation) this.appGitContext.releaseOperation(eventId, this.appGitOwner);
|
|
1218
2071
|
else this.appGitContext.finishOperation(eventId);
|
|
1219
|
-
return;
|
|
2072
|
+
return fate;
|
|
1220
2073
|
}
|
|
1221
2074
|
const timeout = setTimeout(() => {
|
|
1222
2075
|
void this.flushOne(eventId).catch(() => {
|
|
1223
2076
|
});
|
|
1224
2077
|
}, this.partialFlushMs);
|
|
1225
2078
|
this.timers.set(eventId, timeout);
|
|
2079
|
+
return void 0;
|
|
2080
|
+
}
|
|
2081
|
+
/**
|
|
2082
|
+
* A second finish for an event is still sent (ingest finalizes once and
|
|
2083
|
+
* treats it as an update, CONTRACT §10.2), but it usually means several
|
|
2084
|
+
* calls share one event id by mistake, so it is warned about.
|
|
2085
|
+
*/
|
|
2086
|
+
noteFinish(eventId) {
|
|
2087
|
+
if (this.finishedEventIds.has(eventId)) {
|
|
2088
|
+
rateLimitedLog(
|
|
2089
|
+
`${this.prefix}.repeated_finish`,
|
|
2090
|
+
() => console.warn(
|
|
2091
|
+
`${this.prefix} event ${eventId} was already finished in this process; sending the update anyway (ingest finalizes an event once). Use a separate event id per interaction, or keep the event pending until its last call.`
|
|
2092
|
+
)
|
|
2093
|
+
);
|
|
2094
|
+
return;
|
|
2095
|
+
}
|
|
2096
|
+
this.finishedEventIds.add(eventId);
|
|
2097
|
+
if (this.finishedEventIds.size > FINISHED_EVENT_MEMORY) {
|
|
2098
|
+
const oldest = this.finishedEventIds.values().next().value;
|
|
2099
|
+
if (oldest !== void 0) this.finishedEventIds.delete(oldest);
|
|
2100
|
+
}
|
|
2101
|
+
}
|
|
2102
|
+
/**
|
|
2103
|
+
* An event finished with no input, output or attachments is almost always a
|
|
2104
|
+
* caller bug (CONTRACT §14.2, rule C5); it is sent anyway and warned about.
|
|
2105
|
+
* Not for a resumed event: its content may have been sent by another process.
|
|
2106
|
+
*/
|
|
2107
|
+
noteEmptyFinish(eventId) {
|
|
2108
|
+
const sticky = this.sticky.get(eventId);
|
|
2109
|
+
if ((sticky == null ? void 0 : sticky.resumed) === true || (sticky == null ? void 0 : sticky.hasContent) === true) return;
|
|
2110
|
+
rateLimitedLog(
|
|
2111
|
+
`${this.prefix}.empty_finish`,
|
|
2112
|
+
() => console.warn(
|
|
2113
|
+
`${this.prefix} event ${eventId} finished with no input, output or attachments; sending it anyway. Pass the interaction's input at begin or its output at finish.`
|
|
2114
|
+
)
|
|
2115
|
+
);
|
|
2116
|
+
}
|
|
2117
|
+
/**
|
|
2118
|
+
* Continue an event that was begun elsewhere (another process, a queue
|
|
2119
|
+
* worker, a later request) using only its id. No request is sent; later
|
|
2120
|
+
* `patch` / `finish` calls for this id are sent even without a `userId`,
|
|
2121
|
+
* and ingest keeps the user, conversation and start time it already has.
|
|
2122
|
+
* Pass `userId` / `convoId` / `eventName` if you have them.
|
|
2123
|
+
*/
|
|
2124
|
+
resume(eventId, options = {}) {
|
|
2125
|
+
var _a, _b, _c;
|
|
2126
|
+
if (!this.enabled) return;
|
|
2127
|
+
if (!eventId || !eventId.trim()) return;
|
|
2128
|
+
const sticky = (_a = this.sticky.get(eventId)) != null ? _a : {};
|
|
2129
|
+
this.sticky.set(eventId, {
|
|
2130
|
+
...sticky,
|
|
2131
|
+
userId: isMissingUserId(options.userId) ? sticky.userId : options.userId,
|
|
2132
|
+
convoId: (_b = options.convoId) != null ? _b : sticky.convoId,
|
|
2133
|
+
eventName: (_c = options.eventName) != null ? _c : sticky.eventName,
|
|
2134
|
+
resumed: true
|
|
2135
|
+
});
|
|
1226
2136
|
}
|
|
1227
2137
|
async finish(eventId, patch) {
|
|
1228
|
-
|
|
2138
|
+
const update = { ...patch, isPending: false };
|
|
2139
|
+
if (MANUAL_UPDATES.has(patch)) MANUAL_UPDATES.add(update);
|
|
2140
|
+
await this.patch(eventId, update);
|
|
1229
2141
|
}
|
|
2142
|
+
/**
|
|
2143
|
+
* Send everything buffered, open (pending) events included, within
|
|
2144
|
+
* `flushTimeoutMs` (CONTRACT 1.2.1). Resolves, never rejects, to whether it
|
|
2145
|
+
* all reached ingest; when it didn't, it also warns. At the deadline,
|
|
2146
|
+
* payloads not yet sent stay queued for a later send and a request cut off
|
|
2147
|
+
* mid-flight is dropped. Sends already running when it was called are
|
|
2148
|
+
* waited for up to the deadline and then cut off.
|
|
2149
|
+
*/
|
|
1230
2150
|
async flush() {
|
|
1231
|
-
|
|
2151
|
+
const result = await this.drainAll(Date.now() + this.flushTimeoutMs);
|
|
2152
|
+
if (!result.delivered && this.shutdownDeadlineAt === void 0) {
|
|
2153
|
+
rateLimitedLog(
|
|
2154
|
+
`${this.prefix}.flush_undelivered`,
|
|
2155
|
+
() => console.warn(`${this.prefix} ${describeUndelivered("flush()", result)}`)
|
|
2156
|
+
);
|
|
2157
|
+
}
|
|
2158
|
+
return asCompat(result);
|
|
2159
|
+
}
|
|
2160
|
+
async drainAll(deadlineAt) {
|
|
2161
|
+
if (!this.enabled) return { ...DELIVERED };
|
|
2162
|
+
const deferred = [...this.deferredSends];
|
|
2163
|
+
this.deferredSends.clear();
|
|
2164
|
+
for (const entry of deferred) if (entry.timer) clearTimeout(entry.timer);
|
|
1232
2165
|
const ids = [...this.buffers.keys()];
|
|
1233
|
-
await Promise.all(
|
|
1234
|
-
|
|
1235
|
-
|
|
2166
|
+
const fates = await Promise.all([
|
|
2167
|
+
...ids.map((id) => this.flushOne(id, deadlineAt)),
|
|
2168
|
+
...deferred.map((entry) => entry.send(deadlineAt))
|
|
2169
|
+
]);
|
|
2170
|
+
const background = [...this.background];
|
|
2171
|
+
if (background.length > 0) {
|
|
2172
|
+
await raceWithTimeout(Promise.all(background), deadlineAt - Date.now());
|
|
2173
|
+
}
|
|
2174
|
+
for (; this.backgroundDrops > 0; this.backgroundDrops -= 1) fates.push("dropped");
|
|
2175
|
+
const running = [...this.inFlight];
|
|
2176
|
+
const { settled, stillRunning } = await awaitEarlierSends(
|
|
2177
|
+
running,
|
|
2178
|
+
deadlineAt,
|
|
2179
|
+
this.cutOff,
|
|
2180
|
+
(p) => this.inFlight.has(p)
|
|
2181
|
+
);
|
|
2182
|
+
const unresolved = background.filter((op) => this.background.has(op)).length;
|
|
2183
|
+
return summarize2(
|
|
2184
|
+
fates.filter((fate) => fate !== void 0),
|
|
2185
|
+
Math.max(stillRunning, unresolved),
|
|
2186
|
+
!settled || unresolved > 0
|
|
2187
|
+
);
|
|
1236
2188
|
}
|
|
2189
|
+
/**
|
|
2190
|
+
* Flush within `flushTimeoutMs` and stop. Sends retry while the window
|
|
2191
|
+
* allows; whatever is left at the deadline is dropped with a warning, so a
|
|
2192
|
+
* dead network can never wedge process exit. Resolves, never rejects.
|
|
2193
|
+
*/
|
|
1237
2194
|
async shutdown() {
|
|
1238
2195
|
this.hasShutdown = true;
|
|
1239
|
-
|
|
2196
|
+
const deadlineAt = Date.now() + this.flushTimeoutMs;
|
|
2197
|
+
this.shutdownDeadlineAt = deadlineAt;
|
|
2198
|
+
let result = { ...DELIVERED };
|
|
1240
2199
|
try {
|
|
1241
2200
|
for (const t of this.timers.values()) clearTimeout(t);
|
|
1242
2201
|
this.timers.clear();
|
|
1243
2202
|
for (const [eventId, sticky] of this.sticky) {
|
|
1244
2203
|
if (sticky.replayOnly) this.sticky.delete(eventId);
|
|
1245
2204
|
}
|
|
1246
|
-
|
|
1247
|
-
if (!
|
|
2205
|
+
result = await this.drainAll(deadlineAt);
|
|
2206
|
+
if (!result.delivered) {
|
|
2207
|
+
this.warnShutdownDrop(
|
|
2208
|
+
`${result.dropped + result.queued + result.inFlight} payload(s) not delivered`
|
|
2209
|
+
);
|
|
2210
|
+
}
|
|
1248
2211
|
} finally {
|
|
1249
2212
|
this.shutdownDeadlineAt = void 0;
|
|
1250
2213
|
if (this.ownsAppGitContext) this.appGitContext.dispose();
|
|
1251
2214
|
}
|
|
2215
|
+
return asCompat(result);
|
|
1252
2216
|
}
|
|
1253
2217
|
async trackSignal(signal) {
|
|
1254
2218
|
var _a, _b;
|
|
@@ -1269,23 +2233,9 @@ var EventShipper = class {
|
|
|
1269
2233
|
...signal.after ? { after: signal.after } : {}
|
|
1270
2234
|
}
|
|
1271
2235
|
}
|
|
1272
|
-
];
|
|
2236
|
+
].map((item) => this.redactFields("signal", item));
|
|
1273
2237
|
if (!this.writeKey) return;
|
|
1274
|
-
|
|
1275
|
-
const opts = this.requestOpts();
|
|
1276
|
-
if (!opts) {
|
|
1277
|
-
this.warnShutdownDrop("signal");
|
|
1278
|
-
return;
|
|
1279
|
-
}
|
|
1280
|
-
try {
|
|
1281
|
-
await postJson(url, body, this.requestHeaders(), opts);
|
|
1282
|
-
} catch (err) {
|
|
1283
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
1284
|
-
rateLimitedLog(
|
|
1285
|
-
`${this.prefix}.send_signal_failed`,
|
|
1286
|
-
() => console.warn(`${this.prefix} failed to send signal (dropping): ${msg}`)
|
|
1287
|
-
);
|
|
1288
|
-
}
|
|
2238
|
+
await this.sendDirect("signal", `${this.baseUrl}signals/track`, body);
|
|
1289
2239
|
}
|
|
1290
2240
|
async identify(users) {
|
|
1291
2241
|
if (!this.enabled) return;
|
|
@@ -1300,30 +2250,80 @@ var EventShipper = class {
|
|
|
1300
2250
|
return false;
|
|
1301
2251
|
}
|
|
1302
2252
|
return true;
|
|
1303
|
-
}).map(
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
2253
|
+
}).map(
|
|
2254
|
+
(user) => {
|
|
2255
|
+
var _a;
|
|
2256
|
+
return this.redactFields("identify", {
|
|
2257
|
+
user_id: user.userId,
|
|
2258
|
+
traits: (_a = user.traits) != null ? _a : {}
|
|
2259
|
+
});
|
|
2260
|
+
}
|
|
2261
|
+
);
|
|
1310
2262
|
if (!this.writeKey) return;
|
|
1311
2263
|
if (body.length === 0) return;
|
|
1312
|
-
|
|
1313
|
-
|
|
2264
|
+
await this.sendDirect("identify", `${this.baseUrl}users/identify`, body);
|
|
2265
|
+
}
|
|
2266
|
+
/**
|
|
2267
|
+
* Send a signal or identify body. Tracked so `flush()` waits for it. A send
|
|
2268
|
+
* a flush deadline deferred is kept and retried later (outside shutdown).
|
|
2269
|
+
*/
|
|
2270
|
+
async sendDirect(kind, url, body, deadlineAt) {
|
|
2271
|
+
const opts = this.requestOpts(deadlineAt);
|
|
1314
2272
|
if (!opts) {
|
|
1315
|
-
this.warnShutdownDrop(
|
|
1316
|
-
return;
|
|
2273
|
+
this.warnShutdownDrop(kind);
|
|
2274
|
+
return "dropped";
|
|
1317
2275
|
}
|
|
2276
|
+
const sending = sendJson(url, body, this.requestHeaders(), opts);
|
|
2277
|
+
const tracked = sending.then(() => void 0);
|
|
2278
|
+
this.inFlight.add(tracked);
|
|
2279
|
+
let outcome;
|
|
1318
2280
|
try {
|
|
1319
|
-
|
|
1320
|
-
}
|
|
1321
|
-
|
|
2281
|
+
outcome = await sending;
|
|
2282
|
+
} finally {
|
|
2283
|
+
this.inFlight.delete(tracked);
|
|
2284
|
+
}
|
|
2285
|
+
const fate = fateOf(outcome, this.shuttingDown());
|
|
2286
|
+
if (fate === "queued") {
|
|
2287
|
+
this.deferSend(
|
|
2288
|
+
(later) => this.sendDirect(kind, url, body, later),
|
|
2289
|
+
outcome.status === "deferred" ? outcome.retryAtMs : void 0
|
|
2290
|
+
);
|
|
2291
|
+
} else if (fate === "dropped") {
|
|
2292
|
+
this.warnSendDropped(kind, outcome);
|
|
2293
|
+
}
|
|
2294
|
+
return fate;
|
|
2295
|
+
}
|
|
2296
|
+
deferSend(send, retryAtMs) {
|
|
2297
|
+
var _a, _b;
|
|
2298
|
+
if (this.deferredSends.size >= MAX_DEFERRED_SENDS) {
|
|
1322
2299
|
rateLimitedLog(
|
|
1323
|
-
`${this.prefix}.
|
|
1324
|
-
() => console.warn(`${this.prefix}
|
|
2300
|
+
`${this.prefix}.deferred_full`,
|
|
2301
|
+
() => console.warn(`${this.prefix} too many sends waiting for a retry; dropping one`)
|
|
1325
2302
|
);
|
|
2303
|
+
return;
|
|
1326
2304
|
}
|
|
2305
|
+
const entry = { send };
|
|
2306
|
+
const delay = Math.max(this.partialFlushMs, (retryAtMs != null ? retryAtMs : 0) - Date.now());
|
|
2307
|
+
entry.timer = setTimeout(() => {
|
|
2308
|
+
if (!this.deferredSends.delete(entry)) return;
|
|
2309
|
+
void send().catch(() => {
|
|
2310
|
+
});
|
|
2311
|
+
}, delay);
|
|
2312
|
+
(_b = (_a = entry.timer).unref) == null ? void 0 : _b.call(_a);
|
|
2313
|
+
this.deferredSends.add(entry);
|
|
2314
|
+
}
|
|
2315
|
+
warnSendDropped(what, outcome) {
|
|
2316
|
+
var _a, _b;
|
|
2317
|
+
if (outcome.status === "delivered" || outcome.status === "rejected") return;
|
|
2318
|
+
const reason = outcome.status === "cut_off" ? "cut off at the flush deadline (not resent: it may have reached ingest)" : outcome.status === "deferred" ? "not sent before the shutdown deadline" : (_b = (_a = outcome.error) == null ? void 0 : _a.message) != null ? _b : outcome.status;
|
|
2319
|
+
rateLimitedLog(
|
|
2320
|
+
`${this.prefix}.send_${what}_dropped`,
|
|
2321
|
+
() => console.warn(`${this.prefix} failed to send ${what} (dropping): ${reason}`)
|
|
2322
|
+
);
|
|
2323
|
+
}
|
|
2324
|
+
/** The payload with its PII fields redacted when `redactPii` is on (CONTRACT 11.2). */
|
|
2325
|
+
redactFields(kind, payload) {
|
|
2326
|
+
return this.redactPii ? this.piiFields.redact(kind, payload) : payload;
|
|
1327
2327
|
}
|
|
1328
2328
|
warnShutdownDrop(what) {
|
|
1329
2329
|
rateLimitedLog(
|
|
@@ -1331,9 +2331,8 @@ var EventShipper = class {
|
|
|
1331
2331
|
() => console.warn(`${this.prefix} shutdown flush deadline exceeded; dropping ${what}`)
|
|
1332
2332
|
);
|
|
1333
2333
|
}
|
|
1334
|
-
async flushOne(eventId) {
|
|
1335
|
-
|
|
1336
|
-
if (!this.enabled) return;
|
|
2334
|
+
async flushOne(eventId, deadlineAt) {
|
|
2335
|
+
if (!this.enabled) return void 0;
|
|
1337
2336
|
const timer = this.timers.get(eventId);
|
|
1338
2337
|
if (timer) {
|
|
1339
2338
|
clearTimeout(timer);
|
|
@@ -1341,30 +2340,91 @@ var EventShipper = class {
|
|
|
1341
2340
|
}
|
|
1342
2341
|
const accumulated = this.buffers.get(eventId);
|
|
1343
2342
|
this.buffers.delete(eventId);
|
|
1344
|
-
if (!accumulated) return;
|
|
2343
|
+
if (!accumulated) return void 0;
|
|
2344
|
+
const previous = this.sendChains.get(eventId);
|
|
2345
|
+
let release = () => {
|
|
2346
|
+
};
|
|
2347
|
+
const current = new Promise((resolve2) => {
|
|
2348
|
+
release = resolve2;
|
|
2349
|
+
});
|
|
2350
|
+
this.sendChains.set(eventId, current);
|
|
2351
|
+
try {
|
|
2352
|
+
if (previous) {
|
|
2353
|
+
const ready = deadlineAt === void 0 ? (await previous, true) : await raceWithTimeout(previous, deadlineAt - Date.now());
|
|
2354
|
+
if (!ready) {
|
|
2355
|
+
return this.requeue(eventId, accumulated, void 0);
|
|
2356
|
+
}
|
|
2357
|
+
}
|
|
2358
|
+
return await this.sendAccumulated(eventId, accumulated, deadlineAt);
|
|
2359
|
+
} finally {
|
|
2360
|
+
release();
|
|
2361
|
+
if (this.sendChains.get(eventId) === current) this.sendChains.delete(eventId);
|
|
2362
|
+
}
|
|
2363
|
+
}
|
|
2364
|
+
/**
|
|
2365
|
+
* Put an unsent update back under any newer one and send it later
|
|
2366
|
+
* (CONTRACT 1.2.1). During shutdown it is dropped instead.
|
|
2367
|
+
*/
|
|
2368
|
+
requeue(eventId, accumulated, retryAtMs) {
|
|
2369
|
+
var _a, _b;
|
|
2370
|
+
if (this.shuttingDown()) {
|
|
2371
|
+
this.warnShutdownDrop(`track_partial ${eventId}`);
|
|
2372
|
+
if (accumulated.isPending === false) this.sticky.delete(eventId);
|
|
2373
|
+
return "dropped";
|
|
2374
|
+
}
|
|
2375
|
+
const newer = this.buffers.get(eventId);
|
|
2376
|
+
const merged = newer ? mergePatches(accumulated, newer) : accumulated;
|
|
2377
|
+
merged.isPending = (_a = newer == null ? void 0 : newer.isPending) != null ? _a : accumulated.isPending;
|
|
2378
|
+
this.buffers.set(eventId, merged);
|
|
2379
|
+
const existing = this.timers.get(eventId);
|
|
2380
|
+
if (existing) clearTimeout(existing);
|
|
2381
|
+
const delay = Math.max(this.partialFlushMs, (retryAtMs != null ? retryAtMs : 0) - Date.now());
|
|
2382
|
+
const timeout = setTimeout(() => {
|
|
2383
|
+
void this.flushOne(eventId).catch(() => {
|
|
2384
|
+
});
|
|
2385
|
+
}, delay);
|
|
2386
|
+
(_b = timeout.unref) == null ? void 0 : _b.call(timeout);
|
|
2387
|
+
this.timers.set(eventId, timeout);
|
|
2388
|
+
return "queued";
|
|
2389
|
+
}
|
|
2390
|
+
async sendAccumulated(eventId, accumulated, deadlineAt) {
|
|
2391
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p;
|
|
1345
2392
|
const sticky = (_a = this.sticky.get(eventId)) != null ? _a : {};
|
|
1346
2393
|
const isPending = (_c = (_b = accumulated.isPending) != null ? _b : sticky.isPending) != null ? _c : true;
|
|
1347
|
-
const
|
|
1348
|
-
const
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
2394
|
+
const knownEventName = (_d = accumulated.eventName) != null ? _d : sticky.eventName;
|
|
2395
|
+
const eventName = knownEventName != null ? knownEventName : sticky.resumed ? void 0 : this.defaultEventName;
|
|
2396
|
+
const userId = (_e = accumulated.userId) != null ? _e : sticky.userId;
|
|
2397
|
+
if (!userId && !sticky.resumed) {
|
|
2398
|
+
rateLimitedLog(
|
|
2399
|
+
`${this.prefix}.track_partial_missing_user`,
|
|
2400
|
+
() => console.warn(
|
|
2401
|
+
`${this.prefix} skipping track_partial for ${eventId}: missing userId (pass userId, or call resume(eventId) to continue an event begun elsewhere)`
|
|
2402
|
+
)
|
|
2403
|
+
);
|
|
1353
2404
|
this.sticky.delete(eventId);
|
|
1354
|
-
return;
|
|
2405
|
+
return void 0;
|
|
2406
|
+
}
|
|
2407
|
+
if (!userId) {
|
|
2408
|
+
rateLimitedLog(
|
|
2409
|
+
`${this.prefix}.track_partial_resumed_without_user`,
|
|
2410
|
+
() => console.warn(
|
|
2411
|
+
`${this.prefix} sending track_partial for ${eventId} without a userId; ingest will use the user stored for this event (pass userId to resume() to set it explicitly)`
|
|
2412
|
+
)
|
|
2413
|
+
);
|
|
1355
2414
|
}
|
|
1356
|
-
const { wizardSession, ...restProperties } = (
|
|
2415
|
+
const { wizardSession, ...restProperties } = (_f = accumulated.properties) != null ? _f : {};
|
|
1357
2416
|
let telemetryProperties = {};
|
|
1358
2417
|
try {
|
|
1359
2418
|
telemetryProperties = eventTelemetryProperties(accumulated);
|
|
1360
2419
|
} catch (e) {
|
|
1361
2420
|
}
|
|
1362
|
-
const convoId = (
|
|
1363
|
-
const
|
|
2421
|
+
const convoId = (_g = accumulated.convoId) != null ? _g : sticky.convoId;
|
|
2422
|
+
const sessionTag = wizardSession != null ? wizardSession : this.wizardSession;
|
|
2423
|
+
const unredacted = {
|
|
1364
2424
|
event_id: eventId,
|
|
1365
|
-
user_id: userId,
|
|
1366
|
-
event: eventName,
|
|
1367
|
-
timestamp: (_i = accumulated.timestamp) != null ? _i : (/* @__PURE__ */ new Date()).toISOString(),
|
|
2425
|
+
...userId ? { user_id: userId } : {},
|
|
2426
|
+
...eventName ? { event: eventName } : {},
|
|
2427
|
+
timestamp: (_i = (_h = sticky.startedAt) != null ? _h : accumulated.timestamp) != null ? _i : (/* @__PURE__ */ new Date()).toISOString(),
|
|
1368
2428
|
ai_data: {
|
|
1369
2429
|
input: accumulated.input,
|
|
1370
2430
|
output: accumulated.error !== void 0 && accumulated.error !== null ? void 0 : accumulated.output,
|
|
@@ -1372,32 +2432,38 @@ var EventShipper = class {
|
|
|
1372
2432
|
convo_id: convoId
|
|
1373
2433
|
},
|
|
1374
2434
|
properties: {
|
|
1375
|
-
...
|
|
1376
|
-
|
|
1377
|
-
|
|
2435
|
+
...this.withCallerProperties(
|
|
2436
|
+
eventId,
|
|
2437
|
+
{ ...restProperties, ...telemetryProperties },
|
|
2438
|
+
(_j = sticky.callerProperties) != null ? _j : accumulated.callerProperties
|
|
2439
|
+
),
|
|
2440
|
+
...sessionTag ? { "raindrop.wizardSession": sessionTag } : {},
|
|
1378
2441
|
$context: this.context
|
|
1379
2442
|
},
|
|
1380
2443
|
...accumulated.featureFlags && Object.keys(accumulated.featureFlags).length > 0 ? { feature_flags: accumulated.featureFlags } : {},
|
|
1381
2444
|
attachments: accumulated.attachments,
|
|
1382
2445
|
is_pending: isPending
|
|
1383
2446
|
};
|
|
2447
|
+
const payload = this.redactFields("event", unredacted);
|
|
1384
2448
|
const url = `${this.baseUrl}events/track_partial`;
|
|
1385
2449
|
if (this.debug) {
|
|
2450
|
+
const sent = payload;
|
|
2451
|
+
const preview = (v, n) => typeof v === "string" ? v.slice(0, n) : void 0;
|
|
1386
2452
|
console.log(`${this.prefix} sending track_partial`, {
|
|
1387
2453
|
eventId,
|
|
1388
2454
|
eventName,
|
|
1389
2455
|
userId,
|
|
1390
2456
|
convoId,
|
|
1391
2457
|
isPending,
|
|
1392
|
-
inputPreview:
|
|
1393
|
-
outputPreview:
|
|
1394
|
-
attachments: (
|
|
1395
|
-
attachmentKinds: (
|
|
2458
|
+
inputPreview: preview((_k = sent.ai_data) == null ? void 0 : _k.input, 120),
|
|
2459
|
+
outputPreview: preview((_l = sent.ai_data) == null ? void 0 : _l.output, 120),
|
|
2460
|
+
attachments: (_n = (_m = sent.attachments) == null ? void 0 : _m.length) != null ? _n : 0,
|
|
2461
|
+
attachmentKinds: (_p = (_o = sent.attachments) == null ? void 0 : _o.map((a) => ({
|
|
1396
2462
|
type: a.type,
|
|
1397
2463
|
role: a.role,
|
|
1398
2464
|
name: a.name,
|
|
1399
|
-
valuePreview: a.value
|
|
1400
|
-
}))) != null ?
|
|
2465
|
+
valuePreview: preview(a.value, 60)
|
|
2466
|
+
}))) != null ? _p : [],
|
|
1401
2467
|
endpoint: url
|
|
1402
2468
|
});
|
|
1403
2469
|
}
|
|
@@ -1410,39 +2476,94 @@ var EventShipper = class {
|
|
|
1410
2476
|
if (!this.writeKey) {
|
|
1411
2477
|
if (!isPending) this.sticky.delete(eventId);
|
|
1412
2478
|
if (mirror) await mirror;
|
|
1413
|
-
return;
|
|
2479
|
+
return void 0;
|
|
1414
2480
|
}
|
|
1415
|
-
const opts = this.requestOpts();
|
|
2481
|
+
const opts = this.requestOpts(deadlineAt);
|
|
1416
2482
|
if (!opts) {
|
|
1417
2483
|
this.warnShutdownDrop(`track_partial ${eventId}`);
|
|
1418
2484
|
if (!isPending) this.sticky.delete(eventId);
|
|
1419
2485
|
if (mirror) await mirror;
|
|
1420
|
-
return;
|
|
2486
|
+
return "dropped";
|
|
1421
2487
|
}
|
|
1422
|
-
const
|
|
1423
|
-
const combined =
|
|
2488
|
+
const sending = sendJson(url, payload, this.requestHeaders(), opts);
|
|
2489
|
+
const combined = Promise.all([mirror, sending.then(() => void 0)]).then(() => void 0);
|
|
1424
2490
|
this.inFlight.add(combined);
|
|
2491
|
+
let outcome;
|
|
1425
2492
|
try {
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
console.log(`${this.prefix} sent track_partial ${eventId} (${eventName})`);
|
|
1430
|
-
}
|
|
1431
|
-
} catch (err) {
|
|
1432
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
1433
|
-
rateLimitedLog(
|
|
1434
|
-
`${this.prefix}.send_track_partial_failed`,
|
|
1435
|
-
() => console.warn(`${this.prefix} failed to send track_partial (dropping): ${msg}`)
|
|
1436
|
-
);
|
|
1437
|
-
}
|
|
2493
|
+
outcome = await sending;
|
|
2494
|
+
if (mirror) await mirror.catch(() => {
|
|
2495
|
+
});
|
|
1438
2496
|
} finally {
|
|
1439
2497
|
this.inFlight.delete(combined);
|
|
1440
2498
|
}
|
|
2499
|
+
const fate = fateOf(outcome, this.shuttingDown());
|
|
2500
|
+
if (fate === "queued") {
|
|
2501
|
+
return this.requeue(
|
|
2502
|
+
eventId,
|
|
2503
|
+
accumulated,
|
|
2504
|
+
outcome.status === "deferred" ? outcome.retryAtMs : void 0
|
|
2505
|
+
);
|
|
2506
|
+
}
|
|
2507
|
+
if (fate === "dropped") this.warnSendDropped("track_partial", outcome);
|
|
2508
|
+
else if (this.debug && outcome.status === "delivered") {
|
|
2509
|
+
console.log(`${this.prefix} sent track_partial ${eventId} (${eventName})`);
|
|
2510
|
+
}
|
|
1441
2511
|
if (!isPending) {
|
|
1442
2512
|
this.sticky.delete(eventId);
|
|
1443
2513
|
}
|
|
2514
|
+
return fate;
|
|
1444
2515
|
}
|
|
1445
2516
|
};
|
|
2517
|
+
function overriddenKeys(derived, caller) {
|
|
2518
|
+
const keys = [];
|
|
2519
|
+
for (const [key, value] of Object.entries(caller)) {
|
|
2520
|
+
if (value === void 0 || !(key in derived)) continue;
|
|
2521
|
+
const existing = derived[key];
|
|
2522
|
+
if (isPlainObject2(existing) && isPlainObject2(value)) {
|
|
2523
|
+
if (overriddenKeys(existing, value).length > 0) keys.push(key);
|
|
2524
|
+
} else if (JSON.stringify(existing) !== JSON.stringify(value)) {
|
|
2525
|
+
keys.push(key);
|
|
2526
|
+
}
|
|
2527
|
+
}
|
|
2528
|
+
return keys;
|
|
2529
|
+
}
|
|
2530
|
+
function patchHasContent(patch) {
|
|
2531
|
+
var _a, _b;
|
|
2532
|
+
return typeof patch.input === "string" && patch.input.length > 0 || typeof patch.output === "string" && patch.output.length > 0 || ((_b = (_a = patch.attachments) == null ? void 0 : _a.length) != null ? _b : 0) > 0;
|
|
2533
|
+
}
|
|
2534
|
+
function resolveFlushTimeoutMs(value) {
|
|
2535
|
+
return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : DEFAULT_FLUSH_TIMEOUT_MS;
|
|
2536
|
+
}
|
|
2537
|
+
function createEventsApi(shipper) {
|
|
2538
|
+
return {
|
|
2539
|
+
async patch(eventId, patch) {
|
|
2540
|
+
await (shipper == null ? void 0 : shipper.patch(eventId, markManualUpdate(asCallerPatch(patch))));
|
|
2541
|
+
},
|
|
2542
|
+
async finish(eventId, patch = {}) {
|
|
2543
|
+
await (shipper == null ? void 0 : shipper.finish(eventId, markManualUpdate(asCallerPatch(patch))));
|
|
2544
|
+
},
|
|
2545
|
+
async addAttachments(eventId, attachments) {
|
|
2546
|
+
await (shipper == null ? void 0 : shipper.patch(eventId, markManualUpdate({ attachments })));
|
|
2547
|
+
},
|
|
2548
|
+
async setProperties(eventId, properties) {
|
|
2549
|
+
await (shipper == null ? void 0 : shipper.patch(eventId, markManualUpdate({ properties, callerProperties: properties })));
|
|
2550
|
+
},
|
|
2551
|
+
async setFeatureFlags(eventId, featureFlags) {
|
|
2552
|
+
await (shipper == null ? void 0 : shipper.patch(eventId, markManualUpdate({ featureFlags: normalizeFeatureFlags(featureFlags) })));
|
|
2553
|
+
},
|
|
2554
|
+
resume(eventId, options) {
|
|
2555
|
+
shipper == null ? void 0 : shipper.resume(eventId, options);
|
|
2556
|
+
}
|
|
2557
|
+
};
|
|
2558
|
+
}
|
|
2559
|
+
function asCallerPatch(patch) {
|
|
2560
|
+
var _a;
|
|
2561
|
+
if (!patch.properties) return patch;
|
|
2562
|
+
return {
|
|
2563
|
+
...patch,
|
|
2564
|
+
callerProperties: { ...patch.properties, ...(_a = patch.callerProperties) != null ? _a : {} }
|
|
2565
|
+
};
|
|
2566
|
+
}
|
|
1446
2567
|
var MODEL_USAGE_ATTRIBUTES = {
|
|
1447
2568
|
usageSource: "raindrop.usage.source",
|
|
1448
2569
|
providerName: "gen_ai.provider.name",
|
|
@@ -1502,6 +2623,21 @@ function buildRawModelUsageAttributes(usage) {
|
|
|
1502
2623
|
attrDouble(MODEL_USAGE_ATTRIBUTES.providerReportedCost, providerReportedCost)
|
|
1503
2624
|
].filter((attribute) => attribute !== void 0);
|
|
1504
2625
|
}
|
|
2626
|
+
var KNOWN_MODEL_PROVIDERS = /* @__PURE__ */ new Set([
|
|
2627
|
+
...MODEL_PROVIDER_NAMES.map(([, family]) => family),
|
|
2628
|
+
"vercel",
|
|
2629
|
+
// Further vendors Dawn's pricing resolves (apps/dawn/lib/spend).
|
|
2630
|
+
"deepseek",
|
|
2631
|
+
"fireworks-ai",
|
|
2632
|
+
"groq",
|
|
2633
|
+
"inception",
|
|
2634
|
+
"mistral",
|
|
2635
|
+
"moonshotai",
|
|
2636
|
+
"perplexity",
|
|
2637
|
+
"togetherai",
|
|
2638
|
+
"xai",
|
|
2639
|
+
"zai"
|
|
2640
|
+
]);
|
|
1505
2641
|
var STRING_ALIASES = {
|
|
1506
2642
|
[MODEL_USAGE_ATTRIBUTES.requestModel]: ["ai.model.id", "ai.model"]
|
|
1507
2643
|
};
|
|
@@ -1754,6 +2890,7 @@ var TraceShipper = class {
|
|
|
1754
2890
|
this.appGitAdded = /* @__PURE__ */ new WeakMap();
|
|
1755
2891
|
this.queue = [];
|
|
1756
2892
|
this.inFlight = /* @__PURE__ */ new Set();
|
|
2893
|
+
this.cutOff = new InFlightCutOff();
|
|
1757
2894
|
this.hasShutdown = false;
|
|
1758
2895
|
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
|
|
1759
2896
|
this.appGitContext = (_a = opts.appGitContext) != null ? _a : createAppGitContext(opts.appGit);
|
|
@@ -1766,6 +2903,7 @@ var TraceShipper = class {
|
|
|
1766
2903
|
this.flushIntervalMs = (_d = opts.flushIntervalMs) != null ? _d : 1e3;
|
|
1767
2904
|
this.maxBatchSize = (_e = opts.maxBatchSize) != null ? _e : 50;
|
|
1768
2905
|
this.maxQueueSize = (_f = opts.maxQueueSize) != null ? _f : 5e3;
|
|
2906
|
+
this.flushTimeoutMs = resolveFlushTimeoutMs(opts.flushTimeoutMs);
|
|
1769
2907
|
this.sdkName = (_g = opts.sdkName) != null ? _g : "core";
|
|
1770
2908
|
this.prefix = `[raindrop-ai/${this.sdkName}]`;
|
|
1771
2909
|
this.serviceName = (_h = opts.serviceName) != null ? _h : "raindrop.core";
|
|
@@ -2044,25 +3182,51 @@ var TraceShipper = class {
|
|
|
2044
3182
|
}
|
|
2045
3183
|
this.queue.push(redacted);
|
|
2046
3184
|
if (this.queue.length >= this.maxBatchSize) {
|
|
2047
|
-
void this.
|
|
3185
|
+
void this.drain().catch(() => {
|
|
2048
3186
|
});
|
|
2049
3187
|
return;
|
|
2050
3188
|
}
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
3189
|
+
this.scheduleDrain(this.flushIntervalMs);
|
|
3190
|
+
}
|
|
3191
|
+
scheduleDrain(delayMs) {
|
|
3192
|
+
if (this.timer) return;
|
|
3193
|
+
this.timer = setTimeout(() => {
|
|
3194
|
+
this.timer = void 0;
|
|
3195
|
+
void this.drain().catch(() => {
|
|
3196
|
+
});
|
|
3197
|
+
}, delayMs);
|
|
2058
3198
|
}
|
|
3199
|
+
/**
|
|
3200
|
+
* Send every queued span within `flushTimeoutMs` (CONTRACT 1.2.1). Resolves,
|
|
3201
|
+
* never rejects, to whether they all reached ingest, and warns when they
|
|
3202
|
+
* didn't. Spans not yet sent at the deadline stay queued.
|
|
3203
|
+
*/
|
|
2059
3204
|
async flush() {
|
|
2060
|
-
|
|
2061
|
-
if (!this.
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
3205
|
+
const result = await this.drainWithin(Date.now() + this.flushTimeoutMs);
|
|
3206
|
+
if (!result.delivered && this.shutdownDeadlineAt === void 0) {
|
|
3207
|
+
rateLimitedLog(
|
|
3208
|
+
`${this.prefix}.flush_undelivered`,
|
|
3209
|
+
() => console.warn(`${this.prefix} ${describeUndelivered("flush()", result)}`)
|
|
3210
|
+
);
|
|
2065
3211
|
}
|
|
3212
|
+
return asCompat(result);
|
|
3213
|
+
}
|
|
3214
|
+
async drainWithin(deadlineAt) {
|
|
3215
|
+
const fates = this.enabled ? await this.drain(deadlineAt) : [];
|
|
3216
|
+
const running = [...this.inFlight];
|
|
3217
|
+
const { settled, stillRunning } = await awaitEarlierSends(
|
|
3218
|
+
running,
|
|
3219
|
+
deadlineAt,
|
|
3220
|
+
this.cutOff,
|
|
3221
|
+
(p) => this.inFlight.has(p)
|
|
3222
|
+
);
|
|
3223
|
+
return summarize2(fates, stillRunning, !settled);
|
|
3224
|
+
}
|
|
3225
|
+
/** Send queued batches; with a deadline, a deferred batch goes back on the queue. */
|
|
3226
|
+
async drain(deadlineAt) {
|
|
3227
|
+
var _a;
|
|
3228
|
+
const fates = [];
|
|
3229
|
+
if (!this.enabled) return fates;
|
|
2066
3230
|
if (this.timer) {
|
|
2067
3231
|
clearTimeout(this.timer);
|
|
2068
3232
|
this.timer = void 0;
|
|
@@ -2076,10 +3240,12 @@ var TraceShipper = class {
|
|
|
2076
3240
|
if (spans) spans.push(span);
|
|
2077
3241
|
else groups.set(destination, [span]);
|
|
2078
3242
|
}
|
|
3243
|
+
const requeue = [];
|
|
3244
|
+
let retryAtMs;
|
|
2079
3245
|
for (const [destination, spans] of groups) {
|
|
2080
3246
|
if (!destination && !this.writeKey) continue;
|
|
2081
3247
|
if ((destination == null ? void 0 : destination.kind) === "workshop") continue;
|
|
2082
|
-
const opts = this.requestOpts();
|
|
3248
|
+
const opts = this.requestOpts(deadlineAt);
|
|
2083
3249
|
if (!opts) {
|
|
2084
3250
|
rateLimitedLog(
|
|
2085
3251
|
`${this.prefix}.shutdown_deadline`,
|
|
@@ -2087,6 +3253,7 @@ var TraceShipper = class {
|
|
|
2087
3253
|
`${this.prefix} shutdown flush deadline exceeded; dropping ${spans.length} spans`
|
|
2088
3254
|
)
|
|
2089
3255
|
);
|
|
3256
|
+
fates.push("dropped");
|
|
2090
3257
|
continue;
|
|
2091
3258
|
}
|
|
2092
3259
|
const body = buildExportTraceServiceRequest(spans, this.serviceName, this.serviceVersion);
|
|
@@ -2102,35 +3269,56 @@ var TraceShipper = class {
|
|
|
2102
3269
|
endpoint: url
|
|
2103
3270
|
});
|
|
2104
3271
|
}
|
|
2105
|
-
const
|
|
2106
|
-
|
|
3272
|
+
const sending = sendJson(url, body, headers, opts);
|
|
3273
|
+
const tracked = sending.then(() => void 0);
|
|
3274
|
+
this.inFlight.add(tracked);
|
|
3275
|
+
let outcome;
|
|
2107
3276
|
try {
|
|
2108
|
-
|
|
2109
|
-
await p;
|
|
2110
|
-
if (this.debug) console.log(`${this.prefix} sent ${spans.length} spans`);
|
|
2111
|
-
} catch (err) {
|
|
2112
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
2113
|
-
rateLimitedLog(
|
|
2114
|
-
`${this.prefix}.send_spans_failed`,
|
|
2115
|
-
() => console.warn(`${this.prefix} failed to send ${spans.length} spans: ${msg}`)
|
|
2116
|
-
);
|
|
2117
|
-
}
|
|
3277
|
+
outcome = await sending;
|
|
2118
3278
|
} finally {
|
|
2119
|
-
this.inFlight.delete(
|
|
3279
|
+
this.inFlight.delete(tracked);
|
|
3280
|
+
}
|
|
3281
|
+
const fate = fateOf(outcome, this.shutdownDeadlineAt !== void 0 || this.hasShutdown);
|
|
3282
|
+
fates.push(fate);
|
|
3283
|
+
if (fate === "queued") {
|
|
3284
|
+
requeue.push(...spans);
|
|
3285
|
+
if (outcome.status === "deferred" && outcome.retryAtMs !== void 0) {
|
|
3286
|
+
retryAtMs = Math.max(retryAtMs != null ? retryAtMs : 0, outcome.retryAtMs);
|
|
3287
|
+
}
|
|
3288
|
+
} else if (fate === "dropped") {
|
|
3289
|
+
const reason = outcome.status === "cut_off" ? "cut off at the flush deadline (not resent: it may have reached ingest)" : outcome.status === "deferred" ? "not sent before the shutdown deadline" : "error" in outcome && outcome.error ? outcome.error.message : outcome.status;
|
|
3290
|
+
rateLimitedLog(
|
|
3291
|
+
`${this.prefix}.send_spans_failed`,
|
|
3292
|
+
() => console.warn(`${this.prefix} failed to send ${spans.length} spans: ${reason}`)
|
|
3293
|
+
);
|
|
3294
|
+
} else if (this.debug) {
|
|
3295
|
+
console.log(`${this.prefix} sent ${spans.length} spans`);
|
|
3296
|
+
}
|
|
3297
|
+
}
|
|
3298
|
+
if (requeue.length > 0) {
|
|
3299
|
+
this.queue.unshift(...requeue);
|
|
3300
|
+
if (this.queue.length > this.maxQueueSize) {
|
|
3301
|
+
this.queue.splice(this.maxQueueSize);
|
|
2120
3302
|
}
|
|
3303
|
+
this.scheduleDrain(Math.max(this.flushIntervalMs, (retryAtMs != null ? retryAtMs : 0) - Date.now()));
|
|
3304
|
+
break;
|
|
2121
3305
|
}
|
|
2122
3306
|
}
|
|
3307
|
+
return fates;
|
|
3308
|
+
}
|
|
3309
|
+
/** See EventShipper.requestOpts — same deadline semantics. */
|
|
3310
|
+
requestOpts(deadlineAt) {
|
|
3311
|
+
const opts = this.scheduleFor(deadlineAt);
|
|
3312
|
+
return opts && { ...opts, cutOff: this.cutOff.signal };
|
|
2123
3313
|
}
|
|
2124
|
-
|
|
2125
|
-
requestOpts() {
|
|
3314
|
+
scheduleFor(deadlineAt) {
|
|
2126
3315
|
if (this.shutdownDeadlineAt !== void 0) {
|
|
2127
|
-
|
|
2128
|
-
if (remainingMs <= 0) return null;
|
|
3316
|
+
if (this.shutdownDeadlineAt - Date.now() <= 0) return null;
|
|
2129
3317
|
return {
|
|
2130
|
-
maxAttempts:
|
|
3318
|
+
maxAttempts: 3,
|
|
2131
3319
|
debug: this.debug,
|
|
2132
3320
|
sdkName: this.sdkName,
|
|
2133
|
-
|
|
3321
|
+
deadlineAt: Math.min(this.shutdownDeadlineAt, deadlineAt != null ? deadlineAt : Infinity)
|
|
2134
3322
|
};
|
|
2135
3323
|
}
|
|
2136
3324
|
if (this.hasShutdown) {
|
|
@@ -2141,27 +3329,28 @@ var TraceShipper = class {
|
|
|
2141
3329
|
timeoutMs: POST_SHUTDOWN_TIMEOUT_MS
|
|
2142
3330
|
};
|
|
2143
3331
|
}
|
|
2144
|
-
return { maxAttempts: 3, debug: this.debug, sdkName: this.sdkName };
|
|
3332
|
+
return { maxAttempts: 3, debug: this.debug, sdkName: this.sdkName, deadlineAt };
|
|
2145
3333
|
}
|
|
3334
|
+
/**
|
|
3335
|
+
* Flush within `flushTimeoutMs` and stop; spans left at the deadline are
|
|
3336
|
+
* dropped with a warning. Resolves, never rejects.
|
|
3337
|
+
*/
|
|
2146
3338
|
async shutdown() {
|
|
2147
3339
|
this.hasShutdown = true;
|
|
2148
|
-
|
|
3340
|
+
const deadlineAt = Date.now() + this.flushTimeoutMs;
|
|
3341
|
+
this.shutdownDeadlineAt = deadlineAt;
|
|
3342
|
+
let result = { ...DELIVERED };
|
|
2149
3343
|
try {
|
|
2150
3344
|
if (this.timer) {
|
|
2151
3345
|
clearTimeout(this.timer);
|
|
2152
3346
|
this.timer = void 0;
|
|
2153
3347
|
}
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
await Promise.all([...this.inFlight].map((p) => p.catch(() => {
|
|
2157
|
-
})));
|
|
2158
|
-
};
|
|
2159
|
-
const settled = await raceWithTimeout(drain(), SHUTDOWN_DEADLINE_MS);
|
|
2160
|
-
if (!settled) {
|
|
3348
|
+
result = await this.drainWithin(deadlineAt);
|
|
3349
|
+
if (!result.delivered) {
|
|
2161
3350
|
rateLimitedLog(
|
|
2162
3351
|
`${this.prefix}.shutdown_deadline`,
|
|
2163
3352
|
() => console.warn(
|
|
2164
|
-
`${this.prefix} shutdown flush deadline exceeded;
|
|
3353
|
+
`${this.prefix} shutdown flush deadline exceeded; ${describeUndelivered("shutdown()", result)}`
|
|
2165
3354
|
)
|
|
2166
3355
|
);
|
|
2167
3356
|
}
|
|
@@ -2169,10 +3358,74 @@ var TraceShipper = class {
|
|
|
2169
3358
|
this.shutdownDeadlineAt = void 0;
|
|
2170
3359
|
if (this.ownsAppGitContext) this.appGitContext.dispose();
|
|
2171
3360
|
}
|
|
3361
|
+
return asCompat(result);
|
|
2172
3362
|
}
|
|
2173
3363
|
};
|
|
3364
|
+
function eventShipperOptions(client, extras = {}) {
|
|
3365
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i;
|
|
3366
|
+
return {
|
|
3367
|
+
...extras,
|
|
3368
|
+
writeKey: (_a = extras.writeKey) != null ? _a : client.writeKey,
|
|
3369
|
+
endpoint: (_b = extras.endpoint) != null ? _b : client.endpoint,
|
|
3370
|
+
projectId: (_c = extras.projectId) != null ? _c : client.projectId,
|
|
3371
|
+
debug: (_e = (_d = extras.debug) != null ? _d : client.debug) != null ? _e : false,
|
|
3372
|
+
maxTextFieldChars: (_f = extras.maxTextFieldChars) != null ? _f : client.maxTextFieldChars,
|
|
3373
|
+
flushTimeoutMs: (_g = extras.flushTimeoutMs) != null ? _g : client.flushTimeoutMs,
|
|
3374
|
+
redactPii: (_h = extras.redactPii) != null ? _h : client.redactPii,
|
|
3375
|
+
redactPiiFields: (_i = extras.redactPiiFields) != null ? _i : client.redactPiiFields
|
|
3376
|
+
};
|
|
3377
|
+
}
|
|
3378
|
+
function traceShipperOptions(client, extras = {}) {
|
|
3379
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
3380
|
+
return {
|
|
3381
|
+
...extras,
|
|
3382
|
+
writeKey: (_a = extras.writeKey) != null ? _a : client.writeKey,
|
|
3383
|
+
endpoint: (_b = extras.endpoint) != null ? _b : client.endpoint,
|
|
3384
|
+
projectId: (_c = extras.projectId) != null ? _c : client.projectId,
|
|
3385
|
+
debug: (_e = (_d = extras.debug) != null ? _d : client.debug) != null ? _e : false,
|
|
3386
|
+
maxTextFieldChars: (_f = extras.maxTextFieldChars) != null ? _f : client.maxTextFieldChars,
|
|
3387
|
+
flushTimeoutMs: (_g = extras.flushTimeoutMs) != null ? _g : client.flushTimeoutMs
|
|
3388
|
+
};
|
|
3389
|
+
}
|
|
3390
|
+
function createShippers(client, setup = {}) {
|
|
3391
|
+
return {
|
|
3392
|
+
eventShipper: new EventShipper(eventShipperOptions(client, { ...setup.common, ...setup.event })),
|
|
3393
|
+
traceShipper: new TraceShipper(traceShipperOptions(client, { ...setup.common, ...setup.trace }))
|
|
3394
|
+
};
|
|
3395
|
+
}
|
|
3396
|
+
function isFlushResult(value) {
|
|
3397
|
+
return typeof value === "object" && value !== null && "delivered" in value && typeof value.delivered === "boolean" && "dropped" in value && typeof value.dropped === "number" && "queued" in value && typeof value.queued === "number" && "inFlight" in value && typeof value.inFlight === "number" && "timedOut" in value && typeof value.timedOut === "boolean";
|
|
3398
|
+
}
|
|
3399
|
+
var UNDELIVERED = Object.freeze({
|
|
3400
|
+
delivered: false,
|
|
3401
|
+
timedOut: false,
|
|
3402
|
+
dropped: 0,
|
|
3403
|
+
queued: 0,
|
|
3404
|
+
inFlight: 0
|
|
3405
|
+
});
|
|
3406
|
+
async function settle(call, what) {
|
|
3407
|
+
try {
|
|
3408
|
+
const result = await call();
|
|
3409
|
+
return isFlushResult(result) ? result : DELIVERED;
|
|
3410
|
+
} catch (error) {
|
|
3411
|
+
console.warn(`[raindrop-ai] ${what} failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
3412
|
+
return UNDELIVERED;
|
|
3413
|
+
}
|
|
3414
|
+
}
|
|
3415
|
+
async function flushShippers(...shippers) {
|
|
3416
|
+
const results = await Promise.all(
|
|
3417
|
+
shippers.flatMap((s) => s ? [settle(() => s.flush(), "flush()")] : [])
|
|
3418
|
+
);
|
|
3419
|
+
return asCompat(combineResults(...results));
|
|
3420
|
+
}
|
|
3421
|
+
async function shutdownShippers(...shippers) {
|
|
3422
|
+
const results = await Promise.all(
|
|
3423
|
+
shippers.flatMap((s) => s ? [settle(() => s.shutdown(), "shutdown()")] : [])
|
|
3424
|
+
);
|
|
3425
|
+
return asCompat(combineResults(...results));
|
|
3426
|
+
}
|
|
2174
3427
|
var PROMPT_TOOLS_ATTRIBUTE = "ai.prompt.tools";
|
|
2175
|
-
function
|
|
3428
|
+
function isRecord3(value) {
|
|
2176
3429
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2177
3430
|
}
|
|
2178
3431
|
var JSON_SCHEMA_KEYS = [
|
|
@@ -2190,17 +3443,17 @@ var JSON_SCHEMA_KEYS = [
|
|
|
2190
3443
|
"required"
|
|
2191
3444
|
];
|
|
2192
3445
|
function isJsonSchema(value) {
|
|
2193
|
-
if (!
|
|
3446
|
+
if (!isRecord3(value)) return false;
|
|
2194
3447
|
if (typeof value["~standard"] === "object") return false;
|
|
2195
|
-
if (
|
|
3448
|
+
if (isRecord3(value._def) || isRecord3(value._zod)) return false;
|
|
2196
3449
|
if (Object.keys(value).length === 0) return true;
|
|
2197
3450
|
return JSON_SCHEMA_KEYS.some((key) => key in value);
|
|
2198
3451
|
}
|
|
2199
3452
|
function toJsonSchema(value, options) {
|
|
2200
3453
|
if (value === void 0 || value === null) return void 0;
|
|
2201
3454
|
if (isJsonSchema(value)) return value;
|
|
2202
|
-
if (
|
|
2203
|
-
if (
|
|
3455
|
+
if (isRecord3(value) && isJsonSchema(value.jsonSchema)) return value.jsonSchema;
|
|
3456
|
+
if (isRecord3(value) && isJsonSchema(value.json)) return value.json;
|
|
2204
3457
|
if (options == null ? void 0 : options.schema) {
|
|
2205
3458
|
try {
|
|
2206
3459
|
return options.schema(value);
|
|
@@ -2223,23 +3476,23 @@ function functionTool(name, description, schema, options) {
|
|
|
2223
3476
|
}
|
|
2224
3477
|
function normalizeToolDeclaration(tool, options, fallbackName) {
|
|
2225
3478
|
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
|
|
2226
|
-
if (!
|
|
3479
|
+
if (!isRecord3(tool)) return void 0;
|
|
2227
3480
|
if (tool.type === "provider-defined" || tool.type === "provider") {
|
|
2228
3481
|
const name2 = (_b = (_a = pickString(tool.name)) != null ? _a : pickString(tool.id)) != null ? _b : fallbackName;
|
|
2229
3482
|
if (name2 === void 0) return void 0;
|
|
2230
3483
|
const declaration = { type: "provider-defined", name: name2 };
|
|
2231
3484
|
const id = pickString(tool.id);
|
|
2232
3485
|
if (id !== void 0) declaration.id = id;
|
|
2233
|
-
if (
|
|
3486
|
+
if (isRecord3(tool.args)) declaration.args = tool.args;
|
|
2234
3487
|
return declaration;
|
|
2235
3488
|
}
|
|
2236
|
-
if (
|
|
3489
|
+
if (isRecord3(tool.toolSpec)) {
|
|
2237
3490
|
const spec = tool.toolSpec;
|
|
2238
3491
|
const name2 = (_c = pickString(spec.name)) != null ? _c : fallbackName;
|
|
2239
3492
|
if (name2 === void 0) return void 0;
|
|
2240
3493
|
return functionTool(name2, spec.description, spec.inputSchema, options);
|
|
2241
3494
|
}
|
|
2242
|
-
if (
|
|
3495
|
+
if (isRecord3(tool.function)) {
|
|
2243
3496
|
const fn = tool.function;
|
|
2244
3497
|
const name2 = (_d = pickString(fn.name)) != null ? _d : fallbackName;
|
|
2245
3498
|
if (name2 === void 0) return void 0;
|
|
@@ -2265,7 +3518,7 @@ function isGeminiToolGroup(tool) {
|
|
|
2265
3518
|
if (Array.isArray(tool.functionDeclarations)) return true;
|
|
2266
3519
|
const keys = Object.keys(tool);
|
|
2267
3520
|
if (keys.length === 0 || NOT_A_GEMINI_GROUP_KEYS.some((key) => key in tool)) return false;
|
|
2268
|
-
return keys.every((key) =>
|
|
3521
|
+
return keys.every((key) => isRecord3(tool[key]));
|
|
2269
3522
|
}
|
|
2270
3523
|
function expandGeminiTool(tool, options) {
|
|
2271
3524
|
const declarations = [];
|
|
@@ -2275,7 +3528,7 @@ function expandGeminiTool(tool, options) {
|
|
|
2275
3528
|
const normalized = normalizeToolDeclaration(declaration, options);
|
|
2276
3529
|
if (normalized) declarations.push(normalized);
|
|
2277
3530
|
}
|
|
2278
|
-
} else if (
|
|
3531
|
+
} else if (isRecord3(value)) {
|
|
2279
3532
|
declarations.push({ type: "provider-defined", id: key, name: key, args: value });
|
|
2280
3533
|
}
|
|
2281
3534
|
}
|
|
@@ -2285,14 +3538,14 @@ function normalizeToolDeclarations(tools, options) {
|
|
|
2285
3538
|
if (tools === void 0 || tools === null) return void 0;
|
|
2286
3539
|
if (Array.isArray(tools)) {
|
|
2287
3540
|
return tools.flatMap((tool) => {
|
|
2288
|
-
if (
|
|
3541
|
+
if (isRecord3(tool) && isGeminiToolGroup(tool)) {
|
|
2289
3542
|
return expandGeminiTool(tool, options);
|
|
2290
3543
|
}
|
|
2291
3544
|
const declaration = normalizeToolDeclaration(tool, options);
|
|
2292
3545
|
return declaration ? [declaration] : [];
|
|
2293
3546
|
});
|
|
2294
3547
|
}
|
|
2295
|
-
if (!
|
|
3548
|
+
if (!isRecord3(tools)) return void 0;
|
|
2296
3549
|
return Object.entries(tools).flatMap(([key, tool]) => {
|
|
2297
3550
|
const declaration = normalizeToolDeclaration(tool, options, key);
|
|
2298
3551
|
return declaration ? [declaration] : [];
|
|
@@ -2438,39 +3691,6 @@ var resolveLocal = (sourceDirectory, detectBranch, completed) => {
|
|
|
2438
3691
|
function createAppGitContext2(options, runtime = {}) {
|
|
2439
3692
|
return new AppGitContext(options, { ...runtime, resolveLocal });
|
|
2440
3693
|
}
|
|
2441
|
-
function hasDestination(options) {
|
|
2442
|
-
var _a;
|
|
2443
|
-
if (options.enabled === false) return false;
|
|
2444
|
-
return Boolean(((_a = options.writeKey) == null ? void 0 : _a.trim()) || resolveLocalDebuggerBaseUrl(options.localDebuggerUrl));
|
|
2445
|
-
}
|
|
2446
|
-
var EventShipper2 = class extends EventShipper {
|
|
2447
|
-
constructor(options) {
|
|
2448
|
-
var _a;
|
|
2449
|
-
const ownsAppGitContext = options.appGitContext === void 0;
|
|
2450
|
-
const appGitContext = (_a = options.appGitContext) != null ? _a : createAppGitContext2(options.appGit, { allowDiscovery: hasDestination(options) });
|
|
2451
|
-
try {
|
|
2452
|
-
super({ ...options, appGitContext });
|
|
2453
|
-
} catch (error) {
|
|
2454
|
-
if (ownsAppGitContext) appGitContext.dispose();
|
|
2455
|
-
throw error;
|
|
2456
|
-
}
|
|
2457
|
-
if (ownsAppGitContext) this.ownAppGitContextForShutdown();
|
|
2458
|
-
}
|
|
2459
|
-
};
|
|
2460
|
-
var TraceShipper2 = class extends TraceShipper {
|
|
2461
|
-
constructor(options) {
|
|
2462
|
-
var _a;
|
|
2463
|
-
const ownsAppGitContext = options.appGitContext === void 0;
|
|
2464
|
-
const appGitContext = (_a = options.appGitContext) != null ? _a : createAppGitContext2(options.appGit, { allowDiscovery: hasDestination(options) });
|
|
2465
|
-
try {
|
|
2466
|
-
super({ ...options, appGitContext });
|
|
2467
|
-
} catch (error) {
|
|
2468
|
-
if (ownsAppGitContext) appGitContext.dispose();
|
|
2469
|
-
throw error;
|
|
2470
|
-
}
|
|
2471
|
-
this.ownsAppGitContext = ownsAppGitContext;
|
|
2472
|
-
}
|
|
2473
|
-
};
|
|
2474
3694
|
globalThis.RAINDROP_ASYNC_LOCAL_STORAGE = AsyncLocalStorage;
|
|
2475
3695
|
var SUPPRESS_TRACING_KEY = /* @__PURE__ */ Symbol.for(
|
|
2476
3696
|
"OpenTelemetry SDK Context Key SUPPRESS_TRACING"
|
|
@@ -2608,6 +3828,8 @@ var RaindropManagedAgentsHandler = class {
|
|
|
2608
3828
|
eventName: (_e = context.eventName) != null ? _e : "ai_generation",
|
|
2609
3829
|
input: void 0,
|
|
2610
3830
|
model: void 0,
|
|
3831
|
+
// Caller-supplied properties win over the derived keys below (W6).
|
|
3832
|
+
callerProperties: context.properties,
|
|
2611
3833
|
properties: {
|
|
2612
3834
|
...context.properties,
|
|
2613
3835
|
"ai.provider": "openai",
|
|
@@ -2928,7 +4150,7 @@ function isRecord2(value) {
|
|
|
2928
4150
|
// package.json
|
|
2929
4151
|
var package_default = {
|
|
2930
4152
|
name: "@raindrop-ai/openai-managed-agents",
|
|
2931
|
-
version: "0.0.
|
|
4153
|
+
version: "0.0.5",
|
|
2932
4154
|
description: "Raindrop tracing for the OpenAI Agents API",
|
|
2933
4155
|
main: "dist/index.js",
|
|
2934
4156
|
module: "dist/index.mjs",
|
|
@@ -3096,7 +4318,7 @@ function wrapManagedAgents(client, handler, context) {
|
|
|
3096
4318
|
|
|
3097
4319
|
// src/index.ts
|
|
3098
4320
|
function createRaindropOpenAIManagedAgents(opts = {}) {
|
|
3099
|
-
var _a
|
|
4321
|
+
var _a;
|
|
3100
4322
|
const enabled = Boolean((_a = opts.writeKey) == null ? void 0 : _a.trim());
|
|
3101
4323
|
if (!enabled)
|
|
3102
4324
|
console.warn(
|
|
@@ -3105,44 +4327,33 @@ function createRaindropOpenAIManagedAgents(opts = {}) {
|
|
|
3105
4327
|
const appGitContext = createAppGitContext2(enabled ? opts.appGit : false, {
|
|
3106
4328
|
allowLocalGit: false
|
|
3107
4329
|
});
|
|
3108
|
-
const
|
|
3109
|
-
|
|
3110
|
-
|
|
3111
|
-
|
|
3112
|
-
|
|
3113
|
-
|
|
3114
|
-
|
|
3115
|
-
libraryName,
|
|
3116
|
-
libraryVersion
|
|
3117
|
-
appGitContext,
|
|
3118
|
-
maxTextFieldChars: opts.maxTextFieldChars,
|
|
3119
|
-
localDebuggerUrl: opts.localWorkshopUrl === false ? null : opts.localWorkshopUrl
|
|
3120
|
-
};
|
|
3121
|
-
const events = new EventShipper2(shipperOptions);
|
|
3122
|
-
const traces = new TraceShipper2({
|
|
3123
|
-
...shipperOptions,
|
|
3124
|
-
serviceName: "raindrop.openai-managed-agents",
|
|
3125
|
-
serviceVersion: libraryVersion
|
|
4330
|
+
const { eventShipper: events, traceShipper: traces } = createShippers(opts, {
|
|
4331
|
+
common: {
|
|
4332
|
+
enabled,
|
|
4333
|
+
sdkName: "openai-managed-agents",
|
|
4334
|
+
appGitContext,
|
|
4335
|
+
localDebuggerUrl: opts.localWorkshopUrl === false ? null : opts.localWorkshopUrl
|
|
4336
|
+
},
|
|
4337
|
+
event: { libraryName, libraryVersion },
|
|
4338
|
+
trace: { serviceName: "raindrop.openai-managed-agents", serviceVersion: libraryVersion }
|
|
3126
4339
|
});
|
|
3127
4340
|
const handler = new RaindropManagedAgentsHandler(events, traces, opts);
|
|
3128
4341
|
return {
|
|
3129
4342
|
handler,
|
|
3130
4343
|
wrap: (client, context) => wrapManagedAgents(client, handler, context),
|
|
3131
|
-
|
|
3132
|
-
|
|
3133
|
-
finish: (id, patch) => events.finish(id, patch),
|
|
3134
|
-
addAttachments: (id, attachments) => events.patch(id, { attachments }),
|
|
3135
|
-
setProperties: (id, properties) => events.patch(id, { properties })
|
|
4344
|
+
get lastEventId() {
|
|
4345
|
+
return events == null ? void 0 : events.lastFinishedEventId;
|
|
3136
4346
|
},
|
|
4347
|
+
events: createEventsApi(events),
|
|
3137
4348
|
users: { identify: (users) => events.identify(users) },
|
|
3138
4349
|
signals: { track: (signal) => events.trackSignal(signal) },
|
|
3139
|
-
|
|
3140
|
-
|
|
4350
|
+
flush() {
|
|
4351
|
+
return flushShippers(events, traces);
|
|
3141
4352
|
},
|
|
3142
4353
|
async shutdown() {
|
|
3143
4354
|
try {
|
|
3144
4355
|
handler.shutdown();
|
|
3145
|
-
await
|
|
4356
|
+
return await shutdownShippers(events, traces);
|
|
3146
4357
|
} finally {
|
|
3147
4358
|
appGitContext.dispose();
|
|
3148
4359
|
}
|