@codeyam-editor/codeyam-editor 0.1.4 → 0.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. package/npm/cli.js +5 -1
  2. package/npm/cloud-branch-switch.js +1 -1
  3. package/npm/cloud.js +3166 -150
  4. package/npm/codesign-plan.js +68 -0
  5. package/npm/container.js +3 -0
  6. package/npm/disk-pressure.js +78 -0
  7. package/npm/editor-dev.js +96 -15
  8. package/npm/editor.js +85 -37
  9. package/npm/empty-project-dir.js +92 -7
  10. package/npm/fleet-add-failure.js +252 -0
  11. package/npm/fleet-asset-version.js +37 -0
  12. package/npm/fleet-auth-health.js +213 -0
  13. package/npm/fleet-auth.js +6 -1
  14. package/npm/fleet-build-data.js +109 -5
  15. package/npm/fleet-cleanup.js +232 -16
  16. package/npm/fleet-destroy-safety.js +272 -0
  17. package/npm/fleet-early-roster.js +87 -0
  18. package/npm/fleet-effect-poll.js +110 -0
  19. package/npm/fleet-effect-status.js +33 -32
  20. package/npm/fleet-env.js +86 -0
  21. package/npm/fleet-ghcr-secret.js +129 -0
  22. package/npm/fleet-git-maintenance.js +142 -0
  23. package/npm/fleet-host-op-limiter.js +68 -0
  24. package/npm/fleet-host.js +74 -0
  25. package/npm/fleet-iap-token.js +165 -0
  26. package/npm/fleet-job-badge.js +1 -1
  27. package/npm/fleet-launchd.js +171 -0
  28. package/npm/fleet-live-status.js +155 -0
  29. package/npm/fleet-memory.js +245 -9
  30. package/npm/fleet-plans.js +233 -4
  31. package/npm/fleet-pool.js +75 -16
  32. package/npm/fleet-prewarm.js +241 -0
  33. package/npm/fleet-project-drift.js +58 -0
  34. package/npm/fleet-public-url.js +394 -0
  35. package/npm/fleet-queue.js +95 -1
  36. package/npm/fleet-reachability-debounce.js +69 -0
  37. package/npm/fleet-reachability.js +80 -0
  38. package/npm/fleet-reconcile.js +43 -1
  39. package/npm/fleet-reset.js +330 -13
  40. package/npm/fleet-roster.js +6 -8
  41. package/npm/fleet-running-plan.js +85 -0
  42. package/npm/fleet-self-update.js +142 -0
  43. package/npm/fleet-session-token-cache.js +65 -0
  44. package/npm/fleet-setup-steps.js +112 -0
  45. package/npm/fleet-sleep-status.js +33 -0
  46. package/npm/fleet-status-refs.js +96 -0
  47. package/npm/fleet-strand.js +181 -0
  48. package/npm/fleet-stuck-status.js +117 -0
  49. package/npm/fleet-vm-access.js +404 -0
  50. package/npm/fleet-vm-probe-target.js +282 -0
  51. package/npm/fleet-vm-readiness.js +237 -0
  52. package/npm/fleet-vm-slugs.js +116 -0
  53. package/npm/google-ingress.js +226 -0
  54. package/npm/ingress-invoke.js +770 -0
  55. package/npm/launch-config.js +386 -9
  56. package/npm/scenario-check.js +880 -37
  57. package/npm/scenario-handlers.js +154 -30
  58. package/npm/scenario-interactivity.js +145 -6
  59. package/npm/scenario-issues.js +13 -1
  60. package/npm/scenario-metrics.js +116 -1
  61. package/npm/scenario-mocks.js +144 -21
  62. package/npm/scenario-playwright.js +649 -38
  63. package/npm/script-drift.js +152 -0
  64. package/npm/utils.js +365 -52
  65. package/npm/vm-urls.js +69 -8
  66. package/package.json +5 -5
  67. package/ui/dist/assets/ContainerInspector-DgM0pTAx.js +2 -0
  68. package/ui/dist/assets/EditorShell-B7Q06uJ_.js +252 -0
  69. package/ui/dist/assets/EditorShell-DP5UY20G.css +1 -0
  70. package/ui/dist/assets/{Markdown-BHBqz-Mj.js → Markdown-Chgdf3PW.js} +1 -1
  71. package/ui/dist/assets/ProjectLauncherScreen-BRrEr8Ng.js +1 -0
  72. package/ui/dist/assets/ScenarioDataPanel-BeQfa28g.js +9 -0
  73. package/ui/dist/assets/{ScenarioDataPanel-DYP7pi_n.css → ScenarioDataPanel-C1LukYI6.css} +1 -1
  74. package/ui/dist/assets/ScenarioDataPanelFullPage-BLqRCxQX.js +1 -0
  75. package/ui/dist/assets/ScenarioRenderer-CIAxfHPh.js +21 -0
  76. package/ui/dist/assets/StepsSimulator-CymGgfbu.js +1 -0
  77. package/ui/dist/assets/index-BygCiJSb.css +1 -0
  78. package/ui/dist/assets/{index-BuK0lizt.js → index-DCHqRrwO.js} +9 -9
  79. package/ui/dist/assets/{markdown-v0F0UEt3.js → markdown-C9tbsVHX.js} +1 -1
  80. package/ui/dist/assets/react-nrLBr15I.js +28 -0
  81. package/ui/dist/assets/useEvents-S3Qk1Y_d.js +1 -0
  82. package/ui/dist/assets/useServerIdentity-B7rI0u3O.js +1 -0
  83. package/ui/dist/codeyam-mark.svg +4 -0
  84. package/ui/dist/codeyam-wordmark.svg +5 -0
  85. package/ui/dist/index.html +4 -4
  86. package/ui/dist/open-source/codeyam-counter.png +0 -0
  87. package/ui/dist/open-source/el-carot.png +0 -0
  88. package/ui/dist/open-source/tabcommand.png +0 -0
  89. package/ui/dist/assets/ContainerInspector-C8EkH4PP.js +0 -2
  90. package/ui/dist/assets/EditorShell-tMMdarZD.js +0 -187
  91. package/ui/dist/assets/ScenarioDataPanel-xWYGZOpo.js +0 -5
  92. package/ui/dist/assets/ScenarioDataPanelFullPage-5G6KuZgw.js +0 -1
  93. package/ui/dist/assets/ScenarioRenderer-CSdhX1Ak.js +0 -1
  94. package/ui/dist/assets/StepsSimulator-CRtmlyNZ.js +0 -1
  95. package/ui/dist/assets/index-BGqairFV.css +0 -1
  96. package/ui/dist/assets/react-CSS0HapR.js +0 -28
  97. package/ui/dist/assets/useEvents-DggWrtHe.js +0 -1
