@rogatio/cli 6.4.1 → 6.6.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.
@@ -276,13 +276,26 @@
276
276
  .rogatio-editor [data-editor-command-bar] {
277
277
  display: flex;
278
278
  flex-wrap: wrap;
279
- gap: 0.5rem;
279
+ align-items: center;
280
+ justify-content: space-between;
281
+ gap: 0.75rem 1rem;
280
282
  margin-block: 1rem;
281
283
  padding: 0.65rem 0.75rem;
282
284
  border: 1px solid var(--rogatio-border);
283
285
  border-radius: var(--rogatio-radius);
284
286
  background: var(--rogatio-surface-raised);
285
287
  }
288
+ .rogatio-editor [data-action-cluster] {
289
+ display: flex;
290
+ flex-wrap: wrap;
291
+ align-items: center;
292
+ gap: 0.5rem;
293
+ }
294
+ .rogatio-editor [data-action-cluster=danger] {
295
+ margin-left: 0.15rem;
296
+ padding-left: 0.65rem;
297
+ border-left: 1px solid var(--rogatio-border);
298
+ }
286
299
  .rogatio-editor [data-editor-form] {
287
300
  display: grid;
288
301
  gap: 1rem;
@@ -385,9 +398,57 @@
385
398
  justify-content: space-between;
386
399
  gap: 0.65rem;
387
400
  }
