foldkit 0.147.0 → 0.148.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/dist/buildToken.d.ts +3 -0
  2. package/dist/buildToken.d.ts.map +1 -0
  3. package/dist/buildToken.js +21 -0
  4. package/dist/controlledDomState.d.ts +25 -0
  5. package/dist/controlledDomState.d.ts.map +1 -0
  6. package/dist/controlledDomState.js +240 -0
  7. package/dist/cssStyleProperties.d.ts +6 -0
  8. package/dist/cssStyleProperties.d.ts.map +1 -0
  9. package/dist/cssStyleProperties.js +91 -0
  10. package/dist/domReflection.d.ts +73 -0
  11. package/dist/domReflection.d.ts.map +1 -0
  12. package/dist/domReflection.js +557 -0
  13. package/dist/experimental/server/host.d.ts +102 -8
  14. package/dist/experimental/server/host.d.ts.map +1 -1
  15. package/dist/experimental/server/host.js +203 -13
  16. package/dist/experimental/server/public.d.ts +2 -2
  17. package/dist/experimental/server/public.d.ts.map +1 -1
  18. package/dist/experimental/server/public.js +1 -1
  19. package/dist/experimental/server/serialize.d.ts +15 -5
  20. package/dist/experimental/server/serialize.d.ts.map +1 -1
  21. package/dist/experimental/server/serialize.js +373 -144
  22. package/dist/experimental/server/server.d.ts +55 -14
  23. package/dist/experimental/server/server.d.ts.map +1 -1
  24. package/dist/experimental/server/server.js +546 -22
  25. package/dist/experimental/server/template.d.ts +8 -0
  26. package/dist/experimental/server/template.d.ts.map +1 -1
  27. package/dist/experimental/server/template.js +437 -2
  28. package/dist/html/index.d.ts.map +1 -1
  29. package/dist/html/index.js +436 -29
  30. package/dist/hydrate.d.ts +1 -1
  31. package/dist/hydrate.d.ts.map +1 -1
  32. package/dist/hydrate.js +449 -121
  33. package/dist/hydrationMarkers.d.ts +15 -0
  34. package/dist/hydrationMarkers.d.ts.map +1 -0
  35. package/dist/hydrationMarkers.js +72 -0
  36. package/dist/nativeInnerHtml.d.ts +13 -0
  37. package/dist/nativeInnerHtml.d.ts.map +1 -0
  38. package/dist/nativeInnerHtml.js +30 -0
  39. package/dist/propertyProvenance.d.ts +33 -0
  40. package/dist/propertyProvenance.d.ts.map +1 -0
  41. package/dist/propertyProvenance.js +78 -0
  42. package/dist/propsModule.d.ts.map +1 -1
  43. package/dist/propsModule.js +149 -15
  44. package/dist/runtime/public.d.ts +1 -1
  45. package/dist/runtime/public.d.ts.map +1 -1
  46. package/dist/runtime/runtime.d.ts +33 -6
  47. package/dist/runtime/runtime.d.ts.map +1 -1
  48. package/dist/runtime/runtime.js +240 -27
  49. package/dist/snabbdom/attributes.d.ts.map +1 -1
  50. package/dist/snabbdom/attributes.js +65 -37
  51. package/dist/snabbdom/class.d.ts.map +1 -1
  52. package/dist/snabbdom/class.js +61 -5
  53. package/dist/snabbdom/style.d.ts.map +1 -1
  54. package/dist/snabbdom/style.js +57 -34
  55. package/dist/test/apps/attributes.d.ts +1 -0
  56. package/dist/test/apps/attributes.d.ts.map +1 -1
  57. package/dist/test/apps/attributes.js +8 -1
  58. package/dist/test/apps/login.js +1 -1
  59. package/dist/test/matchers.d.ts.map +1 -1
  60. package/dist/test/matchers.js +2 -1
  61. package/dist/test/scene.d.ts.map +1 -1
  62. package/dist/test/scene.js +2 -1
  63. package/package.json +2 -2
@@ -92,21 +92,22 @@ export const acceptsHtml = (acceptHeader) => {
92
92
  return bestSpecificity > 0 && bestQuality > 0;
93
93
  };
