@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.
@@ -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 { createServer } from "node:http";
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 as generateKeyPairSync2, webcrypto } from "node:crypto";
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 join3 } from "node:path";
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 join4 } from "node:path";
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 = mergeProposalIntoProject(
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
- var TOKEN_BYTES = 32;
21434
- var TOKEN_LENGTH = 43;
21435
- function createCapabilityState(preset, now) {
21436
- const bootstrap = randomBytes(TOKEN_BYTES).toString("base64url");
21437
- return {
21438
- presetDigest: preset.digest,
21439
- bootstrap,
21440
- bootstrapDigest: digestToken(bootstrap),
21441
- bootstrapExpiresAt: now + RUNTIME_LIMITS.bootstrapLifetimeMs,
21442
- sessions: [],
21443
- consumed: false,
21444
- closed: false
21445
- };
21446
- }
21447
- function digestToken(value) {
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
- return Buffer.from(value, "base64url").length === TOKEN_BYTES;
21455
- } catch {
21456
- return false;
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 sameToken(value, expectedDigest) {
21460
- const actual = digestToken(value);
21461
- return actual.length === expectedDigest.length && timingSafeEqual(actual, expectedDigest);
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 sameDigest(value, expected) {
21464
- if (!isSha256Digest(value) || value.length !== expected.length) return false;
21465
- const actual = Buffer.from(value, "ascii");
21466
- const wanted = Buffer.from(expected, "ascii");
21467
- return timingSafeEqual(actual, wanted);
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 cleanSessions(state, now) {
21470
- for (let index = state.sessions.length - 1; index >= 0; index -= 1) {
21471
- if (state.sessions[index]?.expiresAt <= now)
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
- function pairCapability(state, capability, digest, now) {
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 (state.sessions.length >= RUNTIME_LIMITS.maxConcurrentSessions) {
21481
- return failure("runtime.overloaded");
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
- sessionCapability,
21496
- expiresInMs: RUNTIME_LIMITS.sessionLifetimeMs
21781
+ body: outputBytes,
21782
+ contentType: input.contentType?.split(";", 1)[0]?.trim() ?? "application/octet-stream"
21497
21783
  }
21498
21784
  };
21499
21785
  }
21500
- function findSession(state, capability, digest, now) {
21501
- cleanSessions(state, now);
21502
- if (state.closed || !isToken(capability) || typeof digest !== "string")
21503
- return null;
21504
- if (!sameDigest(digest, state.presetDigest)) return null;
21505
- const candidate = digestToken(capability);
21506
- for (const session of state.sessions) {
21507
- if (candidate.length === session.tokenDigest.length && timingSafeEqual(candidate, session.tokenDigest) && sameDigest(digest, session.digest.toString("ascii"))) {
21508
- return session;
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
- return null;
21512
- }
21513
- function acquireOperation(_state, session) {
21514
- if (session.activeOperations >= RUNTIME_LIMITS.maxOperationsPerSession) {
21515
- return failure("runtime.overloaded");
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
- session.activeOperations = Math.max(0, session.activeOperations - 1);
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 closeCapabilityState(state) {
21526
- state.closed = true;
21527
- state.consumed = true;
21528
- state.sessions.length = 0;
21529
- state.bootstrapDigest.fill(0);
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
- var registeredProvider = null;
21532
- var currentSession = null;
21533
- async function startInterception(activation, policyDigest, extensionId, pacOrigins, targetPolicy) {
21534
- if (registeredProvider === null) {
21535
- return { kind: "unsupported", reasons: ["no-interception-provider"] };
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
- const capabilities = registeredProvider.detect();
21538
- if (!capabilities.supported) {
21539
- return { kind: "unsupported", reasons: capabilities.reasons };
21864
+ if (!projectHasRule(
21865
+ projectSnap.value,
21866
+ request.groupId,
21867
+ request.ruleId
21868
+ )) {
21869
+ return { allowed: false, reason: "project-inconsistent" };
21540
21870
  }
21541
- if (currentSession !== null) {
21542
- return { kind: "unsupported", reasons: ["session-collision"] };
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 sessionId = `session-${activation.startedAt}-${Math.random().toString(36).slice(2)}`;
21545
- try {
21546
- await registeredProvider.start(activation);
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
- currentSession = {
21554
- sessionId,
21555
- provider: registeredProvider,
21556
- activation,
21557
- policyDigest,
21558
- extensionId,
21559
- pacOrigins,
21560
- targetPolicy,
21561
- startedAt: activation.startedAt
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
- async function stopInterception() {
21566
- if (currentSession === null && registeredProvider === null) return;
21567
- const session = currentSession;
21568
- currentSession = null;
21569
- if (session?.provider) {
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 hasActiveSession() {
21577
- return currentSession !== null;
21912
+ function isBodyOp(op) {
21913
+ return op.kind === "request-body" || op.kind === "response-body";
21578
21914
  }
21579
- function withinRoot2(root, candidate) {
21580
- const rest = relative2(root, candidate);
21581
- return rest.length > 0 && rest !== ".." && !rest.startsWith(`..${sep}`) && !isAbsolute2(rest);
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
- async function readMockFile(root, logicalPath) {
21584
- const normalized = normalizeLogicalPath(logicalPath);
21585
- if (normalized === null) return failure("runtime.file-denied");
21586
- try {
21587
- const canonicalRoot = await realpath2(root);
21588
- const candidate = resolve(canonicalRoot, ...normalized.split("/"));
21589
- const actualPath = await realpath2(candidate);
21590
- if (!withinRoot2(canonicalRoot, actualPath))
21591
- return failure("runtime.file-denied");
21592
- const metadata = await stat(actualPath);
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 headerValue2 of record.headers) {
21760
- const header = normalizeMockHeader(headerValue2);
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 result = await startInterception(
22078
- activation,
22079
- sessionConfig.policyDigest,
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() ? getCurrentSession2() : null;
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 generateKeyPairSync2("rsa", { modulusLength: bits });
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 = join3(tmpdir(), `rogatio-ca-${Date.now()}.crt`);
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 = join4(tmpdir2(), `rogatio-ca-${Date.now()}.crt`);
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
- for await (const chunk of process.stdin) {
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
- let input = "";
23540
- for await (const chunk of process.stdin) {
23541
- const char = chunk.toString();
23542
- if (char === "\n" || char === "\r") {
23543
- process.stdout.write("\n");
23544
- break;
23545
- } else if (char === "") {
23546
- process.exit(1);
23547
- } else if (char === "\x7F" || char === "\b") {
23548
- if (input.length > 0) {
23549
- input = input.slice(0, -1);
23550
- process.stdout.write("\b \b");
23551
- }
23552
- } else {
23553
- input += char;
23554
- process.stdout.write("*");
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 createServer2(handler, options = {}) {
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 join5 } from "node:path";
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 = join5(dirname6(id2), tempName);
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 = join5(scope, entry.name);
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 = createServer2(
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 join6, resolve as resolve5 } from "node:path";
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 = join6(installRoot, "runtime-host.log");
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: join6(installRoot, "runtime-host"),
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 = join6(installRoot, "runtime-host");
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(join6(installRoot, "runtime-host.log"), { force: true });
26904
+ await rm2(join7(installRoot, "runtime-host.log"), { force: true });
25606
26905
  } catch {
25607
26906
  }
25608
26907
  return reportTrust(