@cms0/cms0 0.0.9 → 0.0.11

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.
@@ -1,80 +1,643 @@
1
1
  "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createCmsClient = createCmsClient;
36
4
  exports.cms0 = cms0;
37
5
  const schema_descriptors_1 = require("@cms0/cms0/schema-descriptors");
38
- const Shared = __importStar(require("@cms0/shared"));
39
- /**
40
- * Initializes the CMS SDK for a given schema.
41
- * @param config configuration including API base URL or database URL.
42
- * @returns an object with typed accessors matching the schema.
43
- */
44
- function cms0(config) {
45
- const baseUrl = config.apiConfig?.baseUrl?.replace(/\/$/, "") ?? "";
46
- const apiKey = config.apiConfig?.key;
47
- return new Proxy({}, {
48
- get(target, prop) {
49
- if (!(prop in schema_descriptors_1.schemaDescriptor.roots)) {
50
- throw new Error(`Unknown schema key '${prop}'`);
6
+ const shared_1 = require("@cms0/shared");
7
+ const COLLECTION_SHAPE_ERROR = "Invalid collection response. Expected array or { items, total }.";
8
+ function toPlainText(value) {
9
+ if (typeof value === "string")
10
+ return value;
11
+ if (typeof value === "number" || typeof value === "boolean")
12
+ return String(value);
13
+ if (!value || typeof value !== "object")
14
+ return "";
15
+ const node = value;
16
+ if (typeof node.text === "string")
17
+ return node.text;
18
+ if ("value" in node)
19
+ return toPlainText(node.value);
20
+ if (Array.isArray(node.content)) {
21
+ return node.content
22
+ .map((child) => toPlainText(child))
23
+ .filter(Boolean)
24
+ .join(" ")
25
+ .trim();
26
+ }
27
+ return "";
28
+ }
29
+ function coerceRichTextValue(value) {
30
+ const source = value && typeof value === "object" ? value : {};
31
+ const nested = source.value && typeof source.value === "object"
32
+ ? source.value
33
+ : null;
34
+ const normalizedValue = source.value !== undefined ? source.value : value ?? {};
35
+ const html = typeof source.html === "string"
36
+ ? source.html
37
+ : typeof nested?.html === "string"
38
+ ? nested.html
39
+ : "";
40
+ return {
41
+ value: normalizedValue ?? {},
42
+ html,
43
+ };
44
+ }
45
+ function shouldKeepLocalizedEntry(source, locale, defaultLocale) {
46
+ if (locale === "all")
47
+ return true;
48
+ const rowLocale = typeof source.locale === "string" ? source.locale : "";
49
+ if (locale) {
50
+ return rowLocale === locale;
51
+ }
52
+ if (defaultLocale) {
53
+ return rowLocale === defaultLocale;
54
+ }
55
+ return true;
56
+ }
57
+ function coerceLocalizedStringValue(value, locale, defaultLocale) {
58
+ const rows = Array.isArray(value) ? value : [];
59
+ return rows
60
+ .map((row) => {
61
+ const source = row && typeof row === "object" ? row : {};
62
+ return {
63
+ ...source,
64
+ locale: typeof source.locale === "string" ? source.locale : "",
65
+ isDefault: source.isDefault === true,
66
+ value: toPlainText(source.value),
67
+ };
68
+ })
69
+ .filter((row) => shouldKeepLocalizedEntry(row, locale, defaultLocale));
70
+ }
71
+ function coerceLocalizedRichTextValue(value, locale, defaultLocale) {
72
+ const rows = Array.isArray(value) ? value : [];
73
+ return rows
74
+ .map((row) => {
75
+ const source = row && typeof row === "object" ? row : {};
76
+ const rawValue = source.value;
77
+ const nested = rawValue && typeof rawValue === "object" ? rawValue : null;
78
+ const normalizedValue = nested && "value" in nested && nested.value !== undefined
79
+ ? nested.value
80
+ : rawValue ?? {};
81
+ const html = typeof source.html === "string"
82
+ ? source.html
83
+ : typeof nested?.html === "string"
84
+ ? nested.html
85
+ : "";
86
+ return {
87
+ ...source,
88
+ locale: typeof source.locale === "string" ? source.locale : "",
89
+ isDefault: source.isDefault === true,
90
+ value: normalizedValue ?? {},
91
+ html,
92
+ };
93
+ })
94
+ .filter((row) => shouldKeepLocalizedEntry(row, locale, defaultLocale));
95
+ }
96
+ function coerceCustomTypeValue(descriptor, value, options) {
97
+ const customType = descriptor.customType;
98
+ if (!customType)
99
+ return value;
100
+ if (customType === "RichText")
101
+ return coerceRichTextValue(value);
102
+ if (customType === "LocalizedString") {
103
+ return coerceLocalizedStringValue(value, options?.locale, options?.defaultLocale);
104
+ }
105
+ if (customType === "LocalizedRichText") {
106
+ return coerceLocalizedRichTextValue(value, options?.locale, options?.defaultLocale);
107
+ }
108
+ return value;
109
+ }
110
+ function isPrimitiveDescriptor(desc) {
111
+ return desc.kind === "primitive";
112
+ }
113
+ function isModelRefDescriptor(desc) {
114
+ return desc.kind === "modelRef";
115
+ }
116
+ function isObjectDescriptor(desc) {
117
+ return desc.type === "object" && !!desc.properties;
118
+ }
119
+ function isArrayDescriptor(desc) {
120
+ return desc.type === "array" && !!desc.items;
121
+ }
122
+ function asModelObjectDescriptor(modelName, descriptor) {
123
+ const model = descriptor.models?.[modelName];
124
+ if (!model) {
125
+ throw new Error(`Unknown model '${modelName}' in schema descriptor.`);
126
+ }
127
+ return {
128
+ type: "object",
129
+ properties: model.properties,
130
+ optional: false,
131
+ nullable: false,
132
+ };
133
+ }
134
+ function normalizeBaseUrl(baseUrl) {
135
+ const cleaned = baseUrl?.trim().replace(/\/$/, "") ?? "";
136
+ if (!cleaned) {
137
+ throw new Error("cms0: apiConfig.baseUrl is required to consume API resources.");
138
+ }
139
+ return cleaned;
140
+ }
141
+ function resolveIncludeIdMode(includeId) {
142
+ if (includeId === true)
143
+ return "all";
144
+ if (includeId === false)
145
+ return "none";
146
+ return "collections";
147
+ }
148
+ function shouldIncludeObjectId(mode, isCollectionItem) {
149
+ if (mode === "all")
150
+ return true;
151
+ if (mode === "collections")
152
+ return isCollectionItem;
153
+ return false;
154
+ }
155
+ function buildSearchParams(query) {
156
+ const params = new URLSearchParams();
157
+ if (!query)
158
+ return params;
159
+ for (const [key, rawValue] of Object.entries(query)) {
160
+ if (rawValue === undefined || rawValue === null)
161
+ continue;
162
+ if (Array.isArray(rawValue)) {
163
+ rawValue.forEach((value) => {
164
+ if (value === undefined || value === null)
165
+ return;
166
+ params.append(key, String(value));
167
+ });
168
+ continue;
169
+ }
170
+ params.set(key, String(rawValue));
171
+ }
172
+ return params;
173
+ }
174
+ function ensureCollectionEnvelope(data, path) {
175
+ if (Array.isArray(data)) {
176
+ return { items: data, total: data.length };
177
+ }
178
+ if (data && typeof data === "object" && Array.isArray(data.items)) {
179
+ return {
180
+ items: data.items,
181
+ total: Number(data.total ?? data.items.length ?? 0),
182
+ };
183
+ }
184
+ throw new Error(`${COLLECTION_SHAPE_ERROR} Path: '${path}'.`);
185
+ }
186
+ function extractId(value) {
187
+ if (typeof value === "string" && value.length > 0)
188
+ return value;
189
+ if (value && typeof value === "object" && typeof value.id === "string") {
190
+ return value.id;
191
+ }
192
+ return null;
193
+ }
194
+ function capitalize(input) {
195
+ return input ? input[0].toUpperCase() + input.slice(1) : input;
196
+ }
197
+ function lowerFirst(input) {
198
+ return input ? input[0].toLowerCase() + input.slice(1) : input;
199
+ }
200
+ function camelCaseModelIdKey(modelName) {
201
+ return `${lowerFirst(modelName)}Id`;
202
+ }
203
+ function snakeCaseModelIdKey(modelName) {
204
+ const snake = modelName
205
+ .replace(/([a-z0-9])([A-Z])/g, "$1_$2")
206
+ .replace(/\s+/g, "_")
207
+ .toLowerCase();
208
+ return `${snake}_id`;
209
+ }
210
+ function extractModelRefId(raw, modelName, options) {
211
+ if (typeof raw === "string")
212
+ return raw;
213
+ if (!raw || typeof raw !== "object")
214
+ return null;
215
+ const object = raw;
216
+ const prop = options?.propertyName ?? "";
217
+ const candidates = [
218
+ camelCaseModelIdKey(modelName),
219
+ snakeCaseModelIdKey(modelName),
220
+ prop ? `${prop}Id` : "",
221
+ prop
222
+ ? `${prop.replace(/([a-z0-9])([A-Z])/g, "$1_$2").toLowerCase()}_id`
223
+ : "",
224
+ "value",
225
+ ].filter(Boolean);
226
+ for (const key of candidates) {
227
+ const found = extractId(object[key]);
228
+ if (found)
229
+ return found;
230
+ }
231
+ const byId = extractId(object);
232
+ if (byId)
233
+ return byId;
234
+ return null;
235
+ }
236
+ function formatValidationError(name, error) {
237
+ const payload = error && typeof error === "object" && "format" in error
238
+ ? error.format()
239
+ : error;
240
+ return `Invalid data received for '${name}': ${JSON.stringify(payload)}`;
241
+ }
242
+ function levenshtein(a, b) {
243
+ if (a === b)
244
+ return 0;
245
+ if (!a.length)
246
+ return b.length;
247
+ if (!b.length)
248
+ return a.length;
249
+ const rows = a.length + 1;
250
+ const cols = b.length + 1;
251
+ const matrix = Array.from({ length: rows }, () => new Array(cols).fill(0));
252
+ for (let i = 0; i < rows; i++)
253
+ matrix[i][0] = i;
254
+ for (let j = 0; j < cols; j++)
255
+ matrix[0][j] = j;
256
+ for (let i = 1; i < rows; i++) {
257
+ for (let j = 1; j < cols; j++) {
258
+ const cost = a[i - 1] === b[j - 1] ? 0 : 1;
259
+ matrix[i][j] = Math.min(matrix[i - 1][j] + 1, matrix[i][j - 1] + 1, matrix[i - 1][j - 1] + cost);
260
+ }
261
+ }
262
+ return matrix[rows - 1][cols - 1];
263
+ }
264
+ function unknownKeyError(key, roots, models) {
265
+ const candidates = [...roots, ...models];
266
+ const normalized = key.toLowerCase();
267
+ const suggestions = candidates
268
+ .map((candidate) => ({
269
+ candidate,
270
+ distance: levenshtein(normalized, candidate.toLowerCase()),
271
+ }))
272
+ .sort((a, b) => a.distance - b.distance)
273
+ .slice(0, 3)
274
+ .map((entry) => entry.candidate);
275
+ const suggestionText = suggestions.length
276
+ ? ` Did you mean: ${suggestions.join(", ")}?`
277
+ : "";
278
+ const rootsText = `Available roots: [${roots.join(", ")}]`;
279
+ const modelsText = models.length
280
+ ? `, models (under data.models.*): [${models.join(", ")}]`
281
+ : "";
282
+ throw new Error(`Unknown schema key '${key}'. ${rootsText}${modelsText}.${suggestionText}`);
283
+ }
284
+ async function normalizeModelRef(modelName, id, context, trail, isCollectionItem) {
285
+ if (!id)
286
+ return null;
287
+ if (!context.options.resolveModelRefs)
288
+ return id;
289
+ const nodeKey = `${modelName}:${id}`;
290
+ if (trail.has(nodeKey)) {
291
+ return shouldIncludeObjectId(context.options.includeIdMode, isCollectionItem)
292
+ ? { id }
293
+ : id;
294
+ }
295
+ const modelDescriptor = context.modelDescriptors.get(modelName);
296
+ if (!modelDescriptor) {
297
+ return id;
298
+ }
299
+ const cached = context.modelCache.get(nodeKey);
300
+ if (cached) {
301
+ return cached;
302
+ }
303
+ const nextTrail = new Set(trail);
304
+ nextTrail.add(nodeKey);
305
+ const promise = (async () => {
306
+ const rawModel = await context.requestJson(`models/${modelName}/${id}`, {
307
+ query: {
308
+ raw: 1,
309
+ ...(context.options.locale ? { locale: context.options.locale } : {}),
310
+ },
311
+ });
312
+ return normalizeField(modelDescriptor, `models/${modelName}/${encodeURIComponent(id)}`, rawModel, context, nextTrail, isCollectionItem);
313
+ })().catch((error) => {
314
+ context.modelCache.delete(nodeKey);
315
+ throw error;
316
+ });
317
+ context.modelCache.set(nodeKey, promise);
318
+ return promise;
319
+ }
320
+ async function normalizeObjectField(descriptor, path, raw, context, trail, isCollectionItem) {
321
+ const source = raw && typeof raw === "object" ? raw : {};
322
+ const output = {};
323
+ for (const [propertyName, propertyDescriptor] of Object.entries(descriptor.properties)) {
324
+ if (isPrimitiveDescriptor(propertyDescriptor)) {
325
+ output[propertyName] = coerceCustomTypeValue(propertyDescriptor, source[propertyName], {
326
+ locale: context.options.locale,
327
+ defaultLocale: context.options.defaultLocale,
328
+ });
329
+ continue;
330
+ }
331
+ if (isModelRefDescriptor(propertyDescriptor)) {
332
+ const refId = extractModelRefId(source, propertyDescriptor.model, {
333
+ propertyName,
334
+ });
335
+ output[propertyName] = await normalizeModelRef(propertyDescriptor.model, refId, context, trail, false);
336
+ continue;
337
+ }
338
+ if (isArrayDescriptor(propertyDescriptor)) {
339
+ const childPath = `${path}/${propertyName}`;
340
+ const childRaw = await context.requestJson(childPath, {
341
+ query: {
342
+ raw: 1,
343
+ ...(context.options.locale ? { locale: context.options.locale } : {}),
344
+ },
345
+ });
346
+ const normalizedChild = await normalizeArrayField(propertyDescriptor, childPath, childRaw, context, trail);
347
+ output[propertyName] = coerceCustomTypeValue(propertyDescriptor, normalizedChild, {
348
+ locale: context.options.locale,
349
+ defaultLocale: context.options.defaultLocale,
350
+ });
351
+ continue;
352
+ }
353
+ if (isObjectDescriptor(propertyDescriptor)) {
354
+ const childPath = `${path}/${propertyName}`;
355
+ const childRaw = await context.requestJson(childPath, {
356
+ query: {
357
+ raw: 1,
358
+ ...(context.options.locale ? { locale: context.options.locale } : {}),
359
+ },
360
+ });
361
+ const normalizedChild = await normalizeObjectField(propertyDescriptor, childPath, childRaw, context, trail, false);
362
+ output[propertyName] = coerceCustomTypeValue(propertyDescriptor, normalizedChild, {
363
+ locale: context.options.locale,
364
+ defaultLocale: context.options.defaultLocale,
365
+ });
366
+ }
367
+ }
368
+ if (shouldIncludeObjectId(context.options.includeIdMode, isCollectionItem)) {
369
+ const rowId = extractId(source);
370
+ if (rowId)
371
+ output.id = rowId;
372
+ }
373
+ return output;
374
+ }
375
+ async function normalizeArrayField(descriptor, path, raw, context, trail) {
376
+ const envelope = ensureCollectionEnvelope(raw, path);
377
+ const itemDescriptor = descriptor.items;
378
+ if (isPrimitiveDescriptor(itemDescriptor)) {
379
+ return envelope.items.map((row) => {
380
+ const value = row && typeof row === "object" && "value" in row
381
+ ? row.value
382
+ : row;
383
+ if (context.options.includeIdMode !== "all") {
384
+ return value;
51
385
  }
52
- return async () => {
53
- const url = `${baseUrl}/${prop}`;
54
- const res = await fetch(url, {
55
- method: "GET",
56
- headers: {
57
- "Content-Type": "application/json",
58
- ...(apiKey ? { Authorization: `Bearer ${apiKey}` } : {}),
59
- },
60
- });
61
- if (!res.ok) {
62
- throw new Error(`Request failed for '${prop}' with status ${res.status}: ${res.statusText}`);
63
- }
64
- const data = await res.json();
65
- // Validate via Zod
66
- const { zodSchemas } = Shared.buildZodSchemasFromDescriptor(schema_descriptors_1.schemaDescriptor);
67
- const schema = zodSchemas[prop];
68
- if (!schema) {
69
- // If no schema found, return the raw data
70
- return data;
71
- }
72
- const result = schema.safeParse(data);
73
- if (!result.success) {
74
- throw new Error(`Invalid data received for '${prop}': ${JSON.stringify(result.error.format())}`);
75
- }
76
- return result.data;
386
+ const id = extractId(row);
387
+ return id ? { id, value } : value;
388
+ });
389
+ }
390
+ if (isModelRefDescriptor(itemDescriptor)) {
391
+ const resolved = await Promise.all(envelope.items.map(async (row) => {
392
+ const refId = extractModelRefId(row, itemDescriptor.model);
393
+ return normalizeModelRef(itemDescriptor.model, refId, context, trail, true);
394
+ }));
395
+ return resolved;
396
+ }
397
+ if (isObjectDescriptor(itemDescriptor)) {
398
+ return Promise.all(envelope.items.map(async (row) => {
399
+ const rowId = extractId(row);
400
+ const rowPath = rowId
401
+ ? `${path}/${encodeURIComponent(rowId)}`
402
+ : path;
403
+ return normalizeObjectField(itemDescriptor, rowPath, row, context, trail, true);
404
+ }));
405
+ }
406
+ return envelope.items;
407
+ }
408
+ async function normalizeField(descriptor, path, raw, context, trail, isCollectionItem) {
409
+ if (isPrimitiveDescriptor(descriptor)) {
410
+ const value = raw && typeof raw === "object" && "value" in raw
411
+ ? raw.value
412
+ : raw;
413
+ return coerceCustomTypeValue(descriptor, value, {
414
+ locale: context.options.locale,
415
+ defaultLocale: context.options.defaultLocale,
416
+ });
417
+ }
418
+ if (isModelRefDescriptor(descriptor)) {
419
+ const refId = extractModelRefId(raw, descriptor.model);
420
+ return normalizeModelRef(descriptor.model, refId, context, trail, isCollectionItem);
421
+ }
422
+ if (isArrayDescriptor(descriptor)) {
423
+ const normalized = await normalizeArrayField(descriptor, path, raw, context, trail);
424
+ return coerceCustomTypeValue(descriptor, normalized, {
425
+ locale: context.options.locale,
426
+ defaultLocale: context.options.defaultLocale,
427
+ });
428
+ }
429
+ if (isObjectDescriptor(descriptor)) {
430
+ const normalized = await normalizeObjectField(descriptor, path, raw, context, trail, isCollectionItem);
431
+ return coerceCustomTypeValue(descriptor, normalized, {
432
+ locale: context.options.locale,
433
+ defaultLocale: context.options.defaultLocale,
434
+ });
435
+ }
436
+ return raw;
437
+ }
438
+ function createResourceRegistry(descriptor) {
439
+ const roots = new Map();
440
+ const rootsCaseInsensitive = new Map();
441
+ for (const [key, rootDescriptor] of Object.entries(descriptor.roots ?? {})) {
442
+ const entry = {
443
+ kind: "root",
444
+ key,
445
+ path: key,
446
+ descriptor: rootDescriptor,
447
+ isCollection: isArrayDescriptor(rootDescriptor),
448
+ };
449
+ roots.set(key, entry);
450
+ rootsCaseInsensitive.set(key.toLowerCase(), entry);
451
+ }
452
+ const models = new Map();
453
+ const modelsCaseInsensitive = new Map();
454
+ for (const modelName of Object.keys(descriptor.models ?? {})) {
455
+ const entry = {
456
+ kind: "model",
457
+ key: modelName,
458
+ path: `models/${modelName}`,
459
+ descriptor: asModelObjectDescriptor(modelName, descriptor),
460
+ isCollection: true,
461
+ modelName,
462
+ };
463
+ models.set(modelName, entry);
464
+ modelsCaseInsensitive.set(modelName.toLowerCase(), entry);
465
+ }
466
+ return {
467
+ roots,
468
+ rootsCaseInsensitive,
469
+ models,
470
+ modelsCaseInsensitive,
471
+ };
472
+ }
473
+ async function requestJson(baseUrl, apiKey, path, options) {
474
+ const params = buildSearchParams(options?.query);
475
+ const url = `${baseUrl}/${path}${params.toString() ? `?${params.toString()}` : ""}`;
476
+ const response = await fetch(url, {
477
+ method: "GET",
478
+ signal: options?.signal,
479
+ headers: {
480
+ ...(apiKey ? { Authorization: `Bearer ${apiKey}` } : {}),
481
+ },
482
+ });
483
+ if (!response.ok) {
484
+ throw new Error(`Request failed for '${path}' with status ${response.status}: ${response.statusText}`);
485
+ }
486
+ return response.json();
487
+ }
488
+ function validateResult(resource, result, descriptor, includeIdMode, zodSchemas, modelZodSchemas) {
489
+ if (includeIdMode === "all")
490
+ return;
491
+ if (resource.kind === "root") {
492
+ const schema = zodSchemas[resource.key];
493
+ if (!schema)
494
+ return;
495
+ const parsed = schema.safeParse(result);
496
+ if (!parsed.success) {
497
+ throw new Error(formatValidationError(resource.key, parsed.error));
498
+ }
499
+ return;
500
+ }
501
+ const modelName = resource.modelName;
502
+ if (!modelName)
503
+ return;
504
+ const modelSchema = modelZodSchemas[modelName];
505
+ if (!modelSchema)
506
+ return;
507
+ if (Array.isArray(result)) {
508
+ const parsed = modelSchema.array().safeParse(result);
509
+ if (!parsed.success) {
510
+ throw new Error(formatValidationError(modelName, parsed.error));
511
+ }
512
+ return;
513
+ }
514
+ if (result === null || result === undefined)
515
+ return;
516
+ const parsed = modelSchema.safeParse(result);
517
+ if (!parsed.success) {
518
+ throw new Error(formatValidationError(modelName, parsed.error));
519
+ }
520
+ }
521
+ async function runResource(resource, descriptor, baseUrl, apiKey, defaultLocale, zodSchemas, modelZodSchemas, options, byId) {
522
+ const responseMode = options?.response ?? "normalized";
523
+ const includeIdMode = resolveIncludeIdMode(options?.includeId);
524
+ const resolveModelRefs = options?.resolveModelRefs !== false;
525
+ const locale = options?.locale ??
526
+ (typeof options?.query?.locale === "string"
527
+ ? options.query.locale
528
+ : defaultLocale);
529
+ const query = {
530
+ ...(options?.query ?? {}),
531
+ };
532
+ const shouldNormalize = responseMode !== "raw";
533
+ if (shouldNormalize && query.raw === undefined) {
534
+ query.raw = 1;
535
+ }
536
+ if (locale && query.locale === undefined) {
537
+ query.locale = locale;
538
+ }
539
+ const resourcePath = byId
540
+ ? `${resource.path}/${encodeURIComponent(byId)}`
541
+ : resource.path;
542
+ const rawData = await requestJson(baseUrl, apiKey, resourcePath, {
543
+ query,
544
+ signal: options?.signal,
545
+ });
546
+ if (!shouldNormalize) {
547
+ return rawData;
548
+ }
549
+ const modelDescriptors = new Map();
550
+ for (const modelName of Object.keys(descriptor.models ?? {})) {
551
+ modelDescriptors.set(modelName, asModelObjectDescriptor(modelName, descriptor));
552
+ }
553
+ const context = {
554
+ requestJson: (path, requestOptions) => requestJson(baseUrl, apiKey, path, {
555
+ ...requestOptions,
556
+ signal: options?.signal,
557
+ }),
558
+ modelDescriptors,
559
+ modelCache: new Map(),
560
+ options: {
561
+ includeIdMode,
562
+ resolveModelRefs,
563
+ locale,
564
+ defaultLocale,
565
+ },
566
+ };
567
+ if (resource.isCollection && !byId) {
568
+ const envelope = ensureCollectionEnvelope(rawData, resource.path);
569
+ const descriptorForCollection = resource.kind === "root" && isArrayDescriptor(resource.descriptor)
570
+ ? resource.descriptor
571
+ : {
572
+ type: "array",
573
+ items: resource.descriptor,
574
+ optional: false,
575
+ nullable: false,
576
+ };
577
+ const normalizedItems = await normalizeArrayField(descriptorForCollection, resource.path, envelope, context, new Set());
578
+ if (responseMode === "envelope") {
579
+ validateResult(resource, normalizedItems, descriptor, includeIdMode, zodSchemas, modelZodSchemas);
580
+ return {
581
+ items: normalizedItems,
582
+ total: envelope.total,
77
583
  };
584
+ }
585
+ validateResult(resource, normalizedItems, descriptor, includeIdMode, zodSchemas, modelZodSchemas);
586
+ return normalizedItems;
587
+ }
588
+ const normalized = await normalizeField(resource.descriptor, resourcePath, rawData, context, new Set(), false);
589
+ validateResult(resource, normalized, descriptor, includeIdMode, zodSchemas, modelZodSchemas);
590
+ return normalized;
591
+ }
592
+ function createCmsClient(descriptor, config) {
593
+ const baseUrl = normalizeBaseUrl(config.apiConfig?.baseUrl);
594
+ const apiKey = config.apiConfig?.key;
595
+ const registry = createResourceRegistry(descriptor);
596
+ const rootKeys = Array.from(registry.roots.keys());
597
+ const modelKeys = Array.from(registry.models.keys());
598
+ const { zodSchemas, modelZodSchemas } = (0, shared_1.buildZodSchemasFromDescriptor)(descriptor);
599
+ const buildModelAccessor = (entry) => {
600
+ const accessor = (async (options) => runResource(entry, descriptor, baseUrl, apiKey, config.defaultLocale, zodSchemas, modelZodSchemas, options));
601
+ accessor.byId = async (id, options) => runResource(entry, descriptor, baseUrl, apiKey, config.defaultLocale, zodSchemas, modelZodSchemas, options, id);
602
+ return accessor;
603
+ };
604
+ const modelsProxy = new Proxy({}, {
605
+ get(_target, property) {
606
+ if (typeof property !== "string")
607
+ return undefined;
608
+ if (property === "then")
609
+ return undefined;
610
+ const modelEntry = registry.models.get(property) ??
611
+ registry.modelsCaseInsensitive.get(property.toLowerCase());
612
+ if (!modelEntry) {
613
+ unknownKeyError(property, [], modelKeys);
614
+ }
615
+ return buildModelAccessor(modelEntry);
78
616
  },
79
617
  });
618
+ const rootProxy = new Proxy({}, {
619
+ get(_target, property) {
620
+ if (typeof property !== "string")
621
+ return undefined;
622
+ if (property === "then")
623
+ return undefined;
624
+ if (property === "models")
625
+ return modelsProxy;
626
+ const entry = registry.roots.get(property) ??
627
+ registry.rootsCaseInsensitive.get(property.toLowerCase());
628
+ if (!entry) {
629
+ unknownKeyError(property, rootKeys, []);
630
+ }
631
+ return async (options) => runResource(entry, descriptor, baseUrl, apiKey, config.defaultLocale, zodSchemas, modelZodSchemas, options);
632
+ },
633
+ });
634
+ return rootProxy;
635
+ }
636
+ /**
637
+ * Initializes the CMS SDK for a given schema.
638
+ * @param config configuration including API base URL and API key.
639
+ * @returns typed accessors for root resources and model resources.
640
+ */
641
+ function cms0(config) {
642
+ return createCmsClient(schema_descriptors_1.schemaDescriptor, config);
80
643
  }