94
94
  /**
95
- * Merges the `Accept` field name into an existing `Vary` header value, parsing
96
- * it as a comma-separated, case-insensitive list of field names. `Vary: *`
97
- * already varies on everything and is returned unchanged, an existing `Accept`
98
- * token (in any case, and distinct from `Accept-Language` or `Accept-Encoding`)
99
- * is not duplicated, and otherwise `Accept` is appended.
95
+ * Merges a field name into an existing `Vary` header value, parsing it as a
96
+ * comma-separated, case-insensitive list of field names. `Vary: *` already
97
+ * varies on everything and is returned unchanged, a token already present (in
98
+ * any case, and distinct from a longer name that merely starts with it, such as
99
+ * `Accept-Language` beside `Accept`) is not duplicated, and otherwise the field
100
+ * name is appended.
100
101
  *
101
- * A page host that negotiates HTML on the `Accept` header must declare that in
102
- * `Vary` so a shared cache does not serve one representation in place of the
103
- * other. The dev host, reference server, and scaffold merge through this one
104
- * helper so a comma-joined field-name string like `Accept-Language` is never
105
- * mistaken for the `Accept` field.
102
+ * A host whose response depends on a request header must declare that header in
103
+ * `Vary` so a shared cache does not serve one client's representation to
104
+ * another. The dev host, reference server, and scaffold merge through this one
105
+ * helper rather than assigning `Vary`, which would drop the fields already
106
+ * there.
106
107
  *
107
108
  * @experimental Ships from `foldkit/experimental/server`; expect breaking changes while the API settles.
108
109
  */
