lazypock 0.8.0 → 0.8.2
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 +21 -0
- package/dist/{chunk-TBBHGOSH.js → chunk-V2XSEOWF.js} +40 -3
- package/dist/chunk-V2XSEOWF.js.map +1 -0
- package/dist/cli.cjs +39 -2
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.global.js +39 -2
- package/dist/cli.global.js.map +1 -1
- package/dist/cli.js +1 -1
- package/dist/index.cjs +51 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +5 -5
- package/dist/index.d.ts +5 -5
- package/dist/index.global.js +51 -7
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +13 -6
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/codegen.ts +69 -2
- package/src/collection.ts +15 -7
- package/src/http.ts +21 -7
- package/dist/chunk-TBBHGOSH.js.map +0 -1
package/src/codegen.ts
CHANGED
|
@@ -85,6 +85,19 @@ export function generateTypes(
|
|
|
85
85
|
body,
|
|
86
86
|
})}`,
|
|
87
87
|
);
|
|
88
|
+
|
|
89
|
+
// Write-only create data: what `create()`/`update()` accept. This
|
|
90
|
+
// intentionally includes password fields (and hidden fields) that are
|
|
91
|
+
// excluded from the read model — the server accepts them on write,
|
|
92
|
+
// hashes passwords, and never returns them in responses.
|
|
93
|
+
const createLines = fields
|
|
94
|
+
.map((f) => createDataMemberLine(f))
|
|
95
|
+
.filter((l) => l !== "");
|
|
96
|
+
sections.push(
|
|
97
|
+
`export interface ${typeName}CreateData${renderInterface({
|
|
98
|
+
body: createLines.join("\n"),
|
|
99
|
+
})}`,
|
|
100
|
+
);
|
|
88
101
|
}
|
|
89
102
|
|
|
90
103
|
// Auth collection type
|
|
@@ -104,6 +117,15 @@ export function generateTypes(
|
|
|
104
117
|
.join("\n");
|
|
105
118
|
sections.push(`export interface LazypockCollections {
|
|
106
119
|
${mapEntries}
|
|
120
|
+
}`);
|
|
121
|
+
|
|
122
|
+
// Create-data map — typed `create()`/`update()` payloads, including
|
|
123
|
+
// write-only password fields.
|
|
124
|
+
const createMapEntries = filtered
|
|
125
|
+
.map((c) => ` "${c.name}": ${collectionTypeName(c.name)}CreateData;`)
|
|
126
|
+
.join("\n");
|
|
127
|
+
sections.push(`export interface LazypockCreateData {
|
|
128
|
+
${createMapEntries}
|
|
107
129
|
}`);
|
|
108
130
|
|
|
109
131
|
// Runtime schema snapshot — lets the client exclude hidden fields by
|
|
@@ -135,6 +157,10 @@ ${schemaEntries}
|
|
|
135
157
|
* Collection access is fully type-checked:
|
|
136
158
|
* client.collection("posts").create({ title: "x" }) // title must exist
|
|
137
159
|
*
|
|
160
|
+
* For auth collections the generated *CreateData type includes the
|
|
161
|
+
* write-only password field, so creating a user is type-safe:
|
|
162
|
+
* client.collection("users").create({ email, password }) // ✓
|
|
163
|
+
*
|
|
138
164
|
* The schema snapshot is wired into the client automatically, so hidden
|
|
139
165
|
* fields are excluded from responses and select/expand are validated.
|
|
140
166
|
*/
|
|
@@ -154,8 +180,22 @@ export class TypedClient extends LazypockClient {
|
|
|
154
180
|
// are rejected at compile time:
|
|
155
181
|
// client.collection("posts") // suggested + typed
|
|
156
182
|
// client.collection("nope") // TS error
|
|
157
|
-
|
|
158
|
-
|
|
183
|
+
//
|
|
184
|
+
// create()/update() take the collection's *CreateData — the read model
|
|
185
|
+
// omits password/hidden fields, but the write model carries them.
|
|
186
|
+
// T extends string (rather than keyof LazypockCollections) with a conditional
|
|
187
|
+
// return type, so the IDE suggests collection names AND unknown/dynamic names
|
|
188
|
+
// still resolve to the untyped service — a studio that manages
|
|
189
|
+
// user-created collections must be able to call collection(someString).
|
|
190
|
+
//
|
|
191
|
+
// create()/update() take the collection's *CreateData — the read model
|
|
192
|
+
// omits password/hidden fields, but the write model carries them.
|
|
193
|
+
override collection<T extends string>(name: T): T extends keyof LazypockCollections
|
|
194
|
+
? CollectionService<LazypockCollections[T], LazypockCreateData[T]>
|
|
195
|
+
: CollectionService<unknown> {
|
|
196
|
+
return super.collection(name) as T extends keyof LazypockCollections
|
|
197
|
+
? CollectionService<LazypockCollections[T], LazypockCreateData[T]>
|
|
198
|
+
: CollectionService<unknown>;
|
|
159
199
|
}
|
|
160
200
|
}
|
|
161
201
|
`);
|
|
@@ -185,3 +225,30 @@ function memberLine(f: SchemaField): string {
|
|
|
185
225
|
if (type === "never") return "";
|
|
186
226
|
return ` ${JSON.stringify(key)}${req}: ${type};`;
|
|
187
227
|
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Render a write-only create-data member for a field.
|
|
231
|
+
*
|
|
232
|
+
* Unlike the read model, create/update data includes password fields (sent as
|
|
233
|
+
* plain strings — the server hashes them) and hidden fields: the server
|
|
234
|
+
* accepts them on write and never returns them in responses.
|
|
235
|
+
*
|
|
236
|
+
* A field is only marked required when it actually needs a client value:
|
|
237
|
+
* fields with a server-side default (`options.defaultValue`) and the auth
|
|
238
|
+
* system fields `verified` / `emailVisibility` (the server defaults them to
|
|
239
|
+
* false/true even though the snapshot doesn't carry `defaultValue`) stay
|
|
240
|
+
* optional, so `create({ email, password_hash })` typechecks without forcing
|
|
241
|
+
* callers to send values the server would fill in anyway.
|
|
242
|
+
*/
|
|
243
|
+
function createDataMemberLine(f: SchemaField): string {
|
|
244
|
+
// Autodate columns are server-managed; never writable.
|
|
245
|
+
if (f.type === "autodate") return "";
|
|
246
|
+
const key = fieldKey(f.name);
|
|
247
|
+
const serverDefaulted =
|
|
248
|
+
f.options?.defaultValue !== undefined ||
|
|
249
|
+
(f.system && (f.name === "verified" || f.name === "emailVisibility"));
|
|
250
|
+
const req = f.required && !serverDefaulted ? "" : "?";
|
|
251
|
+
const type = f.type === "password" ? "string" : fieldTypeScriptType(f);
|
|
252
|
+
if (type === "never") return "";
|
|
253
|
+
return ` ${JSON.stringify(key)}${req}: ${type};`;
|
|
254
|
+
}
|
package/src/collection.ts
CHANGED
|
@@ -90,7 +90,7 @@ function normalizeAction(
|
|
|
90
90
|
*
|
|
91
91
|
* @typeParam T — The record shape for this collection. Defaults to {@link ApiRecord}.
|
|
92
92
|
*/
|
|
93
|
-
export class CollectionService<T = ApiRecord> {
|
|
93
|
+
export class CollectionService<T = ApiRecord, TData = never> {
|
|
94
94
|
private http: HttpClient;
|
|
95
95
|
private collectionName: string;
|
|
96
96
|
private authStore?: AuthStore;
|
|
@@ -148,9 +148,9 @@ export class CollectionService<T = ApiRecord> {
|
|
|
148
148
|
* `fields` param — the server returns every non-password field.
|
|
149
149
|
* Pass `select("*")` to restore the default after a projection.
|
|
150
150
|
*/
|
|
151
|
-
select<K extends FieldKey<T> | "*">(...fields: K[]): CollectionService<T> {
|
|
151
|
+
select<K extends FieldKey<T> | "*">(...fields: K[]): CollectionService<T, TData> {
|
|
152
152
|
const preset = fields.length === 0 ? "*" : fields.join(",");
|
|
153
|
-
const derived = new CollectionService<T>(
|
|
153
|
+
const derived = new CollectionService<T, TData>(
|
|
154
154
|
this.http,
|
|
155
155
|
this.collectionName,
|
|
156
156
|
this.authStore,
|
|
@@ -390,7 +390,11 @@ export class CollectionService<T = ApiRecord> {
|
|
|
390
390
|
* @param options Optional request options.
|
|
391
391
|
*/
|
|
392
392
|
create(
|
|
393
|
-
data:
|
|
393
|
+
data: [TData] extends [never]
|
|
394
|
+
? T extends ApiRecord
|
|
395
|
+
? Record<string, unknown>
|
|
396
|
+
: CreateData<T>
|
|
397
|
+
: TData,
|
|
394
398
|
options?: RequestOptions,
|
|
395
399
|
): Promise<T | null> {
|
|
396
400
|
return this.http.post<T>(
|
|
@@ -409,7 +413,11 @@ export class CollectionService<T = ApiRecord> {
|
|
|
409
413
|
*/
|
|
410
414
|
update(
|
|
411
415
|
id: string,
|
|
412
|
-
data:
|
|
416
|
+
data: [TData] extends [never]
|
|
417
|
+
? T extends ApiRecord
|
|
418
|
+
? Record<string, unknown>
|
|
419
|
+
: UpdateData<T>
|
|
420
|
+
: Partial<TData>,
|
|
413
421
|
options?: RequestOptions,
|
|
414
422
|
): Promise<T | null> {
|
|
415
423
|
return this.http.patch<T>(
|
|
@@ -481,8 +489,8 @@ export class CollectionService<T = ApiRecord> {
|
|
|
481
489
|
* `types.schemas`). Enables schema-aware defaults: hidden fields are
|
|
482
490
|
* excluded from responses, select/expand are validated.
|
|
483
491
|
*/
|
|
484
|
-
withSchema(schema: CollectionSchema): CollectionService<T> {
|
|
485
|
-
const derived = new CollectionService<T>(
|
|
492
|
+
withSchema(schema: CollectionSchema): CollectionService<T, TData> {
|
|
493
|
+
const derived = new CollectionService<T, TData>(
|
|
486
494
|
this.http,
|
|
487
495
|
this.collectionName,
|
|
488
496
|
this.authStore,
|
package/src/http.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// Only relies on globalThis.fetch — works in browser, React Native, and Node 18+
|
|
3
3
|
|
|
4
4
|
import { ApiError, type Method, type RequestOptions } from "./types";
|
|
5
|
-
import type { AuthStore } from "./auth";
|
|
5
|
+
import type { AuthModel, AuthStore } from "./auth";
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Low-level HTTP client wrapping `fetch` with automatic auth token injection.
|
|
@@ -74,10 +74,10 @@ export class HttpClient {
|
|
|
74
74
|
}
|
|
75
75
|
const data = (await res.json()) as Record<string, unknown>;
|
|
76
76
|
if (data && typeof data.token === "string") {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
);
|
|
77
|
+
const record = data["record"];
|
|
78
|
+
const model: AuthModel | null =
|
|
79
|
+
record && typeof record === "object" ? (record as AuthModel) : null;
|
|
80
|
+
this.authStore.set(data.token, model);
|
|
81
81
|
return data as { token: string; record: Record<string, unknown> };
|
|
82
82
|
}
|
|
83
83
|
return null;
|
|
@@ -300,8 +300,22 @@ export class HttpClient {
|
|
|
300
300
|
if (bodyText) {
|
|
301
301
|
data = JSON.parse(bodyText) as Record<string, unknown>;
|
|
302
302
|
}
|
|
303
|
-
} catch {
|
|
304
|
-
//
|
|
303
|
+
} catch (err) {
|
|
304
|
+
// An abort that lands while the body is streaming (auto-cancelled
|
|
305
|
+
// duplicate, manual cancel, or external signal) means the whole
|
|
306
|
+
// request was cancelled — surface it as an abort error instead of
|
|
307
|
+
// silently returning an empty object, which callers would treat as
|
|
308
|
+
// a successful-but-empty response (e.g. a list request would clear
|
|
309
|
+
// the current rows).
|
|
310
|
+
if (isAbortError(err)) {
|
|
311
|
+
throw new ApiError(
|
|
312
|
+
"The request was aborted (most likely auto-cancelled by a newer request with the same requestKey)",
|
|
313
|
+
{},
|
|
314
|
+
0,
|
|
315
|
+
true,
|
|
316
|
+
);
|
|
317
|
+
}
|
|
318
|
+
// Not JSON / read failure — keep data as empty object
|
|
305
319
|
}
|
|
306
320
|
|
|
307
321
|
if (!res!.ok) {
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/typegen.ts","../src/codegen.ts"],"sourcesContent":["// ── Type mapping (runtime + codegen) ────────────────────\n// Maps server field types to TypeScript types.\n// Shared by the runtime `SchemaTypes` helper and the codegen CLI.\n\nimport type { SchemaField } from \"./schema\";\n\n/**\n * Map a single server field to its TypeScript type string.\n * Used by the codegen CLI to emit interface members.\n *\n * @param field The field definition.\n * @param fallback Fallback type for unknown field types (default `unknown`).\n */\nexport function fieldTypeScriptType(\n\tfield: SchemaField,\n\tfallback = \"unknown\",\n): string {\n\tconst opts = field.options ?? {};\n\tswitch (field.type) {\n\t\tcase \"text\":\n\t\tcase \"email\":\n\t\tcase \"url\":\n\t\tcase \"editor\":\n\t\tcase \"date\":\n\t\tcase \"datetime\":\n\t\t\treturn \"string\";\n\t\tcase \"number\":\n\t\t\treturn \"number\";\n\t\tcase \"bool\":\n\t\t\treturn \"boolean\";\n\t\tcase \"select\": {\n\t\t\tconst values = Array.isArray(opts.values) ? opts.values : [];\n\t\t\tif (values.length > 0) {\n\t\t\t\treturn values.map((v) => JSON.stringify(String(v))).join(\" | \");\n\t\t\t}\n\t\t\treturn \"string\";\n\t\t}\n\t\tcase \"multi_select\": {\n\t\t\tconst values = Array.isArray(opts.values) ? opts.values : [];\n\t\t\tif (values.length > 0) {\n\t\t\t\treturn `(${values.map((v) => JSON.stringify(String(v))).join(\" | \")})[]`;\n\t\t\t}\n\t\t\treturn \"string[]\";\n\t\t}\n\t\tcase \"file\":\n\t\t\treturn \"string\";\n\t\tcase \"multi_file\":\n\t\t\treturn \"string[]\";\n\t\tcase \"json\":\n\t\tcase \"geo\":\n\t\t\treturn \"Record<string, unknown>\";\n\t\tcase \"relation\":\n\t\t\t// Relations store the target record's ID (string) — or an array\n\t\t\t// of IDs when multi-relation (maxSelect > 1).\n\t\t\treturn (opts.maxSelect ?? 1) > 1 ? \"string[]\" : \"string\";\n\t\tcase \"password\":\n\t\t\t// Passwords are write-only; never expose on read models.\n\t\t\treturn \"never\";\n\t\tdefault:\n\t\t\treturn fallback;\n\t}\n}\n\n/**\n * Returns the runtime type kind for a field — used by {@link schemaFieldType}\n * to build structural types at runtime.\n */\nexport type FieldTypeKind =\n\t| \"string\"\n\t| \"number\"\n\t| \"boolean\"\n\t| \"string-array\"\n\t| \"json\"\n\t| \"relation\"\n\t| \"relation-many\"\n\t| \"password\"\n\t| \"unknown\";\n\n/** Map a server field to its runtime type kind. */\nexport function fieldTypeKind(field: SchemaField): FieldTypeKind {\n\tconst opts = field.options ?? {};\n\tswitch (field.type) {\n\t\tcase \"text\":\n\t\tcase \"email\":\n\t\tcase \"url\":\n\t\tcase \"editor\":\n\t\tcase \"date\":\n\t\tcase \"datetime\":\n\t\tcase \"select\":\n\t\tcase \"file\":\n\t\t\treturn \"string\";\n\t\tcase \"number\":\n\t\t\treturn \"number\";\n\t\tcase \"bool\":\n\t\t\treturn \"boolean\";\n\t\tcase \"multi_select\":\n\t\tcase \"multi_file\":\n\t\t\treturn \"string-array\";\n\t\tcase \"json\":\n\t\tcase \"geo\":\n\t\t\treturn \"json\";\n\t\tcase \"relation\":\n\t\t\treturn (opts.maxSelect ?? 1) > 1 ? \"relation-many\" : \"relation\";\n\t\tcase \"password\":\n\t\t\treturn \"password\";\n\t\tdefault:\n\t\t\treturn \"unknown\";\n\t}\n}\n\n/**\n * Derive a TypeScript field type from a {@link SchemaField} — the runtime\n * counterpart to the codegen mapper. Lets consumers build typed clients\n * from a fetched schema without running the CLI.\n */\nexport function schemaFieldType(field: SchemaField): unknown {\n\tswitch (fieldTypeKind(field)) {\n\t\tcase \"string\":\n\t\t\treturn String;\n\t\tcase \"number\":\n\t\t\treturn Number;\n\t\tcase \"boolean\":\n\t\t\treturn Boolean;\n\t\tcase \"string-array\":\n\t\t\treturn [String] as const;\n\t\tcase \"relation\":\n\t\t\treturn String;\n\t\tcase \"relation-many\":\n\t\t\treturn [String] as const;\n\t\tcase \"json\":\n\t\t\treturn Object;\n\t\tcase \"password\":\n\t\t\treturn undefined;\n\t\tcase \"unknown\":\n\t\t\treturn undefined;\n\t}\n}\n","// ── Codegen ─────────────────────────────────────────────\n// Generates a `lazypock.types.ts` module from the live API schema.\n//\n// The generated file exports:\n// - One interface per collection (e.g. `PostsRecord`)\n// - A `LazypockCollections` map: { posts: PostsRecord; users: UsersRecord; ... }\n// - A `createClient()` factory pre-bound to those types, so\n// `client.collection(\"posts\").create({ title: \"x\" })` is fully type-checked.\n//\n// The CLI in `src/cli.ts` wires this to `GET /collections`.\n\nimport type { CollectionSchema, SchemaField } from \"./schema\";\nimport { fieldTypeScriptType } from \"./typegen\";\n\n/** Format a raw collection name into a valid TS identifier (PascalCase). */\nexport function collectionTypeName(name: string): string {\n\treturn name\n\t\t.split(/[^a-zA-Z0-9]+/)\n\t\t.filter(Boolean)\n\t\t.map((part) => part.charAt(0).toUpperCase() + part.slice(1))\n\t\t.join(\"\")\n\t\t.replace(/^[0-9]/, \"_$&\");\n}\n\n/** Interface member name — sanitize hyphens/spaces but keep readability. */\nexport function fieldKey(name: string): string {\n\treturn name.replace(/[^a-zA-Z0-9_]/g, \"_\");\n}\n\n\n\n/**\n * Generate the full TypeScript source for the typed SDK module.\n *\n * @param collections Collections fetched from the API.\n * @param options Generation options.\n */\nexport function generateTypes(\n\tcollections: CollectionSchema[],\n\toptions: {\n\t\t/** Import specifier for the lazypock package (default `lazypock`). */\n\t\tpackageName?: string;\n\t\t/** Emit base record fields (id, created, updated, …). Default true. */\n\t\tincludeBaseFields?: boolean;\n\t\t/** Skip system collections (names starting with `_` or `users`). Default false. */\n\t\tskipSystem?: boolean;\n\t} = {},\n): string {\n\tconst {\n\t\tpackageName = \"lazypock\",\n\t\tincludeBaseFields = true,\n\t\tskipSystem = false,\n\t} = options;\n\n\tconst filtered = skipSystem\n\t\t? collections.filter(\n\t\t\t\t(c) => !c.system && !c.name.startsWith(\"_\") && c.name !== \"users\",\n\t\t\t)\n\t\t: collections;\n\n\tconst sections: string[] = [];\n\tsections.push(`// ── Auto-generated by lazypock-ts ──────────────────────────\n// Do not edit by hand. Regenerate with: npx lazypock-gen\n// Schema snapshot: ${new Date().toISOString()}`);\n\n\tif (includeBaseFields) {\n\t\tsections.push(`export interface BaseRecord {\n id: string;\n collectionId: string;\n collectionName: string;\n created: string;\n updated: string;\n}`);\n\t}\n\n\t// One interface per collection\n\tfor (const coll of filtered) {\n\t\tconst typeName = collectionTypeName(coll.name);\n\t\tconst fields = coll.fields ?? [];\n\t\tconst lines = fields.map((f) => memberLine(f)).filter((l) => l !== \"\");\n\t\tconst body = lines.join(\"\\n\");\n\t\tsections.push(\n\t\t\t`export interface ${typeName}Record${renderInterface({\n\t\t\t\textends: includeBaseFields ? \"BaseRecord\" : undefined,\n\t\t\t\tbody,\n\t\t\t})}`,\n\t\t);\n\t}\n\n\t// Auth collection type\n\tsections.push(`export interface AuthRecord extends BaseRecord {\n email: string;\n verified: boolean;\n}`);\n\n\t// Collections map\n\tconst mapEntries = filtered\n\t\t.map(\n\t\t\t(c) =>\n\t\t\t\t` \"${c.name}\": ${collectionTypeName(c.name)}Record${\n\t\t\t\t\tc.type === \"auth\" ? \" & AuthRecord\" : \"\"\n\t\t\t\t};`,\n\t\t)\n\t\t.join(\"\\n\");\n\tsections.push(`export interface LazypockCollections {\n${mapEntries}\n}`);\n\n\t// Runtime schema snapshot — lets the client exclude hidden fields by\n\t// default, validate select/expand, and derive visible field lists.\n\tconst schemaEntries = collections\n\t\t.map(\n\t\t\t(c) =>\n\t\t\t\t` {\n id: ${JSON.stringify(c.id ?? null)},\n name: ${JSON.stringify(c.name)},\n type: ${JSON.stringify(c.type)},\n system: ${JSON.stringify(c.system ?? false)},\n fields: ${JSON.stringify(c.fields ?? [], null, 2)},\n rules: ${JSON.stringify(c.rules ?? {})},\n options: ${JSON.stringify(c.options ?? {})},\n }`,\n\t\t)\n\t\t.join(\",\\n\");\n\tsections.push(`// Schema snapshot (runtime) — hidden-field exclusion + query validation.\nexport const lazypockSchema: import(\"${packageName}\").CollectionSchema[] = [\n${schemaEntries}\n];`);\n\n\t// createClient factory\n\tsections.push(`import { LazypockClient, type LazypockClientOptions, type CollectionService } from \"${packageName}\";\n\n/**\n * Create a Lazypock client typed against this schema snapshot.\n * Collection access is fully type-checked:\n * client.collection(\"posts\").create({ title: \"x\" }) // title must exist\n *\n * The schema snapshot is wired into the client automatically, so hidden\n * fields are excluded from responses and select/expand are validated.\n */\nexport function createClient(options: LazypockClientOptions): TypedClient {\n return new TypedClient({\n ...options,\n types: {\n ...options.types,\n schemas: options.types?.schemas ?? lazypockSchema,\n },\n });\n}\n\nexport class TypedClient extends LazypockClient {\n // K extends keyof LazypockCollections (rather than a generic string with a\n // conditional return) so the IDE suggests collection names and unknown names\n // are rejected at compile time:\n // client.collection(\"posts\") // suggested + typed\n // client.collection(\"nope\") // TS error\n override collection<K extends keyof LazypockCollections>(name: K): CollectionService<LazypockCollections[K]> {\n return super.collection(name) as CollectionService<LazypockCollections[K]>;\n }\n}\n`);\n\n\treturn sections.join(\"\\n\\n\") + \"\\n\";\n}\n\n/**\n * Render the interface body including the extends clause.\n * Empty body → ` extends BaseRecord {}` (valid TS).\n */\nfunction renderInterface(opts: { extends?: string; body: string }): string {\n\tconst ext = opts.extends ? ` extends ${opts.extends}` : \"\";\n\tif (!opts.body) return `${ext} {}`;\n\treturn `${ext} {\\n${opts.body}\\n}`;\n}\n\n/** Render a single interface member line for a field. */\nfunction memberLine(f: SchemaField): string {\n\t// Hidden fields are excluded from API responses by the schema-aware\n\t// client default — don't expose them on the read model either.\n\tif (f.hidden) return \"\";\n\tconst key = fieldKey(f.name);\n\tconst req = f.required || f.type === \"password\" ? \"\" : \"?\";\n\tconst type = fieldTypeScriptType(f);\n\t// `never` members (passwords) are omitted from read models.\n\tif (type === \"never\") return \"\";\n\treturn ` ${JSON.stringify(key)}${req}: ${type};`;\n}\n"],"mappings":";AAaO,SAAS,oBACf,OACA,WAAW,WACF;AACT,QAAM,OAAO,MAAM,WAAW,CAAC;AAC/B,UAAQ,MAAM,MAAM;AAAA,IACnB,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACJ,aAAO;AAAA,IACR,KAAK;AACJ,aAAO;AAAA,IACR,KAAK;AACJ,aAAO;AAAA,IACR,KAAK,UAAU;AACd,YAAM,SAAS,MAAM,QAAQ,KAAK,MAAM,IAAI,KAAK,SAAS,CAAC;AAC3D,UAAI,OAAO,SAAS,GAAG;AACtB,eAAO,OAAO,IAAI,CAAC,MAAM,KAAK,UAAU,OAAO,CAAC,CAAC,CAAC,EAAE,KAAK,KAAK;AAAA,MAC/D;AACA,aAAO;AAAA,IACR;AAAA,IACA,KAAK,gBAAgB;AACpB,YAAM,SAAS,MAAM,QAAQ,KAAK,MAAM,IAAI,KAAK,SAAS,CAAC;AAC3D,UAAI,OAAO,SAAS,GAAG;AACtB,eAAO,IAAI,OAAO,IAAI,CAAC,MAAM,KAAK,UAAU,OAAO,CAAC,CAAC,CAAC,EAAE,KAAK,KAAK,CAAC;AAAA,MACpE;AACA,aAAO;AAAA,IACR;AAAA,IACA,KAAK;AACJ,aAAO;AAAA,IACR,KAAK;AACJ,aAAO;AAAA,IACR,KAAK;AAAA,IACL,KAAK;AACJ,aAAO;AAAA,IACR,KAAK;AAGJ,cAAQ,KAAK,aAAa,KAAK,IAAI,aAAa;AAAA,IACjD,KAAK;AAEJ,aAAO;AAAA,IACR;AACC,aAAO;AAAA,EACT;AACD;AAkBO,SAAS,cAAc,OAAmC;AAChE,QAAM,OAAO,MAAM,WAAW,CAAC;AAC/B,UAAQ,MAAM,MAAM;AAAA,IACnB,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACJ,aAAO;AAAA,IACR,KAAK;AACJ,aAAO;AAAA,IACR,KAAK;AACJ,aAAO;AAAA,IACR,KAAK;AAAA,IACL,KAAK;AACJ,aAAO;AAAA,IACR,KAAK;AAAA,IACL,KAAK;AACJ,aAAO;AAAA,IACR,KAAK;AACJ,cAAQ,KAAK,aAAa,KAAK,IAAI,kBAAkB;AAAA,IACtD,KAAK;AACJ,aAAO;AAAA,IACR;AACC,aAAO;AAAA,EACT;AACD;AAOO,SAAS,gBAAgB,OAA6B;AAC5D,UAAQ,cAAc,KAAK,GAAG;AAAA,IAC7B,KAAK;AACJ,aAAO;AAAA,IACR,KAAK;AACJ,aAAO;AAAA,IACR,KAAK;AACJ,aAAO;AAAA,IACR,KAAK;AACJ,aAAO,CAAC,MAAM;AAAA,IACf,KAAK;AACJ,aAAO;AAAA,IACR,KAAK;AACJ,aAAO,CAAC,MAAM;AAAA,IACf,KAAK;AACJ,aAAO;AAAA,IACR,KAAK;AACJ,aAAO;AAAA,IACR,KAAK;AACJ,aAAO;AAAA,EACT;AACD;;;ACzHO,SAAS,mBAAmB,MAAsB;AACxD,SAAO,KACL,MAAM,eAAe,EACrB,OAAO,OAAO,EACd,IAAI,CAAC,SAAS,KAAK,OAAO,CAAC,EAAE,YAAY,IAAI,KAAK,MAAM,CAAC,CAAC,EAC1D,KAAK,EAAE,EACP,QAAQ,UAAU,KAAK;AAC1B;AAGO,SAAS,SAAS,MAAsB;AAC9C,SAAO,KAAK,QAAQ,kBAAkB,GAAG;AAC1C;AAUO,SAAS,cACf,aACA,UAOI,CAAC,GACI;AACT,QAAM;AAAA,IACL,cAAc;AAAA,IACd,oBAAoB;AAAA,IACpB,aAAa;AAAA,EACd,IAAI;AAEJ,QAAM,WAAW,aACd,YAAY;AAAA,IACZ,CAAC,MAAM,CAAC,EAAE,UAAU,CAAC,EAAE,KAAK,WAAW,GAAG,KAAK,EAAE,SAAS;AAAA,EAC3D,IACC;AAEH,QAAM,WAAqB,CAAC;AAC5B,WAAS,KAAK;AAAA;AAAA,uBAEO,oBAAI,KAAK,GAAE,YAAY,CAAC,EAAE;AAE/C,MAAI,mBAAmB;AACtB,aAAS,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMd;AAAA,EACD;AAGA,aAAW,QAAQ,UAAU;AAC5B,UAAM,WAAW,mBAAmB,KAAK,IAAI;AAC7C,UAAM,SAAS,KAAK,UAAU,CAAC;AAC/B,UAAM,QAAQ,OAAO,IAAI,CAAC,MAAM,WAAW,CAAC,CAAC,EAAE,OAAO,CAAC,MAAM,MAAM,EAAE;AACrE,UAAM,OAAO,MAAM,KAAK,IAAI;AAC5B,aAAS;AAAA,MACR,oBAAoB,QAAQ,SAAS,gBAAgB;AAAA,QACpD,SAAS,oBAAoB,eAAe;AAAA,QAC5C;AAAA,MACD,CAAC,CAAC;AAAA,IACH;AAAA,EACD;AAGA,WAAS,KAAK;AAAA;AAAA;AAAA,EAGb;AAGD,QAAM,aAAa,SACjB;AAAA,IACA,CAAC,MACA,MAAM,EAAE,IAAI,MAAM,mBAAmB,EAAE,IAAI,CAAC,SAC3C,EAAE,SAAS,SAAS,kBAAkB,EACvC;AAAA,EACF,EACC,KAAK,IAAI;AACX,WAAS,KAAK;AAAA,EACb,UAAU;AAAA,EACV;AAID,QAAM,gBAAgB,YACpB;AAAA,IACA,CAAC,MACA;AAAA,UACM,KAAK,UAAU,EAAE,MAAM,IAAI,CAAC;AAAA,YAC1B,KAAK,UAAU,EAAE,IAAI,CAAC;AAAA,YACtB,KAAK,UAAU,EAAE,IAAI,CAAC;AAAA,cACpB,KAAK,UAAU,EAAE,UAAU,KAAK,CAAC;AAAA,cACjC,KAAK,UAAU,EAAE,UAAU,CAAC,GAAG,MAAM,CAAC,CAAC;AAAA,aACxC,KAAK,UAAU,EAAE,SAAS,CAAC,CAAC,CAAC;AAAA,eAC3B,KAAK,UAAU,EAAE,WAAW,CAAC,CAAC,CAAC;AAAA;AAAA,EAE5C,EACC,KAAK,KAAK;AACZ,WAAS,KAAK;AAAA,uCACwB,WAAW;AAAA,EAChD,aAAa;AAAA,GACZ;AAGF,WAAS,KAAK,uFAAuF,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CA8BhH;AAEA,SAAO,SAAS,KAAK,MAAM,IAAI;AAChC;AAMA,SAAS,gBAAgB,MAAkD;AAC1E,QAAM,MAAM,KAAK,UAAU,YAAY,KAAK,OAAO,KAAK;AACxD,MAAI,CAAC,KAAK,KAAM,QAAO,GAAG,GAAG;AAC7B,SAAO,GAAG,GAAG;AAAA,EAAO,KAAK,IAAI;AAAA;AAC9B;AAGA,SAAS,WAAW,GAAwB;AAG3C,MAAI,EAAE,OAAQ,QAAO;AACrB,QAAM,MAAM,SAAS,EAAE,IAAI;AAC3B,QAAM,MAAM,EAAE,YAAY,EAAE,SAAS,aAAa,KAAK;AACvD,QAAM,OAAO,oBAAoB,CAAC;AAElC,MAAI,SAAS,QAAS,QAAO;AAC7B,SAAO,KAAK,KAAK,UAAU,GAAG,CAAC,GAAG,GAAG,KAAK,IAAI;AAC/C;","names":[]}
|