388
- .rogatio-editor [data-group-heading] button[data-group-enable] {
389
- padding: 0.55rem 1.05rem;
390
- font-size: 0.95rem;
401
+ .rogatio-editor [data-group-identity] {
402
+ display: flex;
403
+ flex: 1 1 auto;
404
+ align-items: center;
405
+ gap: 0.35rem;
406
+ min-width: 0;
407
+ }
408
+ .rogatio-editor [data-group-actions] {
409
+ display: flex;
410
+ flex-wrap: wrap;
411
+ align-items: center;
412
+ gap: 0.5rem;
413
+ margin-left: auto;
414
+ }
415
+ .rogatio-editor [data-action-dock] {
416
+ display: grid;
417
+ margin-top: 0.35rem;
418
+ border: 1px solid var(--rogatio-border);
419
+ border-left: 3px solid var(--rogatio-card-rule-edge);
420
+ border-radius: var(--rogatio-radius);
421
+ background: var(--rogatio-surface-inset);
422
+ overflow: hidden;
423
+ }
424
+ .rogatio-editor [data-dock-row] {
425
+ display: grid;
426
+ grid-template-columns: 5.5rem minmax(0, 1fr);
427
+ column-gap: 0.75rem;
428
+ align-items: center;
429
+ padding: 0.65rem 0.85rem;
430
+ }
431
+ .rogatio-editor [data-dock-row] + [data-dock-row] {
432
+ border-top: 1px solid var(--rogatio-border);
433
+ }
434
+ .rogatio-editor [data-dock-label] {
435
+ font-family: var(--rogatio-font-mono);
436
+ font-size: 0.6875rem;
437
+ font-weight: 700;
438
+ letter-spacing: 0.08em;
439
+ text-transform: uppercase;
440
+ color: var(--rogatio-muted);
441
+ }
442
+ .rogatio-editor [data-dock-actions] {
443
+ display: flex;
444
+ flex-wrap: wrap;
445
+ align-items: center;
446
+ justify-content: flex-end;
447
+ gap: 0.5rem 0.75rem;
448
+ min-width: 0;
449
+ }
450
+ .rogatio-editor [data-dock-actions] [data-action-cluster=tools] {
451
+ margin-right: auto;
391
452
  }
392
453
  .rogatio-editor [data-group-heading] h2,
393
454
  .rogatio-editor [data-section-heading] h2,
@@ -605,6 +666,22 @@
605
666
  .rogatio-editor [data-section-heading] {
606
667
  align-items: flex-start;
607
668
  }
669
+ .rogatio-editor [data-group-actions] {
670
+ margin-left: 0;
671
+ width: 100%;
672
+ }
673
+ .rogatio-editor [data-dock-row] {
674
+ grid-template-columns: 1fr;
675
+ justify-items: start;
676
+ row-gap: 0.45rem;
677
+ }
678
+ .rogatio-editor [data-dock-actions] {
679
+ justify-content: flex-start;
680
+ width: 100%;
681
+ }
682
+ .rogatio-editor [data-dock-actions] [data-action-cluster=tools] {
683
+ margin-right: 0;
684
+ }
608
685
  .rogatio-editor [data-rule-actions] {
609
686
  justify-content: flex-start;
610
687
  width: 100%;
@@ -630,7 +707,9 @@
630
707
  .rogatio-editor fieldset,
631
708
  .rogatio-editor [data-rule-card],
632
709
  .rogatio-editor [data-group-row],
633
- .rogatio-editor [data-editor-check-group] {
710
+ .rogatio-editor [data-editor-check-group],
711
+ .rogatio-editor [data-action-dock],
712
+ .rogatio-editor [data-action-cluster=danger] {
634
713
  border-color: ButtonText;
635
714
  background: Canvas;
636
715
  }
@@ -2238,7 +2238,7 @@ var EditorControllerImpl = class {
2238
2238
  this.commandBar = this.document.createElement("div");
2239
2239
  this.commandBar.dataset.editorCommandBar = "true";
2240
2240
  this.commandBar.setAttribute("role", "toolbar");
2241
- this.commandBar.setAttribute("aria-label", "Editor commands");
2241
+ this.commandBar.setAttribute("aria-label", "Project actions");
2242
2242
  this.form = this.document.createElement("form");
2243
2243
  this.form.dataset.editorForm = "true";
2244
2244
  this.form.noValidate = true;
@@ -3485,7 +3485,7 @@ var EditorControllerImpl = class {
3485
3485
  const draftGroup = this.draftGroupForSavedId(groupId);
3486
3486
  const groupName = displayName(
3487
3487
  draftGroup?.name,
3488
- button.parentElement?.querySelector("h2")?.textContent?.trim() ?? ""
3488
+ this.host.querySelector("[data-group-heading] h2")?.textContent?.trim() ?? ""
3489
3489
  );
3490
3490
  this.applyGroupEnablementLabel(button, enabled.has(groupId), groupName);
3491
3491
  }
@@ -3616,6 +3616,7 @@ var EditorControllerImpl = class {
3616
3616
  } else {
3617
3617
  this.renderGroup(this.route.groupId);
3618
3618
  }
3619
+ this.renderActionDock();
3619
3620
  this.decorateExtensionControls();
3620
3621
  this.renderSummary();
3621
3622
  this.renderMigrationNotices();
@@ -3722,24 +3723,185 @@ var EditorControllerImpl = class {
3722
3723
  renderCommandBar() {
3723
3724
  this.commandBar.replaceChildren();
3724
3725
  this.commandBar.setAttribute("aria-busy", this.saving ? "true" : "false");
3726
+ this.commandBar.setAttribute("aria-label", "Project actions");
3727
+ const tools = this.document.createElement("div");
3728
+ tools.dataset.actionCluster = "tools";
3725
3729
  if (this.aiAssistPanel) {
3726
- this.commandBar.append(
3730
+ tools.append(
3727
3731
  this.createCommandButton("AI Assist", "ai-assist", this.saving)
3728
3732
  );
3729
3733
  }
3730
- this.commandBar.append(
3731
- this.createCommandButton("Validate", "validate", this.saving),
3734
+ tools.append(this.createCommandButton("Validate", "validate", this.saving));
3735
+ if (this.route.kind === "project") {
3736
+ tools.append(
3737
+ this.createCommandButton(
3738
+ "Add group",
3739
+ "add-group",
3740
+ this.saving,
3741
+ {},
3742
+ "primary"
3743
+ )
3744
+ );
3745
+ } else if (this.route.kind === "test") {
3746
+ tools.append(
3747
+ this.createCommandButton(
3748
+ "Run test",
3749
+ "test:run",
3750
+ this.saving || this.testRunning,
3751
+ {},
3752
+ "primary"
3753
+ )
3754
+ );
3755
+ }
3756
+ const commit = this.document.createElement("div");
3757
+ commit.dataset.actionCluster = "commit";
3758
+ commit.append(
3759
+ this.createCommandButton("Cancel", "cancel", this.saving),
3732
3760
  this.createCommandButton(
3733
3761
  "Save",
3734
3762
  "save",
3735
3763
  this.saving || !this.isDirty(),
3736
3764
  {},
3737
3765
  "primary"
3738
- ),
3739
- this.createCommandButton("Cancel", "cancel", this.saving)
3766
+ )
3740
3767
  );
3741
- if (this.route.kind === "project") {
3742
- this.commandBar.append(
3768
+ this.commandBar.append(tools, commit);
3769
+ }
3770
+ createGroupEnableButton(savedGroupId, groupName) {
3771
+ const enablement = this.options.groupEnablement;
3772
+ const enableButton = this.document.createElement("button");
3773
+ enableButton.type = "button";
3774
+ enableButton.dataset.groupEnable = "true";
3775
+ enableButton.dataset.groupId = savedGroupId;
3776
+ enableButton.dataset.btn = "primary";
3777
+ this.applyGroupEnablementLabel(
3778
+ enableButton,
3779
+ enablement?.isEnabled(savedGroupId) === true,
3780
+ groupName
3781
+ );
3782
+ enableButton.addEventListener("click", (event) => {
3783
+ event.preventDefault();
3784
+ event.stopPropagation();
3785
+ if (enableButton.disabled || !enablement) return;
3786
+ const next = enablement.isEnabled(savedGroupId) !== true;
3787
+ const peers = Array.from(
3788
+ this.host.querySelectorAll(
3789
+ "button[data-group-enable]"
3790
+ )
3791
+ ).filter((peer) => peer.dataset.groupId === savedGroupId);
3792
+ for (const peer of peers) peer.disabled = true;
3793
+ void Promise.resolve(enablement.setEnabled(savedGroupId, next)).finally(
3794
+ () => {
3795
+ for (const peer of peers) {
3796
+ if (peer.isConnected) peer.disabled = false;
3797
+ }
3798
+ }
3799
+ );
3800
+ });
3801
+ return enableButton;
3802
+ }
3803
+ /** Enable/Disable, Copy, and Remove as one toolbar. Remove stays visually last. */
3804
+ createGroupActionClusters(groupId, groupName) {
3805
+ const actions = this.document.createElement("div");
3806
+ actions.dataset.groupActions = "true";
3807
+ actions.setAttribute("role", "toolbar");
3808
+ actions.setAttribute("aria-label", `Actions for group ${groupName}`);
3809
+ const safe = this.document.createElement("div");
3810
+ safe.dataset.actionCluster = "safe";
3811
+ const group = this.groupById(groupId);
3812
+ const savedGroupId = group ? this.savedGroupId(group) : void 0;
3813
+ if (this.options.groupEnablement && savedGroupId) {
3814
+ safe.append(this.createGroupEnableButton(savedGroupId, groupName));
3815
+ }
3816
+ safe.append(
3817
+ this.createCommandButton("Copy group", "copy-group", this.saving, {
3818
+ groupId
3819
+ })
3820
+ );
3821
+ const danger = this.document.createElement("div");
3822
+ danger.dataset.actionCluster = "danger";
3823
+ danger.append(
3824
+ this.createCommandButton(
3825
+ "Remove group",
3826
+ "remove-group",
3827
+ this.saving,
3828
+ { groupId },
3829
+ "danger"
3830
+ )
3831
+ );
3832
+ actions.append(safe, danger);
3833
+ return actions;
3834
+ }
3835
+ createProjectActionRow() {
3836
+ const actions = this.document.createElement("div");
3837
+ const tools = this.document.createElement("div");
3838
+ tools.dataset.actionCluster = "tools";
3839
+ if (this.aiAssistPanel) {
3840
+ tools.append(
3841
+ this.createCommandButton("AI Assist", "ai-assist", this.saving)
3842
+ );
3843
+ }
3844
+ tools.append(this.createCommandButton("Validate", "validate", this.saving));
3845
+ const commit = this.document.createElement("div");
3846
+ commit.dataset.actionCluster = "commit";
3847
+ commit.append(
3848
+ this.createCommandButton("Cancel", "cancel", this.saving),
3849
+ this.createCommandButton(
3850
+ "Save",
3851
+ "save",
3852
+ this.saving || !this.isDirty(),
3853
+ {},
3854
+ "primary"
3855
+ )
3856
+ );
3857
+ actions.append(tools, commit);
3858
+ return actions;
3859
+ }
3860
+ appendDockRow(dock, label, actions) {
3861
+ const row = this.document.createElement("div");
3862
+ row.dataset.dockRow = "true";
3863
+ const labelEl = this.document.createElement("span");
3864
+ labelEl.dataset.dockLabel = "true";
3865
+ labelEl.textContent = label;
3866
+ actions.dataset.dockActions = "true";
3867
+ row.append(labelEl, actions);
3868
+ dock.append(row);
3869
+ }
3870
+ /**
3871
+ * Repeats the actions a long page would otherwise hide: under the last rule,
3872
+ * under the project group list, or under the test results.
3873
+ */
3874
+ renderActionDock() {
3875
+ const dock = this.document.createElement("section");
3876
+ dock.dataset.actionDock = "end";
3877
+ dock.setAttribute("aria-label", "Repeated actions");
3878
+ if (this.route.kind === "group") {
3879
+ const groupId = this.route.groupId;
3880
+ const group = this.groupById(groupId);
3881
+ if (group) {
3882
+ const groupName = displayName(group.name, "Unnamed group");
3883
+ const addRule = this.document.createElement("div");
3884
+ addRule.dataset.actionCluster = "safe";
3885
+ addRule.append(
3886
+ this.createCommandButton(
3887
+ "Add rule",
3888
+ "add-rule",
3889
+ this.saving,
3890
+ { groupId },
3891
+ "primary"
3892
+ )
3893
+ );
3894
+ this.appendDockRow(dock, "Rules", addRule);
3895
+ this.appendDockRow(
3896
+ dock,
3897
+ "Group",
3898
+ this.createGroupActionClusters(groupId, groupName)
3899
+ );
3900
+ }
3901
+ } else if (this.route.kind === "project") {
3902
+ const addGroup = this.document.createElement("div");
3903
+ addGroup.dataset.actionCluster = "safe";
3904
+ addGroup.append(
3743
3905
  this.createCommandButton(
3744
3906
  "Add group",
3745
3907
  "add-group",
@@ -3748,19 +3910,23 @@ var EditorControllerImpl = class {
3748
3910
  "primary"
3749
3911
  )
3750
3912
  );
3751
- return;
3752
- }
3753
- if (this.route.kind === "test") {
3754
- this.commandBar.append(
3913
+ this.appendDockRow(dock, "Groups", addGroup);
3914
+ } else {
3915
+ const run = this.document.createElement("div");
3916
+ run.dataset.actionCluster = "safe";
3917
+ run.append(
3755
3918
  this.createCommandButton(
3756
3919
  "Run test",
3757
3920
  "test:run",
3758
- this.saving,
3921
+ this.saving || this.testRunning,
3759
3922
  {},
3760
3923
  "primary"
3761
3924
  )
3762
3925
  );
3926
+ this.appendDockRow(dock, "Test", run);
3763
3927
  }
3928
+ this.appendDockRow(dock, "Project", this.createProjectActionRow());
3929
+ this.form.append(dock);
3764
3930
  }
3765
3931
  renderProject() {
3766
3932
  const heading = this.document.createElement("h2");
@@ -3841,51 +4007,11 @@ var EditorControllerImpl = class {
3841
4007
  const groupName = displayName(group.name, "Unnamed group");
3842
4008
  const headingRow = this.document.createElement("div");
3843
4009
  headingRow.dataset.groupHeading = "true";
4010
+ const identity = this.document.createElement("div");
4011
+ identity.dataset.groupIdentity = "true";
3844
4012
  const heading = this.document.createElement("h2");
3845
- const copyGroup = this.createCommandButton(
3846
- "Copy group",
3847
- "copy-group",
3848
- this.saving,
3849
- { groupId }
3850
- );
3851
- const removeGroup = this.createCommandButton(
3852
- "Remove group",
3853
- "remove-group",
3854
- this.saving,
3855
- { groupId },
3856
- "danger"
3857
- );
3858
- const savedGroupId = this.savedGroupId(group);
3859
- const enablement = this.options.groupEnablement;
3860
- const commands = [];
3861
- if (enablement && savedGroupId) {
3862
- const enableButton = this.document.createElement("button");
3863
- enableButton.type = "button";
3864
- enableButton.dataset.groupEnable = "true";
3865
- enableButton.dataset.groupId = savedGroupId;
3866
- enableButton.dataset.btn = "primary";
3867
- this.applyGroupEnablementLabel(
3868
- enableButton,
3869
- enablement.isEnabled(savedGroupId) === true,
3870
- groupName
3871
- );
3872
- enableButton.addEventListener("click", (event) => {
3873
- event.preventDefault();
3874
- event.stopPropagation();
3875
- if (enableButton.disabled) return;
3876
- const next = enablement.isEnabled(savedGroupId) !== true;
3877
- enableButton.disabled = true;
3878
- void Promise.resolve(enablement.setEnabled(savedGroupId, next)).finally(
3879
- () => {
3880
- if (enableButton.isConnected) enableButton.disabled = false;
3881
- }
3882
- );
3883
- });
3884
- commands.push(enableButton);
3885
- }
3886
- commands.push(copyGroup, removeGroup);
3887
4013
  this.renderNameHeading({
3888
- row: headingRow,
4014
+ row: identity,
3889
4015
  heading,
3890
4016
  headingId: `${this.instanceId}-group-title-${groupIndex}`,
3891
4017
  kind: "group",
@@ -3893,8 +4019,12 @@ var EditorControllerImpl = class {
3893
4019
  namePath: pointer("groups", groupIndex, "name"),
3894
4020
  name: group.name,
3895
4021
  fallback: "Unnamed group",
3896
- commands
4022
+ commands: []
3897
4023
  });
4024
+ headingRow.append(
4025
+ identity,
4026
+ this.createGroupActionClusters(groupId, groupName)
4027
+ );
3898
4028
  this.form.append(headingRow);
3899
4029
  const rulesSection = this.document.createElement("section");
3900
4030
  rulesSection.dataset.rulesSection = "true";
@@ -6,6 +6,7 @@ import { basename as basename3, dirname as dirname8, resolve as resolve8 } from
6
6
  import { fileURLToPath as fileURLToPath2 } from "node:url";
7
7
 
8
8
  // packages/runtime/dist/node/index.js
9
+ import { isIP } from "node:net";
9
10
  import * as fs from "node:fs/promises";
10
11
  import * as path from "node:path";
11
12
 
@@ -1979,6 +1980,42 @@ function sourceMatches(source, url) {
1979
1980
  return false;
1980
1981
  }
1981
1982
  }
1983
+ var PAC_STEER_MARKER = "steer:";
1984
+ function decodePacSteer(entry) {
1985
+ if (!entry.startsWith(PAC_STEER_MARKER)) return null;
1986
+ const value = entry.slice(PAC_STEER_MARKER.length);
1987
+ let url;
1988
+ try {
1989
+ url = new URL(`${value}/`);
1990
+ } catch {
1991
+ return null;
1992
+ }
1993
+ if (url.username !== "" || url.password !== "" || url.search !== "") {
1994
+ return null;
1995
+ }
1996
+ if (url.protocol !== "http:" && url.protocol !== "https:") return null;
1997
+ const scheme = url.protocol === "https:" ? "https" : "http";
1998
+ const port = url.port === "" ? void 0 : Number(url.port);
1999
+ if (port !== void 0 && (!Number.isInteger(port) || port < 1 || port > 65535)) {
2000
+ return null;
2001
+ }
2002
+ const rebuilt = port === void 0 ? `${scheme}://${url.hostname}` : `${scheme}://${url.hostname}:${port}`;
2003
+ if (rebuilt !== value || !isLiteralSteerHost(url.hostname)) return null;
2004
+ return port === void 0 ? { scheme, host: url.hostname } : { scheme, host: url.hostname, port };
2005
+ }
2006
+ function isLiteralSteerHost(host) {
2007
+ if (host.length === 0 || host.length > 253) return false;
2008
+ if (host.startsWith(".") || host.endsWith(".") || host.includes("..")) {
2009
+ return false;
2010
+ }
2011
+ const labels = host.split(".");
2012
+ for (const label2 of labels) {
2013
+ if (label2.length === 0 || label2.length > 63) return false;
2014
+ if (!/^[A-Za-z0-9-]+$/.test(label2)) return false;
2015
+ if (label2.startsWith("-") || label2.endsWith("-")) return false;
2016
+ }
2017
+ return true;
2018
+ }
1982
2019
  function sameOrigin(a, b) {
1983
2020
  try {
1984
2021
  return new URL(a).origin === new URL(b).origin;
@@ -1998,6 +2035,9 @@ import {
1998
2035
  } from "node:http";
1999
2036
  import { connect } from "node:net";
2000
2037
  import { Worker } from "node:worker_threads";
2038
+ import { lookup as dnsLookup } from "node:dns/promises";
2039
+ import { request as httpRequest } from "node:http";
2040
+ import { request as httpsRequest } from "node:https";
2001
2041
  import { createHash, randomBytes, timingSafeEqual } from "node:crypto";
2002
2042
  import { randomBytes as randomBytes2 } from "node:crypto";
2003
2043
  import { readFile as readFile2, realpath as realpath2, stat } from "node:fs/promises";
@@ -20701,6 +20741,131 @@ var require_x509_cjs = __commonJS({
20701
20741
  exports.idX448 = idX448;
20702
20742
  }
20703
20743
  });
20744
+ function parseIPv4(value) {
20745
+ const parts = value.split(".");
20746
+ if (parts.length !== 4) return null;
20747
+ const numbers = parts.map((part) => {
20748
+ if (!/^(?:0|[1-9]\d*)$/.test(part)) return -1;
20749
+ const number = Number(part);
20750
+ return Number.isInteger(number) && number >= 0 && number <= 255 ? number : -1;
20751
+ });
20752
+ return numbers.some((number) => number < 0) ? null : [numbers[0], numbers[1], numbers[2], numbers[3]];
20753
+ }
20754
+ function parseIPv6(value) {
20755
+ if (value.includes("%")) return null;
20756
+ const halves = value.split("::");
20757
+ if (halves.length > 2) return null;
20758
+ const left = halves[0] === "" ? [] : halves[0]?.split(":") ?? [];
20759
+ const right = halves.length === 2 && halves[1] !== "" ? halves[1]?.split(":") ?? [] : [];
20760
+ const parts = [...left, ...right];
20761
+ const words = [];
20762
+ for (const part of parts) {
20763
+ if (part.includes(".")) {
20764
+ const ipv4 = parseIPv4(part);
20765
+ if (ipv4 === null) return null;
20766
+ words.push(ipv4[0] << 8 | ipv4[1], ipv4[2] << 8 | ipv4[3]);
20767
+ continue;
20768
+ }
20769
+ if (!/^[0-9a-fA-F]{1,4}$/.test(part)) return null;
20770
+ words.push(Number.parseInt(part, 16));
20771
+ }
20772
+ if (halves.length === 1) return words.length === 8 ? words : null;
20773
+ if (words.length >= 8) return null;
20774
+ return [
20775
+ ...words.slice(0, left.length),
20776
+ ...new Array(8 - words.length).fill(0),
20777
+ ...words.slice(left.length)
20778
+ ];
20779
+ }
20780
+ function ipv4Number(value) {
20781
+ return ((value[0] * 256 + value[1]) * 256 + value[2]) * 256 + value[3] >>> 0;
20782
+ }
20783
+ function inIPv4Range(value, start, end) {
20784
+ return value >= start && value <= end;
20785
+ }
20786
+ function prefixMatches(value, prefix, bits) {
20787
+ let remaining = bits;
20788
+ for (let index = 0; remaining > 0; index += 1) {
20789
+ const compareBits = Math.min(remaining, 16);
20790
+ const mask = compareBits === 16 ? 65535 : 65535 << 16 - compareBits & 65535;
20791
+ if (((value[index] ?? 0) & mask) !== ((prefix[index] ?? 0) & mask))
20792
+ return false;
20793
+ remaining -= compareBits;
20794
+ }
20795
+ return true;
20796
+ }
20797
+ function mappedIPv4(value) {
20798
+ if (value.slice(0, 5).some((word) => word !== 0) || value[5] !== 65535)
20799
+ return null;
20800
+ return [
20801
+ (value[6] ?? 0) >> 8,
20802
+ (value[6] ?? 0) & 255,
20803
+ (value[7] ?? 0) >> 8,
20804
+ (value[7] ?? 0) & 255
20805
+ ];
20806
+ }
20807
+ function classifyIPv4(value) {
20808
+ const number = ipv4Number(value);
20809
+ if (inIPv4Range(number, 0, 16777215)) return "unspecified";
20810
+ if (inIPv4Range(number, 167772160, 184549375) || inIPv4Range(number, 2886729728, 2887778303) || inIPv4Range(number, 3232235520, 3232301055))
20811
+ return "private";
20812
+ if (inIPv4Range(number, 2130706432, 2147483647)) return "loopback";
20813
+ if (inIPv4Range(number, 2851995648, 2852061183)) return "link-local";
20814
+ if (inIPv4Range(number, 1681915904, 1686110207)) return "carrier-grade";
20815
+ if (inIPv4Range(number, 3221225472, 3221225727) || inIPv4Range(number, 3221225984, 3221226239) || inIPv4Range(number, 3227017984, 3227018239))
20816
+ return "reserved";
20817
+ if (inIPv4Range(number, 3323068416, 3323199487)) return "benchmarking";
20818
+ if (inIPv4Range(number, 3325256704, 3325256959) || inIPv4Range(number, 3405803776, 3405804031))
20819
+ return "documentation";
20820
+ if (inIPv4Range(number, 3758096384, 4294967295)) return "multicast";
20821
+ return "public";
20822
+ }
20823
+ function classifyIPv6(value) {
20824
+ const mapped = mappedIPv4(value);
20825
+ if (mapped !== null) {
20826
+ return classifyIPv4(mapped);
20827
+ }
20828
+ if (value.every((word) => word === 0)) return "unspecified";
20829
+ if (value.slice(0, 7).every((word) => word === 0) && value[7] === 1)
20830
+ return "loopback";
20831
+ if (prefixMatches(value, [64512], 7)) return "private";
20832
+ if (prefixMatches(value, [65152], 10)) return "link-local";
20833
+ if (prefixMatches(value, [65280], 8)) return "multicast";
20834
+ if (prefixMatches(value, [8193, 3512], 32)) return "documentation";
20835
+ if (prefixMatches(value, [8193, 0], 32)) return "reserved";
20836
+ if (prefixMatches(value, [8193, 2, 0], 48)) return "benchmarking";
20837
+ if (prefixMatches(value, [8193, 16], 28)) return "reserved";
20838
+ if (prefixMatches(value, [100, 65435, 0, 0, 0, 0], 96))
20839
+ return "reserved";
20840
+ if (prefixMatches(value, [256], 8)) return "reserved";
20841
+ return "public";
20842
+ }
20843
+ function classifyAddress(value) {
20844
+ if (typeof value !== "string") return "invalid";
20845
+ const family = isIP(value);
20846
+ if (family === 4) {
20847
+ const parsed = parseIPv4(value);
20848
+ return parsed === null ? "invalid" : classifyIPv4(parsed);
20849
+ }
20850
+ if (family === 6) {
20851
+ const parsed = parseIPv6(value);
20852
+ return parsed === null ? "invalid" : classifyIPv6(parsed);
20853
+ }
20854
+ return "invalid";
20855
+ }
20856
+ function validateResolvedAddresses(addresses, maxAddresses) {
20857
+ if (addresses.length === 0 || addresses.length > maxAddresses) return null;
20858
+ const checked = [];
20859
+ for (const address of addresses) {
20860
+ if (address.family !== 4 && address.family !== 6 || classifyAddress(address.address) !== "public")
20861
+ return null;
20862
+ checked.push({ address: address.address, family: address.family });
20863
+ }
20864
+ checked.sort(
20865
+ (left, right) => left.family - right.family || (left.address < right.address ? -1 : left.address > right.address ? 1 : 0)
20866
+ );
20867
+ return checked;
20868
+ }
20704
20869
  var MAX_RETRIES = 2;
20705
20870
  var RETRY_DELAY_BASE = 1e3;
20706
20871
  var COMPLETE_TIMEOUT = 6e4;
@@ -22084,11 +22249,183 @@ async function rewriteRequestBody(input, action, captureContext) {
22084
22249
  }
22085
22250
  };
22086
22251
  }
22252
+ var defaultResolver = {
22253
+ async lookup(hostname, signal) {
22254
+ if (signal?.aborted) throw new Error("aborted");
22255
+ const addresses = await dnsLookup(hostname, { all: true });
22256
+ return addresses.map((address) => ({
22257
+ address: address.address,
22258
+ family: address.family
22259
+ }));
22260
+ }
22261
+ };
22262
+ function responseHeaders(response) {
22263
+ const headers = [];
22264
+ for (let index = 0; index < response.rawHeaders.length; index += 2) {
22265
+ const name = response.rawHeaders[index];
22266
+ const value = response.rawHeaders[index + 1];
22267
+ if (name !== void 0 && value !== void 0)
22268
+ headers.push([name.toLowerCase(), value]);
22269
+ }
22270
+ return headers;
22271
+ }
22272
+ var defaultTransport = {
22273
+ request(options) {
22274
+ return new Promise((resolve22, reject) => {
22275
+ const lookup = (_hostname, _options, callback) => {
22276
+ callback(null, options.address, options.address.includes(":") ? 6 : 4);
22277
+ };
22278
+ const requestOptions = {
22279
+ hostname: options.hostname,
22280
+ port: options.port,
22281
+ path: options.path,
22282
+ method: options.method,
22283
+ headers: options.headers,
22284
+ agent: false,
22285
+ lookup,
22286
+ signal: options.signal,
22287
+ setHost: false,
22288
+ autoSelectFamily: false
22289
+ };
22290
+ const request = options.protocol === "https:" ? httpsRequest(
22291
+ { ...requestOptions, servername: options.servername },
22292
+ (response) => {
22293
+ resolve22({
22294
+ status: response.statusCode ?? 0,
22295
+ headers: responseHeaders(response),
22296
+ body: response
22297
+ });
22298
+ }
22299
+ ) : httpRequest(requestOptions, (response) => {
22300
+ resolve22({
22301
+ status: response.statusCode ?? 0,
22302
+ headers: responseHeaders(response),
22303
+ body: response
22304
+ });
22305
+ });
22306
+ request.once("error", reject);
22307
+ request.end();
22308
+ });
22309
+ }
22310
+ };
22311
+ function headerValue(headers, name) {
22312
+ return headers.find(([headerName]) => headerName.toLowerCase() === name)?.[1];
22313
+ }
22314
+ function responseHeaderBytes(headers) {
22315
+ let bytes = 0;
22316
+ for (const [name, value] of headers)
22317
+ bytes += Buffer.byteLength(name) + Buffer.byteLength(value) + 4;
22318
+ return bytes;
22319
+ }
22320
+ function combineSignals(signal, timeoutMs) {
22321
+ const controller = new AbortController();
22322
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
22323
+ const abort = () => controller.abort();
22324
+ signal?.addEventListener("abort", abort, { once: true });
22325
+ return {
22326
+ signal: controller.signal,
22327
+ dispose: () => {
22328
+ clearTimeout(timer);
22329
+ signal?.removeEventListener("abort", abort);
22330
+ }
22331
+ };
22332
+ }
22333
+ async function fetchAuthorized(operation, options = {}) {
22334
+ if (operation.kind !== "outbound-http" || operation.method !== "GET" && operation.method !== "HEAD")
22335
+ return failure("runtime.unsupported-method");
22336
+ const target = canonicalizeOutboundTarget(operation.target);
22337
+ if (target === null || target !== operation.target)
22338
+ return failure("runtime.invalid-target");
22339
+ const url = new URL(target);
22340
+ const protocol = url.protocol === "https:" ? "https:" : "http:";
22341
+ const port = protocol === "https:" ? 443 : 80;
22342
+ const timeoutMs = options.operationTimeoutMs ?? RUNTIME_LIMITS.operationTimeoutMs;
22343
+ const combined = combineSignals(
22344
+ options.signal,
22345
+ Math.max(1, Math.min(timeoutMs, RUNTIME_LIMITS.operationTimeoutMs))
22346
+ );
22347
+ try {
22348
+ const resolver = options.resolver ?? defaultResolver;
22349
+ const resolved = await resolver.lookup(url.hostname, combined.signal);
22350
+ const addresses = validateResolvedAddresses(
22351
+ resolved,
22352
+ RUNTIME_LIMITS.maxDnsAddresses
22353
+ );
22354
+ if (addresses === null || addresses.length === 0)
22355
+ return failure("runtime.address-denied");
22356
+ const selected = addresses[0];
22357
+ const transport = options.transport ?? defaultTransport;
22358
+ let response;
22359
+ try {
22360
+ response = await transport.request({
22361
+ protocol,
22362
+ hostname: url.hostname,
22363
+ address: selected.address,
22364
+ port,
22365
+ path: `${url.pathname}${url.search}`,
22366
+ method: operation.method,
22367
+ headers: { host: url.host, "accept-encoding": "identity" },
22368
+ ...protocol === "https:" ? { servername: url.hostname } : {},
22369
+ signal: combined.signal
22370
+ });
22371
+ } catch {
22372
+ return combined.signal.aborted ? failure("runtime.timeout") : failure("runtime.internal");
22373
+ }
22374
+ if (combined.signal.aborted) return failure("runtime.timeout");
22375
+ if (response.status >= 300 && response.status <= 399)
22376
+ return failure("runtime.redirect-rejected");
22377
+ if (responseHeaderBytes(response.headers) > RUNTIME_LIMITS.maxResponseHeaderBytes)
22378
+ return failure("runtime.size-limit");
22379
+ const encoding = headerValue(response.headers, "content-encoding");
22380
+ if (encoding !== void 0 && encoding.toLowerCase() !== "identity")
22381
+ return failure("runtime.size-limit");
22382
+ const chunks = [];
22383
+ let total = 0;
22384
+ try {
22385
+ for await (const chunk of response.body) {
22386
+ if (combined.signal.aborted) return failure("runtime.timeout");
22387
+ const bytes = chunk instanceof Uint8Array ? Uint8Array.from(chunk) : Uint8Array.from(chunk);
22388
+ total += bytes.byteLength;
22389
+ if (total > RUNTIME_LIMITS.maxResponseBodyBytes)
22390
+ return failure("runtime.size-limit");
22391
+ chunks.push(bytes);
22392
+ }
22393
+ } catch {
22394
+ return combined.signal.aborted ? failure("runtime.timeout") : failure("runtime.internal");
22395
+ }
22396
+ const body = new Uint8Array(total);
22397
+ let offset = 0;
22398
+ for (const chunk of chunks) {
22399
+ body.set(chunk, offset);
22400
+ offset += chunk.byteLength;
22401
+ }
22402
+ return {
22403
+ ok: true,
22404
+ value: { status: response.status, headers: response.headers, body }
22405
+ };
22406
+ } catch {
22407
+ return combined.signal.aborted ? failure("runtime.timeout") : failure("runtime.dns-failed");
22408
+ } finally {
22409
+ combined.dispose();
22410
+ }
22411
+ }
22087
22412
  function supportedContentType2(value) {
22088
22413
  if (value === void 0) return false;
22089
22414
  const mediaType = value.split(";", 1)[0]?.trim().toLowerCase() ?? "";
22090
22415
  return mediaType.startsWith("text/") || mediaType === "application/json" || mediaType === "application/javascript" || mediaType === "text/javascript" || mediaType === "text/css" || mediaType === "application/xml" || mediaType === "text/xml";
22091
22416
  }
22417
+ function responseHeader(headers, name) {
22418
+ return headers.find(([key]) => key.toLowerCase() === name)?.[1];
22419
+ }
22420
+ function responseBodyReplacements(action) {
22421
+ if ("replacements" in action && Array.isArray(action.replacements)) {
22422
+ return action.replacements;
22423
+ }
22424
+ return [];
22425
+ }
22426
+ function isReplaceAction(action) {
22427
+ return "mode" in action && action.mode === "replace";
22428
+ }
22092
22429
  async function rewriteResponseBody(input, replacements, replaceAction, captureContext) {
22093
22430
  if (!supportedContentType2(input.contentType) || input.contentType === void 0)
22094
22431
  return failure("runtime.size-limit");
@@ -22134,6 +22471,78 @@ async function rewriteResponseBody(input, replacements, replaceAction, captureCo
22134
22471
  }
22135
22472
  };
22136
22473
  }
22474
+ function replaceResponseBody(body, contentType, captureContext) {
22475
+ const captures = captureContext === void 0 ? [] : matchUrlCaptures(captureContext.urlRegex, captureContext.url);
22476
+ if (captureContext !== void 0 && captures === null) {
22477
+ return failure("runtime.url-capture-mismatch");
22478
+ }
22479
+ const expanded = captureContext === void 0 ? body : substituteUrlCaptures(body, captures ?? []);
22480
+ const encoded = new TextEncoder().encode(expanded);
22481
+ if (encoded.byteLength > RUNTIME_LIMITS.maxResponseBodyBytes)
22482
+ return failure("runtime.size-limit");
22483
+ return {
22484
+ ok: true,
22485
+ value: {
22486
+ body: encoded,
22487
+ contentType: contentType?.split(";", 1)[0]?.trim() ?? "text/plain"
22488
+ }
22489
+ };
22490
+ }
22491
+ async function fetchAndRewriteAuthorizedResponse(operation, action, options = {}) {
22492
+ if (operation.kind !== "outbound-http" || operation.method !== "GET")
22493
+ return failure("runtime.unsupported-method");
22494
+ const response = await fetchAuthorized(operation, options);
22495
+ if (!response.ok) return response;
22496
+ const contentType = responseHeader(response.value.headers, "content-type");
22497
+ const transformed = isReplaceAction(action) ? replaceResponseBody(
22498
+ action.body,
22499
+ contentType,
22500
+ operation.sourceValue === void 0 ? void 0 : { url: operation.target, urlRegex: operation.sourceValue }
22501
+ ) : await rewriteResponseBody(
22502
+ {
22503
+ contentType,
22504
+ contentEncoding: responseHeader(
22505
+ response.value.headers,
22506
+ "content-encoding"
22507
+ ),
22508
+ body: response.value.body
22509
+ },
22510
+ responseBodyReplacements(action)
22511
+ );
22512
+ if (!transformed.ok) return transformed;
22513
+ return {
22514
+ ok: true,
22515
+ value: {
22516
+ ...transformed.value,
22517
+ status: response.value.status,
22518
+ headers: response.value.headers
22519
+ }
22520
+ };
22521
+ }
22522
+ var RESPONSE_BODY_LISTENER_PREFIX = "/.rogatio/body/";
22523
+ function parseResponseBodyRedirect(rawUrl) {
22524
+ const queryAt = rawUrl.indexOf("?");
22525
+ const path2 = queryAt === -1 ? rawUrl : rawUrl.slice(0, queryAt);
22526
+ const search = queryAt === -1 ? "" : rawUrl.slice(queryAt);
22527
+ if (!path2.startsWith(RESPONSE_BODY_LISTENER_PREFIX)) return null;
22528
+ const rest = path2.slice(RESPONSE_BODY_LISTENER_PREFIX.length);
22529
+ const slash1 = rest.indexOf("/");
22530
+ if (slash1 <= 0) return null;
22531
+ const slash2 = rest.indexOf("/", slash1 + 1);
22532
+ if (slash2 <= slash1 + 1) return null;
22533
+ let ruleId;
22534
+ let digest;
22535
+ try {
22536
+ ruleId = decodeURIComponent(rest.slice(0, slash1));
22537
+ digest = decodeURIComponent(rest.slice(slash1 + 1, slash2));
22538
+ } catch {
22539
+ return null;
22540
+ }
22541
+ if (ruleId.length === 0 || digest.length === 0) return null;
22542
+ const original = rest.slice(slash2 + 1) + search;
22543
+ if (!/^https?:\/\//i.test(original)) return null;
22544
+ return { ruleId, digest, originalUrl: original };
22545
+ }
22137
22546
  function originOf(value) {
22138
22547
  const direct = normalizeSiteOrigin(value);
22139
22548
  if (direct !== null) return direct;
@@ -22445,6 +22854,9 @@ function writeResponse(res, status, statusMessage, headers, body) {
22445
22854
  res.writeHead(status, statusMessage, out);
22446
22855
  res.end(body);
22447
22856
  }
22857
+ function asPresetDigest(value) {
22858
+ return value.startsWith("sha256:") ? value : null;
22859
+ }
22448
22860
  function initiatorFromHeaders(headers, targetUrl) {
22449
22861
  const origin = headerValue2(headers, "origin");
22450
22862
  if (typeof origin === "string" && /^https?:\/\//i.test(origin)) {
@@ -22487,6 +22899,10 @@ async function startInterceptProxy(options = {}) {
22487
22899
  async function handleHttp(req, res) {
22488
22900
  try {
22489
22901
  const targetUrl = req.url ?? "";
22902
+ if (targetUrl.startsWith("/.rogatio/body/")) {
22903
+ await handleResponseBodyRedirect(req, res, targetUrl);
22904
+ return;
22905
+ }
22490
22906
  if (!/^https?:\/\//i.test(targetUrl)) {
22491
22907
  res.writeHead(400);
22492
22908
  res.end();
@@ -22602,6 +23018,96 @@ async function startInterceptProxy(options = {}) {
22602
23018
  }
22603
23019
  }
22604
23020
  }
23021
+ async function handleResponseBodyRedirect(req, res, rawUrl) {
23022
+ const method = (req.method ?? "GET").toUpperCase();
23023
+ if (method !== "GET") {
23024
+ res.writeHead(405);
23025
+ res.end();
23026
+ return;
23027
+ }
23028
+ const parsed = parseResponseBodyRedirect(rawUrl);
23029
+ const active = policy;
23030
+ if (parsed === null || active === null || active.presetDigest === void 0) {
23031
+ res.writeHead(parsed === null ? 400 : 403);
23032
+ res.end();
23033
+ return;
23034
+ }
23035
+ const presetDigest = asPresetDigest(active.presetDigest);
23036
+ if (presetDigest === null || parsed.digest !== presetDigest) {
23037
+ res.writeHead(403);
23038
+ res.end();
23039
+ return;
23040
+ }
23041
+ const operation = active.operations.find(
23042
+ (op) => op.kind === "response-body" && op.ruleId === parsed.ruleId
23043
+ );
23044
+ if (operation === void 0 || !sourceMatches(operation.matcher.source, parsed.originalUrl)) {
23045
+ res.writeHead(404);
23046
+ res.end();
23047
+ return;
23048
+ }
23049
+ if (operation.matcher.method !== void 0 && operation.matcher.method !== "GET") {
23050
+ res.writeHead(405);
23051
+ res.end();
23052
+ return;
23053
+ }
23054
+ const target = canonicalizeOutboundTarget(parsed.originalUrl);
23055
+ if (target === null) {
23056
+ res.writeHead(400);
23057
+ res.end();
23058
+ return;
23059
+ }
23060
+ const allowed = revalidateAuthority(active.project, active.operations, {
23061
+ groupId: operation.groupId,
23062
+ ruleId: operation.ruleId,
23063
+ url: parsed.originalUrl,
23064
+ target,
23065
+ method: "GET",
23066
+ initiator: initiatorFromHeaders(req.headers, parsed.originalUrl) ?? new URL(target).origin,
23067
+ resourceType: operation.matcher.resourceTypes[0]
23068
+ });
23069
+ if (!allowed.allowed) {
23070
+ res.writeHead(403);
23071
+ res.end();
23072
+ return;
23073
+ }
23074
+ const fetched = await fetchAndRewriteAuthorizedResponse(
23075
+ {
23076
+ groupId: operation.groupId,
23077
+ ruleId: operation.ruleId,
23078
+ operationId: operation.ruleId,
23079
+ kind: "outbound-http",
23080
+ target,
23081
+ method: "GET",
23082
+ sourceValue: operation.matcher.source.value,
23083
+ presetDigest
23084
+ },
23085
+ operation.responseBody
23086
+ );
23087
+ if (!fetched.ok) {
23088
+ res.writeHead(502);
23089
+ res.end();
23090
+ return;
23091
+ }
23092
+ const headers = {};
23093
+ for (const [name, value] of fetched.value.headers) {
23094
+ const lower = name.toLowerCase();
23095
+ if (lower === "set-cookie" || lower === "cookie" || lower === "authorization" || lower === "proxy-authorization") {
23096
+ continue;
23097
+ }
23098
+ const existing = headers[lower];
23099
+ if (existing === void 0) headers[lower] = value;
23100
+ else if (Array.isArray(existing)) existing.push(value);
23101
+ else headers[lower] = [existing, value];
23102
+ }
23103
+ writeResponse(
23104
+ res,
23105
+ fetched.value.status,
23106
+ fetched.value.status === 200 ? "OK" : "Upstream",
23107
+ headers,
23108
+ Buffer.from(fetched.value.body)
23109
+ );
23110
+ }
22605
23111
  function handleConnect(req, clientSocket, head) {
22606
23112
  const authority = req.url ?? "";
22607
23113
  const [host, portText] = authority.split(":");
@@ -22646,6 +23152,19 @@ async function startInterceptProxy(options = {}) {
22646
23152
  }
22647
23153
  };
22648
23154
  }
23155
+ function steerKey(origin) {
23156
+ const port = origin.port !== void 0 ? `:${origin.port}` : "";
23157
+ return `steer:${origin.scheme}://${origin.host}${port}`;
23158
+ }
23159
+ function pacRouteFromEntry(entry) {
23160
+ const steer = decodePacSteer(entry);
23161
+ if (steer !== null) return { steer };
23162
+ if (entry.includes("://")) {
23163
+ return isExactHttpUrl(entry) ? { url: entry } : null;
23164
+ }
23165
+ if (entry.length === 0) return null;
23166
+ return { hostname: entry };
23167
+ }
22649
23168
  function pacCheck(route) {
22650
23169
  if (typeof route.url === "string" && isExactHttpUrl(route.url)) {
22651
23170
  return {
@@ -22653,6 +23172,12 @@ function pacCheck(route) {
22653
23172
  line: `url === ${JSON.stringify(route.url)}`
22654
23173
  };
22655
23174
  }
23175
+ if (route.steer !== void 0) {
23176
+ return {
23177
+ key: steerKey(route.steer),
23178
+ line: steerPredicate(route.steer)
23179
+ };
23180
+ }
22656
23181
  if (typeof route.hostname === "string" && route.hostname.length > 0 && !route.hostname.includes("://")) {
22657
23182
  return {
22658
23183
  key: `host:${route.hostname}`,
@@ -22661,6 +23186,17 @@ function pacCheck(route) {
22661
23186
  }
22662
23187
  return null;
22663
23188
  }
23189
+ function steerPredicate(origin) {
23190
+ const hostCheck = `host === ${JSON.stringify(origin.host)}`;
23191
+ const base = origin.port !== void 0 ? `${origin.scheme}://${origin.host}:${origin.port}` : `${origin.scheme}://${origin.host}`;
23192
+ if (origin.port !== void 0) {
23193
+ const withSlash = JSON.stringify(`${base}/`);
23194
+ const exact = JSON.stringify(base);
23195
+ const withQuery = JSON.stringify(`${base}?`);
23196
+ return `${hostCheck} && (url.indexOf(${withSlash}) === 0 || url === ${exact} || url.indexOf(${withQuery}) === 0)`;
23197
+ }
23198
+ return `${hostCheck} && url.indexOf(${JSON.stringify(base)}) === 0`;
23199
+ }
22664
23200
  function isExactHttpUrl(value) {
22665
23201
  try {
22666
23202
  const url = new URL(value);
@@ -22782,6 +23318,7 @@ function unsupportedReasons(capabilities) {
22782
23318
  function createPlatformInterceptionProvider(adapter) {
22783
23319
  let state = "stopped";
22784
23320
  let active = false;
23321
+ let pacInstalled = false;
22785
23322
  return {
22786
23323
  platform: adapter.platform,
22787
23324
  detect() {
@@ -22793,6 +23330,17 @@ function createPlatformInterceptionProvider(adapter) {
22793
23330
  };
22794
23331
  },
22795
23332
  async start(activation, pacRoutes) {
23333
+ const decoded = pacRoutes.flatMap((entry) => {
23334
+ const route = pacRouteFromEntry(entry);
23335
+ return route === null ? [] : [route];
23336
+ });
23337
+ if (pacRoutes.length === 0) {
23338
+ const endpoint2 = await adapter.startTlsProxy(activation);
23339
+ active = true;
23340
+ pacInstalled = false;
23341
+ state = "running";
23342
+ return endpoint2;
23343
+ }
22796
23344
  const capabilities = adapter.detect();
22797
23345
  const reasons = unsupportedReasons(capabilities);
22798
23346
  if (!capabilities.supported || reasons.length > 0) {
@@ -22804,20 +23352,17 @@ function createPlatformInterceptionProvider(adapter) {
22804
23352
  throw new Error("runtime.platform-unsupported");
22805
23353
  }
22806
23354
  const endpoint = await adapter.startTlsProxy(activation);
22807
- const pac = generatePacScript(
22808
- pacRoutes.map(
22809
- (entry) => entry.includes("://") ? { url: entry } : { hostname: entry }
22810
- ),
22811
- endpoint
22812
- );
23355
+ const pac = generatePacScript(decoded, endpoint);
22813
23356
  try {
22814
23357
  await adapter.installPac(pac);
22815
23358
  active = true;
23359
+ pacInstalled = true;
22816
23360
  state = "running";
22817
23361
  return endpoint;
22818
23362
  } catch (error) {
22819
23363
  await adapter.stopTlsProxy();
22820
23364
  active = false;
23365
+ pacInstalled = false;
22821
23366
  state = "stopped";
22822
23367
  throw error;
22823
23368
  }
@@ -22827,9 +23372,10 @@ function createPlatformInterceptionProvider(adapter) {
22827
23372
  state = state === "unsupported" ? "unsupported" : "stopped";
22828
23373
  return;
22829
23374
  }
22830
- await adapter.removePac();
23375
+ if (pacInstalled) await adapter.removePac();
22831
23376
  await adapter.stopTlsProxy();
22832
23377
  active = false;
23378
+ pacInstalled = false;
22833
23379
  state = "stopped";
22834
23380
  },
22835
23381
  status() {
@@ -23429,7 +23975,7 @@ function createNativeRuntimeController(options) {
23429
23975
  return aiConfigInForce;
23430
23976
  }
23431
23977
  async function bindInterception(current, sessionConfig) {
23432
- if (sessionConfig.pacRoutes.length === 0) {
23978
+ if (sessionConfig.pacRoutes.length === 0 && sessionConfig.contentListener !== true) {
23433
23979
  return {
23434
23980
  activation: { ...current, pacRoutes: [] },
23435
23981
  session: null,
@@ -23638,7 +24184,8 @@ function createNativeRuntimeController(options) {
23638
24184
  preset = normalized.value;
23639
24185
  activePolicy = {
23640
24186
  project: schemaResult.data,
23641
- operations: compileResult.operations
24187
+ operations: compileResult.operations,
24188
+ presetDigest: preset.digest
23642
24189
  };
23643
24190
  const startResult = await this.start();
23644
24191
  if (startResult.state !== "running") {
@@ -23686,6 +24233,7 @@ function createNativeRuntimeController(options) {
23686
24233
  policyDigest: typeof meta.policyDigest === "string" ? meta.policyDigest : "",
23687
24234
  extensionId: typeof meta.extensionId === "string" ? meta.extensionId : "",
23688
24235
  pacRoutes: Array.isArray(meta.pacRoutes) ? meta.pacRoutes : [],
24236
+ contentListener: meta.contentListener === true,
23689
24237
  targetPolicy: {
23690
24238
  public: meta.targetPolicy?.public === true || meta.targetPolicy?.publicAllowed === true,
23691
24239
  localOrigins: Array.isArray(meta.targetPolicy?.localOrigins) ? meta.targetPolicy.localOrigins : []
@@ -24539,7 +25087,11 @@ function createNativeHost(options) {
24539
25087
  }
24540
25088
  const policy = controller.getActivePolicy();
24541
25089
  interceptProxy = await startInterceptProxy({
24542
- policy: policy ? { project: policy.project, operations: policy.operations } : null
25090
+ policy: policy ? {
25091
+ project: policy.project,
25092
+ operations: policy.operations,
25093
+ presetDigest: policy.presetDigest
25094
+ } : null
24543
25095
  });
24544
25096
  return interceptProxy.endpoint;
24545
25097
  },
@@ -24560,7 +25112,11 @@ function createNativeHost(options) {
24560
25112
  const endpoint = await platformProvider.start(activation, routes);
24561
25113
  const policy = controller.getActivePolicy();
24562
25114
  interceptProxy?.setPolicy(
24563
- policy ? { project: policy.project, operations: policy.operations } : null
25115
+ policy ? {
25116
+ project: policy.project,
25117
+ operations: policy.operations,
25118
+ presetDigest: policy.presetDigest
25119
+ } : null
24564
25120
  );
24565
25121
  return endpoint;
24566
25122
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rogatio/cli",
3
- "version": "6.4.1",
3
+ "version": "6.6.0",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "Local-first browser request and response rules — editor host, file verification, test runner, and runtime dispatch.",