@rogatio/cli 5.18.0 → 5.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/editor/index.js +56 -3
- package/dist/node/index.js +1683 -384
- package/package.json +1 -1
package/dist/node/index.js
CHANGED
|
@@ -1351,7 +1351,14 @@ function validateProjectDetailed(value) {
|
|
|
1351
1351
|
// packages/runtime/dist/node/index.js
|
|
1352
1352
|
import { isIP as isIP2 } from "node:net";
|
|
1353
1353
|
import { Buffer as Buffer2 } from "node:buffer";
|
|
1354
|
-
import {
|
|
1354
|
+
import { existsSync } from "node:fs";
|
|
1355
|
+
import { createServer as createServer2 } from "node:http";
|
|
1356
|
+
import { join as join3 } from "node:path";
|
|
1357
|
+
import {
|
|
1358
|
+
createServer
|
|
1359
|
+
} from "node:http";
|
|
1360
|
+
import { connect } from "node:net";
|
|
1361
|
+
import { Worker } from "node:worker_threads";
|
|
1355
1362
|
|
|
1356
1363
|
// packages/compiler/dist/node/index.js
|
|
1357
1364
|
var ISSUE_CODES = {
|
|
@@ -1717,11 +1724,11 @@ import { isAbsolute as isAbsolute2, relative as relative2, resolve, sep } from "
|
|
|
1717
1724
|
import { createHash as createHash2 } from "node:crypto";
|
|
1718
1725
|
import { mkdir as mkdir2, readFile as readFile3, rename, rm, stat as stat2, writeFile as writeFile2 } from "node:fs/promises";
|
|
1719
1726
|
import { basename, dirname as dirname2, isAbsolute as isAbsolute3, join as join2, relative as relative3 } from "node:path";
|
|
1720
|
-
import { generateKeyPairSync
|
|
1727
|
+
import { generateKeyPairSync, webcrypto } from "node:crypto";
|
|
1721
1728
|
import { spawn, spawnSync } from "node:child_process";
|
|
1722
1729
|
import { accessSync, constants as constants2, unlinkSync, writeFileSync } from "node:fs";
|
|
1723
1730
|
import { tmpdir } from "node:os";
|
|
1724
|
-
import { dirname as dirname3, join as
|
|
1731
|
+
import { dirname as dirname3, join as join4 } from "node:path";
|
|
1725
1732
|
import { join as posixJoin } from "node:path/posix";
|
|
1726
1733
|
import { spawn as spawn2, spawnSync as spawnSync2 } from "node:child_process";
|
|
1727
1734
|
import { accessSync as accessSync2, constants as constants3, mkdirSync, unlinkSync as unlinkSync2 } from "node:fs";
|
|
@@ -1730,7 +1737,7 @@ import { join as posixJoin2 } from "node:path/posix";
|
|
|
1730
1737
|
import { spawn as spawn3, spawnSync as spawnSync3 } from "node:child_process";
|
|
1731
1738
|
import { accessSync as accessSync3, constants as constants4, unlinkSync as unlinkSync3, writeFileSync as writeFileSync2 } from "node:fs";
|
|
1732
1739
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
1733
|
-
import { join as
|
|
1740
|
+
import { join as join5 } from "node:path";
|
|
1734
1741
|
import { join as posixJoin3 } from "node:path/posix";
|
|
1735
1742
|
var __create = Object.create;
|
|
1736
1743
|
var __defProp = Object.defineProperty;
|
|
@@ -20878,6 +20885,115 @@ function mergeProposalIntoProject(project, proposal) {
|
|
|
20878
20885
|
}
|
|
20879
20886
|
return { ...project, groups };
|
|
20880
20887
|
}
|
|
20888
|
+
var RULE_PATH_PATTERN = /^\/groups\/(0|[1-9][0-9]*)\/rules\/(0|[1-9][0-9]*)(?:\/|$)/;
|
|
20889
|
+
function repairTargetsFromDiagnostics(diagnostics) {
|
|
20890
|
+
if (!Array.isArray(diagnostics)) return [];
|
|
20891
|
+
const seen = /* @__PURE__ */ new Set();
|
|
20892
|
+
const targets = [];
|
|
20893
|
+
for (const diagnostic of diagnostics) {
|
|
20894
|
+
if (!isRecord(diagnostic) || typeof diagnostic.path !== "string") continue;
|
|
20895
|
+
const match = RULE_PATH_PATTERN.exec(diagnostic.path);
|
|
20896
|
+
if (!match) continue;
|
|
20897
|
+
const groupIndex = Number(match[1]);
|
|
20898
|
+
const ruleIndex = Number(match[2]);
|
|
20899
|
+
if (!Number.isSafeInteger(groupIndex) || !Number.isSafeInteger(ruleIndex)) {
|
|
20900
|
+
continue;
|
|
20901
|
+
}
|
|
20902
|
+
const key = `${groupIndex}/${ruleIndex}`;
|
|
20903
|
+
if (seen.has(key)) continue;
|
|
20904
|
+
seen.add(key);
|
|
20905
|
+
targets.push({ groupIndex, ruleIndex });
|
|
20906
|
+
}
|
|
20907
|
+
targets.sort(
|
|
20908
|
+
(left, right) => left.groupIndex - right.groupIndex || left.ruleIndex - right.ruleIndex
|
|
20909
|
+
);
|
|
20910
|
+
return targets;
|
|
20911
|
+
}
|
|
20912
|
+
var RULE_KINDS = /* @__PURE__ */ new Set([
|
|
20913
|
+
"redirect",
|
|
20914
|
+
"query",
|
|
20915
|
+
"header",
|
|
20916
|
+
"response-body",
|
|
20917
|
+
"request-body"
|
|
20918
|
+
]);
|
|
20919
|
+
function stringArray(value) {
|
|
20920
|
+
if (!Array.isArray(value)) return void 0;
|
|
20921
|
+
const items = value.filter(
|
|
20922
|
+
(item) => typeof item === "string"
|
|
20923
|
+
);
|
|
20924
|
+
return items.length === value.length ? items : void 0;
|
|
20925
|
+
}
|
|
20926
|
+
function parseProposalRule(value) {
|
|
20927
|
+
if (!isRecord(value)) return null;
|
|
20928
|
+
const kind = value.kind;
|
|
20929
|
+
if (typeof kind !== "string" || !RULE_KINDS.has(kind) || typeof value.groupId !== "string" || typeof value.name !== "string" || typeof value.urlRegex !== "string" || !Object.hasOwn(value, "action")) {
|
|
20930
|
+
return null;
|
|
20931
|
+
}
|
|
20932
|
+
return {
|
|
20933
|
+
kind,
|
|
20934
|
+
groupId: value.groupId,
|
|
20935
|
+
name: value.name,
|
|
20936
|
+
urlRegex: value.urlRegex,
|
|
20937
|
+
origins: stringArray(value.origins),
|
|
20938
|
+
resourceTypes: stringArray(value.resourceTypes),
|
|
20939
|
+
priority: typeof value.priority === "number" ? value.priority : void 0,
|
|
20940
|
+
method: typeof value.method === "string" ? value.method : void 0,
|
|
20941
|
+
action: value.action
|
|
20942
|
+
};
|
|
20943
|
+
}
|
|
20944
|
+
function repairProposalIntoProject(project, diagnostics, proposal) {
|
|
20945
|
+
const groups = Array.isArray(project.groups) ? project.groups.map((group) => {
|
|
20946
|
+
if (!isRecord(group)) {
|
|
20947
|
+
return { id: "invalid", name: "invalid", origins: [], rules: [] };
|
|
20948
|
+
}
|
|
20949
|
+
return {
|
|
20950
|
+
...group,
|
|
20951
|
+
rules: Array.isArray(group.rules) ? [...group.rules] : []
|
|
20952
|
+
};
|
|
20953
|
+
}) : [];
|
|
20954
|
+
const queues = /* @__PURE__ */ new Map();
|
|
20955
|
+
for (const target of repairTargetsFromDiagnostics(diagnostics)) {
|
|
20956
|
+
const group = groups[target.groupIndex];
|
|
20957
|
+
if (!group) continue;
|
|
20958
|
+
const rules = group.rules;
|
|
20959
|
+
if (target.ruleIndex >= rules.length) continue;
|
|
20960
|
+
if (!isRecord(rules[target.ruleIndex])) continue;
|
|
20961
|
+
const queue = queues.get(target.groupIndex) ?? [];
|
|
20962
|
+
queue.push(target.ruleIndex);
|
|
20963
|
+
queues.set(target.groupIndex, queue);
|
|
20964
|
+
}
|
|
20965
|
+
let seq = 0;
|
|
20966
|
+
const newId = () => `ai-${Date.now()}-${seq++}`;
|
|
20967
|
+
const proposed = Array.isArray(proposal.rules) ? proposal.rules : [];
|
|
20968
|
+
for (const entry of proposed) {
|
|
20969
|
+
const ruleProposal = parseProposalRule(entry);
|
|
20970
|
+
if (!ruleProposal) continue;
|
|
20971
|
+
const groupIndex = groups.findIndex(
|
|
20972
|
+
(candidate) => candidate.id === ruleProposal.groupId
|
|
20973
|
+
);
|
|
20974
|
+
const queue = groupIndex >= 0 ? queues.get(groupIndex) : void 0;
|
|
20975
|
+
const targetIndex = queue?.shift();
|
|
20976
|
+
if (groupIndex >= 0 && targetIndex !== void 0) {
|
|
20977
|
+
const rules = groups[groupIndex].rules;
|
|
20978
|
+
const existing = rules[targetIndex];
|
|
20979
|
+
const keptId = typeof existing.id === "string" ? existing.id : newId();
|
|
20980
|
+
rules[targetIndex] = ruleFromProposal(ruleProposal, keptId);
|
|
20981
|
+
continue;
|
|
20982
|
+
}
|
|
20983
|
+
let group = groupIndex >= 0 ? groups[groupIndex] : void 0;
|
|
20984
|
+
if (!group) {
|
|
20985
|
+
group = {
|
|
20986
|
+
id: ruleProposal.groupId,
|
|
20987
|
+
name: "AI Group",
|
|
20988
|
+
origins: [],
|
|
20989
|
+
rules: []
|
|
20990
|
+
};
|
|
20991
|
+
groups.push(group);
|
|
20992
|
+
}
|
|
20993
|
+
group.rules.push(ruleFromProposal(ruleProposal, newId()));
|
|
20994
|
+
}
|
|
20995
|
+
return { ...project, groups };
|
|
20996
|
+
}
|
|
20881
20997
|
function parseProposal(content) {
|
|
20882
20998
|
try {
|
|
20883
20999
|
const parsed = JSON.parse(content);
|
|
@@ -20943,6 +21059,11 @@ async function runStream(client, options) {
|
|
|
20943
21059
|
async function runAIAssist(request, config, validate, dryRun, client) {
|
|
20944
21060
|
const aiClient = client ?? createAIClient(config);
|
|
20945
21061
|
const systemPrompt = buildSystemPrompt(request.context.project);
|
|
21062
|
+
const merge = (project, proposal) => request.kind === "fix" ? repairProposalIntoProject(
|
|
21063
|
+
project,
|
|
21064
|
+
request.context.diagnostics,
|
|
21065
|
+
proposal
|
|
21066
|
+
) : mergeProposalIntoProject(project, proposal);
|
|
20946
21067
|
let currentProposal = null;
|
|
20947
21068
|
let attempts = 0;
|
|
20948
21069
|
while (attempts < MAX_FIX_ATTEMPTS) {
|
|
@@ -20950,9 +21071,7 @@ async function runAIAssist(request, config, validate, dryRun, client) {
|
|
|
20950
21071
|
const isFixAttempt = attempts > 1 || request.kind === "fix";
|
|
20951
21072
|
const validationErrors = (() => {
|
|
20952
21073
|
if (!isFixAttempt || !currentProposal) return [];
|
|
20953
|
-
return validate(
|
|
20954
|
-
mergeProposalIntoProject(request.context.project, currentProposal)
|
|
20955
|
-
);
|
|
21074
|
+
return validate(merge(request.context.project, currentProposal));
|
|
20956
21075
|
})();
|
|
20957
21076
|
const messages = buildMessages(
|
|
20958
21077
|
systemPrompt,
|
|
@@ -20983,10 +21102,7 @@ async function runAIAssist(request, config, validate, dryRun, client) {
|
|
|
20983
21102
|
throw new Error("AI returned invalid proposal format");
|
|
20984
21103
|
}
|
|
20985
21104
|
currentProposal = proposal;
|
|
20986
|
-
const testProject =
|
|
20987
|
-
request.context.project,
|
|
20988
|
-
proposal
|
|
20989
|
-
);
|
|
21105
|
+
const testProject = merge(request.context.project, proposal);
|
|
20990
21106
|
const diagnostics = validate(testProject);
|
|
20991
21107
|
if (diagnostics.length === 0) {
|
|
20992
21108
|
if (dryRun && request.context.dryRunCases && request.context.dryRunCases.length > 0) {
|
|
@@ -21316,6 +21432,7 @@ var RUNTIME_LIMITS = Object.freeze({
|
|
|
21316
21432
|
});
|
|
21317
21433
|
var PROTOCOL = "v1";
|
|
21318
21434
|
var ENVELOPE_MAX_BYTES = 64 * 1024;
|
|
21435
|
+
var MAX_PAC_ORIGINS = 256;
|
|
21319
21436
|
var FORBIDDEN_BODY_KEYS = /* @__PURE__ */ new Set(["body", "requestBody", "responseBody"]);
|
|
21320
21437
|
var MOCK_BODY_KEY = "mockBody";
|
|
21321
21438
|
var MOCK_BODY_ALLOWED_TYPES = /* @__PURE__ */ new Set(["mock.response"]);
|
|
@@ -21325,6 +21442,8 @@ var ENVELOPE_MESSAGE_TYPES = /* @__PURE__ */ new Set([
|
|
|
21325
21442
|
"runtime.stop",
|
|
21326
21443
|
"runtime.status",
|
|
21327
21444
|
"runtime.project.set",
|
|
21445
|
+
"runtime.pac.install",
|
|
21446
|
+
"runtime.pac.remove",
|
|
21328
21447
|
"authority.grant",
|
|
21329
21448
|
"authority.revoke",
|
|
21330
21449
|
"transform.request",
|
|
@@ -21430,166 +21549,1054 @@ function parseEnvelope(json) {
|
|
|
21430
21549
|
};
|
|
21431
21550
|
return envelope;
|
|
21432
21551
|
}
|
|
21433
|
-
|
|
21434
|
-
|
|
21435
|
-
|
|
21436
|
-
|
|
21437
|
-
|
|
21438
|
-
|
|
21439
|
-
|
|
21440
|
-
|
|
21441
|
-
|
|
21442
|
-
|
|
21443
|
-
|
|
21444
|
-
|
|
21445
|
-
|
|
21446
|
-
|
|
21447
|
-
|
|
21448
|
-
return createHash("sha256").update(value, "utf8").digest();
|
|
21449
|
-
}
|
|
21450
|
-
function isToken(value) {
|
|
21451
|
-
if (typeof value !== "string" || value.length !== TOKEN_LENGTH) return false;
|
|
21452
|
-
if (!/^[A-Za-z0-9_-]+$/.test(value)) return false;
|
|
21552
|
+
function supportedContentType(value) {
|
|
21553
|
+
if (value === void 0) return false;
|
|
21554
|
+
const mediaType = value.split(";", 1)[0]?.trim().toLowerCase() ?? "";
|
|
21555
|
+
return mediaType === "application/json" || mediaType.startsWith("application/") && mediaType.endsWith("+json") || mediaType === "application/x-www-form-urlencoded" || mediaType.startsWith("text/");
|
|
21556
|
+
}
|
|
21557
|
+
var REGEX_WORKER_SOURCE = `
|
|
21558
|
+
const workerThreads =
|
|
21559
|
+
typeof process.getBuiltinModule === "function"
|
|
21560
|
+
? process.getBuiltinModule("worker_threads")
|
|
21561
|
+
: require("worker_threads");
|
|
21562
|
+
const { parentPort } = workerThreads;
|
|
21563
|
+
parentPort.postMessage({ type: "ready" });
|
|
21564
|
+
parentPort.on("message", (msg) => {
|
|
21565
|
+
if (msg.type !== "replace") return;
|
|
21566
|
+
parentPort.postMessage({ id: msg.id, type: "ack" });
|
|
21453
21567
|
try {
|
|
21454
|
-
|
|
21455
|
-
|
|
21456
|
-
|
|
21568
|
+
const out = msg.text.replace(new RegExp(msg.pattern, "gu"), msg.replacement);
|
|
21569
|
+
parentPort.postMessage({ id: msg.id, type: "result", ok: true, out });
|
|
21570
|
+
} catch (err) {
|
|
21571
|
+
parentPort.postMessage({
|
|
21572
|
+
id: msg.id,
|
|
21573
|
+
type: "result",
|
|
21574
|
+
ok: false,
|
|
21575
|
+
error: String((err && err.message) || err),
|
|
21576
|
+
});
|
|
21457
21577
|
}
|
|
21578
|
+
});
|
|
21579
|
+
`;
|
|
21580
|
+
var REGEX_WORKER_BOOT_TIMEOUT_MS = 5e3;
|
|
21581
|
+
var regexWorker = null;
|
|
21582
|
+
var regexWorkerBoot = null;
|
|
21583
|
+
var nextRegexJobId = 1;
|
|
21584
|
+
var regexWorkerBootDelayForTestsMs = 0;
|
|
21585
|
+
function discardRegexWorker(worker) {
|
|
21586
|
+
if (regexWorker === worker) {
|
|
21587
|
+
regexWorker = null;
|
|
21588
|
+
regexWorkerBoot = null;
|
|
21589
|
+
}
|
|
21590
|
+
worker.terminate().catch(() => {
|
|
21591
|
+
});
|
|
21458
21592
|
}
|
|
21459
|
-
function
|
|
21460
|
-
|
|
21461
|
-
|
|
21593
|
+
function bootRegexWorker() {
|
|
21594
|
+
if (regexWorker !== null) return Promise.resolve(regexWorker);
|
|
21595
|
+
if (regexWorkerBoot !== null) return regexWorkerBoot;
|
|
21596
|
+
const boot = new Promise((resolve22, reject) => {
|
|
21597
|
+
const start = () => {
|
|
21598
|
+
let worker;
|
|
21599
|
+
try {
|
|
21600
|
+
worker = new Worker(REGEX_WORKER_SOURCE, { eval: true });
|
|
21601
|
+
} catch (error) {
|
|
21602
|
+
reject(
|
|
21603
|
+
error instanceof Error ? error : new Error("regex-worker-boot-failed")
|
|
21604
|
+
);
|
|
21605
|
+
return;
|
|
21606
|
+
}
|
|
21607
|
+
let settled = false;
|
|
21608
|
+
const bootTimer = setTimeout(() => {
|
|
21609
|
+
if (settled) return;
|
|
21610
|
+
settled = true;
|
|
21611
|
+
regexWorkerBoot = null;
|
|
21612
|
+
worker.terminate().catch(() => {
|
|
21613
|
+
});
|
|
21614
|
+
reject(new Error("regex-worker-boot-timeout"));
|
|
21615
|
+
}, REGEX_WORKER_BOOT_TIMEOUT_MS);
|
|
21616
|
+
worker.once("message", () => {
|
|
21617
|
+
if (settled) return;
|
|
21618
|
+
settled = true;
|
|
21619
|
+
clearTimeout(bootTimer);
|
|
21620
|
+
worker.unref();
|
|
21621
|
+
worker.on("error", () => {
|
|
21622
|
+
});
|
|
21623
|
+
worker.once("exit", () => {
|
|
21624
|
+
if (regexWorker === worker) {
|
|
21625
|
+
regexWorker = null;
|
|
21626
|
+
regexWorkerBoot = null;
|
|
21627
|
+
}
|
|
21628
|
+
});
|
|
21629
|
+
regexWorker = worker;
|
|
21630
|
+
resolve22(worker);
|
|
21631
|
+
});
|
|
21632
|
+
worker.once("error", (error) => {
|
|
21633
|
+
if (settled) return;
|
|
21634
|
+
settled = true;
|
|
21635
|
+
clearTimeout(bootTimer);
|
|
21636
|
+
regexWorkerBoot = null;
|
|
21637
|
+
reject(error);
|
|
21638
|
+
});
|
|
21639
|
+
worker.once("exit", () => {
|
|
21640
|
+
if (settled) return;
|
|
21641
|
+
settled = true;
|
|
21642
|
+
clearTimeout(bootTimer);
|
|
21643
|
+
regexWorkerBoot = null;
|
|
21644
|
+
reject(new Error("regex-worker-exit-during-boot"));
|
|
21645
|
+
});
|
|
21646
|
+
};
|
|
21647
|
+
if (regexWorkerBootDelayForTestsMs > 0) {
|
|
21648
|
+
const delay2 = regexWorkerBootDelayForTestsMs;
|
|
21649
|
+
regexWorkerBootDelayForTestsMs = 0;
|
|
21650
|
+
setTimeout(start, delay2).unref();
|
|
21651
|
+
} else {
|
|
21652
|
+
start();
|
|
21653
|
+
}
|
|
21654
|
+
});
|
|
21655
|
+
regexWorkerBoot = boot;
|
|
21656
|
+
void boot.catch(() => {
|
|
21657
|
+
if (regexWorkerBoot === boot) regexWorkerBoot = null;
|
|
21658
|
+
});
|
|
21659
|
+
return boot;
|
|
21660
|
+
}
|
|
21661
|
+
function runOnRegexWorker(worker, id2, text, pattern, replacement, deadlineMs) {
|
|
21662
|
+
return new Promise((resolve22, reject) => {
|
|
21663
|
+
let timer = null;
|
|
21664
|
+
const cleanup = () => {
|
|
21665
|
+
if (timer !== null) clearTimeout(timer);
|
|
21666
|
+
worker.off("message", onMessage);
|
|
21667
|
+
worker.off("error", onError);
|
|
21668
|
+
worker.off("exit", onExit);
|
|
21669
|
+
};
|
|
21670
|
+
const onMessage = (msg) => {
|
|
21671
|
+
if (msg.id !== id2) return;
|
|
21672
|
+
if (msg.type === "ack") {
|
|
21673
|
+
timer = setTimeout(() => {
|
|
21674
|
+
cleanup();
|
|
21675
|
+
discardRegexWorker(worker);
|
|
21676
|
+
reject(new Error("deadline"));
|
|
21677
|
+
}, deadlineMs);
|
|
21678
|
+
return;
|
|
21679
|
+
}
|
|
21680
|
+
if (msg.type === "result") {
|
|
21681
|
+
cleanup();
|
|
21682
|
+
if (msg.ok && typeof msg.out === "string") resolve22(msg.out);
|
|
21683
|
+
else reject(new Error(msg.error || "regex-invalid"));
|
|
21684
|
+
}
|
|
21685
|
+
};
|
|
21686
|
+
const onError = (error) => {
|
|
21687
|
+
cleanup();
|
|
21688
|
+
reject(error);
|
|
21689
|
+
};
|
|
21690
|
+
const onExit = () => {
|
|
21691
|
+
cleanup();
|
|
21692
|
+
reject(new Error("regex-worker-exited"));
|
|
21693
|
+
};
|
|
21694
|
+
worker.on("message", onMessage);
|
|
21695
|
+
worker.once("error", onError);
|
|
21696
|
+
worker.once("exit", onExit);
|
|
21697
|
+
worker.postMessage({ id: id2, type: "replace", text, pattern, replacement });
|
|
21698
|
+
});
|
|
21462
21699
|
}
|
|
21463
|
-
function
|
|
21464
|
-
|
|
21465
|
-
|
|
21466
|
-
|
|
21467
|
-
|
|
21700
|
+
function runRegexReplace(text, pattern, replacement, deadlineMs) {
|
|
21701
|
+
const id2 = nextRegexJobId;
|
|
21702
|
+
nextRegexJobId += 1;
|
|
21703
|
+
return bootRegexWorker().then(
|
|
21704
|
+
(worker) => runOnRegexWorker(worker, id2, text, pattern, replacement, deadlineMs),
|
|
21705
|
+
() => {
|
|
21706
|
+
try {
|
|
21707
|
+
return text.replace(new RegExp(pattern, "gu"), replacement);
|
|
21708
|
+
} catch {
|
|
21709
|
+
throw new Error("regex-invalid");
|
|
21710
|
+
}
|
|
21711
|
+
}
|
|
21712
|
+
);
|
|
21468
21713
|
}
|
|
21469
|
-
function
|
|
21470
|
-
|
|
21471
|
-
|
|
21472
|
-
state.sessions.splice(index, 1);
|
|
21714
|
+
async function rewriteRequestBody(input, action, captureContext) {
|
|
21715
|
+
if (!supportedContentType(input.contentType)) {
|
|
21716
|
+
return failure("runtime.request-body-unsupported-mime-type");
|
|
21473
21717
|
}
|
|
21474
|
-
|
|
21475
|
-
|
|
21476
|
-
cleanSessions(state, now);
|
|
21477
|
-
if (state.closed || state.consumed || !isToken(capability) || typeof digest !== "string" || !sameDigest(digest, state.presetDigest) || now >= state.bootstrapExpiresAt || !sameToken(capability, state.bootstrapDigest)) {
|
|
21478
|
-
return failure("runtime.pairing-denied");
|
|
21718
|
+
if (input.contentEncoding !== void 0 && input.contentEncoding !== "identity") {
|
|
21719
|
+
return failure("runtime.request-body-unsupported-content-encoding");
|
|
21479
21720
|
}
|
|
21480
|
-
if (
|
|
21481
|
-
return failure("runtime.
|
|
21721
|
+
if (input.body.byteLength > RUNTIME_LIMITS.maxRequestBodyBytes) {
|
|
21722
|
+
return failure("runtime.body-too-large");
|
|
21723
|
+
}
|
|
21724
|
+
let text;
|
|
21725
|
+
try {
|
|
21726
|
+
text = new TextDecoder("utf-8", { fatal: true }).decode(input.body);
|
|
21727
|
+
} catch {
|
|
21728
|
+
return failure("runtime.request-body-invalid-utf8");
|
|
21729
|
+
}
|
|
21730
|
+
if (hasLoneSurrogate(text)) {
|
|
21731
|
+
return failure("runtime.request-body-lone-surrogate");
|
|
21732
|
+
}
|
|
21733
|
+
let outputText;
|
|
21734
|
+
if (action.mode === "replace") {
|
|
21735
|
+
if (hasLoneSurrogate(action.body)) {
|
|
21736
|
+
return failure("runtime.request-body-lone-surrogate");
|
|
21737
|
+
}
|
|
21738
|
+
outputText = action.body;
|
|
21739
|
+
if (captureContext !== void 0) {
|
|
21740
|
+
const captures = matchUrlCaptures(
|
|
21741
|
+
captureContext.urlRegex,
|
|
21742
|
+
captureContext.url
|
|
21743
|
+
);
|
|
21744
|
+
if (captures === null) return failure("runtime.url-capture-mismatch");
|
|
21745
|
+
outputText = substituteUrlCaptures(outputText, captures);
|
|
21746
|
+
}
|
|
21747
|
+
} else {
|
|
21748
|
+
if (action.pattern.length === 0) {
|
|
21749
|
+
return failure("runtime.request-body-regex-missing-pattern");
|
|
21750
|
+
}
|
|
21751
|
+
if (action.pattern.length > LIMITS.maxRequestBodyPatternLength) {
|
|
21752
|
+
return failure("runtime.request-body-regex-pattern-too-large");
|
|
21753
|
+
}
|
|
21754
|
+
if (action.replacement.length > LIMITS.maxRequestBodyReplacementLength) {
|
|
21755
|
+
return failure("runtime.request-body-regex-replacement-too-large");
|
|
21756
|
+
}
|
|
21757
|
+
if (hasLoneSurrogate(action.replacement)) {
|
|
21758
|
+
return failure("runtime.request-body-lone-surrogate");
|
|
21759
|
+
}
|
|
21760
|
+
try {
|
|
21761
|
+
outputText = await runRegexReplace(
|
|
21762
|
+
text,
|
|
21763
|
+
action.pattern,
|
|
21764
|
+
action.replacement,
|
|
21765
|
+
RUNTIME_LIMITS.maxRegexDeadlineMs
|
|
21766
|
+
);
|
|
21767
|
+
} catch (error) {
|
|
21768
|
+
if (error instanceof Error && error.message === "deadline") {
|
|
21769
|
+
return failure("runtime.request-body-regex-deadline-exceeded");
|
|
21770
|
+
}
|
|
21771
|
+
return failure("runtime.request-body-regex-invalid");
|
|
21772
|
+
}
|
|
21773
|
+
}
|
|
21774
|
+
const outputBytes = new TextEncoder().encode(outputText);
|
|
21775
|
+
if (outputBytes.byteLength > RUNTIME_LIMITS.maxRequestBodyBytes) {
|
|
21776
|
+
return failure("runtime.request-body-replace-too-large");
|
|
21482
21777
|
}
|
|
21483
|
-
state.consumed = true;
|
|
21484
|
-
const sessionCapability = randomBytes(TOKEN_BYTES).toString("base64url");
|
|
21485
|
-
const expiresAt = now + RUNTIME_LIMITS.sessionLifetimeMs;
|
|
21486
|
-
state.sessions.push({
|
|
21487
|
-
digest: Buffer.from(state.presetDigest, "ascii"),
|
|
21488
|
-
expiresAt,
|
|
21489
|
-
tokenDigest: digestToken(sessionCapability),
|
|
21490
|
-
activeOperations: 0
|
|
21491
|
-
});
|
|
21492
21778
|
return {
|
|
21493
21779
|
ok: true,
|
|
21494
21780
|
value: {
|
|
21495
|
-
|
|
21496
|
-
|
|
21781
|
+
body: outputBytes,
|
|
21782
|
+
contentType: input.contentType?.split(";", 1)[0]?.trim() ?? "application/octet-stream"
|
|
21497
21783
|
}
|
|
21498
21784
|
};
|
|
21499
21785
|
}
|
|
21500
|
-
function
|
|
21501
|
-
|
|
21502
|
-
|
|
21503
|
-
|
|
21504
|
-
|
|
21505
|
-
|
|
21506
|
-
|
|
21507
|
-
|
|
21508
|
-
|
|
21786
|
+
function supportedContentType2(value) {
|
|
21787
|
+
if (value === void 0) return false;
|
|
21788
|
+
const mediaType = value.split(";", 1)[0]?.trim().toLowerCase() ?? "";
|
|
21789
|
+
return mediaType.startsWith("text/") || mediaType === "application/json" || mediaType === "application/javascript" || mediaType === "text/javascript" || mediaType === "text/css" || mediaType === "application/xml" || mediaType === "text/xml";
|
|
21790
|
+
}
|
|
21791
|
+
async function rewriteResponseBody(input, replacements, replaceAction, captureContext) {
|
|
21792
|
+
if (!supportedContentType2(input.contentType) || input.contentType === void 0)
|
|
21793
|
+
return failure("runtime.size-limit");
|
|
21794
|
+
if (input.contentEncoding !== void 0 && input.contentEncoding !== "identity")
|
|
21795
|
+
return failure("runtime.size-limit");
|
|
21796
|
+
if (input.body.byteLength > RUNTIME_LIMITS.maxResponseBodyBytes || replaceAction === void 0 && replacements.length === 0 || replacements.length > LIMITS.maxResponseBodyReplacements)
|
|
21797
|
+
return failure("runtime.size-limit");
|
|
21798
|
+
let text;
|
|
21799
|
+
try {
|
|
21800
|
+
text = new TextDecoder("utf-8", { fatal: true }).decode(input.body);
|
|
21801
|
+
} catch {
|
|
21802
|
+
return failure("runtime.size-limit");
|
|
21803
|
+
}
|
|
21804
|
+
if (replaceAction !== void 0) {
|
|
21805
|
+
if (captureContext === void 0) {
|
|
21806
|
+
text = replaceAction.body;
|
|
21807
|
+
} else {
|
|
21808
|
+
const captures = matchUrlCaptures(
|
|
21809
|
+
captureContext.urlRegex,
|
|
21810
|
+
captureContext.url
|
|
21811
|
+
);
|
|
21812
|
+
if (captures === null) return failure("runtime.url-capture-mismatch");
|
|
21813
|
+
text = substituteUrlCaptures(replaceAction.body, captures);
|
|
21509
21814
|
}
|
|
21510
21815
|
}
|
|
21511
|
-
|
|
21512
|
-
|
|
21513
|
-
|
|
21514
|
-
|
|
21515
|
-
|
|
21816
|
+
try {
|
|
21817
|
+
for (const entry of replacements) {
|
|
21818
|
+
if (entry.pattern.length === 0 || entry.pattern.length > LIMITS.maxResponseBodyPatternLength || entry.replacement.length > LIMITS.maxResponseBodyReplacementLength)
|
|
21819
|
+
return failure("runtime.size-limit");
|
|
21820
|
+
const regex = new RegExp(entry.pattern, "gu");
|
|
21821
|
+
text = text.replace(regex, entry.replacement);
|
|
21822
|
+
if (new TextEncoder().encode(text).byteLength > RUNTIME_LIMITS.maxResponseBodyBytes)
|
|
21823
|
+
return failure("runtime.size-limit");
|
|
21824
|
+
}
|
|
21825
|
+
} catch {
|
|
21826
|
+
return failure("runtime.invalid-canonical-value");
|
|
21516
21827
|
}
|
|
21517
|
-
session.activeOperations += 1;
|
|
21518
21828
|
return {
|
|
21519
21829
|
ok: true,
|
|
21520
|
-
value:
|
|
21521
|
-
|
|
21830
|
+
value: {
|
|
21831
|
+
body: new TextEncoder().encode(text),
|
|
21832
|
+
contentType: input.contentType.split(";", 1)[0]?.trim() ?? input.contentType
|
|
21522
21833
|
}
|
|
21523
21834
|
};
|
|
21524
21835
|
}
|
|
21525
|
-
function
|
|
21526
|
-
|
|
21527
|
-
|
|
21528
|
-
|
|
21529
|
-
|
|
21836
|
+
function originOf(value) {
|
|
21837
|
+
const direct = normalizeSiteOrigin(value);
|
|
21838
|
+
if (direct !== null) return direct;
|
|
21839
|
+
try {
|
|
21840
|
+
return normalizeSiteOrigin(new URL(value).origin);
|
|
21841
|
+
} catch {
|
|
21842
|
+
return null;
|
|
21843
|
+
}
|
|
21530
21844
|
}
|
|
21531
|
-
|
|
21532
|
-
|
|
21533
|
-
|
|
21534
|
-
if (
|
|
21535
|
-
|
|
21845
|
+
function projectHasRule(project, groupId, ruleId) {
|
|
21846
|
+
if (!Array.isArray(project.groups)) return false;
|
|
21847
|
+
const group = project.groups.find((candidate) => candidate.id === groupId);
|
|
21848
|
+
if (group === void 0 || !Array.isArray(group.rules)) return false;
|
|
21849
|
+
return group.rules.some((rule) => rule.id === ruleId);
|
|
21850
|
+
}
|
|
21851
|
+
function revalidateAuthority(project, operations, request) {
|
|
21852
|
+
const projectSnap = snapshotOwnData3(project);
|
|
21853
|
+
if (!projectSnap.valid) return { allowed: false, reason: "project-invalid" };
|
|
21854
|
+
const opsSnap = snapshotOwnData3(operations);
|
|
21855
|
+
if (!opsSnap.valid) return { allowed: false, reason: "project-invalid" };
|
|
21856
|
+
const reqSnap = snapshotOwnData3(request);
|
|
21857
|
+
if (!reqSnap.valid) return { allowed: false, reason: "project-invalid" };
|
|
21858
|
+
const operation = operations.find(
|
|
21859
|
+
(candidate) => candidate.groupId === request.groupId && candidate.ruleId === request.ruleId && "matcher" in candidate
|
|
21860
|
+
);
|
|
21861
|
+
if (operation === void 0 || !("matcher" in operation)) {
|
|
21862
|
+
return { allowed: false, reason: "operation-unknown" };
|
|
21536
21863
|
}
|
|
21537
|
-
|
|
21538
|
-
|
|
21539
|
-
|
|
21864
|
+
if (!projectHasRule(
|
|
21865
|
+
projectSnap.value,
|
|
21866
|
+
request.groupId,
|
|
21867
|
+
request.ruleId
|
|
21868
|
+
)) {
|
|
21869
|
+
return { allowed: false, reason: "project-inconsistent" };
|
|
21540
21870
|
}
|
|
21541
|
-
|
|
21542
|
-
|
|
21871
|
+
const matcher = operation.matcher;
|
|
21872
|
+
const regex = compileUrlRegex(matcher.urlRegex.source);
|
|
21873
|
+
if (regex === null || !regex.test(request.url)) {
|
|
21874
|
+
return { allowed: false, reason: "url-mismatch" };
|
|
21543
21875
|
}
|
|
21544
|
-
const
|
|
21545
|
-
|
|
21546
|
-
|
|
21547
|
-
} catch (error) {
|
|
21548
|
-
return {
|
|
21549
|
-
kind: "unsupported",
|
|
21550
|
-
reasons: ["provider-start-failed", String(error)]
|
|
21551
|
-
};
|
|
21876
|
+
const targetOrigin2 = request.target ? originOf(request.target) : originOf(request.url);
|
|
21877
|
+
if (targetOrigin2 === null || !matcher.origins.includes(targetOrigin2)) {
|
|
21878
|
+
return { allowed: false, reason: "target-unauthorized" };
|
|
21552
21879
|
}
|
|
21553
|
-
|
|
21554
|
-
|
|
21555
|
-
|
|
21556
|
-
|
|
21557
|
-
|
|
21558
|
-
|
|
21559
|
-
|
|
21560
|
-
|
|
21561
|
-
|
|
21880
|
+
if (request.initiator !== void 0) {
|
|
21881
|
+
const initiatorOrigin = originOf(request.initiator);
|
|
21882
|
+
if (initiatorOrigin === null || !matcher.origins.includes(initiatorOrigin)) {
|
|
21883
|
+
return { allowed: false, reason: "initiator-unauthorized" };
|
|
21884
|
+
}
|
|
21885
|
+
}
|
|
21886
|
+
if (matcher.method !== void 0) {
|
|
21887
|
+
const method = typeof request.method === "string" ? request.method.toUpperCase() : void 0;
|
|
21888
|
+
if (method !== matcher.method) {
|
|
21889
|
+
return { allowed: false, reason: "method-mismatch" };
|
|
21890
|
+
}
|
|
21891
|
+
}
|
|
21892
|
+
if (matcher.resourceTypes.length > 0) {
|
|
21893
|
+
const resourceType = typeof request.resourceType === "string" ? request.resourceType : void 0;
|
|
21894
|
+
if (resourceType === void 0 || !matcher.resourceTypes.includes(resourceType)) {
|
|
21895
|
+
return { allowed: false, reason: "resource-type-unauthorized" };
|
|
21896
|
+
}
|
|
21897
|
+
}
|
|
21898
|
+
return {
|
|
21899
|
+
allowed: true,
|
|
21900
|
+
groupId: request.groupId,
|
|
21901
|
+
ruleId: request.ruleId,
|
|
21902
|
+
operation
|
|
21562
21903
|
};
|
|
21563
|
-
return { kind: "active", provider: registeredProvider.platform };
|
|
21564
21904
|
}
|
|
21565
|
-
|
|
21566
|
-
|
|
21567
|
-
|
|
21568
|
-
|
|
21569
|
-
|
|
21570
|
-
try {
|
|
21571
|
-
await session.provider.stop();
|
|
21572
|
-
} catch {
|
|
21573
|
-
}
|
|
21905
|
+
function originOf2(url) {
|
|
21906
|
+
try {
|
|
21907
|
+
return normalizeSiteOrigin(new URL(url).origin);
|
|
21908
|
+
} catch {
|
|
21909
|
+
return null;
|
|
21574
21910
|
}
|
|
21575
21911
|
}
|
|
21576
|
-
function
|
|
21577
|
-
return
|
|
21912
|
+
function isBodyOp(op) {
|
|
21913
|
+
return op.kind === "request-body" || op.kind === "response-body";
|
|
21578
21914
|
}
|
|
21579
|
-
function
|
|
21580
|
-
const
|
|
21581
|
-
|
|
21915
|
+
function matcherMatches(op, url, method) {
|
|
21916
|
+
const regex = compileUrlRegex(op.matcher.urlRegex.source);
|
|
21917
|
+
if (regex === null || !regex.test(url)) return false;
|
|
21918
|
+
const origin = originOf2(url);
|
|
21919
|
+
if (origin === null || !op.matcher.origins.includes(origin)) return false;
|
|
21920
|
+
if (op.matcher.method !== void 0 && op.matcher.method !== method.toUpperCase()) {
|
|
21921
|
+
return false;
|
|
21922
|
+
}
|
|
21923
|
+
return true;
|
|
21582
21924
|
}
|
|
21583
|
-
|
|
21584
|
-
|
|
21585
|
-
|
|
21586
|
-
|
|
21587
|
-
|
|
21588
|
-
|
|
21589
|
-
|
|
21590
|
-
|
|
21591
|
-
|
|
21592
|
-
|
|
21925
|
+
function pickHighest(operations, kind, url, method) {
|
|
21926
|
+
let best = null;
|
|
21927
|
+
for (const op of operations) {
|
|
21928
|
+
if (!isBodyOp(op) || op.kind !== kind) continue;
|
|
21929
|
+
if (!matcherMatches(op, url, method)) continue;
|
|
21930
|
+
if (best === null || op.matcher.priority > best.matcher.priority || op.matcher.priority === best.matcher.priority && op.ruleId.localeCompare(best.ruleId) < 0) {
|
|
21931
|
+
best = op;
|
|
21932
|
+
}
|
|
21933
|
+
}
|
|
21934
|
+
return best;
|
|
21935
|
+
}
|
|
21936
|
+
function headerValue2(headers, name) {
|
|
21937
|
+
const raw = headers[name];
|
|
21938
|
+
if (Array.isArray(raw)) return raw[0];
|
|
21939
|
+
return raw;
|
|
21940
|
+
}
|
|
21941
|
+
function readBoundedBody(req, maxBytes) {
|
|
21942
|
+
return new Promise((resolve22) => {
|
|
21943
|
+
const chunks = [];
|
|
21944
|
+
let total = 0;
|
|
21945
|
+
let settled = false;
|
|
21946
|
+
const finish = (result) => {
|
|
21947
|
+
if (settled) return;
|
|
21948
|
+
settled = true;
|
|
21949
|
+
resolve22(result);
|
|
21950
|
+
};
|
|
21951
|
+
req.on("data", (chunk) => {
|
|
21952
|
+
total += chunk.byteLength;
|
|
21953
|
+
if (total > maxBytes) {
|
|
21954
|
+
req.destroy();
|
|
21955
|
+
finish({ ok: false, reason: "oversized" });
|
|
21956
|
+
return;
|
|
21957
|
+
}
|
|
21958
|
+
chunks.push(chunk);
|
|
21959
|
+
});
|
|
21960
|
+
req.on("end", () => {
|
|
21961
|
+
finish({ ok: true, body: Buffer.concat(chunks) });
|
|
21962
|
+
});
|
|
21963
|
+
req.on("error", () => {
|
|
21964
|
+
finish({ ok: true, body: Buffer.concat(chunks) });
|
|
21965
|
+
});
|
|
21966
|
+
});
|
|
21967
|
+
}
|
|
21968
|
+
function hopByHop() {
|
|
21969
|
+
return /* @__PURE__ */ new Set([
|
|
21970
|
+
"connection",
|
|
21971
|
+
"keep-alive",
|
|
21972
|
+
"proxy-authenticate",
|
|
21973
|
+
"proxy-authorization",
|
|
21974
|
+
"proxy-connection",
|
|
21975
|
+
"te",
|
|
21976
|
+
"trailer",
|
|
21977
|
+
"transfer-encoding",
|
|
21978
|
+
"upgrade",
|
|
21979
|
+
"content-length"
|
|
21980
|
+
]);
|
|
21981
|
+
}
|
|
21982
|
+
function forwardRequestHeaders(headers, host, contentLength) {
|
|
21983
|
+
const skip = hopByHop();
|
|
21984
|
+
const out = {
|
|
21985
|
+
host,
|
|
21986
|
+
"content-length": String(contentLength),
|
|
21987
|
+
connection: "close"
|
|
21988
|
+
};
|
|
21989
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
21990
|
+
if (value === void 0) continue;
|
|
21991
|
+
const lower = key.toLowerCase();
|
|
21992
|
+
if (skip.has(lower) || lower.startsWith("proxy-")) continue;
|
|
21993
|
+
if (lower.startsWith("x-rogatio-dispatch-")) continue;
|
|
21994
|
+
out[key] = Array.isArray(value) ? value.join(", ") : value;
|
|
21995
|
+
}
|
|
21996
|
+
return out;
|
|
21997
|
+
}
|
|
21998
|
+
function pipeSockets(a, b) {
|
|
21999
|
+
a.pipe(b);
|
|
22000
|
+
b.pipe(a);
|
|
22001
|
+
const closeBoth = () => {
|
|
22002
|
+
a.destroy();
|
|
22003
|
+
b.destroy();
|
|
22004
|
+
};
|
|
22005
|
+
a.on("error", closeBoth);
|
|
22006
|
+
b.on("error", closeBoth);
|
|
22007
|
+
a.on("close", () => b.destroy());
|
|
22008
|
+
b.on("close", () => a.destroy());
|
|
22009
|
+
}
|
|
22010
|
+
async function upstreamHttp(method, target, headers, body) {
|
|
22011
|
+
const port = target.port ? Number(target.port) : 80;
|
|
22012
|
+
const path2 = `${target.pathname}${target.search}`;
|
|
22013
|
+
return new Promise((resolve22, reject) => {
|
|
22014
|
+
const socket = connect(port, target.hostname);
|
|
22015
|
+
let buf = Buffer.alloc(0);
|
|
22016
|
+
let settled = false;
|
|
22017
|
+
const fail = (err) => {
|
|
22018
|
+
if (settled) return;
|
|
22019
|
+
settled = true;
|
|
22020
|
+
socket.destroy();
|
|
22021
|
+
reject(err);
|
|
22022
|
+
};
|
|
22023
|
+
socket.setTimeout(RUNTIME_LIMITS.operationTimeoutMs);
|
|
22024
|
+
socket.on("timeout", () => fail(new Error("upstream timeout")));
|
|
22025
|
+
socket.on("error", (err) => fail(err));
|
|
22026
|
+
socket.on("connect", () => {
|
|
22027
|
+
const lines = Object.entries(headers).map(([k, v]) => `${k}: ${v}`).join("\r\n");
|
|
22028
|
+
socket.write(`${method} ${path2} HTTP/1.1\r
|
|
22029
|
+
${lines}\r
|
|
22030
|
+
\r
|
|
22031
|
+
`);
|
|
22032
|
+
if (body.byteLength > 0) socket.write(body);
|
|
22033
|
+
});
|
|
22034
|
+
socket.on("data", (chunk) => {
|
|
22035
|
+
const piece = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
|
|
22036
|
+
buf = Buffer.concat([buf, piece]);
|
|
22037
|
+
const sep2 = buf.indexOf("\r\n\r\n");
|
|
22038
|
+
if (sep2 < 0) return;
|
|
22039
|
+
const head = buf.subarray(0, sep2).toString("latin1");
|
|
22040
|
+
const statusMatch = /^HTTP\/1\.[01] (\d+)(?: (.*))?/.exec(
|
|
22041
|
+
head.split("\r\n")[0] ?? ""
|
|
22042
|
+
);
|
|
22043
|
+
if (!statusMatch) {
|
|
22044
|
+
fail(new Error("bad upstream status"));
|
|
22045
|
+
return;
|
|
22046
|
+
}
|
|
22047
|
+
const status = Number(statusMatch[1]);
|
|
22048
|
+
const statusMessage = statusMatch[2]?.trim() ?? "";
|
|
22049
|
+
const headerMap = {};
|
|
22050
|
+
for (const line of head.split("\r\n").slice(1)) {
|
|
22051
|
+
const i = line.indexOf(":");
|
|
22052
|
+
if (i <= 0) continue;
|
|
22053
|
+
const name = line.slice(0, i).trim().toLowerCase();
|
|
22054
|
+
const value = line.slice(i + 1).trim();
|
|
22055
|
+
const existing = headerMap[name];
|
|
22056
|
+
if (existing === void 0) headerMap[name] = value;
|
|
22057
|
+
else if (Array.isArray(existing)) existing.push(value);
|
|
22058
|
+
else headerMap[name] = [existing, value];
|
|
22059
|
+
}
|
|
22060
|
+
const clRaw = headerMap["content-length"];
|
|
22061
|
+
const hasContentLength = clRaw !== void 0;
|
|
22062
|
+
const cl = typeof clRaw === "string" ? Number(clRaw) : Array.isArray(clRaw) ? Number(clRaw[0]) : Number.NaN;
|
|
22063
|
+
const bodyStart = sep2 + 4;
|
|
22064
|
+
if (hasContentLength && Number.isFinite(cl) && cl >= 0) {
|
|
22065
|
+
if (buf.length - bodyStart < cl) return;
|
|
22066
|
+
if (settled) return;
|
|
22067
|
+
settled = true;
|
|
22068
|
+
socket.destroy();
|
|
22069
|
+
resolve22({
|
|
22070
|
+
status,
|
|
22071
|
+
statusMessage,
|
|
22072
|
+
headers: headerMap,
|
|
22073
|
+
body: buf.subarray(bodyStart, bodyStart + cl)
|
|
22074
|
+
});
|
|
22075
|
+
return;
|
|
22076
|
+
}
|
|
22077
|
+
});
|
|
22078
|
+
socket.on("end", () => {
|
|
22079
|
+
if (settled) return;
|
|
22080
|
+
const sep2 = buf.indexOf("\r\n\r\n");
|
|
22081
|
+
if (sep2 < 0) {
|
|
22082
|
+
fail(new Error("upstream closed early"));
|
|
22083
|
+
return;
|
|
22084
|
+
}
|
|
22085
|
+
const head = buf.subarray(0, sep2).toString("latin1");
|
|
22086
|
+
const statusMatch = /^HTTP\/1\.[01] (\d+)(?: (.*))?/.exec(
|
|
22087
|
+
head.split("\r\n")[0] ?? ""
|
|
22088
|
+
);
|
|
22089
|
+
if (!statusMatch) {
|
|
22090
|
+
fail(new Error("bad upstream status"));
|
|
22091
|
+
return;
|
|
22092
|
+
}
|
|
22093
|
+
const headerMap = {};
|
|
22094
|
+
for (const line of head.split("\r\n").slice(1)) {
|
|
22095
|
+
const i = line.indexOf(":");
|
|
22096
|
+
if (i <= 0) continue;
|
|
22097
|
+
headerMap[line.slice(0, i).trim().toLowerCase()] = line.slice(i + 1).trim();
|
|
22098
|
+
}
|
|
22099
|
+
let body2 = Buffer.from(buf.subarray(sep2 + 4));
|
|
22100
|
+
const te = headerMap["transfer-encoding"];
|
|
22101
|
+
const teValue = Array.isArray(te) ? te[0] : te;
|
|
22102
|
+
if (typeof teValue === "string" && teValue.toLowerCase().includes("chunked")) {
|
|
22103
|
+
body2 = Buffer.from(decodeChunkedBody(body2));
|
|
22104
|
+
delete headerMap["transfer-encoding"];
|
|
22105
|
+
headerMap["content-length"] = String(body2.byteLength);
|
|
22106
|
+
}
|
|
22107
|
+
settled = true;
|
|
22108
|
+
resolve22({
|
|
22109
|
+
status: Number(statusMatch[1]),
|
|
22110
|
+
statusMessage: statusMatch[2]?.trim() ?? "",
|
|
22111
|
+
headers: headerMap,
|
|
22112
|
+
body: body2
|
|
22113
|
+
});
|
|
22114
|
+
});
|
|
22115
|
+
});
|
|
22116
|
+
}
|
|
22117
|
+
function decodeChunkedBody(buf) {
|
|
22118
|
+
const parts = [];
|
|
22119
|
+
let offset = 0;
|
|
22120
|
+
while (offset < buf.length) {
|
|
22121
|
+
const lineEnd = buf.indexOf("\r\n", offset);
|
|
22122
|
+
if (lineEnd < 0) break;
|
|
22123
|
+
const size = Number.parseInt(
|
|
22124
|
+
buf.subarray(offset, lineEnd).toString("ascii"),
|
|
22125
|
+
16
|
|
22126
|
+
);
|
|
22127
|
+
if (!Number.isFinite(size) || size < 0) break;
|
|
22128
|
+
offset = lineEnd + 2;
|
|
22129
|
+
if (size === 0) break;
|
|
22130
|
+
parts.push(buf.subarray(offset, offset + size));
|
|
22131
|
+
offset += size + 2;
|
|
22132
|
+
}
|
|
22133
|
+
return Buffer.from(Buffer.concat(parts));
|
|
22134
|
+
}
|
|
22135
|
+
function writeResponse(res, status, statusMessage, headers, body) {
|
|
22136
|
+
const skip = hopByHop();
|
|
22137
|
+
const out = {
|
|
22138
|
+
"content-length": body.byteLength
|
|
22139
|
+
};
|
|
22140
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
22141
|
+
if (skip.has(key) || key.startsWith("proxy-")) continue;
|
|
22142
|
+
out[key] = value;
|
|
22143
|
+
}
|
|
22144
|
+
res.writeHead(status, statusMessage, out);
|
|
22145
|
+
res.end(body);
|
|
22146
|
+
}
|
|
22147
|
+
function authorizeOp(policy, op, url, method) {
|
|
22148
|
+
const resourceType = op.matcher.resourceTypes[0];
|
|
22149
|
+
const decision = revalidateAuthority(policy.project, policy.operations, {
|
|
22150
|
+
groupId: op.groupId,
|
|
22151
|
+
ruleId: op.ruleId,
|
|
22152
|
+
url,
|
|
22153
|
+
method,
|
|
22154
|
+
...resourceType !== void 0 ? { resourceType } : {}
|
|
22155
|
+
});
|
|
22156
|
+
return decision.allowed;
|
|
22157
|
+
}
|
|
22158
|
+
async function startInterceptProxy(options = {}) {
|
|
22159
|
+
let policy = options.policy ?? null;
|
|
22160
|
+
const server = createServer((req, res) => {
|
|
22161
|
+
void handleHttp(req, res);
|
|
22162
|
+
});
|
|
22163
|
+
server.on("connect", (req, clientSocket, head) => {
|
|
22164
|
+
handleConnect(req, clientSocket, head);
|
|
22165
|
+
});
|
|
22166
|
+
async function handleHttp(req, res) {
|
|
22167
|
+
try {
|
|
22168
|
+
const targetUrl = req.url ?? "";
|
|
22169
|
+
if (!/^https?:\/\//i.test(targetUrl)) {
|
|
22170
|
+
res.writeHead(400);
|
|
22171
|
+
res.end();
|
|
22172
|
+
return;
|
|
22173
|
+
}
|
|
22174
|
+
let target;
|
|
22175
|
+
try {
|
|
22176
|
+
target = new URL(targetUrl);
|
|
22177
|
+
} catch {
|
|
22178
|
+
res.writeHead(400);
|
|
22179
|
+
res.end();
|
|
22180
|
+
return;
|
|
22181
|
+
}
|
|
22182
|
+
if (target.protocol !== "http:") {
|
|
22183
|
+
res.writeHead(501);
|
|
22184
|
+
res.end();
|
|
22185
|
+
return;
|
|
22186
|
+
}
|
|
22187
|
+
const method = (req.method ?? "GET").toUpperCase();
|
|
22188
|
+
const active = policy;
|
|
22189
|
+
const requestOp = active === null ? null : pickHighest(
|
|
22190
|
+
active.operations,
|
|
22191
|
+
"request-body",
|
|
22192
|
+
targetUrl,
|
|
22193
|
+
method
|
|
22194
|
+
);
|
|
22195
|
+
const responseOp = active === null ? null : pickHighest(
|
|
22196
|
+
active.operations,
|
|
22197
|
+
"response-body",
|
|
22198
|
+
targetUrl,
|
|
22199
|
+
method
|
|
22200
|
+
);
|
|
22201
|
+
const needsRequestBody = requestOp !== null;
|
|
22202
|
+
const bodyResult = await readBoundedBody(
|
|
22203
|
+
req,
|
|
22204
|
+
RUNTIME_LIMITS.maxRequestBodyBytes
|
|
22205
|
+
);
|
|
22206
|
+
if (!bodyResult.ok) {
|
|
22207
|
+
if (!res.headersSent) {
|
|
22208
|
+
res.writeHead(413);
|
|
22209
|
+
res.end();
|
|
22210
|
+
}
|
|
22211
|
+
return;
|
|
22212
|
+
}
|
|
22213
|
+
let requestBody = bodyResult.body;
|
|
22214
|
+
if (needsRequestBody && requestOp !== null && active !== null) {
|
|
22215
|
+
if (!authorizeOp(active, requestOp, targetUrl, method)) {
|
|
22216
|
+
} else {
|
|
22217
|
+
const rewritten = await rewriteRequestBody(
|
|
22218
|
+
{
|
|
22219
|
+
contentType: headerValue2(req.headers, "content-type"),
|
|
22220
|
+
contentEncoding: headerValue2(req.headers, "content-encoding") ?? "identity",
|
|
22221
|
+
body: new Uint8Array(requestBody)
|
|
22222
|
+
},
|
|
22223
|
+
requestOp.requestBody,
|
|
22224
|
+
{
|
|
22225
|
+
url: targetUrl,
|
|
22226
|
+
urlRegex: requestOp.matcher.urlRegex.source
|
|
22227
|
+
}
|
|
22228
|
+
);
|
|
22229
|
+
if (rewritten.ok) {
|
|
22230
|
+
requestBody = Buffer.from(rewritten.value.body);
|
|
22231
|
+
}
|
|
22232
|
+
}
|
|
22233
|
+
}
|
|
22234
|
+
const forwardHeaders = forwardRequestHeaders(
|
|
22235
|
+
req.headers,
|
|
22236
|
+
target.host,
|
|
22237
|
+
requestBody.byteLength
|
|
22238
|
+
);
|
|
22239
|
+
const upstream = await upstreamHttp(
|
|
22240
|
+
method,
|
|
22241
|
+
target,
|
|
22242
|
+
forwardHeaders,
|
|
22243
|
+
requestBody
|
|
22244
|
+
);
|
|
22245
|
+
let responseBody = upstream.body;
|
|
22246
|
+
if (responseOp !== null && active !== null) {
|
|
22247
|
+
if (responseBody.byteLength > RUNTIME_LIMITS.maxResponseBodyBytes) {
|
|
22248
|
+
} else if (!authorizeOp(active, responseOp, targetUrl, method)) {
|
|
22249
|
+
} else {
|
|
22250
|
+
const action = responseOp.responseBody;
|
|
22251
|
+
const isReplace = "mode" in action && action.mode === "replace";
|
|
22252
|
+
const rewritten = await rewriteResponseBody(
|
|
22253
|
+
{
|
|
22254
|
+
contentType: typeof upstream.headers["content-type"] === "string" ? upstream.headers["content-type"] : Array.isArray(upstream.headers["content-type"]) ? upstream.headers["content-type"][0] : void 0,
|
|
22255
|
+
contentEncoding: typeof upstream.headers["content-encoding"] === "string" ? upstream.headers["content-encoding"] : "identity",
|
|
22256
|
+
body: new Uint8Array(responseBody)
|
|
22257
|
+
},
|
|
22258
|
+
"replacements" in action && Array.isArray(action.replacements) ? action.replacements : [],
|
|
22259
|
+
isReplace ? action : void 0,
|
|
22260
|
+
{
|
|
22261
|
+
url: targetUrl,
|
|
22262
|
+
urlRegex: responseOp.matcher.urlRegex.source
|
|
22263
|
+
}
|
|
22264
|
+
);
|
|
22265
|
+
if (rewritten.ok) {
|
|
22266
|
+
responseBody = Buffer.from(rewritten.value.body);
|
|
22267
|
+
}
|
|
22268
|
+
}
|
|
22269
|
+
}
|
|
22270
|
+
writeResponse(
|
|
22271
|
+
res,
|
|
22272
|
+
upstream.status,
|
|
22273
|
+
upstream.statusMessage,
|
|
22274
|
+
upstream.headers,
|
|
22275
|
+
responseBody
|
|
22276
|
+
);
|
|
22277
|
+
} catch {
|
|
22278
|
+
if (!res.headersSent) {
|
|
22279
|
+
res.writeHead(502);
|
|
22280
|
+
res.end();
|
|
22281
|
+
}
|
|
22282
|
+
}
|
|
22283
|
+
}
|
|
22284
|
+
function handleConnect(req, clientSocket, head) {
|
|
22285
|
+
const authority = req.url ?? "";
|
|
22286
|
+
const [host, portText] = authority.split(":");
|
|
22287
|
+
const port = Number(portText);
|
|
22288
|
+
if (!host || !Number.isInteger(port) || port <= 0) {
|
|
22289
|
+
clientSocket.write("HTTP/1.1 400 Bad Request\r\n\r\n");
|
|
22290
|
+
clientSocket.destroy();
|
|
22291
|
+
return;
|
|
22292
|
+
}
|
|
22293
|
+
const upstream = connect(port, host);
|
|
22294
|
+
upstream.on("connect", () => {
|
|
22295
|
+
clientSocket.write("HTTP/1.1 200 Connection Established\r\n\r\n");
|
|
22296
|
+
if (head.byteLength > 0) upstream.write(head);
|
|
22297
|
+
pipeSockets(clientSocket, upstream);
|
|
22298
|
+
});
|
|
22299
|
+
upstream.on("error", () => {
|
|
22300
|
+
clientSocket.write("HTTP/1.1 502 Bad Gateway\r\n\r\n");
|
|
22301
|
+
clientSocket.destroy();
|
|
22302
|
+
});
|
|
22303
|
+
clientSocket.on("error", () => upstream.destroy());
|
|
22304
|
+
}
|
|
22305
|
+
const endpoint = await new Promise((resolve22, reject) => {
|
|
22306
|
+
server.once("error", reject);
|
|
22307
|
+
server.listen(0, "127.0.0.1", () => {
|
|
22308
|
+
const addr = server.address();
|
|
22309
|
+
if (!addr || typeof addr === "string") {
|
|
22310
|
+
reject(new Error("intercept-proxy bind failed"));
|
|
22311
|
+
return;
|
|
22312
|
+
}
|
|
22313
|
+
resolve22({ host: "127.0.0.1", port: addr.port });
|
|
22314
|
+
});
|
|
22315
|
+
});
|
|
22316
|
+
return {
|
|
22317
|
+
endpoint,
|
|
22318
|
+
setPolicy(next) {
|
|
22319
|
+
policy = next;
|
|
22320
|
+
},
|
|
22321
|
+
async stop() {
|
|
22322
|
+
await new Promise((resolve22, reject) => {
|
|
22323
|
+
server.close((err) => err ? reject(err) : resolve22());
|
|
22324
|
+
});
|
|
22325
|
+
}
|
|
22326
|
+
};
|
|
22327
|
+
}
|
|
22328
|
+
function generatePacScript(origins, endpoint, options) {
|
|
22329
|
+
if (!Array.isArray(origins)) {
|
|
22330
|
+
throw new Error("pac origins must be an array");
|
|
22331
|
+
}
|
|
22332
|
+
const valid = [];
|
|
22333
|
+
for (const origin of origins) {
|
|
22334
|
+
const normalized = normalizeSiteOrigin(origin);
|
|
22335
|
+
if (normalized !== null) valid.push(normalized);
|
|
22336
|
+
}
|
|
22337
|
+
const unique = Array.from(new Set(valid)).sort();
|
|
22338
|
+
if (unique.length > MAX_PAC_ORIGINS) {
|
|
22339
|
+
throw new Error("pac origin count exceeds maximum");
|
|
22340
|
+
}
|
|
22341
|
+
const proxyType = options?.proxyType ?? "PROXY";
|
|
22342
|
+
const proxy = `${proxyType} ${endpoint.host}:${endpoint.port}`;
|
|
22343
|
+
const originsLiteral = JSON.stringify(unique);
|
|
22344
|
+
const proxyLiteral = JSON.stringify(proxy);
|
|
22345
|
+
return [
|
|
22346
|
+
"function FindProxyForURL(url, host) {",
|
|
22347
|
+
` var origins = ${originsLiteral};`,
|
|
22348
|
+
" var origin = null;",
|
|
22349
|
+
" try { origin = new URL(url).origin; } catch (e) { origin = null; }",
|
|
22350
|
+
" if (origin !== null && origins.indexOf(origin) !== -1) {",
|
|
22351
|
+
` return ${proxyLiteral};`,
|
|
22352
|
+
" }",
|
|
22353
|
+
" return 'DIRECT';",
|
|
22354
|
+
"}"
|
|
22355
|
+
].join("\n");
|
|
22356
|
+
}
|
|
22357
|
+
var registeredProvider = null;
|
|
22358
|
+
var currentSession = null;
|
|
22359
|
+
function registerInterceptionProvider(provider) {
|
|
22360
|
+
registeredProvider = provider;
|
|
22361
|
+
}
|
|
22362
|
+
function getCurrentSession() {
|
|
22363
|
+
return currentSession;
|
|
22364
|
+
}
|
|
22365
|
+
async function startInterception(activation, policyDigest, extensionId, pacOrigins, targetPolicy) {
|
|
22366
|
+
if (registeredProvider === null) {
|
|
22367
|
+
return { kind: "unsupported", reasons: ["no-interception-provider"] };
|
|
22368
|
+
}
|
|
22369
|
+
const capabilities = registeredProvider.detect();
|
|
22370
|
+
if (!capabilities.supported) {
|
|
22371
|
+
return { kind: "unsupported", reasons: capabilities.reasons };
|
|
22372
|
+
}
|
|
22373
|
+
if (currentSession !== null) {
|
|
22374
|
+
return { kind: "unsupported", reasons: ["session-collision"] };
|
|
22375
|
+
}
|
|
22376
|
+
const sessionId = `session-${activation.startedAt}-${Math.random().toString(36).slice(2)}`;
|
|
22377
|
+
let proxy;
|
|
22378
|
+
try {
|
|
22379
|
+
const started = await registeredProvider.start(activation);
|
|
22380
|
+
if (started && typeof started === "object" && typeof started.host === "string" && typeof started.port === "number") {
|
|
22381
|
+
proxy = started;
|
|
22382
|
+
} else if (activation.proxy) {
|
|
22383
|
+
proxy = activation.proxy;
|
|
22384
|
+
} else {
|
|
22385
|
+
return {
|
|
22386
|
+
kind: "unsupported",
|
|
22387
|
+
reasons: ["provider-start-failed", "missing-proxy-endpoint"]
|
|
22388
|
+
};
|
|
22389
|
+
}
|
|
22390
|
+
} catch (error) {
|
|
22391
|
+
return {
|
|
22392
|
+
kind: "unsupported",
|
|
22393
|
+
reasons: ["provider-start-failed", String(error)]
|
|
22394
|
+
};
|
|
22395
|
+
}
|
|
22396
|
+
currentSession = {
|
|
22397
|
+
sessionId,
|
|
22398
|
+
provider: registeredProvider,
|
|
22399
|
+
activation: { ...activation, proxy, pacOrigins },
|
|
22400
|
+
policyDigest,
|
|
22401
|
+
extensionId,
|
|
22402
|
+
pacOrigins,
|
|
22403
|
+
targetPolicy,
|
|
22404
|
+
startedAt: activation.startedAt
|
|
22405
|
+
};
|
|
22406
|
+
return { kind: "active", provider: registeredProvider.platform, proxy };
|
|
22407
|
+
}
|
|
22408
|
+
async function stopInterception() {
|
|
22409
|
+
if (currentSession === null && registeredProvider === null) return;
|
|
22410
|
+
const session = currentSession;
|
|
22411
|
+
currentSession = null;
|
|
22412
|
+
if (session?.provider) {
|
|
22413
|
+
try {
|
|
22414
|
+
await session.provider.stop();
|
|
22415
|
+
} catch {
|
|
22416
|
+
}
|
|
22417
|
+
}
|
|
22418
|
+
}
|
|
22419
|
+
function hasActiveSession() {
|
|
22420
|
+
return currentSession !== null;
|
|
22421
|
+
}
|
|
22422
|
+
function clearSession() {
|
|
22423
|
+
currentSession = null;
|
|
22424
|
+
}
|
|
22425
|
+
function unsupportedReasons(capabilities) {
|
|
22426
|
+
const reasons = [...capabilities.reasons];
|
|
22427
|
+
if (!capabilities.trustedDeviceLocalCa)
|
|
22428
|
+
reasons.push("device-local-ca-untrusted");
|
|
22429
|
+
if (capabilities.controllingProxy) reasons.push("controlling-proxy");
|
|
22430
|
+
if (capabilities.controllingPac) reasons.push("controlling-pac");
|
|
22431
|
+
if (capabilities.controllingExtension) reasons.push("controlling-extension");
|
|
22432
|
+
if (capabilities.enterprisePolicy) reasons.push("enterprise-policy");
|
|
22433
|
+
return [...new Set(reasons)].sort();
|
|
22434
|
+
}
|
|
22435
|
+
function createPlatformInterceptionProvider(adapter) {
|
|
22436
|
+
let state = "stopped";
|
|
22437
|
+
let active = false;
|
|
22438
|
+
return {
|
|
22439
|
+
platform: adapter.platform,
|
|
22440
|
+
detect() {
|
|
22441
|
+
const capabilities = adapter.detect();
|
|
22442
|
+
const reasons = unsupportedReasons(capabilities);
|
|
22443
|
+
return {
|
|
22444
|
+
supported: capabilities.supported && reasons.length === 0,
|
|
22445
|
+
reasons
|
|
22446
|
+
};
|
|
22447
|
+
},
|
|
22448
|
+
async start(activation, origins) {
|
|
22449
|
+
const capabilities = adapter.detect();
|
|
22450
|
+
const reasons = unsupportedReasons(capabilities);
|
|
22451
|
+
if (!capabilities.supported || reasons.length > 0) {
|
|
22452
|
+
state = "unsupported";
|
|
22453
|
+
throw new Error("runtime.platform-unsupported");
|
|
22454
|
+
}
|
|
22455
|
+
if (!await adapter.provisionOrVerifyCa()) {
|
|
22456
|
+
state = "unsupported";
|
|
22457
|
+
throw new Error("runtime.platform-unsupported");
|
|
22458
|
+
}
|
|
22459
|
+
const endpoint = await adapter.startTlsProxy(activation);
|
|
22460
|
+
const pac = generatePacScript(origins, endpoint);
|
|
22461
|
+
try {
|
|
22462
|
+
await adapter.installPac(pac);
|
|
22463
|
+
active = true;
|
|
22464
|
+
state = "running";
|
|
22465
|
+
return endpoint;
|
|
22466
|
+
} catch (error) {
|
|
22467
|
+
await adapter.stopTlsProxy();
|
|
22468
|
+
active = false;
|
|
22469
|
+
state = "stopped";
|
|
22470
|
+
throw error;
|
|
22471
|
+
}
|
|
22472
|
+
},
|
|
22473
|
+
async stop() {
|
|
22474
|
+
if (!active && state !== "running") {
|
|
22475
|
+
state = state === "unsupported" ? "unsupported" : "stopped";
|
|
22476
|
+
return;
|
|
22477
|
+
}
|
|
22478
|
+
await adapter.removePac();
|
|
22479
|
+
await adapter.stopTlsProxy();
|
|
22480
|
+
active = false;
|
|
22481
|
+
state = "stopped";
|
|
22482
|
+
},
|
|
22483
|
+
status() {
|
|
22484
|
+
return state;
|
|
22485
|
+
}
|
|
22486
|
+
};
|
|
22487
|
+
}
|
|
22488
|
+
var TOKEN_BYTES = 32;
|
|
22489
|
+
var TOKEN_LENGTH = 43;
|
|
22490
|
+
function createCapabilityState(preset, now) {
|
|
22491
|
+
const bootstrap = randomBytes(TOKEN_BYTES).toString("base64url");
|
|
22492
|
+
return {
|
|
22493
|
+
presetDigest: preset.digest,
|
|
22494
|
+
bootstrap,
|
|
22495
|
+
bootstrapDigest: digestToken(bootstrap),
|
|
22496
|
+
bootstrapExpiresAt: now + RUNTIME_LIMITS.bootstrapLifetimeMs,
|
|
22497
|
+
sessions: [],
|
|
22498
|
+
consumed: false,
|
|
22499
|
+
closed: false
|
|
22500
|
+
};
|
|
22501
|
+
}
|
|
22502
|
+
function digestToken(value) {
|
|
22503
|
+
return createHash("sha256").update(value, "utf8").digest();
|
|
22504
|
+
}
|
|
22505
|
+
function isToken(value) {
|
|
22506
|
+
if (typeof value !== "string" || value.length !== TOKEN_LENGTH) return false;
|
|
22507
|
+
if (!/^[A-Za-z0-9_-]+$/.test(value)) return false;
|
|
22508
|
+
try {
|
|
22509
|
+
return Buffer.from(value, "base64url").length === TOKEN_BYTES;
|
|
22510
|
+
} catch {
|
|
22511
|
+
return false;
|
|
22512
|
+
}
|
|
22513
|
+
}
|
|
22514
|
+
function sameToken(value, expectedDigest) {
|
|
22515
|
+
const actual = digestToken(value);
|
|
22516
|
+
return actual.length === expectedDigest.length && timingSafeEqual(actual, expectedDigest);
|
|
22517
|
+
}
|
|
22518
|
+
function sameDigest(value, expected) {
|
|
22519
|
+
if (!isSha256Digest(value) || value.length !== expected.length) return false;
|
|
22520
|
+
const actual = Buffer.from(value, "ascii");
|
|
22521
|
+
const wanted = Buffer.from(expected, "ascii");
|
|
22522
|
+
return timingSafeEqual(actual, wanted);
|
|
22523
|
+
}
|
|
22524
|
+
function cleanSessions(state, now) {
|
|
22525
|
+
for (let index = state.sessions.length - 1; index >= 0; index -= 1) {
|
|
22526
|
+
if (state.sessions[index]?.expiresAt <= now)
|
|
22527
|
+
state.sessions.splice(index, 1);
|
|
22528
|
+
}
|
|
22529
|
+
}
|
|
22530
|
+
function pairCapability(state, capability, digest, now) {
|
|
22531
|
+
cleanSessions(state, now);
|
|
22532
|
+
if (state.closed || state.consumed || !isToken(capability) || typeof digest !== "string" || !sameDigest(digest, state.presetDigest) || now >= state.bootstrapExpiresAt || !sameToken(capability, state.bootstrapDigest)) {
|
|
22533
|
+
return failure("runtime.pairing-denied");
|
|
22534
|
+
}
|
|
22535
|
+
if (state.sessions.length >= RUNTIME_LIMITS.maxConcurrentSessions) {
|
|
22536
|
+
return failure("runtime.overloaded");
|
|
22537
|
+
}
|
|
22538
|
+
state.consumed = true;
|
|
22539
|
+
const sessionCapability = randomBytes(TOKEN_BYTES).toString("base64url");
|
|
22540
|
+
const expiresAt = now + RUNTIME_LIMITS.sessionLifetimeMs;
|
|
22541
|
+
state.sessions.push({
|
|
22542
|
+
digest: Buffer.from(state.presetDigest, "ascii"),
|
|
22543
|
+
expiresAt,
|
|
22544
|
+
tokenDigest: digestToken(sessionCapability),
|
|
22545
|
+
activeOperations: 0
|
|
22546
|
+
});
|
|
22547
|
+
return {
|
|
22548
|
+
ok: true,
|
|
22549
|
+
value: {
|
|
22550
|
+
sessionCapability,
|
|
22551
|
+
expiresInMs: RUNTIME_LIMITS.sessionLifetimeMs
|
|
22552
|
+
}
|
|
22553
|
+
};
|
|
22554
|
+
}
|
|
22555
|
+
function findSession(state, capability, digest, now) {
|
|
22556
|
+
cleanSessions(state, now);
|
|
22557
|
+
if (state.closed || !isToken(capability) || typeof digest !== "string")
|
|
22558
|
+
return null;
|
|
22559
|
+
if (!sameDigest(digest, state.presetDigest)) return null;
|
|
22560
|
+
const candidate = digestToken(capability);
|
|
22561
|
+
for (const session of state.sessions) {
|
|
22562
|
+
if (candidate.length === session.tokenDigest.length && timingSafeEqual(candidate, session.tokenDigest) && sameDigest(digest, session.digest.toString("ascii"))) {
|
|
22563
|
+
return session;
|
|
22564
|
+
}
|
|
22565
|
+
}
|
|
22566
|
+
return null;
|
|
22567
|
+
}
|
|
22568
|
+
function acquireOperation(_state, session) {
|
|
22569
|
+
if (session.activeOperations >= RUNTIME_LIMITS.maxOperationsPerSession) {
|
|
22570
|
+
return failure("runtime.overloaded");
|
|
22571
|
+
}
|
|
22572
|
+
session.activeOperations += 1;
|
|
22573
|
+
return {
|
|
22574
|
+
ok: true,
|
|
22575
|
+
value: () => {
|
|
22576
|
+
session.activeOperations = Math.max(0, session.activeOperations - 1);
|
|
22577
|
+
}
|
|
22578
|
+
};
|
|
22579
|
+
}
|
|
22580
|
+
function closeCapabilityState(state) {
|
|
22581
|
+
state.closed = true;
|
|
22582
|
+
state.consumed = true;
|
|
22583
|
+
state.sessions.length = 0;
|
|
22584
|
+
state.bootstrapDigest.fill(0);
|
|
22585
|
+
}
|
|
22586
|
+
function withinRoot2(root, candidate) {
|
|
22587
|
+
const rest = relative2(root, candidate);
|
|
22588
|
+
return rest.length > 0 && rest !== ".." && !rest.startsWith(`..${sep}`) && !isAbsolute2(rest);
|
|
22589
|
+
}
|
|
22590
|
+
async function readMockFile(root, logicalPath) {
|
|
22591
|
+
const normalized = normalizeLogicalPath(logicalPath);
|
|
22592
|
+
if (normalized === null) return failure("runtime.file-denied");
|
|
22593
|
+
try {
|
|
22594
|
+
const canonicalRoot = await realpath2(root);
|
|
22595
|
+
const candidate = resolve(canonicalRoot, ...normalized.split("/"));
|
|
22596
|
+
const actualPath = await realpath2(candidate);
|
|
22597
|
+
if (!withinRoot2(canonicalRoot, actualPath))
|
|
22598
|
+
return failure("runtime.file-denied");
|
|
22599
|
+
const metadata = await stat(actualPath);
|
|
21593
22600
|
if (!metadata.isFile()) return failure("runtime.file-denied");
|
|
21594
22601
|
if (metadata.size > RUNTIME_LIMITS.maxFileBytes)
|
|
21595
22602
|
return failure("runtime.size-limit");
|
|
@@ -21756,8 +22763,8 @@ function normalizeMockConfig(value, matcherById) {
|
|
|
21756
22763
|
if (!Array.isArray(record.headers) || record.headers.length > LIMITS.maxMockHeadersPerRule)
|
|
21757
22764
|
return null;
|
|
21758
22765
|
const normalizedHeaders = [];
|
|
21759
|
-
for (const
|
|
21760
|
-
const header = normalizeMockHeader(
|
|
22766
|
+
for (const headerValue3 of record.headers) {
|
|
22767
|
+
const header = normalizeMockHeader(headerValue3);
|
|
21761
22768
|
if (header === null) return null;
|
|
21762
22769
|
normalizedHeaders.push(header);
|
|
21763
22770
|
}
|
|
@@ -22046,14 +23053,72 @@ function createNativeRuntimeController(options) {
|
|
|
22046
23053
|
let state = "idle";
|
|
22047
23054
|
let activation;
|
|
22048
23055
|
let capability;
|
|
23056
|
+
let activePolicy = null;
|
|
22049
23057
|
const mockTokens = /* @__PURE__ */ new Map();
|
|
22050
23058
|
let aiClient;
|
|
22051
23059
|
if (options.aiProviderConfig) {
|
|
22052
23060
|
aiClient = createAIClient(options.aiProviderConfig);
|
|
22053
23061
|
}
|
|
23062
|
+
async function bindInterception(current, sessionConfig) {
|
|
23063
|
+
if (sessionConfig.pacOrigins.length === 0) {
|
|
23064
|
+
return {
|
|
23065
|
+
activation: { ...current, pacOrigins: [] },
|
|
23066
|
+
session: null,
|
|
23067
|
+
interception: { active: false, reasons: ["no-pac-origins"] }
|
|
23068
|
+
};
|
|
23069
|
+
}
|
|
23070
|
+
if (hasActiveSession()) {
|
|
23071
|
+
const session2 = getCurrentSession();
|
|
23072
|
+
return {
|
|
23073
|
+
activation: current,
|
|
23074
|
+
session: session2,
|
|
23075
|
+
interception: {
|
|
23076
|
+
active: session2 !== null,
|
|
23077
|
+
reasons: session2 !== null ? [] : ["session-missing"]
|
|
23078
|
+
}
|
|
23079
|
+
};
|
|
23080
|
+
}
|
|
23081
|
+
const result = await startInterception(
|
|
23082
|
+
current,
|
|
23083
|
+
sessionConfig.policyDigest,
|
|
23084
|
+
sessionConfig.extensionId,
|
|
23085
|
+
sessionConfig.pacOrigins,
|
|
23086
|
+
{
|
|
23087
|
+
public: sessionConfig.targetPolicy.public,
|
|
23088
|
+
localOrigins: sessionConfig.targetPolicy.localOrigins
|
|
23089
|
+
}
|
|
23090
|
+
);
|
|
23091
|
+
if (result.kind === "unsupported") {
|
|
23092
|
+
return {
|
|
23093
|
+
activation: current,
|
|
23094
|
+
session: null,
|
|
23095
|
+
interception: { active: false, reasons: [...result.reasons] }
|
|
23096
|
+
};
|
|
23097
|
+
}
|
|
23098
|
+
const session = getCurrentSession();
|
|
23099
|
+
const next = {
|
|
23100
|
+
...current,
|
|
23101
|
+
pacOrigins: sessionConfig.pacOrigins,
|
|
23102
|
+
proxy: result.proxy
|
|
23103
|
+
};
|
|
23104
|
+
return {
|
|
23105
|
+
activation: next,
|
|
23106
|
+
session,
|
|
23107
|
+
interception: { active: true, reasons: [] }
|
|
23108
|
+
};
|
|
23109
|
+
}
|
|
22054
23110
|
return {
|
|
22055
23111
|
async start(sessionConfig) {
|
|
22056
23112
|
if (state === "running" || state === "starting") {
|
|
23113
|
+
if (sessionConfig && activation) {
|
|
23114
|
+
const bound = await bindInterception(activation, sessionConfig);
|
|
23115
|
+
activation = bound.activation;
|
|
23116
|
+
return {
|
|
23117
|
+
state: "running",
|
|
23118
|
+
activation,
|
|
23119
|
+
session: bound.session
|
|
23120
|
+
};
|
|
23121
|
+
}
|
|
22057
23122
|
if (activation) return { state: "running", activation };
|
|
22058
23123
|
return { state };
|
|
22059
23124
|
}
|
|
@@ -22070,22 +23135,13 @@ function createNativeRuntimeController(options) {
|
|
|
22070
23135
|
state: "running",
|
|
22071
23136
|
startedAt,
|
|
22072
23137
|
presetDigest: preset.digest,
|
|
22073
|
-
pacOrigins: []
|
|
23138
|
+
pacOrigins: sessionConfig?.pacOrigins ?? []
|
|
22074
23139
|
};
|
|
22075
23140
|
let session = null;
|
|
22076
23141
|
if (sessionConfig) {
|
|
22077
|
-
const
|
|
22078
|
-
|
|
22079
|
-
|
|
22080
|
-
sessionConfig.extensionId,
|
|
22081
|
-
sessionConfig.pacOrigins,
|
|
22082
|
-
sessionConfig.targetPolicy
|
|
22083
|
-
);
|
|
22084
|
-
if (result.kind !== "unsupported") {
|
|
22085
|
-
session = hasActiveSession() ? getCurrentSession2() : null;
|
|
22086
|
-
if (session)
|
|
22087
|
-
activation = { ...activation, pacOrigins: session.pacOrigins };
|
|
22088
|
-
}
|
|
23142
|
+
const bound = await bindInterception(activation, sessionConfig);
|
|
23143
|
+
activation = bound.activation;
|
|
23144
|
+
session = bound.session;
|
|
22089
23145
|
}
|
|
22090
23146
|
if (options.onStart) await options.onStart(activation, session);
|
|
22091
23147
|
state = "running";
|
|
@@ -22105,6 +23161,7 @@ function createNativeRuntimeController(options) {
|
|
|
22105
23161
|
if (capability) closeCapabilityState(capability);
|
|
22106
23162
|
mockTokens.clear();
|
|
22107
23163
|
activation = void 0;
|
|
23164
|
+
activePolicy = null;
|
|
22108
23165
|
state = "stopped";
|
|
22109
23166
|
return { state: "stopped" };
|
|
22110
23167
|
},
|
|
@@ -22112,7 +23169,10 @@ function createNativeRuntimeController(options) {
|
|
|
22112
23169
|
return { state };
|
|
22113
23170
|
},
|
|
22114
23171
|
getSession() {
|
|
22115
|
-
return hasActiveSession() ?
|
|
23172
|
+
return hasActiveSession() ? getCurrentSession() : null;
|
|
23173
|
+
},
|
|
23174
|
+
getActivePolicy() {
|
|
23175
|
+
return activePolicy;
|
|
22116
23176
|
},
|
|
22117
23177
|
async serveMock(token) {
|
|
22118
23178
|
const mock = mockTokens.get(token);
|
|
@@ -22207,6 +23267,10 @@ function createNativeRuntimeController(options) {
|
|
|
22207
23267
|
};
|
|
22208
23268
|
}
|
|
22209
23269
|
preset = normalized.value;
|
|
23270
|
+
activePolicy = {
|
|
23271
|
+
project: schemaResult.data,
|
|
23272
|
+
operations: compileResult.operations
|
|
23273
|
+
};
|
|
22210
23274
|
const startResult = await this.start();
|
|
22211
23275
|
if (startResult.state !== "running") {
|
|
22212
23276
|
return {
|
|
@@ -22225,6 +23289,64 @@ function createNativeRuntimeController(options) {
|
|
|
22225
23289
|
metadata: { ok: true, presetDigest: preset.digest }
|
|
22226
23290
|
};
|
|
22227
23291
|
}
|
|
23292
|
+
if (input.type === "runtime.project.set" && state === "running") {
|
|
23293
|
+
return {
|
|
23294
|
+
protocol: "v1",
|
|
23295
|
+
type: "runtime.project.set",
|
|
23296
|
+
...requestId !== void 0 ? { requestId } : {},
|
|
23297
|
+
timestamp,
|
|
23298
|
+
metadata: { ok: false, error: "runtime.already-started" }
|
|
23299
|
+
};
|
|
23300
|
+
}
|
|
23301
|
+
if (input.type === "runtime.start") {
|
|
23302
|
+
if (state === "idle" || !preset || activation === void 0) {
|
|
23303
|
+
return {
|
|
23304
|
+
protocol: "v1",
|
|
23305
|
+
type: "runtime.start",
|
|
23306
|
+
...requestId !== void 0 ? { requestId } : {},
|
|
23307
|
+
timestamp,
|
|
23308
|
+
metadata: {
|
|
23309
|
+
ok: false,
|
|
23310
|
+
error: "runtime.not-ready",
|
|
23311
|
+
interception: { active: false, reasons: ["not-ready"] }
|
|
23312
|
+
}
|
|
23313
|
+
};
|
|
23314
|
+
}
|
|
23315
|
+
const meta = input.metadata;
|
|
23316
|
+
const sessionConfig = {
|
|
23317
|
+
policyDigest: typeof meta.policyDigest === "string" ? meta.policyDigest : "",
|
|
23318
|
+
extensionId: typeof meta.extensionId === "string" ? meta.extensionId : "",
|
|
23319
|
+
pacOrigins: Array.isArray(meta.pacOrigins) ? meta.pacOrigins : [],
|
|
23320
|
+
targetPolicy: {
|
|
23321
|
+
public: meta.targetPolicy?.public === true || meta.targetPolicy?.publicAllowed === true,
|
|
23322
|
+
localOrigins: Array.isArray(meta.targetPolicy?.localOrigins) ? meta.targetPolicy.localOrigins : []
|
|
23323
|
+
}
|
|
23324
|
+
};
|
|
23325
|
+
const bound = await bindInterception(activation, sessionConfig);
|
|
23326
|
+
activation = bound.activation;
|
|
23327
|
+
return {
|
|
23328
|
+
protocol: "v1",
|
|
23329
|
+
type: "runtime.start",
|
|
23330
|
+
...requestId !== void 0 ? { requestId } : {},
|
|
23331
|
+
timestamp,
|
|
23332
|
+
metadata: {
|
|
23333
|
+
ok: bound.interception.active,
|
|
23334
|
+
interception: bound.interception,
|
|
23335
|
+
...activation.proxy !== void 0 ? { proxy: activation.proxy } : {},
|
|
23336
|
+
pacOrigins: activation.pacOrigins
|
|
23337
|
+
}
|
|
23338
|
+
};
|
|
23339
|
+
}
|
|
23340
|
+
if (input.type === "runtime.stop") {
|
|
23341
|
+
await this.stop();
|
|
23342
|
+
return {
|
|
23343
|
+
protocol: "v1",
|
|
23344
|
+
type: "runtime.stop",
|
|
23345
|
+
...requestId !== void 0 ? { requestId } : {},
|
|
23346
|
+
timestamp,
|
|
23347
|
+
metadata: { ok: true, state: "stopped" }
|
|
23348
|
+
};
|
|
23349
|
+
}
|
|
22228
23350
|
if (state !== "running" || capability === void 0) {
|
|
22229
23351
|
throw new Error("runtime not started");
|
|
22230
23352
|
}
|
|
@@ -22512,200 +23634,18 @@ function createNativeRuntimeController(options) {
|
|
|
22512
23634
|
headers.push([header[0], header[1]]);
|
|
22513
23635
|
}
|
|
22514
23636
|
const metadata = {
|
|
22515
|
-
status: rendered.value.status,
|
|
22516
|
-
headers,
|
|
22517
|
-
mockBody: base64(rendered.value.bodyBytes)
|
|
22518
|
-
};
|
|
22519
|
-
return {
|
|
22520
|
-
protocol: "v1",
|
|
22521
|
-
type: "mock.response",
|
|
22522
|
-
...requestId !== void 0 ? { requestId } : {},
|
|
22523
|
-
timestamp,
|
|
22524
|
-
metadata
|
|
22525
|
-
};
|
|
22526
|
-
}
|
|
22527
|
-
}
|
|
22528
|
-
function getCurrentSession2() {
|
|
22529
|
-
return null;
|
|
22530
|
-
}
|
|
22531
|
-
function encodeEnvelopeFrame(envelope) {
|
|
22532
|
-
const json = new TextEncoder().encode(serializeEnvelope(envelope));
|
|
22533
|
-
const out = new Uint8Array(4 + json.byteLength);
|
|
22534
|
-
new DataView(out.buffer).setUint32(0, json.byteLength, true);
|
|
22535
|
-
out.set(json, 4);
|
|
22536
|
-
return out;
|
|
22537
|
-
}
|
|
22538
|
-
function decodeEnvelopeFrame(buffer) {
|
|
22539
|
-
if (buffer.byteLength < 4) throw new Error("frame too small");
|
|
22540
|
-
const length = new DataView(buffer.buffer, buffer.byteOffset, 4).getUint32(
|
|
22541
|
-
0,
|
|
22542
|
-
true
|
|
22543
|
-
);
|
|
22544
|
-
if (buffer.byteLength !== 4 + length)
|
|
22545
|
-
throw new Error("frame length mismatch");
|
|
22546
|
-
const json = new TextDecoder("utf-8", { fatal: true }).decode(
|
|
22547
|
-
buffer.slice(4)
|
|
22548
|
-
);
|
|
22549
|
-
return parseEnvelope(json);
|
|
22550
|
-
}
|
|
22551
|
-
function startMockFaucet(port, controller) {
|
|
22552
|
-
const server = createServer((req, res) => {
|
|
22553
|
-
void (async () => {
|
|
22554
|
-
try {
|
|
22555
|
-
const url = new URL(req.url ?? "", "http://localhost");
|
|
22556
|
-
const match = /^\/mock\/([a-f0-9]+)$/.exec(url.pathname);
|
|
22557
|
-
if (!match || req.method !== "GET") {
|
|
22558
|
-
res.writeHead(404);
|
|
22559
|
-
res.end();
|
|
22560
|
-
return;
|
|
22561
|
-
}
|
|
22562
|
-
const result = await controller.serveMock(match[1]);
|
|
22563
|
-
if (!result.ok) {
|
|
22564
|
-
res.writeHead(404);
|
|
22565
|
-
res.end();
|
|
22566
|
-
return;
|
|
22567
|
-
}
|
|
22568
|
-
const { status, headers, bodyBytes } = result.value;
|
|
22569
|
-
res.writeHead(
|
|
22570
|
-
status,
|
|
22571
|
-
Object.fromEntries(
|
|
22572
|
-
headers.map((h) => [h[0], h[1]])
|
|
22573
|
-
)
|
|
22574
|
-
);
|
|
22575
|
-
res.end(Buffer2.from(bodyBytes));
|
|
22576
|
-
} catch {
|
|
22577
|
-
if (!res.headersSent) res.writeHead(500);
|
|
22578
|
-
res.end();
|
|
22579
|
-
}
|
|
22580
|
-
})();
|
|
22581
|
-
});
|
|
22582
|
-
return new Promise(
|
|
22583
|
-
(resolve22) => server.listen(port, () => resolve22(server))
|
|
22584
|
-
);
|
|
22585
|
-
}
|
|
22586
|
-
function createNativeHost(options) {
|
|
22587
|
-
const controller = createNativeRuntimeController({
|
|
22588
|
-
preset: options.preset,
|
|
22589
|
-
fileRoot: options.fileRoot,
|
|
22590
|
-
...options.mockPort !== void 0 ? { mockPort: options.mockPort } : {},
|
|
22591
|
-
...options.aiProviderConfig !== void 0 ? { aiProviderConfig: options.aiProviderConfig } : {},
|
|
22592
|
-
...options.clock ? { clock: options.clock } : {}
|
|
22593
|
-
});
|
|
22594
|
-
let faucet = null;
|
|
22595
|
-
return {
|
|
22596
|
-
controller,
|
|
22597
|
-
mockPort: options.mockPort ?? null,
|
|
22598
|
-
async start() {
|
|
22599
|
-
await controller.start();
|
|
22600
|
-
if (options.mockPort !== void 0) {
|
|
22601
|
-
faucet = await startMockFaucet(options.mockPort, controller);
|
|
22602
|
-
}
|
|
22603
|
-
},
|
|
22604
|
-
async stop() {
|
|
22605
|
-
if (faucet) {
|
|
22606
|
-
await new Promise((resolve22) => faucet?.close(() => resolve22()));
|
|
22607
|
-
faucet = null;
|
|
22608
|
-
}
|
|
22609
|
-
await controller.stop();
|
|
22610
|
-
},
|
|
22611
|
-
async processFrame(frame) {
|
|
22612
|
-
let envelope;
|
|
22613
|
-
try {
|
|
22614
|
-
envelope = decodeEnvelopeFrame(frame);
|
|
22615
|
-
} catch (error) {
|
|
22616
|
-
console.error(
|
|
22617
|
-
"[rogatio-host] decodeEnvelopeFrame failed:",
|
|
22618
|
-
error instanceof Error ? error.message : String(error)
|
|
22619
|
-
);
|
|
22620
|
-
return null;
|
|
22621
|
-
}
|
|
22622
|
-
console.error(
|
|
22623
|
-
"[rogatio-host] received envelope:",
|
|
22624
|
-
envelope.type,
|
|
22625
|
-
"requestId:",
|
|
22626
|
-
envelope.requestId
|
|
22627
|
-
);
|
|
22628
|
-
let response;
|
|
22629
|
-
try {
|
|
22630
|
-
response = await controller.handleEnvelope(envelope);
|
|
22631
|
-
} catch (error) {
|
|
22632
|
-
console.error(
|
|
22633
|
-
"[rogatio-host] handleEnvelope failed:",
|
|
22634
|
-
error instanceof Error ? error.message : String(error)
|
|
22635
|
-
);
|
|
22636
|
-
return null;
|
|
22637
|
-
}
|
|
22638
|
-
try {
|
|
22639
|
-
return encodeEnvelopeFrame(response);
|
|
22640
|
-
} catch {
|
|
22641
|
-
return null;
|
|
22642
|
-
}
|
|
22643
|
-
}
|
|
22644
|
-
};
|
|
22645
|
-
}
|
|
22646
|
-
async function runNativeHost(options) {
|
|
22647
|
-
const host = createNativeHost(options);
|
|
22648
|
-
await host.start();
|
|
22649
|
-
const stdin = options.stdin ?? process.stdin;
|
|
22650
|
-
const stdout = options.stdout ?? process.stdout;
|
|
22651
|
-
if (options.onReady) options.onReady();
|
|
22652
|
-
let buffer = Buffer2.alloc(0);
|
|
22653
|
-
stdin.on("data", (chunk) => {
|
|
22654
|
-
const buf = Buffer2.isBuffer(chunk) ? chunk : Buffer2.from(chunk);
|
|
22655
|
-
console.error(
|
|
22656
|
-
"[rogatio-host] stdin data:",
|
|
22657
|
-
buf.length,
|
|
22658
|
-
"bytes, buffer:",
|
|
22659
|
-
buffer.length
|
|
22660
|
-
);
|
|
22661
|
-
buffer = Buffer2.concat([buffer, buf]);
|
|
22662
|
-
void (async () => {
|
|
22663
|
-
for (; ; ) {
|
|
22664
|
-
if (buffer.length < 4) break;
|
|
22665
|
-
const length = buffer.readUInt32LE(0);
|
|
22666
|
-
if (buffer.length < 4 + length) break;
|
|
22667
|
-
const frame = new Uint8Array(
|
|
22668
|
-
buffer.buffer,
|
|
22669
|
-
buffer.byteOffset,
|
|
22670
|
-
4 + length
|
|
22671
|
-
);
|
|
22672
|
-
console.error("[rogatio-host] processing frame:", 4 + length, "bytes");
|
|
22673
|
-
const response = await host.processFrame(frame);
|
|
22674
|
-
buffer = buffer.subarray(4 + length);
|
|
22675
|
-
if (response && stdout.writable) {
|
|
22676
|
-
console.error(
|
|
22677
|
-
"[rogatio-host] writing response:",
|
|
22678
|
-
response.length,
|
|
22679
|
-
"bytes"
|
|
22680
|
-
);
|
|
22681
|
-
stdout.write(Buffer2.from(response));
|
|
22682
|
-
} else {
|
|
22683
|
-
console.error("[rogatio-host] no response to write");
|
|
22684
|
-
}
|
|
22685
|
-
}
|
|
22686
|
-
})();
|
|
22687
|
-
});
|
|
22688
|
-
await new Promise((resolve22) => {
|
|
22689
|
-
stdin.on("end", () => {
|
|
22690
|
-
void host.stop().then(resolve22);
|
|
22691
|
-
});
|
|
22692
|
-
});
|
|
22693
|
-
}
|
|
22694
|
-
var NATIVE_FRAME_MAX_BYTES = 64 * 1024;
|
|
22695
|
-
var NATIVE_POLICY_MAX_BYTES = 256 * 1024;
|
|
22696
|
-
var PRIVATE_RANGES = [
|
|
22697
|
-
{ start: ipToInt("10.0.0.0"), end: ipToInt("10.255.255.255") },
|
|
22698
|
-
{ start: ipToInt("172.16.0.0"), end: ipToInt("172.31.255.255") },
|
|
22699
|
-
{ start: ipToInt("192.168.0.0"), end: ipToInt("192.168.255.255") },
|
|
22700
|
-
{ start: ipToInt("127.0.0.0"), end: ipToInt("127.255.255.255") },
|
|
22701
|
-
{ start: ipToInt("169.254.0.0"), end: ipToInt("169.254.255.255") },
|
|
22702
|
-
{ start: ipToInt("0.0.0.0"), end: ipToInt("0.255.255.255") },
|
|
22703
|
-
{ start: ipToInt("224.0.0.0"), end: ipToInt("239.255.255.255") },
|
|
22704
|
-
{ start: ipToInt("240.0.0.0"), end: ipToInt("255.255.255.255") }
|
|
22705
|
-
];
|
|
22706
|
-
function ipToInt(ip) {
|
|
22707
|
-
const parts = ip.split(".").map(Number);
|
|
22708
|
-
return parts[0] << 24 | parts[1] << 16 | parts[2] << 8 | parts[3];
|
|
23637
|
+
status: rendered.value.status,
|
|
23638
|
+
headers,
|
|
23639
|
+
mockBody: base64(rendered.value.bodyBytes)
|
|
23640
|
+
};
|
|
23641
|
+
return {
|
|
23642
|
+
protocol: "v1",
|
|
23643
|
+
type: "mock.response",
|
|
23644
|
+
...requestId !== void 0 ? { requestId } : {},
|
|
23645
|
+
timestamp,
|
|
23646
|
+
metadata
|
|
23647
|
+
};
|
|
23648
|
+
}
|
|
22709
23649
|
}
|
|
22710
23650
|
var import_reflect_metadata = __toESM(require_Reflect(), 1);
|
|
22711
23651
|
var import_x509 = __toESM(require_x509_cjs(), 1);
|
|
@@ -22742,7 +23682,7 @@ async function createCertificate(subjectName, _privateKey, validityDays) {
|
|
|
22742
23682
|
return { certPem, keyPem };
|
|
22743
23683
|
}
|
|
22744
23684
|
function generateCaKeyPair(bits = 2048) {
|
|
22745
|
-
return
|
|
23685
|
+
return generateKeyPairSync("rsa", { modulusLength: bits });
|
|
22746
23686
|
}
|
|
22747
23687
|
var TRUST_LIMITS = {
|
|
22748
23688
|
manifestMaxBytes: 4096,
|
|
@@ -23067,6 +24007,323 @@ function createRequestBodyTrustController(options = {}) {
|
|
|
23067
24007
|
}
|
|
23068
24008
|
return { install, uninstall, status, verify };
|
|
23069
24009
|
}
|
|
24010
|
+
function encodeEnvelopeFrame(envelope) {
|
|
24011
|
+
const json = new TextEncoder().encode(serializeEnvelope(envelope));
|
|
24012
|
+
const out = new Uint8Array(4 + json.byteLength);
|
|
24013
|
+
new DataView(out.buffer).setUint32(0, json.byteLength, true);
|
|
24014
|
+
out.set(json, 4);
|
|
24015
|
+
return out;
|
|
24016
|
+
}
|
|
24017
|
+
function decodeEnvelopeFrame(buffer) {
|
|
24018
|
+
if (buffer.byteLength < 4) throw new Error("frame too small");
|
|
24019
|
+
const length = new DataView(buffer.buffer, buffer.byteOffset, 4).getUint32(
|
|
24020
|
+
0,
|
|
24021
|
+
true
|
|
24022
|
+
);
|
|
24023
|
+
if (buffer.byteLength !== 4 + length)
|
|
24024
|
+
throw new Error("frame length mismatch");
|
|
24025
|
+
const json = new TextDecoder("utf-8", { fatal: true }).decode(
|
|
24026
|
+
buffer.slice(4)
|
|
24027
|
+
);
|
|
24028
|
+
return parseEnvelope(json);
|
|
24029
|
+
}
|
|
24030
|
+
function startMockFaucet(port, controller) {
|
|
24031
|
+
const server = createServer2((req, res) => {
|
|
24032
|
+
void (async () => {
|
|
24033
|
+
try {
|
|
24034
|
+
const url = new URL(req.url ?? "", "http://localhost");
|
|
24035
|
+
const match = /^\/mock\/([a-f0-9]+)$/.exec(url.pathname);
|
|
24036
|
+
if (!match || req.method !== "GET") {
|
|
24037
|
+
res.writeHead(404);
|
|
24038
|
+
res.end();
|
|
24039
|
+
return;
|
|
24040
|
+
}
|
|
24041
|
+
const result = await controller.serveMock(match[1]);
|
|
24042
|
+
if (!result.ok) {
|
|
24043
|
+
res.writeHead(404);
|
|
24044
|
+
res.end();
|
|
24045
|
+
return;
|
|
24046
|
+
}
|
|
24047
|
+
const { status, headers, bodyBytes } = result.value;
|
|
24048
|
+
res.writeHead(
|
|
24049
|
+
status,
|
|
24050
|
+
Object.fromEntries(
|
|
24051
|
+
headers.map((h) => [h[0], h[1]])
|
|
24052
|
+
)
|
|
24053
|
+
);
|
|
24054
|
+
res.end(Buffer2.from(bodyBytes));
|
|
24055
|
+
} catch {
|
|
24056
|
+
if (!res.headersSent) res.writeHead(500);
|
|
24057
|
+
res.end();
|
|
24058
|
+
}
|
|
24059
|
+
})();
|
|
24060
|
+
});
|
|
24061
|
+
return new Promise(
|
|
24062
|
+
(resolve22) => server.listen(port, () => resolve22(server))
|
|
24063
|
+
);
|
|
24064
|
+
}
|
|
24065
|
+
function defaultTrustRoot() {
|
|
24066
|
+
return defaultTrustInstallRoot(process.platform);
|
|
24067
|
+
}
|
|
24068
|
+
function createNativeHost(options) {
|
|
24069
|
+
const controller = createNativeRuntimeController({
|
|
24070
|
+
preset: options.preset,
|
|
24071
|
+
fileRoot: options.fileRoot,
|
|
24072
|
+
...options.mockPort !== void 0 ? { mockPort: options.mockPort } : {},
|
|
24073
|
+
...options.aiProviderConfig !== void 0 ? { aiProviderConfig: options.aiProviderConfig } : {},
|
|
24074
|
+
...options.clock ? { clock: options.clock } : {}
|
|
24075
|
+
});
|
|
24076
|
+
let faucet = null;
|
|
24077
|
+
let interceptProxy = null;
|
|
24078
|
+
let outboundWrite = null;
|
|
24079
|
+
let hostRequestCounter = 0;
|
|
24080
|
+
const pendingHost = /* @__PURE__ */ new Map();
|
|
24081
|
+
function sendHostRequest(type, metadata) {
|
|
24082
|
+
const requestId = `host-${++hostRequestCounter}`;
|
|
24083
|
+
const envelope = {
|
|
24084
|
+
protocol: "v1",
|
|
24085
|
+
type,
|
|
24086
|
+
requestId,
|
|
24087
|
+
timestamp: Date.now(),
|
|
24088
|
+
metadata
|
|
24089
|
+
};
|
|
24090
|
+
return new Promise((resolve22, reject) => {
|
|
24091
|
+
if (!outboundWrite) {
|
|
24092
|
+
reject(new Error("host stdout not attached"));
|
|
24093
|
+
return;
|
|
24094
|
+
}
|
|
24095
|
+
pendingHost.set(requestId, { resolve: resolve22, reject });
|
|
24096
|
+
try {
|
|
24097
|
+
outboundWrite(encodeEnvelopeFrame(envelope));
|
|
24098
|
+
} catch (error) {
|
|
24099
|
+
pendingHost.delete(requestId);
|
|
24100
|
+
reject(error instanceof Error ? error : new Error(String(error)));
|
|
24101
|
+
return;
|
|
24102
|
+
}
|
|
24103
|
+
setTimeout(() => {
|
|
24104
|
+
if (pendingHost.has(requestId)) {
|
|
24105
|
+
pendingHost.delete(requestId);
|
|
24106
|
+
reject(new Error("host pac request timed out"));
|
|
24107
|
+
}
|
|
24108
|
+
}, 1e4);
|
|
24109
|
+
});
|
|
24110
|
+
}
|
|
24111
|
+
const trustRoot = options.trustRoot ?? defaultTrustRoot();
|
|
24112
|
+
const caKeyFile = join3(trustRoot, ".rogatio-ca.key");
|
|
24113
|
+
const caCertFile = join3(trustRoot, ".rogatio-ca.crt");
|
|
24114
|
+
const platformAdapter = {
|
|
24115
|
+
platform: process.platform,
|
|
24116
|
+
detect() {
|
|
24117
|
+
const trusted = existsSync(caKeyFile) && existsSync(caCertFile);
|
|
24118
|
+
return {
|
|
24119
|
+
supported: true,
|
|
24120
|
+
reasons: [],
|
|
24121
|
+
trustedDeviceLocalCa: trusted,
|
|
24122
|
+
controllingProxy: false,
|
|
24123
|
+
controllingPac: false,
|
|
24124
|
+
controllingExtension: false,
|
|
24125
|
+
enterprisePolicy: false
|
|
24126
|
+
};
|
|
24127
|
+
},
|
|
24128
|
+
async provisionOrVerifyCa() {
|
|
24129
|
+
return existsSync(caKeyFile) && existsSync(caCertFile);
|
|
24130
|
+
},
|
|
24131
|
+
async installPac(script) {
|
|
24132
|
+
const response = await sendHostRequest("runtime.pac.install", {
|
|
24133
|
+
script
|
|
24134
|
+
});
|
|
24135
|
+
if (response.metadata.ok !== true) {
|
|
24136
|
+
const error = typeof response.metadata.error === "string" ? response.metadata.error : "pac-install-failed";
|
|
24137
|
+
throw new Error(error);
|
|
24138
|
+
}
|
|
24139
|
+
},
|
|
24140
|
+
async removePac() {
|
|
24141
|
+
try {
|
|
24142
|
+
await sendHostRequest("runtime.pac.remove", {});
|
|
24143
|
+
} catch {
|
|
24144
|
+
}
|
|
24145
|
+
},
|
|
24146
|
+
async startTlsProxy() {
|
|
24147
|
+
if (interceptProxy) {
|
|
24148
|
+
await interceptProxy.stop();
|
|
24149
|
+
interceptProxy = null;
|
|
24150
|
+
}
|
|
24151
|
+
const policy = controller.getActivePolicy();
|
|
24152
|
+
interceptProxy = await startInterceptProxy({
|
|
24153
|
+
policy: policy ? { project: policy.project, operations: policy.operations } : null
|
|
24154
|
+
});
|
|
24155
|
+
return interceptProxy.endpoint;
|
|
24156
|
+
},
|
|
24157
|
+
async stopTlsProxy() {
|
|
24158
|
+
if (interceptProxy) {
|
|
24159
|
+
await interceptProxy.stop();
|
|
24160
|
+
interceptProxy = null;
|
|
24161
|
+
}
|
|
24162
|
+
}
|
|
24163
|
+
};
|
|
24164
|
+
const platformProvider = createPlatformInterceptionProvider(platformAdapter);
|
|
24165
|
+
let pendingOrigins = [];
|
|
24166
|
+
registerInterceptionProvider({
|
|
24167
|
+
platform: platformProvider.platform,
|
|
24168
|
+
detect: () => platformProvider.detect(),
|
|
24169
|
+
async start(activation) {
|
|
24170
|
+
const origins = pendingOrigins.length > 0 ? pendingOrigins : activation.pacOrigins;
|
|
24171
|
+
const endpoint = await platformProvider.start(activation, origins);
|
|
24172
|
+
const policy = controller.getActivePolicy();
|
|
24173
|
+
interceptProxy?.setPolicy(
|
|
24174
|
+
policy ? { project: policy.project, operations: policy.operations } : null
|
|
24175
|
+
);
|
|
24176
|
+
return endpoint;
|
|
24177
|
+
},
|
|
24178
|
+
async stop() {
|
|
24179
|
+
await platformProvider.stop();
|
|
24180
|
+
}
|
|
24181
|
+
});
|
|
24182
|
+
const handle = {
|
|
24183
|
+
controller,
|
|
24184
|
+
mockPort: options.mockPort ?? null,
|
|
24185
|
+
async start() {
|
|
24186
|
+
await controller.start();
|
|
24187
|
+
if (options.mockPort !== void 0) {
|
|
24188
|
+
faucet = await startMockFaucet(options.mockPort, controller);
|
|
24189
|
+
}
|
|
24190
|
+
},
|
|
24191
|
+
async stop() {
|
|
24192
|
+
if (faucet) {
|
|
24193
|
+
await new Promise((resolve22) => faucet?.close(() => resolve22()));
|
|
24194
|
+
faucet = null;
|
|
24195
|
+
}
|
|
24196
|
+
await controller.stop();
|
|
24197
|
+
clearSession();
|
|
24198
|
+
if (interceptProxy) {
|
|
24199
|
+
await interceptProxy.stop();
|
|
24200
|
+
interceptProxy = null;
|
|
24201
|
+
}
|
|
24202
|
+
},
|
|
24203
|
+
async processFrame(frame) {
|
|
24204
|
+
let envelope;
|
|
24205
|
+
try {
|
|
24206
|
+
envelope = decodeEnvelopeFrame(frame);
|
|
24207
|
+
} catch (error) {
|
|
24208
|
+
console.error(
|
|
24209
|
+
"[rogatio-host] decodeEnvelopeFrame failed:",
|
|
24210
|
+
error instanceof Error ? error.message : String(error)
|
|
24211
|
+
);
|
|
24212
|
+
return null;
|
|
24213
|
+
}
|
|
24214
|
+
if (typeof envelope.requestId === "string" && envelope.requestId.startsWith("host-")) {
|
|
24215
|
+
const pending = pendingHost.get(envelope.requestId);
|
|
24216
|
+
if (pending) {
|
|
24217
|
+
pendingHost.delete(envelope.requestId);
|
|
24218
|
+
pending.resolve(envelope);
|
|
24219
|
+
return null;
|
|
24220
|
+
}
|
|
24221
|
+
}
|
|
24222
|
+
if (envelope.type === "runtime.start") {
|
|
24223
|
+
const origins = envelope.metadata.pacOrigins;
|
|
24224
|
+
pendingOrigins = Array.isArray(origins) ? origins.filter((o) => typeof o === "string") : [];
|
|
24225
|
+
}
|
|
24226
|
+
console.error(
|
|
24227
|
+
"[rogatio-host] received envelope:",
|
|
24228
|
+
envelope.type,
|
|
24229
|
+
"requestId:",
|
|
24230
|
+
envelope.requestId
|
|
24231
|
+
);
|
|
24232
|
+
let response;
|
|
24233
|
+
try {
|
|
24234
|
+
response = await controller.handleEnvelope(envelope);
|
|
24235
|
+
} catch (error) {
|
|
24236
|
+
console.error(
|
|
24237
|
+
"[rogatio-host] handleEnvelope failed:",
|
|
24238
|
+
error instanceof Error ? error.message : String(error)
|
|
24239
|
+
);
|
|
24240
|
+
return null;
|
|
24241
|
+
}
|
|
24242
|
+
try {
|
|
24243
|
+
return encodeEnvelopeFrame(response);
|
|
24244
|
+
} catch {
|
|
24245
|
+
return null;
|
|
24246
|
+
}
|
|
24247
|
+
}
|
|
24248
|
+
};
|
|
24249
|
+
Object.defineProperty(handle, "__setOutboundWrite", {
|
|
24250
|
+
value(write) {
|
|
24251
|
+
outboundWrite = write;
|
|
24252
|
+
},
|
|
24253
|
+
enumerable: false
|
|
24254
|
+
});
|
|
24255
|
+
return handle;
|
|
24256
|
+
}
|
|
24257
|
+
async function runNativeHost(options) {
|
|
24258
|
+
const host = createNativeHost(options);
|
|
24259
|
+
const setOutbound = host.__setOutboundWrite;
|
|
24260
|
+
const stdout = options.stdout ?? process.stdout;
|
|
24261
|
+
if (setOutbound) {
|
|
24262
|
+
setOutbound((frame) => {
|
|
24263
|
+
if (stdout.writable) stdout.write(Buffer2.from(frame));
|
|
24264
|
+
});
|
|
24265
|
+
}
|
|
24266
|
+
await host.start();
|
|
24267
|
+
const stdin = options.stdin ?? process.stdin;
|
|
24268
|
+
if (options.onReady) options.onReady();
|
|
24269
|
+
let buffer = Buffer2.alloc(0);
|
|
24270
|
+
stdin.on("data", (chunk) => {
|
|
24271
|
+
const buf = Buffer2.isBuffer(chunk) ? Buffer2.from(chunk) : Buffer2.from(chunk);
|
|
24272
|
+
console.error(
|
|
24273
|
+
"[rogatio-host] stdin data:",
|
|
24274
|
+
buf.length,
|
|
24275
|
+
"bytes, buffer:",
|
|
24276
|
+
buffer.length
|
|
24277
|
+
);
|
|
24278
|
+
buffer = Buffer2.concat([buffer, buf]);
|
|
24279
|
+
void (async () => {
|
|
24280
|
+
for (; ; ) {
|
|
24281
|
+
if (buffer.length < 4) break;
|
|
24282
|
+
const length = buffer.readUInt32LE(0);
|
|
24283
|
+
if (buffer.length < 4 + length) break;
|
|
24284
|
+
const frame = new Uint8Array(
|
|
24285
|
+
buffer.buffer,
|
|
24286
|
+
buffer.byteOffset,
|
|
24287
|
+
4 + length
|
|
24288
|
+
);
|
|
24289
|
+
console.error("[rogatio-host] processing frame:", 4 + length, "bytes");
|
|
24290
|
+
const response = await host.processFrame(frame);
|
|
24291
|
+
buffer = buffer.subarray(4 + length);
|
|
24292
|
+
if (response && stdout.writable) {
|
|
24293
|
+
console.error(
|
|
24294
|
+
"[rogatio-host] writing response:",
|
|
24295
|
+
response.length,
|
|
24296
|
+
"bytes"
|
|
24297
|
+
);
|
|
24298
|
+
stdout.write(Buffer2.from(response));
|
|
24299
|
+
} else {
|
|
24300
|
+
console.error("[rogatio-host] no response to write");
|
|
24301
|
+
}
|
|
24302
|
+
}
|
|
24303
|
+
})();
|
|
24304
|
+
});
|
|
24305
|
+
await new Promise((resolve22) => {
|
|
24306
|
+
stdin.on("end", () => {
|
|
24307
|
+
void host.stop().then(resolve22);
|
|
24308
|
+
});
|
|
24309
|
+
});
|
|
24310
|
+
}
|
|
24311
|
+
var NATIVE_FRAME_MAX_BYTES = 64 * 1024;
|
|
24312
|
+
var NATIVE_POLICY_MAX_BYTES = 256 * 1024;
|
|
24313
|
+
var PRIVATE_RANGES = [
|
|
24314
|
+
{ start: ipToInt("10.0.0.0"), end: ipToInt("10.255.255.255") },
|
|
24315
|
+
{ start: ipToInt("172.16.0.0"), end: ipToInt("172.31.255.255") },
|
|
24316
|
+
{ start: ipToInt("192.168.0.0"), end: ipToInt("192.168.255.255") },
|
|
24317
|
+
{ start: ipToInt("127.0.0.0"), end: ipToInt("127.255.255.255") },
|
|
24318
|
+
{ start: ipToInt("169.254.0.0"), end: ipToInt("169.254.255.255") },
|
|
24319
|
+
{ start: ipToInt("0.0.0.0"), end: ipToInt("0.255.255.255") },
|
|
24320
|
+
{ start: ipToInt("224.0.0.0"), end: ipToInt("239.255.255.255") },
|
|
24321
|
+
{ start: ipToInt("240.0.0.0"), end: ipToInt("255.255.255.255") }
|
|
24322
|
+
];
|
|
24323
|
+
function ipToInt(ip) {
|
|
24324
|
+
const parts = ip.split(".").map(Number);
|
|
24325
|
+
return parts[0] << 24 | parts[1] << 16 | parts[2] << 8 | parts[3];
|
|
24326
|
+
}
|
|
23070
24327
|
var darwinAdapter = {
|
|
23071
24328
|
platform: "darwin",
|
|
23072
24329
|
defaultManifestDir: () => {
|
|
@@ -23108,7 +24365,7 @@ var darwinAdapter = {
|
|
|
23108
24365
|
},
|
|
23109
24366
|
async caTrustInstaller(certPem) {
|
|
23110
24367
|
const keychain = this.defaultCaInstallPath();
|
|
23111
|
-
const tmpPath =
|
|
24368
|
+
const tmpPath = join4(tmpdir(), `rogatio-ca-${Date.now()}.crt`);
|
|
23112
24369
|
try {
|
|
23113
24370
|
writeFileSync(tmpPath, certPem, "utf8");
|
|
23114
24371
|
} catch {
|
|
@@ -23340,7 +24597,7 @@ var win32Adapter = {
|
|
|
23340
24597
|
};
|
|
23341
24598
|
},
|
|
23342
24599
|
async caTrustInstaller(certPem) {
|
|
23343
|
-
const tmpPath =
|
|
24600
|
+
const tmpPath = join5(tmpdir2(), `rogatio-ca-${Date.now()}.crt`);
|
|
23344
24601
|
try {
|
|
23345
24602
|
writeFileSync2(tmpPath, certPem, "utf8");
|
|
23346
24603
|
} catch {
|
|
@@ -23526,36 +24783,78 @@ Options:
|
|
|
23526
24783
|
}
|
|
23527
24784
|
|
|
23528
24785
|
// packages/cli/src/commands/ai.ts
|
|
24786
|
+
var pendingInput = "";
|
|
24787
|
+
function readLine() {
|
|
24788
|
+
return new Promise((resolve9) => {
|
|
24789
|
+
const take = () => {
|
|
24790
|
+
const newline = pendingInput.search(/[\r\n]/u);
|
|
24791
|
+
if (newline === -1) return false;
|
|
24792
|
+
const line = pendingInput.slice(0, newline);
|
|
24793
|
+
pendingInput = pendingInput.slice(newline + 1);
|
|
24794
|
+
resolve9(line);
|
|
24795
|
+
return true;
|
|
24796
|
+
};
|
|
24797
|
+
if (take()) return;
|
|
24798
|
+
const onData = (chunk) => {
|
|
24799
|
+
pendingInput += chunk.toString();
|
|
24800
|
+
if (!take()) return;
|
|
24801
|
+
process.stdin.off("data", onData);
|
|
24802
|
+
process.stdin.pause();
|
|
24803
|
+
};
|
|
24804
|
+
process.stdin.on("data", onData);
|
|
24805
|
+
process.stdin.resume();
|
|
24806
|
+
});
|
|
24807
|
+
}
|
|
23529
24808
|
async function promptInput(prompt) {
|
|
23530
24809
|
process.stdout.write(prompt);
|
|
23531
|
-
|
|
23532
|
-
return chunk.toString().trim();
|
|
23533
|
-
}
|
|
23534
|
-
return "";
|
|
24810
|
+
return (await readLine()).trim();
|
|
23535
24811
|
}
|
|
23536
24812
|
async function promptSecret(prompt) {
|
|
23537
24813
|
process.stdout.write(prompt);
|
|
23538
24814
|
process.stdin.setRawMode(true);
|
|
23539
|
-
|
|
23540
|
-
|
|
23541
|
-
|
|
23542
|
-
|
|
23543
|
-
|
|
23544
|
-
|
|
23545
|
-
|
|
23546
|
-
|
|
23547
|
-
|
|
23548
|
-
|
|
23549
|
-
|
|
23550
|
-
|
|
23551
|
-
|
|
23552
|
-
|
|
23553
|
-
|
|
23554
|
-
|
|
23555
|
-
|
|
24815
|
+
try {
|
|
24816
|
+
return await new Promise((resolve9) => {
|
|
24817
|
+
let input = "";
|
|
24818
|
+
let settled = false;
|
|
24819
|
+
const finish = () => {
|
|
24820
|
+
settled = true;
|
|
24821
|
+
process.stdin.off("data", onData);
|
|
24822
|
+
process.stdin.pause();
|
|
24823
|
+
resolve9(input.trim());
|
|
24824
|
+
};
|
|
24825
|
+
const consume = (text) => {
|
|
24826
|
+
if (settled) return;
|
|
24827
|
+
for (let index = 0; index < text.length; index += 1) {
|
|
24828
|
+
const char = text[index];
|
|
24829
|
+
if (char === "\n" || char === "\r") {
|
|
24830
|
+
process.stdout.write("\n");
|
|
24831
|
+
pendingInput = text.slice(index + 1);
|
|
24832
|
+
finish();
|
|
24833
|
+
return;
|
|
24834
|
+
}
|
|
24835
|
+
if (char === "") {
|
|
24836
|
+
process.exit(1);
|
|
24837
|
+
} else if (char === "\x7F" || char === "\b") {
|
|
24838
|
+
if (input.length > 0) {
|
|
24839
|
+
input = input.slice(0, -1);
|
|
24840
|
+
process.stdout.write("\b \b");
|
|
24841
|
+
}
|
|
24842
|
+
} else {
|
|
24843
|
+
input += char;
|
|
24844
|
+
process.stdout.write("*");
|
|
24845
|
+
}
|
|
24846
|
+
}
|
|
24847
|
+
};
|
|
24848
|
+
const onData = (chunk) => consume(chunk.toString());
|
|
24849
|
+
consume(pendingInput);
|
|
24850
|
+
if (settled) return;
|
|
24851
|
+
pendingInput = "";
|
|
24852
|
+
process.stdin.on("data", onData);
|
|
24853
|
+
process.stdin.resume();
|
|
24854
|
+
});
|
|
24855
|
+
} finally {
|
|
24856
|
+
process.stdin.setRawMode(false);
|
|
23556
24857
|
}
|
|
23557
|
-
process.stdin.setRawMode(false);
|
|
23558
|
-
return input.trim();
|
|
23559
24858
|
}
|
|
23560
24859
|
async function aiCommand(args) {
|
|
23561
24860
|
if (args.includes("--help") || args.includes("-h")) {
|
|
@@ -23718,7 +25017,7 @@ var HttpServerError = class extends Error {
|
|
|
23718
25017
|
this.code = code;
|
|
23719
25018
|
}
|
|
23720
25019
|
};
|
|
23721
|
-
function
|
|
25020
|
+
function createServer3(handler, options = {}) {
|
|
23722
25021
|
const server = createHttpServer(handler);
|
|
23723
25022
|
const preferredPort = options.port;
|
|
23724
25023
|
let port = null;
|
|
@@ -24786,7 +26085,7 @@ import {
|
|
|
24786
26085
|
unlink as unlink2,
|
|
24787
26086
|
writeFile as writeFile3
|
|
24788
26087
|
} from "node:fs/promises";
|
|
24789
|
-
import { basename as basename2, dirname as dirname6, join as
|
|
26088
|
+
import { basename as basename2, dirname as dirname6, join as join6 } from "node:path";
|
|
24790
26089
|
var ProjectStorageError = class extends Error {
|
|
24791
26090
|
code;
|
|
24792
26091
|
id;
|
|
@@ -24949,7 +26248,7 @@ async function isDirectoryPath(id2) {
|
|
|
24949
26248
|
}
|
|
24950
26249
|
async function writeDocument(id2, data) {
|
|
24951
26250
|
const tempName = `.${basename2(dirname6(id2))}.${randomBytes4(8).toString("hex")}.tmp`;
|
|
24952
|
-
const tempPath =
|
|
26251
|
+
const tempPath = join6(dirname6(id2), tempName);
|
|
24953
26252
|
try {
|
|
24954
26253
|
if (await isDirectoryPath(id2)) {
|
|
24955
26254
|
throw new ProjectFileError(
|
|
@@ -25008,7 +26307,7 @@ function createJsonFileProjectStorage() {
|
|
|
25008
26307
|
if (entry.isDirectory() || !isRogatioProjectFilename(entry.name)) {
|
|
25009
26308
|
continue;
|
|
25010
26309
|
}
|
|
25011
|
-
const id2 =
|
|
26310
|
+
const id2 = join6(scope, entry.name);
|
|
25012
26311
|
let name = "";
|
|
25013
26312
|
try {
|
|
25014
26313
|
const data = await readDocument(id2);
|
|
@@ -25197,7 +26496,7 @@ async function editCommand(args, options = {}) {
|
|
|
25197
26496
|
};
|
|
25198
26497
|
let server;
|
|
25199
26498
|
try {
|
|
25200
|
-
server =
|
|
26499
|
+
server = createServer3(
|
|
25201
26500
|
createRoutes(context),
|
|
25202
26501
|
port !== void 0 ? { port } : {}
|
|
25203
26502
|
);
|
|
@@ -25477,7 +26776,7 @@ function generateEditorHtml(apiBase, csrfToken, filePath, aiConfigured) {
|
|
|
25477
26776
|
|
|
25478
26777
|
// packages/cli/src/commands/runtime.ts
|
|
25479
26778
|
import { chmod, mkdir as mkdir4, rm as rm2, writeFile as writeFile4 } from "node:fs/promises";
|
|
25480
|
-
import { dirname as dirname7, join as
|
|
26779
|
+
import { dirname as dirname7, join as join7, resolve as resolve5 } from "node:path";
|
|
25481
26780
|
function toMatcherOperations2(operations) {
|
|
25482
26781
|
return operations.map(
|
|
25483
26782
|
({ groupId, ruleId, name, matcher, redactSensitiveInLogs }) => ({
|
|
@@ -25504,7 +26803,7 @@ exec "${nodeBin}" "${cliScript}" runtime host 2>>"${logPath}"
|
|
|
25504
26803
|
}
|
|
25505
26804
|
async function writeHostWrapper(hostPath, installRoot) {
|
|
25506
26805
|
await mkdir4(installRoot, { recursive: true });
|
|
25507
|
-
const logPath =
|
|
26806
|
+
const logPath = join7(installRoot, "runtime-host.log");
|
|
25508
26807
|
const script = generateHostWrapper(
|
|
25509
26808
|
`${process.execPath} ${process.argv[1] ?? "rogatio"}`,
|
|
25510
26809
|
logPath
|
|
@@ -25519,7 +26818,7 @@ function makeTrustController() {
|
|
|
25519
26818
|
return createRequestBodyTrustController({
|
|
25520
26819
|
platform,
|
|
25521
26820
|
installRoot,
|
|
25522
|
-
hostPath:
|
|
26821
|
+
hostPath: join7(installRoot, "runtime-host"),
|
|
25523
26822
|
hostName: "com.rogatio.runtime",
|
|
25524
26823
|
allowedOrigins: [],
|
|
25525
26824
|
manifestDir: adapter.defaultManifestDir(),
|
|
@@ -25576,7 +26875,7 @@ async function trustRuntimeCommand(args) {
|
|
|
25576
26875
|
}
|
|
25577
26876
|
const controller = makeTrustController();
|
|
25578
26877
|
const installRoot = defaultTrustInstallRoot(process.platform);
|
|
25579
|
-
const hostPath =
|
|
26878
|
+
const hostPath = join7(installRoot, "runtime-host");
|
|
25580
26879
|
switch (subcommand) {
|
|
25581
26880
|
case "install": {
|
|
25582
26881
|
const installResult = await controller.install(extensionId ?? "");
|
|
@@ -25602,7 +26901,7 @@ async function trustRuntimeCommand(args) {
|
|
|
25602
26901
|
} catch {
|
|
25603
26902
|
}
|
|
25604
26903
|
try {
|
|
25605
|
-
await rm2(
|
|
26904
|
+
await rm2(join7(installRoot, "runtime-host.log"), { force: true });
|
|
25606
26905
|
} catch {
|
|
25607
26906
|
}
|
|
25608
26907
|
return reportTrust(
|