@rubytech/create-maxy-code 0.1.475 → 0.1.477
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/package.json +1 -1
- package/payload/platform/lib/storage-broker/dist/cf-exec.d.ts.map +1 -1
- package/payload/platform/lib/storage-broker/dist/cf-exec.js +3 -2
- package/payload/platform/lib/storage-broker/dist/cf-exec.js.map +1 -1
- package/payload/platform/lib/storage-broker/src/cf-exec.ts +3 -2
- package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +3 -3
- package/payload/platform/plugins/cloudflare/skills/calendar-site/template/schema.sql +13 -3
- package/payload/platform/plugins/docs/references/calendar-booking.md +2 -2
- package/payload/platform/plugins/scheduling/PLUGIN.md +2 -2
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/booking-block-sqlite.test.d.ts +2 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/booking-block-sqlite.test.d.ts.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/booking-block-sqlite.test.js +150 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/booking-block-sqlite.test.js.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/booking-block.test.d.ts +2 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/booking-block.test.d.ts.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/booking-block.test.js +248 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/booking-block.test.js.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/booking-reconcile.test.js +158 -23
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/booking-reconcile.test.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/booking-schema-migration.test.d.ts +2 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/booking-schema-migration.test.d.ts.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/booking-schema-migration.test.js +200 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/booking-schema-migration.test.js.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/connector-sync-provision.test.d.ts +2 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/connector-sync-provision.test.d.ts.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/connector-sync-provision.test.js +309 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/connector-sync-provision.test.js.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/d1-command.test.js +219 -19
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/d1-command.test.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/lib/booking-reconcile.d.ts +184 -11
- package/payload/platform/plugins/scheduling/mcp/dist/lib/booking-reconcile.d.ts.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/lib/booking-reconcile.js +211 -22
- package/payload/platform/plugins/scheduling/mcp/dist/lib/booking-reconcile.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/lib/connector-sync-provision.d.ts +109 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/connector-sync-provision.d.ts.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/connector-sync-provision.js +213 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/connector-sync-provision.js.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/d1-command.d.ts +80 -8
- package/payload/platform/plugins/scheduling/mcp/dist/lib/d1-command.d.ts.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/lib/d1-command.js +202 -8
- package/payload/platform/plugins/scheduling/mcp/dist/lib/d1-command.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/reconcile-bookings.d.ts +6 -4
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/reconcile-bookings.d.ts.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/reconcile-bookings.js +411 -141
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/reconcile-bookings.js.map +1 -1
- package/payload/platform/scripts/cpu-triage.sh +313 -0
- package/payload/server/{chunk-Y6V45R6M.js → chunk-JECAP3Z2.js} +296 -63
- package/payload/server/maxy-edge.js +1 -1
- package/payload/server/public/activity.html +6 -6
- package/payload/server/public/assets/{AdminLoginScreens-B44KbEuC.js → AdminLoginScreens-mEKP4pDi.js} +1 -1
- package/payload/server/public/assets/{AdminShell-BjxV2qkb.js → AdminShell-BwSaZ88d.js} +1 -1
- package/payload/server/public/assets/{Checkbox-DSeZNGNA.js → Checkbox-CN4uQ80w.js} +1 -1
- package/payload/server/public/assets/activity-CIQ8ozNZ.js +1 -0
- package/payload/server/public/assets/{admin-B4LpTCur.js → admin-BVhgfgs1.js} +1 -1
- package/payload/server/public/assets/{browser-CEFvaWwI.js → browser-D-HMmHcM.js} +1 -1
- package/payload/server/public/assets/{calendar-B3zo6V34.js → calendar-tGWvFyFn.js} +1 -1
- package/payload/server/public/assets/chat-DkttVxAz.js +1 -0
- package/payload/server/public/assets/chevron-left-CZ4ez9G5.js +1 -0
- package/payload/server/public/assets/data-P-mcmnNi.js +1 -0
- package/payload/server/public/assets/{graph-labels-GlTEIYJj.js → graph-labels-qnBleOE6.js} +1 -1
- package/payload/server/public/assets/{graph-RaOrnSf2.js → graph-zEw610xK.js} +1 -1
- package/payload/server/public/assets/{maximize-2-CHDa8p5h.js → maximize-2-BlTjXT_Y.js} +1 -1
- package/payload/server/public/assets/{operator-DtqHY4jV.js → operator-C7oIw2PG.js} +1 -1
- package/payload/server/public/assets/{page-DxnWgPtd.js → page-CTP7OFZa.js} +1 -1
- package/payload/server/public/assets/{page-CkhFj8GQ.js → page-DL6Zsdvk.js} +1 -1
- package/payload/server/public/assets/{public-D5TUfQ3I.js → public-r1A9dqR_.js} +1 -1
- package/payload/server/public/assets/{rotate-ccw-BJjVAQQY.js → rotate-ccw-CzkkKx4-.js} +1 -1
- package/payload/server/public/assets/{tasks-CM9pYYG1.js → tasks-fIJwYFWG.js} +1 -1
- package/payload/server/public/assets/{time-entry-format-C5RYEYjM.js → time-entry-format-j669DgXj.js} +1 -1
- package/payload/server/public/assets/{triangle-alert-DLfIsuo_.js → triangle-alert-BPgCgIef.js} +1 -1
- package/payload/server/public/assets/{useCopyFeedback-7yKeiAzV.js → useCopyFeedback-BmLa2aes.js} +1 -1
- package/payload/server/public/assets/{useSelectionMode-CWlh6AEq.js → useSelectionMode-DnnM7A8-.js} +1 -1
- package/payload/server/public/assets/{useSubAccountSwitcher-B2n9QPVI.css → useSubAccountSwitcher-C_E8h07P.css} +1 -1
- package/payload/server/public/assets/{useVoiceRecorder-j3ZArZ2H.js → useVoiceRecorder-u2dwZfen.js} +1 -1
- package/payload/server/public/browser.html +5 -5
- package/payload/server/public/calendar.html +6 -6
- package/payload/server/public/chat.html +12 -12
- package/payload/server/public/data.html +11 -11
- package/payload/server/public/graph.html +11 -11
- package/payload/server/public/index.html +14 -14
- package/payload/server/public/operator.html +14 -14
- package/payload/server/public/public.html +12 -12
- package/payload/server/public/tasks.html +5 -5
- package/payload/server/server.js +358 -189
- package/payload/server/public/assets/activity-Mz1BhgB1.js +0 -1
- package/payload/server/public/assets/chat-5tJdo9i_.js +0 -1
- package/payload/server/public/assets/chevron-left-BJllrPBj.js +0 -1
- package/payload/server/public/assets/data-Du79EgR-.js +0 -1
- /package/payload/server/public/assets/{useSubAccountSwitcher-CBlKgwms.js → useSubAccountSwitcher-CFa6ZAT1.js} +0 -0
package/payload/server/server.js
CHANGED
|
@@ -28,6 +28,7 @@ import {
|
|
|
28
28
|
VNC_DISPLAY,
|
|
29
29
|
WEBSOCKIFY_PORT,
|
|
30
30
|
accessPasswordCollides,
|
|
31
|
+
armedCount,
|
|
31
32
|
autoDeliverPremiumPlugins,
|
|
32
33
|
canAccessAdmin,
|
|
33
34
|
checkRateLimit,
|
|
@@ -71,6 +72,7 @@ import {
|
|
|
71
72
|
isValidAccountId,
|
|
72
73
|
linkConversationTranscript,
|
|
73
74
|
listAdminSessions,
|
|
75
|
+
listLoops,
|
|
74
76
|
listValidAccounts,
|
|
75
77
|
loadAdminUserName,
|
|
76
78
|
loadPersonNameByElementId,
|
|
@@ -81,6 +83,7 @@ import {
|
|
|
81
83
|
projectAgent,
|
|
82
84
|
reconcileEnabledPluginsForAccounts,
|
|
83
85
|
recordFailedAttempt,
|
|
86
|
+
registerLoop,
|
|
84
87
|
registerSession,
|
|
85
88
|
renameConversation,
|
|
86
89
|
renderLoginPage,
|
|
@@ -94,6 +97,8 @@ import {
|
|
|
94
97
|
runAdminUserSelfHeal,
|
|
95
98
|
runUserProfileReconcile,
|
|
96
99
|
safeJson,
|
|
100
|
+
sampleCpu,
|
|
101
|
+
sampleProcessCpu,
|
|
97
102
|
sanitizeClientCorrId,
|
|
98
103
|
serve,
|
|
99
104
|
setAccessPassword,
|
|
@@ -112,7 +117,7 @@ import {
|
|
|
112
117
|
vncLog,
|
|
113
118
|
walkPremiumBundles,
|
|
114
119
|
writeAdminUserAndPerson
|
|
115
|
-
} from "./chunk-
|
|
120
|
+
} from "./chunk-JECAP3Z2.js";
|
|
116
121
|
import {
|
|
117
122
|
D1_MAX_SQL_STATEMENT_BYTES,
|
|
118
123
|
D1_QUERY_MAX_BODY_BYTES,
|
|
@@ -2391,12 +2396,12 @@ function startAuthHealthHeartbeat(intervalMs = 5 * 60 * 1e3) {
|
|
|
2391
2396
|
ticking = false;
|
|
2392
2397
|
}
|
|
2393
2398
|
};
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2399
|
+
return registerLoop({
|
|
2400
|
+
name: "auth-health",
|
|
2401
|
+
intervalMs,
|
|
2402
|
+
firstRunDelayMs: 0,
|
|
2403
|
+
run: tick
|
|
2404
|
+
});
|
|
2400
2405
|
}
|
|
2401
2406
|
async function ensureAuth() {
|
|
2402
2407
|
const health = assessAuthHealth();
|
|
@@ -2809,12 +2814,12 @@ function createBaileysLogger(bindings = {}, authDir) {
|
|
|
2809
2814
|
var credsSaveQueue = Promise.resolve();
|
|
2810
2815
|
async function drainCredsSaveQueue(timeoutMs = 5e3) {
|
|
2811
2816
|
console.error(`${TAG6} draining credential save queue\u2026`);
|
|
2812
|
-
const
|
|
2817
|
+
const timer = new Promise(
|
|
2813
2818
|
(resolve37) => setTimeout(() => resolve37("timeout"), timeoutMs)
|
|
2814
2819
|
);
|
|
2815
2820
|
const result = await Promise.race([
|
|
2816
2821
|
credsSaveQueue.then(() => "drained"),
|
|
2817
|
-
|
|
2822
|
+
timer
|
|
2818
2823
|
]);
|
|
2819
2824
|
if (result === "timeout") {
|
|
2820
2825
|
console.error(`${TAG6} credential save queue drain timed out after ${timeoutMs}ms`);
|
|
@@ -3100,19 +3105,19 @@ function isTimeoutError(err) {
|
|
|
3100
3105
|
}
|
|
3101
3106
|
function withTimeout(label, promise, timeoutMs) {
|
|
3102
3107
|
return new Promise((resolve37, reject) => {
|
|
3103
|
-
const
|
|
3108
|
+
const timer = setTimeout(() => {
|
|
3104
3109
|
const err = new Error(`${label} timed out after ${timeoutMs}ms`);
|
|
3105
3110
|
err.__maxyTimeout = true;
|
|
3106
3111
|
reject(err);
|
|
3107
3112
|
}, timeoutMs);
|
|
3108
|
-
|
|
3113
|
+
timer.unref?.();
|
|
3109
3114
|
promise.then(
|
|
3110
3115
|
(value) => {
|
|
3111
|
-
clearTimeout(
|
|
3116
|
+
clearTimeout(timer);
|
|
3112
3117
|
resolve37(value);
|
|
3113
3118
|
},
|
|
3114
3119
|
(err) => {
|
|
3115
|
-
clearTimeout(
|
|
3120
|
+
clearTimeout(timer);
|
|
3116
3121
|
reject(err);
|
|
3117
3122
|
}
|
|
3118
3123
|
);
|
|
@@ -5197,10 +5202,10 @@ function createInboundDebouncer(opts) {
|
|
|
5197
5202
|
flushKey(key).catch(onError);
|
|
5198
5203
|
}, debounceMs);
|
|
5199
5204
|
} else {
|
|
5200
|
-
const
|
|
5205
|
+
const timer = setTimeout(() => {
|
|
5201
5206
|
flushKey(key).catch(onError);
|
|
5202
5207
|
}, debounceMs);
|
|
5203
|
-
pending.set(key, { entries: [msg], timer
|
|
5208
|
+
pending.set(key, { entries: [msg], timer });
|
|
5204
5209
|
}
|
|
5205
5210
|
}
|
|
5206
5211
|
function registerPending(key, promise) {
|
|
@@ -5855,9 +5860,9 @@ async function connectWithReconnect(conn) {
|
|
|
5855
5860
|
`${TAG17} reconnecting account=${conn.accountId} in ${delay}ms (attempt ${decision.nextAttempts}/${maxAttempts})`
|
|
5856
5861
|
);
|
|
5857
5862
|
await new Promise((resolve37) => {
|
|
5858
|
-
const
|
|
5863
|
+
const timer = setTimeout(resolve37, delay);
|
|
5859
5864
|
conn.abortController.signal.addEventListener("abort", () => {
|
|
5860
|
-
clearTimeout(
|
|
5865
|
+
clearTimeout(timer);
|
|
5861
5866
|
resolve37();
|
|
5862
5867
|
}, { once: true });
|
|
5863
5868
|
});
|
|
@@ -9633,36 +9638,43 @@ app3.post("/r2/object/delete", envelopeBodyLimit("write"), async (c) => {
|
|
|
9633
9638
|
var storage_broker_default = app3;
|
|
9634
9639
|
async function runStorageAudit(root) {
|
|
9635
9640
|
const { reconcileStorage } = await import("./src-JYPKMWJR.js");
|
|
9636
|
-
const
|
|
9637
|
-
|
|
9638
|
-
|
|
9639
|
-
|
|
9640
|
-
|
|
9641
|
-
|
|
9642
|
-
|
|
9643
|
-
|
|
9641
|
+
const cf = await makeHouseCfExec(root);
|
|
9642
|
+
const accountsDir = resolve11(root, "..", "data", "accounts");
|
|
9643
|
+
const strays = (await reconcileStorage({
|
|
9644
|
+
cfD1: async () => (await cf.d1List()).map((d) => d.name),
|
|
9645
|
+
cfR2: async () => (await cf.r2List()).map((b) => b.name),
|
|
9646
|
+
// Its own session per invocation, never one captured from the enclosing
|
|
9647
|
+
// scope. reconcileStorage issues the "d1" and "r2" reads through the same
|
|
9648
|
+
// Promise.all, and a Neo4j session admits one query at a time — sharing one
|
|
9649
|
+
// made the second reject, which left this audit reporting nothing for 802
|
|
9650
|
+
// consecutive ticks on maxy-code and 295 on sitedesk-code. Sessions come
|
|
9651
|
+
// from the driver pool, so one per read is cheap; the alternative,
|
|
9652
|
+
// serialising the library's fan-out, would bend it around this caller.
|
|
9653
|
+
registeredNames: async (kind) => {
|
|
9654
|
+
const session = getSession();
|
|
9655
|
+
try {
|
|
9644
9656
|
const res = await session.run(
|
|
9645
9657
|
"MATCH (r:StorageResource {kind: $kind}) RETURN r.name AS name",
|
|
9646
9658
|
{ kind }
|
|
9647
9659
|
);
|
|
9648
9660
|
return res.records.map((rec) => rec.get("name"));
|
|
9649
|
-
}
|
|
9650
|
-
|
|
9651
|
-
if (!existsSync9(accountsDir)) return [];
|
|
9652
|
-
const files = [];
|
|
9653
|
-
for (const accountId of readdirSync8(accountsDir)) {
|
|
9654
|
-
const p = join13(accountsDir, accountId, "secrets", "cloudflare.env");
|
|
9655
|
-
if (existsSync9(p)) files.push({ accountId, path: p, contents: readFileSync15(p, "utf8") });
|
|
9656
|
-
}
|
|
9657
|
-
return files;
|
|
9661
|
+
} finally {
|
|
9662
|
+
await session.close();
|
|
9658
9663
|
}
|
|
9659
|
-
}
|
|
9660
|
-
|
|
9661
|
-
|
|
9662
|
-
|
|
9663
|
-
|
|
9664
|
-
|
|
9665
|
-
|
|
9664
|
+
},
|
|
9665
|
+
accountSecretsFiles: async () => {
|
|
9666
|
+
if (!existsSync9(accountsDir)) return [];
|
|
9667
|
+
const files = [];
|
|
9668
|
+
for (const accountId of readdirSync8(accountsDir)) {
|
|
9669
|
+
const p = join13(accountsDir, accountId, "secrets", "cloudflare.env");
|
|
9670
|
+
if (existsSync9(p)) files.push({ accountId, path: p, contents: readFileSync15(p, "utf8") });
|
|
9671
|
+
}
|
|
9672
|
+
return files;
|
|
9673
|
+
}
|
|
9674
|
+
})).strays;
|
|
9675
|
+
console.error(
|
|
9676
|
+
`[storage-audit] strays=${strays.length}${strays.map((s) => ` ${s.kind}:${s.detail}`).join("")}`
|
|
9677
|
+
);
|
|
9666
9678
|
}
|
|
9667
9679
|
async function runPagesAudit(root) {
|
|
9668
9680
|
const { reconcilePages } = await import("./src-JYPKMWJR.js");
|
|
@@ -10445,9 +10457,9 @@ function isModelGated(turns) {
|
|
|
10445
10457
|
return turns.some((t) => t.kind === "agent-error" && t.code === "model_unavailable");
|
|
10446
10458
|
}
|
|
10447
10459
|
function renderOrSuppressChannelInbound(u, ts, out, queuedPendingSuppress) {
|
|
10448
|
-
const
|
|
10449
|
-
if (
|
|
10450
|
-
queuedPendingSuppress.set(u.text,
|
|
10460
|
+
const armed2 = queuedPendingSuppress.get(u.text) ?? 0;
|
|
10461
|
+
if (armed2 > 0) {
|
|
10462
|
+
queuedPendingSuppress.set(u.text, armed2 - 1);
|
|
10451
10463
|
} else {
|
|
10452
10464
|
out.push(operatorInboundTurn(u, ts));
|
|
10453
10465
|
}
|
|
@@ -10656,8 +10668,8 @@ function pickActivity(entries, grown, nowMs, concurrencyWindowMs) {
|
|
|
10656
10668
|
|
|
10657
10669
|
// server/routes/stream-lifecycle.ts
|
|
10658
10670
|
var GAUGE_INTERVAL_MS = 6e4;
|
|
10659
|
-
function isArmed(
|
|
10660
|
-
return
|
|
10671
|
+
function isArmed(timer) {
|
|
10672
|
+
return timer._destroyed !== true;
|
|
10661
10673
|
}
|
|
10662
10674
|
var Registration = class {
|
|
10663
10675
|
constructor(connId, channel, startedAt) {
|
|
@@ -10667,9 +10679,9 @@ var Registration = class {
|
|
|
10667
10679
|
}
|
|
10668
10680
|
timers = [];
|
|
10669
10681
|
closed = false;
|
|
10670
|
-
arm(
|
|
10671
|
-
this.timers.push(
|
|
10672
|
-
return
|
|
10682
|
+
arm(timer) {
|
|
10683
|
+
this.timers.push(timer);
|
|
10684
|
+
return timer;
|
|
10673
10685
|
}
|
|
10674
10686
|
teardown(reason) {
|
|
10675
10687
|
if (this.closed) return false;
|
|
@@ -10703,11 +10715,11 @@ function emitGauge() {
|
|
|
10703
10715
|
counts[reg.channel]++;
|
|
10704
10716
|
oldestMs = Math.max(oldestMs, now - reg.startedAt);
|
|
10705
10717
|
}
|
|
10706
|
-
const
|
|
10718
|
+
const armed2 = counts.reader + counts.store;
|
|
10707
10719
|
console.log(
|
|
10708
|
-
`[wa-stream] op=gauge armed=${
|
|
10720
|
+
`[wa-stream] op=gauge armed=${armed2} reader=${counts.reader} store=${counts.store} oldestSec=${Math.floor(oldestMs / 1e3)} stale=${stale}`
|
|
10709
10721
|
);
|
|
10710
|
-
if (
|
|
10722
|
+
if (armed2 === 0) stopGauge();
|
|
10711
10723
|
}
|
|
10712
10724
|
function startGauge() {
|
|
10713
10725
|
if (gaugeTimer) return;
|
|
@@ -13902,12 +13914,21 @@ function checkRateLimit2(ip, cls) {
|
|
|
13902
13914
|
}
|
|
13903
13915
|
return { allow: true, blocked: 0, shouldLog: false };
|
|
13904
13916
|
}
|
|
13905
|
-
|
|
13906
|
-
|
|
13907
|
-
|
|
13908
|
-
|
|
13917
|
+
registerLoop({
|
|
13918
|
+
name: "client-error-rate-cleanup",
|
|
13919
|
+
intervalMs: WINDOW_MS,
|
|
13920
|
+
run: () => {
|
|
13921
|
+
const now = Date.now();
|
|
13922
|
+
let purged = 0;
|
|
13923
|
+
for (const [key, rec] of rateHits) {
|
|
13924
|
+
if (now - rec.windowStart >= WINDOW_MS * 2) {
|
|
13925
|
+
rateHits.delete(key);
|
|
13926
|
+
purged += 1;
|
|
13927
|
+
}
|
|
13928
|
+
}
|
|
13929
|
+
return `purged ${purged}, ${rateHits.size} live`;
|
|
13909
13930
|
}
|
|
13910
|
-
}
|
|
13931
|
+
});
|
|
13911
13932
|
function truncate(value, max) {
|
|
13912
13933
|
if (typeof value !== "string") return "";
|
|
13913
13934
|
return value.length > max ? value.slice(0, max) + "\u2026" : value;
|
|
@@ -20701,18 +20722,18 @@ async function probeConversationDb() {
|
|
|
20701
20722
|
} catch (err) {
|
|
20702
20723
|
return { state: "error", reason: err instanceof Error ? err.message : String(err) };
|
|
20703
20724
|
}
|
|
20704
|
-
let
|
|
20725
|
+
let timer;
|
|
20705
20726
|
try {
|
|
20706
20727
|
const probe = session.run("RETURN 1");
|
|
20707
20728
|
const timeout = new Promise((_, reject) => {
|
|
20708
|
-
|
|
20729
|
+
timer = setTimeout(() => reject(new Error("timeout")), PROBE_TIMEOUT_MS);
|
|
20709
20730
|
});
|
|
20710
20731
|
await Promise.race([probe, timeout]);
|
|
20711
20732
|
return { state: "ok" };
|
|
20712
20733
|
} catch (err) {
|
|
20713
20734
|
return { state: "error", reason: err instanceof Error ? err.message : String(err) };
|
|
20714
20735
|
} finally {
|
|
20715
|
-
if (
|
|
20736
|
+
if (timer) clearTimeout(timer);
|
|
20716
20737
|
session.close().catch(() => {
|
|
20717
20738
|
});
|
|
20718
20739
|
}
|
|
@@ -22383,10 +22404,32 @@ app52.get("/", requireAdminSession, async (c) => {
|
|
|
22383
22404
|
if (name) names[a.accountId] = name;
|
|
22384
22405
|
})
|
|
22385
22406
|
);
|
|
22407
|
+
const sampledAt = Date.now();
|
|
22408
|
+
sampleCpu(sampledAt);
|
|
22409
|
+
const cpu = sampleProcessCpu(sampledAt);
|
|
22410
|
+
const loopRows = listLoops();
|
|
22411
|
+
const armed2 = armedCount();
|
|
22412
|
+
const byState = loopRows.reduce((acc, r) => {
|
|
22413
|
+
acc[r.state] = (acc[r.state] ?? 0) + 1;
|
|
22414
|
+
return acc;
|
|
22415
|
+
}, {});
|
|
22416
|
+
console.log(
|
|
22417
|
+
`${TAG42} op=loops req=${req} armed=${armed2} rendered=${loopRows.length} procPct=${cpu.processPct?.toFixed(1) ?? "null"} attributedPct=${cpu.attributedPct?.toFixed(1) ?? "null"} ` + Object.entries(byState).map(([s, n]) => `${s}=${n}`).join(" ")
|
|
22418
|
+
);
|
|
22386
22419
|
return c.json({
|
|
22387
22420
|
rows,
|
|
22388
22421
|
census,
|
|
22389
22422
|
censusAgeMs,
|
|
22423
|
+
loops: {
|
|
22424
|
+
armed: armed2,
|
|
22425
|
+
rows: loopRows,
|
|
22426
|
+
// The server's own CPU beside what the registry can explain. The GAP is
|
|
22427
|
+
// the point: loops summing to 2% against a process at 60% says the cost
|
|
22428
|
+
// is somewhere else, which small numbers alone would never tell you.
|
|
22429
|
+
processPct: cpu.processPct,
|
|
22430
|
+
attributedPct: cpu.attributedPct,
|
|
22431
|
+
unattributedPct: cpu.unattributedPct
|
|
22432
|
+
},
|
|
22390
22433
|
accounts: {
|
|
22391
22434
|
onDisk,
|
|
22392
22435
|
valid: valid.length,
|
|
@@ -23130,12 +23173,21 @@ function rateLimit(ip, now = Date.now()) {
|
|
|
23130
23173
|
if (b.count > RATE_LIMIT) return { ok: false, resetIn: b.resetAt - now };
|
|
23131
23174
|
return { ok: true, resetIn: b.resetAt - now };
|
|
23132
23175
|
}
|
|
23133
|
-
|
|
23134
|
-
|
|
23135
|
-
|
|
23136
|
-
|
|
23176
|
+
registerLoop({
|
|
23177
|
+
name: "visitor-event-rate-cleanup",
|
|
23178
|
+
intervalMs: 5 * RATE_WINDOW_MS,
|
|
23179
|
+
run: () => {
|
|
23180
|
+
const now = Date.now();
|
|
23181
|
+
let purged = 0;
|
|
23182
|
+
for (const [ip, b] of buckets) {
|
|
23183
|
+
if (now >= b.resetAt) {
|
|
23184
|
+
buckets.delete(ip);
|
|
23185
|
+
purged += 1;
|
|
23186
|
+
}
|
|
23187
|
+
}
|
|
23188
|
+
return `purged ${purged}, ${buckets.size} live`;
|
|
23137
23189
|
}
|
|
23138
|
-
}
|
|
23190
|
+
});
|
|
23139
23191
|
var VALID_TYPES = /* @__PURE__ */ new Set(["pageview", "click", "scroll", "dwell"]);
|
|
23140
23192
|
var ID_RE = /^[A-Za-z0-9_-]{6,128}$/;
|
|
23141
23193
|
function parseEvent(body) {
|
|
@@ -23801,14 +23853,12 @@ function startTimeEntryCensus(openSession, opts = {}) {
|
|
|
23801
23853
|
}
|
|
23802
23854
|
}
|
|
23803
23855
|
};
|
|
23804
|
-
|
|
23805
|
-
|
|
23806
|
-
|
|
23807
|
-
|
|
23808
|
-
|
|
23809
|
-
|
|
23810
|
-
}
|
|
23811
|
-
return () => clearInterval(id);
|
|
23856
|
+
return registerLoop({
|
|
23857
|
+
name: "timeentry-census",
|
|
23858
|
+
intervalMs,
|
|
23859
|
+
firstRunDelayMs: 0,
|
|
23860
|
+
run: tick
|
|
23861
|
+
});
|
|
23812
23862
|
}
|
|
23813
23863
|
|
|
23814
23864
|
// app/lib/ledger-census.ts
|
|
@@ -23962,15 +24012,12 @@ function startLedgerCensus(openSession, opts = {}) {
|
|
|
23962
24012
|
}
|
|
23963
24013
|
}
|
|
23964
24014
|
};
|
|
23965
|
-
|
|
23966
|
-
|
|
23967
|
-
|
|
23968
|
-
|
|
23969
|
-
|
|
23970
|
-
|
|
23971
|
-
id.unref();
|
|
23972
|
-
}
|
|
23973
|
-
return () => clearInterval(id);
|
|
24015
|
+
return registerLoop({
|
|
24016
|
+
name: "ledger-census",
|
|
24017
|
+
intervalMs,
|
|
24018
|
+
firstRunDelayMs: 0,
|
|
24019
|
+
run: tick
|
|
24020
|
+
});
|
|
23974
24021
|
}
|
|
23975
24022
|
|
|
23976
24023
|
// app/lib/conversation-audit.ts
|
|
@@ -24022,7 +24069,7 @@ function renderLabelTop(rows) {
|
|
|
24022
24069
|
return `${labels}:${c}`;
|
|
24023
24070
|
}).join(",");
|
|
24024
24071
|
}
|
|
24025
|
-
var
|
|
24072
|
+
var armed = false;
|
|
24026
24073
|
async function runGraphHealthTick() {
|
|
24027
24074
|
const session = getSession();
|
|
24028
24075
|
try {
|
|
@@ -24117,16 +24164,16 @@ async function verifyUserProfileConstraint() {
|
|
|
24117
24164
|
}
|
|
24118
24165
|
}
|
|
24119
24166
|
function startGraphHealthTimer() {
|
|
24120
|
-
if (
|
|
24167
|
+
if (armed) return;
|
|
24121
24168
|
verifyUserProfileConstraint().catch(() => {
|
|
24122
24169
|
});
|
|
24123
|
-
|
|
24170
|
+
registerLoop({
|
|
24171
|
+
name: "graph-health",
|
|
24172
|
+
intervalMs: HOUR_MS,
|
|
24173
|
+
firstRunDelayMs: 0,
|
|
24174
|
+
run: () => runGraphHealthTick()
|
|
24124
24175
|
});
|
|
24125
|
-
|
|
24126
|
-
runGraphHealthTick().catch(() => {
|
|
24127
|
-
});
|
|
24128
|
-
}, HOUR_MS);
|
|
24129
|
-
if (typeof timer.unref === "function") timer.unref();
|
|
24176
|
+
armed = true;
|
|
24130
24177
|
}
|
|
24131
24178
|
|
|
24132
24179
|
// app/lib/file-watcher.ts
|
|
@@ -24968,10 +25015,28 @@ var WaGateway = class {
|
|
|
24968
25015
|
}
|
|
24969
25016
|
return events;
|
|
24970
25017
|
}
|
|
24971
|
-
/**
|
|
24972
|
-
*
|
|
25018
|
+
/** Arm the periodic reconciliation sweep in the long-lived UI process.
|
|
25019
|
+
*
|
|
25020
|
+
* Task 1814 — armed through the registry, so it appears on /activity. This
|
|
25021
|
+
* gateway is constructed once at module scope in server/index.ts and reached
|
|
25022
|
+
* everywhere else through the singleton accessor in ./instance, so the sweep
|
|
25023
|
+
* is per-install, not per-instance. Returns the registry's disarm function
|
|
25024
|
+
* rather than the interval handle; no caller reads it.
|
|
25025
|
+
*
|
|
25026
|
+
* Two semantics move with it. The timer is now unref'd, where the bare
|
|
25027
|
+
* setInterval was not: a loop is a passenger of the process, never what
|
|
25028
|
+
* keeps it alive. And a throwing sweep is recorded as lastError instead of
|
|
25029
|
+
* surfacing as an uncaught timer exception, so a sweep that fails every
|
|
25030
|
+
* tick now reads as a failing row on /activity rather than a crash. */
|
|
24973
25031
|
startSweeper(intervalMs = SWEEP_INTERVAL_MS) {
|
|
24974
|
-
return
|
|
25032
|
+
return registerLoop({
|
|
25033
|
+
name: "whatsapp-native-sweep",
|
|
25034
|
+
intervalMs,
|
|
25035
|
+
run: () => {
|
|
25036
|
+
const events = this.reconcile(Date.now());
|
|
25037
|
+
return events.length > 0 ? `${events.length} terminal events` : void 0;
|
|
25038
|
+
}
|
|
25039
|
+
});
|
|
24975
25040
|
}
|
|
24976
25041
|
/** Handle one inbound admin WhatsApp message. */
|
|
24977
25042
|
async handleInbound(input) {
|
|
@@ -25446,13 +25511,13 @@ var WebchatGateway = class _WebchatGateway {
|
|
|
25446
25511
|
* response, preserving the pre-756 POST→single-blob browser contract. */
|
|
25447
25512
|
awaitReply(key, timeoutMs) {
|
|
25448
25513
|
return new Promise((resolve37) => {
|
|
25449
|
-
const
|
|
25514
|
+
const timer = setTimeout(() => {
|
|
25450
25515
|
this.replyAwaiters.delete(key);
|
|
25451
25516
|
resolve37({ timeout: true });
|
|
25452
25517
|
}, timeoutMs);
|
|
25453
|
-
if (
|
|
25518
|
+
if (timer.unref) timer.unref();
|
|
25454
25519
|
this.replyAwaiters.set(key, (r) => {
|
|
25455
|
-
clearTimeout(
|
|
25520
|
+
clearTimeout(timer);
|
|
25456
25521
|
this.replyAwaiters.delete(key);
|
|
25457
25522
|
resolve37(r);
|
|
25458
25523
|
});
|
|
@@ -25467,16 +25532,16 @@ var WebchatGateway = class _WebchatGateway {
|
|
|
25467
25532
|
const k = _WebchatGateway.promptKey(p.key, p.requestId);
|
|
25468
25533
|
return new Promise((resolve37) => {
|
|
25469
25534
|
this.pendingPrompts.get(k)?.resolve({ timeout: true });
|
|
25470
|
-
const
|
|
25535
|
+
const timer = setTimeout(() => {
|
|
25471
25536
|
this.pendingPrompts.delete(k);
|
|
25472
25537
|
resolve37({ timeout: true });
|
|
25473
25538
|
}, timeoutMs);
|
|
25474
|
-
if (
|
|
25539
|
+
if (timer.unref) timer.unref();
|
|
25475
25540
|
this.pendingPrompts.set(k, {
|
|
25476
25541
|
...p,
|
|
25477
25542
|
at: Date.now(),
|
|
25478
25543
|
resolve: (r) => {
|
|
25479
|
-
clearTimeout(
|
|
25544
|
+
clearTimeout(timer);
|
|
25480
25545
|
this.pendingPrompts.delete(k);
|
|
25481
25546
|
resolve37(r);
|
|
25482
25547
|
}
|
|
@@ -25544,11 +25609,22 @@ var WebchatGateway = class _WebchatGateway {
|
|
|
25544
25609
|
void this.deps.deleteSession?.(rec.sessionId);
|
|
25545
25610
|
}
|
|
25546
25611
|
}
|
|
25547
|
-
/**
|
|
25612
|
+
/** Arm the periodic public idle reaper in the long-lived UI process.
|
|
25613
|
+
*
|
|
25614
|
+
* Task 1814 — armed through the registry, so it appears on /activity. Like
|
|
25615
|
+
* the sweeper below, this is per-install: one gateway per server, reached
|
|
25616
|
+
* through the singleton accessor in ./instance. Returns the registry's
|
|
25617
|
+
* disarm function rather than the interval handle; no caller reads it.
|
|
25618
|
+
*
|
|
25619
|
+
* This one already unref'd its handle, so only the error semantics move: a
|
|
25620
|
+
* throwing reap is recorded as lastError rather than surfacing as an
|
|
25621
|
+
* uncaught timer exception. */
|
|
25548
25622
|
startPublicReaper(intervalMs = 6e4) {
|
|
25549
|
-
|
|
25550
|
-
|
|
25551
|
-
|
|
25623
|
+
return registerLoop({
|
|
25624
|
+
name: "webchat-public-reaper",
|
|
25625
|
+
intervalMs,
|
|
25626
|
+
run: () => this.reapPublic(Date.now())
|
|
25627
|
+
});
|
|
25552
25628
|
}
|
|
25553
25629
|
/** A gated public PTY exited explicitly on the manager side (operator stop,
|
|
25554
25630
|
* claude crash, manager DELETE), not via the idle reaper. The manager POSTs
|
|
@@ -25630,15 +25706,36 @@ var WebchatGateway = class _WebchatGateway {
|
|
|
25630
25706
|
}
|
|
25631
25707
|
return events;
|
|
25632
25708
|
}
|
|
25633
|
-
/**
|
|
25709
|
+
/** Arm the periodic reconciliation sweep in the long-lived UI process. Each
|
|
25634
25710
|
* tick runs the sync sweep (drain-/inbound-undelivered) AND the async
|
|
25635
|
-
* recovery pass for queued-no-subscriber messages (Task-962).
|
|
25711
|
+
* recovery pass for queued-no-subscriber messages (Task-962).
|
|
25712
|
+
*
|
|
25713
|
+
* Task 1814 — armed through the registry, so it appears on /activity. This
|
|
25714
|
+
* gateway is constructed once at module scope in server/index.ts and reached
|
|
25715
|
+
* everywhere else through the singleton accessor in ./instance, so the sweep
|
|
25716
|
+
* is per-install, not per-instance. Returns the registry's disarm function
|
|
25717
|
+
* rather than the interval handle; no caller reads it.
|
|
25718
|
+
*
|
|
25719
|
+
* Two semantics move with it. The timer is now unref'd, where the bare
|
|
25720
|
+
* setInterval was not: a loop is a passenger of the process, never what
|
|
25721
|
+
* keeps it alive. And a throwing sweep is recorded as lastError instead of
|
|
25722
|
+
* surfacing as an uncaught timer exception, so a sweep that fails every
|
|
25723
|
+
* tick now reads as a failing row on /activity rather than a crash.
|
|
25724
|
+
*
|
|
25725
|
+
* recoverStalled stays fire-and-forget, exactly as it was: run() returns the
|
|
25726
|
+
* sync note, so the registry's duration covers the sweep and not the
|
|
25727
|
+
* recovery pass. */
|
|
25636
25728
|
startSweeper(intervalMs = SWEEP_INTERVAL_MS2) {
|
|
25637
|
-
return
|
|
25638
|
-
|
|
25639
|
-
|
|
25640
|
-
|
|
25641
|
-
|
|
25729
|
+
return registerLoop({
|
|
25730
|
+
name: "webchat-inbound-sweep",
|
|
25731
|
+
intervalMs,
|
|
25732
|
+
run: () => {
|
|
25733
|
+
const now = Date.now();
|
|
25734
|
+
const events = this.reconcile(now);
|
|
25735
|
+
void this.recoverStalled(now);
|
|
25736
|
+
return events.length > 0 ? `${events.length} terminal events` : void 0;
|
|
25737
|
+
}
|
|
25738
|
+
});
|
|
25642
25739
|
}
|
|
25643
25740
|
/** Task-962 — the per-session delivery-failure marker for the /session pointer.
|
|
25644
25741
|
* Non-null only when redelivery was exhausted for `key`; cleared on the next
|
|
@@ -26576,9 +26673,28 @@ var TelegramGateway = class {
|
|
|
26576
26673
|
}
|
|
26577
26674
|
return events;
|
|
26578
26675
|
}
|
|
26579
|
-
/**
|
|
26676
|
+
/** Arm the periodic reconciliation sweep in the long-lived UI process.
|
|
26677
|
+
*
|
|
26678
|
+
* Task 1814 — armed through the registry, so it appears on /activity. This
|
|
26679
|
+
* gateway is constructed once at module scope in server/index.ts and reached
|
|
26680
|
+
* everywhere else through the singleton accessor in ./instance, so the sweep
|
|
26681
|
+
* is per-install, not per-instance. Returns the registry's disarm function
|
|
26682
|
+
* rather than the interval handle; no caller reads it.
|
|
26683
|
+
*
|
|
26684
|
+
* Two semantics move with it. The timer is now unref'd, where the bare
|
|
26685
|
+
* setInterval was not: a loop is a passenger of the process, never what
|
|
26686
|
+
* keeps it alive. And a throwing sweep is recorded as lastError instead of
|
|
26687
|
+
* surfacing as an uncaught timer exception, so a sweep that fails every
|
|
26688
|
+
* tick now reads as a failing row on /activity rather than a crash. */
|
|
26580
26689
|
startSweeper(intervalMs = SWEEP_INTERVAL_MS3) {
|
|
26581
|
-
return
|
|
26690
|
+
return registerLoop({
|
|
26691
|
+
name: "telegram-native-sweep",
|
|
26692
|
+
intervalMs,
|
|
26693
|
+
run: () => {
|
|
26694
|
+
const events = this.reconcile(Date.now());
|
|
26695
|
+
return events.length > 0 ? `${events.length} terminal events` : void 0;
|
|
26696
|
+
}
|
|
26697
|
+
});
|
|
26582
26698
|
}
|
|
26583
26699
|
/** Handle one inbound telegram message. */
|
|
26584
26700
|
async handleInbound(input) {
|
|
@@ -27569,8 +27685,12 @@ function runDuplicateSenderAudit() {
|
|
|
27569
27685
|
console.error(`[whatsapp-native] op=duplicate-sender-audit-error error=${err instanceof Error ? err.message : String(err)}`);
|
|
27570
27686
|
}
|
|
27571
27687
|
}
|
|
27572
|
-
|
|
27573
|
-
|
|
27688
|
+
registerLoop({
|
|
27689
|
+
name: "whatsapp-duplicate-sender-audit",
|
|
27690
|
+
intervalMs: 15 * 6e4,
|
|
27691
|
+
firstRunDelayMs: 0,
|
|
27692
|
+
run: runDuplicateSenderAudit
|
|
27693
|
+
});
|
|
27574
27694
|
var webchatGateway = new WebchatGateway({
|
|
27575
27695
|
fetchStandingRules: fetchAccountStandingRules,
|
|
27576
27696
|
gatewayUrl: webchatGatewayUrl(),
|
|
@@ -28499,7 +28619,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
28499
28619
|
const reconcilePlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join42(__dirname, "..");
|
|
28500
28620
|
const reconcileScript = resolve36(reconcilePlatformRoot, "plugins/scheduling/mcp/dist/scripts/reconcile-bookings.js");
|
|
28501
28621
|
const RECONCILE_INTERVAL_MS = 12e4;
|
|
28502
|
-
const runReconcile = () => {
|
|
28622
|
+
const runReconcile = (ctx) => {
|
|
28503
28623
|
if (!existsSync38(reconcileScript)) return;
|
|
28504
28624
|
try {
|
|
28505
28625
|
const child = spawn3(process.execPath, [reconcileScript], {
|
|
@@ -28507,21 +28627,25 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
28507
28627
|
stdio: "inherit"
|
|
28508
28628
|
});
|
|
28509
28629
|
child.unref();
|
|
28630
|
+
ctx.child(child.pid);
|
|
28510
28631
|
child.on("error", (err) => console.error(`[calendar-reconcile] spawn-failed err="${err.message}"`));
|
|
28511
28632
|
} catch (err) {
|
|
28512
28633
|
console.error(`[calendar-reconcile] spawn-failed err="${err.message}"`);
|
|
28513
28634
|
}
|
|
28514
28635
|
};
|
|
28515
|
-
|
|
28516
|
-
|
|
28517
|
-
|
|
28518
|
-
|
|
28636
|
+
registerLoop({
|
|
28637
|
+
name: "calendar-reconcile",
|
|
28638
|
+
intervalMs: RECONCILE_INTERVAL_MS,
|
|
28639
|
+
firstRunDelayMs: 15e3,
|
|
28640
|
+
detached: true,
|
|
28641
|
+
run: runReconcile
|
|
28642
|
+
});
|
|
28519
28643
|
}
|
|
28520
28644
|
{
|
|
28521
28645
|
const outlookPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join42(__dirname, "..");
|
|
28522
28646
|
const outlookScript = resolve36(outlookPlatformRoot, "plugins/outlook/mcp/dist/scripts/complete-registration.js");
|
|
28523
28647
|
const OUTLOOK_COMPLETE_INTERVAL_MS = 3e4;
|
|
28524
|
-
const runOutlookComplete = () => {
|
|
28648
|
+
const runOutlookComplete = (ctx) => {
|
|
28525
28649
|
if (!existsSync38(outlookScript)) return;
|
|
28526
28650
|
try {
|
|
28527
28651
|
const child = spawn3(process.execPath, [outlookScript], {
|
|
@@ -28529,15 +28653,19 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
28529
28653
|
stdio: "inherit"
|
|
28530
28654
|
});
|
|
28531
28655
|
child.unref();
|
|
28656
|
+
ctx.child(child.pid);
|
|
28532
28657
|
child.on("error", (err) => console.error(`[outlook-complete] spawn-failed err="${err.message}"`));
|
|
28533
28658
|
} catch (err) {
|
|
28534
28659
|
console.error(`[outlook-complete] spawn-failed err="${err.message}"`);
|
|
28535
28660
|
}
|
|
28536
28661
|
};
|
|
28537
|
-
|
|
28538
|
-
|
|
28539
|
-
|
|
28540
|
-
|
|
28662
|
+
registerLoop({
|
|
28663
|
+
name: "outlook-devicecode-complete",
|
|
28664
|
+
intervalMs: OUTLOOK_COMPLETE_INTERVAL_MS,
|
|
28665
|
+
firstRunDelayMs: 18e3,
|
|
28666
|
+
detached: true,
|
|
28667
|
+
run: runOutlookComplete
|
|
28668
|
+
});
|
|
28541
28669
|
}
|
|
28542
28670
|
{
|
|
28543
28671
|
const auditRoot = process.env.MAXY_PLATFORM_ROOT ?? join42(__dirname, "..");
|
|
@@ -28562,10 +28690,12 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
28562
28690
|
console.error(`[outlook-mcp] devicecode-stranded-audit error="${err.message}"`);
|
|
28563
28691
|
}
|
|
28564
28692
|
};
|
|
28565
|
-
|
|
28566
|
-
|
|
28567
|
-
|
|
28568
|
-
|
|
28693
|
+
registerLoop({
|
|
28694
|
+
name: "outlook-stranded-audit",
|
|
28695
|
+
intervalMs: STRANDED_AUDIT_INTERVAL_MS,
|
|
28696
|
+
firstRunDelayMs: 25e3,
|
|
28697
|
+
run: runStrandedAudit
|
|
28698
|
+
});
|
|
28569
28699
|
}
|
|
28570
28700
|
{
|
|
28571
28701
|
const googleRoot = process.env.MAXY_PLATFORM_ROOT ?? join42(__dirname, "..");
|
|
@@ -28578,13 +28708,15 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
28578
28708
|
console.error(`[google-oauth] op=pending-audit-error error="${err.message}"`);
|
|
28579
28709
|
}
|
|
28580
28710
|
};
|
|
28581
|
-
|
|
28582
|
-
|
|
28583
|
-
|
|
28584
|
-
|
|
28711
|
+
registerLoop({
|
|
28712
|
+
name: "google-pending-audit",
|
|
28713
|
+
intervalMs: GOOGLE_PENDING_AUDIT_INTERVAL_MS,
|
|
28714
|
+
firstRunDelayMs: 27e3,
|
|
28715
|
+
run: runGooglePendingAuditSafe
|
|
28716
|
+
});
|
|
28585
28717
|
const googleAuditScript = resolve36(googleRoot, "plugins/google/mcp/dist/scripts/account-audit.js");
|
|
28586
28718
|
const GOOGLE_ACCOUNT_AUDIT_INTERVAL_MS = 36e5;
|
|
28587
|
-
const runGoogleAccountAudit = () => {
|
|
28719
|
+
const runGoogleAccountAudit = (ctx) => {
|
|
28588
28720
|
if (!existsSync38(googleAuditScript)) return;
|
|
28589
28721
|
try {
|
|
28590
28722
|
const child = spawn3(process.execPath, [googleAuditScript], {
|
|
@@ -28592,6 +28724,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
28592
28724
|
stdio: "inherit"
|
|
28593
28725
|
});
|
|
28594
28726
|
child.unref();
|
|
28727
|
+
ctx.child(child.pid);
|
|
28595
28728
|
child.on(
|
|
28596
28729
|
"error",
|
|
28597
28730
|
(err) => console.error(`[google-account-audit] op=spawn-failed error="${err.message}"`)
|
|
@@ -28600,32 +28733,37 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
28600
28733
|
console.error(`[google-account-audit] op=spawn-failed error="${err.message}"`);
|
|
28601
28734
|
}
|
|
28602
28735
|
};
|
|
28603
|
-
|
|
28604
|
-
|
|
28605
|
-
|
|
28606
|
-
|
|
28736
|
+
registerLoop({
|
|
28737
|
+
name: "google-account-audit",
|
|
28738
|
+
intervalMs: GOOGLE_ACCOUNT_AUDIT_INTERVAL_MS,
|
|
28739
|
+
firstRunDelayMs: 45e3,
|
|
28740
|
+
detached: true,
|
|
28741
|
+
run: runGoogleAccountAudit
|
|
28742
|
+
});
|
|
28607
28743
|
}
|
|
28608
28744
|
{
|
|
28609
28745
|
const auditPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join42(__dirname, "..");
|
|
28610
28746
|
const STORAGE_AUDIT_INTERVAL_MS = 3e5;
|
|
28611
|
-
const runStorageAuditSafe = () => {
|
|
28612
|
-
|
|
28613
|
-
|
|
28614
|
-
|
|
28615
|
-
|
|
28616
|
-
|
|
28617
|
-
|
|
28618
|
-
|
|
28619
|
-
|
|
28620
|
-
|
|
28621
|
-
|
|
28622
|
-
|
|
28623
|
-
|
|
28624
|
-
};
|
|
28625
|
-
|
|
28626
|
-
|
|
28627
|
-
|
|
28628
|
-
|
|
28747
|
+
const runStorageAuditSafe = () => runStorageAudit(auditPlatformRoot).catch((err) => {
|
|
28748
|
+
console.error(`[storage-audit] error="${err.message}"`);
|
|
28749
|
+
throw err;
|
|
28750
|
+
});
|
|
28751
|
+
registerLoop({
|
|
28752
|
+
name: "storage-audit",
|
|
28753
|
+
intervalMs: STORAGE_AUDIT_INTERVAL_MS,
|
|
28754
|
+
firstRunDelayMs: 2e4,
|
|
28755
|
+
run: runStorageAuditSafe
|
|
28756
|
+
});
|
|
28757
|
+
const runPagesAuditSafe = () => runPagesAudit(auditPlatformRoot).catch((err) => {
|
|
28758
|
+
console.error(`[pages-audit] error="${err.message}"`);
|
|
28759
|
+
throw err;
|
|
28760
|
+
});
|
|
28761
|
+
registerLoop({
|
|
28762
|
+
name: "pages-audit",
|
|
28763
|
+
intervalMs: STORAGE_AUDIT_INTERVAL_MS,
|
|
28764
|
+
firstRunDelayMs: 35e3,
|
|
28765
|
+
run: runPagesAuditSafe
|
|
28766
|
+
});
|
|
28629
28767
|
}
|
|
28630
28768
|
{
|
|
28631
28769
|
const publishPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join42(__dirname, "..");
|
|
@@ -28639,7 +28777,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
28639
28777
|
return null;
|
|
28640
28778
|
}
|
|
28641
28779
|
};
|
|
28642
|
-
const spawnPublish = (account) => {
|
|
28780
|
+
const spawnPublish = (account, ctx) => {
|
|
28643
28781
|
if (!existsSync38(publishScript)) return;
|
|
28644
28782
|
try {
|
|
28645
28783
|
const child = spawn3(process.execPath, [publishScript], {
|
|
@@ -28652,6 +28790,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
28652
28790
|
stdio: "inherit"
|
|
28653
28791
|
});
|
|
28654
28792
|
child.unref();
|
|
28793
|
+
ctx.child(child.pid);
|
|
28655
28794
|
child.on("error", (err) => console.error(`[calendar-availability] op=publish result=error reason=spawn-failed err="${err.message}"`));
|
|
28656
28795
|
} catch (err) {
|
|
28657
28796
|
console.error(`[calendar-availability] op=publish result=error reason=spawn-failed err="${err.message}"`);
|
|
@@ -28683,16 +28822,19 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
28683
28822
|
const ageMs = Number.isNaN(parsed) ? null : Date.now() - parsed;
|
|
28684
28823
|
console.error(`[calendar-availability] op=audit accountId=${account.accountId} snapshotAgeMs=${ageMs ?? "na"}`);
|
|
28685
28824
|
};
|
|
28686
|
-
const publishTick = () => {
|
|
28825
|
+
const publishTick = (ctx) => {
|
|
28687
28826
|
const account = currentAccount();
|
|
28688
28827
|
if (!account) return;
|
|
28689
|
-
spawnPublish(account);
|
|
28828
|
+
spawnPublish(account, ctx);
|
|
28690
28829
|
auditSnapshotAge(account);
|
|
28691
28830
|
};
|
|
28692
|
-
|
|
28693
|
-
|
|
28694
|
-
|
|
28695
|
-
|
|
28831
|
+
registerLoop({
|
|
28832
|
+
name: "calendar-availability-publish",
|
|
28833
|
+
intervalMs: PUBLISH_INTERVAL_MS,
|
|
28834
|
+
firstRunDelayMs: 2e4,
|
|
28835
|
+
detached: true,
|
|
28836
|
+
run: publishTick
|
|
28837
|
+
});
|
|
28696
28838
|
}
|
|
28697
28839
|
startTimeEntryCensus(() => getSession());
|
|
28698
28840
|
startLedgerCensus(() => getSession());
|
|
@@ -28701,7 +28843,7 @@ startLedgerCensus(() => getSession());
|
|
|
28701
28843
|
const auditScript = resolve36(auditPlatformRoot, "plugins/connector/mcp/dist/scripts/audit-connectors.js");
|
|
28702
28844
|
const auditLogDir = process.env.LOG_DIR ?? LOG_DIR;
|
|
28703
28845
|
const CONNECTOR_AUDIT_INTERVAL_MS = 3e5;
|
|
28704
|
-
const runConnectorAudit = () => {
|
|
28846
|
+
const runConnectorAudit = (ctx) => {
|
|
28705
28847
|
if (!existsSync38(auditScript)) return;
|
|
28706
28848
|
try {
|
|
28707
28849
|
const child = spawn3(process.execPath, [auditScript], {
|
|
@@ -28709,15 +28851,19 @@ startLedgerCensus(() => getSession());
|
|
|
28709
28851
|
stdio: "inherit"
|
|
28710
28852
|
});
|
|
28711
28853
|
child.unref();
|
|
28854
|
+
ctx.child(child.pid);
|
|
28712
28855
|
child.on("error", (err) => console.error(`[connector-audit] spawn-failed err="${err.message}"`));
|
|
28713
28856
|
} catch (err) {
|
|
28714
28857
|
console.error(`[connector-audit] spawn-failed err="${err.message}"`);
|
|
28715
28858
|
}
|
|
28716
28859
|
};
|
|
28717
|
-
|
|
28718
|
-
|
|
28719
|
-
|
|
28720
|
-
|
|
28860
|
+
registerLoop({
|
|
28861
|
+
name: "connector-audit",
|
|
28862
|
+
intervalMs: CONNECTOR_AUDIT_INTERVAL_MS,
|
|
28863
|
+
firstRunDelayMs: 3e4,
|
|
28864
|
+
detached: true,
|
|
28865
|
+
run: runConnectorAudit
|
|
28866
|
+
});
|
|
28721
28867
|
}
|
|
28722
28868
|
{
|
|
28723
28869
|
const census = pwaCensus({
|
|
@@ -28740,15 +28886,19 @@ startAuthHealthHeartbeat();
|
|
|
28740
28886
|
loopHist.enable();
|
|
28741
28887
|
const LOG_THRESHOLD_MS = 1e3;
|
|
28742
28888
|
const WINDOW_MS2 = 3e4;
|
|
28743
|
-
|
|
28744
|
-
|
|
28745
|
-
|
|
28746
|
-
|
|
28747
|
-
|
|
28748
|
-
|
|
28889
|
+
registerLoop({
|
|
28890
|
+
name: "event-loop-lag",
|
|
28891
|
+
intervalMs: WINDOW_MS2,
|
|
28892
|
+
run: () => {
|
|
28893
|
+
const maxMs = loopHist.max / 1e6;
|
|
28894
|
+
const p99Ms = loopHist.percentile(99) / 1e6;
|
|
28895
|
+
loopHist.reset();
|
|
28896
|
+
if (maxMs >= LOG_THRESHOLD_MS) {
|
|
28897
|
+
console.error(`[event-loop] lag p99=${Math.round(p99Ms)} max=${Math.round(maxMs)} window=${WINDOW_MS2 / 1e3}s`);
|
|
28898
|
+
}
|
|
28899
|
+
return `p99 ${Math.round(p99Ms)}ms, max ${Math.round(maxMs)}ms`;
|
|
28749
28900
|
}
|
|
28750
|
-
}
|
|
28751
|
-
lagTimer.unref();
|
|
28901
|
+
});
|
|
28752
28902
|
}
|
|
28753
28903
|
var SUBAPP_MANIFEST = [
|
|
28754
28904
|
{ prefix: "/api/health", file: "server/routes/health.ts", subapp: health_default },
|
|
@@ -28840,11 +28990,14 @@ async function runAdminUserReconcileTick() {
|
|
|
28840
28990
|
console.error(`[adminuser-self-heal] rejected: ${err instanceof Error ? err.message : String(err)}`);
|
|
28841
28991
|
}
|
|
28842
28992
|
}
|
|
28843
|
-
|
|
28844
|
-
|
|
28845
|
-
|
|
28846
|
-
|
|
28847
|
-
|
|
28993
|
+
registerLoop({
|
|
28994
|
+
name: "adminuser-reconcile",
|
|
28995
|
+
intervalMs: ADMINUSER_RECONCILE_INTERVAL_MS,
|
|
28996
|
+
firstRunDelayMs: 0,
|
|
28997
|
+
// Returned, not void-called: the registry awaits it, so the recorded
|
|
28998
|
+
// duration and outcome describe the tick rather than the call that started it.
|
|
28999
|
+
run: () => runAdminUserReconcileTick()
|
|
29000
|
+
});
|
|
28848
29001
|
var INGEST_AUDIT_INTERVAL_MS = 15 * 60 * 1e3;
|
|
28849
29002
|
var runIngestAuditTick = () => {
|
|
28850
29003
|
try {
|
|
@@ -28853,9 +29006,12 @@ var runIngestAuditTick = () => {
|
|
|
28853
29006
|
console.error(`[wa-ingest-audit] rejected: ${err instanceof Error ? err.message : String(err)}`);
|
|
28854
29007
|
}
|
|
28855
29008
|
};
|
|
28856
|
-
|
|
28857
|
-
|
|
28858
|
-
|
|
29009
|
+
registerLoop({
|
|
29010
|
+
name: "wa-ingest-audit",
|
|
29011
|
+
intervalMs: INGEST_AUDIT_INTERVAL_MS,
|
|
29012
|
+
firstRunDelayMs: 0,
|
|
29013
|
+
run: runIngestAuditTick
|
|
29014
|
+
});
|
|
28859
29015
|
var USERS_RECONCILE_INTERVAL_MS = 60 * 60 * 1e3;
|
|
28860
29016
|
function countUsersRows() {
|
|
28861
29017
|
if (!existsSync38(USERS_FILE)) return 0;
|
|
@@ -28882,9 +29038,12 @@ function runUsersReconcileTick() {
|
|
|
28882
29038
|
console.error(`[users-reconcile] op=error detail=${err instanceof Error ? err.message : String(err)}`);
|
|
28883
29039
|
}
|
|
28884
29040
|
}
|
|
28885
|
-
|
|
28886
|
-
|
|
28887
|
-
|
|
29041
|
+
registerLoop({
|
|
29042
|
+
name: "users-reconcile",
|
|
29043
|
+
intervalMs: USERS_RECONCILE_INTERVAL_MS,
|
|
29044
|
+
firstRunDelayMs: 0,
|
|
29045
|
+
run: runUsersReconcileTick
|
|
29046
|
+
});
|
|
28888
29047
|
startGraphHealthTimer();
|
|
28889
29048
|
void migrateUploads().catch((err) => console.error(`[uploads-migrate] failed err="${err instanceof Error ? err.message : String(err)}"`)).finally(() => {
|
|
28890
29049
|
void startFileWatcher().catch((err) => {
|
|
@@ -28893,9 +29052,19 @@ void migrateUploads().catch((err) => console.error(`[uploads-migrate] failed err
|
|
|
28893
29052
|
});
|
|
28894
29053
|
void sweepStaleUploadTemps().catch((err) => console.error(`[data-upload] op=sweep-failed err="${err instanceof Error ? err.message : String(err)}"`));
|
|
28895
29054
|
var CHUNK_IDLE_TTL_MS = 30 * 60 * 1e3;
|
|
28896
|
-
|
|
28897
|
-
|
|
28898
|
-
|
|
29055
|
+
registerLoop({
|
|
29056
|
+
name: "upload-chunk-evict",
|
|
29057
|
+
intervalMs: 10 * 60 * 1e3,
|
|
29058
|
+
// The domain-tagged line is kept and the rejection rethrown: existing
|
|
29059
|
+
// `[data-upload]` greps keep working AND the registry records the failure,
|
|
29060
|
+
// rather than swallowing it and reporting the run as healthy.
|
|
29061
|
+
run: () => evictStaleChunkUploads(CHUNK_IDLE_TTL_MS).then((evicted) => `evicted ${evicted}`).catch((err) => {
|
|
29062
|
+
console.error(
|
|
29063
|
+
`[data-upload] op=evict-failed err="${err instanceof Error ? err.message : String(err)}"`
|
|
29064
|
+
);
|
|
29065
|
+
throw err;
|
|
29066
|
+
})
|
|
29067
|
+
});
|
|
28899
29068
|
void migrateAdminWebchatSidecars().catch((err) => console.error(`[sidecar-backfill] failed err="${err instanceof Error ? err.message : String(err)}"`));
|
|
28900
29069
|
try {
|
|
28901
29070
|
const accounts = enumerateValidAccountIds(getAccountsDirFromEnv());
|