@@ -1,45 +1,124 @@
1
- function normalizeMockCandidates(url) {
1
+ // Route matcher shared, semantically, with the injected live-preview shim
2
+ // (crates/proxy-http/src/fetch_patch.js::matchUrl / matchPath / matchQuerySpec).
3
+ // This is a VERBATIM port of that shim's matcher — the two interception paths
4
+ // MUST agree on which requests a mock route covers. When they drifted (the
5
+ // shim gained `:param` + query-spec parity but this capture-harness matcher was
6
+ // left doing exact string matching), a parameterized or query-spec'd mock
7
+ // rendered in the Live Preview but escaped Playwright's `page.route` during
8
+ // capture and rendered an empty list. `scenario-mocks.test.js` pins the two to
9
+ // identical verdicts on a shared fixture table so a future divergence is a
10
+ // test failure, not another lost build session.
11
+ //
12
+ // `:param` path segments match any single non-empty segment; a `?k=v` / `?k=*`
13
+ // query-spec suffix constrains the query as a subset match (`k=*` matches any
14
+ // value; an empty spec matches any query). Full-URL patterns (`http://…`) match
15
+ // by prefix on the raw URL. Mirrors crates/mock-engine's server matcher.
16
+ function matchUrl(pattern, url) {
17
+ // Full-URL patterns (external APIs) match by prefix on the raw URL.
18
+ if (pattern.startsWith("http://") || pattern.startsWith("https://")) {
19
+ return url.indexOf(pattern) === 0;
20
+ }
21
+
22
+ let reqPath = url;
23
+ let reqQuery = "";
2
24
  try {
3
- const parsed = new URL(url);
4
- return [url, `${parsed.pathname}${parsed.search}`, parsed.pathname];
25
+ const u = new URL(url);
26
+ reqPath = u.pathname;
27
+ reqQuery = u.search.replace(/^\?/, "");
5
28
  } catch {
6
- return [url];
29
+ const qi = url.indexOf("?");
30
+ if (qi >= 0) {
31
+ reqPath = url.slice(0, qi);
32
+ reqQuery = url.slice(qi + 1);
33
+ }
7
34
  }
35
+
36
+ const patParts = pattern.split("?");
37
+ if (!matchPath(patParts[0], reqPath)) return false;
38
+ return matchQuerySpec(patParts.length > 1 ? patParts[1] : "", reqQuery);
39
+ }
40
+
41
+ // Segment-wise path match with `:param` wildcards. A `:name` segment matches
42
+ // any single non-empty segment; every other segment must be equal, and the
43
+ // segment counts must match — no implicit prefix match, same as the server.
44
+ function matchPath(pattern, path) {
45
+ const pp = pattern.split("/");
46
+ const rp = path.split("/");
47
+ if (pp.length !== rp.length) return false;
48
+ for (let i = 0; i < pp.length; i++) {
49
+ if (pp[i].charAt(0) === ":") {
50
+ if (rp[i] === "") return false;
51
+ continue;
52
+ }
53
+ if (pp[i] !== rp[i]) return false;
54
+ }
55
+ return true;
56
+ }
57
+
58
+ // Query-spec match. An empty spec matches any query (a path-only route still
59
+ // matches a request that carries query params). Otherwise every `k=v` pair in
60
+ // the spec must be present in the request query; `k=*` matches any value.
61
+ function matchQuerySpec(spec, query) {
62
+ if (!spec) return true;
63
+ const want = new URLSearchParams(spec);
64
+ const have = new URLSearchParams(query);
65
+ let ok = true;
66
+ want.forEach((v, k) => {
67
+ const got = have.get(k);
68
+ if (got === null) {
69
+ ok = false;
70
+ return;
71
+ }
72
+ if (v !== "*" && got !== v) ok = false;
73
+ });
74
+ return ok;
75
+ }
76
+
77
+ // Split a mock key (`"<METHOD> <route>"`, e.g. `"GET /api/plans"`) into its
78
+ // method and route pattern. Returns null for a malformed key with no separator.
79
+ function splitMockKey(key) {
80
+ const spaceIdx = key.indexOf(" ");
81
+ if (spaceIdx === -1) return null;
82
+ return { method: key.slice(0, spaceIdx), route: key.slice(spaceIdx + 1) };
8
83
  }
9
84
 
10
85
  function findHttpMock(httpMocks, request) {
11
86
  const method = request.method().toUpperCase();
12
- const candidates = normalizeMockCandidates(request.url());
13
- for (const candidate of candidates) {
14
- const key = `${method} ${candidate}`;
15
- if (httpMocks[key]) {
16
- return httpMocks[key];
17
- }
87
+ const url = request.url();
88
+ for (const [key, mock] of Object.entries(httpMocks)) {
89
+ const parsed = splitMockKey(key);
90
+ if (!parsed) continue;
91
+ // Method stays an exact check; only the route is matched by pattern.
92
+ if (parsed.method.toUpperCase() !== method) continue;
93
+ if (matchUrl(parsed.route, url)) return mock;
18
94
  }
19
95
  return null;
20
96
  }
21
97
 
22
- // The set of path/URL targets declared by the mock keys. A key is
23
- // `"<METHOD> <target>"` (e.g. `"GET /api/plans"`); we strip the method so the
98
+ // The set of path/URL route patterns declared by the mock keys. A key is
99
+ // `"<METHOD> <route>"` (e.g. `"GET /api/plans"`); we strip the method so the
24
100
  // route matcher can decide whether a request *could* match any mock without
25
101
  // knowing the method (the handler re-checks method via findHttpMock).
26
102
  function mockedTargets(httpMocks) {
27
103
  const targets = new Set();
28
104
  for (const key of Object.keys(httpMocks)) {
29
- const spaceIdx = key.indexOf(" ");
30
- if (spaceIdx === -1) continue;
31
- targets.add(key.slice(spaceIdx + 1));
105
+ const parsed = splitMockKey(key);
106
+ if (!parsed) continue;
107
+ targets.add(parsed.route);
32
108
  }
33
109
  return targets;
34
110
  }
35
111
 
36
- // True when a request URL matches one of the declared mock targets. Accepts
37
- // either a string or a WHATWG URL (Playwright's URL-matcher passes a URL).
112
+ // True when a request URL matches one of the declared mock route patterns under
113
+ // the shared route matcher (`:param` + query-spec parity), not exact string
114
+ // equality. Accepts either a string or a WHATWG URL (Playwright's URL-matcher
115
+ // passes a URL).
38
116
  function requestTargetsMock(targets, url) {
39
117
  const href = typeof url === "string" ? url : url.href;
40
- return normalizeMockCandidates(href).some((candidate) =>
41
- targets.has(candidate),
42
- );
118
+ for (const target of targets) {
119
+ if (matchUrl(target, href)) return true;
120
+ }
121
+ return false;
43
122
  }
44
123
 
45
124
  async function attachHttpMocks(page, httpMocks) {
@@ -98,10 +177,54 @@ async function attachHttpMocks(page, httpMocks) {
98
177
  });
99
178
  }
100
179
 
180
+
181
+ // True when a console "Failed to load resource" error at `url` corresponds to
182
+ // a mock this scenario DECLARED with an error status (>= 400). An intentional
183
+ // error-state scenario (e.g. a History tab mocking `GET /api/history` -> 500)
184
+ // must not fail its own capture on the console noise its mock deliberately
185
+ // produces. Console errors carry no HTTP method, so any method's mock on a
186
+ // matching target counts.
187
+ function isDeclaredErrorMock(httpMocks, url) {
188
+ for (const [key, mock] of Object.entries(httpMocks || {})) {
189
+ const parsed = splitMockKey(key);
190
+ if (!parsed) continue;
191
+ // Method-agnostic on purpose: console errors carry no HTTP method, so any
192
+ // method's error mock on a matching route counts. Route matching uses the
193
+ // shared matcher so a `:param`/query-spec error mock is recognised too.
194
+ if (!matchUrl(parsed.route, url)) continue;
195
+ if ((mock.status || 200) >= 400) return true;
196
+ }
197
+ return false;
198
+ }
199
+
200
+ // Given a same-origin response's method/url/status and the scenario's declared
201
+ // mocks, return the `{method, path, status}` to record as an unmocked route, or
202
+ // `null` if it should be ignored: a sub-4xx response, or one already covered by
203
+ // a declared error mock (status >= 400, whose 4xx is the mock's intended
204
+ // behavior). The caller applies the same-origin and `expectedConsoleErrors`
205
+ // gates before calling. `path` is the URL pathname — the route half of the
206
+ // `"<METHOD> <path>"` stub-mock key; a malformed URL falls back to the raw
207
+ // string so the key is still well-formed.
208
+ function unmockedRouteFrom(method, url, status, httpMocks) {
209
+ if (status < 400) return null;
210
+ if (isDeclaredErrorMock(httpMocks, url)) return null;
211
+ let path = url;
212
+ try {
213
+ path = new URL(url).pathname;
214
+ } catch {
215
+ /* malformed URL — fall back to the raw string for the stub key */
216
+ }
217
+ return { method: String(method).toUpperCase(), path, status };
218
+ }
219
+
101
220
  module.exports = {
102
- normalizeMockCandidates,
221
+ matchUrl,
222
+ matchPath,
223
+ matchQuerySpec,
103
224
  findHttpMock,
104
225
  mockedTargets,
105
226
  requestTargetsMock,
106
227
  attachHttpMocks,
228
+ isDeclaredErrorMock,
229
+ unmockedRouteFrom,
107
230
  };