@quadrokit/client 0.3.11 → 0.3.13

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 (35) hide show
  1. package/README.md +3 -2
  2. package/dist/generate/codegen.d.ts +18 -0
  3. package/dist/generate/codegen.d.ts.map +1 -1
  4. package/dist/generate/codegen.mjs +84 -202
  5. package/dist/runtime/catalog-builder.d.ts +25 -0
  6. package/dist/runtime/catalog-builder.d.ts.map +1 -0
  7. package/dist/runtime/catalog-builder.mjs +99 -0
  8. package/dist/runtime/class-function.d.ts +0 -4
  9. package/dist/runtime/class-function.d.ts.map +1 -1
  10. package/dist/runtime/class-function.mjs +28 -6
  11. package/dist/runtime/client-types.d.ts +17 -0
  12. package/dist/runtime/client-types.d.ts.map +1 -0
  13. package/dist/runtime/client-types.mjs +1 -0
  14. package/dist/runtime/collection.d.ts.map +1 -1
  15. package/dist/runtime/collection.mjs +56 -41
  16. package/dist/runtime/data-class.d.ts.map +1 -1
  17. package/dist/runtime/data-class.mjs +10 -2
  18. package/dist/runtime/datastore.d.ts +2 -1
  19. package/dist/runtime/datastore.d.ts.map +1 -1
  20. package/dist/runtime/datastore.mjs +8 -3
  21. package/dist/runtime/events.d.ts +65 -0
  22. package/dist/runtime/events.d.ts.map +1 -0
  23. package/dist/runtime/events.mjs +86 -0
  24. package/dist/runtime/http.d.ts +24 -3
  25. package/dist/runtime/http.d.ts.map +1 -1
  26. package/dist/runtime/http.mjs +65 -14
  27. package/dist/runtime/index.d.ts +4 -1
  28. package/dist/runtime/index.d.ts.map +1 -1
  29. package/dist/runtime/index.mjs +2 -0
  30. package/dist/runtime/paths.d.ts +17 -1
  31. package/dist/runtime/paths.d.ts.map +1 -1
  32. package/dist/runtime/rxjs.d.ts +20 -0
  33. package/dist/runtime/rxjs.d.ts.map +1 -0
  34. package/dist/runtime/rxjs.mjs +27 -0
  35. package/package.json +13 -2
package/README.md CHANGED
@@ -51,8 +51,9 @@ Environment variables (often via `.env` in the project root): `VITE_4D_ORIGIN`,
51
51
 
52
52
  | File | Purpose |
53
53
  |------|---------|
54
- | **`types.gen.ts`** | Entity interfaces and `*Path` unions for typed `select`. |
55
- | **`client.gen.ts`** | `createClient(config)` dataclass APIs, optional `authentify`, `rpc`, `quadrokitCatalogMeta`. |
54
+ | **`types.gen.ts`** | Entity interfaces; **`*Path`** aliases use **`QuadroAttributePaths<T>`** (recursive dot paths, depth-limited for circular relations); **`QuadroClient`** typing. |
55
+ | **`catalog.gen.json`** | Catalog runtime spec (dataclass layouts, methods, relations) consumed by `@quadrokit/client/runtime` — keeps **`client.gen.ts`** tiny. |
56
+ | **`client.gen.ts`** | Thin `createClient(config)` that wires `QuadroHttp` + `buildQuadroClientFromCatalogSpec` + `catalog.gen.json`. |
56
57
  | **`meta.json`** | `__NAME`, `sessionCookieName` hint for 4D session cookies. |
57
58
 
58
59
  Point your app imports at the generated folder, for example:
@@ -1,4 +1,22 @@
1
1
  import type { CatalogJson } from '@quadrokit/shared';
2
+ /** Serializable spec consumed by {@link buildQuadroClientFromCatalogSpec} at runtime. */
3
+ export declare function buildCatalogRuntimeSpec(catalog: CatalogJson): {
4
+ classes: {
5
+ name: string;
6
+ relationMap: Record<string, string>;
7
+ keyNames: string[];
8
+ entityMethodNames: string[];
9
+ entityCollectionMethodNames: string[];
10
+ dataClassMethodNames: string[];
11
+ navigable: {
12
+ attr: string;
13
+ targetClass: string;
14
+ entityCollectionMethodNames: string[];
15
+ }[];
16
+ }[];
17
+ keyNamesByClass: Record<string, string[]>;
18
+ hasAuthentify: boolean;
19
+ };
2
20
  /** Warn when the catalog lists dataclasses but omits attributes (e.g. plain `GET /rest/$catalog` instead of `/rest/$catalog/$all`). */
3
21
  export declare function warnIfCatalogLacksAttributes(catalog: CatalogJson): void;
4
22
  export declare function writeGenerated(outDir: string, catalog: CatalogJson): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"codegen.d.ts","sourceRoot":"","sources":["../../src/generate/codegen.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAsC,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAmXxF,uIAAuI;AACvI,wBAAgB,4BAA4B,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI,CAYvE;AAED,wBAAsB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAiBxF"}
