lua-cli 3.37.0 → 3.39.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api-exports.d.ts +99 -0
- package/dist/api-exports.js +1130 -2
- package/dist/api-exports.js.map +1 -1
- package/dist/index.js +3788 -229
- package/dist/index.js.map +1 -1
- package/dist/workflow-builder.js +1114 -0
- package/dist/workflow-builder.js.map +1 -1
- package/docs/CLI_REFERENCE.md +16 -1
- package/docs/README.md +2 -2
- package/package.json +3 -3
- package/template/package.json +1 -1
package/dist/workflow-builder.js
CHANGED
|
@@ -10,6 +10,39 @@ import { z as z2 } from "zod";
|
|
|
10
10
|
import { z as z3 } from "zod";
|
|
11
11
|
var __defProp2 = Object.defineProperty;
|
|
12
12
|
var __name2 = /* @__PURE__ */ __name((target, value3) => __defProp2(target, "name", { value: value3, configurable: true }), "__name");
|
|
13
|
+
var PLUMBING_THREAD_CHANNELS = [
|
|
14
|
+
"trigger",
|
|
15
|
+
"template-install",
|
|
16
|
+
"template-uninstall"
|
|
17
|
+
];
|
|
18
|
+
var CHANNEL_CONVERSATION_CHANNELS = [
|
|
19
|
+
"whatsapp",
|
|
20
|
+
"slack",
|
|
21
|
+
"teams",
|
|
22
|
+
"front",
|
|
23
|
+
"email",
|
|
24
|
+
"messagebird",
|
|
25
|
+
"sms",
|
|
26
|
+
"mms",
|
|
27
|
+
"rcs",
|
|
28
|
+
"instagram",
|
|
29
|
+
"facebook",
|
|
30
|
+
"imessage"
|
|
31
|
+
];
|
|
32
|
+
var HIDDEN_THREAD_CHANNELS = [
|
|
33
|
+
...PLUMBING_THREAD_CHANNELS,
|
|
34
|
+
...CHANNEL_CONVERSATION_CHANNELS
|
|
35
|
+
];
|
|
36
|
+
function isChannelConversationChannel(channel) {
|
|
37
|
+
return !!channel && CHANNEL_CONVERSATION_CHANNELS.includes(channel);
|
|
38
|
+
}
|
|
39
|
+
__name(isChannelConversationChannel, "isChannelConversationChannel");
|
|
40
|
+
__name2(isChannelConversationChannel, "isChannelConversationChannel");
|
|
41
|
+
function isChannelConversationThread(threadId, channel) {
|
|
42
|
+
return !!threadId && isChannelConversationChannel(channel);
|
|
43
|
+
}
|
|
44
|
+
__name(isChannelConversationThread, "isChannelConversationThread");
|
|
45
|
+
__name2(isChannelConversationThread, "isChannelConversationThread");
|
|
13
46
|
function isPersonaTextObject(value3) {
|
|
14
47
|
if (value3 === null || typeof value3 !== "object" || Array.isArray(value3)) return false;
|
|
15
48
|
const obj = value3;
|
|
@@ -631,6 +664,199 @@ var BROWSER_COMMANDS = [
|
|
|
631
664
|
}
|
|
632
665
|
];
|
|
633
666
|
var BROWSER_COMMAND_NAMES = BROWSER_COMMANDS.map((c) => c.name);
|
|
667
|
+
var LOG_FIELDS_MAX_KEYS = 32;
|
|
668
|
+
var LOG_FIELD_MAX_VALUE_BYTES = 1024;
|
|
669
|
+
var LOG_FIELDS_MAX_BYTES = 8192;
|
|
670
|
+
var LOG_FIELD_KEY_PATTERN = /^[a-z][a-z0-9_]{0,63}$/;
|
|
671
|
+
var LOG_FIELD_SECRET_SHAPED_KEY_PATTERNS = Object.freeze([
|
|
672
|
+
/^api_[0-9a-f]{24,}$/,
|
|
673
|
+
/^gh[pousr]_[a-z0-9]{36}$/,
|
|
674
|
+
/^(?:sk|rk|pk)_(?:live|test)_[a-z0-9]{16,}$/,
|
|
675
|
+
/^lua_hc_[a-z0-9]{20,}/,
|
|
676
|
+
/^lua_sk_[a-z0-9]{20,}/
|
|
677
|
+
]);
|
|
678
|
+
var LOG_FIELDS_CLAMPED_KEY = "lua_fields_clamped";
|
|
679
|
+
var LOG_FIELD_ARRAY_COUNT_SUFFIX = ".count";
|
|
680
|
+
var LuaLogFieldsError = class _LuaLogFieldsError extends Error {
|
|
681
|
+
static {
|
|
682
|
+
__name(this, "_LuaLogFieldsError");
|
|
683
|
+
}
|
|
684
|
+
static {
|
|
685
|
+
__name2(this, "LuaLogFieldsError");
|
|
686
|
+
}
|
|
687
|
+
constructor(message) {
|
|
688
|
+
super(message);
|
|
689
|
+
this.name = "LuaLogFieldsError";
|
|
690
|
+
Object.setPrototypeOf(this, _LuaLogFieldsError.prototype);
|
|
691
|
+
}
|
|
692
|
+
};
|
|
693
|
+
function utf8WidthAt(value3, index) {
|
|
694
|
+
const code = value3.charCodeAt(index);
|
|
695
|
+
if (code < 128) return {
|
|
696
|
+
bytes: 1,
|
|
697
|
+
units: 1
|
|
698
|
+
};
|
|
699
|
+
if (code < 2048) return {
|
|
700
|
+
bytes: 2,
|
|
701
|
+
units: 1
|
|
702
|
+
};
|
|
703
|
+
if (code >= 55296 && code <= 56319) {
|
|
704
|
+
const next = value3.charCodeAt(index + 1);
|
|
705
|
+
if (next >= 56320 && next <= 57343) return {
|
|
706
|
+
bytes: 4,
|
|
707
|
+
units: 2
|
|
708
|
+
};
|
|
709
|
+
}
|
|
710
|
+
return {
|
|
711
|
+
bytes: 3,
|
|
712
|
+
units: 1
|
|
713
|
+
};
|
|
714
|
+
}
|
|
715
|
+
__name(utf8WidthAt, "utf8WidthAt");
|
|
716
|
+
__name2(utf8WidthAt, "utf8WidthAt");
|
|
717
|
+
function utf8ByteLength(value3) {
|
|
718
|
+
let bytes = 0;
|
|
719
|
+
for (let i = 0; i < value3.length; ) {
|
|
720
|
+
const width = utf8WidthAt(value3, i);
|
|
721
|
+
bytes += width.bytes;
|
|
722
|
+
i += width.units;
|
|
723
|
+
}
|
|
724
|
+
return bytes;
|
|
725
|
+
}
|
|
726
|
+
__name(utf8ByteLength, "utf8ByteLength");
|
|
727
|
+
__name2(utf8ByteLength, "utf8ByteLength");
|
|
728
|
+
function clampUtf8(value3, maxBytes) {
|
|
729
|
+
let bytes = 0;
|
|
730
|
+
for (let i = 0; i < value3.length; ) {
|
|
731
|
+
const width = utf8WidthAt(value3, i);
|
|
732
|
+
if (bytes + width.bytes > maxBytes) return value3.slice(0, i);
|
|
733
|
+
bytes += width.bytes;
|
|
734
|
+
i += width.units;
|
|
735
|
+
}
|
|
736
|
+
return value3;
|
|
737
|
+
}
|
|
738
|
+
__name(clampUtf8, "clampUtf8");
|
|
739
|
+
__name2(clampUtf8, "clampUtf8");
|
|
740
|
+
function mapBytes(fields, withMark) {
|
|
741
|
+
return utf8ByteLength(JSON.stringify(withMark ? {
|
|
742
|
+
...fields,
|
|
743
|
+
[LOG_FIELDS_CLAMPED_KEY]: true
|
|
744
|
+
} : fields));
|
|
745
|
+
}
|
|
746
|
+
__name(mapBytes, "mapBytes");
|
|
747
|
+
__name2(mapBytes, "mapBytes");
|
|
748
|
+
function withValueCap(fields, capBytes) {
|
|
749
|
+
const out = {};
|
|
750
|
+
for (const [key, value3] of Object.entries(fields)) {
|
|
751
|
+
out[key] = typeof value3 === "string" ? clampUtf8(value3, capBytes) : value3;
|
|
752
|
+
}
|
|
753
|
+
return out;
|
|
754
|
+
}
|
|
755
|
+
__name(withValueCap, "withValueCap");
|
|
756
|
+
__name2(withValueCap, "withValueCap");
|
|
757
|
+
function describeValue(value3) {
|
|
758
|
+
if (value3 === null) return "null";
|
|
759
|
+
if (value3 === void 0) return "undefined";
|
|
760
|
+
if (Array.isArray(value3)) return "an array";
|
|
761
|
+
return typeof value3 === "object" ? "an object" : `a ${typeof value3}`;
|
|
762
|
+
}
|
|
763
|
+
__name(describeValue, "describeValue");
|
|
764
|
+
__name2(describeValue, "describeValue");
|
|
765
|
+
function assertValidLogFieldKey(key) {
|
|
766
|
+
if (!LOG_FIELD_KEY_PATTERN.test(key)) {
|
|
767
|
+
throw new LuaLogFieldsError(`log fields: key \`${key}\` is not allowed \u2014 a key must match ${LOG_FIELD_KEY_PATTERN.source} (lower-case, starts with a letter, then letters/digits/underscore, at most 64 characters)`);
|
|
768
|
+
}
|
|
769
|
+
if (LOG_FIELD_SECRET_SHAPED_KEY_PATTERNS.some((pattern) => pattern.test(key))) {
|
|
770
|
+
throw new LuaLogFieldsError(`log fields: key \`${key}\` is not allowed \u2014 it has the shape of a credential that the log-drain scrubber masks in values; a field KEY is never scrubbed, so it may never carry a secret shape`);
|
|
771
|
+
}
|
|
772
|
+
if (key === LOG_FIELDS_CLAMPED_KEY) {
|
|
773
|
+
throw new LuaLogFieldsError(`log fields: key \`${key}\` is reserved \u2014 the platform sets it to mark a field map it had to clamp`);
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
__name(assertValidLogFieldKey, "assertValidLogFieldKey");
|
|
777
|
+
__name2(assertValidLogFieldKey, "assertValidLogFieldKey");
|
|
778
|
+
function normalizeLogFields(fields) {
|
|
779
|
+
if (fields === void 0 || fields === null) return void 0;
|
|
780
|
+
if (typeof fields !== "object" || Array.isArray(fields)) {
|
|
781
|
+
throw new LuaLogFieldsError(`log fields: expected a plain object of fields, received ${describeValue(fields)}`);
|
|
782
|
+
}
|
|
783
|
+
const entries = Object.entries(fields);
|
|
784
|
+
if (entries.length > LOG_FIELDS_MAX_KEYS) {
|
|
785
|
+
throw new LuaLogFieldsError(`log fields: ${entries.length} keys exceeds the cap of ${LOG_FIELDS_MAX_KEYS} keys per call`);
|
|
786
|
+
}
|
|
787
|
+
const out = {};
|
|
788
|
+
for (const [key, value3] of entries) {
|
|
789
|
+
assertValidLogFieldKey(key);
|
|
790
|
+
if (typeof value3 === "string" || typeof value3 === "boolean") {
|
|
791
|
+
out[key] = value3;
|
|
792
|
+
continue;
|
|
793
|
+
}
|
|
794
|
+
if (typeof value3 === "number") {
|
|
795
|
+
if (!Number.isFinite(value3)) {
|
|
796
|
+
throw new LuaLogFieldsError(`log fields: \`${key}\` must be a finite number \u2014 NaN and Infinity have no JSON form`);
|
|
797
|
+
}
|
|
798
|
+
out[key] = value3;
|
|
799
|
+
continue;
|
|
800
|
+
}
|
|
801
|
+
if (Array.isArray(value3)) {
|
|
802
|
+
const parts = [];
|
|
803
|
+
for (const element of value3) {
|
|
804
|
+
if (typeof element !== "string") {
|
|
805
|
+
throw new LuaLogFieldsError(`log fields: \`${key}\` is an array, so every element must be a string (found ${describeValue(element)})`);
|
|
806
|
+
}
|
|
807
|
+
if (element.includes(",")) {
|
|
808
|
+
throw new LuaLogFieldsError(`log fields: \`${key}\` \u2014 an array element may not contain a comma; elements are comma-joined into one value (with \`${key}${LOG_FIELD_ARRAY_COUNT_SUFFIX}\` beside it), so a comma inside one would be indistinguishable from the separator`);
|
|
809
|
+
}
|
|
810
|
+
parts.push(element);
|
|
811
|
+
}
|
|
812
|
+
out[key] = parts.join(",");
|
|
813
|
+
out[`${key}${LOG_FIELD_ARRAY_COUNT_SUFFIX}`] = parts.length;
|
|
814
|
+
continue;
|
|
815
|
+
}
|
|
816
|
+
throw new LuaLogFieldsError(`log fields: \`${key}\` must be a string, number, boolean or string[] \u2014 received ${describeValue(value3)}` + (value3 !== null && typeof value3 === "object" ? " (nested objects are not supported)" : ""));
|
|
817
|
+
}
|
|
818
|
+
const keys = Object.keys(out);
|
|
819
|
+
if (keys.length === 0) return void 0;
|
|
820
|
+
if (keys.length > LOG_FIELDS_MAX_KEYS) {
|
|
821
|
+
throw new LuaLogFieldsError(`log fields: ${keys.length} keys exceeds the cap of ${LOG_FIELDS_MAX_KEYS} keys per call \u2014 an array field also contributes its \`${LOG_FIELD_ARRAY_COUNT_SUFFIX.slice(1)}\` sibling`);
|
|
822
|
+
}
|
|
823
|
+
if (clampLogFields(out)) out[LOG_FIELDS_CLAMPED_KEY] = true;
|
|
824
|
+
return out;
|
|
825
|
+
}
|
|
826
|
+
__name(normalizeLogFields, "normalizeLogFields");
|
|
827
|
+
__name2(normalizeLogFields, "normalizeLogFields");
|
|
828
|
+
function clampLogFields(out) {
|
|
829
|
+
let clamped = false;
|
|
830
|
+
for (const [key, value3] of Object.entries(out)) {
|
|
831
|
+
if (typeof value3 !== "string") continue;
|
|
832
|
+
const capped = clampUtf8(value3, LOG_FIELD_MAX_VALUE_BYTES);
|
|
833
|
+
if (capped !== value3) {
|
|
834
|
+
out[key] = capped;
|
|
835
|
+
clamped = true;
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
if (mapBytes(out, clamped) <= LOG_FIELDS_MAX_BYTES) return clamped;
|
|
839
|
+
const base = {
|
|
840
|
+
...out
|
|
841
|
+
};
|
|
842
|
+
let low = 0;
|
|
843
|
+
let high = LOG_FIELD_MAX_VALUE_BYTES;
|
|
844
|
+
let best = 0;
|
|
845
|
+
while (low <= high) {
|
|
846
|
+
const mid = Math.floor((low + high) / 2);
|
|
847
|
+
if (mapBytes(withValueCap(base, mid), true) <= LOG_FIELDS_MAX_BYTES) {
|
|
848
|
+
best = mid;
|
|
849
|
+
low = mid + 1;
|
|
850
|
+
} else {
|
|
851
|
+
high = mid - 1;
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
const fitted = withValueCap(base, best);
|
|
855
|
+
for (const key of Object.keys(out)) out[key] = fitted[key];
|
|
856
|
+
return true;
|
|
857
|
+
}
|
|
858
|
+
__name(clampLogFields, "clampLogFields");
|
|
859
|
+
__name2(clampLogFields, "clampLogFields");
|
|
634
860
|
var DESKTOP_FILE_COMMANDS = [
|
|
635
861
|
"files_roots",
|
|
636
862
|
"files_stat",
|
|
@@ -1174,6 +1400,894 @@ function buildPersonalSpaceStartingPersona(agentName) {
|
|
|
1174
1400
|
}
|
|
1175
1401
|
__name(buildPersonalSpaceStartingPersona, "buildPersonalSpaceStartingPersona");
|
|
1176
1402
|
__name2(buildPersonalSpaceStartingPersona, "buildPersonalSpaceStartingPersona");
|
|
1403
|
+
var AGENT_LOG_SOURCES = [
|
|
1404
|
+
"skill",
|
|
1405
|
+
"job",
|
|
1406
|
+
"webhook",
|
|
1407
|
+
"trigger",
|
|
1408
|
+
"preprocessor",
|
|
1409
|
+
"postprocessor",
|
|
1410
|
+
"user_message",
|
|
1411
|
+
"agent_response",
|
|
1412
|
+
"agent_error",
|
|
1413
|
+
"runtime",
|
|
1414
|
+
"mcp",
|
|
1415
|
+
"rag",
|
|
1416
|
+
"device",
|
|
1417
|
+
"device-trigger",
|
|
1418
|
+
"model-resolver",
|
|
1419
|
+
"workflow-step",
|
|
1420
|
+
"workflow-script",
|
|
1421
|
+
"workflow"
|
|
1422
|
+
];
|
|
1423
|
+
var AGENT_LOG_FIELDS_MAX_WIRE_KEYS = LOG_FIELDS_MAX_KEYS + 1;
|
|
1424
|
+
function utf8Bytes(value3) {
|
|
1425
|
+
let bytes = 0;
|
|
1426
|
+
for (let i = 0; i < value3.length; ) {
|
|
1427
|
+
const code = value3.charCodeAt(i);
|
|
1428
|
+
if (code < 128) {
|
|
1429
|
+
bytes += 1;
|
|
1430
|
+
i += 1;
|
|
1431
|
+
} else if (code < 2048) {
|
|
1432
|
+
bytes += 2;
|
|
1433
|
+
i += 1;
|
|
1434
|
+
} else if (code >= 55296 && code <= 56319) {
|
|
1435
|
+
const next = value3.charCodeAt(i + 1);
|
|
1436
|
+
if (next >= 56320 && next <= 57343) {
|
|
1437
|
+
bytes += 4;
|
|
1438
|
+
i += 2;
|
|
1439
|
+
} else {
|
|
1440
|
+
bytes += 3;
|
|
1441
|
+
i += 1;
|
|
1442
|
+
}
|
|
1443
|
+
} else {
|
|
1444
|
+
bytes += 3;
|
|
1445
|
+
i += 1;
|
|
1446
|
+
}
|
|
1447
|
+
}
|
|
1448
|
+
return bytes;
|
|
1449
|
+
}
|
|
1450
|
+
__name(utf8Bytes, "utf8Bytes");
|
|
1451
|
+
__name2(utf8Bytes, "utf8Bytes");
|
|
1452
|
+
function isPlainFieldKey(key) {
|
|
1453
|
+
if (!LOG_FIELD_KEY_PATTERN.test(key)) return false;
|
|
1454
|
+
return !LOG_FIELD_SECRET_SHAPED_KEY_PATTERNS.some((pattern) => pattern.test(key));
|
|
1455
|
+
}
|
|
1456
|
+
__name(isPlainFieldKey, "isPlainFieldKey");
|
|
1457
|
+
__name2(isPlainFieldKey, "isPlainFieldKey");
|
|
1458
|
+
function describeAgentLogFieldsViolation(value3) {
|
|
1459
|
+
if (typeof value3 !== "object" || value3 === null || Array.isArray(value3)) {
|
|
1460
|
+
return "fields must be an object";
|
|
1461
|
+
}
|
|
1462
|
+
const entries = Object.entries(value3);
|
|
1463
|
+
let userKeys = 0;
|
|
1464
|
+
for (const [key, entry] of entries) {
|
|
1465
|
+
if (key === LOG_FIELDS_CLAMPED_KEY) {
|
|
1466
|
+
if (entry !== true) return `fields.${key} must be true`;
|
|
1467
|
+
continue;
|
|
1468
|
+
}
|
|
1469
|
+
userKeys += 1;
|
|
1470
|
+
if (key.endsWith(LOG_FIELD_ARRAY_COUNT_SUFFIX)) {
|
|
1471
|
+
const base = key.slice(0, -LOG_FIELD_ARRAY_COUNT_SUFFIX.length);
|
|
1472
|
+
if (!isPlainFieldKey(base)) return `fields key \`${key}\` is not a legal field key`;
|
|
1473
|
+
if (typeof entry !== "number" || !Number.isFinite(entry)) {
|
|
1474
|
+
return `fields.${key} must be a finite number`;
|
|
1475
|
+
}
|
|
1476
|
+
continue;
|
|
1477
|
+
}
|
|
1478
|
+
if (!isPlainFieldKey(key)) return `fields key \`${key}\` is not a legal field key`;
|
|
1479
|
+
if (typeof entry === "string") {
|
|
1480
|
+
if (utf8Bytes(entry) > LOG_FIELD_MAX_VALUE_BYTES) {
|
|
1481
|
+
return `fields.${key} exceeds ${LOG_FIELD_MAX_VALUE_BYTES} bytes`;
|
|
1482
|
+
}
|
|
1483
|
+
continue;
|
|
1484
|
+
}
|
|
1485
|
+
if (typeof entry === "boolean") continue;
|
|
1486
|
+
if (typeof entry === "number") {
|
|
1487
|
+
if (!Number.isFinite(entry)) return `fields.${key} must be a finite number`;
|
|
1488
|
+
continue;
|
|
1489
|
+
}
|
|
1490
|
+
return `fields.${key} must be a string, number or boolean`;
|
|
1491
|
+
}
|
|
1492
|
+
if (userKeys > LOG_FIELDS_MAX_KEYS) {
|
|
1493
|
+
return `fields has ${userKeys} keys, over the cap of ${LOG_FIELDS_MAX_KEYS}`;
|
|
1494
|
+
}
|
|
1495
|
+
if (utf8Bytes(JSON.stringify(value3)) > LOG_FIELDS_MAX_BYTES) {
|
|
1496
|
+
return `fields exceeds ${LOG_FIELDS_MAX_BYTES} bytes`;
|
|
1497
|
+
}
|
|
1498
|
+
return void 0;
|
|
1499
|
+
}
|
|
1500
|
+
__name(describeAgentLogFieldsViolation, "describeAgentLogFieldsViolation");
|
|
1501
|
+
__name2(describeAgentLogFieldsViolation, "describeAgentLogFieldsViolation");
|
|
1502
|
+
function isAgentLogFields(value3) {
|
|
1503
|
+
return describeAgentLogFieldsViolation(value3) === void 0;
|
|
1504
|
+
}
|
|
1505
|
+
__name(isAgentLogFields, "isAgentLogFields");
|
|
1506
|
+
__name2(isAgentLogFields, "isAgentLogFields");
|
|
1507
|
+
var LOG_DRAIN_TYPES_PHASE1 = [
|
|
1508
|
+
"http",
|
|
1509
|
+
"otlp",
|
|
1510
|
+
"datadog",
|
|
1511
|
+
"betterstack"
|
|
1512
|
+
];
|
|
1513
|
+
var LOG_DRAIN_TYPES_PHASE2 = [
|
|
1514
|
+
"splunk",
|
|
1515
|
+
"loki",
|
|
1516
|
+
"axiom",
|
|
1517
|
+
"newrelic",
|
|
1518
|
+
"sumologic"
|
|
1519
|
+
];
|
|
1520
|
+
var LOG_DRAIN_TYPES_IMPLEMENTED = [
|
|
1521
|
+
...LOG_DRAIN_TYPES_PHASE1,
|
|
1522
|
+
...LOG_DRAIN_TYPES_PHASE2,
|
|
1523
|
+
// RECONCILE-4 (W4-4). `s3` is implemented (H4 / PRO-1887) but is NOT in
|
|
1524
|
+
// `LOG_DRAIN_TYPES_PHASE2`, because its own flag opens it and `*` must not. It
|
|
1525
|
+
// belongs here all the same: this list is what a CLIENT may offer, and the server
|
|
1526
|
+
// remains the authority that answers 422 with the live list.
|
|
1527
|
+
"s3"
|
|
1528
|
+
];
|
|
1529
|
+
var LOG_DRAIN_SOURCES = [
|
|
1530
|
+
...AGENT_LOG_SOURCES,
|
|
1531
|
+
"execution",
|
|
1532
|
+
// ── phase 2 ──
|
|
1533
|
+
"delivery",
|
|
1534
|
+
"trigger-execution",
|
|
1535
|
+
"job-execution",
|
|
1536
|
+
"workflow-run",
|
|
1537
|
+
"workflow-audit",
|
|
1538
|
+
// PRO-1884 (H2). Appended AFTER 'workflow-audit' so the enum stays additive and
|
|
1539
|
+
// no existing member changes position.
|
|
1540
|
+
"voice-call"
|
|
1541
|
+
];
|
|
1542
|
+
var LOG_DRAIN_MAX_PER_ORG = 5;
|
|
1543
|
+
var LOG_DRAIN_MAX_PER_ORG_ENTERPRISE = 10;
|
|
1544
|
+
function maxDrainsForTier(tier) {
|
|
1545
|
+
return tier === "enterprise" ? LOG_DRAIN_MAX_PER_ORG_ENTERPRISE : LOG_DRAIN_MAX_PER_ORG;
|
|
1546
|
+
}
|
|
1547
|
+
__name(maxDrainsForTier, "maxDrainsForTier");
|
|
1548
|
+
__name2(maxDrainsForTier, "maxDrainsForTier");
|
|
1549
|
+
var LOG_DRAIN_DATADOG_SITES = [
|
|
1550
|
+
"datadoghq.com",
|
|
1551
|
+
"datadoghq.eu",
|
|
1552
|
+
"us3.datadoghq.com",
|
|
1553
|
+
"us5.datadoghq.com",
|
|
1554
|
+
"ap1.datadoghq.com",
|
|
1555
|
+
"ddog-gov.com"
|
|
1556
|
+
];
|
|
1557
|
+
var LOG_DRAIN_NEWRELIC_SITES = [
|
|
1558
|
+
"log-api.newrelic.com",
|
|
1559
|
+
"log-api.eu.newrelic.com",
|
|
1560
|
+
"log-api.jp.newrelic.com"
|
|
1561
|
+
];
|
|
1562
|
+
var LOG_DRAIN_ENDPOINT_TEMPLATES = {
|
|
1563
|
+
datadog: "https://http-intake.logs.{site}/api/v2/logs",
|
|
1564
|
+
newrelic: "https://{site}/log/v1"
|
|
1565
|
+
};
|
|
1566
|
+
var LOG_DRAIN_PRESET_SITES = {
|
|
1567
|
+
datadog: LOG_DRAIN_DATADOG_SITES,
|
|
1568
|
+
newrelic: LOG_DRAIN_NEWRELIC_SITES
|
|
1569
|
+
};
|
|
1570
|
+
function resolvePresetEndpoint(type, site) {
|
|
1571
|
+
const template3 = LOG_DRAIN_ENDPOINT_TEMPLATES[type];
|
|
1572
|
+
if (!template3 || !site) return void 0;
|
|
1573
|
+
return template3.replace("{site}", site);
|
|
1574
|
+
}
|
|
1575
|
+
__name(resolvePresetEndpoint, "resolvePresetEndpoint");
|
|
1576
|
+
__name2(resolvePresetEndpoint, "resolvePresetEndpoint");
|
|
1577
|
+
var LOG_DRAIN_BUCKET_NAME_PATTERN = /^[a-z0-9][a-z0-9-]{1,61}[a-z0-9]$/;
|
|
1578
|
+
var LOG_DRAIN_BUCKET_HOST_PATTERNS = Object.freeze({
|
|
1579
|
+
aws: [
|
|
1580
|
+
// virtual-host style, regional and legacy global
|
|
1581
|
+
/^[a-z0-9][a-z0-9-]{1,61}[a-z0-9]\.s3(\.dualstack)?(\.[a-z0-9-]+)?\.amazonaws\.com$/,
|
|
1582
|
+
// path style
|
|
1583
|
+
/^s3(\.dualstack)?(\.[a-z0-9-]+)?\.amazonaws\.com$/
|
|
1584
|
+
],
|
|
1585
|
+
r2: [
|
|
1586
|
+
/^[a-f0-9]{32}\.r2\.cloudflarestorage\.com$/
|
|
1587
|
+
],
|
|
1588
|
+
gcs: [
|
|
1589
|
+
/^storage\.googleapis\.com$/
|
|
1590
|
+
]
|
|
1591
|
+
});
|
|
1592
|
+
function isLogDrainBucketHostAllowed(provider, host) {
|
|
1593
|
+
const normalized = host.trim().toLowerCase().replace(/^\[|\]$/g, "");
|
|
1594
|
+
if (!normalized) return false;
|
|
1595
|
+
return (LOG_DRAIN_BUCKET_HOST_PATTERNS[provider] ?? []).some((pattern) => pattern.test(normalized));
|
|
1596
|
+
}
|
|
1597
|
+
__name(isLogDrainBucketHostAllowed, "isLogDrainBucketHostAllowed");
|
|
1598
|
+
__name2(isLogDrainBucketHostAllowed, "isLogDrainBucketHostAllowed");
|
|
1599
|
+
function resolveDrainBucketEndpoint(bucket) {
|
|
1600
|
+
if (!LOG_DRAIN_BUCKET_NAME_PATTERN.test(bucket.bucket)) {
|
|
1601
|
+
throw new Error("log drain bucket name is not a valid S3 bucket label");
|
|
1602
|
+
}
|
|
1603
|
+
if (bucket.provider === "aws") {
|
|
1604
|
+
const region = bucket.region.trim().toLowerCase();
|
|
1605
|
+
if (!/^[a-z0-9-]{1,32}$/.test(region)) throw new Error("log drain bucket region is not an AWS region");
|
|
1606
|
+
return `https://${bucket.bucket}.s3.${region}.amazonaws.com`;
|
|
1607
|
+
}
|
|
1608
|
+
if (!bucket.endpoint) throw new Error(`log drain '${bucket.provider}' bucket requires an endpoint`);
|
|
1609
|
+
let url;
|
|
1610
|
+
try {
|
|
1611
|
+
url = new URL(bucket.endpoint);
|
|
1612
|
+
} catch {
|
|
1613
|
+
throw new Error(`log drain '${bucket.provider}' bucket endpoint is not an absolute URL`);
|
|
1614
|
+
}
|
|
1615
|
+
if (url.protocol !== "https:") throw new Error(`log drain '${bucket.provider}' bucket endpoint must be https`);
|
|
1616
|
+
return `https://${url.host}/${bucket.bucket}`;
|
|
1617
|
+
}
|
|
1618
|
+
__name(resolveDrainBucketEndpoint, "resolveDrainBucketEndpoint");
|
|
1619
|
+
__name2(resolveDrainBucketEndpoint, "resolveDrainBucketEndpoint");
|
|
1620
|
+
function drainBucketUsesPathStyle(provider) {
|
|
1621
|
+
return provider !== "aws";
|
|
1622
|
+
}
|
|
1623
|
+
__name(drainBucketUsesPathStyle, "drainBucketUsesPathStyle");
|
|
1624
|
+
__name2(drainBucketUsesPathStyle, "drainBucketUsesPathStyle");
|
|
1625
|
+
function presetIntakeHosts(type) {
|
|
1626
|
+
const template3 = LOG_DRAIN_ENDPOINT_TEMPLATES[type];
|
|
1627
|
+
const sites = LOG_DRAIN_PRESET_SITES[type];
|
|
1628
|
+
if (!template3 || !sites) return [];
|
|
1629
|
+
const hosts = [];
|
|
1630
|
+
for (const site of sites) {
|
|
1631
|
+
try {
|
|
1632
|
+
hosts.push(new URL(template3.replace("{site}", site)).hostname.toLowerCase());
|
|
1633
|
+
} catch {
|
|
1634
|
+
}
|
|
1635
|
+
}
|
|
1636
|
+
return hosts;
|
|
1637
|
+
}
|
|
1638
|
+
__name(presetIntakeHosts, "presetIntakeHosts");
|
|
1639
|
+
__name2(presetIntakeHosts, "presetIntakeHosts");
|
|
1640
|
+
var LOG_DRAIN_PRESET_HOST_SUFFIXES = {
|
|
1641
|
+
axiom: [
|
|
1642
|
+
".axiom.co"
|
|
1643
|
+
],
|
|
1644
|
+
sumologic: [
|
|
1645
|
+
".sumologic.com"
|
|
1646
|
+
]
|
|
1647
|
+
};
|
|
1648
|
+
function presetHostAllowlist(type) {
|
|
1649
|
+
return [
|
|
1650
|
+
...presetIntakeHosts(type),
|
|
1651
|
+
...LOG_DRAIN_PRESET_HOST_SUFFIXES[type] ?? []
|
|
1652
|
+
];
|
|
1653
|
+
}
|
|
1654
|
+
__name(presetHostAllowlist, "presetHostAllowlist");
|
|
1655
|
+
__name2(presetHostAllowlist, "presetHostAllowlist");
|
|
1656
|
+
function drainHostAllowlistAllows(allowlist, host) {
|
|
1657
|
+
const needle = host.toLowerCase();
|
|
1658
|
+
return allowlist.some((raw) => {
|
|
1659
|
+
const entry = raw.toLowerCase();
|
|
1660
|
+
if (entry.startsWith(".")) return needle === entry.slice(1) || needle.endsWith(entry);
|
|
1661
|
+
return entry === needle;
|
|
1662
|
+
});
|
|
1663
|
+
}
|
|
1664
|
+
__name(drainHostAllowlistAllows, "drainHostAllowlistAllows");
|
|
1665
|
+
__name2(drainHostAllowlistAllows, "drainHostAllowlistAllows");
|
|
1666
|
+
function drainDestinationIsVendorPinned(type) {
|
|
1667
|
+
if (LOG_DRAIN_ENDPOINT_TEMPLATES[type]) return true;
|
|
1668
|
+
return presetHostAllowlist(type).length > 0;
|
|
1669
|
+
}
|
|
1670
|
+
__name(drainDestinationIsVendorPinned, "drainDestinationIsVendorPinned");
|
|
1671
|
+
__name2(drainDestinationIsVendorPinned, "drainDestinationIsVendorPinned");
|
|
1672
|
+
function drainVerificationOwnership(input) {
|
|
1673
|
+
if (input.proved === true) return "verified";
|
|
1674
|
+
if (input.mode === "test-post" && drainDestinationIsVendorPinned(input.type)) return "verified";
|
|
1675
|
+
return "reachability-only";
|
|
1676
|
+
}
|
|
1677
|
+
__name(drainVerificationOwnership, "drainVerificationOwnership");
|
|
1678
|
+
__name2(drainVerificationOwnership, "drainVerificationOwnership");
|
|
1679
|
+
function drainOwnershipOrDefault(ownership) {
|
|
1680
|
+
return ownership === "verified" ? "verified" : "reachability-only";
|
|
1681
|
+
}
|
|
1682
|
+
__name(drainOwnershipOrDefault, "drainOwnershipOrDefault");
|
|
1683
|
+
__name2(drainOwnershipOrDefault, "drainOwnershipOrDefault");
|
|
1684
|
+
var DRAIN_CONTENT_ACK_ERROR_CODE = "DRAIN_CONTENT_ACK_REQUIRED";
|
|
1685
|
+
var DRAIN_CONTENT_ACK_FIELD = "includeContentAck";
|
|
1686
|
+
var DrainContentAckRequiredError = class extends Error {
|
|
1687
|
+
static {
|
|
1688
|
+
__name(this, "DrainContentAckRequiredError");
|
|
1689
|
+
}
|
|
1690
|
+
static {
|
|
1691
|
+
__name2(this, "DrainContentAckRequiredError");
|
|
1692
|
+
}
|
|
1693
|
+
code = DRAIN_CONTENT_ACK_ERROR_CODE;
|
|
1694
|
+
field = DRAIN_CONTENT_ACK_FIELD;
|
|
1695
|
+
constructor() {
|
|
1696
|
+
super("includeContent ships end-user message content to a third party; set includeContentAck: true to confirm.");
|
|
1697
|
+
this.name = "DrainContentAckRequiredError";
|
|
1698
|
+
}
|
|
1699
|
+
};
|
|
1700
|
+
function assertDrainContentAck(input) {
|
|
1701
|
+
const turningOn = input.next === true && input.was !== true;
|
|
1702
|
+
if (!turningOn) return void 0;
|
|
1703
|
+
if (input.ack !== true) throw new DrainContentAckRequiredError();
|
|
1704
|
+
return {
|
|
1705
|
+
by: input.actor,
|
|
1706
|
+
source: input.source,
|
|
1707
|
+
at: input.at,
|
|
1708
|
+
...input.inheritedFrom ? {
|
|
1709
|
+
inheritedFrom: input.inheritedFrom
|
|
1710
|
+
} : {}
|
|
1711
|
+
};
|
|
1712
|
+
}
|
|
1713
|
+
__name(assertDrainContentAck, "assertDrainContentAck");
|
|
1714
|
+
__name2(assertDrainContentAck, "assertDrainContentAck");
|
|
1715
|
+
var LOG_DRAIN_PRESET_PATHS = {
|
|
1716
|
+
// https://docs.splunk.com/Documentation/Splunk/latest/Data/HECExamples
|
|
1717
|
+
splunk: {
|
|
1718
|
+
path: "/services/collector/event"
|
|
1719
|
+
},
|
|
1720
|
+
// https://grafana.com/docs/loki/latest/reference/loki-http-api/#ingest-logs
|
|
1721
|
+
loki: {
|
|
1722
|
+
path: "/loki/api/v1/push"
|
|
1723
|
+
},
|
|
1724
|
+
// https://axiom.co/docs/restapi/endpoints/ingestIntoDataset
|
|
1725
|
+
axiom: {
|
|
1726
|
+
path: "/v1/datasets",
|
|
1727
|
+
segment: "dataset",
|
|
1728
|
+
suffix: "/ingest"
|
|
1729
|
+
},
|
|
1730
|
+
// https://help.sumologic.com/docs/send-data/hosted-collectors/http-source/logs-metrics/upload-logs/
|
|
1731
|
+
sumologic: {
|
|
1732
|
+
path: "/receiver/v1/http",
|
|
1733
|
+
segment: "token"
|
|
1734
|
+
}
|
|
1735
|
+
};
|
|
1736
|
+
var PRESET_SEGMENT_RE = /^[A-Za-z0-9._~%=+-]{1,512}$/;
|
|
1737
|
+
function composePresetEndpoint(type, endpoint) {
|
|
1738
|
+
const rule = LOG_DRAIN_PRESET_PATHS[type];
|
|
1739
|
+
if (!rule) return void 0;
|
|
1740
|
+
let url;
|
|
1741
|
+
try {
|
|
1742
|
+
url = new URL(endpoint);
|
|
1743
|
+
} catch {
|
|
1744
|
+
return {
|
|
1745
|
+
ok: false,
|
|
1746
|
+
reason: "invalid_url"
|
|
1747
|
+
};
|
|
1748
|
+
}
|
|
1749
|
+
if (url.protocol !== "https:" || !url.hostname) return {
|
|
1750
|
+
ok: false,
|
|
1751
|
+
reason: "invalid_url"
|
|
1752
|
+
};
|
|
1753
|
+
const origin = url.origin;
|
|
1754
|
+
const path = url.pathname.replace(/\/+$/, "");
|
|
1755
|
+
if (!rule.segment) {
|
|
1756
|
+
const base2 = path.endsWith(rule.path) ? path.slice(0, path.length - rule.path.length) : path;
|
|
1757
|
+
return {
|
|
1758
|
+
ok: true,
|
|
1759
|
+
endpoint: `${origin}${base2}${rule.path}`
|
|
1760
|
+
};
|
|
1761
|
+
}
|
|
1762
|
+
const marker = `${rule.path}/`;
|
|
1763
|
+
const at = path.indexOf(marker);
|
|
1764
|
+
if (at < 0) {
|
|
1765
|
+
return {
|
|
1766
|
+
ok: false,
|
|
1767
|
+
reason: rule.segment === "dataset" ? "missing_dataset" : "missing_token"
|
|
1768
|
+
};
|
|
1769
|
+
}
|
|
1770
|
+
const base = path.slice(0, at);
|
|
1771
|
+
const afterMarker = path.slice(at + marker.length);
|
|
1772
|
+
const rest = rule.suffix && afterMarker.endsWith(rule.suffix) ? afterMarker.slice(0, afterMarker.length - rule.suffix.length) : afterMarker;
|
|
1773
|
+
if (!rest || rest.includes("/")) {
|
|
1774
|
+
return {
|
|
1775
|
+
ok: false,
|
|
1776
|
+
reason: rule.segment === "dataset" ? "missing_dataset" : "missing_token"
|
|
1777
|
+
};
|
|
1778
|
+
}
|
|
1779
|
+
if (!PRESET_SEGMENT_RE.test(rest)) return {
|
|
1780
|
+
ok: false,
|
|
1781
|
+
reason: "bad_segment"
|
|
1782
|
+
};
|
|
1783
|
+
if (rule.segment === "dataset") {
|
|
1784
|
+
return {
|
|
1785
|
+
ok: true,
|
|
1786
|
+
endpoint: `${origin}${base}${rule.path}/${rest}${rule.suffix ?? ""}`,
|
|
1787
|
+
dataset: rest
|
|
1788
|
+
};
|
|
1789
|
+
}
|
|
1790
|
+
return {
|
|
1791
|
+
ok: true,
|
|
1792
|
+
endpoint: `${origin}${base}${rule.path}/`,
|
|
1793
|
+
token: rest
|
|
1794
|
+
};
|
|
1795
|
+
}
|
|
1796
|
+
__name(composePresetEndpoint, "composePresetEndpoint");
|
|
1797
|
+
__name2(composePresetEndpoint, "composePresetEndpoint");
|
|
1798
|
+
function joinPresetEndpointToken(endpoint, token) {
|
|
1799
|
+
if (typeof token !== "string" || !PRESET_SEGMENT_RE.test(token)) return endpoint;
|
|
1800
|
+
return endpoint.endsWith("/") ? `${endpoint}${token}` : `${endpoint}/${token}`;
|
|
1801
|
+
}
|
|
1802
|
+
__name(joinPresetEndpointToken, "joinPresetEndpointToken");
|
|
1803
|
+
__name2(joinPresetEndpointToken, "joinPresetEndpointToken");
|
|
1804
|
+
var LOG_DRAIN_QUOTAS = {
|
|
1805
|
+
team: {
|
|
1806
|
+
eventsPerDay: 1e6,
|
|
1807
|
+
bytesPerDay: 1 * 1024 ** 3
|
|
1808
|
+
},
|
|
1809
|
+
business: {
|
|
1810
|
+
eventsPerDay: 1e7,
|
|
1811
|
+
bytesPerDay: 10 * 1024 ** 3
|
|
1812
|
+
},
|
|
1813
|
+
enterprise: {
|
|
1814
|
+
eventsPerDay: Number.MAX_SAFE_INTEGER,
|
|
1815
|
+
bytesPerDay: Number.MAX_SAFE_INTEGER
|
|
1816
|
+
}
|
|
1817
|
+
};
|
|
1818
|
+
var LOG_DRAIN_QUOTA_WARN_RATIO = 0.8;
|
|
1819
|
+
var LOG_DRAIN_QUOTA_DROP_DEBUG_RATIO = 1;
|
|
1820
|
+
var LOG_DRAIN_QUOTA_DROP_INFO_RATIO = 1.25;
|
|
1821
|
+
var LOG_DRAIN_QUOTA_PAUSE_RATIO = 1.5;
|
|
1822
|
+
function nextLogDrainQuotaResetAt(now) {
|
|
1823
|
+
return new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate() + 1)).toISOString();
|
|
1824
|
+
}
|
|
1825
|
+
__name(nextLogDrainQuotaResetAt, "nextLogDrainQuotaResetAt");
|
|
1826
|
+
__name2(nextLogDrainQuotaResetAt, "nextLogDrainQuotaResetAt");
|
|
1827
|
+
function logDrainQuotaWindowExpired(usage, now) {
|
|
1828
|
+
const resetsAt = Date.parse(usage?.resetsAt ?? "");
|
|
1829
|
+
if (!Number.isFinite(resetsAt)) return true;
|
|
1830
|
+
return now.getTime() >= resetsAt;
|
|
1831
|
+
}
|
|
1832
|
+
__name(logDrainQuotaWindowExpired, "logDrainQuotaWindowExpired");
|
|
1833
|
+
__name2(logDrainQuotaWindowExpired, "logDrainQuotaWindowExpired");
|
|
1834
|
+
function logDrainQuotaRatio(usage, now) {
|
|
1835
|
+
if (!usage) return 0;
|
|
1836
|
+
if (now && logDrainQuotaWindowExpired(usage, now)) return 0;
|
|
1837
|
+
const dimension = /* @__PURE__ */ __name2((used, limit) => {
|
|
1838
|
+
if (!Number.isFinite(limit) || limit <= 0) return 0;
|
|
1839
|
+
if (!Number.isFinite(used) || used <= 0) return 0;
|
|
1840
|
+
return used / limit;
|
|
1841
|
+
}, "dimension");
|
|
1842
|
+
return Math.max(dimension(usage.usedEvents, usage.eventsPerDay), dimension(usage.usedBytes, usage.bytesPerDay));
|
|
1843
|
+
}
|
|
1844
|
+
__name(logDrainQuotaRatio, "logDrainQuotaRatio");
|
|
1845
|
+
__name2(logDrainQuotaRatio, "logDrainQuotaRatio");
|
|
1846
|
+
function logDrainQuotaDegradationForRatio(ratio) {
|
|
1847
|
+
if (!Number.isFinite(ratio)) return "none";
|
|
1848
|
+
if (ratio >= LOG_DRAIN_QUOTA_PAUSE_RATIO) return "paused";
|
|
1849
|
+
if (ratio >= LOG_DRAIN_QUOTA_DROP_INFO_RATIO) return "info_dropped";
|
|
1850
|
+
if (ratio >= LOG_DRAIN_QUOTA_DROP_DEBUG_RATIO) return "debug_dropped";
|
|
1851
|
+
return "none";
|
|
1852
|
+
}
|
|
1853
|
+
__name(logDrainQuotaDegradationForRatio, "logDrainQuotaDegradationForRatio");
|
|
1854
|
+
__name2(logDrainQuotaDegradationForRatio, "logDrainQuotaDegradationForRatio");
|
|
1855
|
+
function logDrainQuotaDegradation(usage, now) {
|
|
1856
|
+
return logDrainQuotaDegradationForRatio(logDrainQuotaRatio(usage, now));
|
|
1857
|
+
}
|
|
1858
|
+
__name(logDrainQuotaDegradation, "logDrainQuotaDegradation");
|
|
1859
|
+
__name2(logDrainQuotaDegradation, "logDrainQuotaDegradation");
|
|
1860
|
+
function logDrainQuotaWarned(usage, now) {
|
|
1861
|
+
return logDrainQuotaRatio(usage, now) >= LOG_DRAIN_QUOTA_WARN_RATIO;
|
|
1862
|
+
}
|
|
1863
|
+
__name(logDrainQuotaWarned, "logDrainQuotaWarned");
|
|
1864
|
+
__name2(logDrainQuotaWarned, "logDrainQuotaWarned");
|
|
1865
|
+
function logDrainQuotaDroppedSeverities(degradation) {
|
|
1866
|
+
switch (degradation) {
|
|
1867
|
+
case "debug_dropped":
|
|
1868
|
+
return [
|
|
1869
|
+
5
|
|
1870
|
+
];
|
|
1871
|
+
case "info_dropped":
|
|
1872
|
+
return [
|
|
1873
|
+
5,
|
|
1874
|
+
9
|
|
1875
|
+
];
|
|
1876
|
+
default:
|
|
1877
|
+
return [];
|
|
1878
|
+
}
|
|
1879
|
+
}
|
|
1880
|
+
__name(logDrainQuotaDroppedSeverities, "logDrainQuotaDroppedSeverities");
|
|
1881
|
+
__name2(logDrainQuotaDroppedSeverities, "logDrainQuotaDroppedSeverities");
|
|
1882
|
+
var LOG_EXPORT_SOURCES = [
|
|
1883
|
+
...AGENT_LOG_SOURCES,
|
|
1884
|
+
"execution"
|
|
1885
|
+
];
|
|
1886
|
+
var LOG_EXPORT_MAX_WINDOW_DAYS = 31;
|
|
1887
|
+
var LOG_EXPORT_MAX_WINDOW_MS = LOG_EXPORT_MAX_WINDOW_DAYS * 24 * 60 * 60 * 1e3;
|
|
1888
|
+
var LOG_EXPORT_URL_TTL_SECONDS = 24 * 60 * 60;
|
|
1889
|
+
var LOG_EXPORT_FILE_RETENTION_DAYS = 7;
|
|
1890
|
+
var LOG_EXPORT_FILE_RETENTION_MS = LOG_EXPORT_FILE_RETENTION_DAYS * 24 * 60 * 60 * 1e3;
|
|
1891
|
+
var LOG_EXPORT_PART_MAX_BYTES = 256 * 1024 * 1024;
|
|
1892
|
+
function isLogExportSource(source) {
|
|
1893
|
+
return LOG_EXPORT_SOURCES.includes(source);
|
|
1894
|
+
}
|
|
1895
|
+
__name(isLogExportSource, "isLogExportSource");
|
|
1896
|
+
__name2(isLogExportSource, "isLogExportSource");
|
|
1897
|
+
var LOG_DRAIN_NOTICE_RATE_LIMIT_MS = 60 * 6e4;
|
|
1898
|
+
var LOG_DRAIN_VERIFICATION_STALE_MS = 24 * 60 * 6e4;
|
|
1899
|
+
var LOG_DRAIN_DIGEST_INTERVAL_MS = 24 * 60 * 6e4;
|
|
1900
|
+
var LOG_DRAIN_DIGEST_MAX_ENTRIES = 50;
|
|
1901
|
+
var LOG_DRAIN_NOTICE_ERROR_MAX_CHARS = 200;
|
|
1902
|
+
function clamp(value3, max) {
|
|
1903
|
+
if (typeof value3 !== "string") return void 0;
|
|
1904
|
+
const trimmed = value3.trim();
|
|
1905
|
+
if (!trimmed) return void 0;
|
|
1906
|
+
return trimmed.length <= max ? trimmed : `${trimmed.slice(0, max - 1)}\u2026`;
|
|
1907
|
+
}
|
|
1908
|
+
__name(clamp, "clamp");
|
|
1909
|
+
__name2(clamp, "clamp");
|
|
1910
|
+
function numberOr(value3, fallback) {
|
|
1911
|
+
return typeof value3 === "number" && Number.isFinite(value3) ? value3 : fallback;
|
|
1912
|
+
}
|
|
1913
|
+
__name(numberOr, "numberOr");
|
|
1914
|
+
__name2(numberOr, "numberOr");
|
|
1915
|
+
function isoOr(value3) {
|
|
1916
|
+
return typeof value3 === "string" && value3.length > 0 ? value3 : void 0;
|
|
1917
|
+
}
|
|
1918
|
+
__name(isoOr, "isoOr");
|
|
1919
|
+
__name2(isoOr, "isoOr");
|
|
1920
|
+
function logDrainNoticeView(drain, now) {
|
|
1921
|
+
const health = drain.health ?? {};
|
|
1922
|
+
const quota = drain.quota;
|
|
1923
|
+
const view = {
|
|
1924
|
+
id: String(drain.id ?? ""),
|
|
1925
|
+
name: String(drain.name ?? ""),
|
|
1926
|
+
type: drain.type,
|
|
1927
|
+
state: drain.state,
|
|
1928
|
+
deliveredCount24h: numberOr(health.deliveredCount24h, 0),
|
|
1929
|
+
droppedCount24h: numberOr(health.droppedCount24h, 0),
|
|
1930
|
+
rejectedCount24h: numberOr(health.rejectedCount24h, 0),
|
|
1931
|
+
backlog: numberOr(health.backlog, 0),
|
|
1932
|
+
quotaRatio: quota ? logDrainQuotaRatio(quota, now) : 0
|
|
1933
|
+
};
|
|
1934
|
+
if (health.pauseReason) view.pauseReason = health.pauseReason;
|
|
1935
|
+
const lastError = clamp(health.lastError, LOG_DRAIN_NOTICE_ERROR_MAX_CHARS);
|
|
1936
|
+
if (lastError) view.lastError = lastError;
|
|
1937
|
+
if (typeof health.lastStatusCode === "number") view.lastStatusCode = health.lastStatusCode;
|
|
1938
|
+
const lastSuccessAt = isoOr(health.lastSuccessAt);
|
|
1939
|
+
if (lastSuccessAt) view.lastSuccessAt = lastSuccessAt;
|
|
1940
|
+
const lastFailureAt = isoOr(health.lastFailureAt);
|
|
1941
|
+
if (lastFailureAt) view.lastFailureAt = lastFailureAt;
|
|
1942
|
+
const resetsAt = isoOr(quota?.resetsAt);
|
|
1943
|
+
if (resetsAt) view.quotaResetsAt = resetsAt;
|
|
1944
|
+
return view;
|
|
1945
|
+
}
|
|
1946
|
+
__name(logDrainNoticeView, "logDrainNoticeView");
|
|
1947
|
+
__name2(logDrainNoticeView, "logDrainNoticeView");
|
|
1948
|
+
function logDrainHealthCardPath(orgId, drainId) {
|
|
1949
|
+
return `/orgs/${encodeURIComponent(orgId)}/log-drains/${encodeURIComponent(drainId)}`;
|
|
1950
|
+
}
|
|
1951
|
+
__name(logDrainHealthCardPath, "logDrainHealthCardPath");
|
|
1952
|
+
__name2(logDrainHealthCardPath, "logDrainHealthCardPath");
|
|
1953
|
+
function percent(ratio) {
|
|
1954
|
+
if (!Number.isFinite(ratio) || ratio <= 0) return "0%";
|
|
1955
|
+
return `${Math.round(ratio * 100)}%`;
|
|
1956
|
+
}
|
|
1957
|
+
__name(percent, "percent");
|
|
1958
|
+
__name2(percent, "percent");
|
|
1959
|
+
function becauseClause(view) {
|
|
1960
|
+
const bits = [];
|
|
1961
|
+
if (view.lastStatusCode) bits.push(`HTTP ${view.lastStatusCode}`);
|
|
1962
|
+
if (view.lastError) bits.push(view.lastError);
|
|
1963
|
+
return bits.length ? ` Last error: ${bits.join(" \u2014 ")}.` : "";
|
|
1964
|
+
}
|
|
1965
|
+
__name(becauseClause, "becauseClause");
|
|
1966
|
+
__name2(becauseClause, "becauseClause");
|
|
1967
|
+
function logDrainNoticeCopy(payload) {
|
|
1968
|
+
const view = payload.drain;
|
|
1969
|
+
const name = view.name || view.id;
|
|
1970
|
+
const backlog = view.backlog > 0 ? ` ${view.backlog.toLocaleString("en-US")} records are buffered.` : "";
|
|
1971
|
+
switch (payload.kind) {
|
|
1972
|
+
case "failing":
|
|
1973
|
+
return {
|
|
1974
|
+
title: name,
|
|
1975
|
+
subject: `Log drain "${name}" is failing`,
|
|
1976
|
+
previewLine: "Failing \u2014 15 minutes without a successful delivery",
|
|
1977
|
+
summary: `The log drain "${name}" (${view.type}) has gone 15 minutes without a successful delivery and is now failing.${becauseClause(view)}${backlog} Records keep buffering; the drain pauses itself after 24 hours without a success.`,
|
|
1978
|
+
status: "failed",
|
|
1979
|
+
priority: "high"
|
|
1980
|
+
};
|
|
1981
|
+
case "paused_auto":
|
|
1982
|
+
return {
|
|
1983
|
+
title: name,
|
|
1984
|
+
subject: `Log drain "${name}" was paused`,
|
|
1985
|
+
previewLine: "Paused \u2014 24 hours without a successful delivery",
|
|
1986
|
+
summary: `The log drain "${name}" (${view.type}) was paused automatically after 24 hours without a successful delivery.${becauseClause(view)}${backlog} Nothing is being sent while it is paused, and the buffer is delivered on resume. Fix the destination, then resume it from the drain's health card or with \`lua drains resume ${view.id}\`.`,
|
|
1987
|
+
status: "failed",
|
|
1988
|
+
priority: "high"
|
|
1989
|
+
};
|
|
1990
|
+
case "paused_quota":
|
|
1991
|
+
return {
|
|
1992
|
+
title: name,
|
|
1993
|
+
subject: `Log drain "${name}" was paused \u2014 daily quota exhausted`,
|
|
1994
|
+
previewLine: `Paused \u2014 ${percent(view.quotaRatio)} of the daily allowance used`,
|
|
1995
|
+
summary: `The log drain "${name}" (${view.type}) reached ${percent(view.quotaRatio)} of its daily allowance and was paused.${backlog} Records keep buffering. The allowance resets${view.quotaResetsAt ? ` at ${view.quotaResetsAt}` : " at 00:00 UTC"}; narrow the drain's sources or raise the plan's limit to stop it happening again, then resume it with \`lua drains resume ${view.id}\`.`,
|
|
1996
|
+
status: "failed",
|
|
1997
|
+
priority: "high"
|
|
1998
|
+
};
|
|
1999
|
+
case "quota_warning":
|
|
2000
|
+
return {
|
|
2001
|
+
title: name,
|
|
2002
|
+
subject: `Log drain "${name}" has used 80% of its daily allowance`,
|
|
2003
|
+
previewLine: `${percent(view.quotaRatio)} of the daily allowance used`,
|
|
2004
|
+
summary: `The log drain "${name}" (${view.type}) has used ${percent(view.quotaRatio)} of today's allowance. Past 100% debug records are dropped, past 125% info records as well, and at 150% the drain pauses. The allowance resets${view.quotaResetsAt ? ` at ${view.quotaResetsAt}` : " at 00:00 UTC"}.`,
|
|
2005
|
+
status: "failed",
|
|
2006
|
+
priority: "normal"
|
|
2007
|
+
};
|
|
2008
|
+
case "dropped": {
|
|
2009
|
+
const dropped = payload.droppedCount ?? view.droppedCount24h;
|
|
2010
|
+
return {
|
|
2011
|
+
title: name,
|
|
2012
|
+
subject: `Log drain "${name}" is dropping records`,
|
|
2013
|
+
previewLine: `${dropped.toLocaleString("en-US")} records dropped`,
|
|
2014
|
+
summary: `The log drain "${name}" (${view.type}) dropped ${dropped.toLocaleString("en-US")} records because its buffer filled up faster than the destination accepted them.${becauseClause(view)} The gap is reported in band on the next successful batch, so the range is recoverable from the destination itself.`,
|
|
2015
|
+
status: "failed",
|
|
2016
|
+
priority: "high"
|
|
2017
|
+
};
|
|
2018
|
+
}
|
|
2019
|
+
case "verification_pending":
|
|
2020
|
+
return {
|
|
2021
|
+
title: name,
|
|
2022
|
+
subject: `Log drain "${name}" is still unverified`,
|
|
2023
|
+
previewLine: "Unverified after 24 hours \u2014 nothing is being delivered",
|
|
2024
|
+
summary: `The log drain "${name}" (${view.type}) was created more than 24 hours ago and has never completed verification, so nothing is being delivered to it.${becauseClause(view)} Run \`lua drains verify ${view.id}\` once the destination echoes the verification token.`,
|
|
2025
|
+
status: "failed",
|
|
2026
|
+
priority: "normal"
|
|
2027
|
+
};
|
|
2028
|
+
default: {
|
|
2029
|
+
const exhaustive = payload.kind;
|
|
2030
|
+
throw new Error(`unhandled log-drain notice kind: ${String(exhaustive)}`);
|
|
2031
|
+
}
|
|
2032
|
+
}
|
|
2033
|
+
}
|
|
2034
|
+
__name(logDrainNoticeCopy, "logDrainNoticeCopy");
|
|
2035
|
+
__name2(logDrainNoticeCopy, "logDrainNoticeCopy");
|
|
2036
|
+
function logDrainNoticeLabel(kind) {
|
|
2037
|
+
switch (kind) {
|
|
2038
|
+
case "failing":
|
|
2039
|
+
return "failing";
|
|
2040
|
+
case "paused_auto":
|
|
2041
|
+
return "paused (no success for 24 h)";
|
|
2042
|
+
case "paused_quota":
|
|
2043
|
+
return "paused (daily allowance exhausted)";
|
|
2044
|
+
case "quota_warning":
|
|
2045
|
+
return "80% of the daily allowance used";
|
|
2046
|
+
case "dropped":
|
|
2047
|
+
return "dropping records";
|
|
2048
|
+
case "verification_pending":
|
|
2049
|
+
return "still unverified";
|
|
2050
|
+
default: {
|
|
2051
|
+
const exhaustive = kind;
|
|
2052
|
+
throw new Error(`unhandled log-drain notice kind: ${String(exhaustive)}`);
|
|
2053
|
+
}
|
|
2054
|
+
}
|
|
2055
|
+
}
|
|
2056
|
+
__name(logDrainNoticeLabel, "logDrainNoticeLabel");
|
|
2057
|
+
__name2(logDrainNoticeLabel, "logDrainNoticeLabel");
|
|
2058
|
+
function logDrainNoticeDigestCopy(payload) {
|
|
2059
|
+
const entries = [
|
|
2060
|
+
...payload.entries ?? []
|
|
2061
|
+
].sort((a, b) => a.at < b.at ? -1 : a.at > b.at ? 1 : 0).slice(0, LOG_DRAIN_DIGEST_MAX_ENTRIES);
|
|
2062
|
+
const drains = new Set(entries.map((entry) => entry.drainId));
|
|
2063
|
+
const noun = `${entries.length} notice${entries.length === 1 ? "" : "s"}`;
|
|
2064
|
+
const across = `${drains.size} drain${drains.size === 1 ? "" : "s"}`;
|
|
2065
|
+
const lines = entries.map((entry) => `${entry.drainName || entry.drainId} \u2014 ${logDrainNoticeLabel(entry.kind)}`);
|
|
2066
|
+
return {
|
|
2067
|
+
title: "Log drains \u2014 daily summary",
|
|
2068
|
+
subject: `Log drains \u2014 ${noun} in the last day`,
|
|
2069
|
+
previewLine: `${noun} across ${across}`,
|
|
2070
|
+
summary: `${noun} across ${across} in the last day: ${lines.join("; ")}.`,
|
|
2071
|
+
status: "failed",
|
|
2072
|
+
priority: "normal"
|
|
2073
|
+
};
|
|
2074
|
+
}
|
|
2075
|
+
__name(logDrainNoticeDigestCopy, "logDrainNoticeDigestCopy");
|
|
2076
|
+
__name2(logDrainNoticeDigestCopy, "logDrainNoticeDigestCopy");
|
|
2077
|
+
var LOG_DRAIN_USAGE_LINE_ITEM = "log_drain_events";
|
|
2078
|
+
var LOG_DRAIN_BYTES_PER_GIB = 1024 ** 3;
|
|
2079
|
+
var DEFAULT_LOG_DRAIN_PLAN_CONFIG = {
|
|
2080
|
+
version: 1,
|
|
2081
|
+
tiers: {
|
|
2082
|
+
team: {
|
|
2083
|
+
...LOG_DRAIN_QUOTAS.team
|
|
2084
|
+
},
|
|
2085
|
+
business: {
|
|
2086
|
+
...LOG_DRAIN_QUOTAS.business
|
|
2087
|
+
},
|
|
2088
|
+
enterprise: {
|
|
2089
|
+
...LOG_DRAIN_QUOTAS.enterprise
|
|
2090
|
+
}
|
|
2091
|
+
},
|
|
2092
|
+
pricing: {
|
|
2093
|
+
team: {
|
|
2094
|
+
includedEventsPerMonth: 0,
|
|
2095
|
+
includedBytesPerMonth: 0,
|
|
2096
|
+
usdPerMillionEvents: 0,
|
|
2097
|
+
usdPerGiB: 0
|
|
2098
|
+
},
|
|
2099
|
+
business: {
|
|
2100
|
+
includedEventsPerMonth: 0,
|
|
2101
|
+
includedBytesPerMonth: 0,
|
|
2102
|
+
usdPerMillionEvents: 0,
|
|
2103
|
+
usdPerGiB: 0
|
|
2104
|
+
},
|
|
2105
|
+
enterprise: {
|
|
2106
|
+
includedEventsPerMonth: 0,
|
|
2107
|
+
includedBytesPerMonth: 0,
|
|
2108
|
+
usdPerMillionEvents: 0,
|
|
2109
|
+
usdPerGiB: 0
|
|
2110
|
+
}
|
|
2111
|
+
}
|
|
2112
|
+
};
|
|
2113
|
+
var TIERS = [
|
|
2114
|
+
"team",
|
|
2115
|
+
"business",
|
|
2116
|
+
"enterprise"
|
|
2117
|
+
];
|
|
2118
|
+
function finiteNonNegative(value3) {
|
|
2119
|
+
return typeof value3 === "number" && Number.isFinite(value3) && value3 >= 0 ? value3 : void 0;
|
|
2120
|
+
}
|
|
2121
|
+
__name(finiteNonNegative, "finiteNonNegative");
|
|
2122
|
+
__name2(finiteNonNegative, "finiteNonNegative");
|
|
2123
|
+
function mergeLimits(base, stored) {
|
|
2124
|
+
const patch = stored ?? {};
|
|
2125
|
+
return {
|
|
2126
|
+
eventsPerDay: finiteNonNegative(patch.eventsPerDay) ?? base.eventsPerDay,
|
|
2127
|
+
bytesPerDay: finiteNonNegative(patch.bytesPerDay) ?? base.bytesPerDay
|
|
2128
|
+
};
|
|
2129
|
+
}
|
|
2130
|
+
__name(mergeLimits, "mergeLimits");
|
|
2131
|
+
__name2(mergeLimits, "mergeLimits");
|
|
2132
|
+
function mergeCard(base, stored) {
|
|
2133
|
+
const patch = stored ?? {};
|
|
2134
|
+
return {
|
|
2135
|
+
includedEventsPerMonth: finiteNonNegative(patch.includedEventsPerMonth) ?? base.includedEventsPerMonth,
|
|
2136
|
+
includedBytesPerMonth: finiteNonNegative(patch.includedBytesPerMonth) ?? base.includedBytesPerMonth,
|
|
2137
|
+
usdPerMillionEvents: finiteNonNegative(patch.usdPerMillionEvents) ?? base.usdPerMillionEvents,
|
|
2138
|
+
usdPerGiB: finiteNonNegative(patch.usdPerGiB) ?? base.usdPerGiB
|
|
2139
|
+
};
|
|
2140
|
+
}
|
|
2141
|
+
__name(mergeCard, "mergeCard");
|
|
2142
|
+
__name2(mergeCard, "mergeCard");
|
|
2143
|
+
function resolveStoredLogDrainPlanConfig(stored) {
|
|
2144
|
+
const values = stored;
|
|
2145
|
+
if (!values || typeof values.version !== "number" || !Number.isFinite(values.version)) {
|
|
2146
|
+
return DEFAULT_LOG_DRAIN_PLAN_CONFIG;
|
|
2147
|
+
}
|
|
2148
|
+
const tiers = {};
|
|
2149
|
+
const pricing = {};
|
|
2150
|
+
for (const tier of TIERS) {
|
|
2151
|
+
tiers[tier] = mergeLimits(DEFAULT_LOG_DRAIN_PLAN_CONFIG.tiers[tier], values.tiers?.[tier]);
|
|
2152
|
+
pricing[tier] = mergeCard(DEFAULT_LOG_DRAIN_PLAN_CONFIG.pricing[tier], values.pricing?.[tier]);
|
|
2153
|
+
}
|
|
2154
|
+
const orgs = {};
|
|
2155
|
+
for (const [orgId, override] of Object.entries(values.orgs ?? {})) {
|
|
2156
|
+
if (!orgId || !override || typeof override !== "object") continue;
|
|
2157
|
+
const row = {};
|
|
2158
|
+
if (override.tier && TIERS.includes(override.tier)) row.tier = override.tier;
|
|
2159
|
+
const events = finiteNonNegative(override.eventsPerDay);
|
|
2160
|
+
const bytes = finiteNonNegative(override.bytesPerDay);
|
|
2161
|
+
if (events !== void 0) row.eventsPerDay = events;
|
|
2162
|
+
if (bytes !== void 0) row.bytesPerDay = bytes;
|
|
2163
|
+
if (override.pricing && typeof override.pricing === "object") row.pricing = {
|
|
2164
|
+
...override.pricing
|
|
2165
|
+
};
|
|
2166
|
+
if (Object.keys(row).length) orgs[orgId] = row;
|
|
2167
|
+
}
|
|
2168
|
+
return {
|
|
2169
|
+
version: values.version,
|
|
2170
|
+
tiers,
|
|
2171
|
+
pricing,
|
|
2172
|
+
...Object.keys(orgs).length ? {
|
|
2173
|
+
orgs
|
|
2174
|
+
} : {}
|
|
2175
|
+
};
|
|
2176
|
+
}
|
|
2177
|
+
__name(resolveStoredLogDrainPlanConfig, "resolveStoredLogDrainPlanConfig");
|
|
2178
|
+
__name2(resolveStoredLogDrainPlanConfig, "resolveStoredLogDrainPlanConfig");
|
|
2179
|
+
function logDrainPlanTierOverride(config, orgId) {
|
|
2180
|
+
return orgId ? config.orgs?.[orgId]?.tier : void 0;
|
|
2181
|
+
}
|
|
2182
|
+
__name(logDrainPlanTierOverride, "logDrainPlanTierOverride");
|
|
2183
|
+
__name2(logDrainPlanTierOverride, "logDrainPlanTierOverride");
|
|
2184
|
+
function logDrainQuotaLimitsFor(config, orgId, tier) {
|
|
2185
|
+
const base = config.tiers[tier] ?? config.tiers.team ?? LOG_DRAIN_QUOTAS.team;
|
|
2186
|
+
const override = orgId ? config.orgs?.[orgId] : void 0;
|
|
2187
|
+
if (!override) return {
|
|
2188
|
+
...base
|
|
2189
|
+
};
|
|
2190
|
+
return {
|
|
2191
|
+
eventsPerDay: override.eventsPerDay ?? base.eventsPerDay,
|
|
2192
|
+
bytesPerDay: override.bytesPerDay ?? base.bytesPerDay
|
|
2193
|
+
};
|
|
2194
|
+
}
|
|
2195
|
+
__name(logDrainQuotaLimitsFor, "logDrainQuotaLimitsFor");
|
|
2196
|
+
__name2(logDrainQuotaLimitsFor, "logDrainQuotaLimitsFor");
|
|
2197
|
+
function logDrainPriceCardFor(config, orgId, tier) {
|
|
2198
|
+
const base = config.pricing[tier] ?? config.pricing.team ?? DEFAULT_LOG_DRAIN_PLAN_CONFIG.pricing.team;
|
|
2199
|
+
const override = orgId ? config.orgs?.[orgId]?.pricing : void 0;
|
|
2200
|
+
return override ? mergeCard(base, override) : {
|
|
2201
|
+
...base
|
|
2202
|
+
};
|
|
2203
|
+
}
|
|
2204
|
+
__name(logDrainPriceCardFor, "logDrainPriceCardFor");
|
|
2205
|
+
__name2(logDrainPriceCardFor, "logDrainPriceCardFor");
|
|
2206
|
+
function priceDrainUsage(totals, card, tier) {
|
|
2207
|
+
const billableRecords = Math.max(0, Math.floor(finiteNonNegative(totals?.billableRecords) ?? 0));
|
|
2208
|
+
const billableBytes = Math.max(0, Math.floor(finiteNonNegative(totals?.billableBytes) ?? 0));
|
|
2209
|
+
const includedEvents = card.includedEventsPerMonth;
|
|
2210
|
+
const includedBytes = card.includedBytesPerMonth;
|
|
2211
|
+
const overageEvents = Math.max(0, billableRecords - includedEvents);
|
|
2212
|
+
const overageBytes = Math.max(0, billableBytes - includedBytes);
|
|
2213
|
+
const eventsUsd = overageEvents / 1e6 * card.usdPerMillionEvents;
|
|
2214
|
+
const bytesUsd = overageBytes / LOG_DRAIN_BYTES_PER_GIB * card.usdPerGiB;
|
|
2215
|
+
const unpriced = card.usdPerMillionEvents === 0 && card.usdPerGiB === 0;
|
|
2216
|
+
const round = /* @__PURE__ */ __name2((usd) => Math.round(usd * 100) / 100, "round");
|
|
2217
|
+
return {
|
|
2218
|
+
lineItem: LOG_DRAIN_USAGE_LINE_ITEM,
|
|
2219
|
+
tier,
|
|
2220
|
+
billableRecords,
|
|
2221
|
+
billableBytes,
|
|
2222
|
+
includedEvents,
|
|
2223
|
+
includedBytes,
|
|
2224
|
+
overageEvents,
|
|
2225
|
+
overageBytes,
|
|
2226
|
+
eventsUsd: round(eventsUsd),
|
|
2227
|
+
bytesUsd: round(bytesUsd),
|
|
2228
|
+
usd: round(Math.max(eventsUsd, bytesUsd)),
|
|
2229
|
+
unpriced
|
|
2230
|
+
};
|
|
2231
|
+
}
|
|
2232
|
+
__name(priceDrainUsage, "priceDrainUsage");
|
|
2233
|
+
__name2(priceDrainUsage, "priceDrainUsage");
|
|
2234
|
+
var LOG_CURSOR_MAX_LENGTH = 512;
|
|
2235
|
+
var LOG_CURSOR_MAX_ID_LENGTH = 128;
|
|
2236
|
+
var LOG_RELATIVE_TIME_PATTERN = /^(\d{1,9})([smhd])$/;
|
|
2237
|
+
var LOG_ISO_TIME_PATTERN = /^\d{4}-\d{2}-\d{2}([Tt ]\d{2}:\d{2}(:\d{2}(\.\d{1,9})?)?([Zz]|[+-]\d{2}:?\d{2})?)?$/;
|
|
2238
|
+
var RELATIVE_UNIT_MS = {
|
|
2239
|
+
s: 1e3,
|
|
2240
|
+
m: 6e4,
|
|
2241
|
+
h: 36e5,
|
|
2242
|
+
d: 864e5
|
|
2243
|
+
};
|
|
2244
|
+
function encodeLogCursor(c) {
|
|
2245
|
+
return Buffer.from(JSON.stringify({
|
|
2246
|
+
t: c.t,
|
|
2247
|
+
id: c.id
|
|
2248
|
+
}), "utf8").toString("base64url");
|
|
2249
|
+
}
|
|
2250
|
+
__name(encodeLogCursor, "encodeLogCursor");
|
|
2251
|
+
__name2(encodeLogCursor, "encodeLogCursor");
|
|
2252
|
+
function decodeLogCursor(raw) {
|
|
2253
|
+
if (typeof raw !== "string") return null;
|
|
2254
|
+
const trimmed = raw.trim();
|
|
2255
|
+
if (!trimmed || trimmed.length > LOG_CURSOR_MAX_LENGTH) return null;
|
|
2256
|
+
let parsed;
|
|
2257
|
+
try {
|
|
2258
|
+
parsed = JSON.parse(Buffer.from(trimmed, "base64url").toString("utf8"));
|
|
2259
|
+
} catch {
|
|
2260
|
+
return null;
|
|
2261
|
+
}
|
|
2262
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return null;
|
|
2263
|
+
const { t, id } = parsed;
|
|
2264
|
+
if (typeof t !== "number" || !Number.isSafeInteger(t) || t < 0) return null;
|
|
2265
|
+
if (typeof id !== "string" || !id || id.length > LOG_CURSOR_MAX_ID_LENGTH) return null;
|
|
2266
|
+
return {
|
|
2267
|
+
t,
|
|
2268
|
+
id
|
|
2269
|
+
};
|
|
2270
|
+
}
|
|
2271
|
+
__name(decodeLogCursor, "decodeLogCursor");
|
|
2272
|
+
__name2(decodeLogCursor, "decodeLogCursor");
|
|
2273
|
+
function parseLogTimeBound(raw, now = /* @__PURE__ */ new Date()) {
|
|
2274
|
+
if (typeof raw !== "string") return null;
|
|
2275
|
+
const value3 = raw.trim();
|
|
2276
|
+
if (!value3) return null;
|
|
2277
|
+
const relative = LOG_RELATIVE_TIME_PATTERN.exec(value3);
|
|
2278
|
+
if (relative) {
|
|
2279
|
+
const amount = Number(relative[1]);
|
|
2280
|
+
const unitMs = RELATIVE_UNIT_MS[relative[2]];
|
|
2281
|
+
if (!Number.isFinite(amount) || unitMs === void 0) return null;
|
|
2282
|
+
const at2 = now.getTime() - amount * unitMs;
|
|
2283
|
+
return Number.isFinite(at2) ? new Date(at2) : null;
|
|
2284
|
+
}
|
|
2285
|
+
if (!LOG_ISO_TIME_PATTERN.test(value3)) return null;
|
|
2286
|
+
const at = Date.parse(value3);
|
|
2287
|
+
return Number.isNaN(at) ? null : new Date(at);
|
|
2288
|
+
}
|
|
2289
|
+
__name(parseLogTimeBound, "parseLogTimeBound");
|
|
2290
|
+
__name2(parseLogTimeBound, "parseLogTimeBound");
|
|
1177
2291
|
var CORE_DRAINING_CODE = "CORE_DRAINING";
|
|
1178
2292
|
var CORE_DRAINING_DEFAULT_RETRY_MS = 1e3;
|
|
1179
2293
|
var CORE_DRAINING_MAX_RETRY_MS = 5e3;
|