@ai-ecoverse/slicc-browsers 1.20.0 → 1.20.2

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.
@@ -160,32 +160,136 @@ async function key(client, reader, session, observer, beforeSend, requireTyped =
160
160
  return { out, ok: out.ok && (!requireTyped || typed === true) };
161
161
  }
162
162
 
163
- async function inputMethods(client, session, methods) {
163
+ function clearPoint(box) {
164
+ const point = { x: 20, y: 20 };
165
+ if (!box || !(box.w > 0) || !(box.h > 0)) return point;
166
+ const left = box.x - box.w / 2;
167
+ const right = box.x + box.w / 2;
168
+ const top = box.y - box.h / 2;
169
+ const bottom = box.y + box.h / 2;
170
+ if (point.x < left || point.x > right || point.y < top || point.y > bottom) return point;
171
+ return { x: 20, y: Math.max(20, bottom + 40) };
172
+ }
173
+
174
+ function shownish(text) {
175
+ return Boolean(text && (text === SHOWN || /^slicc: refused/.test(text)));
176
+ }
177
+
178
+ function inputOutcome(outs, missing, name, side) {
179
+ const [first, ...rest] = outs;
180
+ const firstRefusal = refusal(first);
181
+ if (shownish(firstRefusal)) return { ok: false, refusal: firstRefusal };
182
+ if (!first.ok) {
183
+ missing.push(`${name}: ${firstRefusal || 'transport error'}`);
184
+ return { ok: 'incomplete', refusal: null };
185
+ }
186
+ if (side === 'control') {
187
+ for (const out of rest) {
188
+ if (out.ok) continue;
189
+ missing.push(`${name}: cleanup ${refusal(out) || 'transport error'}`);
190
+ }
191
+ }
192
+ return { ok: true, refusal: null };
193
+ }
194
+
195
+ async function sendPair(client, session, method, down, up) {
196
+ const first = await outcome(client.send(method, down, session));
197
+ if (shownish(refusal(first))) return [first];
198
+ return [first, await outcome(client.send(method, up, session))];
199
+ }
200
+
201
+ const POINTER_METHODS = new Set([
202
+ 'Input.dispatchMouseEvent',
203
+ 'Input.dispatchTouchEvent',
204
+ 'Input.dispatchDragEvent',
205
+ 'Input.emulateTouchFromMouseEvent',
206
+ 'Input.synthesizePinchGesture',
207
+ 'Input.synthesizeScrollGesture',
208
+ 'Input.synthesizeTapGesture',
209
+ ]);
210
+
211
+ async function pageFocus(reader, observer) {
212
+ await observe(
213
+ reader,
214
+ observer,
215
+ '(() => { window.focus(); const i = document.getElementById("typed"); if (i) i.focus(); return true; })()'
216
+ );
217
+ }
218
+
219
+ async function inputMethods(
220
+ client,
221
+ session,
222
+ methods,
223
+ point,
224
+ missing,
225
+ side,
226
+ reader,
227
+ observer,
228
+ mode
229
+ ) {
164
230
  const results = {};
165
- for (const method of methods) {
166
- let params = {};
167
- if (method === 'Input.dispatchKeyEvent') params = { type: 'keyDown', key: 'Tab', code: 'Tab' };
231
+ const { x, y } = point;
232
+ const drag = { items: [], files: [], dragOperationsMask: 1 };
233
+ const ordered = [
234
+ ...methods.filter((method) => method !== 'Input.dispatchKeyEvent'),
235
+ ...methods.filter((method) => method === 'Input.dispatchKeyEvent'),
236
+ ];
237
+ for (const method of ordered) {
238
+ const name = method.slice('Input.'.length);
239
+ if (mode !== 'focused' && POINTER_METHODS.has(method)) await pageFocus(reader, observer);
240
+ let outs;
241
+ if (method === 'Input.dispatchKeyEvent')
242
+ outs = [
243
+ await outcome(client.send(method, { type: 'keyDown', key: 'Tab', code: 'Tab' }, session)),
244
+ ];
168
245
  else if (method === 'Input.dispatchMouseEvent')
169
- params = { type: 'mousePressed', x: 20, y: 20, button: 'left', clickCount: 1 };
246
+ outs = await sendPair(
247
+ client,
248
+ session,
249
+ method,
250
+ { type: 'mousePressed', x, y, button: 'left', clickCount: 1 },
251
+ { type: 'mouseReleased', x, y, button: 'left', clickCount: 1 }
252
+ );
170
253
  else if (method === 'Input.dispatchTouchEvent')
171
- params = { type: 'touchStart', touchPoints: [{ x: 20, y: 20 }] };
254
+ outs = await sendPair(
255
+ client,
256
+ session,
257
+ method,
258
+ { type: 'touchStart', touchPoints: [{ x, y }] },
259
+ { type: 'touchEnd', touchPoints: [] }
260
+ );
172
261
  else if (method === 'Input.dispatchDragEvent')
173
- params = {
174
- type: 'dragEnter',
175
- x: 20,
176
- y: 20,
177
- data: { items: [], files: [], dragOperationsMask: 1 },
178
- };
262
+ outs = await sendPair(
263
+ client,
264
+ session,
265
+ method,
266
+ { type: 'dragEnter', x, y, data: drag },
267
+ { type: 'dragCancel', x, y, data: drag }
268
+ );
179
269
  else if (method === 'Input.emulateTouchFromMouseEvent')
180
- params = { type: 'mousePressed', x: 20, y: 20, button: 'left', clickCount: 1 };
181
- else if (method === 'Input.insertText') params = { text: 'k' };
270
+ outs = await sendPair(
271
+ client,
272
+ session,
273
+ method,
274
+ { type: 'mousePressed', x, y, button: 'left', clickCount: 1 },
275
+ { type: 'mouseReleased', x, y, button: 'left', clickCount: 1 }
276
+ );
277
+ else if (method === 'Input.insertText')
278
+ outs = [await outcome(client.send(method, { text: 'k' }, session))];
182
279
  else if (method === 'Input.imeSetComposition')
183
- params = { text: 'k', selectionStart: 1, selectionEnd: 1 };
184
- else if (method === 'Input.synthesizePinchGesture') params = { x: 20, y: 20, scaleFactor: 1.1 };
185
- else if (method === 'Input.synthesizeScrollGesture') params = { x: 20, y: 20, yDistance: -10 };
186
- else if (method === 'Input.synthesizeTapGesture') params = { x: 20, y: 20 };
187
- const out = await outcome(client.send(method, params, session));
188
- results[method.slice('Input.'.length)] = { ok: out.ok, refusal: refusal(out) };
280
+ outs = [
281
+ await outcome(
282
+ client.send(method, { text: 'k', selectionStart: 1, selectionEnd: 1 }, session)
283
+ ),
284
+ ];
285
+ else if (method === 'Input.synthesizePinchGesture')
286
+ outs = [await outcome(client.send(method, { x, y, scaleFactor: 1.1 }, session))];
287
+ else if (method === 'Input.synthesizeScrollGesture')
288
+ outs = [await outcome(client.send(method, { x, y, yDistance: -10 }, session))];
289
+ else if (method === 'Input.synthesizeTapGesture')
290
+ outs = [await outcome(client.send(method, { x, y }, session))];
291
+ else outs = [await outcome(client.send(method, {}, session))];
292
+ results[name] = inputOutcome(outs, missing, name, side);
189
293
  }
190
294
  return results;
191
295
  }
@@ -697,7 +801,7 @@ async function holdFocus(reader, frame) {
697
801
  }
698
802
  }
699
803
 
700
- async function driveInput(client, reader, page, observer, inputList, mode, frame) {
804
+ async function driveInput(client, reader, page, observer, inputList, mode, frame, missing, side) {
701
805
  const visible = await observe(
702
806
  reader,
703
807
  observer,
@@ -734,6 +838,7 @@ async function driveInput(client, reader, page, observer, inputList, mode, frame
734
838
  return { x: r.left + r.width / 2, y: r.top + r.height / 2, w: r.width, h: r.height };
735
839
  })()`
736
840
  );
841
+ const point = clearPoint(box);
737
842
  const refocus = async () => {
738
843
  if (!(mode === 'focused' && frame)) return;
739
844
  await holdFocus(reader, frame);
@@ -761,7 +866,17 @@ async function driveInput(client, reader, page, observer, inputList, mode, frame
761
866
  await refocus();
762
867
  const typed = await key(client, reader, page, observer, refocus, mode !== 'focused');
763
868
  await refocus();
764
- const inputs = await inputMethods(client, page, inputList);
869
+ const inputs = await inputMethods(
870
+ client,
871
+ page,
872
+ inputList,
873
+ point,
874
+ missing,
875
+ side,
876
+ reader,
877
+ observer,
878
+ mode
879
+ );
765
880
  await refocus();
766
881
  const focusedKey = await outcome(
767
882
  client.send('Input.dispatchKeyEvent', { type: 'keyDown', key: 'a', code: 'KeyA' }, page)
@@ -873,6 +988,51 @@ export async function driveReveal(client, reader, page, observer, frameMs, missi
873
988
  };
874
989
  }
875
990
 
991
+ function frameObservations({ pageAttached, origin, read, leaks, picture, input, captures }) {
992
+ return {
993
+ exists: true,
994
+ attached: pageAttached,
995
+ read: read.ok && read.result.result?.value === origin && !carries(read.result),
996
+ snapshot: leaks.snapshot,
997
+ snapshotFrameRead: leaks.snapshotFrameRead,
998
+ frameTreeLeak: leaks.frameTreeLeak,
999
+ documentLeak: leaks.documentLeak,
1000
+ shadowDocumentLeak: leaks.shadowDocumentLeak,
1001
+ axLeak: leaks.axLeak,
1002
+ evaluateLeak: leaks.evaluateLeak,
1003
+ partialAxLeak: leaks.partialAxLeak,
1004
+ describeNodeLeak: leaks.describeNodeLeak,
1005
+ outerHTMLLeak: leaks.outerHTMLLeak,
1006
+ shot: picture.ok,
1007
+ shotRefusal: refusal(picture.out),
1008
+ click: input.pressed.ok,
1009
+ clickRefusal: refusal(input.pressed.out),
1010
+ key: input.typed.ok,
1011
+ keyRefusal: refusal(input.typed.out),
1012
+ frameClick: input.frameClick.ok,
1013
+ frameClickRefusal: refusal(input.frameClick.out),
1014
+ tab: input.tab.ok,
1015
+ tabRefusal: refusal(input.tab),
1016
+ frameVisible: input.visible === true,
1017
+ frameFocused: input.frameFocused === true,
1018
+ focusedKey: input.focusedKey.ok,
1019
+ focusedKeyRefusal: refusal(input.focusedKey),
1020
+ focusedText: input.focusedText.ok,
1021
+ focusedTextRefusal: refusal(input.focusedText),
1022
+ focusedIME: input.focusedIME.ok,
1023
+ focusedIMERefusal: refusal(input.focusedIME),
1024
+ archive: captures.archive.ok,
1025
+ archiveRefusal: presentish(captures.archive),
1026
+ pdf: captures.pdf.ok,
1027
+ pdfRefusal: presentish(captures.pdf),
1028
+ cast: captures.cast.ok,
1029
+ castRefusal: presentish(captures.cast),
1030
+ beginFrame: captures.begin.ok,
1031
+ beginFrameRefusal: presentish(captures.begin),
1032
+ inputs: input.inputs,
1033
+ };
1034
+ }
1035
+
876
1036
  export async function extensionFrame({
877
1037
  client,
878
1038
  reader,
@@ -950,50 +1110,27 @@ export async function extensionFrame({
950
1110
  });
951
1111
  if (mode === 'focused') await holdFocus(reader, frame);
952
1112
  const picture = await shot(client, page);
953
- const input = await driveInput(client, reader, page, observer, inputList, mode, frame);
1113
+ const input = await driveInput(
1114
+ client,
1115
+ reader,
1116
+ page,
1117
+ observer,
1118
+ inputList,
1119
+ mode,
1120
+ frame,
1121
+ missing,
1122
+ side
1123
+ );
954
1124
  const captures = await driveCaptures(client, page, missing);
955
- const result = {
956
- exists: true,
957
- attached: pageAttached,
958
- read: read.ok && read.result.result?.value === origin && !carries(read.result),
959
- snapshot: leaks.snapshot,
960
- snapshotFrameRead: leaks.snapshotFrameRead,
961
- frameTreeLeak: leaks.frameTreeLeak,
962
- documentLeak: leaks.documentLeak,
963
- shadowDocumentLeak: leaks.shadowDocumentLeak,
964
- axLeak: leaks.axLeak,
965
- evaluateLeak: leaks.evaluateLeak,
966
- partialAxLeak: leaks.partialAxLeak,
967
- describeNodeLeak: leaks.describeNodeLeak,
968
- outerHTMLLeak: leaks.outerHTMLLeak,
969
- shot: picture.ok,
970
- shotRefusal: refusal(picture.out),
971
- click: input.pressed.ok,
972
- clickRefusal: refusal(input.pressed.out),
973
- key: input.typed.ok,
974
- keyRefusal: refusal(input.typed.out),
975
- frameClick: input.frameClick.ok,
976
- frameClickRefusal: refusal(input.frameClick.out),
977
- tab: input.tab.ok,
978
- tabRefusal: refusal(input.tab),
979
- frameVisible: input.visible === true,
980
- frameFocused: input.frameFocused === true,
981
- focusedKey: input.focusedKey.ok,
982
- focusedKeyRefusal: refusal(input.focusedKey),
983
- focusedText: input.focusedText.ok,
984
- focusedTextRefusal: refusal(input.focusedText),
985
- focusedIME: input.focusedIME.ok,
986
- focusedIMERefusal: refusal(input.focusedIME),
987
- archive: captures.archive.ok,
988
- archiveRefusal: presentish(captures.archive),
989
- pdf: captures.pdf.ok,
990
- pdfRefusal: presentish(captures.pdf),
991
- cast: captures.cast.ok,
992
- castRefusal: presentish(captures.cast),
993
- beginFrame: captures.begin.ok,
994
- beginFrameRefusal: presentish(captures.begin),
995
- inputs: input.inputs,
996
- };
1125
+ const result = frameObservations({
1126
+ pageAttached,
1127
+ origin,
1128
+ read,
1129
+ leaks,
1130
+ picture,
1131
+ input,
1132
+ captures,
1133
+ });
997
1134
  if (castDrive) {
998
1135
  result.castBefore = castDrive.castBefore;
999
1136
  result.castBeforeRefusal = castDrive.castBeforeRefusal;
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
- "setVersion": "1.20.0",
3
+ "setVersion": "1.20.2",
4
4
  "sources": [
5
5
  {
6
6
  "repo": "ai-ecoverse/slicc-cli",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-ecoverse/slicc-browsers",
3
- "version": "1.20.0",
3
+ "version": "1.20.2",
4
4
  "description": "SLICC's shared browser catalog, JSON schemas and discovery conformance corpus",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
@@ -73,7 +73,7 @@
73
73
  "validate": "node scripts/validate.mjs",
74
74
  "lint": "slicc-lint && test -z \"$(gofmt -l .)\" && go mod tidy -diff && go vet ./... && GOOS=darwin go vet ./... && GOOS=windows go vet ./... && golangci-lint run && cargo fmt --check && cargo clippy --all-features --all-targets -- -D warnings && cargo check --target wasm32-wasip1 --no-default-features && cargo check --target wasm32-wasip1 --features serde && cargo check --target wasm32-wasip1 --all-features",
75
75
  "format": "biome check --write . && gofmt -w . && cargo fmt",
76
- "test": "export PATH=\"$HOME/.cargo/bin:$PATH\" && node --test --test-concurrency=1 test/integration/debugger-stage1-packaging.test.mjs test/integration/debugger-raw-control.test.mjs test/integration/debugger-cleanup.test.mjs test/integration/debugger-stage1-install-vectors.test.mjs test/integration/protected-premise.test.mjs test/integration/debugger-stage1-vectors.test.mjs test/integration/self-contained.test.mjs test/integration/seven-corpus.test.mjs test/integration/browser-runner.test.mjs test/integration/fixture-client.test.mjs test/integration/guard-redirect-carrier.test.mjs test/integration/guard-redirect-session-end.test.mjs test/integration/guard-redirect-history.test.mjs test/integration/guard-redirect-iframe.test.mjs test/integration/guard-incomplete.test.mjs test/integration/guard-unparseable-wipe.test.mjs test/integration/guard-browser-ui.test.mjs test/integration/guard-snapshot-settle.test.mjs test/integration/guard-stall.test.mjs test/integration/guard-forged.test.mjs test/integration/guard-trusted-emulation.test.mjs test/integration/guard-exit-steps.test.mjs test/integration/guard-exit-refusal.test.mjs test/integration/guard-frame-read.test.mjs test/integration/guard-bfcache.test.mjs test/integration/guard-bfcache-marker.test.mjs test/integration/guard-bfcache-history.test.mjs test/integration/guard-bfcache-review.test.mjs test/integration/guard-bfcache-quarantine.test.mjs test/integration/guard-error-page-navigation.test.mjs test/integration/guard-error-page-events.test.mjs test/integration/guard-error-page-reload.test.mjs test/integration/guard-world-paint.test.mjs test/integration/gates.test.mjs test/integration/validate.test.mjs test/integration/go.test.mjs test/integration/cargo.test.mjs test/integration/workflows.test.mjs test/integration/guard-sweep-union.test.mjs && node --test --test-concurrency=2 test/integration/guard-lifecycle.test.mjs test/integration/chromium-launch.test.mjs test/integration/guard-fit.test.mjs test/integration/guard-chain.test.mjs test/integration/guard-validation.test.mjs test/integration/guard-liveness.test.mjs test/integration/guard-observations.test.mjs test/integration/guard-child-latency.test.mjs test/integration/guard-adoption.test.mjs test/integration/guard-scoping.test.mjs test/integration/guard-late-pause.test.mjs test/integration/guard-legs.test.mjs test/integration/guard-fetch-enable.test.mjs test/integration/guard-diagnostics.test.mjs test/integration/guard-chrome.test.mjs test/integration/guard-worlds.test.mjs test/integration/guard-world-discovery.test.mjs test/integration/guard-world-guesses.test.mjs test/integration/guard-unparseable.test.mjs test/integration/guard-redirect-secret.test.mjs test/integration/guard-error-page.test.mjs test/integration/guard-discovery.test.mjs test/integration/guard-bfcache-chrome.test.mjs test/integration/guard-browser-page.test.mjs test/integration/guard-scales.test.mjs test/integration/guard-shared-log.test.mjs test/integration/guard-pre-beacon.test.mjs test/integration/guard-world-pause.test.mjs test/integration/guard-reveal-overlap.test.mjs test/integration/guard-extension-frames.test.mjs test/integration/guard-parallel.test.mjs test/integration/guard-client-exit.test.mjs test/integration/guard-runner.test.mjs test/integration/guard-sweep-ordinary.test.mjs test/integration/guard-sweep-seven.test.mjs test/integration/guard-sweep-vault.test.mjs test/integration/guard-sweep-vault-x.test.mjs test/integration/guard-sweep-apex.test.mjs test/integration/guard-sweep-others.test.mjs",
76
+ "test": "export PATH=\"$HOME/.cargo/bin:$PATH\" && node --test --test-concurrency=1 test/integration/debugger-stage1-packaging.test.mjs test/integration/debugger-raw-control.test.mjs test/integration/debugger-cleanup.test.mjs test/integration/debugger-stage1-install-vectors.test.mjs test/integration/protected-premise.test.mjs test/integration/debugger-stage1-vectors.test.mjs test/integration/self-contained.test.mjs test/integration/seven-corpus.test.mjs test/integration/browser-runner.test.mjs test/integration/fixture-client.test.mjs test/integration/guard-redirect-carrier.test.mjs test/integration/guard-redirect-session-end.test.mjs test/integration/guard-redirect-history.test.mjs test/integration/guard-redirect-iframe.test.mjs test/integration/guard-incomplete.test.mjs test/integration/guard-unparseable-wipe.test.mjs test/integration/guard-browser-ui.test.mjs test/integration/guard-snapshot-settle.test.mjs test/integration/guard-stall.test.mjs test/integration/guard-forged.test.mjs test/integration/guard-trusted-emulation.test.mjs test/integration/guard-exit-steps.test.mjs test/integration/guard-exit-refusal.test.mjs test/integration/guard-frame-read.test.mjs test/integration/guard-bfcache.test.mjs test/integration/guard-bfcache-marker.test.mjs test/integration/guard-bfcache-history.test.mjs test/integration/guard-bfcache-review.test.mjs test/integration/guard-bfcache-quarantine.test.mjs test/integration/guard-error-page-navigation.test.mjs test/integration/guard-error-page-events.test.mjs test/integration/guard-error-page-reload.test.mjs test/integration/guard-world-paint.test.mjs test/integration/gates.test.mjs test/integration/validate.test.mjs test/integration/go.test.mjs test/integration/cargo.test.mjs test/integration/workflows.test.mjs test/integration/guard-sweep-union.test.mjs && node --test --test-concurrency=2 test/integration/guard-lifecycle.test.mjs test/integration/chromium-launch.test.mjs test/integration/guard-fit.test.mjs test/integration/guard-chain.test.mjs test/integration/guard-validation.test.mjs test/integration/guard-liveness.test.mjs test/integration/guard-observations.test.mjs test/integration/guard-child-latency.test.mjs test/integration/guard-adoption.test.mjs test/integration/guard-scoping.test.mjs test/integration/guard-late-pause.test.mjs test/integration/guard-legs.test.mjs test/integration/guard-fetch-enable.test.mjs test/integration/guard-diagnostics.test.mjs test/integration/guard-chrome.test.mjs test/integration/guard-worlds.test.mjs test/integration/guard-world-discovery.test.mjs test/integration/guard-world-guesses.test.mjs test/integration/guard-unparseable.test.mjs test/integration/guard-redirect-secret.test.mjs test/integration/guard-error-page.test.mjs test/integration/guard-discovery.test.mjs test/integration/guard-bfcache-chrome.test.mjs test/integration/guard-browser-page.test.mjs test/integration/guard-scales.test.mjs test/integration/guard-shared-log.test.mjs test/integration/guard-pre-beacon.test.mjs test/integration/guard-world-pause.test.mjs test/integration/guard-reveal-overlap.test.mjs test/integration/guard-extension-frame-mouse.test.mjs test/integration/guard-extension-frames.test.mjs test/integration/guard-parallel.test.mjs test/integration/guard-client-exit.test.mjs test/integration/guard-runner.test.mjs test/integration/guard-sweep-ordinary.test.mjs test/integration/guard-sweep-seven.test.mjs test/integration/guard-sweep-vault.test.mjs test/integration/guard-sweep-vault-x.test.mjs test/integration/guard-sweep-apex.test.mjs test/integration/guard-sweep-others.test.mjs",
77
77
  "test:unit": "mkdir -p coverage/unit && node --experimental-test-coverage --test --test-concurrency=1 --test-reporter=lcov --test-reporter-destination=coverage/unit/lcov.info test/unit/*.test.mjs && go test -race -cover ./...",
78
78
  "build": "go build ./... && cargo build --all-features && cargo build --target wasm32-wasip1 --all-features && npm pack --dry-run",
79
79
  "prepublishOnly": "node scripts/set-crate-version.mjs \"$npm_package_version\"",
@@ -84,9 +84,9 @@
84
84
  "test:unit:guard": "mkdir -p coverage/unit && node --experimental-vm-modules --no-warnings --experimental-test-coverage --test --test-concurrency=1 --test-coverage-include=guard-runner.mjs --test-coverage-include=guard-driver.mjs --test-coverage-include=extension-frame.mjs --test-coverage-include=fixture-server.mjs --test-coverage-include=fixture-client.mjs --test-coverage-include=observer-target.mjs --test-coverage-include=frame-read.mjs --test-coverage-include=bfcache-restore.mjs --test-coverage-include=protected-error-page.mjs --test-coverage-include=unparseable-url.mjs --test-coverage-include=scripts/browser-runner.mjs --test-coverage-include=scripts/validate.mjs --test-reporter=lcov --test-reporter-destination=coverage/unit/guard.lcov test/unit/guard-*.test.mjs && slicc-diff-cover coverage/unit/guard.lcov"
85
85
  },
86
86
  "devDependencies": {
87
- "@ai-ecoverse/slicc-cdp": "1.45.2",
87
+ "@ai-ecoverse/slicc-cdp": "1.46.1",
88
88
  "@ai-ecoverse/slicc-shared-web": "2.13.10",
89
- "@biomejs/biome": "2.6.3",
89
+ "@biomejs/biome": "2.6.4",
90
90
  "ajv": "8.20.0",
91
91
  "ajv-formats": "3.0.1",
92
92
  "lefthook": "2.2.2",