stitchkit 0.115.0 → 0.117.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/CHANGELOG.md +67 -0
- package/dist/agent-runtime/coding-tool-paths.d.ts.map +1 -1
- package/dist/agent-runtime/run-acquisition.d.ts +9 -2
- package/dist/agent-runtime/run-acquisition.d.ts.map +1 -1
- package/dist/agent-runtime/run-execution.d.ts +3 -0
- package/dist/agent-runtime/run-execution.d.ts.map +1 -1
- package/dist/agent-runtime/run-failure.d.ts +4 -1
- package/dist/agent-runtime/run-failure.d.ts.map +1 -1
- package/dist/agent-runtime/run-store-retry.d.ts +8 -0
- package/dist/agent-runtime/run-store-retry.d.ts.map +1 -0
- package/dist/agent-runtime/run-terminal.d.ts.map +1 -1
- package/dist/agent-runtime/run-unacquired.d.ts +19 -0
- package/dist/agent-runtime/run-unacquired.d.ts.map +1 -0
- package/dist/agent-runtime/store-conformance.d.ts +8 -0
- package/dist/agent-runtime/store-conformance.d.ts.map +1 -1
- package/dist/agent-runtime/store-driver-contract.d.ts +5 -0
- package/dist/agent-runtime/store-driver-contract.d.ts.map +1 -1
- package/dist/agent-runtime/terminal-commit.d.ts +34 -4
- package/dist/agent-runtime/terminal-commit.d.ts.map +1 -1
- package/dist/entrypoints/agent-runtime/coding-tools.js +4 -4
- package/dist/entrypoints/agent-runtime/harness.js +4 -4
- package/dist/entrypoints/agent-runtime/sandbox.js +4 -4
- package/dist/entrypoints/agent-runtime/sqlite/bun.js +7 -7
- package/dist/entrypoints/agent-runtime/sqlite/node.js +7 -7
- package/dist/entrypoints/agent-runtime/testing.js +26 -8
- package/dist/entrypoints/agent-runtime.d.ts +1 -1
- package/dist/entrypoints/agent-runtime.d.ts.map +1 -1
- package/dist/entrypoints/agent-runtime.js +17 -15
- package/dist/entrypoints/application/diagnostic-journal.js +1 -1
- package/dist/entrypoints/application/directory-inbox.js +3 -3
- package/dist/entrypoints/cli/publish.js +2 -2
- package/dist/entrypoints/cli.js +3 -3
- package/dist/entrypoints/files.js +2 -2
- package/dist/entrypoints/primitives.js +51 -154
- package/dist/entrypoints/server.js +6 -6
- package/dist/entrypoints/telegram/grammy.js +2 -2
- package/dist/entrypoints/telegram.d.ts +1 -1
- package/dist/entrypoints/telegram.d.ts.map +1 -1
- package/dist/entrypoints/telegram.js +203 -70
- package/dist/entrypoints/tools.js +3 -3
- package/dist/entrypoints/tracking/contract.d.ts +11 -0
- package/dist/entrypoints/tracking/contract.d.ts.map +1 -0
- package/dist/entrypoints/tracking/contract.js +162 -0
- package/dist/entrypoints/tracking/performance.d.ts +8 -0
- package/dist/entrypoints/tracking/performance.d.ts.map +1 -0
- package/dist/entrypoints/tracking/performance.js +181 -0
- package/dist/entrypoints/tracking/server.d.ts +1 -0
- package/dist/entrypoints/tracking/server.d.ts.map +1 -1
- package/dist/entrypoints/tracking/server.js +40 -12
- package/dist/entrypoints/tracking.d.ts +4 -3
- package/dist/entrypoints/tracking.d.ts.map +1 -1
- package/dist/entrypoints/tracking.js +43 -143
- package/dist/entrypoints/xlsx.d.ts +4 -0
- package/dist/entrypoints/xlsx.d.ts.map +1 -0
- package/dist/entrypoints/xlsx.js +406 -0
- package/dist/{index-crmswbrt.js → index-073nw9qr.js} +8 -8
- package/dist/index-1f40z584.js +7 -0
- package/dist/{index-nregbbsc.js → index-6f49krb5.js} +1 -1
- package/dist/{index-fdk4r4r6.js → index-75ns2ybj.js} +1 -1
- package/dist/{index-x0ddbj85.js → index-arjmb6de.js} +36 -1
- package/dist/{index-944x38nv.js → index-cycp3r3e.js} +125 -182
- package/dist/{index-dx5cm9pc.js → index-ghtpfz4z.js} +9 -9
- package/dist/{index-n3v695sb.js → index-hdjmdwsj.js} +277 -96
- package/dist/{index-7yx8j6ay.js → index-n5sv4z0w.js} +12 -3
- package/dist/{index-zqkz4af9.js → index-nqxrm176.js} +1 -1
- package/dist/{index-j8kf56wx.js → index-q968hy6y.js} +1 -1
- package/dist/index-qezhmp51.js +242 -0
- package/dist/index-vv1sch8a.js +94 -0
- package/dist/{index-3qqdqwxe.js → index-w7jq3fz9.js} +25 -5
- package/dist/{index-fggxgbrk.js → index-xx1j310k.js} +165 -102
- package/dist/internal/contained-files.d.ts +10 -0
- package/dist/internal/contained-files.d.ts.map +1 -1
- package/dist/internal/exclusive-lock.d.ts.map +1 -1
- package/dist/primitives/decimal.d.ts +10 -0
- package/dist/primitives/decimal.d.ts.map +1 -1
- package/dist/primitives/index.d.ts +3 -1
- package/dist/primitives/index.d.ts.map +1 -1
- package/dist/primitives/money.d.ts +20 -0
- package/dist/primitives/money.d.ts.map +1 -1
- package/dist/primitives/quantity.d.ts.map +1 -1
- package/dist/primitives/rounding.d.ts +40 -0
- package/dist/primitives/rounding.d.ts.map +1 -0
- package/dist/telegram/budget-transformer.d.ts +6 -3
- package/dist/telegram/budget-transformer.d.ts.map +1 -1
- package/dist/telegram/not-dispatched.d.ts +2 -2
- package/dist/telegram/not-dispatched.d.ts.map +1 -1
- package/dist/telegram/outbound-budget.d.ts +72 -20
- package/dist/telegram/outbound-budget.d.ts.map +1 -1
- package/dist/telegram/outbound-cost.d.ts +5 -0
- package/dist/telegram/outbound-cost.d.ts.map +1 -0
- package/dist/telegram/outbound-pauses.d.ts +17 -0
- package/dist/telegram/outbound-pauses.d.ts.map +1 -0
- package/dist/telegram/outbound-queue.d.ts +17 -0
- package/dist/telegram/outbound-queue.d.ts.map +1 -0
- package/dist/tools/cli/view.d.ts +7 -1
- package/dist/tools/cli/view.d.ts.map +1 -1
- package/dist/tracking/attribution.d.ts +1 -1
- package/dist/tracking/attribution.d.ts.map +1 -1
- package/dist/tracking/client-visit.d.ts +3 -1
- package/dist/tracking/client-visit.d.ts.map +1 -1
- package/dist/tracking/client.d.ts.map +1 -1
- package/dist/tracking/performance/collector.d.ts +61 -0
- package/dist/tracking/performance/collector.d.ts.map +1 -0
- package/dist/tracking/performance/schema.d.ts +45 -0
- package/dist/tracking/performance/schema.d.ts.map +1 -0
- package/dist/tracking/performance/summary.d.ts +12 -0
- package/dist/tracking/performance/summary.d.ts.map +1 -0
- package/dist/tracking/privacy.d.ts +5 -0
- package/dist/tracking/privacy.d.ts.map +1 -0
- package/dist/tracking/server/telemetry-health.d.ts +31 -0
- package/dist/tracking/server/telemetry-health.d.ts.map +1 -0
- package/dist/xlsx/cells.d.ts +17 -0
- package/dist/xlsx/cells.d.ts.map +1 -0
- package/dist/xlsx/render.d.ts +11 -0
- package/dist/xlsx/render.d.ts.map +1 -0
- package/dist/xlsx/schema.d.ts +119 -0
- package/dist/xlsx/schema.d.ts.map +1 -0
- package/dist/xlsx/zip.d.ts +13 -0
- package/dist/xlsx/zip.d.ts.map +1 -0
- package/llms/agent-runtime.2.txt +40 -16
- package/llms/agent-runtime.3.txt +17 -0
- package/llms/agent-runtime.txt +6 -3
- package/llms/cli.txt +3 -1
- package/llms/primitives.txt +21 -0
- package/llms/stitchkit.txt +9 -6
- package/llms/telegram.txt +39 -12
- package/llms/tracking-contract.txt +32 -0
- package/llms/tracking-performance.txt +21 -0
- package/llms/tracking-server.txt +1 -0
- package/llms/tracking.txt +75 -12
- package/llms/{upgrading-0.104.0-0.115.0.txt → upgrading-0.105.0-0.117.0.txt} +73 -124
- package/llms/{upgrading-0.44.0-0.61.0.txt → upgrading-0.44.0-0.62.0.txt} +120 -3
- package/llms/{upgrading-0.62.0-0.78.0.txt → upgrading-0.63.0-0.83.0.txt} +181 -120
- package/llms/{upgrading-0.79.0-0.103.13.txt → upgrading-0.84.0-0.104.0.txt} +124 -181
- package/llms/upgrading.txt +4 -4
- package/llms/xlsx.txt +107 -0
- package/llms-full.txt +390 -34
- package/llms.txt +15 -11
- package/package.json +27 -9
- package/dist/{index-z3d6smer.js → index-tdpmfks8.js} +5 -5
|
@@ -5,7 +5,7 @@ import"../index-2kbysk9s.js";
|
|
|
5
5
|
import"../index-n8z3rvzw.js";
|
|
6
6
|
import {
|
|
7
7
|
attemptExclusiveLock
|
|
8
|
-
} from "../index-
|
|
8
|
+
} from "../index-tdpmfks8.js";
|
|
9
9
|
import {
|
|
10
10
|
TELEGRAM_SEND_FAILURE_REASONS2,
|
|
11
11
|
classifyTelegramSendFailure2
|
|
@@ -908,11 +908,8 @@ function telegramOperatorSender(config) {
|
|
|
908
908
|
}
|
|
909
909
|
// src/telegram/outbound-budget.ts
|
|
910
910
|
import { z as z5 } from "zod";
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
var TOKEN = z5.string().min(1, "token must not be empty");
|
|
914
|
-
var MESSAGES_PER_SECOND = z5.number().positive().max(1000);
|
|
915
|
-
var RETRY_AFTER_FALLBACK_MS = z5.number().int().nonnegative().max(MAX_TIMER_MS);
|
|
911
|
+
|
|
912
|
+
// src/telegram/outbound-cost.ts
|
|
916
913
|
var SEND_METHODS = new Set([
|
|
917
914
|
"sendMessage",
|
|
918
915
|
"sendPhoto",
|
|
@@ -959,15 +956,69 @@ function sendCost(method, payload) {
|
|
|
959
956
|
const value = payload[field];
|
|
960
957
|
return Array.isArray(value) ? Math.max(1, value.length) : 1;
|
|
961
958
|
}
|
|
962
|
-
function
|
|
963
|
-
|
|
959
|
+
function chatOf(payload) {
|
|
960
|
+
if (!isRecord(payload))
|
|
961
|
+
return;
|
|
962
|
+
const chat = payload.chat_id;
|
|
963
|
+
return typeof chat === "number" || typeof chat === "string" ? String(chat) : undefined;
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
// src/telegram/outbound-pauses.ts
|
|
967
|
+
function createOutboundPauses({ tokenPauseChats, tokenPauseWindowMs }, now, onPause) {
|
|
968
|
+
const chatPauses = new Map;
|
|
969
|
+
const refusedChats = new Map;
|
|
970
|
+
let pausedUntil = Number.NEGATIVE_INFINITY;
|
|
971
|
+
const pauseEnd = (milliseconds) => {
|
|
972
|
+
if (Number.isNaN(milliseconds) || milliseconds < 0) {
|
|
973
|
+
throw new RangeError("pause must be a non-negative number of milliseconds");
|
|
974
|
+
}
|
|
975
|
+
return now() + (Number.isFinite(milliseconds) ? milliseconds : Number.MAX_SAFE_INTEGER);
|
|
976
|
+
};
|
|
977
|
+
const pauseToken = (milliseconds) => {
|
|
978
|
+
pausedUntil = Math.max(pausedUntil, pauseEnd(milliseconds));
|
|
979
|
+
onPause();
|
|
980
|
+
};
|
|
981
|
+
const forgetExpired = (current) => {
|
|
982
|
+
for (const [chat, until] of chatPauses)
|
|
983
|
+
if (until <= current)
|
|
984
|
+
chatPauses.delete(chat);
|
|
985
|
+
for (const [chat, at] of refusedChats) {
|
|
986
|
+
if (current - at > tokenPauseWindowMs)
|
|
987
|
+
refusedChats.delete(chat);
|
|
988
|
+
}
|
|
989
|
+
};
|
|
990
|
+
return {
|
|
991
|
+
resumesAt: (chat) => Math.max(pausedUntil, (chat === undefined ? undefined : chatPauses.get(chat)) ?? Number.NEGATIVE_INFINITY),
|
|
992
|
+
pauseToken,
|
|
993
|
+
pauseChat(chat, milliseconds) {
|
|
994
|
+
const until = pauseEnd(milliseconds);
|
|
995
|
+
const current = now();
|
|
996
|
+
forgetExpired(current);
|
|
997
|
+
chatPauses.set(chat, Math.max(chatPauses.get(chat) ?? until, until));
|
|
998
|
+
refusedChats.set(chat, current);
|
|
999
|
+
onPause();
|
|
1000
|
+
if (refusedChats.size < tokenPauseChats)
|
|
1001
|
+
return;
|
|
1002
|
+
refusedChats.clear();
|
|
1003
|
+
pauseToken(milliseconds);
|
|
1004
|
+
},
|
|
1005
|
+
pausedForMs: () => Math.max(0, pausedUntil - now()),
|
|
1006
|
+
pausedChats() {
|
|
1007
|
+
forgetExpired(now());
|
|
1008
|
+
return chatPauses.size;
|
|
1009
|
+
}
|
|
1010
|
+
};
|
|
1011
|
+
}
|
|
1012
|
+
|
|
1013
|
+
// src/telegram/outbound-queue.ts
|
|
1014
|
+
function createOutboundQueue(interval, now, sleepFor, pauses) {
|
|
964
1015
|
const queue = [];
|
|
965
1016
|
let nextGrantAt = now();
|
|
966
|
-
let pausedUntil = Number.NEGATIVE_INFINITY;
|
|
967
1017
|
let granted = 0;
|
|
968
1018
|
let messages = 0;
|
|
969
1019
|
let draining = false;
|
|
970
|
-
let
|
|
1020
|
+
let waking;
|
|
1021
|
+
let wakingAt = Number.POSITIVE_INFINITY;
|
|
971
1022
|
const wait = async (milliseconds, signal) => {
|
|
972
1023
|
const delay = Math.min(MAX_TIMER_MS, Math.max(0, milliseconds));
|
|
973
1024
|
if (delay <= 0)
|
|
@@ -978,18 +1029,40 @@ function createBudget(rate, fallback, now, sleepFor) {
|
|
|
978
1029
|
else
|
|
979
1030
|
await pending;
|
|
980
1031
|
};
|
|
981
|
-
const
|
|
982
|
-
const current =
|
|
983
|
-
|
|
1032
|
+
const wake = () => {
|
|
1033
|
+
const current = waking;
|
|
1034
|
+
waking = undefined;
|
|
984
1035
|
current?.abort();
|
|
985
1036
|
};
|
|
1037
|
+
const nextWaiter = (current) => {
|
|
1038
|
+
let bulk;
|
|
1039
|
+
let held;
|
|
1040
|
+
for (const waiter of queue) {
|
|
1041
|
+
if (pauses.resumesAt(waiter.chat) > current) {
|
|
1042
|
+
if (held === undefined || pauses.resumesAt(waiter.chat) < pauses.resumesAt(held.chat)) {
|
|
1043
|
+
held = waiter;
|
|
1044
|
+
}
|
|
1045
|
+
} else if (waiter.lane === "interactive") {
|
|
1046
|
+
return waiter;
|
|
1047
|
+
} else {
|
|
1048
|
+
bulk ??= waiter;
|
|
1049
|
+
}
|
|
1050
|
+
}
|
|
1051
|
+
return bulk ?? held;
|
|
1052
|
+
};
|
|
1053
|
+
const detach = (waiter) => {
|
|
1054
|
+
if (waiter.onAbort)
|
|
1055
|
+
waiter.signal?.removeEventListener("abort", waiter.onAbort);
|
|
1056
|
+
waiter.expiry?.abort();
|
|
1057
|
+
};
|
|
986
1058
|
const remove = (waiter) => {
|
|
987
1059
|
const index = queue.indexOf(waiter);
|
|
988
1060
|
if (index === -1)
|
|
989
1061
|
return;
|
|
1062
|
+
const next = nextWaiter(now()) === waiter;
|
|
990
1063
|
queue.splice(index, 1);
|
|
991
|
-
if (
|
|
992
|
-
|
|
1064
|
+
if (next)
|
|
1065
|
+
wake();
|
|
993
1066
|
};
|
|
994
1067
|
const drain = async () => {
|
|
995
1068
|
if (draining)
|
|
@@ -997,38 +1070,38 @@ function createBudget(rate, fallback, now, sleepFor) {
|
|
|
997
1070
|
draining = true;
|
|
998
1071
|
try {
|
|
999
1072
|
while (queue.length > 0) {
|
|
1000
|
-
const
|
|
1073
|
+
const current = now();
|
|
1074
|
+
const head = nextWaiter(current);
|
|
1001
1075
|
if (head === undefined)
|
|
1002
1076
|
break;
|
|
1003
1077
|
if (head.signal?.aborted) {
|
|
1004
1078
|
remove(head);
|
|
1005
1079
|
continue;
|
|
1006
1080
|
}
|
|
1007
|
-
const
|
|
1008
|
-
const at = Math.max(current, nextGrantAt, pausedUntil);
|
|
1081
|
+
const at = Math.max(current, nextGrantAt, pauses.resumesAt(head.chat));
|
|
1009
1082
|
if (at > current) {
|
|
1010
1083
|
const controller = new AbortController;
|
|
1011
|
-
|
|
1084
|
+
waking = controller;
|
|
1085
|
+
wakingAt = at;
|
|
1012
1086
|
try {
|
|
1013
1087
|
await wait(at - current, controller.signal);
|
|
1014
1088
|
} catch (error) {
|
|
1015
1089
|
if (!controller.signal.aborted) {
|
|
1016
1090
|
for (const waiter of queue.splice(0)) {
|
|
1017
|
-
|
|
1018
|
-
waiter.signal?.removeEventListener("abort", waiter.onAbort);
|
|
1091
|
+
detach(waiter);
|
|
1019
1092
|
waiter.reject(error);
|
|
1020
1093
|
}
|
|
1021
1094
|
return;
|
|
1022
1095
|
}
|
|
1023
1096
|
} finally {
|
|
1024
|
-
if (
|
|
1025
|
-
|
|
1097
|
+
if (waking === controller)
|
|
1098
|
+
waking = undefined;
|
|
1099
|
+
wakingAt = Number.POSITIVE_INFINITY;
|
|
1026
1100
|
}
|
|
1027
1101
|
continue;
|
|
1028
1102
|
}
|
|
1029
|
-
queue.
|
|
1030
|
-
|
|
1031
|
-
head.signal?.removeEventListener("abort", head.onAbort);
|
|
1103
|
+
queue.splice(queue.indexOf(head), 1);
|
|
1104
|
+
detach(head);
|
|
1032
1105
|
nextGrantAt = at + head.cost * interval;
|
|
1033
1106
|
granted += 1;
|
|
1034
1107
|
messages += head.cost;
|
|
@@ -1040,84 +1113,140 @@ function createBudget(rate, fallback, now, sleepFor) {
|
|
|
1040
1113
|
drain();
|
|
1041
1114
|
}
|
|
1042
1115
|
};
|
|
1043
|
-
const
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
remove(waiter);
|
|
1054
|
-
reject(signal.reason);
|
|
1055
|
-
};
|
|
1056
|
-
waiter.onAbort = onAbort;
|
|
1057
|
-
signal.addEventListener("abort", onAbort, { once: true });
|
|
1058
|
-
}
|
|
1059
|
-
queue.push(waiter);
|
|
1060
|
-
drain();
|
|
1116
|
+
const expireAfter = (waiter, maxWaitMs, reject) => {
|
|
1117
|
+
waiter.expiry = new AbortController;
|
|
1118
|
+
wait(maxWaitMs, waiter.expiry.signal).then(() => {
|
|
1119
|
+
if (!queue.includes(waiter))
|
|
1120
|
+
return;
|
|
1121
|
+
remove(waiter);
|
|
1122
|
+
detach(waiter);
|
|
1123
|
+
reject(new TelegramNotDispatchedError2("queue", "the Telegram request waited longer than maxWaitMs for its turn"));
|
|
1124
|
+
}, () => {
|
|
1125
|
+
return;
|
|
1061
1126
|
});
|
|
1062
1127
|
};
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1128
|
+
return {
|
|
1129
|
+
acquire(cost, signal, options) {
|
|
1130
|
+
if (!Number.isSafeInteger(cost) || cost < 1) {
|
|
1131
|
+
return Promise.reject(new RangeError("cost must be an integer of at least one message"));
|
|
1132
|
+
}
|
|
1133
|
+
if (signal?.aborted)
|
|
1134
|
+
return Promise.reject(signal.reason);
|
|
1135
|
+
const maxWaitMs = options?.maxWaitMs;
|
|
1136
|
+
if (maxWaitMs !== undefined && (!Number.isSafeInteger(maxWaitMs) || maxWaitMs < 1 || maxWaitMs > MAX_TIMER_MS)) {
|
|
1137
|
+
return Promise.reject(new RangeError(`maxWaitMs must be an integer from 1 to ${MAX_TIMER_MS}`));
|
|
1138
|
+
}
|
|
1139
|
+
const chat = options?.chatId === undefined ? undefined : String(options.chatId);
|
|
1140
|
+
return new Promise((resolve, reject) => {
|
|
1141
|
+
const waiter = {
|
|
1142
|
+
cost,
|
|
1143
|
+
lane: options?.lane ?? "interactive",
|
|
1144
|
+
chat,
|
|
1145
|
+
resolve,
|
|
1146
|
+
reject,
|
|
1147
|
+
...signal && { signal }
|
|
1148
|
+
};
|
|
1149
|
+
if (signal) {
|
|
1150
|
+
const onAbort = () => {
|
|
1151
|
+
remove(waiter);
|
|
1152
|
+
detach(waiter);
|
|
1153
|
+
reject(signal.reason);
|
|
1154
|
+
};
|
|
1155
|
+
waiter.onAbort = onAbort;
|
|
1156
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
1157
|
+
}
|
|
1158
|
+
if (maxWaitMs !== undefined)
|
|
1159
|
+
expireAfter(waiter, maxWaitMs, reject);
|
|
1160
|
+
queue.push(waiter);
|
|
1161
|
+
if (Math.max(now(), nextGrantAt, pauses.resumesAt(chat)) < wakingAt)
|
|
1162
|
+
wake();
|
|
1163
|
+
drain();
|
|
1164
|
+
});
|
|
1165
|
+
},
|
|
1166
|
+
wake,
|
|
1167
|
+
wait,
|
|
1168
|
+
counts: () => ({
|
|
1169
|
+
granted,
|
|
1170
|
+
messages,
|
|
1171
|
+
queued: queue.length,
|
|
1172
|
+
queuedBulk: queue.filter((waiter) => waiter.lane === "bulk").length
|
|
1173
|
+
})
|
|
1070
1174
|
};
|
|
1071
|
-
|
|
1175
|
+
}
|
|
1176
|
+
|
|
1177
|
+
// src/telegram/outbound-budget.ts
|
|
1178
|
+
var DEFAULT_MESSAGES_PER_SECOND = 24;
|
|
1179
|
+
var DEFAULT_RETRY_AFTER_FALLBACK_MS = 1000;
|
|
1180
|
+
var DEFAULT_TOKEN_PAUSE_CHATS = 3;
|
|
1181
|
+
var DEFAULT_TOKEN_PAUSE_WINDOW_MS = 5000;
|
|
1182
|
+
var TOKEN = z5.string().min(1, "token must not be empty");
|
|
1183
|
+
var MESSAGES_PER_SECOND = z5.number().positive().max(1000);
|
|
1184
|
+
var RETRY_AFTER_FALLBACK_MS = z5.number().int().nonnegative().max(MAX_TIMER_MS);
|
|
1185
|
+
var TOKEN_PAUSE_CHATS = z5.number().int().min(2).max(1000);
|
|
1186
|
+
var TOKEN_PAUSE_WINDOW_MS = z5.number().int().positive().max(MAX_TIMER_MS);
|
|
1187
|
+
function createBudget(policy, now, sleepFor) {
|
|
1188
|
+
const { rate, fallback } = policy;
|
|
1189
|
+
const pauses = createOutboundPauses(policy, now, () => queue.wake());
|
|
1190
|
+
const queue = createOutboundQueue(1000 / rate, now, sleepFor, pauses);
|
|
1191
|
+
const pauseAfter = (error, options) => {
|
|
1072
1192
|
const failure = classifyTelegramSendFailure2(error);
|
|
1073
1193
|
if (failure.reason !== "rate-limited")
|
|
1074
1194
|
return;
|
|
1075
|
-
|
|
1195
|
+
const milliseconds = failure.retryAfterSeconds === undefined ? fallback : failure.retryAfterSeconds * 1000;
|
|
1196
|
+
if (options?.chatId === undefined)
|
|
1197
|
+
pauses.pauseToken(milliseconds);
|
|
1198
|
+
else
|
|
1199
|
+
pauses.pauseChat(String(options.chatId), milliseconds);
|
|
1076
1200
|
};
|
|
1077
|
-
const waitUntilResumed = async (signal) => {
|
|
1201
|
+
const waitUntilResumed = async (signal, options) => {
|
|
1202
|
+
const chat = options?.chatId === undefined ? undefined : String(options.chatId);
|
|
1078
1203
|
while (true) {
|
|
1079
1204
|
if (signal?.aborted)
|
|
1080
1205
|
throw signal.reason;
|
|
1081
|
-
const remaining =
|
|
1206
|
+
const remaining = pauses.resumesAt(chat) - now();
|
|
1082
1207
|
if (remaining <= 0)
|
|
1083
1208
|
return;
|
|
1084
|
-
await wait(Math.min(remaining, MAX_TIMER_MS), signal);
|
|
1209
|
+
await queue.wait(Math.min(remaining, MAX_TIMER_MS), signal);
|
|
1085
1210
|
}
|
|
1086
1211
|
};
|
|
1087
|
-
const run = async (method, payload, signal, send) => {
|
|
1212
|
+
const run = async (method, payload, signal, send, options) => {
|
|
1088
1213
|
if (signal?.aborted)
|
|
1089
1214
|
throw signal.reason;
|
|
1090
1215
|
const cost = sendCost(method, payload);
|
|
1216
|
+
const chatId = options?.chatId ?? chatOf(payload);
|
|
1217
|
+
const call = chatId === undefined ? {} : { chatId };
|
|
1091
1218
|
if (cost > 0)
|
|
1092
|
-
await acquire(cost, signal);
|
|
1219
|
+
await queue.acquire(cost, signal, { ...options, ...call });
|
|
1093
1220
|
if (signal?.aborted)
|
|
1094
1221
|
throw signal.reason;
|
|
1222
|
+
const pauseOnRefusal = (refusal) => {
|
|
1223
|
+
if (cost > 0 && options?.refusal !== "call")
|
|
1224
|
+
pauseAfter(refusal, call);
|
|
1225
|
+
};
|
|
1095
1226
|
let result;
|
|
1096
1227
|
try {
|
|
1097
1228
|
result = await send();
|
|
1098
1229
|
} catch (error) {
|
|
1099
|
-
|
|
1230
|
+
pauseOnRefusal(error);
|
|
1100
1231
|
throw error;
|
|
1101
1232
|
}
|
|
1102
1233
|
if (isRecord(result) && result.ok === false)
|
|
1103
|
-
|
|
1234
|
+
pauseOnRefusal(result);
|
|
1104
1235
|
return result;
|
|
1105
1236
|
};
|
|
1106
|
-
|
|
1237
|
+
return {
|
|
1107
1238
|
run,
|
|
1108
|
-
acquire,
|
|
1109
|
-
pause:
|
|
1239
|
+
acquire: queue.acquire,
|
|
1240
|
+
pause: pauses.pauseToken,
|
|
1110
1241
|
pauseAfter,
|
|
1111
1242
|
waitUntilResumed,
|
|
1112
1243
|
stats: () => ({
|
|
1113
|
-
|
|
1114
|
-
messages,
|
|
1115
|
-
queued: queue.length,
|
|
1244
|
+
...queue.counts(),
|
|
1116
1245
|
messagesPerSecond: rate,
|
|
1117
|
-
pausedForMs:
|
|
1246
|
+
pausedForMs: pauses.pausedForMs(),
|
|
1247
|
+
pausedChats: pauses.pausedChats()
|
|
1118
1248
|
})
|
|
1119
1249
|
};
|
|
1120
|
-
return budget;
|
|
1121
1250
|
}
|
|
1122
1251
|
var budgets = new Map;
|
|
1123
1252
|
function keyOf(token) {
|
|
@@ -1127,20 +1256,24 @@ function telegramOutboundBudget(config) {
|
|
|
1127
1256
|
const token = TOKEN.parse(config.token);
|
|
1128
1257
|
const rate = MESSAGES_PER_SECOND.parse(config.messagesPerSecond ?? DEFAULT_MESSAGES_PER_SECOND);
|
|
1129
1258
|
const fallback = RETRY_AFTER_FALLBACK_MS.parse(config.retryAfterFallbackMs ?? DEFAULT_RETRY_AFTER_FALLBACK_MS);
|
|
1259
|
+
const tokenPauseChats = TOKEN_PAUSE_CHATS.parse(config.tokenPauseChats ?? DEFAULT_TOKEN_PAUSE_CHATS);
|
|
1260
|
+
const tokenPauseWindowMs = TOKEN_PAUSE_WINDOW_MS.parse(config.tokenPauseWindowMs ?? DEFAULT_TOKEN_PAUSE_WINDOW_MS);
|
|
1130
1261
|
const key = keyOf(token);
|
|
1131
1262
|
const existing = budgets.get(key);
|
|
1132
1263
|
if (existing) {
|
|
1133
|
-
const same = existing.rate === rate && existing.fallback === fallback && existing.nowOption === config.now && existing.sleepOption === config.sleep;
|
|
1264
|
+
const same = existing.rate === rate && existing.fallback === fallback && existing.tokenPauseChats === tokenPauseChats && existing.tokenPauseWindowMs === tokenPauseWindowMs && existing.nowOption === config.now && existing.sleepOption === config.sleep;
|
|
1134
1265
|
if (!same) {
|
|
1135
1266
|
throw new Error("a Telegram outbound budget already exists for this token with different options");
|
|
1136
1267
|
}
|
|
1137
1268
|
return existing.budget;
|
|
1138
1269
|
}
|
|
1139
|
-
const budget = createBudget(rate, fallback, config.now ?? (() => performance.now()), config.sleep ?? sleep);
|
|
1270
|
+
const budget = createBudget({ rate, fallback, tokenPauseChats, tokenPauseWindowMs }, config.now ?? (() => performance.now()), config.sleep ?? sleep);
|
|
1140
1271
|
budgets.set(key, {
|
|
1141
1272
|
budget,
|
|
1142
1273
|
rate,
|
|
1143
1274
|
fallback,
|
|
1275
|
+
tokenPauseChats,
|
|
1276
|
+
tokenPauseWindowMs,
|
|
1144
1277
|
nowOption: config.now,
|
|
1145
1278
|
sleepOption: config.sleep
|
|
1146
1279
|
});
|
|
@@ -74,7 +74,7 @@ import {
|
|
|
74
74
|
WaitTimeoutError,
|
|
75
75
|
runWaitOperation,
|
|
76
76
|
createCli2
|
|
77
|
-
} from "../index-
|
|
77
|
+
} from "../index-w7jq3fz9.js";
|
|
78
78
|
import"../index-2kbysk9s.js";
|
|
79
79
|
import {
|
|
80
80
|
ManagedFilePathSchema2,
|
|
@@ -94,8 +94,8 @@ import {
|
|
|
94
94
|
import {
|
|
95
95
|
createToolInvoker2
|
|
96
96
|
} from "../index-vwhrnp67.js";
|
|
97
|
-
import"../index-
|
|
98
|
-
import"../index-
|
|
97
|
+
import"../index-q968hy6y.js";
|
|
98
|
+
import"../index-arjmb6de.js";
|
|
99
99
|
import {
|
|
100
100
|
collectToolSurface
|
|
101
101
|
} from "../index-86nbfysb.js";
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `stitchkit/tracking/contract` — the wire shapes of tracking: the contract
|
|
3
|
+
* factory, the event and visit schemas, and the performance sample with its
|
|
4
|
+
* trust threshold. It brings `zod`, so it belongs to the server and to a shared
|
|
5
|
+
* contract, and browser code that sends events does not import it. → ADR 0280.
|
|
6
|
+
*/
|
|
7
|
+
export { createTrackingContract, type TrackingContractConfig, type TrackingContractEndpoints, } from '../../tracking/contract.js';
|
|
8
|
+
export { type PerformanceSample, PerformanceSampleSchema, type PerformanceVitals, PerformanceVitalsSchema, } from '../../tracking/performance/schema.js';
|
|
9
|
+
export { type PerformanceMetricSummary, summarizePerformanceMetric, } from '../../tracking/performance/summary.js';
|
|
10
|
+
export { type AttributionData, AttributionDataSchema, createTrackingSchemas, DEFAULT_BUILD_ID_PATTERN, type TrackEventsRequest, type TrackEventsResponse, TrackEventsResponseSchema, type TrackingDisposition, TrackingDispositionSchema, type TrackingDispositionStatus, TrackingDispositionStatusSchema, type TrackingEventEnvelope, type TrackingEventShape, type TrackingOutboxState, TrackingOutboxStateSchema, type TrackingSchemas, type TrackingSchemasConfig, type UtmData, UtmDataSchema, type VisitBootstrapResponse, VisitBootstrapResponseSchema, type VisitEntryContext, type VisitEntryContextShape, } from '../../tracking/schemas.js';
|
|
11
|
+
//# sourceMappingURL=contract.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../../../src/entrypoints/tracking/contract.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EACL,sBAAsB,EACtB,KAAK,sBAAsB,EAC3B,KAAK,yBAAyB,GAC/B,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACL,KAAK,iBAAiB,EACtB,uBAAuB,EACvB,KAAK,iBAAiB,EACtB,uBAAuB,GACxB,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EACL,KAAK,wBAAwB,EAC7B,0BAA0B,GAC3B,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EACL,KAAK,eAAe,EACpB,qBAAqB,EACrB,qBAAqB,EACrB,wBAAwB,EACxB,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,EACxB,yBAAyB,EACzB,KAAK,mBAAmB,EACxB,yBAAyB,EACzB,KAAK,yBAAyB,EAC9B,+BAA+B,EAC/B,KAAK,qBAAqB,EAC1B,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,EACxB,yBAAyB,EACzB,KAAK,eAAe,EACpB,KAAK,qBAAqB,EAC1B,KAAK,OAAO,EACZ,aAAa,EACb,KAAK,sBAAsB,EAC3B,4BAA4B,EAC5B,KAAK,iBAAiB,EACtB,KAAK,sBAAsB,GAC5B,MAAM,wBAAwB,CAAC"}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import"../../index-m38ej7e5.js";
|
|
2
|
+
import {
|
|
3
|
+
defineContract2
|
|
4
|
+
} from "../../index-d9hq291n.js";
|
|
5
|
+
|
|
6
|
+
// src/tracking/schemas.ts
|
|
7
|
+
import { z } from "zod";
|
|
8
|
+
var UtmDataSchema = z.object({
|
|
9
|
+
source: z.string().max(200).optional(),
|
|
10
|
+
medium: z.string().max(200).optional(),
|
|
11
|
+
campaign: z.string().max(200).optional(),
|
|
12
|
+
content: z.string().max(200).optional(),
|
|
13
|
+
term: z.string().max(200).optional()
|
|
14
|
+
});
|
|
15
|
+
var AttributionDataSchema = z.object({
|
|
16
|
+
utm: UtmDataSchema.optional(),
|
|
17
|
+
referrer: z.string().optional(),
|
|
18
|
+
landingPage: z.string().optional()
|
|
19
|
+
});
|
|
20
|
+
var DEFAULT_BUILD_ID_PATTERN = /^(dev|[a-f0-9]{7,40})$/;
|
|
21
|
+
var TrackingDispositionStatusSchema = z.enum([
|
|
22
|
+
"accepted",
|
|
23
|
+
"duplicate",
|
|
24
|
+
"identity-invalid",
|
|
25
|
+
"excluded-bot"
|
|
26
|
+
]);
|
|
27
|
+
var TrackingDispositionSchema = z.object({
|
|
28
|
+
eventId: z.uuid(),
|
|
29
|
+
status: TrackingDispositionStatusSchema
|
|
30
|
+
});
|
|
31
|
+
var TrackEventsResponseSchema = z.object({
|
|
32
|
+
accepted: z.number().int().nonnegative(),
|
|
33
|
+
dispositions: z.array(TrackingDispositionSchema)
|
|
34
|
+
});
|
|
35
|
+
var VisitBootstrapResponseSchema = z.object({
|
|
36
|
+
visitId: z.uuid(),
|
|
37
|
+
expiresAt: z.iso.datetime()
|
|
38
|
+
});
|
|
39
|
+
var TrackingOutboxStateSchema = z.enum(["available", "unavailable"]);
|
|
40
|
+
function trackingEventShape(eventTypes) {
|
|
41
|
+
return {
|
|
42
|
+
eventId: z.uuid(),
|
|
43
|
+
visitId: z.uuid(),
|
|
44
|
+
browserStreamId: z.uuid(),
|
|
45
|
+
browserSequence: z.number().int().nonnegative(),
|
|
46
|
+
type: z.enum(eventTypes),
|
|
47
|
+
page: z.string().max(2000),
|
|
48
|
+
metadata: z.record(z.string(), z.unknown()).optional(),
|
|
49
|
+
clientTimestamp: z.number()
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
function visitEntryContextShape(buildIdPattern) {
|
|
53
|
+
return {
|
|
54
|
+
browserStreamId: z.uuid(),
|
|
55
|
+
previousVisitId: z.uuid().optional(),
|
|
56
|
+
origin: z.url().max(500),
|
|
57
|
+
landingPath: z.string().startsWith("/").max(300).regex(/^[^?#]*$/),
|
|
58
|
+
referrer: z.url().max(2000).optional(),
|
|
59
|
+
utm: UtmDataSchema.optional(),
|
|
60
|
+
displayMode: z.enum(["browser", "standalone"]),
|
|
61
|
+
screenWidth: z.number().int().positive().max(20000),
|
|
62
|
+
screenHeight: z.number().int().positive().max(20000),
|
|
63
|
+
buildId: z.string().regex(buildIdPattern),
|
|
64
|
+
outboxState: TrackingOutboxStateSchema,
|
|
65
|
+
outboxQueued: z.number().int().nonnegative().max(1000),
|
|
66
|
+
outboxDropped: z.number().int().nonnegative()
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
function createTrackingSchemas(config) {
|
|
70
|
+
const base = z.object(trackingEventShape(config.eventTypes));
|
|
71
|
+
const event = config.eventExtras ? base.extend(config.eventExtras.shape) : base;
|
|
72
|
+
const buildIdPattern = config.buildIdPattern ?? DEFAULT_BUILD_ID_PATTERN;
|
|
73
|
+
const maxEvents = config.maxEventsPerBatch ?? 50;
|
|
74
|
+
return {
|
|
75
|
+
event,
|
|
76
|
+
request: z.object({
|
|
77
|
+
buildId: z.string().regex(buildIdPattern),
|
|
78
|
+
events: z.array(event).min(1).max(maxEvents),
|
|
79
|
+
utm: UtmDataSchema.optional()
|
|
80
|
+
}),
|
|
81
|
+
response: TrackEventsResponseSchema,
|
|
82
|
+
disposition: TrackingDispositionSchema,
|
|
83
|
+
entry: z.object(visitEntryContextShape(buildIdPattern)),
|
|
84
|
+
bootstrap: VisitBootstrapResponseSchema
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// src/tracking/contract.ts
|
|
89
|
+
function createTrackingContract(config) {
|
|
90
|
+
const schemas = createTrackingSchemas(config);
|
|
91
|
+
return defineContract2({ prefix: config.prefix ?? "tracking", scope: config.scope }, {
|
|
92
|
+
bootstrap: {
|
|
93
|
+
method: "POST",
|
|
94
|
+
path: "/visit",
|
|
95
|
+
expose: ["HTTP"],
|
|
96
|
+
desc: "Issue or renew a browser visit lease",
|
|
97
|
+
input: schemas.entry,
|
|
98
|
+
output: schemas.bootstrap
|
|
99
|
+
},
|
|
100
|
+
track: {
|
|
101
|
+
method: "POST",
|
|
102
|
+
path: "/events",
|
|
103
|
+
expose: ["HTTP"],
|
|
104
|
+
desc: "Batch track browser events",
|
|
105
|
+
input: schemas.request,
|
|
106
|
+
output: schemas.response,
|
|
107
|
+
safelistedBody: true,
|
|
108
|
+
maxJsonBodyBytes: config.maxJsonBodyBytes ?? 256 * 1024
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
// src/tracking/performance/schema.ts
|
|
113
|
+
import { z as z2 } from "zod";
|
|
114
|
+
var BoundedMsSchema = z2.number().nonnegative().max(3600000).nullable();
|
|
115
|
+
var PerformanceVitalsSchema = z2.object({
|
|
116
|
+
lcpMs: BoundedMsSchema,
|
|
117
|
+
inpMs: BoundedMsSchema,
|
|
118
|
+
fcpMs: BoundedMsSchema,
|
|
119
|
+
ttfbMs: BoundedMsSchema,
|
|
120
|
+
cls: z2.number().nonnegative().max(100).nullable()
|
|
121
|
+
});
|
|
122
|
+
var PerformanceSampleSchema = z2.object({
|
|
123
|
+
schemaVersion: z2.literal(1),
|
|
124
|
+
id: z2.string().min(1).max(64),
|
|
125
|
+
kind: z2.enum(["early", "final"]),
|
|
126
|
+
route: z2.string().min(1).max(2000),
|
|
127
|
+
buildId: z2.string().min(1).max(64),
|
|
128
|
+
visitId: z2.string().min(1).max(128).nullable(),
|
|
129
|
+
deviceClass: z2.enum(["mobile", "desktop"]),
|
|
130
|
+
navigationType: z2.string().min(1).max(32).nullable(),
|
|
131
|
+
vitals: PerformanceVitalsSchema,
|
|
132
|
+
capturedAt: z2.number().int().nonnegative()
|
|
133
|
+
});
|
|
134
|
+
// src/tracking/performance/summary.ts
|
|
135
|
+
var DEFAULT_MIN_SAMPLES = 100;
|
|
136
|
+
function percentile(ascending, rank) {
|
|
137
|
+
return ascending[Math.ceil(ascending.length * rank) - 1] ?? null;
|
|
138
|
+
}
|
|
139
|
+
function summarizePerformanceMetric(values, options = {}) {
|
|
140
|
+
const present = values.filter((value) => value !== null).sort((left, right) => left - right);
|
|
141
|
+
const trusted = present.length >= (options.minSamples ?? DEFAULT_MIN_SAMPLES);
|
|
142
|
+
return {
|
|
143
|
+
samples: present.length,
|
|
144
|
+
p75: percentile(present, 0.75),
|
|
145
|
+
p95: trusted ? percentile(present, 0.95) : null
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
export {
|
|
149
|
+
AttributionDataSchema,
|
|
150
|
+
DEFAULT_BUILD_ID_PATTERN,
|
|
151
|
+
PerformanceSampleSchema,
|
|
152
|
+
PerformanceVitalsSchema,
|
|
153
|
+
TrackEventsResponseSchema,
|
|
154
|
+
TrackingDispositionSchema,
|
|
155
|
+
TrackingDispositionStatusSchema,
|
|
156
|
+
TrackingOutboxStateSchema,
|
|
157
|
+
UtmDataSchema,
|
|
158
|
+
VisitBootstrapResponseSchema,
|
|
159
|
+
createTrackingContract,
|
|
160
|
+
createTrackingSchemas,
|
|
161
|
+
summarizePerformanceMetric
|
|
162
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `stitchkit/tracking/performance` — Web Vitals from real visitors, collected
|
|
3
|
+
* after the page has loaded. The sample's schema and the report's trust threshold
|
|
4
|
+
* are `stitchkit/tracking/contract`; tables and reports stay the application's.
|
|
5
|
+
* Importing this needs the optional peer `web-vitals`. → ADR 0280.
|
|
6
|
+
*/
|
|
7
|
+
export { createPerformanceCollector, isLabUserAgent, type PerformanceCollector, type PerformanceCollectorConfig, type PerformanceHost, type VitalsLibrary, type VitalsMetric, type VitalsObserver, } from '../../tracking/performance/collector.js';
|
|
8
|
+
//# sourceMappingURL=performance.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"performance.d.ts","sourceRoot":"","sources":["../../../src/entrypoints/tracking/performance.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EACL,0BAA0B,EAC1B,cAAc,EACd,KAAK,oBAAoB,EACzB,KAAK,0BAA0B,EAC/B,KAAK,eAAe,EACpB,KAAK,aAAa,EAClB,KAAK,YAAY,EACjB,KAAK,cAAc,GACpB,MAAM,sCAAsC,CAAC"}
|