diff --git a/.changeset/olive-pens-draw.md b/.changeset/olive-pens-draw.md new file mode 100644 index 0000000..12b126f --- /dev/null +++ b/.changeset/olive-pens-draw.md @@ -0,0 +1,10 @@ +--- +'@tanstack/angular-store': patch +'@tanstack/preact-store': patch +'@tanstack/svelte-store': patch +'@tanstack/react-store': patch +'@tanstack/solid-store': patch +'@tanstack/vue-store': patch +--- + +Fix adapter `shallow` equality for keyless value objects (e.g. Temporal) so updates aren’t skipped. diff --git a/package.json b/package.json index 5af6e0c..467a5ab 100644 --- a/package.json +++ b/package.json @@ -41,6 +41,7 @@ "devDependencies": { "@changesets/cli": "^2.29.8", "@eslint-react/eslint-plugin": "^1.53.1", + "@js-temporal/polyfill": "^0.5.1", "@svitejs/changesets-changelog-github-compact": "^1.2.0", "@tanstack/eslint-config": "0.3.3", "@tanstack/typedoc-config": "0.3.1", @@ -60,7 +61,9 @@ "prettier-plugin-svelte": "^3.4.0", "publint": "^0.3.15", "sherif": "^1.9.0", + "temporal-polyfill": "^0.3.0", "tinyglobby": "^0.2.15", + "tsx": "^4.21.0", "typescript": "5.6.3", "typescript50": "npm:typescript@5.0", "typescript51": "npm:typescript@5.1", @@ -79,4 +82,4 @@ "@tanstack/svelte-store": "workspace:*", "@tanstack/vue-store": "workspace:*" } -} +} \ No newline at end of file diff --git a/packages/angular-store/src/index.ts b/packages/angular-store/src/index.ts index 130120a..bf71688 100644 --- a/packages/angular-store/src/index.ts +++ b/packages/angular-store/src/index.ts @@ -90,6 +90,32 @@ function shallow(objA: T, objB: T) { return true } + /** + * Temporal branding note: + * Temporal types (native or polyfill) define `Symbol.toStringTag` values like + * `"Temporal.PlainDate"` as part of the TC39 Temporal spec, which makes this + * check reliable across realms/polyfills (unlike `instanceof`). + * + * See: + * - https://tc39.es/proposal-temporal/ + * - https://tc39.es/proposal-temporal/docs/plaindate.html + */ + const tagA = getToStringTag(objA) + const tagB = getToStringTag(objB) + const isTemporal = + tagA !== undefined && + tagB !== undefined && + tagA === tagB && + tagA.startsWith('Temporal.') + + if (isTemporal && hasEquals(objA) && hasEquals(objB)) { + try { + return objA.equals(objB) + } catch { + return false + } + } + const keysA = Object.keys(objA) if (keysA.length !== Object.keys(objB).length) { return false @@ -105,3 +131,20 @@ function shallow(objA: T, objB: T) { } return true } + +function hasEquals( + value: TValue, +): value is TValue & { equals: (other: unknown) => boolean } { + return ( + typeof value === 'object' && + value !== null && + 'equals' in (value as object) && + typeof (value as any).equals === 'function' + ) +} + +function getToStringTag(value: unknown): string | undefined { + if (typeof value !== 'object' || value === null) return undefined + const tag = (value as any)[Symbol.toStringTag] + return typeof tag === 'string' ? tag : undefined +} diff --git a/packages/angular-store/tests/index.test.ts b/packages/angular-store/tests/index.test.ts index 17c5e46..0f290e8 100644 --- a/packages/angular-store/tests/index.test.ts +++ b/packages/angular-store/tests/index.test.ts @@ -3,6 +3,7 @@ import { Component, effect } from '@angular/core' import { TestBed } from '@angular/core/testing' import { By } from '@angular/platform-browser' import { Store } from '@tanstack/store' +import { Temporal } from 'temporal-polyfill' import { injectStore } from '../src/index' describe('injectStore', () => { @@ -142,4 +143,52 @@ describe('dataType', () => { debugElement.query(By.css('p#displayStoreVal')).nativeElement.textContent, ).toContain(new Date('2025-03-29T21:06:40.401Z')) }) + + test('temporal change trigger re-render', () => { + const store = new Store({ date: Temporal.PlainDate.from('2025-03-29') }) + + @Component({ + template: ` +
+

{{ storeVal().toString() }}

+ +
+ `, + standalone: true, + }) + class MyCmp { + storeVal = injectStore(store, (state) => state.date) + + constructor() { + effect(() => { + console.log(this.storeVal()) + }) + } + + updateDate() { + store.setState((v) => ({ + ...v, + date: Temporal.PlainDate.from('2025-03-30'), + })) + } + } + + const fixture = TestBed.createComponent(MyCmp) + fixture.detectChanges() + + const debugElement = fixture.debugElement + + expect( + debugElement.query(By.css('p#displayStoreVal')).nativeElement.textContent, + ).toContain('2025-03-29') + + debugElement + .query(By.css('button#updateDate')) + .triggerEventHandler('click', null) + + fixture.detectChanges() + expect( + debugElement.query(By.css('p#displayStoreVal')).nativeElement.textContent, + ).toContain('2025-03-30') + }) }) diff --git a/packages/preact-store/src/index.ts b/packages/preact-store/src/index.ts index 7b2c5bc..dea75df 100644 --- a/packages/preact-store/src/index.ts +++ b/packages/preact-store/src/index.ts @@ -162,6 +162,32 @@ export function shallow(objA: T, objB: T) { return true } + /** + * Temporal branding note: + * Temporal types (native or polyfill) define `Symbol.toStringTag` values like + * `"Temporal.PlainDate"` as part of the TC39 Temporal spec, which makes this + * check reliable across realms/polyfills (unlike `instanceof`). + * + * See: + * - https://tc39.es/proposal-temporal/ + * - https://tc39.es/proposal-temporal/docs/plaindate.html + */ + const tagA = getToStringTag(objA) + const tagB = getToStringTag(objB) + const isTemporal = + tagA !== undefined && + tagB !== undefined && + tagA === tagB && + tagA.startsWith('Temporal.') + + if (isTemporal && hasEquals(objA) && hasEquals(objB)) { + try { + return objA.equals(objB) + } catch { + return false + } + } + const keysA = getOwnKeys(objA) if (keysA.length !== getOwnKeys(objB).length) { return false @@ -169,7 +195,7 @@ export function shallow(objA: T, objB: T) { for (const key of keysA) { if ( - !Object.prototype.hasOwnProperty.call(objB, key as string) || + !Object.prototype.hasOwnProperty.call(objB, key) || !Object.is(objA[key as keyof T], objB[key as keyof T]) ) { return false @@ -178,6 +204,23 @@ export function shallow(objA: T, objB: T) { return true } +function hasEquals( + value: TValue, +): value is TValue & { equals: (other: unknown) => boolean } { + return ( + typeof value === 'object' && + value !== null && + 'equals' in (value as object) && + typeof (value as any).equals === 'function' + ) +} + +function getToStringTag(value: unknown): string | undefined { + if (typeof value !== 'object' || value === null) return undefined + const tag = (value as any)[Symbol.toStringTag] + return typeof tag === 'string' ? tag : undefined +} + function getOwnKeys(obj: object): Array { return (Object.keys(obj) as Array).concat( Object.getOwnPropertySymbols(obj), diff --git a/packages/preact-store/tests/index.test.tsx b/packages/preact-store/tests/index.test.tsx index 06315d5..d5e21e7 100644 --- a/packages/preact-store/tests/index.test.tsx +++ b/packages/preact-store/tests/index.test.tsx @@ -3,6 +3,7 @@ import { render, waitFor } from '@testing-library/preact' import { Derived, Store } from '@tanstack/store' import { useState } from 'preact/hooks' import { userEvent } from '@testing-library/user-event' +import { Temporal } from 'temporal-polyfill' import { shallow, useStore } from '../src/index' const user = userEvent.setup() @@ -303,4 +304,10 @@ describe('shallow', () => { const objB = new Date('2025-02-10') expect(shallow(objA, objB)).toBe(true) }) + + test('should return false for temporal objects with different values', () => { + const objA = Temporal.PlainDate.from('2025-02-10') + const objB = Temporal.PlainDate.from('2025-02-11') + expect(shallow(objA, objB)).toBe(false) + }) }) diff --git a/packages/react-store/src/index.ts b/packages/react-store/src/index.ts index 21d3a47..cdb7b5d 100644 --- a/packages/react-store/src/index.ts +++ b/packages/react-store/src/index.ts @@ -74,15 +74,41 @@ export function shallow(objA: T, objB: T) { return true } + /** + * Temporal branding note: + * Temporal types (native or polyfill) define `Symbol.toStringTag` values like + * `"Temporal.PlainDate"` as part of the TC39 Temporal spec, which makes this + * check reliable across realms/polyfills (unlike `instanceof`). + * + * See: + * - https://tc39.es/proposal-temporal/ + * - https://tc39.es/proposal-temporal/docs/plaindate.html + */ + const tagA = getToStringTag(objA) + const tagB = getToStringTag(objB) + const isTemporal = + tagA !== undefined && + tagB !== undefined && + tagA === tagB && + tagA.startsWith('Temporal.') + + if (isTemporal && hasEquals(objA) && hasEquals(objB)) { + try { + return objA.equals(objB) + } catch { + return false + } + } + const keysA = getOwnKeys(objA) if (keysA.length !== getOwnKeys(objB).length) { return false } - for (let i = 0; i < keysA.length; i++) { + for (const key of keysA) { if ( - !Object.prototype.hasOwnProperty.call(objB, keysA[i] as string) || - !Object.is(objA[keysA[i] as keyof T], objB[keysA[i] as keyof T]) + !Object.prototype.hasOwnProperty.call(objB, key) || + !Object.is(objA[key as keyof T], objB[key as keyof T]) ) { return false } @@ -90,6 +116,23 @@ export function shallow(objA: T, objB: T) { return true } +function hasEquals( + value: TValue, +): value is TValue & { equals: (other: unknown) => boolean } { + return ( + typeof value === 'object' && + value !== null && + 'equals' in (value as object) && + typeof (value as any).equals === 'function' + ) +} + +function getToStringTag(value: unknown): string | undefined { + if (typeof value !== 'object' || value === null) return undefined + const tag = (value as any)[Symbol.toStringTag] + return typeof tag === 'string' ? tag : undefined +} + function getOwnKeys(obj: object): Array { return (Object.keys(obj) as Array).concat( Object.getOwnPropertySymbols(obj), diff --git a/packages/react-store/tests/index.test.tsx b/packages/react-store/tests/index.test.tsx index 37d1d37..596a89e 100644 --- a/packages/react-store/tests/index.test.tsx +++ b/packages/react-store/tests/index.test.tsx @@ -3,6 +3,8 @@ import { render, waitFor } from '@testing-library/react' import { Derived, Store } from '@tanstack/store' import { useState } from 'react' import { userEvent } from '@testing-library/user-event' +import { Temporal as JsTemporal } from '@js-temporal/polyfill' +import { Temporal } from 'temporal-polyfill' import { shallow, useStore } from '../src/index' const user = userEvent.setup() @@ -302,4 +304,16 @@ describe('shallow', () => { const objB = new Date('2025-02-10') expect(shallow(objA, objB)).toBe(true) }) + + test('should return false for temporal objects with different values', () => { + const objA = Temporal.PlainDate.from('2025-02-10') + const objB = Temporal.PlainDate.from('2025-02-11') + expect(shallow(objA, objB)).toBe(false) + }) + + test('supports Temporal from @js-temporal/polyfill', () => { + const objA = JsTemporal.PlainDate.from('2025-02-10') + const objB = JsTemporal.PlainDate.from('2025-02-10') + expect(shallow(objA, objB)).toBe(true) + }) }) diff --git a/packages/solid-store/src/index.tsx b/packages/solid-store/src/index.tsx index 104653b..0cd26f7 100644 --- a/packages/solid-store/src/index.tsx +++ b/packages/solid-store/src/index.tsx @@ -81,6 +81,32 @@ export function shallow(objA: T, objB: T) { return true } + /** + * Temporal branding note: + * Temporal types (native or polyfill) define `Symbol.toStringTag` values like + * `"Temporal.PlainDate"` as part of the TC39 Temporal spec, which makes this + * check reliable across realms/polyfills (unlike `instanceof`). + * + * See: + * - https://tc39.es/proposal-temporal/ + * - https://tc39.es/proposal-temporal/docs/plaindate.html + */ + const tagA = getToStringTag(objA) + const tagB = getToStringTag(objB) + const isTemporal = + tagA !== undefined && + tagB !== undefined && + tagA === tagB && + tagA.startsWith('Temporal.') + + if (isTemporal && hasEquals(objA) && hasEquals(objB)) { + try { + return objA.equals(objB) + } catch { + return false + } + } + const keysA = Object.keys(objA) if (keysA.length !== Object.keys(objB).length) { return false @@ -96,3 +122,20 @@ export function shallow(objA: T, objB: T) { } return true } + +function hasEquals( + value: TValue, +): value is TValue & { equals: (other: unknown) => boolean } { + return ( + typeof value === 'object' && + value !== null && + 'equals' in (value as object) && + typeof (value as any).equals === 'function' + ) +} + +function getToStringTag(value: unknown): string | undefined { + if (typeof value !== 'object' || value === null) return undefined + const tag = (value as any)[Symbol.toStringTag] + return typeof tag === 'string' ? tag : undefined +} diff --git a/packages/solid-store/tests/index.test.tsx b/packages/solid-store/tests/index.test.tsx index 2efa725..a078fe4 100644 --- a/packages/solid-store/tests/index.test.tsx +++ b/packages/solid-store/tests/index.test.tsx @@ -1,7 +1,8 @@ -import { describe, expect, it } from 'vitest' +import { describe, expect, it, test } from 'vitest' import { render, renderHook } from '@solidjs/testing-library' import { Store } from '@tanstack/store' -import { useStore } from '../src/index' +import { Temporal } from 'temporal-polyfill' +import { shallow, useStore } from '../src/index' describe('useStore', () => { it.todo('allows us to select state using a selector', () => { @@ -53,3 +54,11 @@ describe('useStore', () => { expect(result()).toStrictEqual(new Date('2025-03-29T21:06:40.401Z')) }) }) + +describe('shallow', () => { + test('should return false for temporal objects with different values', () => { + const objA = Temporal.PlainDate.from('2025-02-10') + const objB = Temporal.PlainDate.from('2025-02-11') + expect(shallow(objA, objB)).toBe(false) + }) +}) diff --git a/packages/svelte-store/src/index.svelte.ts b/packages/svelte-store/src/index.svelte.ts index 636dd43..c6318d2 100644 --- a/packages/svelte-store/src/index.svelte.ts +++ b/packages/svelte-store/src/index.svelte.ts @@ -83,18 +83,61 @@ export function shallow(objA: T, objB: T) { return true } + /** + * Temporal branding note: + * Temporal types (native or polyfill) define `Symbol.toStringTag` values like + * `"Temporal.PlainDate"` as part of the TC39 Temporal spec, which makes this + * check reliable across realms/polyfills (unlike `instanceof`). + * + * See: + * - https://tc39.es/proposal-temporal/ + * - https://tc39.es/proposal-temporal/docs/plaindate.html + */ + const tagA = getToStringTag(objA) + const tagB = getToStringTag(objB) + const isTemporal = + tagA !== undefined && + tagB !== undefined && + tagA === tagB && + tagA.startsWith('Temporal.') + + if (isTemporal && hasEquals(objA) && hasEquals(objB)) { + try { + return objA.equals(objB) + } catch { + return false + } + } + const keysA = Object.keys(objA) if (keysA.length !== Object.keys(objB).length) { return false } - for (let i = 0; i < keysA.length; i++) { + for (const key of keysA) { if ( - !Object.prototype.hasOwnProperty.call(objB, keysA[i] as string) || - !Object.is(objA[keysA[i] as keyof T], objB[keysA[i] as keyof T]) + !Object.prototype.hasOwnProperty.call(objB, key) || + !Object.is(objA[key as keyof T], objB[key as keyof T]) ) { return false } } return true } + +function hasEquals( + value: TValue, +): value is TValue & { equals: (other: unknown) => boolean } { + return ( + typeof value === 'object' && + value !== null && + 'equals' in (value as object) && + typeof (value as any).equals === 'function' + ) +} + +function getToStringTag(value: unknown): string | undefined { + if (typeof value !== 'object' || value === null) return undefined + const tag = (value as any)[Symbol.toStringTag] + return typeof tag === 'string' ? tag : undefined +} diff --git a/packages/svelte-store/tests/index.test.ts b/packages/svelte-store/tests/index.test.ts index 24f7a3d..ab43595 100644 --- a/packages/svelte-store/tests/index.test.ts +++ b/packages/svelte-store/tests/index.test.ts @@ -1,6 +1,7 @@ import { describe, expect, it, test } from 'vitest' import { render, waitFor } from '@testing-library/svelte' import { userEvent } from '@testing-library/user-event' +import { Temporal } from 'temporal-polyfill' import { shallow } from '../src/index.svelte.js' import TestBaseStore from './BaseStore.test.svelte' import TestRerender from './Render.test.svelte' @@ -91,4 +92,10 @@ describe('shallow', () => { const objB = new Date('2025-02-10') expect(shallow(objA, objB)).toBe(true) }) + + test('should return false for temporal objects with different values', () => { + const objA = Temporal.PlainDate.from('2025-02-10') + const objB = Temporal.PlainDate.from('2025-02-11') + expect(shallow(objA, objB)).toBe(false) + }) }) diff --git a/packages/vue-store/src/index.ts b/packages/vue-store/src/index.ts index 6b2ebd0..9910cd4 100644 --- a/packages/vue-store/src/index.ts +++ b/packages/vue-store/src/index.ts @@ -87,6 +87,32 @@ export function shallow(objA: T, objB: T) { return true } + /** + * Temporal branding note: + * Temporal types (native or polyfill) define `Symbol.toStringTag` values like + * `"Temporal.PlainDate"` as part of the TC39 Temporal spec, which makes this + * check reliable across realms/polyfills (unlike `instanceof`). + * + * See: + * - https://tc39.es/proposal-temporal/ + * - https://tc39.es/proposal-temporal/docs/plaindate.html + */ + const tagA = getToStringTag(objA) + const tagB = getToStringTag(objB) + const isTemporal = + tagA !== undefined && + tagB !== undefined && + tagA === tagB && + tagA.startsWith('Temporal.') + + if (isTemporal && hasEquals(objA) && hasEquals(objB)) { + try { + return objA.equals(objB) + } catch { + return false + } + } + const keysA = Object.keys(objA) if (keysA.length !== Object.keys(objB).length) { return false @@ -102,3 +128,20 @@ export function shallow(objA: T, objB: T) { } return true } + +function hasEquals( + value: TValue, +): value is TValue & { equals: (other: unknown) => boolean } { + return ( + typeof value === 'object' && + value !== null && + 'equals' in (value as object) && + typeof (value as any).equals === 'function' + ) +} + +function getToStringTag(value: unknown): string | undefined { + if (typeof value !== 'object' || value === null) return undefined + const tag = (value as any)[Symbol.toStringTag] + return typeof tag === 'string' ? tag : undefined +} diff --git a/packages/vue-store/tests/index.test.tsx b/packages/vue-store/tests/index.test.tsx index ebdb3f9..832784f 100644 --- a/packages/vue-store/tests/index.test.tsx +++ b/packages/vue-store/tests/index.test.tsx @@ -4,6 +4,7 @@ import { defineComponent, h } from 'vue-demi' import { render, waitFor } from '@testing-library/vue' import { Store } from '@tanstack/store' import { userEvent } from '@testing-library/user-event' +import { Temporal } from 'temporal-polyfill' import { shallow, useStore } from '../src/index' const user = userEvent.setup() @@ -168,4 +169,10 @@ describe('shallow', () => { const objB = new Date('2025-02-10') expect(shallow(objA, objB)).toBe(true) }) + + test('should return false for temporal objects with different values', () => { + const objA = Temporal.PlainDate.from('2025-02-10') + const objB = Temporal.PlainDate.from('2025-02-11') + expect(shallow(objA, objB)).toBe(false) + }) }) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9fe910c..5fe9b3e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -14,6 +14,9 @@ importers: '@eslint-react/eslint-plugin': specifier: ^1.53.1 version: 1.53.1(eslint@9.39.2(jiti@2.6.1))(ts-api-utils@2.1.0(typescript@5.6.3))(typescript@5.6.3) + '@js-temporal/polyfill': + specifier: ^0.5.1 + version: 0.5.1 '@svitejs/changesets-changelog-github-compact': specifier: ^1.2.0 version: 1.2.0(encoding@0.1.13) @@ -71,9 +74,15 @@ importers: sherif: specifier: ^1.9.0 version: 1.9.0 + temporal-polyfill: + specifier: ^0.3.0 + version: 0.3.0 tinyglobby: specifier: ^0.2.15 version: 0.2.15 + tsx: + specifier: ^4.21.0 + version: 4.21.0 typescript: specifier: 5.6.3 version: 5.6.3 @@ -2074,6 +2083,10 @@ packages: '@jridgewell/trace-mapping@0.3.31': resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + '@js-temporal/polyfill@0.5.1': + resolution: {integrity: sha512-hloP58zRVCRSpgDxmqCWJNlizAlUgJFqG2ypq79DCvyv9tHjRYMDOcPFjzfl/A1/YxDvRCZz8wvZvmapQnKwFQ==} + engines: {node: '>=12'} + '@jsonjoy.com/base64@1.1.2': resolution: {integrity: sha512-q6XAnWQDIMA3+FTiOYajoYqySkO+JSat0ytXGSuRdq9uXE7o92gzuQwQM14xaCRlBLGq3v5miDGC4vkVTn54xA==} engines: {node: '>=10.0'} @@ -5450,6 +5463,9 @@ packages: resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} hasBin: true + jsbi@4.3.2: + resolution: {integrity: sha512-9fqMSQbhJykSeii05nxKl4m6Eqn2P6rOlYiS+C5Dr/HPIU/7yZxu5qzbs40tgaFORiw2Amd0mirjxatXYMkIew==} + jsdom@25.0.1: resolution: {integrity: sha512-8i7LzZj7BF8uplX+ZyOlIz86V6TAsSs+np6m1kpW9u0JWi4z/1t+FzcK1aek+ybTnAC4KhBL4uXCNT0wcUIeCw==} engines: {node: '>=18'} @@ -7183,10 +7199,18 @@ packages: tar@6.2.1: resolution: {integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==} engines: {node: '>=10'} + deprecated: Old versions of tar are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exhorbitant rates) by contacting i@izs.me tar@7.5.2: resolution: {integrity: sha512-7NyxrTE4Anh8km8iEy7o0QYPs+0JKBTj5ZaqHg6B39erLg0qYXN3BijtShwbsNSvQ+LN75+KV+C4QR/f6Gwnpg==} engines: {node: '>=18'} + deprecated: Old versions of tar are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exhorbitant rates) by contacting i@izs.me + + temporal-polyfill@0.3.0: + resolution: {integrity: sha512-qNsTkX9K8hi+FHDfHmf22e/OGuXmfBm9RqNismxBrnSmZVJKegQ+HYYXT+R7Ha8F/YSm2Y34vmzD4cxMu2u95g==} + + temporal-spec@0.3.0: + resolution: {integrity: sha512-n+noVpIqz4hYgFSMOSiINNOUOMFtV5cZQNCmmszA6GiVFVRt3G7AqVyhXjhCSmowvQn+NsGn+jMDMKJYHd3bSQ==} term-size@2.2.1: resolution: {integrity: sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==} @@ -8000,9 +8024,9 @@ snapshots: tree-kill: 1.2.2 tslib: 2.8.1 typescript: 5.6.3 - webpack: 5.98.0(esbuild@0.25.4) + webpack: 5.98.0 webpack-dev-middleware: 7.4.2(webpack@5.98.0(esbuild@0.25.4)) - webpack-dev-server: 5.2.2(webpack@5.98.0(esbuild@0.25.4)) + webpack-dev-server: 5.2.2(webpack@5.98.0) webpack-merge: 6.0.1 webpack-subresource-integrity: 5.1.0(webpack@5.98.0(esbuild@0.25.4)) optionalDependencies: @@ -8164,7 +8188,7 @@ snapshots: '@babel/helper-split-export-declaration': 7.24.7 '@babel/plugin-syntax-import-attributes': 7.26.0(@babel/core@7.26.10) '@inquirer/confirm': 5.1.6(@types/node@24.9.2) - '@vitejs/plugin-basic-ssl': 1.2.0(vite@6.4.1(@types/node@24.9.2)(jiti@2.6.1)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.21.0)(yaml@2.8.1)) + '@vitejs/plugin-basic-ssl': 1.2.0(vite@6.4.1(@types/node@24.9.2)(jiti@2.6.1)(less@4.4.2)(sass@1.93.3)(terser@5.39.0)(tsx@4.21.0)(yaml@2.8.1)) beasties: 0.3.2 browserslist: 4.27.0 esbuild: 0.25.4 @@ -9903,6 +9927,10 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.5 + '@js-temporal/polyfill@0.5.1': + dependencies: + jsbi: 4.3.2 + '@jsonjoy.com/base64@1.1.2(tslib@2.8.1)': dependencies: tslib: 2.8.1 @@ -11176,7 +11204,6 @@ snapshots: '@vitejs/plugin-basic-ssl@1.2.0(vite@6.4.1(@types/node@24.9.2)(jiti@2.6.1)(less@4.4.2)(sass@1.93.3)(terser@5.39.0)(tsx@4.21.0)(yaml@2.8.1))': dependencies: vite: 6.4.1(@types/node@24.9.2)(jiti@2.6.1)(less@4.4.2)(sass@1.93.3)(terser@5.39.0)(tsx@4.21.0)(yaml@2.8.1) - optional: true '@vitejs/plugin-react@4.7.0(vite@6.4.1(@types/node@24.9.2)(jiti@2.6.1)(less@4.4.2)(sass@1.93.3)(terser@5.39.0)(tsx@4.21.0)(yaml@2.8.1))': dependencies: @@ -13684,6 +13711,8 @@ snapshots: dependencies: argparse: 2.0.1 + jsbi@4.3.2: {} + jsdom@25.0.1: dependencies: cssstyle: 4.6.0 @@ -15685,6 +15714,12 @@ snapshots: minizlib: 3.1.0 yallist: 5.0.0 + temporal-polyfill@0.3.0: + dependencies: + temporal-spec: 0.3.0 + + temporal-spec@0.3.0: {} + term-size@2.2.1: {} terser-webpack-plugin@5.3.14(esbuild@0.25.4)(webpack@5.98.0(esbuild@0.25.4)): @@ -15698,6 +15733,15 @@ snapshots: optionalDependencies: esbuild: 0.25.4 + terser-webpack-plugin@5.3.14(webpack@5.98.0(esbuild@0.25.4)): + dependencies: + '@jridgewell/trace-mapping': 0.3.31 + jest-worker: 27.5.1 + schema-utils: 4.3.3 + serialize-javascript: 6.0.2 + terser: 5.39.0 + webpack: 5.98.0 + terser@5.39.0: dependencies: '@jridgewell/source-map': 0.3.11 @@ -16273,6 +16317,17 @@ snapshots: optionalDependencies: webpack: 5.98.0(esbuild@0.25.4) + webpack-dev-middleware@7.4.2(webpack@5.98.0): + dependencies: + colorette: 2.0.20 + memfs: 4.50.0 + mime-types: 2.1.35 + on-finished: 2.4.1 + range-parser: 1.2.1 + schema-utils: 4.3.3 + optionalDependencies: + webpack: 5.98.0 + webpack-dev-server@5.2.2(webpack@5.98.0(esbuild@0.25.4)): dependencies: '@types/bonjour': 3.5.13 @@ -16311,6 +16366,44 @@ snapshots: - supports-color - utf-8-validate + webpack-dev-server@5.2.2(webpack@5.98.0): + dependencies: + '@types/bonjour': 3.5.13 + '@types/connect-history-api-fallback': 1.5.4 + '@types/express': 4.17.25 + '@types/express-serve-static-core': 4.19.7 + '@types/serve-index': 1.9.4 + '@types/serve-static': 1.15.10 + '@types/sockjs': 0.3.36 + '@types/ws': 8.18.1 + ansi-html-community: 0.0.8 + bonjour-service: 1.3.0 + chokidar: 3.6.0 + colorette: 2.0.20 + compression: 1.8.1 + connect-history-api-fallback: 2.0.0 + express: 4.21.2 + graceful-fs: 4.2.11 + http-proxy-middleware: 2.0.9(@types/express@4.17.25) + ipaddr.js: 2.2.0 + launch-editor: 2.12.0 + open: 10.1.0 + p-retry: 6.2.1 + schema-utils: 4.3.3 + selfsigned: 2.4.1 + serve-index: 1.9.1 + sockjs: 0.3.24 + spdy: 4.0.2 + webpack-dev-middleware: 7.4.2(webpack@5.98.0) + ws: 8.18.3 + optionalDependencies: + webpack: 5.98.0 + transitivePeerDependencies: + - bufferutil + - debug + - supports-color + - utf-8-validate + webpack-merge@6.0.1: dependencies: clone-deep: 4.0.1 @@ -16327,6 +16420,36 @@ snapshots: webpack-virtual-modules@0.6.2: optional: true + webpack@5.98.0: + dependencies: + '@types/eslint-scope': 3.7.7 + '@types/estree': 1.0.8 + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/wasm-edit': 1.14.1 + '@webassemblyjs/wasm-parser': 1.14.1 + acorn: 8.15.0 + browserslist: 4.27.0 + chrome-trace-event: 1.0.4 + enhanced-resolve: 5.18.3 + es-module-lexer: 1.7.0 + eslint-scope: 5.1.1 + events: 3.3.0 + glob-to-regexp: 0.4.1 + graceful-fs: 4.2.11 + json-parse-even-better-errors: 2.3.1 + loader-runner: 4.3.1 + mime-types: 2.1.35 + neo-async: 2.6.2 + schema-utils: 4.3.3 + tapable: 2.3.0 + terser-webpack-plugin: 5.3.14(webpack@5.98.0(esbuild@0.25.4)) + watchpack: 2.4.4 + webpack-sources: 3.3.3 + transitivePeerDependencies: + - '@swc/core' + - esbuild + - uglify-js + webpack@5.98.0(esbuild@0.25.4): dependencies: '@types/eslint-scope': 3.7.7