@happyvertical/smrt-svelte 0.42.6 → 0.43.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.
- package/README.md +20 -0
- package/dist/Provider.svelte +49 -0
- package/dist/Provider.svelte.d.ts +15 -0
- package/dist/Provider.svelte.d.ts.map +1 -1
- package/dist/__tests__/data-surface-bridge.test.js +351 -0
- package/dist/components/forms/AddressInput.svelte +11 -0
- package/dist/components/forms/AddressInput.svelte.d.ts.map +1 -1
- package/dist/components/forms/CheckboxInput.svelte +3 -1
- package/dist/components/forms/CheckboxInput.svelte.d.ts.map +1 -1
- package/dist/components/forms/DateRangeInput.svelte +3 -0
- package/dist/components/forms/DateRangeInput.svelte.d.ts.map +1 -1
- package/dist/components/forms/DateTimeInput.svelte +2 -0
- package/dist/components/forms/DateTimeInput.svelte.d.ts.map +1 -1
- package/dist/components/forms/Form.svelte +172 -6
- package/dist/components/forms/Form.svelte.d.ts +8 -1
- package/dist/components/forms/Form.svelte.d.ts.map +1 -1
- package/dist/components/forms/MeasurementInput.svelte +3 -0
- package/dist/components/forms/MeasurementInput.svelte.d.ts.map +1 -1
- package/dist/components/forms/MoneyInput.svelte +3 -0
- package/dist/components/forms/MoneyInput.svelte.d.ts.map +1 -1
- package/dist/components/forms/NumberInput.svelte +3 -0
- package/dist/components/forms/NumberInput.svelte.d.ts.map +1 -1
- package/dist/components/forms/PhoneInput.svelte +2 -0
- package/dist/components/forms/PhoneInput.svelte.d.ts.map +1 -1
- package/dist/components/forms/SelectInput.svelte +7 -1
- package/dist/components/forms/SelectInput.svelte.d.ts.map +1 -1
- package/dist/components/forms/TextInput.svelte +5 -1
- package/dist/components/forms/TextInput.svelte.d.ts.map +1 -1
- package/dist/components/forms/TextareaInput.svelte +3 -1
- package/dist/components/forms/TextareaInput.svelte.d.ts.map +1 -1
- package/dist/components/forms/__tests__/Form.webmcp.test.js +216 -0
- package/dist/components/forms/__tests__/form-with-fields.fixture.svelte +25 -3
- package/dist/components/forms/__tests__/form-with-fields.fixture.svelte.d.ts +5 -0
- package/dist/components/forms/__tests__/form-with-fields.fixture.svelte.d.ts.map +1 -1
- package/dist/components/forms/__tests__/form-with-structured-fields.fixture.svelte +40 -0
- package/dist/components/forms/__tests__/form-with-structured-fields.fixture.svelte.d.ts +10 -0
- package/dist/components/forms/__tests__/form-with-structured-fields.fixture.svelte.d.ts.map +1 -0
- package/dist/data-surface.d.ts +104 -0
- package/dist/data-surface.d.ts.map +1 -0
- package/dist/data-surface.js +348 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -0
- package/dist/state/form-context.d.ts +2 -0
- package/dist/state/form-context.d.ts.map +1 -1
- package/dist/web/__tests__/webmcp-harness.svelte +14 -0
- package/dist/web/__tests__/webmcp-harness.svelte.d.ts +7 -0
- package/dist/web/__tests__/webmcp-harness.svelte.d.ts.map +1 -0
- package/dist/web/__tests__/webmcp.test.js +39 -0
- package/dist/web/webmcp.d.ts +21 -0
- package/dist/web/webmcp.svelte.d.ts +28 -0
- package/dist/web/webmcp.svelte.d.ts.map +1 -0
- package/dist/web/webmcp.svelte.js +27 -0
- package/package.json +17 -5
package/README.md
CHANGED
|
@@ -38,6 +38,26 @@ Svelte 5 component library for the s-m-r-t framework. Provides UI components, br
|
|
|
38
38
|
pnpm add @happyvertical/smrt-svelte
|
|
39
39
|
```
|
|
40
40
|
|
|
41
|
+
## Data-surface browser bridge security
|
|
42
|
+
|
|
43
|
+
The browser bridge is a transport adapter, not an authentication system.
|
|
44
|
+
Configure it only with a session/source binding established by the server and
|
|
45
|
+
use a transport that supplies verified peer metadata. It accepts commands only
|
|
46
|
+
from the configured server peer and emits acknowledgements/events only on the
|
|
47
|
+
bound route; wire `sessionId` and `source` fields must never be treated as
|
|
48
|
+
proof of identity.
|
|
49
|
+
|
|
50
|
+
The adapter canonicalizes requests and applies the shared identifier limit
|
|
51
|
+
from `@happyvertical/smrt-ui/data-surface` along with bounded envelopes before
|
|
52
|
+
calling the registry. The registry remains the authority for command
|
|
53
|
+
authorization and execution. Command IDs are idempotent while their bounded
|
|
54
|
+
replay entries are retained; concurrent same-signature requests coalesce, a
|
|
55
|
+
conflicting signature is rejected, and replay-capacity exhaustion is reported
|
|
56
|
+
explicitly. Malformed requests and unauthenticated peers are ignored before an
|
|
57
|
+
acknowledgement; valid requests that expire or encounter disconnect and
|
|
58
|
+
transport failures produce bounded protocol outcomes without exposing registry
|
|
59
|
+
state.
|
|
60
|
+
|
|
41
61
|
## Usage
|
|
42
62
|
|
|
43
63
|
### Provider Setup
|
package/dist/Provider.svelte
CHANGED
|
@@ -4,6 +4,11 @@ import {
|
|
|
4
4
|
type I18nSnapshot,
|
|
5
5
|
setI18nContext,
|
|
6
6
|
} from '@happyvertical/smrt-ui/i18n';
|
|
7
|
+
import {
|
|
8
|
+
type RegisterWebMcpToolsOptions,
|
|
9
|
+
type SmrtWebClient,
|
|
10
|
+
type SmrtWebCollectionDefinition,
|
|
11
|
+
} from '@happyvertical/smrt-web';
|
|
7
12
|
import type { Snippet } from 'svelte';
|
|
8
13
|
import { onDestroy, untrack } from 'svelte';
|
|
9
14
|
import { logger } from './internal/logger.js';
|
|
@@ -78,12 +83,27 @@ interface Props {
|
|
|
78
83
|
* English-default-only rendering.
|
|
79
84
|
*/
|
|
80
85
|
i18n?: I18nSnapshot;
|
|
86
|
+
/**
|
|
87
|
+
* Opt in to the generated collection tools for this browser surface.
|
|
88
|
+
* WebMCP is feature-detected by smrt-web, so this is safe during SSR and on
|
|
89
|
+
* browsers that do not expose `document.modelContext`.
|
|
90
|
+
*/
|
|
91
|
+
webmcp?: boolean | WebMcpProviderConfig;
|
|
81
92
|
/**
|
|
82
93
|
* Children to render
|
|
83
94
|
*/
|
|
84
95
|
children: Snippet;
|
|
85
96
|
}
|
|
86
97
|
|
|
98
|
+
export interface WebMcpProviderConfig {
|
|
99
|
+
definitions?: SmrtWebCollectionDefinition[];
|
|
100
|
+
client?: SmrtWebClient;
|
|
101
|
+
basePath?: string;
|
|
102
|
+
fetchFn?: typeof fetch;
|
|
103
|
+
scope?: string;
|
|
104
|
+
filter?: RegisterWebMcpToolsOptions['filter'];
|
|
105
|
+
}
|
|
106
|
+
|
|
87
107
|
const {
|
|
88
108
|
mode,
|
|
89
109
|
autoEnableSmrt = true,
|
|
@@ -95,6 +115,7 @@ const {
|
|
|
95
115
|
onModeChange,
|
|
96
116
|
onAILoadingChange,
|
|
97
117
|
i18n,
|
|
118
|
+
webmcp,
|
|
98
119
|
children,
|
|
99
120
|
}: Props = $props();
|
|
100
121
|
|
|
@@ -128,6 +149,34 @@ $effect(() => {
|
|
|
128
149
|
});
|
|
129
150
|
});
|
|
130
151
|
|
|
152
|
+
// Keep generated data-plane tools scoped to this Provider. The registrar
|
|
153
|
+
// feature-detects WebMCP itself; effects do not run during SSR.
|
|
154
|
+
$effect(() => {
|
|
155
|
+
if (typeof window === 'undefined' || !webmcp) return;
|
|
156
|
+
|
|
157
|
+
const config = typeof webmcp === 'object' ? webmcp : {};
|
|
158
|
+
let cancelled = false;
|
|
159
|
+
let dispose = () => {};
|
|
160
|
+
|
|
161
|
+
// Keep the data-plane engine out of applications that do not opt in. The
|
|
162
|
+
// dynamic import also means SSR never evaluates browser-only engine code.
|
|
163
|
+
void import('@happyvertical/smrt-web').then(({ registerWebMcpTools }) => {
|
|
164
|
+
if (cancelled) return;
|
|
165
|
+
dispose = registerWebMcpTools(config.definitions ?? [], {
|
|
166
|
+
...(config.client ? { client: config.client } : {}),
|
|
167
|
+
...(config.basePath ? { basePath: config.basePath } : {}),
|
|
168
|
+
...(config.fetchFn ? { fetchFn: config.fetchFn } : {}),
|
|
169
|
+
...(config.scope ? { scope: config.scope } : {}),
|
|
170
|
+
...(config.filter ? { filter: config.filter } : {}),
|
|
171
|
+
});
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
return () => {
|
|
175
|
+
cancelled = true;
|
|
176
|
+
dispose();
|
|
177
|
+
};
|
|
178
|
+
});
|
|
179
|
+
|
|
131
180
|
$effect(() => {
|
|
132
181
|
if (mode) {
|
|
133
182
|
appState.setMode(mode, 'explicit');
|
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
import { type I18nSnapshot } from '@happyvertical/smrt-ui/i18n';
|
|
2
|
+
import { type RegisterWebMcpToolsOptions, type SmrtWebClient, type SmrtWebCollectionDefinition } from '@happyvertical/smrt-web';
|
|
2
3
|
import type { Snippet } from 'svelte';
|
|
3
4
|
import type { AIConfig, AILoadingState, AppMode, SocketConfig, User } from './state/app-state.js';
|
|
5
|
+
export interface WebMcpProviderConfig {
|
|
6
|
+
definitions?: SmrtWebCollectionDefinition[];
|
|
7
|
+
client?: SmrtWebClient;
|
|
8
|
+
basePath?: string;
|
|
9
|
+
fetchFn?: typeof fetch;
|
|
10
|
+
scope?: string;
|
|
11
|
+
filter?: RegisterWebMcpToolsOptions['filter'];
|
|
12
|
+
}
|
|
4
13
|
interface Props {
|
|
5
14
|
/**
|
|
6
15
|
* Initial mode: 'default' | 'smrt'
|
|
@@ -62,6 +71,12 @@ interface Props {
|
|
|
62
71
|
* English-default-only rendering.
|
|
63
72
|
*/
|
|
64
73
|
i18n?: I18nSnapshot;
|
|
74
|
+
/**
|
|
75
|
+
* Opt in to the generated collection tools for this browser surface.
|
|
76
|
+
* WebMCP is feature-detected by smrt-web, so this is safe during SSR and on
|
|
77
|
+
* browsers that do not expose `document.modelContext`.
|
|
78
|
+
*/
|
|
79
|
+
webmcp?: boolean | WebMcpProviderConfig;
|
|
65
80
|
/**
|
|
66
81
|
* Children to render
|
|
67
82
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Provider.svelte.d.ts","sourceRoot":"","sources":["../src/Provider.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,EAEL,KAAK,YAAY,EAElB,MAAM,6BAA6B,CAAC;AACrC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAGtC,OAAO,KAAK,EACV,QAAQ,EACR,cAAc,EACd,OAAO,EACP,YAAY,EACZ,IAAI,EACL,MAAM,sBAAsB,CAAC;AAK9B,UAAU,KAAK;IACb;;;OAGG;IACH,IAAI,CAAC,EAAE,OAAO,CAAC;IACf;;;OAGG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB;;;OAGG;IACH,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IACnB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB;;;OAGG;IACH,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB;;;;;;;;;;;;;;;OAeG;IACH,EAAE,CAAC,EAAE,QAAQ,CAAC;IACd;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB;;OAEG;IACH,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACvC;;OAEG;IACH,iBAAiB,CAAC,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAC;IACpD;;;;;OAKG;IACH,IAAI,CAAC,EAAE,YAAY,CAAC;IACpB;;OAEG;IACH,QAAQ,EAAE,OAAO,CAAC;CACnB;
|
|
1
|
+
{"version":3,"file":"Provider.svelte.d.ts","sourceRoot":"","sources":["../src/Provider.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,EAEL,KAAK,YAAY,EAElB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EACL,KAAK,0BAA0B,EAC/B,KAAK,aAAa,EAClB,KAAK,2BAA2B,EACjC,MAAM,yBAAyB,CAAC;AACjC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAGtC,OAAO,KAAK,EACV,QAAQ,EACR,cAAc,EACd,OAAO,EACP,YAAY,EACZ,IAAI,EACL,MAAM,sBAAsB,CAAC;AAK9B,MAAM,WAAW,oBAAoB;IACnC,WAAW,CAAC,EAAE,2BAA2B,EAAE,CAAC;IAC5C,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,KAAK,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,0BAA0B,CAAC,QAAQ,CAAC,CAAC;CAC/C;AAED,UAAU,KAAK;IACb;;;OAGG;IACH,IAAI,CAAC,EAAE,OAAO,CAAC;IACf;;;OAGG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB;;;OAGG;IACH,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IACnB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB;;;OAGG;IACH,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB;;;;;;;;;;;;;;;OAeG;IACH,EAAE,CAAC,EAAE,QAAQ,CAAC;IACd;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB;;OAEG;IACH,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACvC;;OAEG;IACH,iBAAiB,CAAC,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAC;IACpD;;;;;OAKG;IACH,IAAI,CAAC,EAAE,YAAY,CAAC;IACpB;;;;OAIG;IACH,MAAM,CAAC,EAAE,OAAO,GAAG,oBAAoB,CAAC;IACxC;;OAEG;IACH,QAAQ,EAAE,OAAO,CAAC;CACnB;AA4KD,QAAA,MAAM,QAAQ,2CAAwC,CAAC;AACvD,KAAK,QAAQ,GAAG,UAAU,CAAC,OAAO,QAAQ,CAAC,CAAC;AAC5C,eAAe,QAAQ,CAAC"}
|
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
import { createDataSurfaceRegistry, } from '@happyvertical/smrt-ui/data';
|
|
2
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
3
|
+
import { createDataSurfaceBrowserBridge, DATA_SURFACE_IDENTIFIER_MAX_LENGTH, } from '../data-surface.js';
|
|
4
|
+
const identity = { surfaceId: 'orders', kind: 'table' };
|
|
5
|
+
const descriptor = {
|
|
6
|
+
version: 1,
|
|
7
|
+
identity,
|
|
8
|
+
schemaVersion: 1,
|
|
9
|
+
label: 'Orders',
|
|
10
|
+
rowKey: 'id',
|
|
11
|
+
columns: [{ id: 'id', label: 'ID', capabilities: ['read'] }],
|
|
12
|
+
query: { modes: ['rows'], projectableColumnIds: ['id'] },
|
|
13
|
+
controls: [{ id: 'refresh', label: 'Refresh' }],
|
|
14
|
+
actions: [],
|
|
15
|
+
limits: { maxQueryRows: 10, maxQueryBytes: 1000, maxSelectionSize: 10 },
|
|
16
|
+
};
|
|
17
|
+
function request(overrides = {}) {
|
|
18
|
+
return {
|
|
19
|
+
type: 'data-surface.command',
|
|
20
|
+
version: 1,
|
|
21
|
+
commandId: 'command-1',
|
|
22
|
+
sessionId: 'session-1',
|
|
23
|
+
source: 'server-1',
|
|
24
|
+
expiresAt: 10_000,
|
|
25
|
+
identity,
|
|
26
|
+
expectedRevision: 1,
|
|
27
|
+
controlId: 'refresh',
|
|
28
|
+
...overrides,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
function transport() {
|
|
32
|
+
const messages = [];
|
|
33
|
+
const listeners = new Set();
|
|
34
|
+
return {
|
|
35
|
+
messages,
|
|
36
|
+
send: vi.fn((message) => {
|
|
37
|
+
messages.push(message);
|
|
38
|
+
}),
|
|
39
|
+
subscribe(listener) {
|
|
40
|
+
listeners.add(listener);
|
|
41
|
+
return () => listeners.delete(listener);
|
|
42
|
+
},
|
|
43
|
+
receive(message, peer = {
|
|
44
|
+
sessionId: 'session-1',
|
|
45
|
+
source: 'server-1',
|
|
46
|
+
}) {
|
|
47
|
+
for (const listener of listeners)
|
|
48
|
+
listener(message, peer);
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
function fixture() {
|
|
53
|
+
let revision = 1;
|
|
54
|
+
const execute = vi.fn(() => {
|
|
55
|
+
revision += 1;
|
|
56
|
+
});
|
|
57
|
+
const registry = createDataSurfaceRegistry();
|
|
58
|
+
registry.register({
|
|
59
|
+
descriptor,
|
|
60
|
+
getSnapshot: () => ({ revision, state: { refreshed: revision > 1 } }),
|
|
61
|
+
execute,
|
|
62
|
+
});
|
|
63
|
+
return { registry, execute };
|
|
64
|
+
}
|
|
65
|
+
const drain = () => new Promise((resolve) => setTimeout(resolve, 0));
|
|
66
|
+
describe('data-surface browser bridge', () => {
|
|
67
|
+
it('requires the bound session/source and acknowledges a successful command', async () => {
|
|
68
|
+
const { registry, execute } = fixture();
|
|
69
|
+
const link = transport();
|
|
70
|
+
createDataSurfaceBrowserBridge({
|
|
71
|
+
registry,
|
|
72
|
+
transport: link,
|
|
73
|
+
sessionId: 'session-1',
|
|
74
|
+
source: 'browser-1',
|
|
75
|
+
peerSource: 'server-1',
|
|
76
|
+
now: () => 1_000,
|
|
77
|
+
});
|
|
78
|
+
await link.receive(request({ expiresAt: 2_000 }));
|
|
79
|
+
await drain();
|
|
80
|
+
expect(execute).toHaveBeenCalledTimes(1);
|
|
81
|
+
expect(link.messages.at(-1)).toMatchObject({
|
|
82
|
+
type: 'data-surface.ack',
|
|
83
|
+
commandId: 'command-1',
|
|
84
|
+
sessionId: 'session-1',
|
|
85
|
+
source: 'browser-1',
|
|
86
|
+
ok: true,
|
|
87
|
+
});
|
|
88
|
+
await link.receive(request({ expiresAt: 5_000 }));
|
|
89
|
+
await drain();
|
|
90
|
+
expect(execute).toHaveBeenCalledTimes(1);
|
|
91
|
+
expect(link.messages.at(-1)).toMatchObject({ expiresAt: 5_000 });
|
|
92
|
+
});
|
|
93
|
+
it('does not execute stale, expired, or cross-session/source commands', async () => {
|
|
94
|
+
const { registry, execute } = fixture();
|
|
95
|
+
const link = transport();
|
|
96
|
+
createDataSurfaceBrowserBridge({
|
|
97
|
+
registry,
|
|
98
|
+
transport: link,
|
|
99
|
+
sessionId: 'session-1',
|
|
100
|
+
source: 'browser-1',
|
|
101
|
+
peerSource: 'server-1',
|
|
102
|
+
now: () => 1_000,
|
|
103
|
+
});
|
|
104
|
+
await link.receive(request({ commandId: 'stale', expectedRevision: 99 }));
|
|
105
|
+
await link.receive(request({ commandId: 'expired', expiresAt: 500 }));
|
|
106
|
+
await link.receive(request({ commandId: 'session', sessionId: 'other' }));
|
|
107
|
+
await link.receive(request({ commandId: 'source', source: 'other' }));
|
|
108
|
+
await drain();
|
|
109
|
+
expect(execute).not.toHaveBeenCalled();
|
|
110
|
+
expect(link.messages
|
|
111
|
+
.filter((message) => message.type === 'data-surface.ack')
|
|
112
|
+
.map((message) => message.reason)).toEqual(expect.arrayContaining([
|
|
113
|
+
'stale_revision',
|
|
114
|
+
'expired',
|
|
115
|
+
'session_mismatch',
|
|
116
|
+
'source_mismatch',
|
|
117
|
+
]));
|
|
118
|
+
});
|
|
119
|
+
it('rejects a command whose wire identity is accompanied by an unauthenticated peer', async () => {
|
|
120
|
+
const { registry, execute } = fixture();
|
|
121
|
+
const link = transport();
|
|
122
|
+
createDataSurfaceBrowserBridge({
|
|
123
|
+
registry,
|
|
124
|
+
transport: link,
|
|
125
|
+
sessionId: 'session-1',
|
|
126
|
+
source: 'browser-1',
|
|
127
|
+
peerSource: 'server-1',
|
|
128
|
+
now: () => 1_000,
|
|
129
|
+
});
|
|
130
|
+
await link.receive(request(), {
|
|
131
|
+
sessionId: 'session-1',
|
|
132
|
+
source: 'attacker',
|
|
133
|
+
});
|
|
134
|
+
await link.receive(request({ commandId: 'session-spoof' }), {
|
|
135
|
+
sessionId: 'attacker',
|
|
136
|
+
source: 'server-1',
|
|
137
|
+
});
|
|
138
|
+
expect(execute).not.toHaveBeenCalled();
|
|
139
|
+
expect(link.messages).toHaveLength(0);
|
|
140
|
+
});
|
|
141
|
+
it('rejects identifiers longer than the shared bridge contract', async () => {
|
|
142
|
+
const { registry, execute } = fixture();
|
|
143
|
+
const link = transport();
|
|
144
|
+
createDataSurfaceBrowserBridge({
|
|
145
|
+
registry,
|
|
146
|
+
transport: link,
|
|
147
|
+
sessionId: 'session-1',
|
|
148
|
+
source: 'browser-1',
|
|
149
|
+
peerSource: 'server-1',
|
|
150
|
+
now: () => 1_000,
|
|
151
|
+
});
|
|
152
|
+
const tooLong = 'x'.repeat(DATA_SURFACE_IDENTIFIER_MAX_LENGTH + 1);
|
|
153
|
+
await link.receive(request({ commandId: tooLong }));
|
|
154
|
+
await link.receive(request({ controlId: tooLong }));
|
|
155
|
+
await link.receive(request({ identity: { surfaceId: tooLong, kind: 'table' } }));
|
|
156
|
+
await link.receive(request({
|
|
157
|
+
identity: {
|
|
158
|
+
surfaceId: 'orders',
|
|
159
|
+
kind: 'table',
|
|
160
|
+
subject: { type: tooLong, id: 'docs' },
|
|
161
|
+
},
|
|
162
|
+
}));
|
|
163
|
+
await link.receive(request({
|
|
164
|
+
identity: {
|
|
165
|
+
surfaceId: 'orders',
|
|
166
|
+
kind: 'table',
|
|
167
|
+
subject: { type: 'site', id: tooLong },
|
|
168
|
+
},
|
|
169
|
+
}));
|
|
170
|
+
expect(execute).not.toHaveBeenCalled();
|
|
171
|
+
expect(link.messages).toHaveLength(0);
|
|
172
|
+
});
|
|
173
|
+
it('retains every unexpired replay outcome and refuses new commands at capacity', async () => {
|
|
174
|
+
const { registry, execute } = fixture();
|
|
175
|
+
const link = transport();
|
|
176
|
+
createDataSurfaceBrowserBridge({
|
|
177
|
+
registry,
|
|
178
|
+
transport: link,
|
|
179
|
+
sessionId: 'session-1',
|
|
180
|
+
source: 'browser-1',
|
|
181
|
+
peerSource: 'server-1',
|
|
182
|
+
now: () => 1_000,
|
|
183
|
+
maxReplayEntries: 2,
|
|
184
|
+
});
|
|
185
|
+
await link.receive(request({ commandId: 'one', expiresAt: 5_000 }));
|
|
186
|
+
await drain();
|
|
187
|
+
await link.receive(request({ commandId: 'two', expectedRevision: 2, expiresAt: 5_000 }));
|
|
188
|
+
await drain();
|
|
189
|
+
await link.receive(request({ commandId: 'three', expectedRevision: 3, expiresAt: 5_000 }));
|
|
190
|
+
await drain();
|
|
191
|
+
expect(execute).toHaveBeenCalledTimes(2);
|
|
192
|
+
expect(link.messages.at(-1)).toMatchObject({
|
|
193
|
+
commandId: 'three',
|
|
194
|
+
reason: 'replay_capacity_exceeded',
|
|
195
|
+
});
|
|
196
|
+
await link.receive(request({ commandId: 'one', expiresAt: 5_000 }));
|
|
197
|
+
await drain();
|
|
198
|
+
expect(execute).toHaveBeenCalledTimes(2);
|
|
199
|
+
});
|
|
200
|
+
it('atomically reserves replay capacity while concurrent executions are held', async () => {
|
|
201
|
+
const registry = createDataSurfaceRegistry();
|
|
202
|
+
const releases = [];
|
|
203
|
+
const execute = vi.fn(() => new Promise((resolve) => releases.push(resolve)));
|
|
204
|
+
registry.register({
|
|
205
|
+
descriptor,
|
|
206
|
+
getSnapshot: () => ({ revision: 1, state: {} }),
|
|
207
|
+
execute,
|
|
208
|
+
});
|
|
209
|
+
const link = transport();
|
|
210
|
+
createDataSurfaceBrowserBridge({
|
|
211
|
+
registry,
|
|
212
|
+
transport: link,
|
|
213
|
+
sessionId: 'session-1',
|
|
214
|
+
source: 'browser-1',
|
|
215
|
+
peerSource: 'server-1',
|
|
216
|
+
now: () => 1_000,
|
|
217
|
+
maxReplayEntries: 2,
|
|
218
|
+
});
|
|
219
|
+
void link.receive(request({ commandId: 'held-one', expiresAt: 5_000 }));
|
|
220
|
+
void link.receive(request({ commandId: 'held-two', expiresAt: 5_000 }));
|
|
221
|
+
void link.receive(request({ commandId: 'held-three', expiresAt: 5_000 }));
|
|
222
|
+
for (let attempt = 0; attempt < 5 && execute.mock.calls.length < 1; attempt++) {
|
|
223
|
+
await drain();
|
|
224
|
+
}
|
|
225
|
+
expect(execute).toHaveBeenCalledTimes(1);
|
|
226
|
+
expect(link.messages).toContainEqual(expect.objectContaining({
|
|
227
|
+
type: 'data-surface.ack',
|
|
228
|
+
commandId: 'held-three',
|
|
229
|
+
reason: 'replay_capacity_exceeded',
|
|
230
|
+
}));
|
|
231
|
+
releases[0]?.();
|
|
232
|
+
for (let attempt = 0; attempt < 5 && execute.mock.calls.length < 2; attempt++) {
|
|
233
|
+
await drain();
|
|
234
|
+
}
|
|
235
|
+
releases[1]?.();
|
|
236
|
+
await drain();
|
|
237
|
+
await drain();
|
|
238
|
+
expect(link.messages.filter((message) => message.type === 'data-surface.ack' && message.ok === true)).toHaveLength(2);
|
|
239
|
+
});
|
|
240
|
+
it('releases replay reservations when execution errors after expiry', async () => {
|
|
241
|
+
let current = 1_000;
|
|
242
|
+
const registry = createDataSurfaceRegistry();
|
|
243
|
+
const execute = vi
|
|
244
|
+
.fn()
|
|
245
|
+
.mockImplementationOnce(() => {
|
|
246
|
+
throw new Error('boom');
|
|
247
|
+
})
|
|
248
|
+
.mockImplementationOnce(() => undefined);
|
|
249
|
+
registry.register({
|
|
250
|
+
descriptor,
|
|
251
|
+
getSnapshot: () => ({ revision: 1, state: {} }),
|
|
252
|
+
execute,
|
|
253
|
+
});
|
|
254
|
+
const link = transport();
|
|
255
|
+
createDataSurfaceBrowserBridge({
|
|
256
|
+
registry,
|
|
257
|
+
transport: link,
|
|
258
|
+
sessionId: 'session-1',
|
|
259
|
+
source: 'browser-1',
|
|
260
|
+
peerSource: 'server-1',
|
|
261
|
+
now: () => current,
|
|
262
|
+
maxReplayEntries: 1,
|
|
263
|
+
});
|
|
264
|
+
await link.receive(request({ commandId: 'expired-error', expiresAt: 1_100 }));
|
|
265
|
+
await drain();
|
|
266
|
+
current = 1_200;
|
|
267
|
+
await link.receive(request({ commandId: 'after-error', expiresAt: 5_000 }));
|
|
268
|
+
await drain();
|
|
269
|
+
expect(execute).toHaveBeenCalledTimes(2);
|
|
270
|
+
expect(link.messages.at(-1)).toMatchObject({
|
|
271
|
+
commandId: 'after-error',
|
|
272
|
+
ok: true,
|
|
273
|
+
});
|
|
274
|
+
});
|
|
275
|
+
it('releases replay capacity when execution never settles before expiry', async () => {
|
|
276
|
+
vi.useFakeTimers();
|
|
277
|
+
try {
|
|
278
|
+
vi.setSystemTime(1_000);
|
|
279
|
+
const registry = createDataSurfaceRegistry();
|
|
280
|
+
let finishHung;
|
|
281
|
+
const execute = vi
|
|
282
|
+
.fn()
|
|
283
|
+
.mockImplementationOnce(() => new Promise((resolve) => {
|
|
284
|
+
finishHung = resolve;
|
|
285
|
+
}))
|
|
286
|
+
.mockImplementationOnce(() => undefined);
|
|
287
|
+
registry.register({
|
|
288
|
+
descriptor,
|
|
289
|
+
getSnapshot: () => ({ revision: 1, state: {} }),
|
|
290
|
+
execute,
|
|
291
|
+
});
|
|
292
|
+
registry.register({
|
|
293
|
+
descriptor: {
|
|
294
|
+
...descriptor,
|
|
295
|
+
identity: { surfaceId: 'invoices', kind: 'table' },
|
|
296
|
+
},
|
|
297
|
+
getSnapshot: () => ({ revision: 1, state: {} }),
|
|
298
|
+
execute,
|
|
299
|
+
});
|
|
300
|
+
const link = transport();
|
|
301
|
+
createDataSurfaceBrowserBridge({
|
|
302
|
+
registry,
|
|
303
|
+
transport: link,
|
|
304
|
+
sessionId: 'session-1',
|
|
305
|
+
source: 'browser-1',
|
|
306
|
+
peerSource: 'server-1',
|
|
307
|
+
maxReplayEntries: 1,
|
|
308
|
+
});
|
|
309
|
+
const first = link.receive(request({ commandId: 'hung', expiresAt: 1_100 }));
|
|
310
|
+
await vi.advanceTimersByTimeAsync(100);
|
|
311
|
+
await first;
|
|
312
|
+
expect(link.messages.at(-1)).toMatchObject({
|
|
313
|
+
commandId: 'hung',
|
|
314
|
+
reason: 'expired',
|
|
315
|
+
});
|
|
316
|
+
finishHung();
|
|
317
|
+
await vi.runOnlyPendingTimersAsync();
|
|
318
|
+
expect(link.messages.filter((message) => message.type === 'data-surface.ack' && message.commandId === 'hung')).toHaveLength(1);
|
|
319
|
+
await link.receive(request({
|
|
320
|
+
commandId: 'after-hung',
|
|
321
|
+
expiresAt: 5_000,
|
|
322
|
+
identity: { surfaceId: 'invoices', kind: 'table' },
|
|
323
|
+
}));
|
|
324
|
+
await vi.runOnlyPendingTimersAsync();
|
|
325
|
+
expect(execute).toHaveBeenCalledTimes(2);
|
|
326
|
+
expect(link.messages.at(-1)).toMatchObject({
|
|
327
|
+
commandId: 'after-hung',
|
|
328
|
+
ok: true,
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
finally {
|
|
332
|
+
vi.useRealTimers();
|
|
333
|
+
}
|
|
334
|
+
});
|
|
335
|
+
it('forwards only monotonic registry events', async () => {
|
|
336
|
+
const { registry } = fixture();
|
|
337
|
+
const link = transport();
|
|
338
|
+
createDataSurfaceBrowserBridge({
|
|
339
|
+
registry,
|
|
340
|
+
transport: link,
|
|
341
|
+
sessionId: 'session-1',
|
|
342
|
+
source: 'browser-1',
|
|
343
|
+
peerSource: 'server-1',
|
|
344
|
+
});
|
|
345
|
+
await link.receive(request({ commandId: 'event-command', expiresAt: Date.now() + 1000 }));
|
|
346
|
+
await drain();
|
|
347
|
+
const events = link.messages.filter((message) => message.type === 'data-surface.event');
|
|
348
|
+
expect(events.length).toBeGreaterThan(0);
|
|
349
|
+
expect(events.map((event) => event.sequence)).toEqual([...events].map((event) => event.sequence).sort((a, b) => a - b));
|
|
350
|
+
});
|
|
351
|
+
});
|
|
@@ -233,6 +233,17 @@ onMount(() => {
|
|
|
233
233
|
}
|
|
234
234
|
},
|
|
235
235
|
getValue: () => value,
|
|
236
|
+
constraints: { required },
|
|
237
|
+
webMcpSchema: {
|
|
238
|
+
type: 'object',
|
|
239
|
+
properties: Object.fromEntries(
|
|
240
|
+
fields.map((field) => [field, { type: 'string' }]),
|
|
241
|
+
),
|
|
242
|
+
...(required ? { required: [...fields] } : {}),
|
|
243
|
+
},
|
|
244
|
+
validate: () =>
|
|
245
|
+
!required ||
|
|
246
|
+
fields.every((field) => String(value[field] ?? '').trim().length > 0),
|
|
236
247
|
};
|
|
237
248
|
formContext.registerField(fieldDef);
|
|
238
249
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AddressInput.svelte.d.ts","sourceRoot":"","sources":["../../../src/components/forms/AddressInput.svelte.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAG/C,KAAK,YAAY,GAAG,MAAM,YAAY,CAAC;AAEvC,MAAM,WAAW,KAAK;IACpB,wBAAwB;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,kBAAkB;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,uCAAuC;IACvC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,+BAA+B;IAC/B,KAAK,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;IAC9B,2BAA2B;IAC3B,MAAM,CAAC,EAAE,YAAY,EAAE,CAAC;IACxB,qBAAqB;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,qBAAqB;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,+BAA+B;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,mCAAmC;IACnC,SAAS,CAAC,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACpD,0CAA0C;IAC1C,SAAS,CAAC,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACpD,gCAAgC;IAChC,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,YAAY,CAAC,KAAK,IAAI,CAAC;CACnD;
|
|
1
|
+
{"version":3,"file":"AddressInput.svelte.d.ts","sourceRoot":"","sources":["../../../src/components/forms/AddressInput.svelte.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAG/C,KAAK,YAAY,GAAG,MAAM,YAAY,CAAC;AAEvC,MAAM,WAAW,KAAK;IACpB,wBAAwB;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,kBAAkB;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,uCAAuC;IACvC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,+BAA+B;IAC/B,KAAK,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;IAC9B,2BAA2B;IAC3B,MAAM,CAAC,EAAE,YAAY,EAAE,CAAC;IACxB,qBAAqB;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,qBAAqB;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,+BAA+B;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,mCAAmC;IACnC,SAAS,CAAC,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACpD,0CAA0C;IAC1C,SAAS,CAAC,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACpD,gCAAgC;IAChC,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,YAAY,CAAC,KAAK,IAAI,CAAC;CACnD;AAmUD,QAAA,MAAM,YAAY,gDAAwC,CAAC;AAC3D,KAAK,YAAY,GAAG,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC;AACpD,eAAe,YAAY,CAAC"}
|
|
@@ -64,6 +64,8 @@ onMount(() => {
|
|
|
64
64
|
}
|
|
65
65
|
},
|
|
66
66
|
getValue: () => checked,
|
|
67
|
+
constraints: { required },
|
|
68
|
+
validate: () => !required || checked,
|
|
67
69
|
};
|
|
68
70
|
formContext.registerField(fieldDef);
|
|
69
71
|
}
|
|
@@ -206,4 +208,4 @@ function handleChange(e: Event) {
|
|
|
206
208
|
background-color: var(--smrt-color-on-surface);
|
|
207
209
|
opacity: 0.08;
|
|
208
210
|
}
|
|
209
|
-
</style>
|
|
211
|
+
</style>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CheckboxInput.svelte.d.ts","sourceRoot":"","sources":["../../../src/components/forms/CheckboxInput.svelte.ts"],"names":[],"mappings":"AAaA,MAAM,WAAW,KAAK;IACpB,iBAAiB;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,kBAAkB;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,uCAAuC;IACvC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,+BAA+B;IAC/B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,qBAAqB;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,qBAAqB;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,gCAAgC;IAChC,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;CACvC;
|
|
1
|
+
{"version":3,"file":"CheckboxInput.svelte.d.ts","sourceRoot":"","sources":["../../../src/components/forms/CheckboxInput.svelte.ts"],"names":[],"mappings":"AAaA,MAAM,WAAW,KAAK;IACpB,iBAAiB;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,kBAAkB;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,uCAAuC;IACvC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,+BAA+B;IAC/B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,qBAAqB;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,qBAAqB;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,gCAAgC;IAChC,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;CACvC;AA2FD,QAAA,MAAM,aAAa,kDAAwC,CAAC;AAC5D,KAAK,aAAa,GAAG,UAAU,CAAC,OAAO,aAAa,CAAC,CAAC;AACtD,eAAe,aAAa,CAAC"}
|
|
@@ -206,6 +206,9 @@ onMount(() => {
|
|
|
206
206
|
.catch(() => {});
|
|
207
207
|
},
|
|
208
208
|
getValue: () => ({ startDate, endDate }),
|
|
209
|
+
constraints: { required },
|
|
210
|
+
validate: () =>
|
|
211
|
+
!required || (startDate.trim().length > 0 && endDate.trim().length > 0),
|
|
209
212
|
};
|
|
210
213
|
formContext.registerField(fieldDef);
|
|
211
214
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DateRangeInput.svelte.d.ts","sourceRoot":"","sources":["../../../src/components/forms/DateRangeInput.svelte.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAGjD,MAAM,WAAW,KAAK;IACpB,iBAAiB;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,kBAAkB;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,uCAAuC;IACvC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,6BAA6B;IAC7B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,2BAA2B;IAC3B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,2DAA2D;IAC3D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,yDAAyD;IACzD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,8BAA8B;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,8BAA8B;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,qBAAqB;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,qBAAqB;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,+BAA+B;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gCAAgC;IAChC,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAC;CAC5C;
|
|
1
|
+
{"version":3,"file":"DateRangeInput.svelte.d.ts","sourceRoot":"","sources":["../../../src/components/forms/DateRangeInput.svelte.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAGjD,MAAM,WAAW,KAAK;IACpB,iBAAiB;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,kBAAkB;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,uCAAuC;IACvC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,6BAA6B;IAC7B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,2BAA2B;IAC3B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,2DAA2D;IAC3D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,yDAAyD;IACzD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,8BAA8B;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,8BAA8B;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,qBAAqB;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,qBAAqB;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,+BAA+B;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gCAAgC;IAChC,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAC;CAC5C;AAqYD,QAAA,MAAM,cAAc,gEAAwC,CAAC;AAC7D,KAAK,cAAc,GAAG,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC;AACxD,eAAe,cAAc,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DateTimeInput.svelte.d.ts","sourceRoot":"","sources":["../../../src/components/forms/DateTimeInput.svelte.ts"],"names":[],"mappings":"AAgBA,MAAM,WAAW,KAAK;IACpB,iBAAiB;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,kBAAkB;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,2CAA2C;IAC3C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iCAAiC;IACjC,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,uBAAuB;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,2CAA2C;IAC3C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,qBAAqB;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,qBAAqB;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,gCAAgC;IAChC,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACpC;
|
|
1
|
+
{"version":3,"file":"DateTimeInput.svelte.d.ts","sourceRoot":"","sources":["../../../src/components/forms/DateTimeInput.svelte.ts"],"names":[],"mappings":"AAgBA,MAAM,WAAW,KAAK;IACpB,iBAAiB;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,kBAAkB;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,2CAA2C;IAC3C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iCAAiC;IACjC,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,uBAAuB;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,2CAA2C;IAC3C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,qBAAqB;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,qBAAqB;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,gCAAgC;IAChC,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACpC;AA+UD,QAAA,MAAM,aAAa,gDAAwC,CAAC;AAC5D,KAAK,aAAa,GAAG,UAAU,CAAC,OAAO,aAAa,CAAC,CAAC;AACtD,eAAe,aAAa,CAAC"}
|