1
+ {"version":3,"file":"codegen.d.ts","sourceRoot":"","sources":["../../src/generate/codegen.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAsC,WAAW,EAAE,MAAM,mBAAmB,CAAA;AA4GxF,yFAAyF;AACzF,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,WAAW,GAAG;IAC7D,OAAO,EAAE;QACP,IAAI,EAAE,MAAM,CAAA;QACZ,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;QACnC,QAAQ,EAAE,MAAM,EAAE,CAAA;QAClB,iBAAiB,EAAE,MAAM,EAAE,CAAA;QAC3B,2BAA2B,EAAE,MAAM,EAAE,CAAA;QACrC,oBAAoB,EAAE,MAAM,EAAE,CAAA;QAC9B,SAAS,EAAE;YACT,IAAI,EAAE,MAAM,CAAA;YACZ,WAAW,EAAE,MAAM,CAAA;YACnB,2BAA2B,EAAE,MAAM,EAAE,CAAA;SACtC,EAAE,CAAA;KACJ,EAAE,CAAA;IACH,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAA;IACzC,aAAa,EAAE,OAAO,CAAA;CACvB,CAuBA;AA6GD,uIAAuI;AACvI,wBAAgB,4BAA4B,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI,CAYvE;AAED,wBAAsB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAsBxF"}
@@ -66,28 +66,7 @@ function keyNames(dc) {
66
66
  const k = dc.key?.map((x) => x.name) ?? ['ID'];
67
67
  return k.length ? k : ['ID'];
68
68
  }
69
- function collectPaths(dc, byName, maxDepth) {
70
- const paths = new Set();
71
- const visit = (current, prefix, depth) => {
72
- for (const a of current.attributes ?? []) {
73
- if (a.kind === 'storage' || a.kind === 'calculated' || a.kind === 'alias') {
74
- const p = prefix ? `${prefix}.${a.name}` : a.name;
75
- paths.add(p);
76
- }
77
- if (a.kind === 'relatedEntity' && a.type && depth < maxDepth) {
78
- const child = byName.get(a.type);
79
- const base = prefix ? `${prefix}.${a.name}` : a.name;
80
- paths.add(base);
81
- if (child) {
82
- visit(child, base, depth + 1);
83
- }
84
- }
85
- }
86
- };
87
- visit(dc, '', 0);
88
- return [...paths].sort();
89
- }
90
- function emitInterface(dc, _byName) {
69
+ function emitInterface(dc) {
91
70
  const lines = [];
92
71
  lines.push(`export interface ${dc.name} {`);
93
72
  for (const a of dc.attributes ?? []) {
@@ -115,42 +94,94 @@ function methodsForApply(dc, applyTo) {
115
94
  }
116
95
  return (dc.methods ?? []).filter((m) => m.applyTo === applyTo && m.exposed !== false);
117
96
  }
118
- function emitTypes(catalog) {
97
+ function catalogHasAuthentify(catalog) {
98
+ return Boolean(catalog.methods?.some((m) => m.name === 'authentify' && m.applyTo === 'dataStore'));
99
+ }
100
+ /** Serializable spec consumed by {@link buildQuadroClientFromCatalogSpec} at runtime. */
101
+ export function buildCatalogRuntimeSpec(catalog) {
119
102
  const classes = exposedDataClasses(catalog);
120
103
  const byName = new Map(classes.map((c) => [c.name, c]));
121
- const interfaces = classes.map((c) => emitInterface(c, byName));
104
+ return {
105
+ hasAuthentify: catalogHasAuthentify(catalog),
106
+ keyNamesByClass: Object.fromEntries(classes.map((x) => [x.name, [...keyNames(x)]])),
107
+ classes: classes.map((c) => ({
108
+ name: c.name,
109
+ relationMap: relationTargets(c),
110
+ keyNames: [...keyNames(c)],
111
+ entityMethodNames: methodsForApply(c, 'entity').map((m) => m.name),
112
+ entityCollectionMethodNames: methodsForApply(c, 'entityCollection').map((m) => m.name),
113
+ dataClassMethodNames: methodsForApply(c, 'dataClass').map((m) => m.name),
114
+ navigable: navigableRelations(c).map((n) => ({
115
+ attr: n.attr,
116
+ targetClass: n.targetClass,
117
+ entityCollectionMethodNames: methodsForApply(byName.get(n.targetClass), 'entityCollection').map((m) => m.name),
118
+ })),
119
+ })),
120
+ };
121
+ }
122
+ function emitQuadroClientTypeBlock(catalog, withEntities) {
123
+ const classes = exposedDataClasses(catalog);
124
+ const hasAuthentify = catalogHasAuthentify(catalog);
125
+ const authLine = hasAuthentify
126
+ ? ` authentify: { login: (body: { email: string; password: string }) => Promise<unknown> };\n`
127
+ : '';
128
+ const tail = ` rpc: (segments: string[], init?: { method?: 'GET' | 'POST'; body?: unknown }) => Promise<unknown>;
129
+ sessionCookieName: string;
130
+ _http: QuadroHttp;
131
+ };`;
132
+ if (!withEntities || classes.length === 0) {
133
+ return `export type QuadroClient = {
134
+ ${authLine}${tail}
135
+ `;
136
+ }
137
+ const dcFn = `type QuadroDataClassFn = <R = unknown>(args?: readonly unknown[], init?: ClassFunctionHttpOptions & { unwrapResult?: boolean }) => Promise<R>;
138
+
139
+ `;
140
+ const branches = classes
141
+ .map((c) => {
142
+ const keys = methodsForApply(c, 'dataClass')
143
+ .map((m) => `'${m.name}'`)
144
+ .join(' | ');
145
+ const rhs = keys
146
+ ? `BaseDataClassApi<${c.name}, ${c.name}Path> & { [K in ${keys}]: QuadroDataClassFn }`
147
+ : `BaseDataClassApi<${c.name}, ${c.name}Path>`;
148
+ return ` ${c.name}: ${rhs};`;
149
+ })
150
+ .join('\n');
151
+ return `${dcFn}export type QuadroClient = {
152
+ ${authLine}${branches}
153
+ ${tail}
154
+ `;
155
+ }
156
+ function emitTypes(catalog) {
157
+ const classes = exposedDataClasses(catalog);
158
+ const interfaces = classes.map((c) => emitInterface(c));
122
159
  const pathTypes = classes.map((c) => {
123
- const paths = collectPaths(c, byName, 2);
124
160
  const name = `${c.name}Path`;
125
- const body = paths.length ? paths.map((p) => `'${p}'`).join('\n | ') : 'never';
126
- return `export type ${name} =\n | ${body};`;
161
+ return `export type ${name} = QuadroAttributePaths<${c.name}>;`;
127
162
  });
128
163
  const header = `/* eslint-disable */\n/* Auto-generated by @quadrokit/client — do not edit */\n`;
164
+ const pathNote = classes.length > 0
165
+ ? `/**\n * *Path types use {@link QuadroAttributePaths} (recursive relation paths, depth-limited for circular graphs).\n * Override depth: \`type DeepEmployeePath = QuadroAttributePaths<Employee, 12>\`.\n */\n`
166
+ : '';
167
+ const runtimeImport = classes.length > 0
168
+ ? `import type { BaseDataClassApi, ClassFunctionHttpOptions, QuadroAttributePaths, QuadroHttp } from '@quadrokit/client/runtime';\n\n`
169
+ : `import type { QuadroHttp } from '@quadrokit/client/runtime';\n\n`;
129
170
  if (classes.length === 0) {
130
171
  const raw = catalog.dataClasses?.length ?? 0;
131
172
  const note = raw > 0
132
173
  ? `\n/**\n * No entity types: all ${raw} data class(es) in the catalog have exposed: false.\n * Enable REST exposure for tables in 4D, then run quadrokit-client generate again.\n */\n`
133
174
  : `\n/**\n * No entity types: the catalog has no dataClasses (or an empty list).\n */\n`;
134
- return `${header}${note}\n`;
175
+ return `${header}${runtimeImport}${note}\n${emitQuadroClientTypeBlock(catalog, false)}`;
135
176
  }
136
- return `${header}\n${interfaces.join('\n\n')}\n\n${pathTypes.join('\n\n')}\n`;
177
+ return `${header}${runtimeImport}${interfaces.join('\n\n')}\n\n${pathNote}${pathTypes.join('\n\n')}\n\n${emitQuadroClientTypeBlock(catalog, true)}`;
137
178
  }
138
179
  function emitClient(catalog) {
139
- const classes = exposedDataClasses(catalog);
140
- const byName = new Map(classes.map((c) => [c.name, c]));
141
180
  const dbName = catalog.__NAME ?? 'default';
142
- const hasAuthentify = catalog.methods?.some((m) => m.name === 'authentify' && m.applyTo === 'dataStore');
143
- const keyNamesRecord = Object.fromEntries(classes.map((x) => [x.name, keyNames(x)]));
144
- const imports = classes.length > 0
145
- ? `/* eslint-disable */\n/* Auto-generated by @quadrokit/client — do not edit */\n\nimport {\n QuadroHttp,\n makeDataClassApi,\n attachRelatedApis,\n attachEntityClassMethods,\n bindEntityCollectionMethods,\n callDataClassFunction,\n callDatastorePath,\n type ClassFunctionHttpOptions,\n type CollectionHandle,\n type CollectionOptions,\n type SelectedEntity,\n} from '@quadrokit/client/runtime';\n`
146
- : `/* eslint-disable */\n/* Auto-generated by @quadrokit/client — do not edit */\n\nimport { QuadroHttp, callDatastorePath } from '@quadrokit/client/runtime';\n`;
147
- const typeImports = classes.map((c) => c.name).join(', ');
148
- const pathImports = classes.map((c) => `${c.name}Path`).join(', ');
149
- const typeImportLine = typeImports || pathImports
150
- ? // Split so `rename-dist-js-to-mjs` does not rewrite this *emitted* import to `.mjs`.
151
- `\nimport type { ${[typeImports, pathImports].filter(Boolean).join(', ')} } from './types.gen';\n\n`
152
- : '\n';
153
- const header = `${imports}${typeImportLine}`;
181
+ const imports = `/* eslint-disable */\n/* Auto-generated by @quadrokit/client — do not edit */\n\nimport {\n QuadroHttp,\n buildQuadroClientFromCatalogSpec,\n type CatalogRuntimeSpec,\n} from '@quadrokit/client/runtime';\nimport catalogSpec from './catalog.gen.json' with { type: 'json' };\n`;
182
+ // Split so `rename-dist-js-to-mjs` does not rewrite this *emitted* import to `.mjs`.
183
+ const typeImport = `import type { QuadroClient } from './types.gen';\n\n`;
184
+ const header = `${imports}${typeImport}`;
154
185
  const metaExport = `
155
186
  export const quadrokitCatalogMeta = {
156
187
  __NAME: ${JSON.stringify(dbName)},
@@ -162,174 +193,24 @@ export interface QuadroClientConfig {
162
193
  baseURL: string;
163
194
  fetchImpl?: typeof fetch;
164
195
  defaultHeaders?: Record<string, string>;
196
+ /** Optional bus for request lifecycle events (loading / success / error). See {@link QuadroEventBus} from \`@quadrokit/client/runtime\`. */
197
+ events?: import('@quadrokit/client/runtime').QuadroEventBus;
165
198
  }
166
199
  `;
167
- const mapFunctions = classes
168
- .map((c) => {
169
- const nav = navigableRelations(c);
170
- const relMap = JSON.stringify(relationTargets(c));
171
- const kn = JSON.stringify(keyNames(c));
172
- const ecNav = nav.map((n) => ({
173
- attr: n.attr,
174
- targetClass: n.targetClass,
175
- entityCollectionMethodNames: methodsForApply(byName.get(n.targetClass), 'entityCollection').map((m) => m.name),
176
- }));
177
- const entityMethodNames = methodsForApply(c, 'entity').map((m) => m.name);
178
- return ` function map${c.name}Row(http: QuadroHttp, raw: unknown): ${c.name} {
179
- const row = raw as ${c.name};
180
- const pk = (row as { ID?: number }).ID ?? (row as { id?: number }).id;
181
- attachEntityClassMethods(
182
- raw,
183
- {
184
- http,
185
- className: '${c.name}',
186
- relationMap: ${relMap},
187
- keyNames: ${kn},
188
- },
189
- ${JSON.stringify(entityMethodNames)},
190
- );
191
- attachRelatedApis(
192
- raw,
193
- {
194
- http,
195
- parentClass: '${c.name}',
196
- parentId: pk as number,
197
- relationMap: ${relMap},
198
- keyNames: ${JSON.stringify(keyNamesRecord)},
199
- },
200
- ${JSON.stringify(ecNav)},
201
- );
202
- return row;
203
- }`;
204
- })
205
- .join('\n\n');
206
- const classBranches = classes
207
- .map((c) => {
208
- const relMap = JSON.stringify(relationTargets(c));
209
- const kn = JSON.stringify(keyNames(c));
210
- const pathsType = `${c.name}Path`;
211
- const ecNames = JSON.stringify(methodsForApply(c, 'entityCollection').map((m) => m.name));
212
- const dcBlock = methodsForApply(c, 'dataClass')
213
- .map((m) => ` ${m.name}: async <R = unknown>(args: readonly unknown[] = [], init?: ClassFunctionHttpOptions & { unwrapResult?: boolean }) =>
214
- callDataClassFunction<R>(http, '${c.name}', '${m.name}', args, init),`)
215
- .join('\n');
216
- const dcPrefix = dcBlock ? `${dcBlock}\n` : '';
217
- return ` ${c.name}: (() => {
218
- const cfg = {
219
- http,
220
- className: '${c.name}',
221
- relationMap: ${relMap},
222
- keyNames: ${kn},
223
- } as const;
224
- const api = makeDataClassApi<${c.name}>(cfg);
225
- return {
226
- ${dcPrefix} all<S extends readonly ${pathsType}[] = readonly []>(
227
- options?: CollectionOptions & { select?: S },
228
- ): CollectionHandle<S['length'] extends 0 ? ${c.name} : SelectedEntity<${c.name}, S>> {
229
- const inner = api.all(options as CollectionOptions);
230
- bindEntityCollectionMethods(inner, { http, className: '${c.name}', relationMap: ${relMap} }, ${ecNames});
231
- return {
232
- ...inner,
233
- delete: inner.delete.bind(inner),
234
- release: inner.release.bind(inner),
235
- get length() {
236
- return inner.length;
237
- },
238
- [Symbol.asyncIterator]() {
239
- const it = inner[Symbol.asyncIterator]();
240
- return {
241
- async next() {
242
- const n = await it.next();
243
- if (!n.done && n.value) {
244
- map${c.name}Row(http, n.value);
245
- }
246
- return n;
247
- },
248
- return(value) {
249
- return it.return?.(value) ?? Promise.resolve({ done: true, value });
250
- },
251
- throw(e) {
252
- return it.throw?.(e) ?? Promise.reject(e);
253
- },
254
- };
255
- },
256
- } as CollectionHandle<S['length'] extends 0 ? ${c.name} : SelectedEntity<${c.name}, S>>;
257
- },
258
- async get<S extends readonly ${pathsType}[] = readonly []>(
259
- id: string | number,
260
- options?: { select?: S },
261
- ): Promise<(S['length'] extends 0 ? ${c.name} : SelectedEntity<${c.name}, S>) | null> {
262
- const entity = await api.get(id, options);
263
- if (entity) {
264
- map${c.name}Row(http, entity);
265
- }
266
- return entity as (S['length'] extends 0 ? ${c.name} : SelectedEntity<${c.name}, S>) | null;
267
- },
268
- delete: (id: string | number) => api.delete(id),
269
- query<S extends readonly ${pathsType}[] = readonly []>(
270
- filter: string,
271
- options?: CollectionOptions & { params?: unknown[]; select?: S },
272
- ): CollectionHandle<S['length'] extends 0 ? ${c.name} : SelectedEntity<${c.name}, S>> {
273
- const inner = api.query(filter, options as CollectionOptions);
274
- bindEntityCollectionMethods(inner, { http, className: '${c.name}', relationMap: ${relMap} }, ${ecNames});
275
- return {
276
- ...inner,
277
- delete: inner.delete.bind(inner),
278
- release: inner.release.bind(inner),
279
- get length() {
280
- return inner.length;
281
- },
282
- [Symbol.asyncIterator]() {
283
- const it = inner[Symbol.asyncIterator]();
284
- return {
285
- async next() {
286
- const n = await it.next();
287
- if (!n.done && n.value) {
288
- map${c.name}Row(http, n.value);
289
- }
290
- return n;
291
- },
292
- return(value) {
293
- return it.return?.(value) ?? Promise.resolve({ done: true, value });
294
- },
295
- throw(e) {
296
- return it.throw?.(e) ?? Promise.reject(e);
297
- },
298
- };
299
- },
300
- } as CollectionHandle<S['length'] extends 0 ? ${c.name} : SelectedEntity<${c.name}, S>>;
301
- },
302
- };
303
- })(),`;
304
- })
305
- .join('\n');
306
- const authentifyBlock = hasAuthentify
307
- ? `
308
- authentify: {
309
- login: (body: { email: string; password: string }) =>
310
- callDatastorePath(http, ['authentify', 'login'], { body }),
311
- },`
312
- : '';
313
200
  const body = `
314
- export function createClient(config: QuadroClientConfig) {
201
+ export function createClient(config: QuadroClientConfig): QuadroClient {
315
202
  const http = new QuadroHttp({
316
203
  baseURL: config.baseURL,
317
204
  fetchImpl: config.fetchImpl,
318
205
  defaultHeaders: config.defaultHeaders,
206
+ events: config.events,
319
207
  });
320
-
321
- ${mapFunctions}
322
-
323
- return {${authentifyBlock}
324
- ${classBranches}
325
- rpc: (segments: string[], init?: { method?: 'GET' | 'POST'; body?: unknown }) =>
326
- callDatastorePath(http, segments, init),
327
- sessionCookieName: quadrokitCatalogMeta.sessionCookieName,
328
- _http: http,
329
- };
208
+ return buildQuadroClientFromCatalogSpec(
209
+ http,
210
+ catalogSpec as unknown as CatalogRuntimeSpec,
211
+ quadrokitCatalogMeta,
212
+ ) as QuadroClient;
330
213
  }
331
-
332
- export type QuadroClient = ReturnType<typeof createClient>;
333
214
  `;
334
215
  return header + metaExport + configInterface + body;
335
216
  }
@@ -347,6 +228,7 @@ export function warnIfCatalogLacksAttributes(catalog) {
347
228
  }
348
229
  export async function writeGenerated(outDir, catalog) {
349
230
  await mkdir(outDir, { recursive: true });
231
+ await writeFile(path.join(outDir, 'catalog.gen.json'), `${JSON.stringify(buildCatalogRuntimeSpec(catalog), null, 2)}\n`, 'utf8');
350
232
  await writeFile(path.join(outDir, 'types.gen.ts'), emitTypes(catalog), 'utf8');
351
233
  await writeFile(path.join(outDir, 'client.gen.ts'), emitClient(catalog), 'utf8');
352
234
  await writeFile(path.join(outDir, 'meta.json'), JSON.stringify({
@@ -0,0 +1,25 @@
1
+ import { type RelatedNavigationSpec } from './data-class.js';
2
+ import type { QuadroHttp } from './http.js';
3
+ /** One dataclass entry in `catalog.gen.json` (codegen output). */
4
+ export interface CatalogClassRuntimeSpec {
5
+ name: string;
6
+ relationMap: Record<string, string>;
7
+ keyNames: readonly string[];
8
+ entityMethodNames: readonly string[];
9
+ entityCollectionMethodNames: readonly string[];
10
+ dataClassMethodNames: readonly string[];
11
+ navigable: readonly RelatedNavigationSpec[];
12
+ }
13
+ export interface CatalogRuntimeSpec {
14
+ classes: readonly CatalogClassRuntimeSpec[];
15
+ keyNamesByClass: Readonly<Record<string, readonly string[]>>;
16
+ hasAuthentify: boolean;
17
+ }
18
+ /**
19
+ * Builds the object returned by generated `createClient()` from `catalog.gen.json`.
20
+ * Keeps generated `client.gen.ts` small; all repetitive logic lives here.
21
+ */
22
+ export declare function buildQuadroClientFromCatalogSpec(http: QuadroHttp, spec: CatalogRuntimeSpec, meta: {
23
+ sessionCookieName: string;
24
+ }): Record<string, unknown>;
25
+ //# sourceMappingURL=catalog-builder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"catalog-builder.d.ts","sourceRoot":"","sources":["../../src/runtime/catalog-builder.ts"],"names":[],"mappings":"AAEA,OAAO,EAKL,KAAK,qBAAqB,EAC3B,MAAM,iBAAiB,CAAA;AAExB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AAE3C,kEAAkE;AAClE,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACnC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAA;IAC3B,iBAAiB,EAAE,SAAS,MAAM,EAAE,CAAA;IACpC,2BAA2B,EAAE,SAAS,MAAM,EAAE,CAAA;IAC9C,oBAAoB,EAAE,SAAS,MAAM,EAAE,CAAA;IACvC,SAAS,EAAE,SAAS,qBAAqB,EAAE,CAAA;CAC5C;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,SAAS,uBAAuB,EAAE,CAAA;IAC3C,eAAe,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC,CAAC,CAAA;IAC5D,aAAa,EAAE,OAAO,CAAA;CACvB;AAqHD;;;GAGG;AACH,wBAAgB,gCAAgC,CAC9C,IAAI,EAAE,UAAU,EAChB,IAAI,EAAE,kBAAkB,EACxB,IAAI,EAAE;IAAE,iBAAiB,EAAE,MAAM,CAAA;CAAE,GAClC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAoBzB"}
@@ -0,0 +1,99 @@
1
+ import { callDataClassFunction } from './class-function.mjs';
2
+ import { attachEntityClassMethods, attachRelatedApis, bindEntityCollectionMethods, makeDataClassApi, } from './data-class.mjs';
3
+ import { callDatastorePath } from './datastore.mjs';
4
+ function wrapCollectionWithRowMapper(inner, mapRow) {
5
+ return {
6
+ ...inner,
7
+ delete: inner.delete.bind(inner),
8
+ release: inner.release.bind(inner),
9
+ get length() {
10
+ return inner.length;
11
+ },
12
+ [Symbol.asyncIterator]() {
13
+ const it = inner[Symbol.asyncIterator]();
14
+ return {
15
+ async next() {
16
+ const n = await it.next();
17
+ if (!n.done && n.value) {
18
+ mapRow(n.value);
19
+ }
20
+ return n;
21
+ },
22
+ return(value) {
23
+ return it.return?.(value) ?? Promise.resolve({ done: true, value });
24
+ },
25
+ throw(e) {
26
+ return it.throw?.(e) ?? Promise.reject(e);
27
+ },
28
+ };
29
+ },
30
+ };
31
+ }
32
+ function mapRowFromSpec(http, raw, c, keyNamesRecord) {
33
+ const pk = raw.ID ?? raw.id;
34
+ attachEntityClassMethods(raw, {
35
+ http,
36
+ className: c.name,
37
+ relationMap: c.relationMap,
38
+ keyNames: c.keyNames,
39
+ }, c.entityMethodNames);
40
+ attachRelatedApis(raw, {
41
+ http,
42
+ parentClass: c.name,
43
+ parentId: pk,
44
+ relationMap: c.relationMap,
45
+ keyNames: keyNamesRecord,
46
+ }, c.navigable);
47
+ }
48
+ function makeDataClassNamespace(http, c, keyNamesRecord) {
49
+ const cfg = {
50
+ http,
51
+ className: c.name,
52
+ relationMap: c.relationMap,
53
+ keyNames: c.keyNames,
54
+ };
55
+ const api = makeDataClassApi(cfg);
56
+ const mapRow = (raw) => {
57
+ mapRowFromSpec(http, raw, c, keyNamesRecord);
58
+ return raw;
59
+ };
60
+ const bindEc = (inner) => {
61
+ bindEntityCollectionMethods(inner, { http, className: c.name, relationMap: c.relationMap }, c.entityCollectionMethodNames);
62
+ return wrapCollectionWithRowMapper(inner, mapRow);
63
+ };
64
+ const out = {};
65
+ for (const name of c.dataClassMethodNames) {
66
+ out[name] = async (args = [], init) => callDataClassFunction(http, c.name, name, args, init);
67
+ }
68
+ out.all = (options) => bindEc(api.all(options));
69
+ out.get = async (id, options) => {
70
+ const entity = await api.get(id, options);
71
+ if (entity) {
72
+ mapRow(entity);
73
+ }
74
+ return entity;
75
+ };
76
+ out.delete = (id) => api.delete(id);
77
+ out.query = (filter, options) => bindEc(api.query(filter, options ?? {}));
78
+ return out;
79
+ }
80
+ /**
81
+ * Builds the object returned by generated `createClient()` from `catalog.gen.json`.
82
+ * Keeps generated `client.gen.ts` small; all repetitive logic lives here.
83
+ */
84
+ export function buildQuadroClientFromCatalogSpec(http, spec, meta) {
85
+ const keyNamesRecord = spec.keyNamesByClass;
86
+ const out = {};
87
+ if (spec.hasAuthentify) {
88
+ out.authentify = {
89
+ login: (body) => callDatastorePath(http, ['authentify', 'login'], { body }, { operation: 'auth.login' }),
90
+ };
91
+ }
92
+ for (const c of spec.classes) {
93
+ out[c.name] = makeDataClassNamespace(http, c, keyNamesRecord);
94
+ }
95
+ out.rpc = (segments, init) => callDatastorePath(http, segments, init);
96
+ out.sessionCookieName = meta.sessionCookieName;
97
+ out._http = http;
98
+ return out;
99
+ }
@@ -1,7 +1,3 @@
1
- /**
2
- * ORDA class functions over REST ([4D docs](https://developer.4d.com/docs/REST/classFunctions.html)):
3
- * dataclass, entity selection (entityCollection), and entity methods.
4
- */
5
1
  import type { QuadroHttp } from './http.js';
6
2
  import { type MethodSelectionQuery } from './query.js';
7
3
  export type ClassFunctionHttpOptions = {
@@ -1 +1 @@
1
- {"version":3,"file":"class-function.d.ts","sourceRoot":"","sources":["../../src/runtime/class-function.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AAC3C,OAAO,EAA6B,KAAK,oBAAoB,EAAE,MAAM,YAAY,CAAA;AAEjF,MAAM,MAAM,wBAAwB,GAAG;IACrC,4EAA4E;IAC5E,MAAM,CAAC,EAAE,KAAK,GAAG,MAAM,CAAA;IACvB,MAAM,CAAC,EAAE,WAAW,CAAA;CACrB,CAAA;AAED,uGAAuG;AACvG,wBAAgB,yBAAyB,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,GAAG,CAAC,CAK7D;AAED;;;GAGG;AACH,wBAAsB,qBAAqB,CAAC,CAAC,EAC3C,IAAI,EAAE,UAAU,EAChB,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM,EACpB,IAAI,EAAE,SAAS,OAAO,EAAE,EACxB,OAAO,CAAC,EAAE,wBAAwB,GAAG;IAAE,YAAY,CAAC,EAAE,OAAO,CAAA;CAAE,GAC9D,OAAO,CAAC,CAAC,CAAC,CAoBZ;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CAAC,CAAC,EACxC,IAAI,EAAE,UAAU,EAChB,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,GAAG,MAAM,EAC1B,YAAY,EAAE,MAAM,EACpB,IAAI,EAAE,SAAS,OAAO,EAAE,EACxB,OAAO,CAAC,EAAE,wBAAwB,GAAG;IAAE,YAAY,CAAC,EAAE,OAAO,CAAA;CAAE,GAC9D,OAAO,CAAC,CAAC,CAAC,CAqBZ;AAED,MAAM,MAAM,6BAA6B,GAAG,wBAAwB,GAAG;IACrE,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB;;;OAGG;IACH,SAAS,CAAC,EAAE,oBAAoB,CAAA;IAChC;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,CAAA;AAED;;;GAGG;AACH,wBAAsB,4BAA4B,CAAC,CAAC,EAClD,IAAI,EAAE,UAAU,EAChB,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EACnC,YAAY,EAAE,MAAM,EACpB,IAAI,EAAE,SAAS,OAAO,EAAE,EACxB,OAAO,CAAC,EAAE,6BAA6B,GACtC,OAAO,CAAC,CAAC,CAAC,CA2BZ"}
1
+ {"version":3,"file":"class-function.d.ts","sourceRoot":"","sources":["../../src/runtime/class-function.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AAC3C,OAAO,EAA6B,KAAK,oBAAoB,EAAE,MAAM,YAAY,CAAA;AAEjF,MAAM,MAAM,wBAAwB,GAAG;IACrC,4EAA4E;IAC5E,MAAM,CAAC,EAAE,KAAK,GAAG,MAAM,CAAA;IACvB,MAAM,CAAC,EAAE,WAAW,CAAA;CACrB,CAAA;AAED,uGAAuG;AACvG,wBAAgB,yBAAyB,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,GAAG,CAAC,CAK7D;AAED;;;GAGG;AACH,wBAAsB,qBAAqB,CAAC,CAAC,EAC3C,IAAI,EAAE,UAAU,EAChB,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM,EACpB,IAAI,EAAE,SAAS,OAAO,EAAE,EACxB,OAAO,CAAC,EAAE,wBAAwB,GAAG;IAAE,YAAY,CAAC,EAAE,OAAO,CAAA;CAAE,GAC9D,OAAO,CAAC,CAAC,CAAC,CAkCZ;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CAAC,CAAC,EACxC,IAAI,EAAE,UAAU,EAChB,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,GAAG,MAAM,EAC1B,YAAY,EAAE,MAAM,EACpB,IAAI,EAAE,SAAS,OAAO,EAAE,EACxB,OAAO,CAAC,EAAE,wBAAwB,GAAG;IAAE,YAAY,CAAC,EAAE,OAAO,CAAA;CAAE,GAC9D,OAAO,CAAC,CAAC,CAAC,CAoCZ;AAED,MAAM,MAAM,6BAA6B,GAAG,wBAAwB,GAAG;IACrE,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB;;;OAGG;IACH,SAAS,CAAC,EAAE,oBAAoB,CAAA;IAChC;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,CAAA;AAED;;;GAGG;AACH,wBAAsB,4BAA4B,CAAC,CAAC,EAClD,IAAI,EAAE,UAAU,EAChB,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EACnC,YAAY,EAAE,MAAM,EACpB,IAAI,EAAE,SAAS,OAAO,EAAE,EACxB,OAAO,CAAC,EAAE,6BAA6B,GACtC,OAAO,CAAC,CAAC,CAAC,CA4CZ"}
@@ -14,6 +14,12 @@ export async function callDataClassFunction(http, dataClass, functionName, args,
14
14
  const method = options?.method ?? 'POST';
15
15
  const unwrap = options?.unwrapResult !== false;
16
16
  const base = `/${dataClass}/${functionName}`;
17
+ const ctx = {
18
+ operation: 'function.dataclass',
19
+ className: dataClass,
20
+ methodName: functionName,
21
+ attributes: { argCount: args.length },
22
+ };
17
23
  let body;
18
24
  if (method === 'GET') {
19
25
  const params = new URLSearchParams();
@@ -21,14 +27,14 @@ export async function callDataClassFunction(http, dataClass, functionName, args,
21
27
  body = await http.json(`${base}?${params.toString()}`, {
22
28
  method: 'GET',
23
29
  signal: options?.signal,
24
- });
30
+ }, ctx);
25
31
  }
26
32
  else {
27
33
  body = await http.json(base, {
28
34
  method: 'POST',
29
35
  body: JSON.stringify([...args]),
30
36
  signal: options?.signal,
31
- });
37
+ }, ctx);
32
38
  }
33
39
  return (unwrap ? unwrapClassFunctionResult(body) : body);
34
40
  }
@@ -40,6 +46,13 @@ export async function callEntityFunction(http, dataClass, entityKey, functionNam
40
46
  const unwrap = options?.unwrapResult !== false;
41
47
  const key = encodeURIComponent(String(entityKey));
42
48
  const base = `/${dataClass}(${key})/${functionName}`;
49
+ const ctx = {
50
+ operation: 'function.entity',
51
+ className: dataClass,
52
+ methodName: functionName,
53
+ entityKey,
54
+ attributes: { argCount: args.length },
55
+ };
43
56
  let body;
44
57
  if (method === 'GET') {
45
58
  const params = new URLSearchParams();
@@ -47,14 +60,14 @@ export async function callEntityFunction(http, dataClass, entityKey, functionNam
47
60
  body = await http.json(`${base}?${params.toString()}`, {
48
61
  method: 'GET',
49
62
  signal: options?.signal,
50
- });
63
+ }, ctx);
51
64
  }
52
65
  else {
53
66
  body = await http.json(base, {
54
67
  method: 'POST',
55
68
  body: JSON.stringify([...args]),
56
69
  signal: options?.signal,
57
- });
70
+ }, ctx);
58
71
  }
59
72
  return (unwrap ? unwrapClassFunctionResult(body) : body);
60
73
  }
@@ -72,6 +85,15 @@ export async function callEntityCollectionFunction(http, dataClass, relationMap,
72
85
  path += `/$entityset/${encodeURIComponent(id)}`;
73
86
  }
74
87
  path += buildMethodSelectionQuery(dataClass, relationMap, options?.selection);
88
+ const ctx = {
89
+ operation: 'function.entityCollection',
90
+ className: dataClass,
91
+ methodName: functionName,
92
+ attributes: {
93
+ argCount: args.length,
94
+ ...(options?.entitySet ? { entitySet: options.entitySet } : {}),
95
+ },
96
+ };
75
97
  let body;
76
98
  if (method === 'GET') {
77
99
  const params = new URLSearchParams();
@@ -80,14 +102,14 @@ export async function callEntityCollectionFunction(http, dataClass, relationMap,
80
102
  body = await http.json(`${path}${join}${params.toString()}`, {
81
103
  method: 'GET',
82
104
  signal: options?.signal,
83
- });
105
+ }, ctx);
84
106
  }
85
107
  else {
86
108
  body = await http.json(path, {
87
109
  method: 'POST',
88
110
  body: JSON.stringify([...args]),
89
111
  signal: options?.signal,
90
- });
112
+ }, ctx);
91
113
  }
92
114
  return (unwrap ? unwrapClassFunctionResult(body) : body);
93
115
  }
@@ -0,0 +1,17 @@
1
+ import type { CollectionHandle, CollectionOptions } from './collection.js';
2
+ import type { SelectedEntity } from './paths.js';
3
+ /** Shape of each dataclass namespace on `createClient()` (codegen composes with per-class datastore method keys). */
4
+ export type BaseDataClassApi<T, Path extends string> = {
5
+ all<S extends readonly Path[] = readonly []>(options?: CollectionOptions & {
6
+ select?: S;
7
+ }): CollectionHandle<S['length'] extends 0 ? T : SelectedEntity<T, S>>;
8
+ get<S extends readonly Path[] = readonly []>(id: string | number, options?: {
9
+ select?: S;
10
+ }): Promise<(S['length'] extends 0 ? T : SelectedEntity<T, S>) | null>;
11
+ delete(id: string | number): Promise<boolean>;
12
+ query<S extends readonly Path[] = readonly []>(filter: string, options?: CollectionOptions & {
13
+ params?: unknown[];
14
+ select?: S;
15
+ }): CollectionHandle<S['length'] extends 0 ? T : SelectedEntity<T, S>>;
16
+ };
17
+ //# sourceMappingURL=client-types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client-types.d.ts","sourceRoot":"","sources":["../../src/runtime/client-types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AAC1E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAEhD,qHAAqH;AACrH,MAAM,MAAM,gBAAgB,CAAC,CAAC,EAAE,IAAI,SAAS,MAAM,IAAI;IACrD,GAAG,CAAC,CAAC,SAAS,SAAS,IAAI,EAAE,GAAG,SAAS,EAAE,EACzC,OAAO,CAAC,EAAE,iBAAiB,GAAG;QAAE,MAAM,CAAC,EAAE,CAAC,CAAA;KAAE,GAC3C,gBAAgB,CAAC,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,cAAc,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAA;IACrE,GAAG,CAAC,CAAC,SAAS,SAAS,IAAI,EAAE,GAAG,SAAS,EAAE,EACzC,EAAE,EAAE,MAAM,GAAG,MAAM,EACnB,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,CAAC,CAAA;KAAE,GACvB,OAAO,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,cAAc,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAA;IACrE,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IAC7C,KAAK,CAAC,CAAC,SAAS,SAAS,IAAI,EAAE,GAAG,SAAS,EAAE,EAC3C,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,iBAAiB,GAAG;QAAE,MAAM,CAAC,EAAE,OAAO,EAAE,CAAC;QAAC,MAAM,CAAC,EAAE,CAAC,CAAA;KAAE,GAC/D,gBAAgB,CAAC,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,cAAc,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAA;CACtE,CAAA"}
@@ -0,0 +1 @@
1
+ export {};
@@ -1 +1 @@
1
- {"version":3,"file":"collection.d.ts","sourceRoot":"","sources":["../../src/runtime/collection.ts"],"names":[],"mappings":"AAAA,OAAO,EAA0C,KAAK,UAAU,EAAE,MAAM,WAAW,CAAA;AACnF,OAAO,EAIL,KAAK,eAAe,EACrB,MAAM,YAAY,CAAA;AAGnB,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,UAAU,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;IACjB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACnC,gEAAgE;IAChE,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAA;IAC3B,IAAI,EAAE,MAAM,CAAA;IACZ,wEAAwE;IACxE,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB;AAED,MAAM,WAAW,iBAAkB,SAAQ,eAAe;IACxD,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IAC1B,uEAAuE;IACvE,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,sFAAsF;IACtF,MAAM,CAAC,EAAE,WAAW,CAAA;IACpB;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,6FAA6F;IAC7F,gBAAgB,CAAC,EAAE,CAAC,aAAa,EAAE,MAAM,KAAK,IAAI,CAAA;CACnD;AAED,MAAM,MAAM,MAAM,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,KAAK,CAAC,CAAA;AAsE3C;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAChC,GAAG,EAAE,iBAAiB,EACtB,cAAc,EAAE,iBAAiB,EACjC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,GAChB,gBAAgB,CAAC,CAAC,CAAC,CAmKrB;AAED,MAAM,MAAM,gBAAgB,CAAC,CAAC,IAAI,aAAa,CAAC,CAAC,CAAC,GAAG;IACnD,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;IACvB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;IACxB,8EAA8E;IAC9E,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CACxB,CAAA"}
1
+ {"version":3,"file":"collection.d.ts","sourceRoot":"","sources":["../../src/runtime/collection.ts"],"names":[],"mappings":"AAAA,OAAO,EAA0C,KAAK,UAAU,EAAE,MAAM,WAAW,CAAA;AACnF,OAAO,EAIL,KAAK,eAAe,EACrB,MAAM,YAAY,CAAA;AAGnB,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,UAAU,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;IACjB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACnC,gEAAgE;IAChE,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAA;IAC3B,IAAI,EAAE,MAAM,CAAA;IACZ,wEAAwE;IACxE,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB;AAED,MAAM,WAAW,iBAAkB,SAAQ,eAAe;IACxD,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IAC1B,uEAAuE;IACvE,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,sFAAsF;IACtF,MAAM,CAAC,EAAE,WAAW,CAAA;IACpB;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,6FAA6F;IAC7F,gBAAgB,CAAC,EAAE,CAAC,aAAa,EAAE,MAAM,KAAK,IAAI,CAAA;CACnD;AAED,MAAM,MAAM,MAAM,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,KAAK,CAAC,CAAA;AAsE3C;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAChC,GAAG,EAAE,iBAAiB,EACtB,cAAc,EAAE,iBAAiB,EACjC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,GAChB,gBAAgB,CAAC,CAAC,CAAC,CA+LrB;AAED,MAAM,MAAM,gBAAgB,CAAC,CAAC,IAAI,aAAa,CAAC,CAAC,CAAC,GAAG;IACnD,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;IACvB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;IACxB,8EAA8E;IAC9E,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CACxB,CAAA"}