@rogatio/cli 6.19.1 → 6.20.1

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.
@@ -156,6 +156,13 @@
156
156
  grid-template-rows: auto minmax(0, 1fr);
157
157
  min-width: 0;
158
158
  }
159
+ .rogatio-editor [data-desktop-route-rail][hidden],
160
+ .rogatio-editor [data-editor-header][hidden],
161
+ .rogatio-editor [data-editor-status][hidden],
162
+ .rogatio-editor [data-editor-summary][hidden],
163
+ .rogatio-editor [data-editor-form][hidden] {
164
+ display: none;
165
+ }
159
166
  .rogatio-editor [data-desktop-route-rail] {
160
167
  position: sticky;
161
168
  top: 0;
@@ -908,12 +915,28 @@
908
915
  margin: 0;
909
916
  color: var(--rogatio-muted);
910
917
  }
918
+ .rogatio-editor [data-test-page] {
919
+ width: min(68rem, 100%);
920
+ margin-inline: auto;
921
+ }
922
+ .rogatio-editor [data-test-page-head] h2 {
923
+ margin: 0;
924
+ font-size: 1.65rem;
925
+ letter-spacing: -0.03em;
926
+ }
927
+ .rogatio-editor [data-test-page] [data-test-description] {
928
+ margin: 0.35rem 0 1rem;
929
+ max-width: 40rem;
930
+ color: var(--rogatio-muted);
931
+ }
911
932
  @media (min-width: 52rem) {
912
- .rogatio-editor [data-test-dialog] [data-test-panel] {
933
+ .rogatio-editor [data-test-dialog] [data-test-panel],
934
+ .rogatio-editor [data-test-page] [data-test-panel] {
913
935
  grid-template-columns: minmax(0, 1.45fr) minmax(16rem, 0.7fr);
914
936
  align-items: start;
915
937
  }
916
- .rogatio-editor [data-test-dialog] [data-test-panel] > fieldset {
938
+ .rogatio-editor [data-test-dialog] [data-test-panel] > fieldset,
939
+ .rogatio-editor [data-test-page] [data-test-panel] > fieldset {
917
940
  grid-row: 1 / span 3;
918
941
  }
919
942
  }
@@ -2541,6 +2541,11 @@ var EditorControllerImpl = class {
2541
2541
  confirmation;
2542
2542
  groupPickerOpen = false;
2543
2543
  testConsoleOpen = false;
2544
+ /** Page-surface console closed by navigation; the host is told after render. */
2545
+ pendingConsoleLeave = false;
2546
+ /** Rule a console leave is opening, when the destination has one. */
2547
+ consoleLeaveRuleId = null;
2548
+ consoleSurface;
2544
2549
  projectActions;
2545
2550
  focusRequest;
2546
2551
  saving = false;
@@ -2572,6 +2577,7 @@ var EditorControllerImpl = class {
2572
2577
  this.root = options.root;
2573
2578
  this.document = options.root.ownerDocument;
2574
2579
  this.options = options;
2580
+ this.consoleSurface = options.consoleSurface === "page" ? "page" : "dialog";
2575
2581
  this.projectActions = normalizeProjectActions(options.projectActions);
2576
2582
  this.extensions = extensions;
2577
2583
  this.instanceId = `rogatio-editor-${++editorInstanceCount}`;
@@ -2680,7 +2686,7 @@ var EditorControllerImpl = class {
2680
2686
  if (this.destroyed) return;
2681
2687
  const target = event.target;
2682
2688
  if (!(target instanceof Element)) return;
2683
- if (this.testConsoleOpen && target instanceof HTMLElement && target.dataset.testConsole !== void 0 && event.target === target) {
2689
+ if (this.consoleSurface === "dialog" && this.testConsoleOpen && target instanceof HTMLElement && target.dataset.testConsole !== void 0 && event.target === target) {
2684
2690
  this.closeTestConsole();
2685
2691
  return;
2686
2692
  }
@@ -2800,12 +2806,12 @@ var EditorControllerImpl = class {
2800
2806
  this.closeGroupPicker();
2801
2807
  return;
2802
2808
  }
2803
- if (event.key === "Escape" && this.testConsoleOpen) {
2809
+ if (event.key === "Escape" && this.consoleSurface === "dialog" && this.testConsoleOpen) {
2804
2810
  event.preventDefault();
2805
2811
  this.closeTestConsole();
2806
2812
  return;
2807
2813
  }
2808
- if (event.key === "Tab" && this.testConsoleOpen && !this.confirmation) {
2814
+ if (event.key === "Tab" && this.consoleSurface === "dialog" && this.testConsoleOpen && !this.confirmation) {
2809
2815
  this.trapTestConsoleFocus(event);
2810
2816
  }
2811
2817
  const target = event.target;
@@ -2955,7 +2961,7 @@ var EditorControllerImpl = class {
2955
2961
  return;
2956
2962
  }
2957
2963
  if (command === "test:open-rule") {
2958
- this.testConsoleOpen = false;
2964
+ this.releaseConsolePage();
2959
2965
  this.navigateToRule(element.dataset.groupId, element.dataset.ruleId);
2960
2966
  return;
2961
2967
  }
@@ -3712,7 +3718,7 @@ var EditorControllerImpl = class {
3712
3718
  this.statusMessage = count === 0 ? "The project could not be tested." : `${count} validation error${count === 1 ? "" : "s"} found.`;
3713
3719
  const first = diagnostics[0];
3714
3720
  if (first) {
3715
- this.testConsoleOpen = false;
3721
+ this.releaseConsolePage();
3716
3722
  this.navigateToPath(first.path);
3717
3723
  return;
3718
3724
  }
@@ -3958,6 +3964,7 @@ var EditorControllerImpl = class {
3958
3964
  }
3959
3965
  navigate(route, groupId) {
3960
3966
  if (route === "test") {
3967
+ if (this.consoleSurface === "page") return;
3961
3968
  this.openTestConsole();
3962
3969
  return;
3963
3970
  }
@@ -3969,7 +3976,7 @@ var EditorControllerImpl = class {
3969
3976
  } else {
3970
3977
  return;
3971
3978
  }
3972
- this.testConsoleOpen = false;
3979
+ this.releaseConsolePage();
3973
3980
  this.groupPickerOpen = false;
3974
3981
  if (returnFocusToGroups) this.focusRequest = "route:groups";
3975
3982
  this.closeRenameOnLeave();
@@ -3998,11 +4005,8 @@ var EditorControllerImpl = class {
3998
4005
  }
3999
4006
  navigateToGroup(groupId) {
4000
4007
  this.groupPickerOpen = false;
4001
- this.testConsoleOpen = false;
4002
- const groupIds = new Set(
4003
- this.draft.groups.map((group) => typeof group.id === "string" ? group.id : "").filter((id) => id.length > 0)
4004
- );
4005
- const resolved = resolveGroupRoute(groupId, groupIds);
4008
+ this.releaseConsolePage();
4009
+ const resolved = resolveGroupRoute(groupId, this.draftGroupIds());
4006
4010
  if (resolved.kind === "group") {
4007
4011
  this.route = { kind: "group", groupId: resolved.groupId };
4008
4012
  } else {
@@ -4012,6 +4016,31 @@ var EditorControllerImpl = class {
4012
4016
  this.statusMessage = "";
4013
4017
  this.render();
4014
4018
  }
4019
+ syncRoute(groupId) {
4020
+ if (this.destroyed) return;
4021
+ const resolved = resolveGroupRoute(groupId, this.draftGroupIds());
4022
+ const next = resolved.kind === "group" ? { kind: "group", groupId: resolved.groupId } : { kind: "project" };
4023
+ if (this.sameRoute(this.route, next)) return;
4024
+ this.groupPickerOpen = false;
4025
+ this.route = next;
4026
+ this.closeRenameOnLeave();
4027
+ if (this.consoleSurface === "page" && this.testConsoleOpen) return;
4028
+ this.testRequestId += 1;
4029
+ this.statusMessage = "";
4030
+ this.render();
4031
+ }
4032
+ draftGroupIds() {
4033
+ return new Set(
4034
+ this.draft.groups.map((group) => typeof group.id === "string" ? group.id : "").filter((id) => id.length > 0)
4035
+ );
4036
+ }
4037
+ sameRoute(left, right) {
4038
+ if (left.kind === "project" && right.kind === "project") return true;
4039
+ if (left.kind === "group" && right.kind === "group") {
4040
+ return left.groupId === right.groupId;
4041
+ }
4042
+ return false;
4043
+ }
4015
4044
  syncGroupEnablement(enabledGroupIds) {
4016
4045
  if (this.destroyed) return;
4017
4046
  const enabled = /* @__PURE__ */ new Set();
@@ -4064,6 +4093,8 @@ var EditorControllerImpl = class {
4064
4093
  * failing.
4065
4094
  */
4066
4095
  navigateToRule(groupId, ruleId) {
4096
+ const rule = safeText(ruleId);
4097
+ this.consoleLeaveRuleId = rule.length > 0 ? rule : null;
4067
4098
  this.navigateToGroup(groupId);
4068
4099
  const resolvedGroup = safeText(this.currentGroupId());
4069
4100
  const resolvedRule = safeText(ruleId);
@@ -4072,7 +4103,7 @@ var EditorControllerImpl = class {
4072
4103
  }
4073
4104
  navigateToSearchResult(path) {
4074
4105
  this.groupPickerOpen = false;
4075
- this.testConsoleOpen = false;
4106
+ this.releaseConsolePage();
4076
4107
  const segments = decodePointer(path);
4077
4108
  if (segments?.[0] !== "groups") {
4078
4109
  this.route = { kind: "project" };
@@ -4088,6 +4119,7 @@ var EditorControllerImpl = class {
4088
4119
  this.route = { kind: "group", groupId: group.id };
4089
4120
  this.searchQuery = "";
4090
4121
  this.statusMessage = "Jumped to rule.";
4122
+ this.consoleLeaveRuleId = rule && typeof rule.id === "string" && rule.id.length > 0 ? rule.id : null;
4091
4123
  this.render();
4092
4124
  if (rule && typeof rule.id === "string") {
4093
4125
  this.revealRuleCard(group.id, rule.id);
@@ -4097,7 +4129,8 @@ var EditorControllerImpl = class {
4097
4129
  const segments = decodePointer(path);
4098
4130
  if (segments?.[0] !== "groups") {
4099
4131
  this.route = { kind: "project" };
4100
- this.testConsoleOpen = false;
4132
+ this.consoleLeaveRuleId = null;
4133
+ this.releaseConsolePage();
4101
4134
  this.focusRequest = path;
4102
4135
  this.render();
4103
4136
  return;
@@ -4107,9 +4140,11 @@ var EditorControllerImpl = class {
4107
4140
  const group = this.draft.groups[groupIndex];
4108
4141
  if (!group || typeof group.id !== "string") return;
4109
4142
  this.route = { kind: "group", groupId: group.id };
4110
- this.testConsoleOpen = false;
4111
- const last = segments[segments.length - 1];
4112
4143
  const ruleIndex = arrayIndex(segments[3] ?? "");
4144
+ const namedRule = ruleIndex === void 0 ? void 0 : group.rules[ruleIndex];
4145
+ this.consoleLeaveRuleId = namedRule && typeof namedRule.id === "string" && namedRule.id.length > 0 ? namedRule.id : null;
4146
+ this.releaseConsolePage();
4147
+ const last = segments[segments.length - 1];
4113
4148
  const entityPath = last === "name" ? path : segments.length === 2 ? pointer("groups", groupIndex, "name") : segments.length === 4 && ruleIndex !== void 0 ? pointer("groups", groupIndex, "rules", ruleIndex, "name") : path;
4114
4149
  this.focusRequest = entityPath;
4115
4150
  this.render();
@@ -4167,8 +4202,20 @@ var EditorControllerImpl = class {
4167
4202
  this.renderConfirmation();
4168
4203
  this.renderGroupPicker();
4169
4204
  this.renderTestConsole();
4205
+ this.syncConsolePageChrome();
4206
+ const leavingConsole = this.pendingConsoleLeave;
4207
+ this.pendingConsoleLeave = false;
4208
+ const leaveGroupId = this.currentGroupId() ?? null;
4209
+ const leaveRuleId = this.consoleLeaveRuleId;
4210
+ this.consoleLeaveRuleId = null;
4170
4211
  this.restoreFocus();
4171
4212
  this.focusRequest = void 0;
4213
+ if (leavingConsole) {
4214
+ this.options.onLeaveConsole?.({
4215
+ groupId: leaveGroupId,
4216
+ ruleId: leaveGroupId !== null && leaveRuleId !== null && this.ruleById(leaveGroupId, leaveRuleId) ? leaveRuleId : null
4217
+ });
4218
+ }
4172
4219
  }
4173
4220
  renderHeader() {
4174
4221
  this.header.replaceChildren();
@@ -4243,19 +4290,22 @@ var EditorControllerImpl = class {
4243
4290
  searchWrap.append(searchLabel, this.searchResults);
4244
4291
  const railTools = this.document.createElement("div");
4245
4292
  railTools.dataset.railTools = "true";
4246
- const testBtn = this.createButton("Console", "route:test");
4247
- testBtn.dataset.route = "test";
4248
- testBtn.dataset.editorKey = "route:test";
4249
- testBtn.dataset.btn = "secondary";
4250
- testBtn.disabled = this.saving;
4251
- testBtn.setAttribute("aria-label", "Test console");
4252
- testBtn.setAttribute("aria-haspopup", "dialog");
4253
- testBtn.setAttribute(
4254
- "aria-expanded",
4255
- this.testConsoleOpen ? "true" : "false"
4256
- );
4257
- testBtn.setAttribute("aria-controls", `${this.instanceId}-test-console`);
4258
- railTools.append(testBtn, searchWrap);
4293
+ if (this.consoleSurface === "dialog") {
4294
+ const testBtn = this.createButton("Console", "route:test");
4295
+ testBtn.dataset.route = "test";
4296
+ testBtn.dataset.editorKey = "route:test";
4297
+ testBtn.dataset.btn = "secondary";
4298
+ testBtn.disabled = this.saving;
4299
+ testBtn.setAttribute("aria-label", "Test console");
4300
+ testBtn.setAttribute("aria-haspopup", "dialog");
4301
+ testBtn.setAttribute(
4302
+ "aria-expanded",
4303
+ this.testConsoleOpen ? "true" : "false"
4304
+ );
4305
+ testBtn.setAttribute("aria-controls", `${this.instanceId}-test-console`);
4306
+ railTools.append(testBtn);
4307
+ }
4308
+ railTools.append(searchWrap);
4259
4309
  this.rail.append(railTools);
4260
4310
  }
4261
4311
  appendProjectActions(actions) {
@@ -5605,6 +5655,30 @@ var EditorControllerImpl = class {
5605
5655
  }
5606
5656
  fields.append(group);
5607
5657
  }
5658
+ setConsolePage(open) {
5659
+ if (this.destroyed || this.consoleSurface !== "page") return;
5660
+ if (this.testConsoleOpen === open) return;
5661
+ this.pendingConsoleLeave = false;
5662
+ this.groupPickerOpen = false;
5663
+ this.testConsoleOpen = open;
5664
+ if (open) this.focusRequest = "test-urls";
5665
+ this.render();
5666
+ }
5667
+ /** Close the console because the user left it for a rule, field, or route. */
5668
+ releaseConsolePage() {
5669
+ if (this.consoleSurface === "page" && this.testConsoleOpen) {
5670
+ this.pendingConsoleLeave = true;
5671
+ }
5672
+ this.testConsoleOpen = false;
5673
+ }
5674
+ syncConsolePageChrome() {
5675
+ const page = this.consoleSurface === "page" && this.testConsoleOpen;
5676
+ this.rail.hidden = page;
5677
+ this.header.hidden = page;
5678
+ this.status.hidden = page;
5679
+ this.form.hidden = page;
5680
+ if (page) this.summary.hidden = true;
5681
+ }
5608
5682
  openTestConsole() {
5609
5683
  this.groupPickerOpen = false;
5610
5684
  this.testConsoleOpen = true;
@@ -5612,12 +5686,13 @@ var EditorControllerImpl = class {
5612
5686
  this.render();
5613
5687
  }
5614
5688
  closeTestConsole() {
5689
+ if (this.consoleSurface === "page") return;
5615
5690
  if (this.testRunning) {
5616
5691
  this.testRequestId += 1;
5617
5692
  this.testRunning = false;
5618
5693
  this.testNotice = "";
5619
5694
  }
5620
- this.testConsoleOpen = false;
5695
+ this.releaseConsolePage();
5621
5696
  this.focusRequest = "route:test";
5622
5697
  this.render();
5623
5698
  }
@@ -5661,6 +5736,13 @@ var EditorControllerImpl = class {
5661
5736
  }
5662
5737
  renderTestConsole() {
5663
5738
  this.host.querySelector("[data-test-console]")?.remove();
5739
+ this.host.querySelector("[data-test-page]")?.remove();
5740
+ if (this.consoleSurface === "page") {
5741
+ if ("inert" in this.layout) this.layout.inert = false;
5742
+ if (!this.testConsoleOpen) return;
5743
+ this.main.append(this.buildTestPage());
5744
+ return;
5745
+ }
5664
5746
  if ("inert" in this.layout) this.layout.inert = this.testConsoleOpen;
5665
5747
  if (!this.testConsoleOpen) return;
5666
5748
  const overlay = this.document.createElement("div");
@@ -5697,8 +5779,31 @@ var EditorControllerImpl = class {
5697
5779
  overlay.append(dialog);
5698
5780
  this.host.append(overlay);
5699
5781
  }
5782
+ buildTestPage() {
5783
+ const page = this.document.createElement("section");
5784
+ page.dataset.testPage = "true";
5785
+ page.id = `${this.instanceId}-test-console`;
5786
+ const head = this.document.createElement("div");
5787
+ head.dataset.testPageHead = "true";
5788
+ const kicker = this.document.createElement("p");
5789
+ kicker.dataset.testKicker = "true";
5790
+ kicker.textContent = "Offline match";
5791
+ const heading = this.document.createElement("h2");
5792
+ heading.id = `${this.instanceId}-test-console-title`;
5793
+ heading.textContent = "Test console";
5794
+ page.setAttribute("aria-labelledby", heading.id);
5795
+ const description = this.document.createElement("p");
5796
+ description.dataset.testDescription = "true";
5797
+ description.textContent = "Check whether these URLs match your rules. Nothing is contacted, and nothing is saved.";
5798
+ head.append(kicker, heading, description);
5799
+ const body = this.document.createElement("div");
5800
+ body.dataset.testPageBody = "true";
5801
+ this.renderTestBody(body);
5802
+ page.append(head, body);
5803
+ return page;
5804
+ }
5700
5805
  openGroupPicker() {
5701
- this.testConsoleOpen = false;
5806
+ this.releaseConsolePage();
5702
5807
  this.groupPickerOpen = true;
5703
5808
  this.focusRequest = this.draft.groups.length > 0 ? "group-picker-first" : "group-picker-close";
5704
5809
  this.render();
@@ -21133,79 +21133,51 @@ function sleep(ms) {
21133
21133
  function calculateRetryDelay(attempt) {
21134
21134
  return RETRY_DELAY_BASE * 2 ** attempt + Math.random() * 100;
21135
21135
  }
21136
- async function fetchWithRetry(url, init, signal) {
21137
- let lastError;
21138
- for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
21139
- if (signal?.aborted) {
21140
- throw new DOMException("Aborted", "AbortError");
21141
- }
21142
- try {
21143
- const controller = new AbortController();
21144
- const timeoutId = setTimeout(() => controller.abort(), COMPLETE_TIMEOUT);
21145
- if (signal) {
21146
- signal.addEventListener("abort", () => controller.abort());
21147
- }
21148
- const response = await fetch(url, {
21149
- ...init,
21150
- signal: controller.signal
21151
- });
21152
- clearTimeout(timeoutId);
21153
- if (response.ok) {
21154
- return response;
21155
- }
21156
- const shouldRetry = response.status === 429 || response.status >= 500;
21157
- if (shouldRetry && attempt < MAX_RETRIES) {
21158
- const retryAfter = response.headers.get("Retry-After");
21159
- const delay = retryAfter ? parseInt(retryAfter, 10) * 1e3 : calculateRetryDelay(attempt);
21160
- await sleep(Math.min(delay, 1e4));
21161
- continue;
21162
- }
21163
- const errorText = await response.text().catch(() => "");
21164
- throw new Error(`HTTP ${response.status}: ${errorText}`);
21165
- } catch (e) {
21166
- lastError = e;
21167
- if (e instanceof DOMException && e.name === "AbortError") {
21168
- throw e;
21169
- }
21170
- if (attempt < MAX_RETRIES && e.name !== "AbortError") {
21171
- await sleep(calculateRetryDelay(attempt));
21172
- continue;
21173
- }
21174
- throw e;
21175
- }
21176
- }
21177
- throw lastError;
21136
+ function providerStatusError(status) {
21137
+ return new Error(`HTTP ${status}`);
21178
21138
  }
21179
- async function fetchStreamWithRetry(url, init, signal) {
21139
+ async function releaseResponse(response) {
21140
+ await response.body?.cancel().catch(() => void 0);
21141
+ }
21142
+ async function fetchProvider(url, init, timeoutMs, signal) {
21180
21143
  let lastError;
21181
21144
  for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
21182
21145
  if (signal?.aborted) {
21183
21146
  throw new DOMException("Aborted", "AbortError");
21184
21147
  }
21148
+ const controller = new AbortController();
21149
+ const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
21150
+ if (signal) {
21151
+ signal.addEventListener("abort", () => controller.abort());
21152
+ }
21153
+ let terminalStatus;
21185
21154
  try {
21186
- const controller = new AbortController();
21187
- const timeoutId = setTimeout(() => controller.abort(), STREAM_TIMEOUT);
21188
- if (signal) {
21189
- signal.addEventListener("abort", () => controller.abort());
21190
- }
21191
21155
  const response = await fetch(url, {
21192
21156
  ...init,
21157
+ // Stay on the configured URL. A 3xx response is not followed.
21158
+ redirect: "manual",
21193
21159
  signal: controller.signal
21194
21160
  });
21195
21161
  clearTimeout(timeoutId);
21196
- if (response.ok) {
21162
+ if (response.status >= 300 && response.status <= 399) {
21163
+ await releaseResponse(response);
21164
+ terminalStatus = response.status;
21165
+ } else if (response.ok) {
21197
21166
  return response;
21167
+ } else {
21168
+ const shouldRetry = response.status === 429 || response.status >= 500;
21169
+ if (shouldRetry && attempt < MAX_RETRIES) {
21170
+ await releaseResponse(response);
21171
+ const retryAfter = response.headers.get("Retry-After");
21172
+ const delay = retryAfter ? parseInt(retryAfter, 10) * 1e3 : calculateRetryDelay(attempt);
21173
+ await sleep(Math.min(delay, 1e4));
21174
+ continue;
21175
+ }
21176
+ await releaseResponse(response);
21177
+ terminalStatus = response.status;
21198
21178
  }
21199
- const shouldRetry = response.status === 429 || response.status >= 500;
21200
- if (shouldRetry && attempt < MAX_RETRIES) {
21201
- const retryAfter = response.headers.get("Retry-After");
21202
- const delay = retryAfter ? parseInt(retryAfter, 10) * 1e3 : calculateRetryDelay(attempt);
21203
- await sleep(Math.min(delay, 1e4));
21204
- continue;
21205
- }
21206
- const errorText = await response.text().catch(() => "");
21207
- throw new Error(`HTTP ${response.status}: ${errorText}`);
21208
21179
  } catch (e) {
21180
+ clearTimeout(timeoutId);
21209
21181
  lastError = e;
21210
21182
  if (e instanceof DOMException && e.name === "AbortError") {
21211
21183
  throw e;
@@ -21216,9 +21188,18 @@ async function fetchStreamWithRetry(url, init, signal) {
21216
21188
  }
21217
21189
  throw e;
21218
21190
  }
21191
+ if (terminalStatus !== void 0) {
21192
+ throw providerStatusError(terminalStatus);
21193
+ }
21219
21194
  }
21220
21195
  throw lastError;
21221
21196
  }
21197
+ function fetchWithRetry(url, init, signal) {
21198
+ return fetchProvider(url, init, COMPLETE_TIMEOUT, signal);
21199
+ }
21200
+ function fetchStreamWithRetry(url, init, signal) {
21201
+ return fetchProvider(url, init, STREAM_TIMEOUT, signal);
21202
+ }
21222
21203
  function sanitizeResponse(text) {
21223
21204
  return text;
21224
21205
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rogatio/cli",
3
- "version": "6.19.1",
3
+ "version": "6.20.1",
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.",