@quadrokit/client 0.3.10 → 0.3.12
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 +3 -2
- package/dist/generate/codegen.d.ts +18 -0
- package/dist/generate/codegen.d.ts.map +1 -1
- package/dist/generate/codegen.mjs +81 -202
- package/dist/runtime/catalog-builder.d.ts +25 -0
- package/dist/runtime/catalog-builder.d.ts.map +1 -0
- package/dist/runtime/catalog-builder.mjs +99 -0
- package/dist/runtime/client-types.d.ts +17 -0
- package/dist/runtime/client-types.d.ts.map +1 -0
- package/dist/runtime/client-types.mjs +1 -0
- package/dist/runtime/index.d.ts +3 -1
- package/dist/runtime/index.d.ts.map +1 -1
- package/dist/runtime/index.mjs +1 -0
- package/dist/runtime/paths.d.ts +17 -1
- package/dist/runtime/paths.d.ts.map +1 -1
- package/package.json +2 -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
|
|
55
|
-
| **`
|
|
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;
|
|
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;AA0GD,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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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}
|
|
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
|
|
143
|
-
|
|
144
|
-
const
|
|
145
|
-
|
|
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)},
|
|
@@ -164,172 +195,19 @@ export interface QuadroClientConfig {
|
|
|
164
195
|
defaultHeaders?: Record<string, string>;
|
|
165
196
|
}
|
|
166
197
|
`;
|
|
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
198
|
const body = `
|
|
314
|
-
export function createClient(config: QuadroClientConfig) {
|
|
199
|
+
export function createClient(config: QuadroClientConfig): QuadroClient {
|
|
315
200
|
const http = new QuadroHttp({
|
|
316
201
|
baseURL: config.baseURL,
|
|
317
202
|
fetchImpl: config.fetchImpl,
|
|
318
203
|
defaultHeaders: config.defaultHeaders,
|
|
319
204
|
});
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
rpc: (segments: string[], init?: { method?: 'GET' | 'POST'; body?: unknown }) =>
|
|
326
|
-
callDatastorePath(http, segments, init),
|
|
327
|
-
sessionCookieName: quadrokitCatalogMeta.sessionCookieName,
|
|
328
|
-
_http: http,
|
|
329
|
-
};
|
|
205
|
+
return buildQuadroClientFromCatalogSpec(
|
|
206
|
+
http,
|
|
207
|
+
catalogSpec as unknown as CatalogRuntimeSpec,
|
|
208
|
+
quadrokitCatalogMeta,
|
|
209
|
+
) as QuadroClient;
|
|
330
210
|
}
|
|
331
|
-
|
|
332
|
-
export type QuadroClient = ReturnType<typeof createClient>;
|
|
333
211
|
`;
|
|
334
212
|
return header + metaExport + configInterface + body;
|
|
335
213
|
}
|
|
@@ -347,6 +225,7 @@ export function warnIfCatalogLacksAttributes(catalog) {
|
|
|
347
225
|
}
|
|
348
226
|
export async function writeGenerated(outDir, catalog) {
|
|
349
227
|
await mkdir(outDir, { recursive: true });
|
|
228
|
+
await writeFile(path.join(outDir, 'catalog.gen.json'), `${JSON.stringify(buildCatalogRuntimeSpec(catalog), null, 2)}\n`, 'utf8');
|
|
350
229
|
await writeFile(path.join(outDir, 'types.gen.ts'), emitTypes(catalog), 'utf8');
|
|
351
230
|
await writeFile(path.join(outDir, 'client.gen.ts'), emitClient(catalog), 'utf8');
|
|
352
231
|
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 }),
|
|
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
|
+
}
|
|
@@ -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 {};
|
package/dist/runtime/index.d.ts
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
|
+
export { buildQuadroClientFromCatalogSpec, type CatalogClassRuntimeSpec, type CatalogRuntimeSpec, } from './catalog-builder.js';
|
|
1
2
|
export { type ClassFunctionHttpOptions, callDataClassFunction, callEntityCollectionFunction, callEntityFunction, type EntityCollectionMethodOptions, unwrapClassFunctionResult, } from './class-function.js';
|
|
3
|
+
export type { BaseDataClassApi } from './client-types.js';
|
|
2
4
|
export { type CollectionContext, type CollectionHandle, type CollectionOptions, createCollection, } from './collection.js';
|
|
3
5
|
export { attachEntityClassMethods, attachRelatedApis, bindEntityCollectionMethods, type DataClassRuntimeConfig, type EntityNavigationConfig, makeDataClassApi, makeRelatedCollectionApi, type RelatedNavigationSpec, } from './data-class.js';
|
|
4
6
|
export { callDatastorePath, createDatastoreNamespace } from './datastore.js';
|
|
5
7
|
export { QuadroHttpError } from './errors.js';
|
|
6
8
|
export { mountPathFromBaseURL, normalizeBaseURL, type QuadroFetchOptions, QuadroHttp, } from './http.js';
|
|
7
|
-
export type { Paths1, SelectedEntity } from './paths.js';
|
|
9
|
+
export type { Paths1, QuadroAttributePaths, SelectedEntity } from './paths.js';
|
|
8
10
|
export { buildEntitySetCreationParams, buildEntitySetPageParams, buildListSearchParams, buildMethodSelectionQuery, type ListQueryParams, type MethodSelectionQuery, } from './query.js';
|
|
9
11
|
export { unwrapEntity, unwrapEntityList } from './unwrap.js';
|
|
10
12
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/runtime/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,wBAAwB,EAC7B,qBAAqB,EACrB,4BAA4B,EAC5B,kBAAkB,EAClB,KAAK,6BAA6B,EAClC,yBAAyB,GAC1B,MAAM,qBAAqB,CAAA;AAC5B,OAAO,EACL,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACrB,KAAK,iBAAiB,EACtB,gBAAgB,GACjB,MAAM,iBAAiB,CAAA;AACxB,OAAO,EACL,wBAAwB,EACxB,iBAAiB,EACjB,2BAA2B,EAC3B,KAAK,sBAAsB,EAC3B,KAAK,sBAAsB,EAC3B,gBAAgB,EAChB,wBAAwB,EACxB,KAAK,qBAAqB,GAC3B,MAAM,iBAAiB,CAAA;AACxB,OAAO,EAAE,iBAAiB,EAAE,wBAAwB,EAAE,MAAM,gBAAgB,CAAA;AAC5E,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAC7C,OAAO,EACL,oBAAoB,EACpB,gBAAgB,EAChB,KAAK,kBAAkB,EACvB,UAAU,GACX,MAAM,WAAW,CAAA;AAClB,YAAY,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/runtime/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gCAAgC,EAChC,KAAK,uBAAuB,EAC5B,KAAK,kBAAkB,GACxB,MAAM,sBAAsB,CAAA;AAC7B,OAAO,EACL,KAAK,wBAAwB,EAC7B,qBAAqB,EACrB,4BAA4B,EAC5B,kBAAkB,EAClB,KAAK,6BAA6B,EAClC,yBAAyB,GAC1B,MAAM,qBAAqB,CAAA;AAC5B,YAAY,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AACzD,OAAO,EACL,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACrB,KAAK,iBAAiB,EACtB,gBAAgB,GACjB,MAAM,iBAAiB,CAAA;AACxB,OAAO,EACL,wBAAwB,EACxB,iBAAiB,EACjB,2BAA2B,EAC3B,KAAK,sBAAsB,EAC3B,KAAK,sBAAsB,EAC3B,gBAAgB,EAChB,wBAAwB,EACxB,KAAK,qBAAqB,GAC3B,MAAM,iBAAiB,CAAA;AACxB,OAAO,EAAE,iBAAiB,EAAE,wBAAwB,EAAE,MAAM,gBAAgB,CAAA;AAC5E,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAC7C,OAAO,EACL,oBAAoB,EACpB,gBAAgB,EAChB,KAAK,kBAAkB,EACvB,UAAU,GACX,MAAM,WAAW,CAAA;AAClB,YAAY,EAAE,MAAM,EAAE,oBAAoB,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAC9E,OAAO,EACL,4BAA4B,EAC5B,wBAAwB,EACxB,qBAAqB,EACrB,yBAAyB,EACzB,KAAK,eAAe,EACpB,KAAK,oBAAoB,GAC1B,MAAM,YAAY,CAAA;AACnB,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA"}
|
package/dist/runtime/index.mjs
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export { buildQuadroClientFromCatalogSpec, } from './catalog-builder.mjs';
|
|
1
2
|
export { callDataClassFunction, callEntityCollectionFunction, callEntityFunction, unwrapClassFunctionResult, } from './class-function.mjs';
|
|
2
3
|
export { createCollection, } from './collection.mjs';
|
|
3
4
|
export { attachEntityClassMethods, attachRelatedApis, bindEntityCollectionMethods, makeDataClassApi, makeRelatedCollectionApi, } from './data-class.mjs';
|
package/dist/runtime/paths.d.ts
CHANGED
|
@@ -1,4 +1,17 @@
|
|
|
1
1
|
/** Type-level helpers for `$attributes` dot paths (compile-time only). */
|
|
2
|
+
/** Decrements depth for {@link QuadroAttributePaths} (index = current max depth). */
|
|
3
|
+
type QuadroPathDepthPrev = [never, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18];
|
|
4
|
+
type QuadroPathNextDepth<D extends number> = D extends keyof QuadroPathDepthPrev ? QuadroPathDepthPrev[D] : 0;
|
|
5
|
+
/**
|
|
6
|
+
* Valid `$attributes` dot paths for entity `T` (e.g. `ceo.manager.manager.employer.name`),
|
|
7
|
+
* including arbitrary nesting along related-entity fields. Bounded by `MaxDepth` so circular
|
|
8
|
+
* graphs (e.g. `Employee.manager: Employee`) stay instantiable in TypeScript.
|
|
9
|
+
*
|
|
10
|
+
* Index-signature objects (`Record<string, unknown>`) are treated as leaves (single segment only).
|
|
11
|
+
*/
|
|
12
|
+
export type QuadroAttributePaths<T, MaxDepth extends number = 8> = [MaxDepth] extends [0] ? never : T extends object ? T extends readonly unknown[] ? never : {
|
|
13
|
+
[K in keyof T & string]: NonNullable<T[K]> extends infer U ? U extends string | number | boolean | bigint | symbol ? K : U extends (...args: never) => unknown ? K : U extends readonly unknown[] ? K : [U] extends [never] ? K : U extends Date ? K : U extends object ? string extends keyof U ? K : K | `${K}.${QuadroAttributePaths<U, QuadroPathNextDepth<MaxDepth>>}` : K : K;
|
|
14
|
+
}[keyof T & string] : never;
|
|
2
15
|
type UnionToIntersection<U> = (U extends unknown ? (k: U) => void : never) extends (k: infer I) => void ? I : never;
|
|
3
16
|
type PickOne<T, H extends string> = H extends keyof T & string ? Pick<T, H> : H extends `${infer K}.${infer R}` ? K extends keyof T & string ? NonNullable<T[K]> extends infer U ? U extends object ? {
|
|
4
17
|
[P in K]: PickOne<U, R>;
|
|
@@ -8,7 +21,10 @@ declare const selectBrand: unique symbol;
|
|
|
8
21
|
export type SelectedEntity<T, S extends readonly string[]> = UnionToIntersection<S[number] extends infer H ? (H extends string ? PickOne<T, H> : never) : never> extends infer O ? O extends object ? O & {
|
|
9
22
|
readonly [selectBrand]: S;
|
|
10
23
|
} : never : never;
|
|
11
|
-
/**
|
|
24
|
+
/**
|
|
25
|
+
* Recursive dot paths (can hit "excessively deep" on circular entity types).
|
|
26
|
+
* Prefer {@link QuadroAttributePaths} for catalog-generated entities.
|
|
27
|
+
*/
|
|
12
28
|
export type Paths1<T> = T extends object ? {
|
|
13
29
|
[K in keyof T & string]: NonNullable<T[K]> extends infer U ? U extends object ? K | `${K}.${Paths1<U>}` : K : K;
|
|
14
30
|
}[keyof T & string] : never;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../src/runtime/paths.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAE1E,KAAK,mBAAmB,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,OAAO,GAAG,CAAC,CAAC,EAAE,CAAC,KAAK,IAAI,GAAG,KAAK,CAAC,SAAS,CACjF,CAAC,EAAE,MAAM,CAAC,KACP,IAAI,GACL,CAAC,GACD,KAAK,CAAA;AAET,KAAK,OAAO,CAAC,CAAC,EAAE,CAAC,SAAS,MAAM,IAAI,CAAC,SAAS,MAAM,CAAC,GAAG,MAAM,GAC1D,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,GACV,CAAC,SAAS,GAAG,MAAM,CAAC,IAAI,MAAM,CAAC,EAAE,GAC/B,CAAC,SAAS,MAAM,CAAC,GAAG,MAAM,GACxB,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,MAAM,CAAC,GAC/B,CAAC,SAAS,MAAM,GACd;KAAG,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC;CAAE,GAC3B,KAAK,GACP,KAAK,GACP,KAAK,GACP,KAAK,CAAA;AAEX,OAAO,CAAC,MAAM,WAAW,EAAE,OAAO,MAAM,CAAA;AAExC,2EAA2E;AAC3E,MAAM,MAAM,cAAc,CAAC,CAAC,EAAE,CAAC,SAAS,SAAS,MAAM,EAAE,IACvD,mBAAmB,CACjB,CAAC,CAAC,MAAM,CAAC,SAAS,MAAM,CAAC,GAAG,CAAC,CAAC,SAAS,MAAM,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAC/E,SAAS,MAAM,CAAC,GACb,CAAC,SAAS,MAAM,GACd,CAAC,GAAG;IAAE,QAAQ,CAAC,CAAC,WAAW,CAAC,EAAE,CAAC,CAAA;CAAE,GACjC,KAAK,GACP,KAAK,CAAA;AAEX
|
|
1
|
+
{"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../src/runtime/paths.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quadrokit/client",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.12",
|
|
4
4
|
"description": "Typed 4D REST client and catalog code generator for QuadroKit",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.mjs",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"generate:fixture": "bun run src/cli.ts generate --url file://../../assets/catalog.json --out ../../.quadrokit/generated-demo"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@quadrokit/shared": "^0.3.
|
|
32
|
+
"@quadrokit/shared": "^0.3.12",
|
|
33
33
|
"undici": "^6.21.0"
|
|
34
34
|
},
|
|
35
35
|
"peerDependencies": {
|