@agent-team-foundation/first-tree-hub 0.8.4 → 0.8.6
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/cli/index.mjs +3 -7
- package/dist/{core-VW2Qfs73.mjs → core-e1-NPfEC.mjs} +3324 -205
- package/dist/{feishu-OezhDY7x.mjs → feishu-n9Y2yGTT.mjs} +21 -4
- package/dist/index.mjs +2 -2
- package/dist/web/assets/geist-cyrillic-wght-normal-CHSlOQsW.woff2 +0 -0
- package/dist/web/assets/geist-latin-ext-wght-normal-DMtmJ5ZE.woff2 +0 -0
- package/dist/web/assets/geist-latin-wght-normal-Dm3htQBi.woff2 +0 -0
- package/dist/web/assets/geist-mono-cyrillic-wght-normal-BZdD_g9V.woff2 +0 -0
- package/dist/web/assets/geist-mono-latin-ext-wght-normal-b6lpi8_2.woff2 +0 -0
- package/dist/web/assets/geist-mono-latin-wght-normal-Cjtb1TV-.woff2 +0 -0
- package/dist/web/assets/index-D9iKLIsB.css +1 -0
- package/dist/web/assets/index-nMyXPMPC.js +361 -0
- package/dist/web/favicon.svg +8 -20
- package/dist/web/index.html +5 -3
- package/package.json +1 -1
- package/dist/web/assets/index-9xygtFGL.css +0 -1
- package/dist/web/assets/index-DpobwdHT.js +0 -333
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { m as __toESM } from "./esm-CYu4tXXn.mjs";
|
|
1
|
+
import { f as __require, l as __commonJSMin, m as __toESM } from "./esm-CYu4tXXn.mjs";
|
|
2
2
|
import { C as setConfigValue, S as serverConfigSchema, _ as loadAgents, d as DEFAULT_HOME_DIR$1, f as agentConfigSchema, g as initConfig, i as loadCredentials, l as DEFAULT_CONFIG_DIR, m as collectMissingPrompts, n as ensureFreshAccessToken, o as resolveServerUrl, p as clientConfigSchema, s as saveAgentConfig, u as DEFAULT_DATA_DIR$1, x as resolveConfigReadonly } from "./bootstrap-99vUYmLs.mjs";
|
|
3
3
|
import { _ as withSpan, a as endWsConnectionSpan, b as require_pino, c as messageAttrs, d as rootLogger$1, g as startWsConnectionSpan, i as currentTraceId, n as applyLoggerConfig, o as getFastifyOtelPlugin, p as setWsConnectionAttrs, r as createLogger, t as adapterAttrs, u as observabilityPlugin, v as withWsMessageSpan, y as FIRST_TREE_HUB_ATTR } from "./observability-CJzDFY_G-CmvgUuzc.mjs";
|
|
4
|
-
import { $ as
|
|
5
|
-
import { copyFileSync, existsSync, mkdirSync, readFileSync, readdirSync, realpathSync, renameSync, rmSync, statSync, watch, writeFileSync } from "node:fs";
|
|
6
|
-
import { dirname, isAbsolute, join, resolve } from "node:path";
|
|
4
|
+
import { $ as updateAdapterConfigSchema, A as createMemberSchema, B as notificationQuerySchema, C as agentTypeSchema$1, D as createAdapterMappingSchema, E as createAdapterConfigSchema, F as inboxPollQuerySchema, G as sendMessageSchema, H as refreshTokenSchema, I as isRedactedEnvValue, J as sessionEventMessageSchema, K as sendToAgentSchema, L as linkTaskChatSchema, M as createTaskSchema, N as delegateFeishuUserSchema, O as createAgentSchema, P as dryRunAgentRuntimeConfigSchema, Q as taskListQuerySchema, R as loginSchema, S as agentRuntimeConfigPayloadSchema$1, T as connectTokenExchangeSchema, U as runtimeStateMessageSchema, V as paginationQuerySchema, W as selfServiceFeishuBotSchema, X as sessionReconcileRequestSchema, Y as sessionEventSchema$1, Z as sessionStateMessageSchema, _ as addParticipantSchema, a as AGENT_SELECTOR_HEADER$1, at as updateSystemConfigSchema, b as agentBindRequestSchema, c as AGENT_TYPES, d as SYSTEM_CONFIG_DEFAULTS, et as updateAgentRuntimeConfigSchema, f as TASK_CREATOR_TYPES, g as WS_AUTH_FRAME_TIMEOUT_MS, h as TASK_TERMINAL_STATUSES, i as AGENT_BIND_REJECT_REASONS, it as updateOrganizationSchema, j as createOrganizationSchema, k as createChatSchema, l as AGENT_VISIBILITY, m as TASK_STATUSES, nt as updateChatSchema, o as AGENT_SOURCES, ot as updateTaskStatusSchema, p as TASK_HEALTH_SIGNALS, q as sessionCompletionMessageSchema, rt as updateMemberSchema, s as AGENT_STATUSES, st as wsAuthFrameSchema, tt as updateAgentSchema, u as DEFAULT_AGENT_RUNTIME_CONFIG_PAYLOAD, v as adminCreateTaskSchema, w as clientRegisterSchema, x as agentPinnedMessageSchema$1, y as adminUpdateTaskSchema, z as messageSourceSchema$1 } from "./feishu-n9Y2yGTT.mjs";
|
|
5
|
+
import { copyFileSync, createReadStream, createWriteStream, existsSync, mkdirSync, readFileSync, readdirSync, realpathSync, renameSync, rmSync, statSync, unlinkSync, watch, writeFileSync } from "node:fs";
|
|
6
|
+
import { dirname, extname, isAbsolute, join, resolve } from "node:path";
|
|
7
7
|
import { ZodError, z } from "zod";
|
|
8
8
|
import { Writable } from "node:stream";
|
|
9
9
|
import { stringify } from "yaml";
|
|
@@ -230,14 +230,16 @@ const runtimeStateSchema = z.enum([
|
|
|
230
230
|
"blocked",
|
|
231
231
|
"error"
|
|
232
232
|
]);
|
|
233
|
-
|
|
233
|
+
z.enum([
|
|
234
234
|
"active",
|
|
235
235
|
"suspended",
|
|
236
236
|
"evicted"
|
|
237
237
|
]);
|
|
238
|
+
/** Wire-level states a client may report. `evicted` from a stale client is rejected. */
|
|
239
|
+
const clientSessionStateSchema = z.enum(["active", "suspended"]);
|
|
238
240
|
z.object({
|
|
239
241
|
chatId: z.string().min(1),
|
|
240
|
-
state:
|
|
242
|
+
state: clientSessionStateSchema
|
|
241
243
|
});
|
|
242
244
|
z.object({ runtimeState: runtimeStateSchema });
|
|
243
245
|
z.object({
|
|
@@ -526,6 +528,7 @@ z.object({
|
|
|
526
528
|
createdAt: z.string(),
|
|
527
529
|
updatedAt: z.string()
|
|
528
530
|
}).extend({ participants: z.array(chatParticipantSchema) });
|
|
531
|
+
z.object({ topic: z.string().trim().max(500).nullable() });
|
|
529
532
|
z.object({
|
|
530
533
|
agentId: z.string().min(1),
|
|
531
534
|
mode: z.enum(["full", "mention_only"]).default("full")
|
|
@@ -641,7 +644,10 @@ z.object({
|
|
|
641
644
|
displayName: z.string().min(1).max(200),
|
|
642
645
|
role: memberRoleSchema.default("member")
|
|
643
646
|
});
|
|
644
|
-
z.object({
|
|
647
|
+
z.object({
|
|
648
|
+
role: memberRoleSchema.optional(),
|
|
649
|
+
displayName: z.string().min(1).max(200).optional()
|
|
650
|
+
});
|
|
645
651
|
memberSchema.extend({
|
|
646
652
|
username: z.string(),
|
|
647
653
|
displayName: z.string(),
|
|
@@ -807,6 +813,16 @@ z.object({
|
|
|
807
813
|
agentId: z.string(),
|
|
808
814
|
chatId: z.string()
|
|
809
815
|
});
|
|
816
|
+
z.object({
|
|
817
|
+
type: z.literal("session:reconcile"),
|
|
818
|
+
agentId: z.string().min(1),
|
|
819
|
+
chatIds: z.array(z.string().min(1)).max(500)
|
|
820
|
+
});
|
|
821
|
+
z.object({
|
|
822
|
+
type: z.literal("session:reconcile:result"),
|
|
823
|
+
agentId: z.string().min(1),
|
|
824
|
+
staleChatIds: z.array(z.string().min(1))
|
|
825
|
+
});
|
|
810
826
|
const orgStatsSchema = z.object({
|
|
811
827
|
organizationId: z.string(),
|
|
812
828
|
agentCount: z.number(),
|
|
@@ -1195,6 +1211,15 @@ var ClientConnection = class extends EventEmitter {
|
|
|
1195
1211
|
chatId
|
|
1196
1212
|
}));
|
|
1197
1213
|
}
|
|
1214
|
+
/** Ask the server which of the supplied chatIds the client should drop. */
|
|
1215
|
+
sendSessionReconcile(agentId, chatIds) {
|
|
1216
|
+
if (!this.ws || this.ws.readyState !== WebSocket.OPEN) return;
|
|
1217
|
+
this.ws.send(JSON.stringify({
|
|
1218
|
+
type: "session:reconcile",
|
|
1219
|
+
agentId,
|
|
1220
|
+
chatIds
|
|
1221
|
+
}));
|
|
1222
|
+
}
|
|
1198
1223
|
async disconnect() {
|
|
1199
1224
|
this.closing = true;
|
|
1200
1225
|
this.clearTimers();
|
|
@@ -1372,7 +1397,7 @@ var ClientConnection = class extends EventEmitter {
|
|
|
1372
1397
|
}
|
|
1373
1398
|
return;
|
|
1374
1399
|
}
|
|
1375
|
-
if (type === "session:suspend" || type === "session:
|
|
1400
|
+
if (type === "session:suspend" || type === "session:terminate") {
|
|
1376
1401
|
const agentId = msg.agentId;
|
|
1377
1402
|
const chatId = msg.chatId;
|
|
1378
1403
|
if (agentId && chatId) this.emit("session:command", {
|
|
@@ -1382,6 +1407,15 @@ var ClientConnection = class extends EventEmitter {
|
|
|
1382
1407
|
});
|
|
1383
1408
|
return;
|
|
1384
1409
|
}
|
|
1410
|
+
if (type === "session:reconcile:result") {
|
|
1411
|
+
const agentId = msg.agentId;
|
|
1412
|
+
const staleChatIds = Array.isArray(msg.staleChatIds) ? msg.staleChatIds : null;
|
|
1413
|
+
if (agentId && staleChatIds) this.emit("session:reconcile:result", {
|
|
1414
|
+
agentId,
|
|
1415
|
+
staleChatIds
|
|
1416
|
+
});
|
|
1417
|
+
return;
|
|
1418
|
+
}
|
|
1385
1419
|
if (type === "new_message") {
|
|
1386
1420
|
const inboxId = msg.inboxId;
|
|
1387
1421
|
if (inboxId) this.emit("agent:message", inboxId, msg);
|
|
@@ -3134,39 +3168,49 @@ var SessionManager = class {
|
|
|
3134
3168
|
const message = this.extractMessage(entry);
|
|
3135
3169
|
await this.routeMessage(chatId, message, entry.id);
|
|
3136
3170
|
}
|
|
3137
|
-
/** Handle a session command
|
|
3171
|
+
/** Handle a server-issued session command. Terminate drops all local state without reporting back. */
|
|
3138
3172
|
async handleCommand(chatId, command) {
|
|
3139
|
-
const session = this.sessions.get(chatId);
|
|
3140
3173
|
if (command === "session:suspend") {
|
|
3174
|
+
const session = this.sessions.get(chatId);
|
|
3141
3175
|
if (session?.status === "active") {
|
|
3142
3176
|
this.config.log(`Session ${chatId}: suspend command received`);
|
|
3143
3177
|
this.suspendSession(session);
|
|
3144
3178
|
}
|
|
3145
|
-
|
|
3146
|
-
|
|
3147
|
-
|
|
3148
|
-
|
|
3149
|
-
|
|
3150
|
-
|
|
3151
|
-
|
|
3152
|
-
|
|
3153
|
-
|
|
3154
|
-
|
|
3155
|
-
await session.handler.shutdown();
|
|
3156
|
-
}
|
|
3157
|
-
this.addEvictedMapping(chatId, {
|
|
3158
|
-
claudeSessionId: session.claudeSessionId,
|
|
3159
|
-
lastActivity: session.lastActivity
|
|
3160
|
-
});
|
|
3161
|
-
this.sessions.delete(chatId);
|
|
3162
|
-
this.sessionRuntimeStates.delete(chatId);
|
|
3163
|
-
this.recomputeRuntimeState();
|
|
3164
|
-
this.notifySessionState(chatId, "evicted");
|
|
3165
|
-
this.persistRegistry();
|
|
3166
|
-
this.drainPendingQueue();
|
|
3179
|
+
return;
|
|
3180
|
+
}
|
|
3181
|
+
if (command === "session:terminate") {
|
|
3182
|
+
const session = this.sessions.get(chatId);
|
|
3183
|
+
const hadMapping = this.evictedMappings.has(chatId);
|
|
3184
|
+
if (!session && !hadMapping) return;
|
|
3185
|
+
this.config.log(`Session ${chatId}: terminate command received`);
|
|
3186
|
+
if (session?.status === "active") {
|
|
3187
|
+
this._activeCount--;
|
|
3188
|
+
await session.handler.shutdown().catch(() => {});
|
|
3167
3189
|
}
|
|
3190
|
+
this.sessions.delete(chatId);
|
|
3191
|
+
this.evictedMappings.delete(chatId);
|
|
3192
|
+
this.sessionRuntimeStates.delete(chatId);
|
|
3193
|
+
this.lastReportedStates.delete(chatId);
|
|
3194
|
+
for (let i = this.pendingQueue.length - 1; i >= 0; i--) if (this.pendingQueue[i]?.chatId === chatId) this.pendingQueue.splice(i, 1);
|
|
3195
|
+
this.recomputeRuntimeState();
|
|
3196
|
+
this.persistRegistry();
|
|
3197
|
+
this.drainPendingQueue();
|
|
3168
3198
|
}
|
|
3169
3199
|
}
|
|
3200
|
+
/** Chat IDs this client still holds locally (sessions + evictedMappings). */
|
|
3201
|
+
getHeldChatIds() {
|
|
3202
|
+
const ids = /* @__PURE__ */ new Set();
|
|
3203
|
+
for (const id of this.sessions.keys()) ids.add(id);
|
|
3204
|
+
for (const id of this.evictedMappings.keys()) ids.add(id);
|
|
3205
|
+
return [...ids];
|
|
3206
|
+
}
|
|
3207
|
+
/**
|
|
3208
|
+
* Apply a server-declared stale list from `session:reconcile:result` — treat
|
|
3209
|
+
* each chatId as if a `session:terminate` command had arrived.
|
|
3210
|
+
*/
|
|
3211
|
+
applyStaleChatIds(staleChatIds) {
|
|
3212
|
+
for (const id of staleChatIds) this.handleCommand(id, "session:terminate");
|
|
3213
|
+
}
|
|
3170
3214
|
/** Shut down all sessions gracefully. */
|
|
3171
3215
|
async shutdown() {
|
|
3172
3216
|
if (this.idleTimer) {
|
|
@@ -3367,8 +3411,6 @@ var SessionManager = class {
|
|
|
3367
3411
|
this._activeCount--;
|
|
3368
3412
|
candidate.session.handler.shutdown().catch(() => {});
|
|
3369
3413
|
}
|
|
3370
|
-
candidate.session.status = "evicted";
|
|
3371
|
-
this.notifySessionState(candidate.key, "evicted");
|
|
3372
3414
|
this.sessions.delete(candidate.key);
|
|
3373
3415
|
this.sessionRuntimeStates.delete(candidate.key);
|
|
3374
3416
|
this.recomputeRuntimeState();
|
|
@@ -3505,6 +3547,7 @@ var AgentSlot = class {
|
|
|
3505
3547
|
sdk = null;
|
|
3506
3548
|
agentConfigCache = null;
|
|
3507
3549
|
pollingTimer = null;
|
|
3550
|
+
reconcileTimer = null;
|
|
3508
3551
|
listeners = [];
|
|
3509
3552
|
constructor(config) {
|
|
3510
3553
|
this.config = config;
|
|
@@ -3540,16 +3583,26 @@ var AgentSlot = class {
|
|
|
3540
3583
|
if (agentId === this.config.agentId) this.pullAndDispatch();
|
|
3541
3584
|
};
|
|
3542
3585
|
const onBound = (boundAgent) => {
|
|
3543
|
-
if (boundAgent.agentId === this.config.agentId)
|
|
3586
|
+
if (boundAgent.agentId === this.config.agentId) {
|
|
3587
|
+
this.fullStateSync();
|
|
3588
|
+
setTimeout(() => this.reconcileNow(), 5e3);
|
|
3589
|
+
}
|
|
3590
|
+
};
|
|
3591
|
+
const onReconcileResult = (result) => {
|
|
3592
|
+
if (result.agentId === this.config.agentId && this.sessionManager) this.sessionManager.applyStaleChatIds(result.staleChatIds);
|
|
3544
3593
|
};
|
|
3545
3594
|
this.clientConnection.on("agent:message", onMessage);
|
|
3546
3595
|
this.clientConnection.on("agent:bound", onBound);
|
|
3596
|
+
this.clientConnection.on("session:reconcile:result", onReconcileResult);
|
|
3547
3597
|
this.listeners.push({
|
|
3548
3598
|
event: "agent:message",
|
|
3549
3599
|
fn: onMessage
|
|
3550
3600
|
}, {
|
|
3551
3601
|
event: "agent:bound",
|
|
3552
3602
|
fn: onBound
|
|
3603
|
+
}, {
|
|
3604
|
+
event: "session:reconcile:result",
|
|
3605
|
+
fn: onReconcileResult
|
|
3553
3606
|
});
|
|
3554
3607
|
const registryPath = join(DEFAULT_DATA_DIR, "sessions", `${this.config.name}.json`);
|
|
3555
3608
|
const gitMirrorManager = createGitMirrorManager({
|
|
@@ -3592,6 +3645,7 @@ var AgentSlot = class {
|
|
|
3592
3645
|
fn: onCommand
|
|
3593
3646
|
});
|
|
3594
3647
|
this.startPolling();
|
|
3648
|
+
this.startReconcileLoop();
|
|
3595
3649
|
return agent;
|
|
3596
3650
|
}
|
|
3597
3651
|
async stop() {
|
|
@@ -3599,8 +3653,13 @@ var AgentSlot = class {
|
|
|
3599
3653
|
clearInterval(this.pollingTimer);
|
|
3600
3654
|
this.pollingTimer = null;
|
|
3601
3655
|
}
|
|
3656
|
+
if (this.reconcileTimer) {
|
|
3657
|
+
clearInterval(this.reconcileTimer);
|
|
3658
|
+
this.reconcileTimer = null;
|
|
3659
|
+
}
|
|
3602
3660
|
for (const entry of this.listeners) if (entry.event === "agent:message") this.clientConnection.off(entry.event, entry.fn);
|
|
3603
3661
|
else if (entry.event === "agent:bound") this.clientConnection.off(entry.event, entry.fn);
|
|
3662
|
+
else if (entry.event === "session:reconcile:result") this.clientConnection.off(entry.event, entry.fn);
|
|
3604
3663
|
else this.clientConnection.off(entry.event, entry.fn);
|
|
3605
3664
|
this.listeners = [];
|
|
3606
3665
|
await this.clientConnection.unbindAgent(this.config.agentId);
|
|
@@ -3631,6 +3690,16 @@ var AgentSlot = class {
|
|
|
3631
3690
|
}, 5e3);
|
|
3632
3691
|
this.pullAndDispatch();
|
|
3633
3692
|
}
|
|
3693
|
+
startReconcileLoop() {
|
|
3694
|
+
const intervalSec = this.config.session.reconcile_interval_seconds ?? 300;
|
|
3695
|
+
this.reconcileTimer = setInterval(() => this.reconcileNow(), intervalSec * 1e3);
|
|
3696
|
+
}
|
|
3697
|
+
reconcileNow() {
|
|
3698
|
+
if (!this.sessionManager) return;
|
|
3699
|
+
const chatIds = this.sessionManager.getHeldChatIds();
|
|
3700
|
+
if (chatIds.length === 0) return;
|
|
3701
|
+
this.clientConnection.sendSessionReconcile(this.config.agentId, chatIds);
|
|
3702
|
+
}
|
|
3634
3703
|
async pullAndDispatch() {
|
|
3635
3704
|
if (!this.sdk || !this.sessionManager) return;
|
|
3636
3705
|
try {
|
|
@@ -3659,7 +3728,8 @@ z.object({
|
|
|
3659
3728
|
}).passthrough();
|
|
3660
3729
|
const sessionConfigSchema = z.object({
|
|
3661
3730
|
idle_timeout: z.number().int().positive().default(IDLE_TIMEOUT_MS / 1e3),
|
|
3662
|
-
max_sessions: z.number().int().positive().default(50)
|
|
3731
|
+
max_sessions: z.number().int().positive().default(50),
|
|
3732
|
+
reconcile_interval_seconds: z.number().int().min(30).max(3600).default(300)
|
|
3663
3733
|
}).passthrough();
|
|
3664
3734
|
const agentSlotConfigSchema = z.object({
|
|
3665
3735
|
agentId: z.string().min(1),
|
|
@@ -3808,7 +3878,8 @@ var ClientRuntime = class {
|
|
|
3808
3878
|
handlerFactory,
|
|
3809
3879
|
session: {
|
|
3810
3880
|
idle_timeout: config.session.idle_timeout,
|
|
3811
|
-
max_sessions: config.session.max_sessions
|
|
3881
|
+
max_sessions: config.session.max_sessions,
|
|
3882
|
+
reconcile_interval_seconds: 300
|
|
3812
3883
|
},
|
|
3813
3884
|
concurrency: config.concurrency,
|
|
3814
3885
|
clientConnection: this.connection
|
|
@@ -4602,7 +4673,7 @@ async function onboardCreate(args) {
|
|
|
4602
4673
|
}
|
|
4603
4674
|
const runtimeAgent = args.type === "human" ? args.assistant : args.id;
|
|
4604
4675
|
if (args.feishuBotAppId && args.feishuBotAppSecret) {
|
|
4605
|
-
const { bindFeishuBot } = await import("./feishu-
|
|
4676
|
+
const { bindFeishuBot } = await import("./feishu-n9Y2yGTT.mjs").then((n) => n.r);
|
|
4606
4677
|
const targetAgentUuid = args.type === "human" ? assistantUuid : primary.uuid;
|
|
4607
4678
|
if (!targetAgentUuid) process.stderr.write(`Warning: Cannot bind Feishu bot — no runtime agent available for "${args.id}".\n`);
|
|
4608
4679
|
else {
|
|
@@ -4675,75 +4746,2781 @@ async function promptMissingFields(options) {
|
|
|
4675
4746
|
setNestedByDot(results, dotPath, value);
|
|
4676
4747
|
}
|
|
4677
4748
|
}
|
|
4678
|
-
return results;
|
|
4679
|
-
}
|
|
4680
|
-
/**
|
|
4681
|
-
* Interactive add agent — simple two-field prompt.
|
|
4682
|
-
*/
|
|
4683
|
-
async function promptAddAgent() {
|
|
4684
|
-
return {
|
|
4685
|
-
name: await input({
|
|
4686
|
-
message: "Local alias:",
|
|
4687
|
-
validate: (v) => /^[a-z0-9][a-z0-9-]*$/.test(v) ? true : "Lowercase alphanumeric and hyphens only"
|
|
4688
|
-
}),
|
|
4689
|
-
agentId: await input({
|
|
4690
|
-
message: "Agent UUID on the Hub:",
|
|
4691
|
-
validate: (v) => v.length > 0 ? true : "Agent UUID is required"
|
|
4692
|
-
})
|
|
4693
|
-
};
|
|
4694
|
-
}
|
|
4695
|
-
async function askPrompt(dotPath, prompt) {
|
|
4696
|
-
const type = prompt.type ?? "input";
|
|
4697
|
-
if (type === "select" && prompt.choices) {
|
|
4698
|
-
const value = await select({
|
|
4699
|
-
message: prompt.message,
|
|
4700
|
-
choices: prompt.choices.map((c) => ({
|
|
4701
|
-
name: c.name,
|
|
4702
|
-
value: c.value
|
|
4703
|
-
}))
|
|
4704
|
-
});
|
|
4705
|
-
if (value === "__auto__") return void 0;
|
|
4706
|
-
if (value === "__input__") return input({
|
|
4707
|
-
message: `${dotPath}:`,
|
|
4708
|
-
validate: (v) => v.length > 0 ? true : "Value is required"
|
|
4749
|
+
return results;
|
|
4750
|
+
}
|
|
4751
|
+
/**
|
|
4752
|
+
* Interactive add agent — simple two-field prompt.
|
|
4753
|
+
*/
|
|
4754
|
+
async function promptAddAgent() {
|
|
4755
|
+
return {
|
|
4756
|
+
name: await input({
|
|
4757
|
+
message: "Local alias:",
|
|
4758
|
+
validate: (v) => /^[a-z0-9][a-z0-9-]*$/.test(v) ? true : "Lowercase alphanumeric and hyphens only"
|
|
4759
|
+
}),
|
|
4760
|
+
agentId: await input({
|
|
4761
|
+
message: "Agent UUID on the Hub:",
|
|
4762
|
+
validate: (v) => v.length > 0 ? true : "Agent UUID is required"
|
|
4763
|
+
})
|
|
4764
|
+
};
|
|
4765
|
+
}
|
|
4766
|
+
async function askPrompt(dotPath, prompt) {
|
|
4767
|
+
const type = prompt.type ?? "input";
|
|
4768
|
+
if (type === "select" && prompt.choices) {
|
|
4769
|
+
const value = await select({
|
|
4770
|
+
message: prompt.message,
|
|
4771
|
+
choices: prompt.choices.map((c) => ({
|
|
4772
|
+
name: c.name,
|
|
4773
|
+
value: c.value
|
|
4774
|
+
}))
|
|
4775
|
+
});
|
|
4776
|
+
if (value === "__auto__") return void 0;
|
|
4777
|
+
if (value === "__input__") return input({
|
|
4778
|
+
message: `${dotPath}:`,
|
|
4779
|
+
validate: (v) => v.length > 0 ? true : "Value is required"
|
|
4780
|
+
});
|
|
4781
|
+
return value;
|
|
4782
|
+
}
|
|
4783
|
+
if (type === "password") return password({ message: prompt.message });
|
|
4784
|
+
return input({
|
|
4785
|
+
message: prompt.message,
|
|
4786
|
+
default: prompt.default
|
|
4787
|
+
});
|
|
4788
|
+
}
|
|
4789
|
+
/** Walk schema to find the env var name for a given dot path. */
|
|
4790
|
+
function findEnvVar(schema, dotPath) {
|
|
4791
|
+
const parts = dotPath.split(".");
|
|
4792
|
+
let current = schema;
|
|
4793
|
+
for (const part of parts) {
|
|
4794
|
+
if (current === null || current === void 0 || typeof current !== "object") return void 0;
|
|
4795
|
+
const obj = current;
|
|
4796
|
+
if (obj._tag === "optional") current = obj.shape[part];
|
|
4797
|
+
else current = obj[part];
|
|
4798
|
+
}
|
|
4799
|
+
if (typeof current === "object" && current !== null && "_tag" in current) {
|
|
4800
|
+
const field = current;
|
|
4801
|
+
if (field._tag === "field") return field.options?.env;
|
|
4802
|
+
}
|
|
4803
|
+
}
|
|
4804
|
+
function setNestedByDot(obj, dotPath, value) {
|
|
4805
|
+
const parts = dotPath.split(".");
|
|
4806
|
+
let current = obj;
|
|
4807
|
+
for (let i = 0; i < parts.length - 1; i++) {
|
|
4808
|
+
const key = parts[i];
|
|
4809
|
+
if (key === void 0) continue;
|
|
4810
|
+
if (!(key in current) || typeof current[key] !== "object" || current[key] === null) current[key] = {};
|
|
4811
|
+
current = current[key];
|
|
4812
|
+
}
|
|
4813
|
+
const lastKey = parts.at(-1);
|
|
4814
|
+
if (lastKey !== void 0) current[lastKey] = value;
|
|
4815
|
+
}
|
|
4816
|
+
//#endregion
|
|
4817
|
+
//#region ../../node_modules/.pnpm/@fastify+busboy@3.2.0/node_modules/@fastify/busboy/deps/streamsearch/sbmh.js
|
|
4818
|
+
var require_sbmh = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
4819
|
+
/**
|
|
4820
|
+
* Copyright Brian White. All rights reserved.
|
|
4821
|
+
*
|
|
4822
|
+
* @see https://github.com/mscdex/streamsearch
|
|
4823
|
+
*
|
|
4824
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
4825
|
+
* of this software and associated documentation files (the "Software"), to
|
|
4826
|
+
* deal in the Software without restriction, including without limitation the
|
|
4827
|
+
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
|
4828
|
+
* sell copies of the Software, and to permit persons to whom the Software is
|
|
4829
|
+
* furnished to do so, subject to the following conditions:
|
|
4830
|
+
*
|
|
4831
|
+
* The above copyright notice and this permission notice shall be included in
|
|
4832
|
+
* all copies or substantial portions of the Software.
|
|
4833
|
+
*
|
|
4834
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
4835
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
4836
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
4837
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
4838
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
4839
|
+
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
|
4840
|
+
* IN THE SOFTWARE.
|
|
4841
|
+
*
|
|
4842
|
+
* Based heavily on the Streaming Boyer-Moore-Horspool C++ implementation
|
|
4843
|
+
* by Hongli Lai at: https://github.com/FooBarWidget/boyer-moore-horspool
|
|
4844
|
+
*/
|
|
4845
|
+
const { EventEmitter: EventEmitter$2 } = __require("node:events");
|
|
4846
|
+
const { inherits: inherits$5 } = __require("node:util");
|
|
4847
|
+
function SBMH(needle) {
|
|
4848
|
+
if (typeof needle === "string") needle = Buffer.from(needle);
|
|
4849
|
+
if (!Buffer.isBuffer(needle)) throw new TypeError("The needle has to be a String or a Buffer.");
|
|
4850
|
+
const needleLength = needle.length;
|
|
4851
|
+
const needleLastCharIndex = needleLength - 1;
|
|
4852
|
+
if (needleLength === 0) throw new Error("The needle cannot be an empty String/Buffer.");
|
|
4853
|
+
if (needleLength > 256) throw new Error("The needle cannot have a length bigger than 256.");
|
|
4854
|
+
this.maxMatches = Infinity;
|
|
4855
|
+
this.matches = 0;
|
|
4856
|
+
this._occ = new Uint8Array(256).fill(needleLength);
|
|
4857
|
+
this._lookbehind_size = 0;
|
|
4858
|
+
this._needle = needle;
|
|
4859
|
+
this._bufpos = 0;
|
|
4860
|
+
this._lookbehind = Buffer.alloc(needleLastCharIndex);
|
|
4861
|
+
for (var i = 0; i < needleLastCharIndex; ++i) this._occ[needle[i]] = needleLastCharIndex - i;
|
|
4862
|
+
}
|
|
4863
|
+
inherits$5(SBMH, EventEmitter$2);
|
|
4864
|
+
SBMH.prototype.reset = function() {
|
|
4865
|
+
this._lookbehind_size = 0;
|
|
4866
|
+
this.matches = 0;
|
|
4867
|
+
this._bufpos = 0;
|
|
4868
|
+
};
|
|
4869
|
+
SBMH.prototype.push = function(chunk, pos) {
|
|
4870
|
+
if (!Buffer.isBuffer(chunk)) chunk = Buffer.from(chunk, "binary");
|
|
4871
|
+
const chlen = chunk.length;
|
|
4872
|
+
this._bufpos = pos || 0;
|
|
4873
|
+
let r;
|
|
4874
|
+
while (r !== chlen && this.matches < this.maxMatches) r = this._sbmh_feed(chunk);
|
|
4875
|
+
return r;
|
|
4876
|
+
};
|
|
4877
|
+
SBMH.prototype._sbmh_feed = function(data) {
|
|
4878
|
+
const len = data.length;
|
|
4879
|
+
const needle = this._needle;
|
|
4880
|
+
const needleLength = needle.length;
|
|
4881
|
+
const needleLastCharIndex = needleLength - 1;
|
|
4882
|
+
const needleLastChar = needle[needleLastCharIndex];
|
|
4883
|
+
let pos = -this._lookbehind_size;
|
|
4884
|
+
let ch;
|
|
4885
|
+
if (pos < 0) {
|
|
4886
|
+
while (pos < 0 && pos <= len - needleLength) {
|
|
4887
|
+
ch = data[pos + needleLastCharIndex];
|
|
4888
|
+
if (ch === needleLastChar && this._sbmh_memcmp(data, pos, needleLastCharIndex)) {
|
|
4889
|
+
this._lookbehind_size = 0;
|
|
4890
|
+
++this.matches;
|
|
4891
|
+
this.emit("info", true);
|
|
4892
|
+
return this._bufpos = pos + needleLength;
|
|
4893
|
+
}
|
|
4894
|
+
pos += this._occ[ch];
|
|
4895
|
+
}
|
|
4896
|
+
while (pos < 0 && !this._sbmh_memcmp(data, pos, len - pos)) ++pos;
|
|
4897
|
+
if (pos >= 0) {
|
|
4898
|
+
this.emit("info", false, this._lookbehind, 0, this._lookbehind_size);
|
|
4899
|
+
this._lookbehind_size = 0;
|
|
4900
|
+
} else {
|
|
4901
|
+
const bytesToCutOff = this._lookbehind_size + pos;
|
|
4902
|
+
if (bytesToCutOff > 0) this.emit("info", false, this._lookbehind, 0, bytesToCutOff);
|
|
4903
|
+
this._lookbehind_size -= bytesToCutOff;
|
|
4904
|
+
this._lookbehind.copy(this._lookbehind, 0, bytesToCutOff, this._lookbehind_size);
|
|
4905
|
+
data.copy(this._lookbehind, this._lookbehind_size);
|
|
4906
|
+
this._lookbehind_size += len;
|
|
4907
|
+
this._bufpos = len;
|
|
4908
|
+
return len;
|
|
4909
|
+
}
|
|
4910
|
+
}
|
|
4911
|
+
pos = data.indexOf(needle, pos + this._bufpos);
|
|
4912
|
+
if (pos !== -1) {
|
|
4913
|
+
++this.matches;
|
|
4914
|
+
if (pos === 0) this.emit("info", true);
|
|
4915
|
+
else this.emit("info", true, data, this._bufpos, pos);
|
|
4916
|
+
return this._bufpos = pos + needleLength;
|
|
4917
|
+
}
|
|
4918
|
+
pos = len - needleLastCharIndex;
|
|
4919
|
+
if (pos < 0) pos = 0;
|
|
4920
|
+
while (pos !== len && (data[pos] !== needle[0] || Buffer.compare(data.subarray(pos + 1, len), needle.subarray(1, len - pos)) !== 0)) ++pos;
|
|
4921
|
+
if (pos !== len) {
|
|
4922
|
+
data.copy(this._lookbehind, 0, pos, len);
|
|
4923
|
+
this._lookbehind_size = len - pos;
|
|
4924
|
+
}
|
|
4925
|
+
if (pos !== 0) this.emit("info", false, data, this._bufpos, pos);
|
|
4926
|
+
this._bufpos = len;
|
|
4927
|
+
return len;
|
|
4928
|
+
};
|
|
4929
|
+
SBMH.prototype._sbmh_lookup_char = function(data, pos) {
|
|
4930
|
+
return pos < 0 ? this._lookbehind[this._lookbehind_size + pos] : data[pos];
|
|
4931
|
+
};
|
|
4932
|
+
SBMH.prototype._sbmh_memcmp = function(data, pos, len) {
|
|
4933
|
+
for (var i = 0; i < len; ++i) if (this._sbmh_lookup_char(data, pos + i) !== this._needle[i]) return false;
|
|
4934
|
+
return true;
|
|
4935
|
+
};
|
|
4936
|
+
module.exports = SBMH;
|
|
4937
|
+
}));
|
|
4938
|
+
//#endregion
|
|
4939
|
+
//#region ../../node_modules/.pnpm/@fastify+busboy@3.2.0/node_modules/@fastify/busboy/deps/dicer/lib/PartStream.js
|
|
4940
|
+
var require_PartStream = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
4941
|
+
const inherits$4 = __require("node:util").inherits;
|
|
4942
|
+
const ReadableStream = __require("node:stream").Readable;
|
|
4943
|
+
function PartStream(opts) {
|
|
4944
|
+
ReadableStream.call(this, opts);
|
|
4945
|
+
}
|
|
4946
|
+
inherits$4(PartStream, ReadableStream);
|
|
4947
|
+
PartStream.prototype._read = function(n) {};
|
|
4948
|
+
module.exports = PartStream;
|
|
4949
|
+
}));
|
|
4950
|
+
//#endregion
|
|
4951
|
+
//#region ../../node_modules/.pnpm/@fastify+busboy@3.2.0/node_modules/@fastify/busboy/lib/utils/getLimit.js
|
|
4952
|
+
var require_getLimit = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
4953
|
+
module.exports = function getLimit(limits, name, defaultLimit) {
|
|
4954
|
+
if (!limits || limits[name] === void 0 || limits[name] === null) return defaultLimit;
|
|
4955
|
+
if (typeof limits[name] !== "number" || isNaN(limits[name])) throw new TypeError("Limit " + name + " is not a valid number");
|
|
4956
|
+
return limits[name];
|
|
4957
|
+
};
|
|
4958
|
+
}));
|
|
4959
|
+
//#endregion
|
|
4960
|
+
//#region ../../node_modules/.pnpm/@fastify+busboy@3.2.0/node_modules/@fastify/busboy/deps/dicer/lib/HeaderParser.js
|
|
4961
|
+
var require_HeaderParser = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
4962
|
+
const EventEmitter$1 = __require("node:events").EventEmitter;
|
|
4963
|
+
const inherits$3 = __require("node:util").inherits;
|
|
4964
|
+
const getLimit = require_getLimit();
|
|
4965
|
+
const StreamSearch = require_sbmh();
|
|
4966
|
+
const B_DCRLF = Buffer.from("\r\n\r\n");
|
|
4967
|
+
const RE_CRLF = /\r\n/g;
|
|
4968
|
+
const RE_HDR = /^([^:]+):[ \t]?([\x00-\xFF]+)?$/;
|
|
4969
|
+
function HeaderParser(cfg) {
|
|
4970
|
+
EventEmitter$1.call(this);
|
|
4971
|
+
cfg = cfg || {};
|
|
4972
|
+
const self = this;
|
|
4973
|
+
this.nread = 0;
|
|
4974
|
+
this.maxed = false;
|
|
4975
|
+
this.npairs = 0;
|
|
4976
|
+
this.maxHeaderPairs = getLimit(cfg, "maxHeaderPairs", 2e3);
|
|
4977
|
+
this.maxHeaderSize = getLimit(cfg, "maxHeaderSize", 80 * 1024);
|
|
4978
|
+
this.buffer = "";
|
|
4979
|
+
this.header = {};
|
|
4980
|
+
this.finished = false;
|
|
4981
|
+
this.ss = new StreamSearch(B_DCRLF);
|
|
4982
|
+
this.ss.on("info", function(isMatch, data, start, end) {
|
|
4983
|
+
if (data && !self.maxed) {
|
|
4984
|
+
if (self.nread + end - start >= self.maxHeaderSize) {
|
|
4985
|
+
end = self.maxHeaderSize - self.nread + start;
|
|
4986
|
+
self.nread = self.maxHeaderSize;
|
|
4987
|
+
self.maxed = true;
|
|
4988
|
+
} else self.nread += end - start;
|
|
4989
|
+
self.buffer += data.toString("binary", start, end);
|
|
4990
|
+
}
|
|
4991
|
+
if (isMatch) self._finish();
|
|
4992
|
+
});
|
|
4993
|
+
}
|
|
4994
|
+
inherits$3(HeaderParser, EventEmitter$1);
|
|
4995
|
+
HeaderParser.prototype.push = function(data) {
|
|
4996
|
+
const r = this.ss.push(data);
|
|
4997
|
+
if (this.finished) return r;
|
|
4998
|
+
};
|
|
4999
|
+
HeaderParser.prototype.reset = function() {
|
|
5000
|
+
this.finished = false;
|
|
5001
|
+
this.buffer = "";
|
|
5002
|
+
this.header = {};
|
|
5003
|
+
this.ss.reset();
|
|
5004
|
+
};
|
|
5005
|
+
HeaderParser.prototype._finish = function() {
|
|
5006
|
+
if (this.buffer) this._parseHeader();
|
|
5007
|
+
this.ss.matches = this.ss.maxMatches;
|
|
5008
|
+
const header = this.header;
|
|
5009
|
+
this.header = {};
|
|
5010
|
+
this.buffer = "";
|
|
5011
|
+
this.finished = true;
|
|
5012
|
+
this.nread = this.npairs = 0;
|
|
5013
|
+
this.maxed = false;
|
|
5014
|
+
this.emit("header", header);
|
|
5015
|
+
};
|
|
5016
|
+
HeaderParser.prototype._parseHeader = function() {
|
|
5017
|
+
if (this.npairs === this.maxHeaderPairs) return;
|
|
5018
|
+
const lines = this.buffer.split(RE_CRLF);
|
|
5019
|
+
const len = lines.length;
|
|
5020
|
+
let m, h;
|
|
5021
|
+
for (var i = 0; i < len; ++i) {
|
|
5022
|
+
if (lines[i].length === 0) continue;
|
|
5023
|
+
if (lines[i][0] === " " || lines[i][0] === " ") {
|
|
5024
|
+
if (h) {
|
|
5025
|
+
this.header[h][this.header[h].length - 1] += lines[i];
|
|
5026
|
+
continue;
|
|
5027
|
+
}
|
|
5028
|
+
}
|
|
5029
|
+
const posColon = lines[i].indexOf(":");
|
|
5030
|
+
if (posColon === -1 || posColon === 0) return;
|
|
5031
|
+
m = RE_HDR.exec(lines[i]);
|
|
5032
|
+
h = m[1].toLowerCase();
|
|
5033
|
+
this.header[h] = this.header[h] || [];
|
|
5034
|
+
this.header[h].push(m[2] || "");
|
|
5035
|
+
if (++this.npairs === this.maxHeaderPairs) break;
|
|
5036
|
+
}
|
|
5037
|
+
};
|
|
5038
|
+
module.exports = HeaderParser;
|
|
5039
|
+
}));
|
|
5040
|
+
//#endregion
|
|
5041
|
+
//#region ../../node_modules/.pnpm/@fastify+busboy@3.2.0/node_modules/@fastify/busboy/deps/dicer/lib/Dicer.js
|
|
5042
|
+
var require_Dicer = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
5043
|
+
const WritableStream$1 = __require("node:stream").Writable;
|
|
5044
|
+
const inherits$2 = __require("node:util").inherits;
|
|
5045
|
+
const StreamSearch = require_sbmh();
|
|
5046
|
+
const PartStream = require_PartStream();
|
|
5047
|
+
const HeaderParser = require_HeaderParser();
|
|
5048
|
+
const DASH = 45;
|
|
5049
|
+
const B_ONEDASH = Buffer.from("-");
|
|
5050
|
+
const B_CRLF = Buffer.from("\r\n");
|
|
5051
|
+
const EMPTY_FN = function() {};
|
|
5052
|
+
function Dicer(cfg) {
|
|
5053
|
+
if (!(this instanceof Dicer)) return new Dicer(cfg);
|
|
5054
|
+
WritableStream$1.call(this, cfg);
|
|
5055
|
+
if (!cfg || !cfg.headerFirst && typeof cfg.boundary !== "string") throw new TypeError("Boundary required");
|
|
5056
|
+
if (typeof cfg.boundary === "string") this.setBoundary(cfg.boundary);
|
|
5057
|
+
else this._bparser = void 0;
|
|
5058
|
+
this._headerFirst = cfg.headerFirst;
|
|
5059
|
+
this._dashes = 0;
|
|
5060
|
+
this._parts = 0;
|
|
5061
|
+
this._finished = false;
|
|
5062
|
+
this._realFinish = false;
|
|
5063
|
+
this._isPreamble = true;
|
|
5064
|
+
this._justMatched = false;
|
|
5065
|
+
this._firstWrite = true;
|
|
5066
|
+
this._inHeader = true;
|
|
5067
|
+
this._part = void 0;
|
|
5068
|
+
this._cb = void 0;
|
|
5069
|
+
this._ignoreData = false;
|
|
5070
|
+
this._partOpts = { highWaterMark: cfg.partHwm };
|
|
5071
|
+
this._pause = false;
|
|
5072
|
+
const self = this;
|
|
5073
|
+
this._hparser = new HeaderParser(cfg);
|
|
5074
|
+
this._hparser.on("header", function(header) {
|
|
5075
|
+
self._inHeader = false;
|
|
5076
|
+
self._part.emit("header", header);
|
|
5077
|
+
});
|
|
5078
|
+
}
|
|
5079
|
+
inherits$2(Dicer, WritableStream$1);
|
|
5080
|
+
Dicer.prototype.emit = function(ev) {
|
|
5081
|
+
if (ev === "finish" && !this._realFinish) {
|
|
5082
|
+
if (!this._finished) {
|
|
5083
|
+
const self = this;
|
|
5084
|
+
process.nextTick(function() {
|
|
5085
|
+
self.emit("error", /* @__PURE__ */ new Error("Unexpected end of multipart data"));
|
|
5086
|
+
if (self._part && !self._ignoreData) {
|
|
5087
|
+
const type = self._isPreamble ? "Preamble" : "Part";
|
|
5088
|
+
self._part.emit("error", /* @__PURE__ */ new Error(type + " terminated early due to unexpected end of multipart data"));
|
|
5089
|
+
self._part.push(null);
|
|
5090
|
+
process.nextTick(function() {
|
|
5091
|
+
self._realFinish = true;
|
|
5092
|
+
self.emit("finish");
|
|
5093
|
+
self._realFinish = false;
|
|
5094
|
+
});
|
|
5095
|
+
return;
|
|
5096
|
+
}
|
|
5097
|
+
self._realFinish = true;
|
|
5098
|
+
self.emit("finish");
|
|
5099
|
+
self._realFinish = false;
|
|
5100
|
+
});
|
|
5101
|
+
}
|
|
5102
|
+
} else WritableStream$1.prototype.emit.apply(this, arguments);
|
|
5103
|
+
};
|
|
5104
|
+
Dicer.prototype._write = function(data, encoding, cb) {
|
|
5105
|
+
if (!this._hparser && !this._bparser) return cb();
|
|
5106
|
+
if (this._headerFirst && this._isPreamble) {
|
|
5107
|
+
if (!this._part) {
|
|
5108
|
+
this._part = new PartStream(this._partOpts);
|
|
5109
|
+
if (this.listenerCount("preamble") !== 0) this.emit("preamble", this._part);
|
|
5110
|
+
else this._ignore();
|
|
5111
|
+
}
|
|
5112
|
+
const r = this._hparser.push(data);
|
|
5113
|
+
if (!this._inHeader && r !== void 0 && r < data.length) data = data.slice(r);
|
|
5114
|
+
else return cb();
|
|
5115
|
+
}
|
|
5116
|
+
if (this._firstWrite) {
|
|
5117
|
+
this._bparser.push(B_CRLF);
|
|
5118
|
+
this._firstWrite = false;
|
|
5119
|
+
}
|
|
5120
|
+
this._bparser.push(data);
|
|
5121
|
+
if (this._pause) this._cb = cb;
|
|
5122
|
+
else cb();
|
|
5123
|
+
};
|
|
5124
|
+
Dicer.prototype.reset = function() {
|
|
5125
|
+
this._part = void 0;
|
|
5126
|
+
this._bparser = void 0;
|
|
5127
|
+
this._hparser = void 0;
|
|
5128
|
+
};
|
|
5129
|
+
Dicer.prototype.setBoundary = function(boundary) {
|
|
5130
|
+
const self = this;
|
|
5131
|
+
this._bparser = new StreamSearch("\r\n--" + boundary);
|
|
5132
|
+
this._bparser.on("info", function(isMatch, data, start, end) {
|
|
5133
|
+
self._oninfo(isMatch, data, start, end);
|
|
5134
|
+
});
|
|
5135
|
+
};
|
|
5136
|
+
Dicer.prototype._ignore = function() {
|
|
5137
|
+
if (this._part && !this._ignoreData) {
|
|
5138
|
+
this._ignoreData = true;
|
|
5139
|
+
this._part.on("error", EMPTY_FN);
|
|
5140
|
+
this._part.resume();
|
|
5141
|
+
}
|
|
5142
|
+
};
|
|
5143
|
+
Dicer.prototype._oninfo = function(isMatch, data, start, end) {
|
|
5144
|
+
let buf;
|
|
5145
|
+
const self = this;
|
|
5146
|
+
let i = 0;
|
|
5147
|
+
let r;
|
|
5148
|
+
let shouldWriteMore = true;
|
|
5149
|
+
if (!this._part && this._justMatched && data) {
|
|
5150
|
+
while (this._dashes < 2 && start + i < end) if (data[start + i] === DASH) {
|
|
5151
|
+
++i;
|
|
5152
|
+
++this._dashes;
|
|
5153
|
+
} else {
|
|
5154
|
+
if (this._dashes) buf = B_ONEDASH;
|
|
5155
|
+
this._dashes = 0;
|
|
5156
|
+
break;
|
|
5157
|
+
}
|
|
5158
|
+
if (this._dashes === 2) {
|
|
5159
|
+
if (start + i < end && this.listenerCount("trailer") !== 0) this.emit("trailer", data.slice(start + i, end));
|
|
5160
|
+
this.reset();
|
|
5161
|
+
this._finished = true;
|
|
5162
|
+
if (self._parts === 0) {
|
|
5163
|
+
self._realFinish = true;
|
|
5164
|
+
self.emit("finish");
|
|
5165
|
+
self._realFinish = false;
|
|
5166
|
+
}
|
|
5167
|
+
}
|
|
5168
|
+
if (this._dashes) return;
|
|
5169
|
+
}
|
|
5170
|
+
if (this._justMatched) this._justMatched = false;
|
|
5171
|
+
if (!this._part) {
|
|
5172
|
+
this._part = new PartStream(this._partOpts);
|
|
5173
|
+
this._part._read = function(n) {
|
|
5174
|
+
self._unpause();
|
|
5175
|
+
};
|
|
5176
|
+
if (this._isPreamble && this.listenerCount("preamble") !== 0) this.emit("preamble", this._part);
|
|
5177
|
+
else if (this._isPreamble !== true && this.listenerCount("part") !== 0) this.emit("part", this._part);
|
|
5178
|
+
else this._ignore();
|
|
5179
|
+
if (!this._isPreamble) this._inHeader = true;
|
|
5180
|
+
}
|
|
5181
|
+
if (data && start < end && !this._ignoreData) {
|
|
5182
|
+
if (this._isPreamble || !this._inHeader) {
|
|
5183
|
+
if (buf) shouldWriteMore = this._part.push(buf);
|
|
5184
|
+
shouldWriteMore = this._part.push(data.slice(start, end));
|
|
5185
|
+
if (!shouldWriteMore) this._pause = true;
|
|
5186
|
+
} else if (!this._isPreamble && this._inHeader) {
|
|
5187
|
+
if (buf) this._hparser.push(buf);
|
|
5188
|
+
r = this._hparser.push(data.slice(start, end));
|
|
5189
|
+
if (!this._inHeader && r !== void 0 && r < end) this._oninfo(false, data, start + r, end);
|
|
5190
|
+
}
|
|
5191
|
+
}
|
|
5192
|
+
if (isMatch) {
|
|
5193
|
+
this._hparser.reset();
|
|
5194
|
+
if (this._isPreamble) this._isPreamble = false;
|
|
5195
|
+
else if (start !== end) {
|
|
5196
|
+
++this._parts;
|
|
5197
|
+
this._part.on("end", function() {
|
|
5198
|
+
if (--self._parts === 0) if (self._finished) {
|
|
5199
|
+
self._realFinish = true;
|
|
5200
|
+
self.emit("finish");
|
|
5201
|
+
self._realFinish = false;
|
|
5202
|
+
} else self._unpause();
|
|
5203
|
+
});
|
|
5204
|
+
}
|
|
5205
|
+
this._part.push(null);
|
|
5206
|
+
this._part = void 0;
|
|
5207
|
+
this._ignoreData = false;
|
|
5208
|
+
this._justMatched = true;
|
|
5209
|
+
this._dashes = 0;
|
|
5210
|
+
}
|
|
5211
|
+
};
|
|
5212
|
+
Dicer.prototype._unpause = function() {
|
|
5213
|
+
if (!this._pause) return;
|
|
5214
|
+
this._pause = false;
|
|
5215
|
+
if (this._cb) {
|
|
5216
|
+
const cb = this._cb;
|
|
5217
|
+
this._cb = void 0;
|
|
5218
|
+
cb();
|
|
5219
|
+
}
|
|
5220
|
+
};
|
|
5221
|
+
module.exports = Dicer;
|
|
5222
|
+
}));
|
|
5223
|
+
//#endregion
|
|
5224
|
+
//#region ../../node_modules/.pnpm/@fastify+busboy@3.2.0/node_modules/@fastify/busboy/lib/utils/decodeText.js
|
|
5225
|
+
var require_decodeText = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
5226
|
+
const utf8Decoder = new TextDecoder("utf-8");
|
|
5227
|
+
const textDecoders = new Map([["utf-8", utf8Decoder], ["utf8", utf8Decoder]]);
|
|
5228
|
+
function getDecoder(charset) {
|
|
5229
|
+
let lc;
|
|
5230
|
+
while (true) switch (charset) {
|
|
5231
|
+
case "utf-8":
|
|
5232
|
+
case "utf8": return decoders.utf8;
|
|
5233
|
+
case "latin1":
|
|
5234
|
+
case "ascii":
|
|
5235
|
+
case "us-ascii":
|
|
5236
|
+
case "iso-8859-1":
|
|
5237
|
+
case "iso8859-1":
|
|
5238
|
+
case "iso88591":
|
|
5239
|
+
case "iso_8859-1":
|
|
5240
|
+
case "windows-1252":
|
|
5241
|
+
case "iso_8859-1:1987":
|
|
5242
|
+
case "cp1252":
|
|
5243
|
+
case "x-cp1252": return decoders.latin1;
|
|
5244
|
+
case "utf16le":
|
|
5245
|
+
case "utf-16le":
|
|
5246
|
+
case "ucs2":
|
|
5247
|
+
case "ucs-2": return decoders.utf16le;
|
|
5248
|
+
case "base64": return decoders.base64;
|
|
5249
|
+
default:
|
|
5250
|
+
if (lc === void 0) {
|
|
5251
|
+
lc = true;
|
|
5252
|
+
charset = charset.toLowerCase();
|
|
5253
|
+
continue;
|
|
5254
|
+
}
|
|
5255
|
+
return decoders.other.bind(charset);
|
|
5256
|
+
}
|
|
5257
|
+
}
|
|
5258
|
+
const decoders = {
|
|
5259
|
+
utf8: (data, sourceEncoding) => {
|
|
5260
|
+
if (data.length === 0) return "";
|
|
5261
|
+
if (typeof data === "string") data = Buffer.from(data, sourceEncoding);
|
|
5262
|
+
return data.utf8Slice(0, data.length);
|
|
5263
|
+
},
|
|
5264
|
+
latin1: (data, sourceEncoding) => {
|
|
5265
|
+
if (data.length === 0) return "";
|
|
5266
|
+
if (typeof data === "string") return data;
|
|
5267
|
+
return data.latin1Slice(0, data.length);
|
|
5268
|
+
},
|
|
5269
|
+
utf16le: (data, sourceEncoding) => {
|
|
5270
|
+
if (data.length === 0) return "";
|
|
5271
|
+
if (typeof data === "string") data = Buffer.from(data, sourceEncoding);
|
|
5272
|
+
return data.ucs2Slice(0, data.length);
|
|
5273
|
+
},
|
|
5274
|
+
base64: (data, sourceEncoding) => {
|
|
5275
|
+
if (data.length === 0) return "";
|
|
5276
|
+
if (typeof data === "string") data = Buffer.from(data, sourceEncoding);
|
|
5277
|
+
return data.base64Slice(0, data.length);
|
|
5278
|
+
},
|
|
5279
|
+
other: (data, sourceEncoding) => {
|
|
5280
|
+
if (data.length === 0) return "";
|
|
5281
|
+
if (typeof data === "string") data = Buffer.from(data, sourceEncoding);
|
|
5282
|
+
if (textDecoders.has(exports.toString())) try {
|
|
5283
|
+
return textDecoders.get(exports).decode(data);
|
|
5284
|
+
} catch {}
|
|
5285
|
+
return typeof data === "string" ? data : data.toString();
|
|
5286
|
+
}
|
|
5287
|
+
};
|
|
5288
|
+
function decodeText(text, sourceEncoding, destEncoding) {
|
|
5289
|
+
if (text) return getDecoder(destEncoding)(text, sourceEncoding);
|
|
5290
|
+
return text;
|
|
5291
|
+
}
|
|
5292
|
+
module.exports = decodeText;
|
|
5293
|
+
}));
|
|
5294
|
+
//#endregion
|
|
5295
|
+
//#region ../../node_modules/.pnpm/@fastify+busboy@3.2.0/node_modules/@fastify/busboy/lib/utils/parseParams.js
|
|
5296
|
+
var require_parseParams = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
5297
|
+
const decodeText = require_decodeText();
|
|
5298
|
+
const RE_ENCODED = /%[a-fA-F0-9][a-fA-F0-9]/g;
|
|
5299
|
+
const EncodedLookup = {
|
|
5300
|
+
"%00": "\0",
|
|
5301
|
+
"%01": "",
|
|
5302
|
+
"%02": "",
|
|
5303
|
+
"%03": "",
|
|
5304
|
+
"%04": "",
|
|
5305
|
+
"%05": "",
|
|
5306
|
+
"%06": "",
|
|
5307
|
+
"%07": "\x07",
|
|
5308
|
+
"%08": "\b",
|
|
5309
|
+
"%09": " ",
|
|
5310
|
+
"%0a": "\n",
|
|
5311
|
+
"%0A": "\n",
|
|
5312
|
+
"%0b": "\v",
|
|
5313
|
+
"%0B": "\v",
|
|
5314
|
+
"%0c": "\f",
|
|
5315
|
+
"%0C": "\f",
|
|
5316
|
+
"%0d": "\r",
|
|
5317
|
+
"%0D": "\r",
|
|
5318
|
+
"%0e": "",
|
|
5319
|
+
"%0E": "",
|
|
5320
|
+
"%0f": "",
|
|
5321
|
+
"%0F": "",
|
|
5322
|
+
"%10": "",
|
|
5323
|
+
"%11": "",
|
|
5324
|
+
"%12": "",
|
|
5325
|
+
"%13": "",
|
|
5326
|
+
"%14": "",
|
|
5327
|
+
"%15": "",
|
|
5328
|
+
"%16": "",
|
|
5329
|
+
"%17": "",
|
|
5330
|
+
"%18": "",
|
|
5331
|
+
"%19": "",
|
|
5332
|
+
"%1a": "",
|
|
5333
|
+
"%1A": "",
|
|
5334
|
+
"%1b": "\x1B",
|
|
5335
|
+
"%1B": "\x1B",
|
|
5336
|
+
"%1c": "",
|
|
5337
|
+
"%1C": "",
|
|
5338
|
+
"%1d": "",
|
|
5339
|
+
"%1D": "",
|
|
5340
|
+
"%1e": "",
|
|
5341
|
+
"%1E": "",
|
|
5342
|
+
"%1f": "",
|
|
5343
|
+
"%1F": "",
|
|
5344
|
+
"%20": " ",
|
|
5345
|
+
"%21": "!",
|
|
5346
|
+
"%22": "\"",
|
|
5347
|
+
"%23": "#",
|
|
5348
|
+
"%24": "$",
|
|
5349
|
+
"%25": "%",
|
|
5350
|
+
"%26": "&",
|
|
5351
|
+
"%27": "'",
|
|
5352
|
+
"%28": "(",
|
|
5353
|
+
"%29": ")",
|
|
5354
|
+
"%2a": "*",
|
|
5355
|
+
"%2A": "*",
|
|
5356
|
+
"%2b": "+",
|
|
5357
|
+
"%2B": "+",
|
|
5358
|
+
"%2c": ",",
|
|
5359
|
+
"%2C": ",",
|
|
5360
|
+
"%2d": "-",
|
|
5361
|
+
"%2D": "-",
|
|
5362
|
+
"%2e": ".",
|
|
5363
|
+
"%2E": ".",
|
|
5364
|
+
"%2f": "/",
|
|
5365
|
+
"%2F": "/",
|
|
5366
|
+
"%30": "0",
|
|
5367
|
+
"%31": "1",
|
|
5368
|
+
"%32": "2",
|
|
5369
|
+
"%33": "3",
|
|
5370
|
+
"%34": "4",
|
|
5371
|
+
"%35": "5",
|
|
5372
|
+
"%36": "6",
|
|
5373
|
+
"%37": "7",
|
|
5374
|
+
"%38": "8",
|
|
5375
|
+
"%39": "9",
|
|
5376
|
+
"%3a": ":",
|
|
5377
|
+
"%3A": ":",
|
|
5378
|
+
"%3b": ";",
|
|
5379
|
+
"%3B": ";",
|
|
5380
|
+
"%3c": "<",
|
|
5381
|
+
"%3C": "<",
|
|
5382
|
+
"%3d": "=",
|
|
5383
|
+
"%3D": "=",
|
|
5384
|
+
"%3e": ">",
|
|
5385
|
+
"%3E": ">",
|
|
5386
|
+
"%3f": "?",
|
|
5387
|
+
"%3F": "?",
|
|
5388
|
+
"%40": "@",
|
|
5389
|
+
"%41": "A",
|
|
5390
|
+
"%42": "B",
|
|
5391
|
+
"%43": "C",
|
|
5392
|
+
"%44": "D",
|
|
5393
|
+
"%45": "E",
|
|
5394
|
+
"%46": "F",
|
|
5395
|
+
"%47": "G",
|
|
5396
|
+
"%48": "H",
|
|
5397
|
+
"%49": "I",
|
|
5398
|
+
"%4a": "J",
|
|
5399
|
+
"%4A": "J",
|
|
5400
|
+
"%4b": "K",
|
|
5401
|
+
"%4B": "K",
|
|
5402
|
+
"%4c": "L",
|
|
5403
|
+
"%4C": "L",
|
|
5404
|
+
"%4d": "M",
|
|
5405
|
+
"%4D": "M",
|
|
5406
|
+
"%4e": "N",
|
|
5407
|
+
"%4E": "N",
|
|
5408
|
+
"%4f": "O",
|
|
5409
|
+
"%4F": "O",
|
|
5410
|
+
"%50": "P",
|
|
5411
|
+
"%51": "Q",
|
|
5412
|
+
"%52": "R",
|
|
5413
|
+
"%53": "S",
|
|
5414
|
+
"%54": "T",
|
|
5415
|
+
"%55": "U",
|
|
5416
|
+
"%56": "V",
|
|
5417
|
+
"%57": "W",
|
|
5418
|
+
"%58": "X",
|
|
5419
|
+
"%59": "Y",
|
|
5420
|
+
"%5a": "Z",
|
|
5421
|
+
"%5A": "Z",
|
|
5422
|
+
"%5b": "[",
|
|
5423
|
+
"%5B": "[",
|
|
5424
|
+
"%5c": "\\",
|
|
5425
|
+
"%5C": "\\",
|
|
5426
|
+
"%5d": "]",
|
|
5427
|
+
"%5D": "]",
|
|
5428
|
+
"%5e": "^",
|
|
5429
|
+
"%5E": "^",
|
|
5430
|
+
"%5f": "_",
|
|
5431
|
+
"%5F": "_",
|
|
5432
|
+
"%60": "`",
|
|
5433
|
+
"%61": "a",
|
|
5434
|
+
"%62": "b",
|
|
5435
|
+
"%63": "c",
|
|
5436
|
+
"%64": "d",
|
|
5437
|
+
"%65": "e",
|
|
5438
|
+
"%66": "f",
|
|
5439
|
+
"%67": "g",
|
|
5440
|
+
"%68": "h",
|
|
5441
|
+
"%69": "i",
|
|
5442
|
+
"%6a": "j",
|
|
5443
|
+
"%6A": "j",
|
|
5444
|
+
"%6b": "k",
|
|
5445
|
+
"%6B": "k",
|
|
5446
|
+
"%6c": "l",
|
|
5447
|
+
"%6C": "l",
|
|
5448
|
+
"%6d": "m",
|
|
5449
|
+
"%6D": "m",
|
|
5450
|
+
"%6e": "n",
|
|
5451
|
+
"%6E": "n",
|
|
5452
|
+
"%6f": "o",
|
|
5453
|
+
"%6F": "o",
|
|
5454
|
+
"%70": "p",
|
|
5455
|
+
"%71": "q",
|
|
5456
|
+
"%72": "r",
|
|
5457
|
+
"%73": "s",
|
|
5458
|
+
"%74": "t",
|
|
5459
|
+
"%75": "u",
|
|
5460
|
+
"%76": "v",
|
|
5461
|
+
"%77": "w",
|
|
5462
|
+
"%78": "x",
|
|
5463
|
+
"%79": "y",
|
|
5464
|
+
"%7a": "z",
|
|
5465
|
+
"%7A": "z",
|
|
5466
|
+
"%7b": "{",
|
|
5467
|
+
"%7B": "{",
|
|
5468
|
+
"%7c": "|",
|
|
5469
|
+
"%7C": "|",
|
|
5470
|
+
"%7d": "}",
|
|
5471
|
+
"%7D": "}",
|
|
5472
|
+
"%7e": "~",
|
|
5473
|
+
"%7E": "~",
|
|
5474
|
+
"%7f": "",
|
|
5475
|
+
"%7F": "",
|
|
5476
|
+
"%80": "",
|
|
5477
|
+
"%81": "",
|
|
5478
|
+
"%82": "",
|
|
5479
|
+
"%83": "",
|
|
5480
|
+
"%84": "",
|
|
5481
|
+
"%85": "
",
|
|
5482
|
+
"%86": "",
|
|
5483
|
+
"%87": "",
|
|
5484
|
+
"%88": "",
|
|
5485
|
+
"%89": "",
|
|
5486
|
+
"%8a": "",
|
|
5487
|
+
"%8A": "",
|
|
5488
|
+
"%8b": "",
|
|
5489
|
+
"%8B": "",
|
|
5490
|
+
"%8c": "",
|
|
5491
|
+
"%8C": "",
|
|
5492
|
+
"%8d": "",
|
|
5493
|
+
"%8D": "",
|
|
5494
|
+
"%8e": "",
|
|
5495
|
+
"%8E": "",
|
|
5496
|
+
"%8f": "",
|
|
5497
|
+
"%8F": "",
|
|
5498
|
+
"%90": "",
|
|
5499
|
+
"%91": "",
|
|
5500
|
+
"%92": "",
|
|
5501
|
+
"%93": "",
|
|
5502
|
+
"%94": "",
|
|
5503
|
+
"%95": "",
|
|
5504
|
+
"%96": "",
|
|
5505
|
+
"%97": "",
|
|
5506
|
+
"%98": "",
|
|
5507
|
+
"%99": "",
|
|
5508
|
+
"%9a": "",
|
|
5509
|
+
"%9A": "",
|
|
5510
|
+
"%9b": "",
|
|
5511
|
+
"%9B": "",
|
|
5512
|
+
"%9c": "",
|
|
5513
|
+
"%9C": "",
|
|
5514
|
+
"%9d": "",
|
|
5515
|
+
"%9D": "",
|
|
5516
|
+
"%9e": "",
|
|
5517
|
+
"%9E": "",
|
|
5518
|
+
"%9f": "",
|
|
5519
|
+
"%9F": "",
|
|
5520
|
+
"%a0": "\xA0",
|
|
5521
|
+
"%A0": "\xA0",
|
|
5522
|
+
"%a1": "¡",
|
|
5523
|
+
"%A1": "¡",
|
|
5524
|
+
"%a2": "¢",
|
|
5525
|
+
"%A2": "¢",
|
|
5526
|
+
"%a3": "£",
|
|
5527
|
+
"%A3": "£",
|
|
5528
|
+
"%a4": "¤",
|
|
5529
|
+
"%A4": "¤",
|
|
5530
|
+
"%a5": "¥",
|
|
5531
|
+
"%A5": "¥",
|
|
5532
|
+
"%a6": "¦",
|
|
5533
|
+
"%A6": "¦",
|
|
5534
|
+
"%a7": "§",
|
|
5535
|
+
"%A7": "§",
|
|
5536
|
+
"%a8": "¨",
|
|
5537
|
+
"%A8": "¨",
|
|
5538
|
+
"%a9": "©",
|
|
5539
|
+
"%A9": "©",
|
|
5540
|
+
"%aa": "ª",
|
|
5541
|
+
"%Aa": "ª",
|
|
5542
|
+
"%aA": "ª",
|
|
5543
|
+
"%AA": "ª",
|
|
5544
|
+
"%ab": "«",
|
|
5545
|
+
"%Ab": "«",
|
|
5546
|
+
"%aB": "«",
|
|
5547
|
+
"%AB": "«",
|
|
5548
|
+
"%ac": "¬",
|
|
5549
|
+
"%Ac": "¬",
|
|
5550
|
+
"%aC": "¬",
|
|
5551
|
+
"%AC": "¬",
|
|
5552
|
+
"%ad": "",
|
|
5553
|
+
"%Ad": "",
|
|
5554
|
+
"%aD": "",
|
|
5555
|
+
"%AD": "",
|
|
5556
|
+
"%ae": "®",
|
|
5557
|
+
"%Ae": "®",
|
|
5558
|
+
"%aE": "®",
|
|
5559
|
+
"%AE": "®",
|
|
5560
|
+
"%af": "¯",
|
|
5561
|
+
"%Af": "¯",
|
|
5562
|
+
"%aF": "¯",
|
|
5563
|
+
"%AF": "¯",
|
|
5564
|
+
"%b0": "°",
|
|
5565
|
+
"%B0": "°",
|
|
5566
|
+
"%b1": "±",
|
|
5567
|
+
"%B1": "±",
|
|
5568
|
+
"%b2": "²",
|
|
5569
|
+
"%B2": "²",
|
|
5570
|
+
"%b3": "³",
|
|
5571
|
+
"%B3": "³",
|
|
5572
|
+
"%b4": "´",
|
|
5573
|
+
"%B4": "´",
|
|
5574
|
+
"%b5": "µ",
|
|
5575
|
+
"%B5": "µ",
|
|
5576
|
+
"%b6": "¶",
|
|
5577
|
+
"%B6": "¶",
|
|
5578
|
+
"%b7": "·",
|
|
5579
|
+
"%B7": "·",
|
|
5580
|
+
"%b8": "¸",
|
|
5581
|
+
"%B8": "¸",
|
|
5582
|
+
"%b9": "¹",
|
|
5583
|
+
"%B9": "¹",
|
|
5584
|
+
"%ba": "º",
|
|
5585
|
+
"%Ba": "º",
|
|
5586
|
+
"%bA": "º",
|
|
5587
|
+
"%BA": "º",
|
|
5588
|
+
"%bb": "»",
|
|
5589
|
+
"%Bb": "»",
|
|
5590
|
+
"%bB": "»",
|
|
5591
|
+
"%BB": "»",
|
|
5592
|
+
"%bc": "¼",
|
|
5593
|
+
"%Bc": "¼",
|
|
5594
|
+
"%bC": "¼",
|
|
5595
|
+
"%BC": "¼",
|
|
5596
|
+
"%bd": "½",
|
|
5597
|
+
"%Bd": "½",
|
|
5598
|
+
"%bD": "½",
|
|
5599
|
+
"%BD": "½",
|
|
5600
|
+
"%be": "¾",
|
|
5601
|
+
"%Be": "¾",
|
|
5602
|
+
"%bE": "¾",
|
|
5603
|
+
"%BE": "¾",
|
|
5604
|
+
"%bf": "¿",
|
|
5605
|
+
"%Bf": "¿",
|
|
5606
|
+
"%bF": "¿",
|
|
5607
|
+
"%BF": "¿",
|
|
5608
|
+
"%c0": "À",
|
|
5609
|
+
"%C0": "À",
|
|
5610
|
+
"%c1": "Á",
|
|
5611
|
+
"%C1": "Á",
|
|
5612
|
+
"%c2": "Â",
|
|
5613
|
+
"%C2": "Â",
|
|
5614
|
+
"%c3": "Ã",
|
|
5615
|
+
"%C3": "Ã",
|
|
5616
|
+
"%c4": "Ä",
|
|
5617
|
+
"%C4": "Ä",
|
|
5618
|
+
"%c5": "Å",
|
|
5619
|
+
"%C5": "Å",
|
|
5620
|
+
"%c6": "Æ",
|
|
5621
|
+
"%C6": "Æ",
|
|
5622
|
+
"%c7": "Ç",
|
|
5623
|
+
"%C7": "Ç",
|
|
5624
|
+
"%c8": "È",
|
|
5625
|
+
"%C8": "È",
|
|
5626
|
+
"%c9": "É",
|
|
5627
|
+
"%C9": "É",
|
|
5628
|
+
"%ca": "Ê",
|
|
5629
|
+
"%Ca": "Ê",
|
|
5630
|
+
"%cA": "Ê",
|
|
5631
|
+
"%CA": "Ê",
|
|
5632
|
+
"%cb": "Ë",
|
|
5633
|
+
"%Cb": "Ë",
|
|
5634
|
+
"%cB": "Ë",
|
|
5635
|
+
"%CB": "Ë",
|
|
5636
|
+
"%cc": "Ì",
|
|
5637
|
+
"%Cc": "Ì",
|
|
5638
|
+
"%cC": "Ì",
|
|
5639
|
+
"%CC": "Ì",
|
|
5640
|
+
"%cd": "Í",
|
|
5641
|
+
"%Cd": "Í",
|
|
5642
|
+
"%cD": "Í",
|
|
5643
|
+
"%CD": "Í",
|
|
5644
|
+
"%ce": "Î",
|
|
5645
|
+
"%Ce": "Î",
|
|
5646
|
+
"%cE": "Î",
|
|
5647
|
+
"%CE": "Î",
|
|
5648
|
+
"%cf": "Ï",
|
|
5649
|
+
"%Cf": "Ï",
|
|
5650
|
+
"%cF": "Ï",
|
|
5651
|
+
"%CF": "Ï",
|
|
5652
|
+
"%d0": "Ð",
|
|
5653
|
+
"%D0": "Ð",
|
|
5654
|
+
"%d1": "Ñ",
|
|
5655
|
+
"%D1": "Ñ",
|
|
5656
|
+
"%d2": "Ò",
|
|
5657
|
+
"%D2": "Ò",
|
|
5658
|
+
"%d3": "Ó",
|
|
5659
|
+
"%D3": "Ó",
|
|
5660
|
+
"%d4": "Ô",
|
|
5661
|
+
"%D4": "Ô",
|
|
5662
|
+
"%d5": "Õ",
|
|
5663
|
+
"%D5": "Õ",
|
|
5664
|
+
"%d6": "Ö",
|
|
5665
|
+
"%D6": "Ö",
|
|
5666
|
+
"%d7": "×",
|
|
5667
|
+
"%D7": "×",
|
|
5668
|
+
"%d8": "Ø",
|
|
5669
|
+
"%D8": "Ø",
|
|
5670
|
+
"%d9": "Ù",
|
|
5671
|
+
"%D9": "Ù",
|
|
5672
|
+
"%da": "Ú",
|
|
5673
|
+
"%Da": "Ú",
|
|
5674
|
+
"%dA": "Ú",
|
|
5675
|
+
"%DA": "Ú",
|
|
5676
|
+
"%db": "Û",
|
|
5677
|
+
"%Db": "Û",
|
|
5678
|
+
"%dB": "Û",
|
|
5679
|
+
"%DB": "Û",
|
|
5680
|
+
"%dc": "Ü",
|
|
5681
|
+
"%Dc": "Ü",
|
|
5682
|
+
"%dC": "Ü",
|
|
5683
|
+
"%DC": "Ü",
|
|
5684
|
+
"%dd": "Ý",
|
|
5685
|
+
"%Dd": "Ý",
|
|
5686
|
+
"%dD": "Ý",
|
|
5687
|
+
"%DD": "Ý",
|
|
5688
|
+
"%de": "Þ",
|
|
5689
|
+
"%De": "Þ",
|
|
5690
|
+
"%dE": "Þ",
|
|
5691
|
+
"%DE": "Þ",
|
|
5692
|
+
"%df": "ß",
|
|
5693
|
+
"%Df": "ß",
|
|
5694
|
+
"%dF": "ß",
|
|
5695
|
+
"%DF": "ß",
|
|
5696
|
+
"%e0": "à",
|
|
5697
|
+
"%E0": "à",
|
|
5698
|
+
"%e1": "á",
|
|
5699
|
+
"%E1": "á",
|
|
5700
|
+
"%e2": "â",
|
|
5701
|
+
"%E2": "â",
|
|
5702
|
+
"%e3": "ã",
|
|
5703
|
+
"%E3": "ã",
|
|
5704
|
+
"%e4": "ä",
|
|
5705
|
+
"%E4": "ä",
|
|
5706
|
+
"%e5": "å",
|
|
5707
|
+
"%E5": "å",
|
|
5708
|
+
"%e6": "æ",
|
|
5709
|
+
"%E6": "æ",
|
|
5710
|
+
"%e7": "ç",
|
|
5711
|
+
"%E7": "ç",
|
|
5712
|
+
"%e8": "è",
|
|
5713
|
+
"%E8": "è",
|
|
5714
|
+
"%e9": "é",
|
|
5715
|
+
"%E9": "é",
|
|
5716
|
+
"%ea": "ê",
|
|
5717
|
+
"%Ea": "ê",
|
|
5718
|
+
"%eA": "ê",
|
|
5719
|
+
"%EA": "ê",
|
|
5720
|
+
"%eb": "ë",
|
|
5721
|
+
"%Eb": "ë",
|
|
5722
|
+
"%eB": "ë",
|
|
5723
|
+
"%EB": "ë",
|
|
5724
|
+
"%ec": "ì",
|
|
5725
|
+
"%Ec": "ì",
|
|
5726
|
+
"%eC": "ì",
|
|
5727
|
+
"%EC": "ì",
|
|
5728
|
+
"%ed": "í",
|
|
5729
|
+
"%Ed": "í",
|
|
5730
|
+
"%eD": "í",
|
|
5731
|
+
"%ED": "í",
|
|
5732
|
+
"%ee": "î",
|
|
5733
|
+
"%Ee": "î",
|
|
5734
|
+
"%eE": "î",
|
|
5735
|
+
"%EE": "î",
|
|
5736
|
+
"%ef": "ï",
|
|
5737
|
+
"%Ef": "ï",
|
|
5738
|
+
"%eF": "ï",
|
|
5739
|
+
"%EF": "ï",
|
|
5740
|
+
"%f0": "ð",
|
|
5741
|
+
"%F0": "ð",
|
|
5742
|
+
"%f1": "ñ",
|
|
5743
|
+
"%F1": "ñ",
|
|
5744
|
+
"%f2": "ò",
|
|
5745
|
+
"%F2": "ò",
|
|
5746
|
+
"%f3": "ó",
|
|
5747
|
+
"%F3": "ó",
|
|
5748
|
+
"%f4": "ô",
|
|
5749
|
+
"%F4": "ô",
|
|
5750
|
+
"%f5": "õ",
|
|
5751
|
+
"%F5": "õ",
|
|
5752
|
+
"%f6": "ö",
|
|
5753
|
+
"%F6": "ö",
|
|
5754
|
+
"%f7": "÷",
|
|
5755
|
+
"%F7": "÷",
|
|
5756
|
+
"%f8": "ø",
|
|
5757
|
+
"%F8": "ø",
|
|
5758
|
+
"%f9": "ù",
|
|
5759
|
+
"%F9": "ù",
|
|
5760
|
+
"%fa": "ú",
|
|
5761
|
+
"%Fa": "ú",
|
|
5762
|
+
"%fA": "ú",
|
|
5763
|
+
"%FA": "ú",
|
|
5764
|
+
"%fb": "û",
|
|
5765
|
+
"%Fb": "û",
|
|
5766
|
+
"%fB": "û",
|
|
5767
|
+
"%FB": "û",
|
|
5768
|
+
"%fc": "ü",
|
|
5769
|
+
"%Fc": "ü",
|
|
5770
|
+
"%fC": "ü",
|
|
5771
|
+
"%FC": "ü",
|
|
5772
|
+
"%fd": "ý",
|
|
5773
|
+
"%Fd": "ý",
|
|
5774
|
+
"%fD": "ý",
|
|
5775
|
+
"%FD": "ý",
|
|
5776
|
+
"%fe": "þ",
|
|
5777
|
+
"%Fe": "þ",
|
|
5778
|
+
"%fE": "þ",
|
|
5779
|
+
"%FE": "þ",
|
|
5780
|
+
"%ff": "ÿ",
|
|
5781
|
+
"%Ff": "ÿ",
|
|
5782
|
+
"%fF": "ÿ",
|
|
5783
|
+
"%FF": "ÿ"
|
|
5784
|
+
};
|
|
5785
|
+
function encodedReplacer(match) {
|
|
5786
|
+
return EncodedLookup[match];
|
|
5787
|
+
}
|
|
5788
|
+
const STATE_KEY = 0;
|
|
5789
|
+
const STATE_VALUE = 1;
|
|
5790
|
+
const STATE_CHARSET = 2;
|
|
5791
|
+
const STATE_LANG = 3;
|
|
5792
|
+
function parseParams(str) {
|
|
5793
|
+
const res = [];
|
|
5794
|
+
let state = STATE_KEY;
|
|
5795
|
+
let charset = "";
|
|
5796
|
+
let inquote = false;
|
|
5797
|
+
let escaping = false;
|
|
5798
|
+
let p = 0;
|
|
5799
|
+
let tmp = "";
|
|
5800
|
+
const len = str.length;
|
|
5801
|
+
for (var i = 0; i < len; ++i) {
|
|
5802
|
+
const char = str[i];
|
|
5803
|
+
if (char === "\\" && inquote) if (escaping) escaping = false;
|
|
5804
|
+
else {
|
|
5805
|
+
escaping = true;
|
|
5806
|
+
continue;
|
|
5807
|
+
}
|
|
5808
|
+
else if (char === "\"") if (!escaping) {
|
|
5809
|
+
if (inquote) {
|
|
5810
|
+
inquote = false;
|
|
5811
|
+
state = STATE_KEY;
|
|
5812
|
+
while (i + 1 < len && str[i + 1] !== ";") ++i;
|
|
5813
|
+
} else inquote = true;
|
|
5814
|
+
continue;
|
|
5815
|
+
} else escaping = false;
|
|
5816
|
+
else {
|
|
5817
|
+
if (escaping && inquote) tmp += "\\";
|
|
5818
|
+
escaping = false;
|
|
5819
|
+
if ((state === STATE_CHARSET || state === STATE_LANG) && char === "'") {
|
|
5820
|
+
if (state === STATE_CHARSET) {
|
|
5821
|
+
state = STATE_LANG;
|
|
5822
|
+
charset = tmp.substring(1);
|
|
5823
|
+
} else state = STATE_VALUE;
|
|
5824
|
+
tmp = "";
|
|
5825
|
+
continue;
|
|
5826
|
+
} else if (state === STATE_KEY && (char === "*" || char === "=") && res.length) {
|
|
5827
|
+
state = char === "*" ? STATE_CHARSET : STATE_VALUE;
|
|
5828
|
+
res[p] = [tmp, void 0];
|
|
5829
|
+
tmp = "";
|
|
5830
|
+
continue;
|
|
5831
|
+
} else if (!inquote && char === ";") {
|
|
5832
|
+
state = STATE_KEY;
|
|
5833
|
+
if (charset) {
|
|
5834
|
+
if (tmp.length) tmp = decodeText(tmp.replace(RE_ENCODED, encodedReplacer), "binary", charset);
|
|
5835
|
+
charset = "";
|
|
5836
|
+
} else if (tmp.length) tmp = decodeText(tmp, "binary", "utf8");
|
|
5837
|
+
if (res[p] === void 0) res[p] = tmp;
|
|
5838
|
+
else res[p][1] = tmp;
|
|
5839
|
+
tmp = "";
|
|
5840
|
+
++p;
|
|
5841
|
+
continue;
|
|
5842
|
+
} else if (!inquote && (char === " " || char === " ")) continue;
|
|
5843
|
+
}
|
|
5844
|
+
tmp += char;
|
|
5845
|
+
}
|
|
5846
|
+
if (charset && tmp.length) tmp = decodeText(tmp.replace(RE_ENCODED, encodedReplacer), "binary", charset);
|
|
5847
|
+
else if (tmp) tmp = decodeText(tmp, "binary", "utf8");
|
|
5848
|
+
if (res[p] === void 0) {
|
|
5849
|
+
if (tmp) res[p] = tmp;
|
|
5850
|
+
} else res[p][1] = tmp;
|
|
5851
|
+
return res;
|
|
5852
|
+
}
|
|
5853
|
+
module.exports = parseParams;
|
|
5854
|
+
}));
|
|
5855
|
+
//#endregion
|
|
5856
|
+
//#region ../../node_modules/.pnpm/@fastify+busboy@3.2.0/node_modules/@fastify/busboy/lib/utils/basename.js
|
|
5857
|
+
var require_basename = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
5858
|
+
module.exports = function basename(path) {
|
|
5859
|
+
if (typeof path !== "string") return "";
|
|
5860
|
+
for (var i = path.length - 1; i >= 0; --i) switch (path.charCodeAt(i)) {
|
|
5861
|
+
case 47:
|
|
5862
|
+
case 92:
|
|
5863
|
+
path = path.slice(i + 1);
|
|
5864
|
+
return path === ".." || path === "." ? "" : path;
|
|
5865
|
+
}
|
|
5866
|
+
return path === ".." || path === "." ? "" : path;
|
|
5867
|
+
};
|
|
5868
|
+
}));
|
|
5869
|
+
//#endregion
|
|
5870
|
+
//#region ../../node_modules/.pnpm/@fastify+busboy@3.2.0/node_modules/@fastify/busboy/lib/types/multipart.js
|
|
5871
|
+
var require_multipart$1 = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
5872
|
+
const { Readable: Readable$1 } = __require("node:stream");
|
|
5873
|
+
const { inherits: inherits$1 } = __require("node:util");
|
|
5874
|
+
const Dicer = require_Dicer();
|
|
5875
|
+
const parseParams = require_parseParams();
|
|
5876
|
+
const decodeText = require_decodeText();
|
|
5877
|
+
const basename = require_basename();
|
|
5878
|
+
const getLimit = require_getLimit();
|
|
5879
|
+
const RE_BOUNDARY = /^boundary$/i;
|
|
5880
|
+
const RE_FIELD = /^form-data$/i;
|
|
5881
|
+
const RE_CHARSET = /^charset$/i;
|
|
5882
|
+
const RE_FILENAME = /^filename$/i;
|
|
5883
|
+
const RE_NAME = /^name$/i;
|
|
5884
|
+
Multipart.detect = /^multipart\/form-data/i;
|
|
5885
|
+
function Multipart(boy, cfg) {
|
|
5886
|
+
let i;
|
|
5887
|
+
let len;
|
|
5888
|
+
const self = this;
|
|
5889
|
+
let boundary;
|
|
5890
|
+
const limits = cfg.limits;
|
|
5891
|
+
const isPartAFile = cfg.isPartAFile || ((fieldName, contentType, fileName) => contentType === "application/octet-stream" || fileName !== void 0);
|
|
5892
|
+
const parsedConType = cfg.parsedConType || [];
|
|
5893
|
+
const defCharset = cfg.defCharset || "utf8";
|
|
5894
|
+
const preservePath = cfg.preservePath;
|
|
5895
|
+
const fileOpts = { highWaterMark: cfg.fileHwm };
|
|
5896
|
+
for (i = 0, len = parsedConType.length; i < len; ++i) if (Array.isArray(parsedConType[i]) && RE_BOUNDARY.test(parsedConType[i][0])) {
|
|
5897
|
+
boundary = parsedConType[i][1];
|
|
5898
|
+
break;
|
|
5899
|
+
}
|
|
5900
|
+
function checkFinished() {
|
|
5901
|
+
if (nends === 0 && finished && !boy._done) {
|
|
5902
|
+
finished = false;
|
|
5903
|
+
self.end();
|
|
5904
|
+
}
|
|
5905
|
+
}
|
|
5906
|
+
if (typeof boundary !== "string") throw new Error("Multipart: Boundary not found");
|
|
5907
|
+
const fieldSizeLimit = getLimit(limits, "fieldSize", 1 * 1024 * 1024);
|
|
5908
|
+
const fileSizeLimit = getLimit(limits, "fileSize", Infinity);
|
|
5909
|
+
const filesLimit = getLimit(limits, "files", Infinity);
|
|
5910
|
+
const fieldsLimit = getLimit(limits, "fields", Infinity);
|
|
5911
|
+
const partsLimit = getLimit(limits, "parts", Infinity);
|
|
5912
|
+
const headerPairsLimit = getLimit(limits, "headerPairs", 2e3);
|
|
5913
|
+
const headerSizeLimit = getLimit(limits, "headerSize", 80 * 1024);
|
|
5914
|
+
let nfiles = 0;
|
|
5915
|
+
let nfields = 0;
|
|
5916
|
+
let nends = 0;
|
|
5917
|
+
let curFile;
|
|
5918
|
+
let curField;
|
|
5919
|
+
let finished = false;
|
|
5920
|
+
this._needDrain = false;
|
|
5921
|
+
this._pause = false;
|
|
5922
|
+
this._cb = void 0;
|
|
5923
|
+
this._nparts = 0;
|
|
5924
|
+
this._boy = boy;
|
|
5925
|
+
this.parser = new Dicer({
|
|
5926
|
+
boundary,
|
|
5927
|
+
maxHeaderPairs: headerPairsLimit,
|
|
5928
|
+
maxHeaderSize: headerSizeLimit,
|
|
5929
|
+
partHwm: fileOpts.highWaterMark,
|
|
5930
|
+
highWaterMark: cfg.highWaterMark
|
|
5931
|
+
});
|
|
5932
|
+
this.parser.on("drain", function() {
|
|
5933
|
+
self._needDrain = false;
|
|
5934
|
+
if (self._cb && !self._pause) {
|
|
5935
|
+
const cb = self._cb;
|
|
5936
|
+
self._cb = void 0;
|
|
5937
|
+
cb();
|
|
5938
|
+
}
|
|
5939
|
+
}).on("part", function onPart(part) {
|
|
5940
|
+
if (++self._nparts > partsLimit) {
|
|
5941
|
+
self.parser.removeListener("part", onPart);
|
|
5942
|
+
self.parser.on("part", skipPart);
|
|
5943
|
+
boy.hitPartsLimit = true;
|
|
5944
|
+
boy.emit("partsLimit");
|
|
5945
|
+
return skipPart(part);
|
|
5946
|
+
}
|
|
5947
|
+
if (curField) {
|
|
5948
|
+
const field = curField;
|
|
5949
|
+
field.emit("end");
|
|
5950
|
+
field.removeAllListeners("end");
|
|
5951
|
+
}
|
|
5952
|
+
part.on("header", function(header) {
|
|
5953
|
+
let contype;
|
|
5954
|
+
let fieldname;
|
|
5955
|
+
let parsed;
|
|
5956
|
+
let charset;
|
|
5957
|
+
let encoding;
|
|
5958
|
+
let filename;
|
|
5959
|
+
let nsize = 0;
|
|
5960
|
+
if (header["content-type"]) {
|
|
5961
|
+
parsed = parseParams(header["content-type"][0]);
|
|
5962
|
+
if (parsed[0]) {
|
|
5963
|
+
contype = parsed[0].toLowerCase();
|
|
5964
|
+
for (i = 0, len = parsed.length; i < len; ++i) if (RE_CHARSET.test(parsed[i][0])) {
|
|
5965
|
+
charset = parsed[i][1].toLowerCase();
|
|
5966
|
+
break;
|
|
5967
|
+
}
|
|
5968
|
+
}
|
|
5969
|
+
}
|
|
5970
|
+
if (contype === void 0) contype = "text/plain";
|
|
5971
|
+
if (charset === void 0) charset = defCharset;
|
|
5972
|
+
if (header["content-disposition"]) {
|
|
5973
|
+
parsed = parseParams(header["content-disposition"][0]);
|
|
5974
|
+
if (!RE_FIELD.test(parsed[0])) return skipPart(part);
|
|
5975
|
+
for (i = 0, len = parsed.length; i < len; ++i) if (RE_NAME.test(parsed[i][0])) fieldname = parsed[i][1];
|
|
5976
|
+
else if (RE_FILENAME.test(parsed[i][0])) {
|
|
5977
|
+
filename = parsed[i][1];
|
|
5978
|
+
if (!preservePath) filename = basename(filename);
|
|
5979
|
+
}
|
|
5980
|
+
} else return skipPart(part);
|
|
5981
|
+
if (header["content-transfer-encoding"]) encoding = header["content-transfer-encoding"][0].toLowerCase();
|
|
5982
|
+
else encoding = "7bit";
|
|
5983
|
+
let onData, onEnd;
|
|
5984
|
+
if (isPartAFile(fieldname, contype, filename)) {
|
|
5985
|
+
if (nfiles === filesLimit) {
|
|
5986
|
+
if (!boy.hitFilesLimit) {
|
|
5987
|
+
boy.hitFilesLimit = true;
|
|
5988
|
+
boy.emit("filesLimit");
|
|
5989
|
+
}
|
|
5990
|
+
return skipPart(part);
|
|
5991
|
+
}
|
|
5992
|
+
++nfiles;
|
|
5993
|
+
if (boy.listenerCount("file") === 0) {
|
|
5994
|
+
self.parser._ignore();
|
|
5995
|
+
return;
|
|
5996
|
+
}
|
|
5997
|
+
++nends;
|
|
5998
|
+
const file = new FileStream(fileOpts);
|
|
5999
|
+
curFile = file;
|
|
6000
|
+
file.on("end", function() {
|
|
6001
|
+
--nends;
|
|
6002
|
+
self._pause = false;
|
|
6003
|
+
checkFinished();
|
|
6004
|
+
if (self._cb && !self._needDrain) {
|
|
6005
|
+
const cb = self._cb;
|
|
6006
|
+
self._cb = void 0;
|
|
6007
|
+
cb();
|
|
6008
|
+
}
|
|
6009
|
+
});
|
|
6010
|
+
file._read = function(n) {
|
|
6011
|
+
if (!self._pause) return;
|
|
6012
|
+
self._pause = false;
|
|
6013
|
+
if (self._cb && !self._needDrain) {
|
|
6014
|
+
const cb = self._cb;
|
|
6015
|
+
self._cb = void 0;
|
|
6016
|
+
cb();
|
|
6017
|
+
}
|
|
6018
|
+
};
|
|
6019
|
+
boy.emit("file", fieldname, file, filename, encoding, contype);
|
|
6020
|
+
onData = function(data) {
|
|
6021
|
+
if ((nsize += data.length) > fileSizeLimit) {
|
|
6022
|
+
const extralen = fileSizeLimit - nsize + data.length;
|
|
6023
|
+
if (extralen > 0) file.push(data.slice(0, extralen));
|
|
6024
|
+
file.truncated = true;
|
|
6025
|
+
file.bytesRead = fileSizeLimit;
|
|
6026
|
+
part.removeAllListeners("data");
|
|
6027
|
+
file.emit("limit");
|
|
6028
|
+
return;
|
|
6029
|
+
} else if (!file.push(data)) self._pause = true;
|
|
6030
|
+
file.bytesRead = nsize;
|
|
6031
|
+
};
|
|
6032
|
+
onEnd = function() {
|
|
6033
|
+
curFile = void 0;
|
|
6034
|
+
file.push(null);
|
|
6035
|
+
};
|
|
6036
|
+
} else {
|
|
6037
|
+
if (nfields === fieldsLimit) {
|
|
6038
|
+
if (!boy.hitFieldsLimit) {
|
|
6039
|
+
boy.hitFieldsLimit = true;
|
|
6040
|
+
boy.emit("fieldsLimit");
|
|
6041
|
+
}
|
|
6042
|
+
return skipPart(part);
|
|
6043
|
+
}
|
|
6044
|
+
++nfields;
|
|
6045
|
+
++nends;
|
|
6046
|
+
let buffer = "";
|
|
6047
|
+
let truncated = false;
|
|
6048
|
+
curField = part;
|
|
6049
|
+
onData = function(data) {
|
|
6050
|
+
if ((nsize += data.length) > fieldSizeLimit) {
|
|
6051
|
+
const extralen = fieldSizeLimit - (nsize - data.length);
|
|
6052
|
+
buffer += data.toString("binary", 0, extralen);
|
|
6053
|
+
truncated = true;
|
|
6054
|
+
part.removeAllListeners("data");
|
|
6055
|
+
} else buffer += data.toString("binary");
|
|
6056
|
+
};
|
|
6057
|
+
onEnd = function() {
|
|
6058
|
+
curField = void 0;
|
|
6059
|
+
if (buffer.length) buffer = decodeText(buffer, "binary", charset);
|
|
6060
|
+
boy.emit("field", fieldname, buffer, false, truncated, encoding, contype);
|
|
6061
|
+
--nends;
|
|
6062
|
+
checkFinished();
|
|
6063
|
+
};
|
|
6064
|
+
}
|
|
6065
|
+
part._readableState.sync = false;
|
|
6066
|
+
part.on("data", onData);
|
|
6067
|
+
part.on("end", onEnd);
|
|
6068
|
+
}).on("error", function(err) {
|
|
6069
|
+
if (curFile) curFile.emit("error", err);
|
|
6070
|
+
});
|
|
6071
|
+
}).on("error", function(err) {
|
|
6072
|
+
boy.emit("error", err);
|
|
6073
|
+
}).on("finish", function() {
|
|
6074
|
+
finished = true;
|
|
6075
|
+
checkFinished();
|
|
6076
|
+
});
|
|
6077
|
+
}
|
|
6078
|
+
Multipart.prototype.write = function(chunk, cb) {
|
|
6079
|
+
const r = this.parser.write(chunk);
|
|
6080
|
+
if (r && !this._pause) cb();
|
|
6081
|
+
else {
|
|
6082
|
+
this._needDrain = !r;
|
|
6083
|
+
this._cb = cb;
|
|
6084
|
+
}
|
|
6085
|
+
};
|
|
6086
|
+
Multipart.prototype.end = function() {
|
|
6087
|
+
const self = this;
|
|
6088
|
+
if (self.parser.writable) self.parser.end();
|
|
6089
|
+
else if (!self._boy._done) process.nextTick(function() {
|
|
6090
|
+
self._boy._done = true;
|
|
6091
|
+
self._boy.emit("finish");
|
|
6092
|
+
});
|
|
6093
|
+
};
|
|
6094
|
+
function skipPart(part) {
|
|
6095
|
+
part.resume();
|
|
6096
|
+
}
|
|
6097
|
+
function FileStream(opts) {
|
|
6098
|
+
Readable$1.call(this, opts);
|
|
6099
|
+
this.bytesRead = 0;
|
|
6100
|
+
this.truncated = false;
|
|
6101
|
+
}
|
|
6102
|
+
inherits$1(FileStream, Readable$1);
|
|
6103
|
+
FileStream.prototype._read = function(n) {};
|
|
6104
|
+
module.exports = Multipart;
|
|
6105
|
+
}));
|
|
6106
|
+
//#endregion
|
|
6107
|
+
//#region ../../node_modules/.pnpm/@fastify+busboy@3.2.0/node_modules/@fastify/busboy/lib/utils/Decoder.js
|
|
6108
|
+
var require_Decoder = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
6109
|
+
const RE_PLUS = /\+/g;
|
|
6110
|
+
const HEX = [
|
|
6111
|
+
0,
|
|
6112
|
+
0,
|
|
6113
|
+
0,
|
|
6114
|
+
0,
|
|
6115
|
+
0,
|
|
6116
|
+
0,
|
|
6117
|
+
0,
|
|
6118
|
+
0,
|
|
6119
|
+
0,
|
|
6120
|
+
0,
|
|
6121
|
+
0,
|
|
6122
|
+
0,
|
|
6123
|
+
0,
|
|
6124
|
+
0,
|
|
6125
|
+
0,
|
|
6126
|
+
0,
|
|
6127
|
+
0,
|
|
6128
|
+
0,
|
|
6129
|
+
0,
|
|
6130
|
+
0,
|
|
6131
|
+
0,
|
|
6132
|
+
0,
|
|
6133
|
+
0,
|
|
6134
|
+
0,
|
|
6135
|
+
0,
|
|
6136
|
+
0,
|
|
6137
|
+
0,
|
|
6138
|
+
0,
|
|
6139
|
+
0,
|
|
6140
|
+
0,
|
|
6141
|
+
0,
|
|
6142
|
+
0,
|
|
6143
|
+
0,
|
|
6144
|
+
0,
|
|
6145
|
+
0,
|
|
6146
|
+
0,
|
|
6147
|
+
0,
|
|
6148
|
+
0,
|
|
6149
|
+
0,
|
|
6150
|
+
0,
|
|
6151
|
+
0,
|
|
6152
|
+
0,
|
|
6153
|
+
0,
|
|
6154
|
+
0,
|
|
6155
|
+
0,
|
|
6156
|
+
0,
|
|
6157
|
+
0,
|
|
6158
|
+
0,
|
|
6159
|
+
1,
|
|
6160
|
+
1,
|
|
6161
|
+
1,
|
|
6162
|
+
1,
|
|
6163
|
+
1,
|
|
6164
|
+
1,
|
|
6165
|
+
1,
|
|
6166
|
+
1,
|
|
6167
|
+
1,
|
|
6168
|
+
1,
|
|
6169
|
+
0,
|
|
6170
|
+
0,
|
|
6171
|
+
0,
|
|
6172
|
+
0,
|
|
6173
|
+
0,
|
|
6174
|
+
0,
|
|
6175
|
+
0,
|
|
6176
|
+
1,
|
|
6177
|
+
1,
|
|
6178
|
+
1,
|
|
6179
|
+
1,
|
|
6180
|
+
1,
|
|
6181
|
+
1,
|
|
6182
|
+
0,
|
|
6183
|
+
0,
|
|
6184
|
+
0,
|
|
6185
|
+
0,
|
|
6186
|
+
0,
|
|
6187
|
+
0,
|
|
6188
|
+
0,
|
|
6189
|
+
0,
|
|
6190
|
+
0,
|
|
6191
|
+
0,
|
|
6192
|
+
0,
|
|
6193
|
+
0,
|
|
6194
|
+
0,
|
|
6195
|
+
0,
|
|
6196
|
+
0,
|
|
6197
|
+
0,
|
|
6198
|
+
0,
|
|
6199
|
+
0,
|
|
6200
|
+
0,
|
|
6201
|
+
0,
|
|
6202
|
+
0,
|
|
6203
|
+
0,
|
|
6204
|
+
0,
|
|
6205
|
+
0,
|
|
6206
|
+
0,
|
|
6207
|
+
0,
|
|
6208
|
+
1,
|
|
6209
|
+
1,
|
|
6210
|
+
1,
|
|
6211
|
+
1,
|
|
6212
|
+
1,
|
|
6213
|
+
1,
|
|
6214
|
+
0,
|
|
6215
|
+
0,
|
|
6216
|
+
0,
|
|
6217
|
+
0,
|
|
6218
|
+
0,
|
|
6219
|
+
0,
|
|
6220
|
+
0,
|
|
6221
|
+
0,
|
|
6222
|
+
0,
|
|
6223
|
+
0,
|
|
6224
|
+
0,
|
|
6225
|
+
0,
|
|
6226
|
+
0,
|
|
6227
|
+
0,
|
|
6228
|
+
0,
|
|
6229
|
+
0,
|
|
6230
|
+
0,
|
|
6231
|
+
0,
|
|
6232
|
+
0,
|
|
6233
|
+
0,
|
|
6234
|
+
0,
|
|
6235
|
+
0,
|
|
6236
|
+
0,
|
|
6237
|
+
0,
|
|
6238
|
+
0
|
|
6239
|
+
];
|
|
6240
|
+
function Decoder() {
|
|
6241
|
+
this.buffer = void 0;
|
|
6242
|
+
}
|
|
6243
|
+
Decoder.prototype.write = function(str) {
|
|
6244
|
+
str = str.replace(RE_PLUS, " ");
|
|
6245
|
+
let res = "";
|
|
6246
|
+
let i = 0;
|
|
6247
|
+
let p = 0;
|
|
6248
|
+
const len = str.length;
|
|
6249
|
+
for (; i < len; ++i) if (this.buffer !== void 0) if (!HEX[str.charCodeAt(i)]) {
|
|
6250
|
+
res += "%" + this.buffer;
|
|
6251
|
+
this.buffer = void 0;
|
|
6252
|
+
--i;
|
|
6253
|
+
} else {
|
|
6254
|
+
this.buffer += str[i];
|
|
6255
|
+
++p;
|
|
6256
|
+
if (this.buffer.length === 2) {
|
|
6257
|
+
res += String.fromCharCode(parseInt(this.buffer, 16));
|
|
6258
|
+
this.buffer = void 0;
|
|
6259
|
+
}
|
|
6260
|
+
}
|
|
6261
|
+
else if (str[i] === "%") {
|
|
6262
|
+
if (i > p) {
|
|
6263
|
+
res += str.substring(p, i);
|
|
6264
|
+
p = i;
|
|
6265
|
+
}
|
|
6266
|
+
this.buffer = "";
|
|
6267
|
+
++p;
|
|
6268
|
+
}
|
|
6269
|
+
if (p < len && this.buffer === void 0) res += str.substring(p);
|
|
6270
|
+
return res;
|
|
6271
|
+
};
|
|
6272
|
+
Decoder.prototype.reset = function() {
|
|
6273
|
+
this.buffer = void 0;
|
|
6274
|
+
};
|
|
6275
|
+
module.exports = Decoder;
|
|
6276
|
+
}));
|
|
6277
|
+
//#endregion
|
|
6278
|
+
//#region ../../node_modules/.pnpm/@fastify+busboy@3.2.0/node_modules/@fastify/busboy/lib/types/urlencoded.js
|
|
6279
|
+
var require_urlencoded = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
6280
|
+
const Decoder = require_Decoder();
|
|
6281
|
+
const decodeText = require_decodeText();
|
|
6282
|
+
const getLimit = require_getLimit();
|
|
6283
|
+
const RE_CHARSET = /^charset$/i;
|
|
6284
|
+
UrlEncoded.detect = /^application\/x-www-form-urlencoded/i;
|
|
6285
|
+
function UrlEncoded(boy, cfg) {
|
|
6286
|
+
const limits = cfg.limits;
|
|
6287
|
+
const parsedConType = cfg.parsedConType;
|
|
6288
|
+
this.boy = boy;
|
|
6289
|
+
this.fieldSizeLimit = getLimit(limits, "fieldSize", 1 * 1024 * 1024);
|
|
6290
|
+
this.fieldNameSizeLimit = getLimit(limits, "fieldNameSize", 100);
|
|
6291
|
+
this.fieldsLimit = getLimit(limits, "fields", Infinity);
|
|
6292
|
+
let charset;
|
|
6293
|
+
for (var i = 0, len = parsedConType.length; i < len; ++i) if (Array.isArray(parsedConType[i]) && RE_CHARSET.test(parsedConType[i][0])) {
|
|
6294
|
+
charset = parsedConType[i][1].toLowerCase();
|
|
6295
|
+
break;
|
|
6296
|
+
}
|
|
6297
|
+
if (charset === void 0) charset = cfg.defCharset || "utf8";
|
|
6298
|
+
this.decoder = new Decoder();
|
|
6299
|
+
this.charset = charset;
|
|
6300
|
+
this._fields = 0;
|
|
6301
|
+
this._state = "key";
|
|
6302
|
+
this._checkingBytes = true;
|
|
6303
|
+
this._bytesKey = 0;
|
|
6304
|
+
this._bytesVal = 0;
|
|
6305
|
+
this._key = "";
|
|
6306
|
+
this._val = "";
|
|
6307
|
+
this._keyTrunc = false;
|
|
6308
|
+
this._valTrunc = false;
|
|
6309
|
+
this._hitLimit = false;
|
|
6310
|
+
}
|
|
6311
|
+
UrlEncoded.prototype.write = function(data, cb) {
|
|
6312
|
+
if (this._fields === this.fieldsLimit) {
|
|
6313
|
+
if (!this.boy.hitFieldsLimit) {
|
|
6314
|
+
this.boy.hitFieldsLimit = true;
|
|
6315
|
+
this.boy.emit("fieldsLimit");
|
|
6316
|
+
}
|
|
6317
|
+
return cb();
|
|
6318
|
+
}
|
|
6319
|
+
let idxeq;
|
|
6320
|
+
let idxamp;
|
|
6321
|
+
let i;
|
|
6322
|
+
let p = 0;
|
|
6323
|
+
const len = data.length;
|
|
6324
|
+
while (p < len) if (this._state === "key") {
|
|
6325
|
+
idxeq = idxamp = void 0;
|
|
6326
|
+
for (i = p; i < len; ++i) {
|
|
6327
|
+
if (!this._checkingBytes) ++p;
|
|
6328
|
+
if (data[i] === 61) {
|
|
6329
|
+
idxeq = i;
|
|
6330
|
+
break;
|
|
6331
|
+
} else if (data[i] === 38) {
|
|
6332
|
+
idxamp = i;
|
|
6333
|
+
break;
|
|
6334
|
+
}
|
|
6335
|
+
if (this._checkingBytes && this._bytesKey === this.fieldNameSizeLimit) {
|
|
6336
|
+
this._hitLimit = true;
|
|
6337
|
+
break;
|
|
6338
|
+
} else if (this._checkingBytes) ++this._bytesKey;
|
|
6339
|
+
}
|
|
6340
|
+
if (idxeq !== void 0) {
|
|
6341
|
+
if (idxeq > p) this._key += this.decoder.write(data.toString("binary", p, idxeq));
|
|
6342
|
+
this._state = "val";
|
|
6343
|
+
this._hitLimit = false;
|
|
6344
|
+
this._checkingBytes = true;
|
|
6345
|
+
this._val = "";
|
|
6346
|
+
this._bytesVal = 0;
|
|
6347
|
+
this._valTrunc = false;
|
|
6348
|
+
this.decoder.reset();
|
|
6349
|
+
p = idxeq + 1;
|
|
6350
|
+
} else if (idxamp !== void 0) {
|
|
6351
|
+
++this._fields;
|
|
6352
|
+
let key;
|
|
6353
|
+
const keyTrunc = this._keyTrunc;
|
|
6354
|
+
if (idxamp > p) key = this._key += this.decoder.write(data.toString("binary", p, idxamp));
|
|
6355
|
+
else key = this._key;
|
|
6356
|
+
this._hitLimit = false;
|
|
6357
|
+
this._checkingBytes = true;
|
|
6358
|
+
this._key = "";
|
|
6359
|
+
this._bytesKey = 0;
|
|
6360
|
+
this._keyTrunc = false;
|
|
6361
|
+
this.decoder.reset();
|
|
6362
|
+
if (key.length) this.boy.emit("field", decodeText(key, "binary", this.charset), "", keyTrunc, false);
|
|
6363
|
+
p = idxamp + 1;
|
|
6364
|
+
if (this._fields === this.fieldsLimit) return cb();
|
|
6365
|
+
} else if (this._hitLimit) {
|
|
6366
|
+
if (i > p) this._key += this.decoder.write(data.toString("binary", p, i));
|
|
6367
|
+
p = i;
|
|
6368
|
+
if ((this._bytesKey = this._key.length) === this.fieldNameSizeLimit) {
|
|
6369
|
+
this._checkingBytes = false;
|
|
6370
|
+
this._keyTrunc = true;
|
|
6371
|
+
}
|
|
6372
|
+
} else {
|
|
6373
|
+
if (p < len) this._key += this.decoder.write(data.toString("binary", p));
|
|
6374
|
+
p = len;
|
|
6375
|
+
}
|
|
6376
|
+
} else {
|
|
6377
|
+
idxamp = void 0;
|
|
6378
|
+
for (i = p; i < len; ++i) {
|
|
6379
|
+
if (!this._checkingBytes) ++p;
|
|
6380
|
+
if (data[i] === 38) {
|
|
6381
|
+
idxamp = i;
|
|
6382
|
+
break;
|
|
6383
|
+
}
|
|
6384
|
+
if (this._checkingBytes && this._bytesVal === this.fieldSizeLimit) {
|
|
6385
|
+
this._hitLimit = true;
|
|
6386
|
+
break;
|
|
6387
|
+
} else if (this._checkingBytes) ++this._bytesVal;
|
|
6388
|
+
}
|
|
6389
|
+
if (idxamp !== void 0) {
|
|
6390
|
+
++this._fields;
|
|
6391
|
+
if (idxamp > p) this._val += this.decoder.write(data.toString("binary", p, idxamp));
|
|
6392
|
+
this.boy.emit("field", decodeText(this._key, "binary", this.charset), decodeText(this._val, "binary", this.charset), this._keyTrunc, this._valTrunc);
|
|
6393
|
+
this._state = "key";
|
|
6394
|
+
this._hitLimit = false;
|
|
6395
|
+
this._checkingBytes = true;
|
|
6396
|
+
this._key = "";
|
|
6397
|
+
this._bytesKey = 0;
|
|
6398
|
+
this._keyTrunc = false;
|
|
6399
|
+
this.decoder.reset();
|
|
6400
|
+
p = idxamp + 1;
|
|
6401
|
+
if (this._fields === this.fieldsLimit) return cb();
|
|
6402
|
+
} else if (this._hitLimit) {
|
|
6403
|
+
if (i > p) this._val += this.decoder.write(data.toString("binary", p, i));
|
|
6404
|
+
p = i;
|
|
6405
|
+
if (this._val === "" && this.fieldSizeLimit === 0 || (this._bytesVal = this._val.length) === this.fieldSizeLimit) {
|
|
6406
|
+
this._checkingBytes = false;
|
|
6407
|
+
this._valTrunc = true;
|
|
6408
|
+
}
|
|
6409
|
+
} else {
|
|
6410
|
+
if (p < len) this._val += this.decoder.write(data.toString("binary", p));
|
|
6411
|
+
p = len;
|
|
6412
|
+
}
|
|
6413
|
+
}
|
|
6414
|
+
cb();
|
|
6415
|
+
};
|
|
6416
|
+
UrlEncoded.prototype.end = function() {
|
|
6417
|
+
if (this.boy._done) return;
|
|
6418
|
+
if (this._state === "key" && this._key.length > 0) this.boy.emit("field", decodeText(this._key, "binary", this.charset), "", this._keyTrunc, false);
|
|
6419
|
+
else if (this._state === "val") this.boy.emit("field", decodeText(this._key, "binary", this.charset), decodeText(this._val, "binary", this.charset), this._keyTrunc, this._valTrunc);
|
|
6420
|
+
this.boy._done = true;
|
|
6421
|
+
this.boy.emit("finish");
|
|
6422
|
+
};
|
|
6423
|
+
module.exports = UrlEncoded;
|
|
6424
|
+
}));
|
|
6425
|
+
//#endregion
|
|
6426
|
+
//#region ../../node_modules/.pnpm/@fastify+busboy@3.2.0/node_modules/@fastify/busboy/lib/main.js
|
|
6427
|
+
var require_main = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
6428
|
+
const WritableStream = __require("node:stream").Writable;
|
|
6429
|
+
const { inherits } = __require("node:util");
|
|
6430
|
+
const Dicer = require_Dicer();
|
|
6431
|
+
const MultipartParser = require_multipart$1();
|
|
6432
|
+
const UrlencodedParser = require_urlencoded();
|
|
6433
|
+
const parseParams = require_parseParams();
|
|
6434
|
+
function Busboy(opts) {
|
|
6435
|
+
if (!(this instanceof Busboy)) return new Busboy(opts);
|
|
6436
|
+
if (typeof opts !== "object") throw new TypeError("Busboy expected an options-Object.");
|
|
6437
|
+
if (typeof opts.headers !== "object") throw new TypeError("Busboy expected an options-Object with headers-attribute.");
|
|
6438
|
+
if (typeof opts.headers["content-type"] !== "string") throw new TypeError("Missing Content-Type-header.");
|
|
6439
|
+
const { headers, ...streamOptions } = opts;
|
|
6440
|
+
this.opts = {
|
|
6441
|
+
autoDestroy: false,
|
|
6442
|
+
...streamOptions
|
|
6443
|
+
};
|
|
6444
|
+
WritableStream.call(this, this.opts);
|
|
6445
|
+
this._done = false;
|
|
6446
|
+
this._parser = this.getParserByHeaders(headers);
|
|
6447
|
+
this._finished = false;
|
|
6448
|
+
}
|
|
6449
|
+
inherits(Busboy, WritableStream);
|
|
6450
|
+
Busboy.prototype.emit = function(ev) {
|
|
6451
|
+
if (ev === "finish") {
|
|
6452
|
+
if (!this._done) {
|
|
6453
|
+
this._parser?.end();
|
|
6454
|
+
return;
|
|
6455
|
+
} else if (this._finished) return;
|
|
6456
|
+
this._finished = true;
|
|
6457
|
+
}
|
|
6458
|
+
WritableStream.prototype.emit.apply(this, arguments);
|
|
6459
|
+
};
|
|
6460
|
+
Busboy.prototype.getParserByHeaders = function(headers) {
|
|
6461
|
+
const parsed = parseParams(headers["content-type"]);
|
|
6462
|
+
const cfg = {
|
|
6463
|
+
defCharset: this.opts.defCharset,
|
|
6464
|
+
fileHwm: this.opts.fileHwm,
|
|
6465
|
+
headers,
|
|
6466
|
+
highWaterMark: this.opts.highWaterMark,
|
|
6467
|
+
isPartAFile: this.opts.isPartAFile,
|
|
6468
|
+
limits: this.opts.limits,
|
|
6469
|
+
parsedConType: parsed,
|
|
6470
|
+
preservePath: this.opts.preservePath
|
|
6471
|
+
};
|
|
6472
|
+
if (MultipartParser.detect.test(parsed[0])) return new MultipartParser(this, cfg);
|
|
6473
|
+
if (UrlencodedParser.detect.test(parsed[0])) return new UrlencodedParser(this, cfg);
|
|
6474
|
+
throw new Error("Unsupported Content-Type.");
|
|
6475
|
+
};
|
|
6476
|
+
Busboy.prototype._write = function(chunk, encoding, cb) {
|
|
6477
|
+
this._parser.write(chunk, cb);
|
|
6478
|
+
};
|
|
6479
|
+
module.exports = Busboy;
|
|
6480
|
+
module.exports.default = Busboy;
|
|
6481
|
+
module.exports.Busboy = Busboy;
|
|
6482
|
+
module.exports.Dicer = Dicer;
|
|
6483
|
+
}));
|
|
6484
|
+
//#endregion
|
|
6485
|
+
//#region ../../node_modules/.pnpm/fastify-plugin@5.1.0/node_modules/fastify-plugin/lib/getPluginName.js
|
|
6486
|
+
var require_getPluginName = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
6487
|
+
const fpStackTracePattern = /at\s(?:.*\.)?plugin\s.*\n\s*(.*)/;
|
|
6488
|
+
const fileNamePattern = /(\w*(\.\w*)*)\..*/;
|
|
6489
|
+
module.exports = function getPluginName(fn) {
|
|
6490
|
+
if (fn.name.length > 0) return fn.name;
|
|
6491
|
+
const stackTraceLimit = Error.stackTraceLimit;
|
|
6492
|
+
Error.stackTraceLimit = 10;
|
|
6493
|
+
try {
|
|
6494
|
+
throw new Error("anonymous function");
|
|
6495
|
+
} catch (e) {
|
|
6496
|
+
Error.stackTraceLimit = stackTraceLimit;
|
|
6497
|
+
return extractPluginName(e.stack);
|
|
6498
|
+
}
|
|
6499
|
+
};
|
|
6500
|
+
function extractPluginName(stack) {
|
|
6501
|
+
const m = stack.match(fpStackTracePattern);
|
|
6502
|
+
return m ? m[1].split(/[/\\]/).slice(-1)[0].match(fileNamePattern)[1] : "anonymous";
|
|
6503
|
+
}
|
|
6504
|
+
module.exports.extractPluginName = extractPluginName;
|
|
6505
|
+
}));
|
|
6506
|
+
//#endregion
|
|
6507
|
+
//#region ../../node_modules/.pnpm/fastify-plugin@5.1.0/node_modules/fastify-plugin/lib/toCamelCase.js
|
|
6508
|
+
var require_toCamelCase = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
6509
|
+
module.exports = function toCamelCase(name) {
|
|
6510
|
+
if (name[0] === "@") name = name.slice(1).replace("/", "-");
|
|
6511
|
+
return name.replace(/-(.)/g, function(match, g1) {
|
|
6512
|
+
return g1.toUpperCase();
|
|
6513
|
+
});
|
|
6514
|
+
};
|
|
6515
|
+
}));
|
|
6516
|
+
//#endregion
|
|
6517
|
+
//#region ../../node_modules/.pnpm/fastify-plugin@5.1.0/node_modules/fastify-plugin/plugin.js
|
|
6518
|
+
var require_plugin = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
6519
|
+
const getPluginName = require_getPluginName();
|
|
6520
|
+
const toCamelCase = require_toCamelCase();
|
|
6521
|
+
let count = 0;
|
|
6522
|
+
function plugin(fn, options = {}) {
|
|
6523
|
+
let autoName = false;
|
|
6524
|
+
if (fn.default !== void 0) fn = fn.default;
|
|
6525
|
+
if (typeof fn !== "function") throw new TypeError(`fastify-plugin expects a function, instead got a '${typeof fn}'`);
|
|
6526
|
+
if (typeof options === "string") options = { fastify: options };
|
|
6527
|
+
if (typeof options !== "object" || Array.isArray(options) || options === null) throw new TypeError("The options object should be an object");
|
|
6528
|
+
if (options.fastify !== void 0 && typeof options.fastify !== "string") throw new TypeError(`fastify-plugin expects a version string, instead got '${typeof options.fastify}'`);
|
|
6529
|
+
if (!options.name) {
|
|
6530
|
+
autoName = true;
|
|
6531
|
+
options.name = getPluginName(fn) + "-auto-" + count++;
|
|
6532
|
+
}
|
|
6533
|
+
fn[Symbol.for("skip-override")] = options.encapsulate !== true;
|
|
6534
|
+
fn[Symbol.for("fastify.display-name")] = options.name;
|
|
6535
|
+
fn[Symbol.for("plugin-meta")] = options;
|
|
6536
|
+
if (!fn.default) fn.default = fn;
|
|
6537
|
+
const camelCase = toCamelCase(options.name);
|
|
6538
|
+
if (!autoName && !fn[camelCase]) fn[camelCase] = fn;
|
|
6539
|
+
return fn;
|
|
6540
|
+
}
|
|
6541
|
+
module.exports = plugin;
|
|
6542
|
+
module.exports.default = plugin;
|
|
6543
|
+
module.exports.fastifyPlugin = plugin;
|
|
6544
|
+
}));
|
|
6545
|
+
//#endregion
|
|
6546
|
+
//#region ../../node_modules/.pnpm/@fastify+multipart@10.0.0/node_modules/@fastify/multipart/lib/generateId.js
|
|
6547
|
+
var require_generateId = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
6548
|
+
const HEX = [
|
|
6549
|
+
"00",
|
|
6550
|
+
"01",
|
|
6551
|
+
"02",
|
|
6552
|
+
"03",
|
|
6553
|
+
"04",
|
|
6554
|
+
"05",
|
|
6555
|
+
"06",
|
|
6556
|
+
"07",
|
|
6557
|
+
"08",
|
|
6558
|
+
"09",
|
|
6559
|
+
"0a",
|
|
6560
|
+
"0b",
|
|
6561
|
+
"0c",
|
|
6562
|
+
"0d",
|
|
6563
|
+
"0e",
|
|
6564
|
+
"0f",
|
|
6565
|
+
"10",
|
|
6566
|
+
"11",
|
|
6567
|
+
"12",
|
|
6568
|
+
"13",
|
|
6569
|
+
"14",
|
|
6570
|
+
"15",
|
|
6571
|
+
"16",
|
|
6572
|
+
"17",
|
|
6573
|
+
"18",
|
|
6574
|
+
"19",
|
|
6575
|
+
"1a",
|
|
6576
|
+
"1b",
|
|
6577
|
+
"1c",
|
|
6578
|
+
"1d",
|
|
6579
|
+
"1e",
|
|
6580
|
+
"1f",
|
|
6581
|
+
"20",
|
|
6582
|
+
"21",
|
|
6583
|
+
"22",
|
|
6584
|
+
"23",
|
|
6585
|
+
"24",
|
|
6586
|
+
"25",
|
|
6587
|
+
"26",
|
|
6588
|
+
"27",
|
|
6589
|
+
"28",
|
|
6590
|
+
"29",
|
|
6591
|
+
"2a",
|
|
6592
|
+
"2b",
|
|
6593
|
+
"2c",
|
|
6594
|
+
"2d",
|
|
6595
|
+
"2e",
|
|
6596
|
+
"2f",
|
|
6597
|
+
"30",
|
|
6598
|
+
"31",
|
|
6599
|
+
"32",
|
|
6600
|
+
"33",
|
|
6601
|
+
"34",
|
|
6602
|
+
"35",
|
|
6603
|
+
"36",
|
|
6604
|
+
"37",
|
|
6605
|
+
"38",
|
|
6606
|
+
"39",
|
|
6607
|
+
"3a",
|
|
6608
|
+
"3b",
|
|
6609
|
+
"3c",
|
|
6610
|
+
"3d",
|
|
6611
|
+
"3e",
|
|
6612
|
+
"3f",
|
|
6613
|
+
"40",
|
|
6614
|
+
"41",
|
|
6615
|
+
"42",
|
|
6616
|
+
"43",
|
|
6617
|
+
"44",
|
|
6618
|
+
"45",
|
|
6619
|
+
"46",
|
|
6620
|
+
"47",
|
|
6621
|
+
"48",
|
|
6622
|
+
"49",
|
|
6623
|
+
"4a",
|
|
6624
|
+
"4b",
|
|
6625
|
+
"4c",
|
|
6626
|
+
"4d",
|
|
6627
|
+
"4e",
|
|
6628
|
+
"4f",
|
|
6629
|
+
"50",
|
|
6630
|
+
"51",
|
|
6631
|
+
"52",
|
|
6632
|
+
"53",
|
|
6633
|
+
"54",
|
|
6634
|
+
"55",
|
|
6635
|
+
"56",
|
|
6636
|
+
"57",
|
|
6637
|
+
"58",
|
|
6638
|
+
"59",
|
|
6639
|
+
"5a",
|
|
6640
|
+
"5b",
|
|
6641
|
+
"5c",
|
|
6642
|
+
"5d",
|
|
6643
|
+
"5e",
|
|
6644
|
+
"5f",
|
|
6645
|
+
"60",
|
|
6646
|
+
"61",
|
|
6647
|
+
"62",
|
|
6648
|
+
"63",
|
|
6649
|
+
"64",
|
|
6650
|
+
"65",
|
|
6651
|
+
"66",
|
|
6652
|
+
"67",
|
|
6653
|
+
"68",
|
|
6654
|
+
"69",
|
|
6655
|
+
"6a",
|
|
6656
|
+
"6b",
|
|
6657
|
+
"6c",
|
|
6658
|
+
"6d",
|
|
6659
|
+
"6e",
|
|
6660
|
+
"6f",
|
|
6661
|
+
"70",
|
|
6662
|
+
"71",
|
|
6663
|
+
"72",
|
|
6664
|
+
"73",
|
|
6665
|
+
"74",
|
|
6666
|
+
"75",
|
|
6667
|
+
"76",
|
|
6668
|
+
"77",
|
|
6669
|
+
"78",
|
|
6670
|
+
"79",
|
|
6671
|
+
"7a",
|
|
6672
|
+
"7b",
|
|
6673
|
+
"7c",
|
|
6674
|
+
"7d",
|
|
6675
|
+
"7e",
|
|
6676
|
+
"7f",
|
|
6677
|
+
"80",
|
|
6678
|
+
"81",
|
|
6679
|
+
"82",
|
|
6680
|
+
"83",
|
|
6681
|
+
"84",
|
|
6682
|
+
"85",
|
|
6683
|
+
"86",
|
|
6684
|
+
"87",
|
|
6685
|
+
"88",
|
|
6686
|
+
"89",
|
|
6687
|
+
"8a",
|
|
6688
|
+
"8b",
|
|
6689
|
+
"8c",
|
|
6690
|
+
"8d",
|
|
6691
|
+
"8e",
|
|
6692
|
+
"8f",
|
|
6693
|
+
"90",
|
|
6694
|
+
"91",
|
|
6695
|
+
"92",
|
|
6696
|
+
"93",
|
|
6697
|
+
"94",
|
|
6698
|
+
"95",
|
|
6699
|
+
"96",
|
|
6700
|
+
"97",
|
|
6701
|
+
"98",
|
|
6702
|
+
"99",
|
|
6703
|
+
"9a",
|
|
6704
|
+
"9b",
|
|
6705
|
+
"9c",
|
|
6706
|
+
"9d",
|
|
6707
|
+
"9e",
|
|
6708
|
+
"9f",
|
|
6709
|
+
"a0",
|
|
6710
|
+
"a1",
|
|
6711
|
+
"a2",
|
|
6712
|
+
"a3",
|
|
6713
|
+
"a4",
|
|
6714
|
+
"a5",
|
|
6715
|
+
"a6",
|
|
6716
|
+
"a7",
|
|
6717
|
+
"a8",
|
|
6718
|
+
"a9",
|
|
6719
|
+
"aa",
|
|
6720
|
+
"ab",
|
|
6721
|
+
"ac",
|
|
6722
|
+
"ad",
|
|
6723
|
+
"ae",
|
|
6724
|
+
"af",
|
|
6725
|
+
"b0",
|
|
6726
|
+
"b1",
|
|
6727
|
+
"b2",
|
|
6728
|
+
"b3",
|
|
6729
|
+
"b4",
|
|
6730
|
+
"b5",
|
|
6731
|
+
"b6",
|
|
6732
|
+
"b7",
|
|
6733
|
+
"b8",
|
|
6734
|
+
"b9",
|
|
6735
|
+
"ba",
|
|
6736
|
+
"bb",
|
|
6737
|
+
"bc",
|
|
6738
|
+
"bd",
|
|
6739
|
+
"be",
|
|
6740
|
+
"bf",
|
|
6741
|
+
"c0",
|
|
6742
|
+
"c1",
|
|
6743
|
+
"c2",
|
|
6744
|
+
"c3",
|
|
6745
|
+
"c4",
|
|
6746
|
+
"c5",
|
|
6747
|
+
"c6",
|
|
6748
|
+
"c7",
|
|
6749
|
+
"c8",
|
|
6750
|
+
"c9",
|
|
6751
|
+
"ca",
|
|
6752
|
+
"cb",
|
|
6753
|
+
"cc",
|
|
6754
|
+
"cd",
|
|
6755
|
+
"ce",
|
|
6756
|
+
"cf",
|
|
6757
|
+
"d0",
|
|
6758
|
+
"d1",
|
|
6759
|
+
"d2",
|
|
6760
|
+
"d3",
|
|
6761
|
+
"d4",
|
|
6762
|
+
"d5",
|
|
6763
|
+
"d6",
|
|
6764
|
+
"d7",
|
|
6765
|
+
"d8",
|
|
6766
|
+
"d9",
|
|
6767
|
+
"da",
|
|
6768
|
+
"db",
|
|
6769
|
+
"dc",
|
|
6770
|
+
"dd",
|
|
6771
|
+
"de",
|
|
6772
|
+
"df",
|
|
6773
|
+
"e0",
|
|
6774
|
+
"e1",
|
|
6775
|
+
"e2",
|
|
6776
|
+
"e3",
|
|
6777
|
+
"e4",
|
|
6778
|
+
"e5",
|
|
6779
|
+
"e6",
|
|
6780
|
+
"e7",
|
|
6781
|
+
"e8",
|
|
6782
|
+
"e9",
|
|
6783
|
+
"ea",
|
|
6784
|
+
"eb",
|
|
6785
|
+
"ec",
|
|
6786
|
+
"ed",
|
|
6787
|
+
"ee",
|
|
6788
|
+
"ef",
|
|
6789
|
+
"f0",
|
|
6790
|
+
"f1",
|
|
6791
|
+
"f2",
|
|
6792
|
+
"f3",
|
|
6793
|
+
"f4",
|
|
6794
|
+
"f5",
|
|
6795
|
+
"f6",
|
|
6796
|
+
"f7",
|
|
6797
|
+
"f8",
|
|
6798
|
+
"f9",
|
|
6799
|
+
"fa",
|
|
6800
|
+
"fb",
|
|
6801
|
+
"fc",
|
|
6802
|
+
"fd",
|
|
6803
|
+
"fe",
|
|
6804
|
+
"ff"
|
|
6805
|
+
];
|
|
6806
|
+
const random = Math.random;
|
|
6807
|
+
function seed() {
|
|
6808
|
+
return HEX[255 * random() | 0] + HEX[255 * random() | 0] + HEX[255 * random() | 0] + HEX[255 * random() | 0] + HEX[255 * random() | 0] + HEX[255 * random() | 0] + HEX[255 * random() | 0];
|
|
6809
|
+
}
|
|
6810
|
+
module.exports.generateId = (function generateIdFn() {
|
|
6811
|
+
let num = 0;
|
|
6812
|
+
let str = seed();
|
|
6813
|
+
return function generateId() {
|
|
6814
|
+
return num === 255 ? (str = seed()) + HEX[num = 0] : str + HEX[++num];
|
|
6815
|
+
};
|
|
6816
|
+
})();
|
|
6817
|
+
}));
|
|
6818
|
+
//#endregion
|
|
6819
|
+
//#region ../../node_modules/.pnpm/@fastify+error@4.2.0/node_modules/@fastify/error/index.js
|
|
6820
|
+
var require_error = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
6821
|
+
const { format } = __require("node:util");
|
|
6822
|
+
function toString() {
|
|
6823
|
+
return `${this.name} [${this.code}]: ${this.message}`;
|
|
6824
|
+
}
|
|
6825
|
+
const FastifyGenericErrorSymbol = Symbol.for("fastify-error-generic");
|
|
6826
|
+
function createError(code, message, statusCode = 500, Base = Error, captureStackTrace = createError.captureStackTrace) {
|
|
6827
|
+
const shouldCreateFastifyGenericError = code === FastifyGenericErrorSymbol;
|
|
6828
|
+
if (shouldCreateFastifyGenericError) code = "FST_ERR";
|
|
6829
|
+
if (!code) throw new Error("Fastify error code must not be empty");
|
|
6830
|
+
if (!message) throw new Error("Fastify error message must not be empty");
|
|
6831
|
+
code = code.toUpperCase();
|
|
6832
|
+
!statusCode && (statusCode = void 0);
|
|
6833
|
+
const FastifySpecificErrorSymbol = Symbol.for(`fastify-error ${code}`);
|
|
6834
|
+
function FastifyError(...args) {
|
|
6835
|
+
if (!new.target) return new FastifyError(...args);
|
|
6836
|
+
this.code = code;
|
|
6837
|
+
this.name = "FastifyError";
|
|
6838
|
+
this.statusCode = statusCode;
|
|
6839
|
+
const lastElement = args.length - 1;
|
|
6840
|
+
if (lastElement !== -1 && args[lastElement] && typeof args[lastElement] === "object" && "cause" in args[lastElement]) this.cause = args.pop().cause;
|
|
6841
|
+
this.message = format(message, ...args);
|
|
6842
|
+
Error.stackTraceLimit && captureStackTrace && Error.captureStackTrace(this, FastifyError);
|
|
6843
|
+
}
|
|
6844
|
+
FastifyError.prototype = Object.create(Base.prototype, {
|
|
6845
|
+
constructor: {
|
|
6846
|
+
value: FastifyError,
|
|
6847
|
+
enumerable: false,
|
|
6848
|
+
writable: true,
|
|
6849
|
+
configurable: true
|
|
6850
|
+
},
|
|
6851
|
+
[FastifyGenericErrorSymbol]: {
|
|
6852
|
+
value: true,
|
|
6853
|
+
enumerable: false,
|
|
6854
|
+
writable: false,
|
|
6855
|
+
configurable: false
|
|
6856
|
+
},
|
|
6857
|
+
[FastifySpecificErrorSymbol]: {
|
|
6858
|
+
value: true,
|
|
6859
|
+
enumerable: false,
|
|
6860
|
+
writable: false,
|
|
6861
|
+
configurable: false
|
|
6862
|
+
}
|
|
6863
|
+
});
|
|
6864
|
+
if (shouldCreateFastifyGenericError) Object.defineProperty(FastifyError, Symbol.hasInstance, {
|
|
6865
|
+
value(instance) {
|
|
6866
|
+
return instance && instance[FastifyGenericErrorSymbol];
|
|
6867
|
+
},
|
|
6868
|
+
configurable: false,
|
|
6869
|
+
writable: false,
|
|
6870
|
+
enumerable: false
|
|
6871
|
+
});
|
|
6872
|
+
else Object.defineProperty(FastifyError, Symbol.hasInstance, {
|
|
6873
|
+
value(instance) {
|
|
6874
|
+
return instance && instance[FastifySpecificErrorSymbol];
|
|
6875
|
+
},
|
|
6876
|
+
configurable: false,
|
|
6877
|
+
writable: false,
|
|
6878
|
+
enumerable: false
|
|
6879
|
+
});
|
|
6880
|
+
FastifyError.prototype[Symbol.toStringTag] = "Error";
|
|
6881
|
+
FastifyError.prototype.toString = toString;
|
|
6882
|
+
return FastifyError;
|
|
6883
|
+
}
|
|
6884
|
+
createError.captureStackTrace = true;
|
|
6885
|
+
const FastifyErrorConstructor = createError(FastifyGenericErrorSymbol, "Fastify Error", 500, Error);
|
|
6886
|
+
module.exports = createError;
|
|
6887
|
+
module.exports.FastifyError = FastifyErrorConstructor;
|
|
6888
|
+
module.exports.default = createError;
|
|
6889
|
+
module.exports.createError = createError;
|
|
6890
|
+
}));
|
|
6891
|
+
//#endregion
|
|
6892
|
+
//#region ../../node_modules/.pnpm/@fastify+multipart@10.0.0/node_modules/@fastify/multipart/lib/stream-consumer.js
|
|
6893
|
+
var require_stream_consumer = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
6894
|
+
module.exports = function streamToNull(stream) {
|
|
6895
|
+
return new Promise((resolve, reject) => {
|
|
6896
|
+
stream.on("data", () => {});
|
|
6897
|
+
stream.on("close", () => {
|
|
6898
|
+
resolve();
|
|
6899
|
+
});
|
|
6900
|
+
stream.on("end", () => {
|
|
6901
|
+
resolve();
|
|
6902
|
+
});
|
|
6903
|
+
stream.on("error", (error) => {
|
|
6904
|
+
reject(error);
|
|
6905
|
+
});
|
|
6906
|
+
});
|
|
6907
|
+
};
|
|
6908
|
+
}));
|
|
6909
|
+
//#endregion
|
|
6910
|
+
//#region ../../node_modules/.pnpm/@fastify+deepmerge@3.2.1/node_modules/@fastify/deepmerge/index.js
|
|
6911
|
+
var require_deepmerge = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
6912
|
+
const JSON_PROTO = Object.getPrototypeOf({});
|
|
6913
|
+
function defaultIsMergeableObjectFactory() {
|
|
6914
|
+
return function defaultIsMergeableObject(value) {
|
|
6915
|
+
return typeof value === "object" && value !== null && !(value instanceof RegExp) && !(value instanceof Date);
|
|
6916
|
+
};
|
|
6917
|
+
}
|
|
6918
|
+
function deepmergeConstructor(options) {
|
|
6919
|
+
function isNotPrototypeKey(value) {
|
|
6920
|
+
return value !== "constructor" && value !== "prototype" && value !== "__proto__";
|
|
6921
|
+
}
|
|
6922
|
+
function cloneArray(value) {
|
|
6923
|
+
let i = 0;
|
|
6924
|
+
const il = value.length;
|
|
6925
|
+
const result = new Array(il);
|
|
6926
|
+
for (; i < il; ++i) result[i] = clone(value[i]);
|
|
6927
|
+
return result;
|
|
6928
|
+
}
|
|
6929
|
+
function cloneObject(target) {
|
|
6930
|
+
const result = {};
|
|
6931
|
+
if (cloneProtoObject && Object.getPrototypeOf(target) !== JSON_PROTO) return cloneProtoObject(target);
|
|
6932
|
+
const targetKeys = getKeys(target);
|
|
6933
|
+
let i, il, key;
|
|
6934
|
+
for (i = 0, il = targetKeys.length; i < il; ++i) isNotPrototypeKey(key = targetKeys[i]) && (result[key] = clone(target[key]));
|
|
6935
|
+
return result;
|
|
6936
|
+
}
|
|
6937
|
+
function concatArrays(target, source) {
|
|
6938
|
+
const tl = target.length;
|
|
6939
|
+
const sl = source.length;
|
|
6940
|
+
let i = 0;
|
|
6941
|
+
const result = new Array(tl + sl);
|
|
6942
|
+
for (; i < tl; ++i) result[i] = clone(target[i]);
|
|
6943
|
+
for (i = 0; i < sl; ++i) result[i + tl] = clone(source[i]);
|
|
6944
|
+
return result;
|
|
6945
|
+
}
|
|
6946
|
+
const propertyIsEnumerable = Object.prototype.propertyIsEnumerable;
|
|
6947
|
+
function getSymbolsAndKeys(value) {
|
|
6948
|
+
const result = Object.keys(value);
|
|
6949
|
+
const keys = Object.getOwnPropertySymbols(value);
|
|
6950
|
+
for (let i = 0, il = keys.length; i < il; ++i) propertyIsEnumerable.call(value, keys[i]) && result.push(keys[i]);
|
|
6951
|
+
return result;
|
|
6952
|
+
}
|
|
6953
|
+
const getKeys = options?.symbols ? getSymbolsAndKeys : Object.keys;
|
|
6954
|
+
const cloneProtoObject = typeof options?.cloneProtoObject === "function" ? options.cloneProtoObject : void 0;
|
|
6955
|
+
const isMergeableObject = typeof options?.isMergeableObject === "function" ? options.isMergeableObject : defaultIsMergeableObjectFactory();
|
|
6956
|
+
const onlyDefinedProperties = options?.onlyDefinedProperties === true;
|
|
6957
|
+
function isPrimitive(value) {
|
|
6958
|
+
return typeof value !== "object" || value === null;
|
|
6959
|
+
}
|
|
6960
|
+
const mergeArray = options && typeof options.mergeArray === "function" ? options.mergeArray({
|
|
6961
|
+
clone,
|
|
6962
|
+
deepmerge: _deepmerge,
|
|
6963
|
+
getKeys,
|
|
6964
|
+
isMergeableObject
|
|
6965
|
+
}) : concatArrays;
|
|
6966
|
+
function clone(entry) {
|
|
6967
|
+
return isMergeableObject(entry) ? Array.isArray(entry) ? cloneArray(entry) : cloneObject(entry) : entry;
|
|
6968
|
+
}
|
|
6969
|
+
function mergeObject(target, source) {
|
|
6970
|
+
const result = {};
|
|
6971
|
+
const targetKeys = getKeys(target);
|
|
6972
|
+
const sourceKeys = getKeys(source);
|
|
6973
|
+
let i, il, key;
|
|
6974
|
+
for (i = 0, il = targetKeys.length; i < il; ++i) isNotPrototypeKey(key = targetKeys[i]) && sourceKeys.indexOf(key) === -1 && (result[key] = clone(target[key]));
|
|
6975
|
+
for (i = 0, il = sourceKeys.length; i < il; ++i) {
|
|
6976
|
+
if (!isNotPrototypeKey(key = sourceKeys[i])) continue;
|
|
6977
|
+
if (key in target) {
|
|
6978
|
+
if (targetKeys.indexOf(key) !== -1) if (cloneProtoObject && isMergeableObject(source[key]) && Object.getPrototypeOf(source[key]) !== JSON_PROTO) result[key] = cloneProtoObject(source[key]);
|
|
6979
|
+
else result[key] = _deepmerge(target[key], source[key]);
|
|
6980
|
+
} else {
|
|
6981
|
+
if (onlyDefinedProperties && typeof source[key] === "undefined") continue;
|
|
6982
|
+
result[key] = clone(source[key]);
|
|
6983
|
+
}
|
|
6984
|
+
}
|
|
6985
|
+
return result;
|
|
6986
|
+
}
|
|
6987
|
+
function _deepmerge(target, source) {
|
|
6988
|
+
if (onlyDefinedProperties && typeof source === "undefined") return clone(target);
|
|
6989
|
+
const sourceIsArray = Array.isArray(source);
|
|
6990
|
+
const targetIsArray = Array.isArray(target);
|
|
6991
|
+
if (isPrimitive(source)) return source;
|
|
6992
|
+
else if (!isMergeableObject(target)) return clone(source);
|
|
6993
|
+
else if (sourceIsArray && targetIsArray) return mergeArray(target, source);
|
|
6994
|
+
else if (sourceIsArray !== targetIsArray) return clone(source);
|
|
6995
|
+
else return mergeObject(target, source);
|
|
6996
|
+
}
|
|
6997
|
+
function _deepmergeAll() {
|
|
6998
|
+
switch (arguments.length) {
|
|
6999
|
+
case 0: return {};
|
|
7000
|
+
case 1: return clone(arguments[0]);
|
|
7001
|
+
case 2: return _deepmerge(arguments[0], arguments[1]);
|
|
7002
|
+
}
|
|
7003
|
+
let result;
|
|
7004
|
+
for (let i = 0, il = arguments.length; i < il; ++i) result = _deepmerge(result, arguments[i]);
|
|
7005
|
+
return result;
|
|
7006
|
+
}
|
|
7007
|
+
return options?.all ? _deepmergeAll : _deepmerge;
|
|
7008
|
+
}
|
|
7009
|
+
module.exports = deepmergeConstructor;
|
|
7010
|
+
module.exports.default = deepmergeConstructor;
|
|
7011
|
+
module.exports.deepmerge = deepmergeConstructor;
|
|
7012
|
+
Object.defineProperty(module.exports, "isMergeableObject", { get: defaultIsMergeableObjectFactory });
|
|
7013
|
+
}));
|
|
7014
|
+
//#endregion
|
|
7015
|
+
//#region ../../node_modules/.pnpm/secure-json-parse@4.1.0/node_modules/secure-json-parse/index.js
|
|
7016
|
+
var require_secure_json_parse = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
7017
|
+
const hasBuffer = typeof Buffer !== "undefined";
|
|
7018
|
+
const suspectProtoRx = /"(?:_|\\u005[Ff])(?:_|\\u005[Ff])(?:p|\\u0070)(?:r|\\u0072)(?:o|\\u006[Ff])(?:t|\\u0074)(?:o|\\u006[Ff])(?:_|\\u005[Ff])(?:_|\\u005[Ff])"\s*:/;
|
|
7019
|
+
const suspectConstructorRx = /"(?:c|\\u0063)(?:o|\\u006[Ff])(?:n|\\u006[Ee])(?:s|\\u0073)(?:t|\\u0074)(?:r|\\u0072)(?:u|\\u0075)(?:c|\\u0063)(?:t|\\u0074)(?:o|\\u006[Ff])(?:r|\\u0072)"\s*:/;
|
|
7020
|
+
/**
|
|
7021
|
+
* @description Internal parse function that parses JSON text with security checks.
|
|
7022
|
+
* @private
|
|
7023
|
+
* @param {string|Buffer} text - The JSON text string or Buffer to parse.
|
|
7024
|
+
* @param {Function} [reviver] - The JSON.parse() optional reviver argument.
|
|
7025
|
+
* @param {import('./types').ParseOptions} [options] - Optional configuration object.
|
|
7026
|
+
* @returns {*} The parsed object.
|
|
7027
|
+
* @throws {SyntaxError} If a forbidden prototype property is found and `options.protoAction` or
|
|
7028
|
+
* `options.constructorAction` is `'error'`.
|
|
7029
|
+
*/
|
|
7030
|
+
function _parse(text, reviver, options) {
|
|
7031
|
+
if (options == null) {
|
|
7032
|
+
if (reviver !== null && typeof reviver === "object") {
|
|
7033
|
+
options = reviver;
|
|
7034
|
+
reviver = void 0;
|
|
7035
|
+
}
|
|
7036
|
+
}
|
|
7037
|
+
if (hasBuffer && Buffer.isBuffer(text)) text = text.toString();
|
|
7038
|
+
if (text && text.charCodeAt(0) === 65279) text = text.slice(1);
|
|
7039
|
+
const obj = JSON.parse(text, reviver);
|
|
7040
|
+
if (obj === null || typeof obj !== "object") return obj;
|
|
7041
|
+
const protoAction = options && options.protoAction || "error";
|
|
7042
|
+
const constructorAction = options && options.constructorAction || "error";
|
|
7043
|
+
if (protoAction === "ignore" && constructorAction === "ignore") return obj;
|
|
7044
|
+
if (protoAction !== "ignore" && constructorAction !== "ignore") {
|
|
7045
|
+
if (suspectProtoRx.test(text) === false && suspectConstructorRx.test(text) === false) return obj;
|
|
7046
|
+
} else if (protoAction !== "ignore" && constructorAction === "ignore") {
|
|
7047
|
+
if (suspectProtoRx.test(text) === false) return obj;
|
|
7048
|
+
} else if (suspectConstructorRx.test(text) === false) return obj;
|
|
7049
|
+
return filter(obj, {
|
|
7050
|
+
protoAction,
|
|
7051
|
+
constructorAction,
|
|
7052
|
+
safe: options && options.safe
|
|
7053
|
+
});
|
|
7054
|
+
}
|
|
7055
|
+
/**
|
|
7056
|
+
* @description Scans and filters an object for forbidden prototype properties.
|
|
7057
|
+
* @param {Object} obj - The object being scanned.
|
|
7058
|
+
* @param {import('./types').ParseOptions} [options] - Optional configuration object.
|
|
7059
|
+
* @returns {Object|null} The filtered object, or `null` if safe mode is enabled and issues are found.
|
|
7060
|
+
* @throws {SyntaxError} If a forbidden prototype property is found and `options.protoAction` or
|
|
7061
|
+
* `options.constructorAction` is `'error'`.
|
|
7062
|
+
*/
|
|
7063
|
+
function filter(obj, { protoAction = "error", constructorAction = "error", safe } = {}) {
|
|
7064
|
+
let next = [obj];
|
|
7065
|
+
while (next.length) {
|
|
7066
|
+
const nodes = next;
|
|
7067
|
+
next = [];
|
|
7068
|
+
for (const node of nodes) {
|
|
7069
|
+
if (protoAction !== "ignore" && Object.prototype.hasOwnProperty.call(node, "__proto__")) {
|
|
7070
|
+
if (safe === true) return null;
|
|
7071
|
+
else if (protoAction === "error") throw new SyntaxError("Object contains forbidden prototype property");
|
|
7072
|
+
delete node.__proto__;
|
|
7073
|
+
}
|
|
7074
|
+
if (constructorAction !== "ignore" && Object.prototype.hasOwnProperty.call(node, "constructor") && node.constructor !== null && typeof node.constructor === "object" && Object.prototype.hasOwnProperty.call(node.constructor, "prototype")) {
|
|
7075
|
+
if (safe === true) return null;
|
|
7076
|
+
else if (constructorAction === "error") throw new SyntaxError("Object contains forbidden prototype property");
|
|
7077
|
+
delete node.constructor;
|
|
7078
|
+
}
|
|
7079
|
+
for (const key in node) {
|
|
7080
|
+
const value = node[key];
|
|
7081
|
+
if (value && typeof value === "object") next.push(value);
|
|
7082
|
+
}
|
|
7083
|
+
}
|
|
7084
|
+
}
|
|
7085
|
+
return obj;
|
|
7086
|
+
}
|
|
7087
|
+
/**
|
|
7088
|
+
* @description Parses a given JSON-formatted text into an object.
|
|
7089
|
+
* @param {string|Buffer} text - The JSON text string or Buffer to parse.
|
|
7090
|
+
* @param {Function} [reviver] - The `JSON.parse()` optional reviver argument, or options object.
|
|
7091
|
+
* @param {import('./types').ParseOptions} [options] - Optional configuration object.
|
|
7092
|
+
* @returns {*} The parsed object.
|
|
7093
|
+
* @throws {SyntaxError} If the JSON text is malformed or contains forbidden prototype properties
|
|
7094
|
+
* when `options.protoAction` or `options.constructorAction` is `'error'`.
|
|
7095
|
+
*/
|
|
7096
|
+
function parse(text, reviver, options) {
|
|
7097
|
+
const { stackTraceLimit } = Error;
|
|
7098
|
+
Error.stackTraceLimit = 0;
|
|
7099
|
+
try {
|
|
7100
|
+
return _parse(text, reviver, options);
|
|
7101
|
+
} finally {
|
|
7102
|
+
Error.stackTraceLimit = stackTraceLimit;
|
|
7103
|
+
}
|
|
7104
|
+
}
|
|
7105
|
+
/**
|
|
7106
|
+
* @description Safely parses a given JSON-formatted text into an object.
|
|
7107
|
+
* @param {string|Buffer} text - The JSON text string or Buffer to parse.
|
|
7108
|
+
* @param {Function} [reviver] - The `JSON.parse()` optional reviver argument.
|
|
7109
|
+
* @returns {*|null|undefined} The parsed object, `null` if security issues found, or `undefined` on parse error.
|
|
7110
|
+
*/
|
|
7111
|
+
function safeParse(text, reviver) {
|
|
7112
|
+
const { stackTraceLimit } = Error;
|
|
7113
|
+
Error.stackTraceLimit = 0;
|
|
7114
|
+
try {
|
|
7115
|
+
return _parse(text, reviver, { safe: true });
|
|
7116
|
+
} catch {
|
|
7117
|
+
return;
|
|
7118
|
+
} finally {
|
|
7119
|
+
Error.stackTraceLimit = stackTraceLimit;
|
|
7120
|
+
}
|
|
7121
|
+
}
|
|
7122
|
+
module.exports = parse;
|
|
7123
|
+
module.exports.default = parse;
|
|
7124
|
+
module.exports.parse = parse;
|
|
7125
|
+
module.exports.safeParse = safeParse;
|
|
7126
|
+
module.exports.scan = filter;
|
|
7127
|
+
}));
|
|
7128
|
+
//#endregion
|
|
7129
|
+
//#region ../server/dist/app-Dlx5GuFi.mjs
|
|
7130
|
+
var import_multipart = /* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
7131
|
+
const Busboy = require_main();
|
|
7132
|
+
const os = __require("node:os");
|
|
7133
|
+
const fp = require_plugin();
|
|
7134
|
+
const { createWriteStream: createWriteStream$1 } = __require("node:fs");
|
|
7135
|
+
const { unlink } = __require("node:fs/promises");
|
|
7136
|
+
const path = __require("node:path");
|
|
7137
|
+
const { generateId } = require_generateId();
|
|
7138
|
+
const createError = require_error();
|
|
7139
|
+
const streamToNull = require_stream_consumer();
|
|
7140
|
+
const deepmergeAll = require_deepmerge()({ all: true });
|
|
7141
|
+
const { PassThrough, Readable } = __require("node:stream");
|
|
7142
|
+
const { pipeline: pump } = __require("node:stream/promises");
|
|
7143
|
+
const secureJSON = require_secure_json_parse();
|
|
7144
|
+
const kMultipart = Symbol("multipart");
|
|
7145
|
+
const kMultipartHandler = Symbol("multipartHandler");
|
|
7146
|
+
const kSavedRequestFilesResult = Symbol("savedRequestFilesResult");
|
|
7147
|
+
const PartsLimitError = createError("FST_PARTS_LIMIT", "reach parts limit", 413);
|
|
7148
|
+
const FilesLimitError = createError("FST_FILES_LIMIT", "reach files limit", 413);
|
|
7149
|
+
const FieldsLimitError = createError("FST_FIELDS_LIMIT", "reach fields limit", 413);
|
|
7150
|
+
const RequestFileTooLargeError = createError("FST_REQ_FILE_TOO_LARGE", "request file too large", 413);
|
|
7151
|
+
const PrototypeViolationError = createError("FST_PROTO_VIOLATION", "prototype property is not allowed as field name", 400);
|
|
7152
|
+
const InvalidMultipartContentTypeError = createError("FST_INVALID_MULTIPART_CONTENT_TYPE", "the request is not multipart", 406);
|
|
7153
|
+
const InvalidJSONFieldError = createError("FST_INVALID_JSON_FIELD_ERROR", "a request field is not a valid JSON as declared by its Content-Type", 406);
|
|
7154
|
+
const FileBufferNotFoundError = createError("FST_FILE_BUFFER_NOT_FOUND", "the file buffer was not found", 500);
|
|
7155
|
+
const NoFormData = createError("FST_NO_FORM_DATA", "FormData is not available", 500);
|
|
7156
|
+
function setMultipart(req, _payload, done) {
|
|
7157
|
+
req[kMultipart] = true;
|
|
7158
|
+
done();
|
|
7159
|
+
}
|
|
7160
|
+
function busboy(options) {
|
|
7161
|
+
try {
|
|
7162
|
+
return new Busboy(options);
|
|
7163
|
+
} catch (error) {
|
|
7164
|
+
const errorEmitter = new PassThrough();
|
|
7165
|
+
process.nextTick(function() {
|
|
7166
|
+
errorEmitter.emit("error", error);
|
|
7167
|
+
});
|
|
7168
|
+
return errorEmitter;
|
|
7169
|
+
}
|
|
7170
|
+
}
|
|
7171
|
+
function fastifyMultipart(fastify, options, done) {
|
|
7172
|
+
options.limits = {
|
|
7173
|
+
...options.limits,
|
|
7174
|
+
parts: options.limits?.parts || 1e3,
|
|
7175
|
+
fileSize: options.limits?.fileSize || fastify.initialConfig.bodyLimit
|
|
7176
|
+
};
|
|
7177
|
+
const attachFieldsToBody = options.attachFieldsToBody;
|
|
7178
|
+
if (attachFieldsToBody === true || attachFieldsToBody === "keyValues") {
|
|
7179
|
+
if (typeof options.sharedSchemaId === "string" && attachFieldsToBody === true) fastify.addSchema({
|
|
7180
|
+
$id: options.sharedSchemaId,
|
|
7181
|
+
type: "object",
|
|
7182
|
+
properties: {
|
|
7183
|
+
fieldname: { type: "string" },
|
|
7184
|
+
encoding: { type: "string" },
|
|
7185
|
+
filename: { type: "string" },
|
|
7186
|
+
mimetype: { type: "string" }
|
|
7187
|
+
}
|
|
7188
|
+
});
|
|
7189
|
+
fastify.addHook("preValidation", async function(req) {
|
|
7190
|
+
if (!req.isMultipart()) return;
|
|
7191
|
+
for await (const part of req.parts(req.routeOptions.config.multipartOptions)) {
|
|
7192
|
+
req.body = part.fields;
|
|
7193
|
+
if (part.file) if (options.onFile) await options.onFile.call(req, part);
|
|
7194
|
+
else await part.toBuffer();
|
|
7195
|
+
}
|
|
7196
|
+
if (attachFieldsToBody === "keyValues") {
|
|
7197
|
+
const body = {};
|
|
7198
|
+
if (req.body) {
|
|
7199
|
+
const reqBodyKeys = Object.keys(req.body);
|
|
7200
|
+
for (let i = 0; i < reqBodyKeys.length; ++i) {
|
|
7201
|
+
const key = reqBodyKeys[i];
|
|
7202
|
+
const field = req.body[key];
|
|
7203
|
+
if (field.value !== void 0) body[key] = field.value;
|
|
7204
|
+
else if (field._buf) body[key] = field._buf;
|
|
7205
|
+
else if (Array.isArray(field)) {
|
|
7206
|
+
const items = [];
|
|
7207
|
+
for (let i = 0; i < field.length; ++i) {
|
|
7208
|
+
const item = field[i];
|
|
7209
|
+
if (item.value !== void 0) items.push(item.value);
|
|
7210
|
+
else if (item._buf) items.push(item._buf);
|
|
7211
|
+
}
|
|
7212
|
+
if (items.length) body[key] = items;
|
|
7213
|
+
}
|
|
7214
|
+
}
|
|
7215
|
+
}
|
|
7216
|
+
req.body = body;
|
|
7217
|
+
}
|
|
7218
|
+
});
|
|
7219
|
+
/* istanbul ignore next */
|
|
7220
|
+
if (globalThis.FormData && !fastify.hasRequestDecorator("formData")) fastify.decorateRequest("formData", async function() {
|
|
7221
|
+
const formData = new FormData();
|
|
7222
|
+
for (const key in this.body) {
|
|
7223
|
+
const value = this.body[key];
|
|
7224
|
+
if (Array.isArray(value)) for (const item of value) await append(key, item);
|
|
7225
|
+
else await append(key, value);
|
|
7226
|
+
}
|
|
7227
|
+
async function append(key, entry) {
|
|
7228
|
+
/* c8 ignore next: Buffer.isBuffer is not covered and causing `npm test` to fail */
|
|
7229
|
+
if (entry.type === "file" || attachFieldsToBody === "keyValues" && Buffer.isBuffer(entry)) formData.append(key, new Blob([await entry.toBuffer()], { type: entry.mimetype }), entry.filename);
|
|
7230
|
+
else formData.append(key, entry.value);
|
|
7231
|
+
}
|
|
7232
|
+
return formData;
|
|
7233
|
+
});
|
|
7234
|
+
}
|
|
7235
|
+
/* istanbul ignore next */
|
|
7236
|
+
if (!fastify.hasRequestDecorator("formData")) fastify.decorateRequest("formData", async function() {
|
|
7237
|
+
/* c8 ignore next: Next line is not covered and causing `npm test` to fail */
|
|
7238
|
+
throw new NoFormData();
|
|
7239
|
+
});
|
|
7240
|
+
const defaultThrowFileSizeLimit = typeof options.throwFileSizeLimit === "boolean" ? options.throwFileSizeLimit : true;
|
|
7241
|
+
fastify.decorate("multipartErrors", {
|
|
7242
|
+
PartsLimitError,
|
|
7243
|
+
FilesLimitError,
|
|
7244
|
+
FieldsLimitError,
|
|
7245
|
+
PrototypeViolationError,
|
|
7246
|
+
InvalidMultipartContentTypeError,
|
|
7247
|
+
RequestFileTooLargeError,
|
|
7248
|
+
FileBufferNotFoundError
|
|
7249
|
+
});
|
|
7250
|
+
fastify.addContentTypeParser("multipart/form-data", setMultipart);
|
|
7251
|
+
fastify.decorateRequest(kMultipart, false);
|
|
7252
|
+
fastify.decorateRequest(kMultipartHandler, handleMultipart);
|
|
7253
|
+
fastify.decorateRequest(kSavedRequestFilesResult, null);
|
|
7254
|
+
fastify.decorateRequest("parts", getMultipartIterator);
|
|
7255
|
+
fastify.decorateRequest("isMultipart", isMultipart);
|
|
7256
|
+
fastify.decorateRequest("tmpUploads", null);
|
|
7257
|
+
fastify.decorateRequest("savedRequestFiles", null);
|
|
7258
|
+
fastify.decorateRequest("file", getMultipartFile);
|
|
7259
|
+
fastify.decorateRequest("files", getMultipartFiles);
|
|
7260
|
+
fastify.decorateRequest("saveRequestFiles", saveRequestFiles);
|
|
7261
|
+
fastify.decorateRequest("cleanRequestFiles", cleanRequestFiles);
|
|
7262
|
+
fastify.addHook("onResponse", async (request) => {
|
|
7263
|
+
await request.cleanRequestFiles();
|
|
7264
|
+
});
|
|
7265
|
+
function isMultipart() {
|
|
7266
|
+
return this[kMultipart];
|
|
7267
|
+
}
|
|
7268
|
+
function handleMultipart(opts = {}) {
|
|
7269
|
+
if (!this.isMultipart()) throw new InvalidMultipartContentTypeError();
|
|
7270
|
+
this.log.debug("starting multipart parsing");
|
|
7271
|
+
let values = [];
|
|
7272
|
+
let pendingHandler = null;
|
|
7273
|
+
const ch = (val) => {
|
|
7274
|
+
if (pendingHandler) {
|
|
7275
|
+
pendingHandler(val);
|
|
7276
|
+
pendingHandler = null;
|
|
7277
|
+
} else values.push(val);
|
|
7278
|
+
};
|
|
7279
|
+
const handle = (handler) => {
|
|
7280
|
+
if (values.length > 0) {
|
|
7281
|
+
const value = values[0];
|
|
7282
|
+
values = values.slice(1);
|
|
7283
|
+
handler(value);
|
|
7284
|
+
} else pendingHandler = handler;
|
|
7285
|
+
};
|
|
7286
|
+
const parts = () => {
|
|
7287
|
+
return new Promise((resolve, reject) => {
|
|
7288
|
+
handle((val) => {
|
|
7289
|
+
if (val instanceof Error) if (val.message === "Unexpected end of multipart data") resolve(null);
|
|
7290
|
+
else reject(val);
|
|
7291
|
+
else resolve(val);
|
|
7292
|
+
});
|
|
7293
|
+
});
|
|
7294
|
+
};
|
|
7295
|
+
const body = {};
|
|
7296
|
+
let lastError = null;
|
|
7297
|
+
let currentFile = null;
|
|
7298
|
+
const request = this.raw;
|
|
7299
|
+
const busboyOptions = deepmergeAll({ headers: request.headers }, options, opts);
|
|
7300
|
+
this.log.trace({ busboyOptions }, "Providing options to busboy");
|
|
7301
|
+
const bb = busboy(busboyOptions);
|
|
7302
|
+
request.on("close", cleanup);
|
|
7303
|
+
request.on("error", cleanup);
|
|
7304
|
+
bb.on("field", onField).on("file", onFile).on("end", cleanup).on("finish", cleanup).on("close", cleanup).on("error", cleanup);
|
|
7305
|
+
bb.on("partsLimit", function() {
|
|
7306
|
+
const err = new PartsLimitError();
|
|
7307
|
+
onError(err);
|
|
7308
|
+
process.nextTick(() => cleanup(err));
|
|
7309
|
+
});
|
|
7310
|
+
bb.on("filesLimit", function() {
|
|
7311
|
+
const err = new FilesLimitError();
|
|
7312
|
+
onError(err);
|
|
7313
|
+
process.nextTick(() => cleanup(err));
|
|
7314
|
+
});
|
|
7315
|
+
bb.on("fieldsLimit", function() {
|
|
7316
|
+
const err = new FieldsLimitError();
|
|
7317
|
+
onError(err);
|
|
7318
|
+
process.nextTick(() => cleanup(err));
|
|
7319
|
+
});
|
|
7320
|
+
request.pipe(bb);
|
|
7321
|
+
function onField(name, fieldValue, fieldnameTruncated, valueTruncated, encoding, contentType) {
|
|
7322
|
+
if (name in Object.prototype) {
|
|
7323
|
+
onError(new PrototypeViolationError());
|
|
7324
|
+
return;
|
|
7325
|
+
}
|
|
7326
|
+
if (contentType.startsWith("application/json")) {
|
|
7327
|
+
if (valueTruncated) {
|
|
7328
|
+
onError(new InvalidJSONFieldError());
|
|
7329
|
+
return;
|
|
7330
|
+
}
|
|
7331
|
+
try {
|
|
7332
|
+
fieldValue = secureJSON.parse(fieldValue);
|
|
7333
|
+
contentType = "application/json";
|
|
7334
|
+
} catch {
|
|
7335
|
+
onError(new InvalidJSONFieldError());
|
|
7336
|
+
return;
|
|
7337
|
+
}
|
|
7338
|
+
}
|
|
7339
|
+
const value = {
|
|
7340
|
+
type: "field",
|
|
7341
|
+
fieldname: name,
|
|
7342
|
+
mimetype: contentType,
|
|
7343
|
+
encoding,
|
|
7344
|
+
value: fieldValue,
|
|
7345
|
+
fieldnameTruncated,
|
|
7346
|
+
valueTruncated,
|
|
7347
|
+
fields: body
|
|
7348
|
+
};
|
|
7349
|
+
if (body[name] === void 0) body[name] = value;
|
|
7350
|
+
else if (Array.isArray(body[name])) body[name].push(value);
|
|
7351
|
+
else body[name] = [body[name], value];
|
|
7352
|
+
ch(value);
|
|
7353
|
+
}
|
|
7354
|
+
function onFile(name, file, filename, encoding, mimetype) {
|
|
7355
|
+
if (name in Object.prototype) {
|
|
7356
|
+
streamToNull(file).catch(() => {});
|
|
7357
|
+
onError(new PrototypeViolationError());
|
|
7358
|
+
return;
|
|
7359
|
+
}
|
|
7360
|
+
const throwFileSizeLimit = typeof opts.throwFileSizeLimit === "boolean" ? opts.throwFileSizeLimit : defaultThrowFileSizeLimit;
|
|
7361
|
+
const value = {
|
|
7362
|
+
type: "file",
|
|
7363
|
+
fieldname: name,
|
|
7364
|
+
filename,
|
|
7365
|
+
encoding,
|
|
7366
|
+
mimetype,
|
|
7367
|
+
file,
|
|
7368
|
+
fields: body,
|
|
7369
|
+
_buf: null,
|
|
7370
|
+
async toBuffer() {
|
|
7371
|
+
if (this._buf) return this._buf;
|
|
7372
|
+
const fileChunks = [];
|
|
7373
|
+
let err;
|
|
7374
|
+
for await (const chunk of this.file) {
|
|
7375
|
+
fileChunks.push(chunk);
|
|
7376
|
+
if (throwFileSizeLimit && this.file.truncated) {
|
|
7377
|
+
err = new RequestFileTooLargeError();
|
|
7378
|
+
err.part = this;
|
|
7379
|
+
onError(err);
|
|
7380
|
+
fileChunks.length = 0;
|
|
7381
|
+
}
|
|
7382
|
+
}
|
|
7383
|
+
if (err) throw err;
|
|
7384
|
+
this._buf = Buffer.concat(fileChunks);
|
|
7385
|
+
return this._buf;
|
|
7386
|
+
}
|
|
7387
|
+
};
|
|
7388
|
+
file.on("error", function(err) {
|
|
7389
|
+
if (err.message && err.message.includes("terminated early")) onError(err);
|
|
7390
|
+
});
|
|
7391
|
+
if (throwFileSizeLimit) file.on("limit", function() {
|
|
7392
|
+
const err = new RequestFileTooLargeError();
|
|
7393
|
+
err.part = value;
|
|
7394
|
+
onError(err);
|
|
7395
|
+
});
|
|
7396
|
+
if (body[name] === void 0) body[name] = value;
|
|
7397
|
+
else if (Array.isArray(body[name])) body[name].push(value);
|
|
7398
|
+
else body[name] = [body[name], value];
|
|
7399
|
+
currentFile = file;
|
|
7400
|
+
ch(value);
|
|
7401
|
+
}
|
|
7402
|
+
function onError(err) {
|
|
7403
|
+
lastError = err;
|
|
7404
|
+
currentFile = null;
|
|
7405
|
+
}
|
|
7406
|
+
function cleanup(err) {
|
|
7407
|
+
request.unpipe(bb);
|
|
7408
|
+
if ((err || request.aborted) && currentFile) {
|
|
7409
|
+
currentFile.destroy();
|
|
7410
|
+
currentFile = null;
|
|
7411
|
+
}
|
|
7412
|
+
ch(err || lastError || null);
|
|
7413
|
+
}
|
|
7414
|
+
return parts;
|
|
7415
|
+
}
|
|
7416
|
+
async function saveRequestFiles(options) {
|
|
7417
|
+
if (this[kSavedRequestFilesResult]) return this[kSavedRequestFilesResult];
|
|
7418
|
+
let parts;
|
|
7419
|
+
let values = {};
|
|
7420
|
+
if (attachFieldsToBody === true || attachFieldsToBody === "keyValues") {
|
|
7421
|
+
parts = this.body ? filesFromFields.call(this, this.body) : [];
|
|
7422
|
+
values = this.body || {};
|
|
7423
|
+
} else parts = this.parts(options);
|
|
7424
|
+
this.savedRequestFiles = [];
|
|
7425
|
+
const tmpdir = options?.tmpdir || os.tmpdir();
|
|
7426
|
+
this.tmpUploads = [];
|
|
7427
|
+
let i = 0;
|
|
7428
|
+
for await (const part of parts) {
|
|
7429
|
+
values = part.fields;
|
|
7430
|
+
if (!part.file) continue;
|
|
7431
|
+
const filepath = path.join(tmpdir, generateId() + path.extname(part.filename || "file" + i++));
|
|
7432
|
+
const target = createWriteStream$1(filepath);
|
|
7433
|
+
try {
|
|
7434
|
+
this.tmpUploads.push(filepath);
|
|
7435
|
+
await pump(part.file, target);
|
|
7436
|
+
this.savedRequestFiles.push({
|
|
7437
|
+
...part,
|
|
7438
|
+
filepath
|
|
7439
|
+
});
|
|
7440
|
+
} catch (err) {
|
|
7441
|
+
target.destroy();
|
|
7442
|
+
await this.cleanRequestFiles();
|
|
7443
|
+
this.log.error({ err }, "save request file");
|
|
7444
|
+
throw err;
|
|
7445
|
+
}
|
|
7446
|
+
}
|
|
7447
|
+
this[kSavedRequestFilesResult] = {
|
|
7448
|
+
files: this.savedRequestFiles,
|
|
7449
|
+
values
|
|
7450
|
+
};
|
|
7451
|
+
return this[kSavedRequestFilesResult];
|
|
7452
|
+
}
|
|
7453
|
+
function* filesFromFields(container) {
|
|
7454
|
+
try {
|
|
7455
|
+
const fields = Array.isArray(container) ? container : Object.values(container);
|
|
7456
|
+
for (let i = 0; i < fields.length; ++i) {
|
|
7457
|
+
const field = fields[i];
|
|
7458
|
+
if (Array.isArray(field)) for (const subField of filesFromFields.call(this, field)) yield subField;
|
|
7459
|
+
if (!field.file) continue;
|
|
7460
|
+
if (!field._buf) throw new FileBufferNotFoundError();
|
|
7461
|
+
field.file = Readable.from(field._buf);
|
|
7462
|
+
yield field;
|
|
7463
|
+
}
|
|
7464
|
+
} catch (err) {
|
|
7465
|
+
this.log.error({ err }, "save request file failed");
|
|
7466
|
+
throw err;
|
|
7467
|
+
}
|
|
7468
|
+
}
|
|
7469
|
+
async function cleanRequestFiles() {
|
|
7470
|
+
if (!this.tmpUploads) return;
|
|
7471
|
+
for (let i = 0; i < this.tmpUploads.length; ++i) {
|
|
7472
|
+
const filepath = this.tmpUploads[i];
|
|
7473
|
+
try {
|
|
7474
|
+
await unlink(filepath);
|
|
7475
|
+
} /* c8 ignore start */catch (error) {
|
|
7476
|
+
this.log.error(error, "Could not delete file");
|
|
7477
|
+
}
|
|
7478
|
+
}
|
|
7479
|
+
}
|
|
7480
|
+
async function getMultipartFile(options) {
|
|
7481
|
+
const parts = this[kMultipartHandler](options);
|
|
7482
|
+
let part;
|
|
7483
|
+
while ((part = await parts()) != null) if (part.file) return part;
|
|
7484
|
+
}
|
|
7485
|
+
async function* getMultipartFiles(options) {
|
|
7486
|
+
const parts = this[kMultipartHandler](options);
|
|
7487
|
+
let part;
|
|
7488
|
+
while ((part = await parts()) != null) if (part.file) yield part;
|
|
7489
|
+
}
|
|
7490
|
+
async function* getMultipartIterator(options) {
|
|
7491
|
+
const parts = this[kMultipartHandler](options);
|
|
7492
|
+
let part;
|
|
7493
|
+
while ((part = await parts()) != null) yield part;
|
|
7494
|
+
}
|
|
7495
|
+
done();
|
|
7496
|
+
}
|
|
7497
|
+
/**
|
|
7498
|
+
* Adds a new type `isFile` to help @fastify/swagger generate the correct schema.
|
|
7499
|
+
*/
|
|
7500
|
+
function ajvFilePlugin(ajv) {
|
|
7501
|
+
return ajv.addKeyword({
|
|
7502
|
+
keyword: "isFile",
|
|
7503
|
+
compile: (_schema, parent) => {
|
|
7504
|
+
parent.type = "string";
|
|
7505
|
+
parent.format = "binary";
|
|
7506
|
+
delete parent.isFile;
|
|
7507
|
+
return (field) => !!field.file;
|
|
7508
|
+
},
|
|
7509
|
+
error: { message: "should be a file" }
|
|
4709
7510
|
});
|
|
4710
|
-
return value;
|
|
4711
|
-
}
|
|
4712
|
-
if (type === "password") return password({ message: prompt.message });
|
|
4713
|
-
return input({
|
|
4714
|
-
message: prompt.message,
|
|
4715
|
-
default: prompt.default
|
|
4716
|
-
});
|
|
4717
|
-
}
|
|
4718
|
-
/** Walk schema to find the env var name for a given dot path. */
|
|
4719
|
-
function findEnvVar(schema, dotPath) {
|
|
4720
|
-
const parts = dotPath.split(".");
|
|
4721
|
-
let current = schema;
|
|
4722
|
-
for (const part of parts) {
|
|
4723
|
-
if (current === null || current === void 0 || typeof current !== "object") return void 0;
|
|
4724
|
-
const obj = current;
|
|
4725
|
-
if (obj._tag === "optional") current = obj.shape[part];
|
|
4726
|
-
else current = obj[part];
|
|
4727
|
-
}
|
|
4728
|
-
if (typeof current === "object" && current !== null && "_tag" in current) {
|
|
4729
|
-
const field = current;
|
|
4730
|
-
if (field._tag === "field") return field.options?.env;
|
|
4731
|
-
}
|
|
4732
|
-
}
|
|
4733
|
-
function setNestedByDot(obj, dotPath, value) {
|
|
4734
|
-
const parts = dotPath.split(".");
|
|
4735
|
-
let current = obj;
|
|
4736
|
-
for (let i = 0; i < parts.length - 1; i++) {
|
|
4737
|
-
const key = parts[i];
|
|
4738
|
-
if (key === void 0) continue;
|
|
4739
|
-
if (!(key in current) || typeof current[key] !== "object" || current[key] === null) current[key] = {};
|
|
4740
|
-
current = current[key];
|
|
4741
7511
|
}
|
|
4742
|
-
|
|
4743
|
-
|
|
4744
|
-
|
|
4745
|
-
|
|
4746
|
-
|
|
7512
|
+
/**
|
|
7513
|
+
* These export configurations enable JS and TS developers
|
|
7514
|
+
* to consumer fastify in whatever way best suits their needs.
|
|
7515
|
+
*/
|
|
7516
|
+
module.exports = fp(fastifyMultipart, {
|
|
7517
|
+
fastify: "5.x",
|
|
7518
|
+
name: "@fastify/multipart"
|
|
7519
|
+
});
|
|
7520
|
+
module.exports.default = fastifyMultipart;
|
|
7521
|
+
module.exports.fastifyMultipart = fastifyMultipart;
|
|
7522
|
+
module.exports.ajvFilePlugin = ajvFilePlugin;
|
|
7523
|
+
})))(), 1);
|
|
4747
7524
|
var __defProp = Object.defineProperty;
|
|
4748
7525
|
var __exportAll = (all, no_symbols) => {
|
|
4749
7526
|
let target = {};
|
|
@@ -5280,6 +8057,8 @@ function parseId$1(raw) {
|
|
|
5280
8057
|
async function adminAdapterMappingRoutes(app) {
|
|
5281
8058
|
app.get("/", async (request) => {
|
|
5282
8059
|
const scope = memberScope(request);
|
|
8060
|
+
const conditions = [eq(agents.organizationId, scope.organizationId)];
|
|
8061
|
+
if (scope.role !== "admin") conditions.push(eq(agents.managerId, scope.memberId));
|
|
5283
8062
|
return (await app.db.select({
|
|
5284
8063
|
id: adapterAgentMappings.id,
|
|
5285
8064
|
platform: adapterAgentMappings.platform,
|
|
@@ -5288,7 +8067,7 @@ async function adminAdapterMappingRoutes(app) {
|
|
|
5288
8067
|
boundVia: adapterAgentMappings.boundVia,
|
|
5289
8068
|
displayName: adapterAgentMappings.displayName,
|
|
5290
8069
|
createdAt: adapterAgentMappings.createdAt
|
|
5291
|
-
}).from(adapterAgentMappings).innerJoin(agents, eq(agents.uuid, adapterAgentMappings.agentId)).where(
|
|
8070
|
+
}).from(adapterAgentMappings).innerJoin(agents, eq(agents.uuid, adapterAgentMappings.agentId)).where(and(...conditions)).orderBy(desc(adapterAgentMappings.createdAt))).map((r) => ({
|
|
5292
8071
|
id: r.id,
|
|
5293
8072
|
platform: r.platform,
|
|
5294
8073
|
externalUserId: r.externalUserId,
|
|
@@ -5336,11 +8115,6 @@ async function adminAdapterMappingRoutes(app) {
|
|
|
5336
8115
|
return reply.status(204).send();
|
|
5337
8116
|
});
|
|
5338
8117
|
}
|
|
5339
|
-
async function adminAdapterStatusRoutes(app) {
|
|
5340
|
-
app.get("/", async () => {
|
|
5341
|
-
return app.adapterManager.getBotStatuses();
|
|
5342
|
-
});
|
|
5343
|
-
}
|
|
5344
8118
|
/** Bot credentials for external platform adapters. Credentials are encrypted at application layer (AES-256-GCM). */
|
|
5345
8119
|
const adapterConfigs = pgTable("adapter_configs", {
|
|
5346
8120
|
id: serial("id").primaryKey(),
|
|
@@ -5351,6 +8125,17 @@ const adapterConfigs = pgTable("adapter_configs", {
|
|
|
5351
8125
|
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
5352
8126
|
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow()
|
|
5353
8127
|
}, (t) => [unique("uq_adapter_configs_agent_platform").on(t.agentId, t.platform)]);
|
|
8128
|
+
async function adminAdapterStatusRoutes(app) {
|
|
8129
|
+
app.get("/", async (request) => {
|
|
8130
|
+
const scope = memberScope(request);
|
|
8131
|
+
const conditions = [eq(agents.organizationId, scope.organizationId), ne(agents.status, "deleted")];
|
|
8132
|
+
if (scope.role !== "admin") conditions.push(eq(agents.managerId, scope.memberId));
|
|
8133
|
+
const visibleRows = await app.db.select({ id: adapterConfigs.id }).from(adapterConfigs).innerJoin(agents, eq(agents.uuid, adapterConfigs.agentId)).where(and(...conditions));
|
|
8134
|
+
const visibleIds = new Set(visibleRows.map((r) => r.id));
|
|
8135
|
+
if (visibleIds.size === 0) return [];
|
|
8136
|
+
return app.adapterManager.getBotStatuses().filter((s) => visibleIds.has(s.configId));
|
|
8137
|
+
});
|
|
8138
|
+
}
|
|
5354
8139
|
const ALGORITHM = "aes-256-gcm";
|
|
5355
8140
|
const IV_LENGTH = 12;
|
|
5356
8141
|
const AUTH_TAG_LENGTH = 16;
|
|
@@ -5464,6 +8249,30 @@ function toResponse(row) {
|
|
|
5464
8249
|
async function listAdapterConfigs(db) {
|
|
5465
8250
|
return (await db.select().from(adapterConfigs).orderBy(desc(adapterConfigs.createdAt))).map(toResponse);
|
|
5466
8251
|
}
|
|
8252
|
+
/**
|
|
8253
|
+
* Scoped variant used by the member-facing admin route.
|
|
8254
|
+
*
|
|
8255
|
+
* - admin: every adapter config whose agent belongs to the caller's org.
|
|
8256
|
+
* - non-admin: only adapter configs bound to agents the caller manages
|
|
8257
|
+
* (Rule: bindings follow manageability).
|
|
8258
|
+
*
|
|
8259
|
+
* Kept as a separate function so internal self-service callers
|
|
8260
|
+
* (`agent/feishu-bot.ts`) that only need a raw read don't accidentally pay
|
|
8261
|
+
* for the join.
|
|
8262
|
+
*/
|
|
8263
|
+
async function listAdapterConfigsForMember(db, scope) {
|
|
8264
|
+
const conditions = [eq(agents.organizationId, scope.organizationId), ne(agents.status, "deleted")];
|
|
8265
|
+
if (scope.role !== "admin") conditions.push(eq(agents.managerId, scope.memberId));
|
|
8266
|
+
return (await db.select({
|
|
8267
|
+
id: adapterConfigs.id,
|
|
8268
|
+
platform: adapterConfigs.platform,
|
|
8269
|
+
agentId: adapterConfigs.agentId,
|
|
8270
|
+
credentials: adapterConfigs.credentials,
|
|
8271
|
+
status: adapterConfigs.status,
|
|
8272
|
+
createdAt: adapterConfigs.createdAt,
|
|
8273
|
+
updatedAt: adapterConfigs.updatedAt
|
|
8274
|
+
}).from(adapterConfigs).innerJoin(agents, eq(agents.uuid, adapterConfigs.agentId)).where(and(...conditions)).orderBy(desc(adapterConfigs.createdAt))).map(toResponse);
|
|
8275
|
+
}
|
|
5467
8276
|
async function getAdapterConfig(db, id) {
|
|
5468
8277
|
const [row] = await db.select().from(adapterConfigs).where(eq(adapterConfigs.id, id)).limit(1);
|
|
5469
8278
|
if (!row) throw new NotFoundError(`Adapter config "${id}" not found`);
|
|
@@ -5513,8 +8322,9 @@ function parseId(raw) {
|
|
|
5513
8322
|
return id;
|
|
5514
8323
|
}
|
|
5515
8324
|
async function adminAdapterRoutes(app) {
|
|
5516
|
-
app.get("/", async () => {
|
|
5517
|
-
|
|
8325
|
+
app.get("/", async (request) => {
|
|
8326
|
+
const scope = memberScope(request);
|
|
8327
|
+
return (await listAdapterConfigsForMember(app.db, scope)).map((c) => ({
|
|
5518
8328
|
...c,
|
|
5519
8329
|
createdAt: c.createdAt.toISOString(),
|
|
5520
8330
|
updatedAt: c.updatedAt.toISOString()
|
|
@@ -5776,6 +8586,47 @@ async function getAgent(db, uuid) {
|
|
|
5776
8586
|
return agent;
|
|
5777
8587
|
}
|
|
5778
8588
|
/**
|
|
8589
|
+
* Admin-only variant: return every non-deleted agent in the org, ignoring
|
|
8590
|
+
* the visibility filter. Used by the `/admin` "All Agents" view so a team
|
|
8591
|
+
* admin can see and act on private agents owned by other members. The
|
|
8592
|
+
* route layer is responsible for gating this to admin callers — the
|
|
8593
|
+
* service does not enforce role by itself, but it does enforce org scope
|
|
8594
|
+
* and the not-deleted predicate.
|
|
8595
|
+
*/
|
|
8596
|
+
async function listAgentsForAdmin(db, scope, limit, cursor) {
|
|
8597
|
+
const conditions = [eq(agents.organizationId, scope.organizationId), ne(agents.status, AGENT_STATUSES.DELETED)];
|
|
8598
|
+
if (cursor) conditions.push(lt(agents.createdAt, new Date(cursor)));
|
|
8599
|
+
const where = and(...conditions);
|
|
8600
|
+
const rows = await db.select({
|
|
8601
|
+
uuid: agents.uuid,
|
|
8602
|
+
name: agents.name,
|
|
8603
|
+
organizationId: agents.organizationId,
|
|
8604
|
+
type: agents.type,
|
|
8605
|
+
displayName: agents.displayName,
|
|
8606
|
+
delegateMention: agents.delegateMention,
|
|
8607
|
+
inboxId: agents.inboxId,
|
|
8608
|
+
status: agents.status,
|
|
8609
|
+
cloudUserId: agents.cloudUserId,
|
|
8610
|
+
visibility: agents.visibility,
|
|
8611
|
+
metadata: agents.metadata,
|
|
8612
|
+
managerId: agents.managerId,
|
|
8613
|
+
clientId: agents.clientId,
|
|
8614
|
+
createdAt: agents.createdAt,
|
|
8615
|
+
updatedAt: agents.updatedAt,
|
|
8616
|
+
presenceStatus: agentPresence.status,
|
|
8617
|
+
runtimeType: agentPresence.runtimeType,
|
|
8618
|
+
runtimeState: agentPresence.runtimeState,
|
|
8619
|
+
activeSessions: agentPresence.activeSessions
|
|
8620
|
+
}).from(agents).leftJoin(agentPresence, eq(agents.uuid, agentPresence.agentId)).where(where).orderBy(desc(agents.createdAt)).limit(limit + 1);
|
|
8621
|
+
const hasMore = rows.length > limit;
|
|
8622
|
+
const items = hasMore ? rows.slice(0, limit) : rows;
|
|
8623
|
+
const last = items[items.length - 1];
|
|
8624
|
+
return {
|
|
8625
|
+
items,
|
|
8626
|
+
nextCursor: hasMore && last ? last.createdAt.toISOString() : null
|
|
8627
|
+
};
|
|
8628
|
+
}
|
|
8629
|
+
/**
|
|
5779
8630
|
* List agents visible to a specific member.
|
|
5780
8631
|
* Uses agentVisibilityCondition from access-control (same rules for all roles).
|
|
5781
8632
|
*/
|
|
@@ -6271,17 +9122,31 @@ async function cleanupStalePresence(db, staleSeconds = 60) {
|
|
|
6271
9122
|
`)).length;
|
|
6272
9123
|
}
|
|
6273
9124
|
/**
|
|
6274
|
-
* Assert the caller
|
|
9125
|
+
* Assert the caller can act on this client. Throws 404 for both "not found"
|
|
6275
9126
|
* and "not yours" to prevent UUID enumeration across org/user boundaries.
|
|
6276
|
-
*
|
|
6277
|
-
*
|
|
9127
|
+
*
|
|
9128
|
+
* - member: owner match (`row.user_id == scope.userId`).
|
|
9129
|
+
* - admin: any client whose owner is a member of the admin's own org.
|
|
9130
|
+
*
|
|
9131
|
+
* Legacy unclaimed rows (`user_id IS NULL`) have no org association we can
|
|
9132
|
+
* verify — we explicitly refuse to grant admin access to them so a
|
|
9133
|
+
* cross-tenant admin can't operate on another org's orphan rows. These
|
|
9134
|
+
* orphans are surfaced for self-service re-registration only; the owning
|
|
9135
|
+
* operator must claim the row via `first-tree-hub connect` before any
|
|
9136
|
+
* admin action becomes available.
|
|
6278
9137
|
*/
|
|
6279
|
-
async function assertClientOwner(db, clientId,
|
|
9138
|
+
async function assertClientOwner(db, clientId, scope) {
|
|
6280
9139
|
const [row] = await db.select({
|
|
6281
9140
|
id: clients.id,
|
|
6282
9141
|
userId: clients.userId
|
|
6283
9142
|
}).from(clients).where(eq(clients.id, clientId)).limit(1);
|
|
6284
|
-
if (!row
|
|
9143
|
+
if (!row) throw new NotFoundError(`Client "${clientId}" not found`);
|
|
9144
|
+
if (row.userId === scope.userId) return;
|
|
9145
|
+
if (scope.role === "admin" && row.userId !== null) {
|
|
9146
|
+
const [sibling] = await db.select({ id: members.id }).from(members).where(and(eq(members.userId, row.userId), eq(members.organizationId, scope.organizationId))).limit(1);
|
|
9147
|
+
if (sibling) return;
|
|
9148
|
+
}
|
|
9149
|
+
throw new NotFoundError(`Client "${clientId}" not found`);
|
|
6285
9150
|
}
|
|
6286
9151
|
/**
|
|
6287
9152
|
* Upsert the clients row for a given `client_id` under an authenticated user.
|
|
@@ -6361,8 +9226,32 @@ async function listActiveAgentsPinnedToClient(db, clientId) {
|
|
|
6361
9226
|
type: agents.type
|
|
6362
9227
|
}).from(agents).where(and(eq(agents.clientId, clientId), ne(agents.status, "deleted")));
|
|
6363
9228
|
}
|
|
6364
|
-
|
|
6365
|
-
|
|
9229
|
+
/**
|
|
9230
|
+
* Scope-aware client listing.
|
|
9231
|
+
*
|
|
9232
|
+
* - member: only rows where `user_id = scope.userId`.
|
|
9233
|
+
* - admin: every claimed row whose owner is a member of the caller's
|
|
9234
|
+
* organization.
|
|
9235
|
+
*
|
|
9236
|
+
* Legacy unclaimed rows (`user_id IS NULL`) are intentionally hidden from
|
|
9237
|
+
* both roles — the `clients` table has no org column, so we cannot verify
|
|
9238
|
+
* which org an orphan belongs to. Exposing them to admin would leak
|
|
9239
|
+
* orphans across tenants. The owning operator reclaims the row via
|
|
9240
|
+
* `first-tree-hub connect`, after which it appears in their list.
|
|
9241
|
+
*/
|
|
9242
|
+
async function listClients(db, scope) {
|
|
9243
|
+
const rows = scope.role === "admin" ? await db.selectDistinct({
|
|
9244
|
+
id: clients.id,
|
|
9245
|
+
userId: clients.userId,
|
|
9246
|
+
status: clients.status,
|
|
9247
|
+
sdkVersion: clients.sdkVersion,
|
|
9248
|
+
hostname: clients.hostname,
|
|
9249
|
+
os: clients.os,
|
|
9250
|
+
instanceId: clients.instanceId,
|
|
9251
|
+
connectedAt: clients.connectedAt,
|
|
9252
|
+
lastSeenAt: clients.lastSeenAt,
|
|
9253
|
+
metadata: clients.metadata
|
|
9254
|
+
}).from(clients).innerJoin(members, eq(members.userId, clients.userId)).where(eq(members.organizationId, scope.organizationId)) : await db.select().from(clients).where(eq(clients.userId, scope.userId));
|
|
6366
9255
|
const counts = await db.select({
|
|
6367
9256
|
clientId: agents.clientId,
|
|
6368
9257
|
count: sql`count(*)::int`
|
|
@@ -6827,6 +9716,33 @@ async function adminAgentRoutes(app) {
|
|
|
6827
9716
|
nextCursor: result.nextCursor
|
|
6828
9717
|
};
|
|
6829
9718
|
});
|
|
9719
|
+
/**
|
|
9720
|
+
* Admin-only: every agent in the caller's org, skipping the visibility
|
|
9721
|
+
* filter applied on the regular `/agents` list. Private agents owned by
|
|
9722
|
+
* other members show up here so an admin can reassign or troubleshoot.
|
|
9723
|
+
* Role gating is enforced here — the parent route group does NOT add
|
|
9724
|
+
* adminOnly because the member-facing `GET /` is shared.
|
|
9725
|
+
*/
|
|
9726
|
+
app.get("/all", async (request) => {
|
|
9727
|
+
const scope = memberScope(request);
|
|
9728
|
+
if (scope.role !== "admin") throw new ForbiddenError("Admin role required");
|
|
9729
|
+
const query = paginationQuerySchema.parse(request.query);
|
|
9730
|
+
const result = await listAgentsForAdmin(app.db, scope, query.limit, query.cursor);
|
|
9731
|
+
return {
|
|
9732
|
+
items: result.items.map((a) => ({
|
|
9733
|
+
...a,
|
|
9734
|
+
managerId: a.managerId ?? null,
|
|
9735
|
+
presenceStatus: a.presenceStatus ?? "offline",
|
|
9736
|
+
createdAt: a.createdAt.toISOString(),
|
|
9737
|
+
updatedAt: a.updatedAt.toISOString(),
|
|
9738
|
+
clientId: a.clientId ?? null,
|
|
9739
|
+
runtimeType: a.runtimeType ?? null,
|
|
9740
|
+
runtimeState: a.runtimeState ?? null,
|
|
9741
|
+
activeSessions: a.activeSessions ?? null
|
|
9742
|
+
})),
|
|
9743
|
+
nextCursor: result.nextCursor
|
|
9744
|
+
};
|
|
9745
|
+
});
|
|
6830
9746
|
app.post("/", async (request, reply) => {
|
|
6831
9747
|
const scope = memberScope(request);
|
|
6832
9748
|
const body = createAgentSchema.parse(request.body);
|
|
@@ -7113,6 +10029,24 @@ async function adminChatRoutes(app) {
|
|
|
7113
10029
|
}))
|
|
7114
10030
|
};
|
|
7115
10031
|
});
|
|
10032
|
+
/** Rename (or clear) a chat's topic. Requires participation or supervision — same gate as reading it. */
|
|
10033
|
+
app.patch("/:chatId", async (request) => {
|
|
10034
|
+
const { chatId } = request.params;
|
|
10035
|
+
const scope = memberScope(request);
|
|
10036
|
+
await assertChatAccess(app.db, scope, chatId);
|
|
10037
|
+
const body = updateChatSchema.parse(request.body);
|
|
10038
|
+
const nextTopic = body.topic && body.topic.length > 0 ? body.topic : null;
|
|
10039
|
+
const [updated] = await app.db.update(chats).set({
|
|
10040
|
+
topic: nextTopic,
|
|
10041
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
10042
|
+
}).where(eq(chats.id, chatId)).returning();
|
|
10043
|
+
if (!updated) throw new Error("Unexpected: chat missing after update");
|
|
10044
|
+
return {
|
|
10045
|
+
...updated,
|
|
10046
|
+
createdAt: updated.createdAt.toISOString(),
|
|
10047
|
+
updatedAt: updated.updatedAt.toISOString()
|
|
10048
|
+
};
|
|
10049
|
+
});
|
|
7116
10050
|
/** List messages in a chat with delivery status (requires participation or supervision) */
|
|
7117
10051
|
app.get("/:chatId/messages", async (request) => {
|
|
7118
10052
|
const { chatId } = request.params;
|
|
@@ -7232,10 +10166,18 @@ const agentChatSessions = pgTable("agent_chat_sessions", {
|
|
|
7232
10166
|
state: text("state").notNull(),
|
|
7233
10167
|
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow()
|
|
7234
10168
|
}, (table) => [primaryKey({ columns: [table.agentId, table.chatId] })]);
|
|
7235
|
-
/**
|
|
10169
|
+
/**
|
|
10170
|
+
* Upsert session state + refresh presence aggregates + NOTIFY.
|
|
10171
|
+
*
|
|
10172
|
+
* Revival defense: an admin-terminated (`evicted`) row is immutable; a client
|
|
10173
|
+
* report for the same chatId is silently dropped after the FOR UPDATE check.
|
|
10174
|
+
*/
|
|
7236
10175
|
async function upsertSessionState(db, agentId, chatId, state, organizationId, notifier) {
|
|
7237
10176
|
const now = /* @__PURE__ */ new Date();
|
|
10177
|
+
let wrote = false;
|
|
7238
10178
|
await db.transaction(async (tx) => {
|
|
10179
|
+
const [existing] = await tx.select({ state: agentChatSessions.state }).from(agentChatSessions).where(and(eq(agentChatSessions.agentId, agentId), eq(agentChatSessions.chatId, chatId))).for("update");
|
|
10180
|
+
if (existing?.state === "evicted") return;
|
|
7239
10181
|
await tx.insert(agentChatSessions).values({
|
|
7240
10182
|
agentId,
|
|
7241
10183
|
chatId,
|
|
@@ -7259,8 +10201,9 @@ async function upsertSessionState(db, agentId, chatId, state, organizationId, no
|
|
|
7259
10201
|
totalSessions,
|
|
7260
10202
|
lastSeenAt: now
|
|
7261
10203
|
}).where(eq(agentPresence.agentId, agentId));
|
|
10204
|
+
wrote = true;
|
|
7262
10205
|
});
|
|
7263
|
-
if (notifier) notifier.notifySessionStateChange(agentId, chatId, state, organizationId).catch(() => {});
|
|
10206
|
+
if (wrote && notifier) notifier.notifySessionStateChange(agentId, chatId, state, organizationId).catch(() => {});
|
|
7264
10207
|
}
|
|
7265
10208
|
async function resetActivity(db, agentId) {
|
|
7266
10209
|
const now = /* @__PURE__ */ new Date();
|
|
@@ -7313,22 +10256,6 @@ async function listAgentsWithRuntime(db, scope) {
|
|
|
7313
10256
|
type: agents.type
|
|
7314
10257
|
}).from(agentPresence).innerJoin(agents, eq(agentPresence.agentId, agents.uuid)).where(and(isNotNull(agentPresence.runtimeState), agentVisibilityCondition(scope)));
|
|
7315
10258
|
}
|
|
7316
|
-
/**
|
|
7317
|
-
* Clean up stale session rows from agent_chat_sessions.
|
|
7318
|
-
* Removes evicted rows older than staleSeconds and suspended rows older than staleSeconds.
|
|
7319
|
-
* Returns the number of rows deleted.
|
|
7320
|
-
*/
|
|
7321
|
-
async function cleanupStaleSessions(db, staleSeconds = 604800) {
|
|
7322
|
-
return (await db.execute(sql`
|
|
7323
|
-
WITH deleted AS (
|
|
7324
|
-
DELETE FROM agent_chat_sessions
|
|
7325
|
-
WHERE state IN ('evicted', 'suspended')
|
|
7326
|
-
AND updated_at < NOW() - make_interval(secs => ${staleSeconds})
|
|
7327
|
-
RETURNING 1
|
|
7328
|
-
)
|
|
7329
|
-
SELECT count(*)::int AS cnt FROM deleted
|
|
7330
|
-
`))[0]?.cnt ?? 0;
|
|
7331
|
-
}
|
|
7332
10259
|
/** Serialize a Date to ISO string, or null. */
|
|
7333
10260
|
function serializeDate(d) {
|
|
7334
10261
|
return d ? d.toISOString() : null;
|
|
@@ -7336,7 +10263,11 @@ function serializeDate(d) {
|
|
|
7336
10263
|
async function adminClientRoutes(app) {
|
|
7337
10264
|
app.get("/", async (request) => {
|
|
7338
10265
|
const scope = memberScope(request);
|
|
7339
|
-
return (await listClients(app.db,
|
|
10266
|
+
return (await listClients(app.db, {
|
|
10267
|
+
userId: scope.userId,
|
|
10268
|
+
organizationId: scope.organizationId,
|
|
10269
|
+
role: scope.role
|
|
10270
|
+
})).map((c) => ({
|
|
7340
10271
|
id: c.id,
|
|
7341
10272
|
userId: c.userId,
|
|
7342
10273
|
status: c.status,
|
|
@@ -7350,7 +10281,7 @@ async function adminClientRoutes(app) {
|
|
|
7350
10281
|
});
|
|
7351
10282
|
app.get("/:clientId", async (request) => {
|
|
7352
10283
|
const scope = memberScope(request);
|
|
7353
|
-
await assertClientOwner(app.db, request.params.clientId, scope
|
|
10284
|
+
await assertClientOwner(app.db, request.params.clientId, scope);
|
|
7354
10285
|
const client = await getClient(app.db, request.params.clientId);
|
|
7355
10286
|
if (!client) throw new Error("unreachable: client missing after owner check");
|
|
7356
10287
|
return {
|
|
@@ -7367,7 +10298,7 @@ async function adminClientRoutes(app) {
|
|
|
7367
10298
|
app.post("/:clientId/disconnect", async (request) => {
|
|
7368
10299
|
const scope = memberScope(request);
|
|
7369
10300
|
const { clientId } = request.params;
|
|
7370
|
-
await assertClientOwner(app.db, clientId, scope
|
|
10301
|
+
await assertClientOwner(app.db, clientId, scope);
|
|
7371
10302
|
const agentIds = forceDisconnectClient(clientId);
|
|
7372
10303
|
await disconnectClient(app.db, clientId);
|
|
7373
10304
|
return {
|
|
@@ -7378,7 +10309,7 @@ async function adminClientRoutes(app) {
|
|
|
7378
10309
|
app.delete("/:clientId", async (request, reply) => {
|
|
7379
10310
|
const scope = memberScope(request);
|
|
7380
10311
|
const { clientId } = request.params;
|
|
7381
|
-
await assertClientOwner(app.db, clientId, scope
|
|
10312
|
+
await assertClientOwner(app.db, clientId, scope);
|
|
7382
10313
|
await retireClient(app.db, clientId);
|
|
7383
10314
|
forceDisconnectClient(clientId);
|
|
7384
10315
|
await disconnectClient(app.db, clientId);
|
|
@@ -7658,16 +10589,26 @@ async function adminOverviewRoutes(app) {
|
|
|
7658
10589
|
};
|
|
7659
10590
|
});
|
|
7660
10591
|
}
|
|
10592
|
+
const SUMMARY_MAX_LENGTH = 50;
|
|
10593
|
+
/** Extract a plain-text summary from a message's JSONB content field. */
|
|
10594
|
+
function extractSummary(content, maxLen = SUMMARY_MAX_LENGTH) {
|
|
10595
|
+
let text = "";
|
|
10596
|
+
if (typeof content === "object" && content !== null && "text" in content) text = String(content.text ?? "");
|
|
10597
|
+
else if (typeof content === "string") text = content;
|
|
10598
|
+
return text ? text.slice(0, maxLen) : null;
|
|
10599
|
+
}
|
|
7661
10600
|
/** List sessions for a specific agent, with optional state filters. */
|
|
7662
10601
|
async function listAgentSessions(db, agentId, filters) {
|
|
7663
10602
|
const conditions = [eq(agentChatSessions.agentId, agentId)];
|
|
7664
10603
|
if (filters?.state) conditions.push(eq(agentChatSessions.state, filters.state));
|
|
10604
|
+
else conditions.push(ne(agentChatSessions.state, "evicted"));
|
|
7665
10605
|
const rows = await db.select({
|
|
7666
10606
|
agentId: agentChatSessions.agentId,
|
|
7667
10607
|
chatId: agentChatSessions.chatId,
|
|
7668
10608
|
state: agentChatSessions.state,
|
|
7669
10609
|
updatedAt: agentChatSessions.updatedAt,
|
|
7670
|
-
chatCreatedAt: chats.createdAt
|
|
10610
|
+
chatCreatedAt: chats.createdAt,
|
|
10611
|
+
chatTopic: chats.topic
|
|
7671
10612
|
}).from(agentChatSessions).innerJoin(chats, eq(agentChatSessions.chatId, chats.id)).where(and(...conditions)).orderBy(desc(agentChatSessions.updatedAt));
|
|
7672
10613
|
const [presence] = await db.select({ runtimeState: agentPresence.runtimeState }).from(agentPresence).where(eq(agentPresence.agentId, agentId)).limit(1);
|
|
7673
10614
|
const agentRuntimeState = presence?.runtimeState ?? null;
|
|
@@ -7678,6 +10619,15 @@ async function listAgentSessions(db, agentId, filters) {
|
|
|
7678
10619
|
count: sql`count(*)::int`
|
|
7679
10620
|
}).from(inboxEntries).where(and(eq(inboxEntries.inboxId, sql`(SELECT inbox_id FROM agents WHERE uuid = ${agentId})`), inArray(inboxEntries.chatId, chatIds))).groupBy(inboxEntries.chatId) : [];
|
|
7680
10621
|
const countMap = new Map(messageCounts.map((r) => [r.chatId, r.count]));
|
|
10622
|
+
const firstMessages = chatIds.length > 0 ? await db.selectDistinctOn([messages.chatId], {
|
|
10623
|
+
chatId: messages.chatId,
|
|
10624
|
+
content: messages.content
|
|
10625
|
+
}).from(messages).where(inArray(messages.chatId, chatIds)).orderBy(messages.chatId, messages.createdAt) : [];
|
|
10626
|
+
const summaryMap = /* @__PURE__ */ new Map();
|
|
10627
|
+
for (const row of firstMessages) {
|
|
10628
|
+
const summary = extractSummary(row.content);
|
|
10629
|
+
if (summary) summaryMap.set(row.chatId, summary);
|
|
10630
|
+
}
|
|
7681
10631
|
return rows.map((r) => ({
|
|
7682
10632
|
agentId: r.agentId,
|
|
7683
10633
|
chatId: r.chatId,
|
|
@@ -7685,7 +10635,9 @@ async function listAgentSessions(db, agentId, filters) {
|
|
|
7685
10635
|
runtimeState: agentRuntimeState,
|
|
7686
10636
|
startedAt: r.chatCreatedAt.toISOString(),
|
|
7687
10637
|
lastActivityAt: r.updatedAt.toISOString(),
|
|
7688
|
-
messageCount: countMap.get(r.chatId) ?? 0
|
|
10638
|
+
messageCount: countMap.get(r.chatId) ?? 0,
|
|
10639
|
+
summary: summaryMap.get(r.chatId) ?? null,
|
|
10640
|
+
topic: r.chatTopic ?? null
|
|
7689
10641
|
}));
|
|
7690
10642
|
}
|
|
7691
10643
|
/** Get a single session's detail. */
|
|
@@ -7695,11 +10647,14 @@ async function getSession(db, agentId, chatId) {
|
|
|
7695
10647
|
chatId: agentChatSessions.chatId,
|
|
7696
10648
|
state: agentChatSessions.state,
|
|
7697
10649
|
updatedAt: agentChatSessions.updatedAt,
|
|
7698
|
-
chatCreatedAt: chats.createdAt
|
|
10650
|
+
chatCreatedAt: chats.createdAt,
|
|
10651
|
+
chatTopic: chats.topic
|
|
7699
10652
|
}).from(agentChatSessions).innerJoin(chats, eq(agentChatSessions.chatId, chats.id)).where(and(eq(agentChatSessions.agentId, agentId), eq(agentChatSessions.chatId, chatId))).limit(1);
|
|
7700
10653
|
if (!row) throw new NotFoundError(`Session (${agentId}, ${chatId}) not found`);
|
|
7701
10654
|
const [presence] = await db.select({ runtimeState: agentPresence.runtimeState }).from(agentPresence).where(eq(agentPresence.agentId, agentId)).limit(1);
|
|
7702
10655
|
const [countRow] = await db.select({ count: sql`count(*)::int` }).from(inboxEntries).where(and(eq(inboxEntries.inboxId, sql`(SELECT inbox_id FROM agents WHERE uuid = ${agentId})`), eq(inboxEntries.chatId, chatId)));
|
|
10656
|
+
const firstMsg = (await db.execute(sql`SELECT content FROM messages WHERE chat_id = ${chatId} ORDER BY created_at ASC LIMIT 1`))[0];
|
|
10657
|
+
const summary = firstMsg ? extractSummary(firstMsg.content) : null;
|
|
7703
10658
|
return {
|
|
7704
10659
|
agentId: row.agentId,
|
|
7705
10660
|
chatId: row.chatId,
|
|
@@ -7707,13 +10662,16 @@ async function getSession(db, agentId, chatId) {
|
|
|
7707
10662
|
runtimeState: presence?.runtimeState ?? null,
|
|
7708
10663
|
startedAt: row.chatCreatedAt.toISOString(),
|
|
7709
10664
|
lastActivityAt: row.updatedAt.toISOString(),
|
|
7710
|
-
messageCount: countRow?.count ?? 0
|
|
10665
|
+
messageCount: countRow?.count ?? 0,
|
|
10666
|
+
summary,
|
|
10667
|
+
topic: row.chatTopic ?? null
|
|
7711
10668
|
};
|
|
7712
10669
|
}
|
|
7713
10670
|
/** List all sessions across all agents, with pagination. Scoped to organization. */
|
|
7714
10671
|
async function listAllSessions(db, limit, cursor, filters) {
|
|
7715
10672
|
const conditions = [];
|
|
7716
10673
|
if (filters?.state) conditions.push(eq(agentChatSessions.state, filters.state));
|
|
10674
|
+
else conditions.push(ne(agentChatSessions.state, "evicted"));
|
|
7717
10675
|
if (filters?.agentId) conditions.push(eq(agentChatSessions.agentId, filters.agentId));
|
|
7718
10676
|
if (filters?.organizationId) conditions.push(eq(agents.organizationId, filters.organizationId));
|
|
7719
10677
|
if (cursor) conditions.push(sql`${agentChatSessions.updatedAt} < ${new Date(cursor)}`);
|
|
@@ -7742,11 +10700,54 @@ async function listAllSessions(db, limit, cursor, filters) {
|
|
|
7742
10700
|
runtimeState: runtimeMap.get(r.agentId) ?? null,
|
|
7743
10701
|
startedAt: r.chatCreatedAt.toISOString(),
|
|
7744
10702
|
lastActivityAt: r.updatedAt.toISOString(),
|
|
7745
|
-
messageCount: 0
|
|
10703
|
+
messageCount: 0,
|
|
10704
|
+
summary: null,
|
|
10705
|
+
topic: null
|
|
7746
10706
|
})),
|
|
7747
10707
|
nextCursor
|
|
7748
10708
|
};
|
|
7749
10709
|
}
|
|
10710
|
+
/** Commit `active → suspended`. No-op on suspended/evicted. Throws if row is missing. */
|
|
10711
|
+
async function suspendSession(db, agentId, chatId, organizationId, notifier) {
|
|
10712
|
+
return transitionSessionState(db, agentId, chatId, "suspended", ["active"], organizationId, notifier);
|
|
10713
|
+
}
|
|
10714
|
+
/** Commit `suspended → evicted` (terminal — listings hide it, revival defense blocks resurrection). */
|
|
10715
|
+
async function archiveSession(db, agentId, chatId, organizationId, notifier) {
|
|
10716
|
+
return transitionSessionState(db, agentId, chatId, "evicted", ["suspended"], organizationId, notifier);
|
|
10717
|
+
}
|
|
10718
|
+
async function transitionSessionState(db, agentId, chatId, target, from, organizationId, notifier) {
|
|
10719
|
+
const now = /* @__PURE__ */ new Date();
|
|
10720
|
+
let finalState = null;
|
|
10721
|
+
let transitioned = false;
|
|
10722
|
+
await db.transaction(async (tx) => {
|
|
10723
|
+
const [existing] = await tx.select({ state: agentChatSessions.state }).from(agentChatSessions).where(and(eq(agentChatSessions.agentId, agentId), eq(agentChatSessions.chatId, chatId))).for("update");
|
|
10724
|
+
if (!existing) return;
|
|
10725
|
+
const current = existing.state;
|
|
10726
|
+
finalState = current;
|
|
10727
|
+
if (!from.includes(current)) return;
|
|
10728
|
+
await tx.update(agentChatSessions).set({
|
|
10729
|
+
state: target,
|
|
10730
|
+
updatedAt: now
|
|
10731
|
+
}).where(and(eq(agentChatSessions.agentId, agentId), eq(agentChatSessions.chatId, chatId)));
|
|
10732
|
+
const [counts] = await tx.select({
|
|
10733
|
+
active: sql`count(*) FILTER (WHERE ${agentChatSessions.state} = 'active')::int`,
|
|
10734
|
+
total: sql`count(*) FILTER (WHERE ${agentChatSessions.state} != 'evicted')::int`
|
|
10735
|
+
}).from(agentChatSessions).where(eq(agentChatSessions.agentId, agentId));
|
|
10736
|
+
await tx.update(agentPresence).set({
|
|
10737
|
+
activeSessions: counts?.active ?? 0,
|
|
10738
|
+
totalSessions: counts?.total ?? 0,
|
|
10739
|
+
lastSeenAt: now
|
|
10740
|
+
}).where(eq(agentPresence.agentId, agentId));
|
|
10741
|
+
finalState = target;
|
|
10742
|
+
transitioned = true;
|
|
10743
|
+
});
|
|
10744
|
+
if (finalState === null) throw new NotFoundError(`Session (${agentId}, ${chatId}) not found`);
|
|
10745
|
+
if (transitioned && notifier) notifier.notifySessionStateChange(agentId, chatId, target, organizationId).catch(() => {});
|
|
10746
|
+
return {
|
|
10747
|
+
state: finalState,
|
|
10748
|
+
transitioned
|
|
10749
|
+
};
|
|
10750
|
+
}
|
|
7750
10751
|
/**
|
|
7751
10752
|
* Filter sessions to only those where the given agent is also a participant in the chat.
|
|
7752
10753
|
* Used when a non-manager views sessions of an org-visible agent — they should only see
|
|
@@ -7927,49 +10928,41 @@ async function adminSessionRoutes(app) {
|
|
|
7927
10928
|
direction
|
|
7928
10929
|
});
|
|
7929
10930
|
});
|
|
7930
|
-
/** POST /admin/sessions/agents/:agentId/:chatId/suspend —
|
|
10931
|
+
/** POST /admin/sessions/agents/:agentId/:chatId/suspend — commit first, WS-send best-effort. */
|
|
7931
10932
|
app.post("/agents/:agentId/:chatId/suspend", async (request, reply) => {
|
|
7932
10933
|
const { agentId, chatId } = request.params;
|
|
7933
10934
|
await assertCanManage(app.db, memberScope(request), agentId);
|
|
7934
|
-
|
|
10935
|
+
const member = requireMember(request);
|
|
10936
|
+
const result = await suspendSession(app.db, agentId, chatId, member.organizationId, app.notifier);
|
|
10937
|
+
if (result.transitioned) sendToAgent$1(agentId, {
|
|
7935
10938
|
type: "session:suspend",
|
|
7936
10939
|
chatId
|
|
7937
|
-
})) throw new ConflictError("Agent is not connected — session command requires a live connection");
|
|
7938
|
-
return reply.status(202).send({
|
|
7939
|
-
status: "sent",
|
|
7940
|
-
command: "suspend",
|
|
7941
|
-
agentId,
|
|
7942
|
-
chatId
|
|
7943
10940
|
});
|
|
7944
|
-
|
|
7945
|
-
/** POST /admin/sessions/agents/:agentId/:chatId/resume — resume a session */
|
|
7946
|
-
app.post("/agents/:agentId/:chatId/resume", async (request, reply) => {
|
|
7947
|
-
const { agentId, chatId } = request.params;
|
|
7948
|
-
await assertCanManage(app.db, memberScope(request), agentId);
|
|
7949
|
-
if (!sendToAgent$1(agentId, {
|
|
7950
|
-
type: "session:resume",
|
|
7951
|
-
chatId
|
|
7952
|
-
})) throw new ConflictError("Agent is not connected — session command requires a live connection");
|
|
7953
|
-
return reply.status(202).send({
|
|
7954
|
-
status: "sent",
|
|
7955
|
-
command: "resume",
|
|
10941
|
+
return reply.status(200).send({
|
|
7956
10942
|
agentId,
|
|
7957
|
-
chatId
|
|
10943
|
+
chatId,
|
|
10944
|
+
state: result.state,
|
|
10945
|
+
transitioned: result.transitioned
|
|
7958
10946
|
});
|
|
7959
10947
|
});
|
|
7960
|
-
/** POST /admin/sessions/agents/:agentId/:chatId/terminate —
|
|
10948
|
+
/** POST /admin/sessions/agents/:agentId/:chatId/terminate — archive; clear events + best-effort WS. */
|
|
7961
10949
|
app.post("/agents/:agentId/:chatId/terminate", async (request, reply) => {
|
|
7962
10950
|
const { agentId, chatId } = request.params;
|
|
7963
10951
|
await assertCanManage(app.db, memberScope(request), agentId);
|
|
7964
|
-
|
|
7965
|
-
|
|
7966
|
-
|
|
7967
|
-
|
|
7968
|
-
|
|
7969
|
-
|
|
7970
|
-
|
|
10952
|
+
const member = requireMember(request);
|
|
10953
|
+
const result = await archiveSession(app.db, agentId, chatId, member.organizationId, app.notifier);
|
|
10954
|
+
if (result.transitioned) {
|
|
10955
|
+
clearEvents(app.db, agentId, chatId).catch(() => {});
|
|
10956
|
+
sendToAgent$1(agentId, {
|
|
10957
|
+
type: "session:terminate",
|
|
10958
|
+
chatId
|
|
10959
|
+
});
|
|
10960
|
+
}
|
|
10961
|
+
return reply.status(200).send({
|
|
7971
10962
|
agentId,
|
|
7972
|
-
chatId
|
|
10963
|
+
chatId,
|
|
10964
|
+
state: result.state,
|
|
10965
|
+
transitioned: result.transitioned
|
|
7973
10966
|
});
|
|
7974
10967
|
});
|
|
7975
10968
|
}
|
|
@@ -8532,6 +11525,99 @@ async function adminTaskRoutes(app) {
|
|
|
8532
11525
|
return getTaskHealth(app.db, request.params.taskId);
|
|
8533
11526
|
});
|
|
8534
11527
|
}
|
|
11528
|
+
const UPLOADS_DIR = join(DEFAULT_DATA_DIR$1, "uploads");
|
|
11529
|
+
const MAX_FILE_SIZE = 10 * 1024 * 1024;
|
|
11530
|
+
const ALLOWED_MIME_TYPES = new Set([
|
|
11531
|
+
"image/png",
|
|
11532
|
+
"image/jpeg",
|
|
11533
|
+
"image/gif",
|
|
11534
|
+
"image/webp",
|
|
11535
|
+
"image/svg+xml"
|
|
11536
|
+
]);
|
|
11537
|
+
function ensureUploadsDir() {
|
|
11538
|
+
if (!existsSync(UPLOADS_DIR)) mkdirSync(UPLOADS_DIR, { recursive: true });
|
|
11539
|
+
}
|
|
11540
|
+
async function adminUploadRoutes(app) {
|
|
11541
|
+
ensureUploadsDir();
|
|
11542
|
+
/** POST /admin/uploads — upload a file, returns URL */
|
|
11543
|
+
app.post("/", async (request, reply) => {
|
|
11544
|
+
requireMember(request);
|
|
11545
|
+
const data = await request.file();
|
|
11546
|
+
if (!data) return reply.status(400).send({ error: "No file provided" });
|
|
11547
|
+
const mimeType = data.mimetype;
|
|
11548
|
+
if (!ALLOWED_MIME_TYPES.has(mimeType)) return reply.status(400).send({ error: `Unsupported file type: ${mimeType}. Allowed: ${[...ALLOWED_MIME_TYPES].join(", ")}` });
|
|
11549
|
+
const ext = extname(data.filename) || mimeExtension(mimeType);
|
|
11550
|
+
const uniqueName = `${(/* @__PURE__ */ new Date()).toISOString().replace(/[-:T]/g, "").slice(0, 14)}_${randomUUID().slice(0, 8)}${ext}`;
|
|
11551
|
+
const filePath = join(UPLOADS_DIR, uniqueName);
|
|
11552
|
+
let totalSize = 0;
|
|
11553
|
+
const writeStream = createWriteStream(filePath);
|
|
11554
|
+
try {
|
|
11555
|
+
const fileStream = data.file;
|
|
11556
|
+
for await (const chunk of fileStream) {
|
|
11557
|
+
totalSize += chunk.length;
|
|
11558
|
+
if (totalSize > MAX_FILE_SIZE) {
|
|
11559
|
+
writeStream.destroy();
|
|
11560
|
+
try {
|
|
11561
|
+
unlinkSync(filePath);
|
|
11562
|
+
} catch {}
|
|
11563
|
+
return reply.status(400).send({ error: `File too large. Maximum size: ${MAX_FILE_SIZE / 1024 / 1024}MB` });
|
|
11564
|
+
}
|
|
11565
|
+
writeStream.write(chunk);
|
|
11566
|
+
}
|
|
11567
|
+
writeStream.end();
|
|
11568
|
+
await new Promise((resolve, reject) => {
|
|
11569
|
+
writeStream.on("finish", resolve);
|
|
11570
|
+
writeStream.on("error", reject);
|
|
11571
|
+
});
|
|
11572
|
+
} catch (err) {
|
|
11573
|
+
writeStream.destroy();
|
|
11574
|
+
throw err;
|
|
11575
|
+
}
|
|
11576
|
+
const url = `/api/v1/uploads/${uniqueName}`;
|
|
11577
|
+
return reply.status(201).send({
|
|
11578
|
+
url,
|
|
11579
|
+
filename: data.filename,
|
|
11580
|
+
storedName: uniqueName,
|
|
11581
|
+
mimeType,
|
|
11582
|
+
size: totalSize
|
|
11583
|
+
});
|
|
11584
|
+
});
|
|
11585
|
+
}
|
|
11586
|
+
/** Public routes — GET uploaded files (URL contains random UUID, not guessable) */
|
|
11587
|
+
async function publicUploadRoutes(app) {
|
|
11588
|
+
ensureUploadsDir();
|
|
11589
|
+
/** GET /uploads/:filename — serve uploaded file without auth */
|
|
11590
|
+
app.get("/:filename", async (request, reply) => {
|
|
11591
|
+
const { filename } = request.params;
|
|
11592
|
+
if (filename.includes("/") || filename.includes("..")) return reply.status(400).send({ error: "Invalid filename" });
|
|
11593
|
+
const filePath = join(UPLOADS_DIR, filename);
|
|
11594
|
+
if (!existsSync(filePath)) return reply.status(404).send({ error: "File not found" });
|
|
11595
|
+
const contentType = extensionToMime(extname(filename).toLowerCase()) ?? "application/octet-stream";
|
|
11596
|
+
const stream = createReadStream(filePath);
|
|
11597
|
+
return reply.type(contentType).send(stream);
|
|
11598
|
+
});
|
|
11599
|
+
}
|
|
11600
|
+
function mimeExtension(mime) {
|
|
11601
|
+
switch (mime) {
|
|
11602
|
+
case "image/png": return ".png";
|
|
11603
|
+
case "image/jpeg": return ".jpg";
|
|
11604
|
+
case "image/gif": return ".gif";
|
|
11605
|
+
case "image/webp": return ".webp";
|
|
11606
|
+
case "image/svg+xml": return ".svg";
|
|
11607
|
+
default: return "";
|
|
11608
|
+
}
|
|
11609
|
+
}
|
|
11610
|
+
function extensionToMime(ext) {
|
|
11611
|
+
switch (ext) {
|
|
11612
|
+
case ".png": return "image/png";
|
|
11613
|
+
case ".jpg":
|
|
11614
|
+
case ".jpeg": return "image/jpeg";
|
|
11615
|
+
case ".gif": return "image/gif";
|
|
11616
|
+
case ".webp": return "image/webp";
|
|
11617
|
+
case ".svg": return "image/svg+xml";
|
|
11618
|
+
default: return null;
|
|
11619
|
+
}
|
|
11620
|
+
}
|
|
8535
11621
|
async function loadVisibleAgentIds(db, organizationId, memberId) {
|
|
8536
11622
|
const rows = await db.select({ id: agents.uuid }).from(agents).where(and(eq(agents.organizationId, organizationId), ne(agents.status, AGENT_STATUSES.DELETED), or(eq(agents.visibility, AGENT_VISIBILITY.ORGANIZATION), eq(agents.managerId, memberId))));
|
|
8537
11623
|
return new Set(rows.map((r) => r.id));
|
|
@@ -9418,9 +12504,47 @@ function clientWsRoutes(notifier, instanceId) {
|
|
|
9418
12504
|
}));
|
|
9419
12505
|
return;
|
|
9420
12506
|
}
|
|
9421
|
-
const
|
|
9422
|
-
if (
|
|
9423
|
-
|
|
12507
|
+
const payloadResult = sessionStateMessageSchema.safeParse(msg);
|
|
12508
|
+
if (!payloadResult.success) {
|
|
12509
|
+
socket.send(JSON.stringify({
|
|
12510
|
+
type: "error",
|
|
12511
|
+
message: "Unsupported session state from client; client upgrade required"
|
|
12512
|
+
}));
|
|
12513
|
+
const rawState = msg.state;
|
|
12514
|
+
app.log.warn({
|
|
12515
|
+
clientId,
|
|
12516
|
+
agentId,
|
|
12517
|
+
rawState
|
|
12518
|
+
}, "session:state rejected — stale client wire");
|
|
12519
|
+
return;
|
|
12520
|
+
}
|
|
12521
|
+
await upsertSessionState(app.db, agentId, payloadResult.data.chatId, payloadResult.data.state, session.organizationId, notifier);
|
|
12522
|
+
} else if (type === "session:reconcile") {
|
|
12523
|
+
const agentId = parsed.data.agentId;
|
|
12524
|
+
if (!agentId || !boundAgents.has(agentId)) {
|
|
12525
|
+
socket.send(JSON.stringify({
|
|
12526
|
+
type: "error",
|
|
12527
|
+
message: "Agent not bound"
|
|
12528
|
+
}));
|
|
12529
|
+
return;
|
|
12530
|
+
}
|
|
12531
|
+
const payloadResult = sessionReconcileRequestSchema.safeParse(msg);
|
|
12532
|
+
if (!payloadResult.success) {
|
|
12533
|
+
socket.send(JSON.stringify({
|
|
12534
|
+
type: "error",
|
|
12535
|
+
message: "Malformed session:reconcile frame"
|
|
12536
|
+
}));
|
|
12537
|
+
return;
|
|
12538
|
+
}
|
|
12539
|
+
const { chatIds } = payloadResult.data;
|
|
12540
|
+
const aliveRows = chatIds.length ? await app.db.select({ chatId: agentChatSessions.chatId }).from(agentChatSessions).where(and(eq(agentChatSessions.agentId, agentId), inArray(agentChatSessions.chatId, chatIds), ne(agentChatSessions.state, "evicted"))) : [];
|
|
12541
|
+
const alive = new Set(aliveRows.map((r) => r.chatId));
|
|
12542
|
+
const staleChatIds = chatIds.filter((id) => !alive.has(id));
|
|
12543
|
+
socket.send(JSON.stringify({
|
|
12544
|
+
type: "session:reconcile:result",
|
|
12545
|
+
agentId,
|
|
12546
|
+
staleChatIds
|
|
12547
|
+
}));
|
|
9424
12548
|
} else if (type === "runtime:state") {
|
|
9425
12549
|
const agentId = parsed.data.agentId;
|
|
9426
12550
|
if (!agentId || !boundAgents.has(agentId)) {
|
|
@@ -9839,14 +12963,18 @@ async function getMember(db, id) {
|
|
|
9839
12963
|
createdAt: row.createdAt.toISOString()
|
|
9840
12964
|
};
|
|
9841
12965
|
}
|
|
9842
|
-
async function updateMember(db, id, data) {
|
|
9843
|
-
if (
|
|
9844
|
-
|
|
9845
|
-
|
|
9846
|
-
|
|
9847
|
-
|
|
9848
|
-
|
|
9849
|
-
|
|
12966
|
+
async function updateMember(db, id, data, callerOrgId) {
|
|
12967
|
+
if (data.role === void 0 && data.displayName === void 0) return getMember(db, id);
|
|
12968
|
+
const current = await getMember(db, id);
|
|
12969
|
+
if (callerOrgId && current.organizationId !== callerOrgId) throw new NotFoundError(`Member "${id}" not found`);
|
|
12970
|
+
if (data.role === "member" && current.role === "admin") await assertNotLastAdmin(db, current.organizationId, id);
|
|
12971
|
+
await db.transaction(async (tx) => {
|
|
12972
|
+
if (data.role !== void 0 && data.role !== current.role) await tx.update(members).set({ role: data.role }).where(eq(members.id, id));
|
|
12973
|
+
if (data.displayName !== void 0 && data.displayName !== current.displayName) {
|
|
12974
|
+
await tx.update(users).set({ displayName: data.displayName }).where(eq(users.id, current.userId));
|
|
12975
|
+
await tx.update(agents).set({ displayName: data.displayName }).where(eq(agents.uuid, current.agentId));
|
|
12976
|
+
}
|
|
12977
|
+
});
|
|
9850
12978
|
return getMember(db, id);
|
|
9851
12979
|
}
|
|
9852
12980
|
async function deleteMember(db, id) {
|
|
@@ -9884,7 +13012,8 @@ async function memberRoutes(app) {
|
|
|
9884
13012
|
app.patch("/:id", async (request) => {
|
|
9885
13013
|
requireAdmin(request);
|
|
9886
13014
|
const body = updateMemberSchema.parse(request.body);
|
|
9887
|
-
|
|
13015
|
+
const m = requireMember(request);
|
|
13016
|
+
return updateMember(app.db, request.params.id, body, m.organizationId);
|
|
9888
13017
|
});
|
|
9889
13018
|
app.delete("/:id", async (request, reply) => {
|
|
9890
13019
|
requireAdmin(request);
|
|
@@ -10965,7 +14094,6 @@ function createBackgroundTasks(app, instanceId, adapterManager, kaelRuntime) {
|
|
|
10965
14094
|
let heartbeatTimer = null;
|
|
10966
14095
|
let adapterOutboundTimer = null;
|
|
10967
14096
|
let kaelOutboundTimer = null;
|
|
10968
|
-
let sessionCleanupTimer = null;
|
|
10969
14097
|
return {
|
|
10970
14098
|
start() {
|
|
10971
14099
|
inboxTimer = setInterval(async () => {
|
|
@@ -11010,14 +14138,6 @@ function createBackgroundTasks(app, instanceId, adapterManager, kaelRuntime) {
|
|
|
11010
14138
|
log.error({ err }, "kael outbound processing failed");
|
|
11011
14139
|
}
|
|
11012
14140
|
}, 5e3);
|
|
11013
|
-
sessionCleanupTimer = setInterval(async () => {
|
|
11014
|
-
try {
|
|
11015
|
-
const deleted = await cleanupStaleSessions(app.db);
|
|
11016
|
-
if (deleted > 0) log.info({ count: deleted }, "cleaned up stale sessions");
|
|
11017
|
-
} catch (err) {
|
|
11018
|
-
log.error({ err }, "failed to clean up stale sessions");
|
|
11019
|
-
}
|
|
11020
|
-
}, 36e5);
|
|
11021
14141
|
heartbeatInstance(app.db, instanceId).catch((err) => {
|
|
11022
14142
|
log.error({ err }, "failed initial heartbeat");
|
|
11023
14143
|
});
|
|
@@ -11039,10 +14159,6 @@ function createBackgroundTasks(app, instanceId, adapterManager, kaelRuntime) {
|
|
|
11039
14159
|
clearInterval(kaelOutboundTimer);
|
|
11040
14160
|
kaelOutboundTimer = null;
|
|
11041
14161
|
}
|
|
11042
|
-
if (sessionCleanupTimer) {
|
|
11043
|
-
clearInterval(sessionCleanupTimer);
|
|
11044
|
-
sessionCleanupTimer = null;
|
|
11045
|
-
}
|
|
11046
14162
|
}
|
|
11047
14163
|
};
|
|
11048
14164
|
}
|
|
@@ -11597,6 +14713,7 @@ async function buildApp(config) {
|
|
|
11597
14713
|
const listenClient = postgres(config.database.url, { max: 1 });
|
|
11598
14714
|
const notifier = createNotifier(listenClient);
|
|
11599
14715
|
await app.register(websocket);
|
|
14716
|
+
await app.register(import_multipart.default, { limits: { fileSize: 10 * 1024 * 1024 } });
|
|
11600
14717
|
const corsOrigin = config.cors?.origin;
|
|
11601
14718
|
const isDev = process.env.NODE_ENV !== "production";
|
|
11602
14719
|
await app.register(cors, {
|
|
@@ -11635,6 +14752,7 @@ async function buildApp(config) {
|
|
|
11635
14752
|
await api.register(authRoutes, { prefix: "/auth" });
|
|
11636
14753
|
await api.register(contextTreeInfoRoutes, { prefix: "/context-tree" });
|
|
11637
14754
|
await api.register(bootstrapConfigRoutes, { prefix: "/bootstrap" });
|
|
14755
|
+
await api.register(publicUploadRoutes, { prefix: "/uploads" });
|
|
11638
14756
|
await api.register(async (adminApp) => {
|
|
11639
14757
|
adminApp.addHook("onRequest", memberAuth);
|
|
11640
14758
|
await adminApp.register(adminAgentRoutes);
|
|
@@ -11659,17 +14777,14 @@ async function buildApp(config) {
|
|
|
11659
14777
|
}, { prefix: "/admin/overview" });
|
|
11660
14778
|
await api.register(async (adminApp) => {
|
|
11661
14779
|
adminApp.addHook("onRequest", memberAuth);
|
|
11662
|
-
adminApp.addHook("onRequest", adminOnly);
|
|
11663
14780
|
await adminApp.register(adminAdapterRoutes);
|
|
11664
14781
|
}, { prefix: "/admin/adapters" });
|
|
11665
14782
|
await api.register(async (adminApp) => {
|
|
11666
14783
|
adminApp.addHook("onRequest", memberAuth);
|
|
11667
|
-
adminApp.addHook("onRequest", adminOnly);
|
|
11668
14784
|
await adminApp.register(adminAdapterMappingRoutes);
|
|
11669
14785
|
}, { prefix: "/admin/adapter-mappings" });
|
|
11670
14786
|
await api.register(async (adminApp) => {
|
|
11671
14787
|
adminApp.addHook("onRequest", memberAuth);
|
|
11672
|
-
adminApp.addHook("onRequest", adminOnly);
|
|
11673
14788
|
await adminApp.register(adminAdapterStatusRoutes);
|
|
11674
14789
|
}, { prefix: "/admin/adapters/status" });
|
|
11675
14790
|
await api.register(async (memberApp) => {
|
|
@@ -11684,6 +14799,10 @@ async function buildApp(config) {
|
|
|
11684
14799
|
adminApp.addHook("onRequest", memberAuth);
|
|
11685
14800
|
await adminApp.register(adminChatRoutes);
|
|
11686
14801
|
}, { prefix: "/admin/chats" });
|
|
14802
|
+
await api.register(async (adminApp) => {
|
|
14803
|
+
adminApp.addHook("onRequest", memberAuth);
|
|
14804
|
+
await adminApp.register(adminUploadRoutes);
|
|
14805
|
+
}, { prefix: "/admin/uploads" });
|
|
11687
14806
|
await api.register(async (adminApp) => {
|
|
11688
14807
|
adminApp.addHook("onRequest", memberAuth);
|
|
11689
14808
|
await adminApp.register(adminClientRoutes);
|