109
- export const varyWithAccept = (existing) => {
110
+ export const varyWith = (existing, fieldName) => {
110
111
  const tokens = existing === undefined
111
112
  ? []
112
113
  : existing
@@ -117,10 +118,61 @@ export const varyWithAccept = (existing) => {
117
118
  if (lowered.includes('*')) {
118
119
  return '*';
119
120
  }
120
- if (lowered.includes('accept')) {
121
+ if (lowered.includes(fieldName.toLowerCase())) {
121
122
  return tokens.join(', ');
122
123
  }
123
- return [...tokens, 'Accept'].join(', ');
124
+ return [...tokens, fieldName].join(', ');
125
+ };
126
+ /**
127
+ * Merges the `Accept` field name into an existing `Vary` header value.
128
+ *
129
+ * A page host that negotiates HTML on the `Accept` header must declare that in
130
+ * `Vary` so a shared cache does not serve one representation in place of the
131
+ * other.
132
+ *
133
+ * @experimental Ships from `foldkit/experimental/server`; expect breaking changes while the API settles.
134
+ */
135
+ export const varyWithAccept = (existing) => varyWith(existing, 'Accept');
136
+ /**
137
+ * Resolves a request target against the origin the host serves, returning the
138
+ * absolute URL to hand the server entry, or `undefined` when the target names
139
+ * a different origin.
140
+ *
141
+ * A request target is not a URL. HTTP allows origin-form (`/page?q=1`) and
142
+ * absolute-form (`http://host/page`), and a client can send a network-path
143
+ * reference (`//elsewhere.example/page`) that resolves against no scheme at
144
+ * all. Resolving one of those against the host origin silently adopts the
145
+ * origin the client wrote, so an entry that derives redirects, canonical URLs,
146
+ * cookie domains, or tenant selection from `Request.url` would take them from
147
+ * the request rather than from the deployment. Only a target that resolves to
148
+ * the host's own origin is accepted; a host behind a proxy that must serve a
149
+ * different public origin passes that origin in explicitly.
150
+ *
151
+ * @experimental Ships from `foldkit/experimental/server`; expect breaking changes while the API settles.
152
+ */
153
+ export const resolveRequestUrl = (requestTarget, origin) => {
154
+ let base;
155
+ try {
156
+ base = new URL(origin);
157
+ }
158
+ catch {
159
+ return undefined;
160
+ }
161
+ let resolved;
162
+ try {
163
+ resolved = new URL(requestTarget, base);
164
+ }
165
+ catch {
166
+ return undefined;
167
+ }
168
+ // Credentials in the target are refused rather than passed along. `origin`
169
+ // ignores them, so `http://user:pass@host/page` reads as same-origin here and
170
+ // then makes `new Request(url)` throw, turning a malformed request into a 500
171
+ // instead of the 400 it is.
172
+ if (resolved.username !== '' || resolved.password !== '') {
173
+ return undefined;
174
+ }
175
+ return resolved.origin === base.origin ? resolved.href : undefined;
124
176
  };
125
177
  const normalizePath = (path) => {
126
178
  const segments = [];
@@ -136,6 +188,108 @@ const normalizePath = (path) => {
136
188
  }
137
189
  return segments.join('/');
138
190
  };
191
+ // The `Sec-Fetch-Dest` values a browser sends for a subresource it fetches for
192
+ // an already-loaded page, as opposed to a navigation (`document`, `iframe`,
193
+ // `frame`) or a scripted fetch whose destination is `empty`. A request carrying
194
+ // one of these is never a page request, whatever it says it accepts.
195
+ const SUBRESOURCE_FETCH_DESTINATIONS = new Set([
196
+ 'audio',
197
+ 'audioworklet',
198
+ 'embed',
199
+ 'font',
200
+ 'image',
201
+ 'manifest',
202
+ 'object',
203
+ 'paintworklet',
204
+ 'script',
205
+ 'serviceworker',
206
+ 'sharedworker',
207
+ 'style',
208
+ 'track',
209
+ 'video',
210
+ 'worker',
211
+ 'xslt',
212
+ ]);
213
+ const ASSET_EXTENSIONS = new Set([
214
+ 'avif',
215
+ 'bmp',
216
+ 'cjs',
217
+ 'css',
218
+ 'csv',
219
+ 'eot',
220
+ 'gif',
221
+ 'gz',
222
+ 'ico',
223
+ 'jpeg',
224
+ 'jpg',
225
+ 'js',
226
+ 'json',
227
+ 'map',
228
+ 'mjs',
229
+ 'mp3',
230
+ 'mp4',
231
+ 'ogg',
232
+ 'otf',
233
+ 'pdf',
234
+ 'png',
235
+ 'svg',
236
+ 'ttf',
237
+ 'txt',
238
+ 'wasm',
239
+ 'wav',
240
+ 'webm',
241
+ 'webmanifest',
242
+ 'webp',
243
+ 'woff',
244
+ 'woff2',
245
+ 'xml',
246
+ 'zip',
247
+ ]);
248
+ /**
249
+ * Classifies a request that no static file answered, from its path and, when
250
+ * the client sent one, its `Sec-Fetch-Dest`.
251
+ *
252
+ * A host answers a static miss by content negotiation, and a browser requests
253
+ * scripts, stylesheets, and images with `Accept: *​/*`, which accepts HTML. A
254
+ * request for a hashed asset that is no longer deployed would therefore be
255
+ * answered with the application shell at 200, so a stale bundle reads as a
256
+ * blank page rather than the 404 it is.
257
+ *
258
+ * The path is read first, so a request the URL alone settles is never made to
259
+ * depend on a header the client may or may not send.
260
+ *
261
+ * @experimental Ships from `foldkit/experimental/server`; expect breaking changes while the API settles.
262
+ */
263
+ export const classifyRequest = (requestUrl, fetchDestination) => {
264
+ let pathname;
265
+ try {
266
+ pathname = new URL(requestUrl, 'http://localhost').pathname;
267
+ }
268
+ catch {
269
+ pathname = '';
270
+ }
271
+ // Read the path a static file server would resolve, not the raw one. A file
272
+ // server percent-decodes before it looks for a file, so `/assets/a%2Ejs` and
273
+ // `/assets/a.js` name the same asset; classifying the raw form reads the
274
+ // first as an ordinary page and answers a missing bundle with the shell.
275
+ try {
276
+ pathname = decodeURIComponent(pathname);
277
+ }
278
+ catch {
279
+ // An undecodable path names no file, so leave it as written.
280
+ }
281
+ const lastSegment = pathname.slice(pathname.lastIndexOf('/') + 1);
282
+ const separator = lastSegment.lastIndexOf('.');
283
+ if (separator > 0 &&
284
+ ASSET_EXTENSIONS.has(lastSegment.slice(separator + 1).toLowerCase())) {
285
+ return 'PathAsset';
286
+ }
287
+ if (fetchDestination !== undefined &&
288
+ SUBRESOURCE_FETCH_DESTINATIONS.has(fetchDestination.trim().toLowerCase())) {
289
+ return 'DestinationAsset';
290
+ }
291
+ return 'Page';
292
+ };
139
293
  /**
140
294
  * Decides whether a request path resolves to the `index.html` template, the
141
295
  * way a static file server resolves it: percent-decoded, backslashes and
@@ -167,3 +321,39 @@ export const resolvesToIndexHtml = (requestUrl) => {
167
321
  const normalized = normalizePath(decoded.replace(/\\/g, '/'));
168
322
  return normalized === '' || normalized.toLowerCase() === 'index.html';
169
323
  };
324
+ /**
325
+ * The answer a host gives for the methods it cannot hand to a server entry.
326
+ *
327
+ * The WHATWG `Request` constructor rejects `CONNECT`, `TRACE`, and `TRACK`, so
328
+ * an entry can never be handed one: forwarding it turns a malformed request
329
+ * into a 500. A host refuses them itself, with `405` and an `Allow` header
330
+ * naming what it does forward.
331
+ *
332
+ * On Node only `TRACE` reaches this rule. The HTTP parser rejects `TRACK` with
333
+ * a 400 before any handler runs, and `CONNECT` arrives on its own event rather
334
+ * than as an ordinary request. Both are named anyway, so a host on another
335
+ * runtime refuses them rather than handing one to `new Request`.
336
+ *
337
+ * Every other method reaches the entry, `OPTIONS` included. A preflight is a
338
+ * question about a resource, so the application answers it: the entry can allow
339
+ * one origin for one route and refuse it for another, which no host-level
340
+ * policy could express. The Vite dev host applies Vite's CORS option only to
341
+ * Vite-owned modules and assets. An application preflight therefore reaches
342
+ * the entry rather than middleware a deployed host has no counterpart for.
343
+ *
344
+ * @experimental Ships from `foldkit/experimental/server`; expect breaking changes while the API settles.
345
+ */
346
+ export const HOST_METHOD_ANSWERS = {
347
+ refusedStatus: 405,
348
+ allow: 'GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS',
349
+ };
350
+ /**
351
+ * Whether a host refuses this method itself instead of calling the server
352
+ * entry. See {@link HOST_METHOD_ANSWERS}.
353
+ *
354
+ * @experimental Ships from `foldkit/experimental/server`; expect breaking changes while the API settles.
355
+ */
356
+ export const isHostSettledMethod = (method) => {
357
+ const normalized = method.toUpperCase();
358
+ return (normalized === 'CONNECT' || normalized === 'TRACE' || normalized === 'TRACK');
359
+ };
@@ -1,3 +1,3 @@
1
- export { FOLDKIT_APP_ATTRIBUTE, FOLDKIT_FLAGS_ATTRIBUTE, FlagsEncodeError, InvalidHydrationRoot, InvalidRuntimeId, InvalidUrl, Rendered, Responded, SerializationError, acceptsHtml, injectIntoTemplate, renderToString, resolvesToIndexHtml, toResponse, varyWithAccept, } from './index.js';
2
- export type { InjectIntoTemplateOptions, ResponseOptions, RenderedApplication, RenderOptions, RenderUrlOptions, RenderFlagsOptions, RenderUrlFlagsOptions, ApplicationConfig, ApplicationConfigWithFlags, EntryModule, EntryResult, RenderError, RoutingApplicationConfig, RoutingApplicationConfigWithFlags, } from './index.js';
1
+ export { FOLDKIT_APP_ATTRIBUTE, FOLDKIT_FLAGS_ATTRIBUTE, FlagsEncodeError, HOST_METHOD_ANSWERS, InvalidHydrationRoot, InvalidRuntimeId, InvalidUrl, MissingBuildId, Rendered, Responded, SerializationError, acceptsHtml, classifyRequest, injectIntoTemplate, isHostSettledMethod, renderToString, resolveRequestUrl, resolvesToIndexHtml, toResponse, varyWith, varyWithAccept, } from './index.js';
2
+ export type { InjectIntoTemplateOptions, RequestClassification, ResponseOptions, RenderedApplication, HydratableRenderOptions, StaticRenderOptions, RenderOptions, RenderUrlOptions, RenderFlagsOptions, RenderUrlFlagsOptions, ApplicationConfig, ApplicationConfigWithFlags, EntryModule, EntryResult, RenderError, RoutingApplicationConfig, RoutingApplicationConfigWithFlags, } from './index.js';
3
3
  //# sourceMappingURL=public.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"public.d.ts","sourceRoot":"","sources":["../../../src/experimental/server/public.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,qBAAqB,EACrB,uBAAuB,EACvB,gBAAgB,EAChB,oBAAoB,EACpB,gBAAgB,EAChB,UAAU,EACV,QAAQ,EACR,SAAS,EACT,kBAAkB,EAClB,WAAW,EACX,kBAAkB,EAClB,cAAc,EACd,mBAAmB,EACnB,UAAU,EACV,cAAc,GACf,MAAM,YAAY,CAAA;AAEnB,YAAY,EACV,yBAAyB,EACzB,eAAe,EACf,mBAAmB,EACnB,aAAa,EACb,gBAAgB,EAChB,kBAAkB,EAClB,qBAAqB,EACrB,iBAAiB,EACjB,0BAA0B,EAC1B,WAAW,EACX,WAAW,EACX,WAAW,EACX,wBAAwB,EACxB,iCAAiC,GAClC,MAAM,YAAY,CAAA"}
1
+ {"version":3,"file":"public.d.ts","sourceRoot":"","sources":["../../../src/experimental/server/public.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,qBAAqB,EACrB,uBAAuB,EACvB,gBAAgB,EAChB,mBAAmB,EACnB,oBAAoB,EACpB,gBAAgB,EAChB,UAAU,EACV,cAAc,EACd,QAAQ,EACR,SAAS,EACT,kBAAkB,EAClB,WAAW,EACX,eAAe,EACf,kBAAkB,EAClB,mBAAmB,EACnB,cAAc,EACd,iBAAiB,EACjB,mBAAmB,EACnB,UAAU,EACV,QAAQ,EACR,cAAc,GACf,MAAM,YAAY,CAAA;AAEnB,YAAY,EACV,yBAAyB,EACzB,qBAAqB,EACrB,eAAe,EACf,mBAAmB,EACnB,uBAAuB,EACvB,mBAAmB,EACnB,aAAa,EACb,gBAAgB,EAChB,kBAAkB,EAClB,qBAAqB,EACrB,iBAAiB,EACjB,0BAA0B,EAC1B,WAAW,EACX,WAAW,EACX,WAAW,EACX,wBAAwB,EACxB,iCAAiC,GAClC,MAAM,YAAY,CAAA"}
@@ -1 +1 @@
1
- export { FOLDKIT_APP_ATTRIBUTE, FOLDKIT_FLAGS_ATTRIBUTE, FlagsEncodeError, InvalidHydrationRoot, InvalidRuntimeId, InvalidUrl, Rendered, Responded, SerializationError, acceptsHtml, injectIntoTemplate, renderToString, resolvesToIndexHtml, toResponse, varyWithAccept, } from './index.js';
1
+ export { FOLDKIT_APP_ATTRIBUTE, FOLDKIT_FLAGS_ATTRIBUTE, FlagsEncodeError, HOST_METHOD_ANSWERS, InvalidHydrationRoot, InvalidRuntimeId, InvalidUrl, MissingBuildId, Rendered, Responded, SerializationError, acceptsHtml, classifyRequest, injectIntoTemplate, isHostSettledMethod, renderToString, resolveRequestUrl, resolvesToIndexHtml, toResponse, varyWith, varyWithAccept, } from './index.js';
@@ -5,10 +5,15 @@ import type { VNode } from '../../snabbdom/vnode.js';
5
5
  * the vnode's own data, so the stamp always wins over a same-named
6
6
  * attribute in the view.
7
7
  *
8
+ * `emitHydrationMarkers` turns on the key and identity markers hydration
9
+ * verifies adoption against. They are part of the hydration handoff, so a
10
+ * render nobody will hydrate carries none of them.
11
+ *
8
12
  * @internal Not part of the `foldkit/experimental/server` surface; `renderToString` is the public entry to serialization.
9
13
  */
10
14
  export type SerializeOptions = Readonly<{
11
15
  rootAttributes?: Readonly<Record<string, string>>;
16
+ emitHydrationMarkers?: boolean;
12
17
  }>;
13
18
  /** Escapes a string for use as HTML text content.
14
19
  *
@@ -21,11 +26,16 @@ export declare const escapeText: (value: string) => string;
21
26
  */
22
27
  export declare const escapeAttributeValue: (value: string) => string;
23
28
  export declare const controlledValueContent: (properties: Readonly<Record<string, unknown>> | undefined) => string | undefined;
24
- /** Serializes a view-produced vnode tree to an HTML string. Event handlers,
25
- * hooks, keys, and identity are behavior, not markup, and are skipped;
26
- * attrs, class, dataset, prop-backed attributes, and inline style are
27
- * emitted in that order. A `null` tree serializes to an empty comment,
28
- * mirroring how the runtime patches `null` as a comment node.
29
+ /** Serializes a view-produced vnode tree to an HTML string. Event handlers and
30
+ * hooks are behavior, not markup, and are skipped; attrs, class, dataset,
31
+ * prop-backed attributes, and inline style are emitted in that order. A `null`
32
+ * tree serializes to an empty comment, mirroring how the runtime patches
33
+ * `null` as a comment node.
34
+ *
35
+ * A hydratable render also stamps a fingerprint of each vnode's key and
36
+ * identity, so hydration can tell one logical entity from another; the raw key
37
+ * and the compiler's source identity never appear in the markup. A render that
38
+ * is not hydratable emits neither.
29
39
  *
30
40
  * @internal Not part of the `foldkit/experimental/server` surface; `renderToString` is the public entry to serialization.
31
41
  */
@@ -1 +1 @@
1
- {"version":3,"file":"serialize.d.ts","sourceRoot":"","sources":["../../../src/experimental/server/serialize.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,yBAAyB,CAAA;AAGpD;;;;;;;GAOG;AACH,MAAM,MAAM,gBAAgB,GAAG,QAAQ,CAAC;IACtC,cAAc,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;CAClD,CAAC,CAAA;AA8MF;;;GAGG;AACH,eAAO,MAAM,UAAU,GAAI,OAAO,MAAM,KAAG,MACmC,CAAA;AAE9E;;;GAGG;AACH,eAAO,MAAM,oBAAoB,GAAI,OAAO,MAAM,KAAG,MAIlD,CAAA;AAuKH,eAAO,MAAM,sBAAsB,GACjC,YAAY,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,SAAS,KACxD,MAAM,GAAG,SAMX,CAAA;AAmRD;;;;;;;GAOG;AACH,eAAO,MAAM,aAAa,GACxB,MAAM,KAAK,GAAG,IAAI,EAClB,UAAU,gBAAgB,KACzB,MAOF,CAAA"}
1
+ {"version":3,"file":"serialize.d.ts","sourceRoot":"","sources":["../../../src/experimental/server/serialize.ts"],"names":[],"mappings":"AA0BA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,yBAAyB,CAAA;AAGpD;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,gBAAgB,GAAG,QAAQ,CAAC;IACtC,cAAc,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;IACjD,oBAAoB,CAAC,EAAE,OAAO,CAAA;CAC/B,CAAC,CAAA;AAsNF;;;GAGG;AACH,eAAO,MAAM,UAAU,GAAI,OAAO,MAAM,KAAG,MAM1C,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,oBAAoB,GAAI,OAAO,MAAM,KAAG,MAMpD,CAAA;AA0MD,eAAO,MAAM,sBAAsB,GACjC,YAAY,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,SAAS,KACxD,MAAM,GAAG,SAMX,CAAA;AA+gBD;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,aAAa,GACxB,MAAM,KAAK,GAAG,IAAI,EAClB,UAAU,gBAAgB,KACzB,MAUF,CAAA"}