@contentrain/query 5.1.1 → 5.1.3
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 +110 -8
- package/dist/cdn/index.cjs +4 -1
- package/dist/cdn/index.d.cts +2 -2
- package/dist/cdn/index.d.mts +2 -2
- package/dist/cdn/index.mjs +2 -2
- package/dist/{cdn-C8uXJe3A.cjs → cdn-5ycdk2ET.cjs} +190 -34
- package/dist/{cdn-D66-Npqt.mjs → cdn-SOuikUcY.mjs} +168 -36
- package/dist/cdn-SOuikUcY.mjs.map +1 -0
- package/dist/cli.cjs +1 -1
- package/dist/cli.mjs +1 -1
- package/dist/{generate-CAoJCGIe.mjs → generate-B5P14n43.mjs} +33 -5
- package/dist/generate-B5P14n43.mjs.map +1 -0
- package/dist/{generate-DWu2BzSt.cjs → generate-DAaCl3Np.cjs} +32 -4
- package/dist/generator/generate.cjs +1 -1
- package/dist/generator/generate.mjs +1 -1
- package/dist/index-BChs94uA.d.cts +285 -0
- package/dist/index-BChs94uA.d.cts.map +1 -0
- package/dist/index-CsCpovuB.d.mts +285 -0
- package/dist/index-CsCpovuB.d.mts.map +1 -0
- package/dist/index.cjs +34 -10
- package/dist/index.d.cts +6 -2
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +6 -2
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +31 -11
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
- package/dist/cdn-D66-Npqt.mjs.map +0 -1
- package/dist/generate-CAoJCGIe.mjs.map +0 -1
- package/dist/index-D5zB3y75.d.mts +0 -127
- package/dist/index-D5zB3y75.d.mts.map +0 -1
- package/dist/index-Xjd0isXU.d.cts +0 -127
- package/dist/index-Xjd0isXU.d.cts.map +0 -1
|
@@ -1,3 +1,24 @@
|
|
|
1
|
+
//#region src/shared/where.ts
|
|
2
|
+
function applyWhere(item, clause) {
|
|
3
|
+
const val = item[clause.field];
|
|
4
|
+
switch (clause.op) {
|
|
5
|
+
case "eq":
|
|
6
|
+
if (Array.isArray(val)) return val.includes(clause.value);
|
|
7
|
+
return val === clause.value;
|
|
8
|
+
case "ne": return val !== clause.value;
|
|
9
|
+
case "gt": return val > clause.value;
|
|
10
|
+
case "gte": return val >= clause.value;
|
|
11
|
+
case "lt": return val < clause.value;
|
|
12
|
+
case "lte": return val <= clause.value;
|
|
13
|
+
case "in": return Array.isArray(clause.value) && clause.value.includes(val);
|
|
14
|
+
case "contains":
|
|
15
|
+
if (typeof val === "string") return val.includes(clause.value);
|
|
16
|
+
if (Array.isArray(val)) return val.includes(clause.value);
|
|
17
|
+
return false;
|
|
18
|
+
default: return true;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
//#endregion
|
|
1
22
|
//#region src/cdn/errors.ts
|
|
2
23
|
var ContentrainError = class extends Error {
|
|
3
24
|
constructor(status, message) {
|
|
@@ -18,6 +39,9 @@ var HttpTransport = class {
|
|
|
18
39
|
this._projectId = config.projectId;
|
|
19
40
|
this._apiKey = config.apiKey;
|
|
20
41
|
}
|
|
42
|
+
buildUrl(path) {
|
|
43
|
+
return `${this._baseUrl}/${this._projectId}/${path}`;
|
|
44
|
+
}
|
|
21
45
|
async fetch(path) {
|
|
22
46
|
const url = `${this._baseUrl}/${this._projectId}/${path}`;
|
|
23
47
|
const cached = this._cache.get(path);
|
|
@@ -75,6 +99,7 @@ var CdnCollectionQuery = class {
|
|
|
75
99
|
_limit = null;
|
|
76
100
|
_offset = 0;
|
|
77
101
|
_includes = [];
|
|
102
|
+
_withMeta = false;
|
|
78
103
|
constructor(transport, modelId, defaultLocale) {
|
|
79
104
|
this._transport = transport;
|
|
80
105
|
this._source = transport.collection(modelId);
|
|
@@ -110,9 +135,13 @@ var CdnCollectionQuery = class {
|
|
|
110
135
|
this._includes.push(...fields);
|
|
111
136
|
return this;
|
|
112
137
|
}
|
|
138
|
+
withMeta() {
|
|
139
|
+
this._withMeta = true;
|
|
140
|
+
return this;
|
|
141
|
+
}
|
|
113
142
|
async all() {
|
|
114
143
|
let items = await this._source.getAll(this._locale);
|
|
115
|
-
for (const clause of this._filters) items = items.filter((item) => applyWhere
|
|
144
|
+
for (const clause of this._filters) items = items.filter((item) => applyWhere(item, clause));
|
|
116
145
|
if (this._sortField) {
|
|
117
146
|
const field = this._sortField;
|
|
118
147
|
const dir = this._sortOrder === "asc" ? 1 : -1;
|
|
@@ -132,8 +161,12 @@ var CdnCollectionQuery = class {
|
|
|
132
161
|
items = items.slice(this._offset, end);
|
|
133
162
|
}
|
|
134
163
|
if (this._includes.length > 0) items = await this._resolveIncludes(items);
|
|
164
|
+
if (this._withMeta) items = await this._enrichMeta(items);
|
|
135
165
|
return items;
|
|
136
166
|
}
|
|
167
|
+
async count() {
|
|
168
|
+
return (await this.all()).length;
|
|
169
|
+
}
|
|
137
170
|
async first() {
|
|
138
171
|
return (await this.all())[0];
|
|
139
172
|
}
|
|
@@ -173,24 +206,24 @@ var CdnCollectionQuery = class {
|
|
|
173
206
|
return resolved;
|
|
174
207
|
});
|
|
175
208
|
}
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
return
|
|
191
|
-
|
|
209
|
+
async _enrichMeta(items) {
|
|
210
|
+
let metaMap = {};
|
|
211
|
+
try {
|
|
212
|
+
metaMap = await this._transport.fetch(`meta/${this._modelId}/${this._locale}.json`);
|
|
213
|
+
} catch {
|
|
214
|
+
return items;
|
|
215
|
+
}
|
|
216
|
+
return items.map((item) => {
|
|
217
|
+
const id = item.id;
|
|
218
|
+
const meta = id ? metaMap[id] : void 0;
|
|
219
|
+
if (meta) return {
|
|
220
|
+
...item,
|
|
221
|
+
_meta: meta
|
|
222
|
+
};
|
|
223
|
+
return item;
|
|
224
|
+
});
|
|
192
225
|
}
|
|
193
|
-
}
|
|
226
|
+
};
|
|
194
227
|
//#endregion
|
|
195
228
|
//#region src/cdn/singleton-accessor.ts
|
|
196
229
|
var CdnSingletonAccessor = class {
|
|
@@ -263,6 +296,9 @@ var CdnDocumentQuery = class {
|
|
|
263
296
|
for (const clause of this._filters) items = items.filter((item) => applyWhere(item, clause));
|
|
264
297
|
return items;
|
|
265
298
|
}
|
|
299
|
+
async count() {
|
|
300
|
+
return (await this.all()).length;
|
|
301
|
+
}
|
|
266
302
|
async first() {
|
|
267
303
|
return (await this.all())[0];
|
|
268
304
|
}
|
|
@@ -270,23 +306,108 @@ var CdnDocumentQuery = class {
|
|
|
270
306
|
return this._source.getBySlug(slug, this._locale);
|
|
271
307
|
}
|
|
272
308
|
};
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
case "lt": return val < clause.value;
|
|
281
|
-
case "lte": return val <= clause.value;
|
|
282
|
-
case "in": return Array.isArray(clause.value) && clause.value.includes(val);
|
|
283
|
-
case "contains":
|
|
284
|
-
if (typeof val === "string") return val.includes(clause.value);
|
|
285
|
-
if (Array.isArray(val)) return val.includes(clause.value);
|
|
286
|
-
return false;
|
|
287
|
-
default: return true;
|
|
309
|
+
//#endregion
|
|
310
|
+
//#region src/cdn/media-accessor.ts
|
|
311
|
+
var MediaAccessor = class {
|
|
312
|
+
_transport;
|
|
313
|
+
_manifest = null;
|
|
314
|
+
constructor(transport) {
|
|
315
|
+
this._transport = transport;
|
|
288
316
|
}
|
|
289
|
-
|
|
317
|
+
async manifest() {
|
|
318
|
+
if (!this._manifest) this._manifest = await this._transport.fetch("_media_manifest.json");
|
|
319
|
+
return this._manifest;
|
|
320
|
+
}
|
|
321
|
+
async assets() {
|
|
322
|
+
return (await this.manifest()).assets;
|
|
323
|
+
}
|
|
324
|
+
async asset(path) {
|
|
325
|
+
return (await this.assets())[path] ?? null;
|
|
326
|
+
}
|
|
327
|
+
async list() {
|
|
328
|
+
const all = await this.assets();
|
|
329
|
+
return Object.entries(all).map(([path, asset]) => Object.assign({ path }, asset));
|
|
330
|
+
}
|
|
331
|
+
resolve(asset, variant) {
|
|
332
|
+
if (variant && asset.variants[variant]) return asset.variants[variant];
|
|
333
|
+
return asset.original;
|
|
334
|
+
}
|
|
335
|
+
url(asset, variant) {
|
|
336
|
+
const path = this.resolve(asset, variant);
|
|
337
|
+
return this._transport.buildUrl(path);
|
|
338
|
+
}
|
|
339
|
+
};
|
|
340
|
+
//#endregion
|
|
341
|
+
//#region src/cdn/forms-client.ts
|
|
342
|
+
var FormsClient = class {
|
|
343
|
+
_baseUrl;
|
|
344
|
+
_projectId;
|
|
345
|
+
_apiKey;
|
|
346
|
+
constructor(config) {
|
|
347
|
+
this._baseUrl = config.baseUrl.replace(/\/+$/, "");
|
|
348
|
+
this._projectId = config.projectId;
|
|
349
|
+
this._apiKey = config.apiKey;
|
|
350
|
+
}
|
|
351
|
+
async config(modelId) {
|
|
352
|
+
const url = `${this._baseUrl}/${this._projectId}/${modelId}/config`;
|
|
353
|
+
const headers = {};
|
|
354
|
+
if (this._apiKey) headers["Authorization"] = `Bearer ${this._apiKey}`;
|
|
355
|
+
const res = await globalThis.fetch(url, { headers });
|
|
356
|
+
if (!res.ok) throw new ContentrainError(res.status, await res.text());
|
|
357
|
+
return await res.json();
|
|
358
|
+
}
|
|
359
|
+
async submit(modelId, data, options) {
|
|
360
|
+
const url = `${this._baseUrl}/${this._projectId}/${modelId}/submit`;
|
|
361
|
+
const headers = { "Content-Type": "application/json" };
|
|
362
|
+
if (this._apiKey) headers["Authorization"] = `Bearer ${this._apiKey}`;
|
|
363
|
+
const body = { ...data };
|
|
364
|
+
if (options?.captchaToken) body["cf-turnstile-response"] = options.captchaToken;
|
|
365
|
+
const res = await globalThis.fetch(url, {
|
|
366
|
+
method: "POST",
|
|
367
|
+
headers,
|
|
368
|
+
body: JSON.stringify(body)
|
|
369
|
+
});
|
|
370
|
+
const result = await res.json();
|
|
371
|
+
if (!res.ok && !result.errors) throw new ContentrainError(res.status, result.message ?? "Form submission failed");
|
|
372
|
+
return result;
|
|
373
|
+
}
|
|
374
|
+
};
|
|
375
|
+
//#endregion
|
|
376
|
+
//#region src/cdn/conversation-client.ts
|
|
377
|
+
var ConversationClient = class {
|
|
378
|
+
_baseUrl;
|
|
379
|
+
_projectId;
|
|
380
|
+
_apiKey;
|
|
381
|
+
constructor(config) {
|
|
382
|
+
this._baseUrl = config.baseUrl.replace(/\/+$/, "");
|
|
383
|
+
this._projectId = config.projectId;
|
|
384
|
+
this._apiKey = config.apiKey;
|
|
385
|
+
}
|
|
386
|
+
async send(message, options) {
|
|
387
|
+
const url = `${this._baseUrl}/${this._projectId}/message`;
|
|
388
|
+
const body = { message };
|
|
389
|
+
if (options?.conversationId) body.conversationId = options.conversationId;
|
|
390
|
+
if (options?.context) body.context = options.context;
|
|
391
|
+
const res = await globalThis.fetch(url, {
|
|
392
|
+
method: "POST",
|
|
393
|
+
headers: {
|
|
394
|
+
"Content-Type": "application/json",
|
|
395
|
+
"Authorization": `Bearer ${this._apiKey}`
|
|
396
|
+
},
|
|
397
|
+
body: JSON.stringify(body)
|
|
398
|
+
});
|
|
399
|
+
if (!res.ok) throw new ContentrainError(res.status, await res.text());
|
|
400
|
+
return await res.json();
|
|
401
|
+
}
|
|
402
|
+
async history(conversationId, options) {
|
|
403
|
+
const params = new URLSearchParams({ conversationId });
|
|
404
|
+
if (options?.limit) params.set("limit", String(options.limit));
|
|
405
|
+
const url = `${this._baseUrl}/${this._projectId}/history?${params}`;
|
|
406
|
+
const res = await globalThis.fetch(url, { headers: { "Authorization": `Bearer ${this._apiKey}` } });
|
|
407
|
+
if (!res.ok) throw new ContentrainError(res.status, await res.text());
|
|
408
|
+
return await res.json();
|
|
409
|
+
}
|
|
410
|
+
};
|
|
290
411
|
//#endregion
|
|
291
412
|
//#region src/cdn/index.ts
|
|
292
413
|
function createContentrain(config) {
|
|
@@ -301,12 +422,23 @@ function createContentrain(config) {
|
|
|
301
422
|
singleton: (modelId) => new CdnSingletonAccessor(transport.singleton(modelId), defaultLocale),
|
|
302
423
|
dictionary: (modelId) => new CdnDictionaryAccessor(transport.dictionary(modelId), defaultLocale),
|
|
303
424
|
document: (modelId) => new CdnDocumentQuery(transport.document(modelId), defaultLocale),
|
|
425
|
+
media: () => new MediaAccessor(transport),
|
|
426
|
+
form: () => new FormsClient({
|
|
427
|
+
baseUrl: (config.baseUrl ?? "https://studio.contentrain.io/api/cdn/v1").replace("/cdn/v1", "/forms/v1"),
|
|
428
|
+
projectId: config.projectId,
|
|
429
|
+
apiKey: config.apiKey
|
|
430
|
+
}),
|
|
431
|
+
conversation: () => new ConversationClient({
|
|
432
|
+
baseUrl: (config.baseUrl ?? "https://studio.contentrain.io/api/cdn/v1").replace("/cdn/v1", "/conversation/v1"),
|
|
433
|
+
projectId: config.projectId,
|
|
434
|
+
apiKey: config.apiKey
|
|
435
|
+
}),
|
|
304
436
|
manifest: () => transport.fetch("_manifest.json"),
|
|
305
437
|
models: () => transport.fetch("models/_index.json"),
|
|
306
438
|
model: (id) => transport.fetch(`models/${id}.json`)
|
|
307
439
|
};
|
|
308
440
|
}
|
|
309
441
|
//#endregion
|
|
310
|
-
export {
|
|
442
|
+
export { CdnDocumentQuery as a, CdnCollectionQuery as c, applyWhere as d, MediaAccessor as i, HttpTransport as l, ConversationClient as n, CdnDictionaryAccessor as o, FormsClient as r, CdnSingletonAccessor as s, createContentrain as t, ContentrainError as u };
|
|
311
443
|
|
|
312
|
-
//# sourceMappingURL=cdn-
|
|
444
|
+
//# sourceMappingURL=cdn-SOuikUcY.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cdn-SOuikUcY.mjs","names":[],"sources":["../src/shared/where.ts","../src/cdn/errors.ts","../src/cdn/http-transport.ts","../src/cdn/collection-query.ts","../src/cdn/singleton-accessor.ts","../src/cdn/dictionary-accessor.ts","../src/cdn/document-query.ts","../src/cdn/media-accessor.ts","../src/cdn/forms-client.ts","../src/cdn/conversation-client.ts","../src/cdn/index.ts"],"sourcesContent":["export type WhereOp = 'eq' | 'ne' | 'gt' | 'gte' | 'lt' | 'lte' | 'in' | 'contains'\n\nexport interface WhereClause {\n field: string\n op: WhereOp\n value: unknown\n}\n\nexport function applyWhere<T>(item: T, clause: WhereClause): boolean {\n const val = (item as Record<string, unknown>)[clause.field]\n switch (clause.op) {\n case 'eq': {\n if (Array.isArray(val)) return val.includes(clause.value)\n return val === clause.value\n }\n case 'ne': return val !== clause.value\n case 'gt': return (val as number) > (clause.value as number)\n case 'gte': return (val as number) >= (clause.value as number)\n case 'lt': return (val as number) < (clause.value as number)\n case 'lte': return (val as number) <= (clause.value as number)\n case 'in': return Array.isArray(clause.value) && (clause.value as unknown[]).includes(val)\n case 'contains': {\n if (typeof val === 'string') return val.includes(clause.value as string)\n if (Array.isArray(val)) return val.includes(clause.value)\n return false\n }\n default: return true\n }\n}\n","export class ContentrainError extends Error {\n constructor(\n public status: number,\n message: string,\n ) {\n super(message)\n this.name = 'ContentrainError'\n }\n}\n","import { ContentrainError } from './errors.js'\nimport type { CollectionDataSource, SingletonDataSource, DictionaryDataSource, DocumentDataSource } from './data-source.js'\n\ninterface CacheEntry {\n data: unknown\n etag: string\n}\n\nexport class HttpTransport {\n private _baseUrl: string\n private _projectId: string\n private _apiKey: string\n private _cache = new Map<string, CacheEntry>()\n\n constructor(config: { baseUrl: string; projectId: string; apiKey: string }) {\n this._baseUrl = config.baseUrl.replace(/\\/+$/, '')\n this._projectId = config.projectId\n this._apiKey = config.apiKey\n }\n\n buildUrl(path: string): string {\n return `${this._baseUrl}/${this._projectId}/${path}`\n }\n\n async fetch<T>(path: string): Promise<T> {\n const url = `${this._baseUrl}/${this._projectId}/${path}`\n const cached = this._cache.get(path)\n\n const headers: Record<string, string> = {\n 'Authorization': `Bearer ${this._apiKey}`,\n }\n if (cached?.etag) {\n headers['If-None-Match'] = cached.etag\n }\n\n const res = await globalThis.fetch(url, { headers })\n\n if (res.status === 304 && cached) return cached.data as T\n if (!res.ok) throw new ContentrainError(res.status, await res.text())\n\n const data = (await res.json()) as T\n const etag = res.headers.get('etag') ?? ''\n if (etag) {\n this._cache.set(path, { data, etag })\n }\n return data\n }\n\n collection<T>(modelId: string): CollectionDataSource<T> {\n return {\n getAll: async (locale) => {\n const map = await this.fetch<Record<string, T>>(`content/${modelId}/${locale}.json`)\n return Object.entries(map).map(([id, entry]) => Object.assign({ id }, entry as object) as T)\n },\n getOne: async (id, locale) => {\n const map = await this.fetch<Record<string, T>>(`content/${modelId}/${locale}.json`)\n const entry = map[id]\n return entry ? { id, ...entry as object } as T : null\n },\n }\n }\n\n singleton<T>(modelId: string): SingletonDataSource<T> {\n return {\n get: (locale) => this.fetch<T>(`content/${modelId}/${locale}.json`),\n }\n }\n\n dictionary(modelId: string): DictionaryDataSource {\n return {\n get: (locale) => this.fetch<Record<string, string>>(`content/${modelId}/${locale}.json`),\n }\n }\n\n document<T>(modelId: string): DocumentDataSource<T> {\n return {\n getIndex: (locale) => this.fetch<T[]>(`documents/${modelId}/_index/${locale}.json`),\n getBySlug: (slug, locale) => this.fetch(`documents/${modelId}/${slug}/${locale}.json`),\n }\n }\n}\n","import type { CollectionDataSource } from './data-source.js'\nimport type { HttpTransport } from './http-transport.js'\nimport type { WhereOp, WhereClause } from '../shared/where.js'\nimport { applyWhere } from '../shared/where.js'\n\nexport interface EntryMeta {\n status?: string\n publish_at?: string\n expire_at?: string\n updated_by?: string\n approved_by?: string\n [key: string]: unknown\n}\n\nexport class CdnCollectionQuery<T extends object> {\n private _transport: HttpTransport\n private _source: CollectionDataSource<T>\n private _modelId: string\n private _locale: string = 'en'\n private _filters: WhereClause[] = []\n private _sortField: string | null = null\n private _sortOrder: 'asc' | 'desc' = 'asc'\n private _limit: number | null = null\n private _offset = 0\n private _includes: string[] = []\n private _withMeta = false\n\n constructor(transport: HttpTransport, modelId: string, defaultLocale?: string) {\n this._transport = transport\n this._source = transport.collection<T>(modelId)\n this._modelId = modelId\n if (defaultLocale) this._locale = defaultLocale\n }\n\n locale(lang: string): this {\n this._locale = lang\n return this\n }\n\n where(field: string, op: WhereOp, value: unknown): this {\n this._filters.push({ field, op, value })\n return this\n }\n\n sort(field: string, order: 'asc' | 'desc' = 'asc'): this {\n this._sortField = field\n this._sortOrder = order\n return this\n }\n\n limit(n: number): this {\n this._limit = n\n return this\n }\n\n offset(n: number): this {\n this._offset = n\n return this\n }\n\n include(...fields: string[]): this {\n this._includes.push(...fields)\n return this\n }\n\n withMeta(): this {\n this._withMeta = true\n return this\n }\n\n async all(): Promise<T[]> {\n let items = await this._source.getAll(this._locale)\n\n // Filter\n for (const clause of this._filters) {\n items = items.filter(item => applyWhere(item, clause))\n }\n\n // Sort\n if (this._sortField) {\n const field = this._sortField\n const dir = this._sortOrder === 'asc' ? 1 : -1\n items = items.toSorted((a, b) => {\n const va = (a as Record<string, unknown>)[field]\n const vb = (b as Record<string, unknown>)[field]\n if (va == null && vb == null) return 0\n if (va == null) return dir\n if (vb == null) return -dir\n if (va < vb) return -dir\n if (va > vb) return dir\n return 0\n })\n }\n\n // Pagination\n if (this._offset > 0 || this._limit !== null) {\n const end = this._limit !== null ? this._offset + this._limit : undefined\n items = items.slice(this._offset, end)\n }\n\n // Resolve relations\n if (this._includes.length > 0) {\n items = await this._resolveIncludes(items)\n }\n\n // Enrich with entry metadata\n if (this._withMeta) {\n items = await this._enrichMeta(items)\n }\n\n return items\n }\n\n async count(): Promise<number> {\n const items = await this.all()\n return items.length\n }\n\n async first(): Promise<T | undefined> {\n const items = await this.all()\n return items[0]\n }\n\n private async _resolveIncludes(items: T[]): Promise<T[]> {\n // Prefetch related collections to avoid N+1\n const cache = new Map<string, Map<string, Record<string, unknown>>>()\n\n for (const field of this._includes) {\n // Collect all IDs for this field\n for (const item of items) {\n const val = (item as Record<string, unknown>)[field]\n const ids = Array.isArray(val) ? val : val ? [val] : []\n for (const id of ids) {\n if (typeof id !== 'string') continue\n // We don't know the target model from here, so we use field name as hint\n // In production, model metadata would provide this mapping\n if (!cache.has(field)) {\n try {\n const related = await this._transport.fetch<Record<string, unknown>>(`content/${field}/${this._locale}.json`)\n const map = new Map<string, Record<string, unknown>>()\n for (const [entryId, entry] of Object.entries(related)) {\n map.set(entryId, { id: entryId, ...entry as object })\n }\n cache.set(field, map)\n } catch {\n cache.set(field, new Map())\n }\n break\n }\n }\n }\n }\n\n return items.map(item => {\n const resolved = { ...item }\n const dst = resolved as Record<string, unknown>\n for (const field of this._includes) {\n const related = cache.get(field)\n if (!related) continue\n const val = (item as Record<string, unknown>)[field]\n if (Array.isArray(val)) {\n dst[field] = val.map(id => typeof id === 'string' ? (related.get(id) ?? id) : id)\n } else if (typeof val === 'string') {\n dst[field] = related.get(val) ?? val\n }\n }\n return resolved\n })\n }\n\n private async _enrichMeta(items: T[]): Promise<T[]> {\n let metaMap: Record<string, EntryMeta> = {}\n try {\n metaMap = await this._transport.fetch<Record<string, EntryMeta>>(`meta/${this._modelId}/${this._locale}.json`)\n } catch {\n // No meta available — return items unchanged\n return items\n }\n return items.map(item => {\n const id = (item as Record<string, unknown>).id as string\n const meta = id ? metaMap[id] : undefined\n if (meta) {\n return { ...item, _meta: meta }\n }\n return item\n })\n }\n}\n\n","import type { SingletonDataSource } from './data-source.js'\n\nexport class CdnSingletonAccessor<T extends Record<string, unknown>> {\n private _source: SingletonDataSource<T>\n private _locale: string = 'en'\n\n constructor(source: SingletonDataSource<T>, defaultLocale?: string) {\n this._source = source\n if (defaultLocale) this._locale = defaultLocale\n }\n\n locale(lang: string): this {\n this._locale = lang\n return this\n }\n\n async get(): Promise<T> {\n return this._source.get(this._locale)\n }\n}\n","import type { DictionaryDataSource } from './data-source.js'\n\nexport class CdnDictionaryAccessor {\n private _source: DictionaryDataSource\n private _locale: string = 'en'\n\n constructor(source: DictionaryDataSource, defaultLocale?: string) {\n this._source = source\n if (defaultLocale) this._locale = defaultLocale\n }\n\n locale(lang: string): this {\n this._locale = lang\n return this\n }\n\n async get(): Promise<Record<string, string>>\n async get(key: string): Promise<string | undefined>\n async get(key: string, params: Record<string, string | number>): Promise<string>\n async get(key?: string, params?: Record<string, string | number>): Promise<Record<string, string> | string | undefined> {\n const dict = await this._source.get(this._locale)\n if (key === undefined) return dict\n const value = dict[key]\n if (value === undefined) return undefined\n if (params) return interpolate(value, params)\n return value\n }\n}\n\nfunction interpolate(template: string, params: Record<string, string | number>): string {\n return template.replace(/\\{(\\w+)\\}/g, (match, key: string) => {\n const val = params[key]\n return val !== undefined ? String(val) : match\n })\n}\n","import type { DocumentDataSource } from './data-source.js'\nimport type { WhereOp, WhereClause } from '../shared/where.js'\nimport { applyWhere } from '../shared/where.js'\n\nexport class CdnDocumentQuery<T extends object> {\n private _source: DocumentDataSource<T>\n private _locale: string = 'en'\n private _filters: WhereClause[] = []\n\n constructor(source: DocumentDataSource<T>, defaultLocale?: string) {\n this._source = source\n if (defaultLocale) this._locale = defaultLocale\n }\n\n locale(lang: string): this {\n this._locale = lang\n return this\n }\n\n where(field: string, op: WhereOp, value: unknown): this {\n this._filters.push({ field, op, value })\n return this\n }\n\n async all(): Promise<T[]> {\n let items = await this._source.getIndex(this._locale)\n\n for (const clause of this._filters) {\n items = items.filter(item => applyWhere(item, clause))\n }\n\n return items\n }\n\n async count(): Promise<number> {\n const items = await this.all()\n return items.length\n }\n\n async first(): Promise<T | undefined> {\n const items = await this.all()\n return items[0]\n }\n\n async bySlug(slug: string): Promise<{ frontmatter: T; body: string; html: string } | null> {\n return this._source.getBySlug(slug, this._locale)\n }\n}\n","import type { HttpTransport } from './http-transport.js'\n\nexport interface MediaAssetMeta {\n width?: number\n height?: number\n format?: string\n size?: number\n blurhash?: string | null\n alt?: string | null\n}\n\nexport interface MediaAsset {\n original: string\n variants: Record<string, string>\n meta: MediaAssetMeta\n}\n\nexport interface MediaManifest {\n version: string\n assets: Record<string, MediaAsset>\n}\n\nexport class MediaAccessor {\n private _transport: HttpTransport\n private _manifest: MediaManifest | null = null\n\n constructor(transport: HttpTransport) {\n this._transport = transport\n }\n\n async manifest(): Promise<MediaManifest> {\n if (!this._manifest) {\n this._manifest = await this._transport.fetch<MediaManifest>('_media_manifest.json')\n }\n return this._manifest\n }\n\n async assets(): Promise<Record<string, MediaAsset>> {\n const m = await this.manifest()\n return m.assets\n }\n\n async asset(path: string): Promise<MediaAsset | null> {\n const all = await this.assets()\n return all[path] ?? null\n }\n\n async list(): Promise<Array<{ path: string } & MediaAsset>> {\n const all = await this.assets()\n return Object.entries(all).map(([path, asset]) =>\n Object.assign({ path }, asset),\n )\n }\n\n resolve(asset: MediaAsset, variant?: string): string {\n if (variant && asset.variants[variant]) {\n return asset.variants[variant]\n }\n return asset.original\n }\n\n url(asset: MediaAsset, variant?: string): string {\n const path = this.resolve(asset, variant)\n return this._transport.buildUrl(path)\n }\n}\n","import { ContentrainError } from './errors.js'\n\nexport interface FormFieldConfig {\n id: string\n type: string\n required?: boolean\n label?: string\n placeholder?: string\n options?: Array<{ value: string; label: string }>\n pattern?: string\n min?: number\n max?: number\n}\n\nexport interface FormConfig {\n modelId: string\n fields: FormFieldConfig[]\n captchaType?: 'turnstile' | null\n successMessage?: string\n honeypotField?: string\n}\n\nexport interface FormSubmitResult {\n success: boolean\n message?: string\n errors?: Array<{ field: string; message: string }>\n}\n\nexport interface FormsClientConfig {\n baseUrl: string\n projectId: string\n apiKey?: string\n}\n\nexport class FormsClient {\n private _baseUrl: string\n private _projectId: string\n private _apiKey: string | undefined\n\n constructor(config: FormsClientConfig) {\n this._baseUrl = config.baseUrl.replace(/\\/+$/, '')\n this._projectId = config.projectId\n this._apiKey = config.apiKey\n }\n\n async config(modelId: string): Promise<FormConfig> {\n const url = `${this._baseUrl}/${this._projectId}/${modelId}/config`\n const headers: Record<string, string> = {}\n if (this._apiKey) headers['Authorization'] = `Bearer ${this._apiKey}`\n\n const res = await globalThis.fetch(url, { headers })\n if (!res.ok) throw new ContentrainError(res.status, await res.text())\n return (await res.json()) as FormConfig\n }\n\n async submit(modelId: string, data: Record<string, unknown>, options?: {\n captchaToken?: string\n }): Promise<FormSubmitResult> {\n const url = `${this._baseUrl}/${this._projectId}/${modelId}/submit`\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n }\n if (this._apiKey) headers['Authorization'] = `Bearer ${this._apiKey}`\n\n const body: Record<string, unknown> = { ...data }\n if (options?.captchaToken) {\n body['cf-turnstile-response'] = options.captchaToken\n }\n\n const res = await globalThis.fetch(url, {\n method: 'POST',\n headers,\n body: JSON.stringify(body),\n })\n\n const result = (await res.json()) as FormSubmitResult\n\n if (!res.ok && !result.errors) {\n throw new ContentrainError(res.status, result.message ?? 'Form submission failed')\n }\n\n return result\n }\n}\n","import { ContentrainError } from './errors.js'\n\nexport interface ConversationContext {\n activeModelId?: string | null\n activeLocale?: string\n activeEntryId?: string | null\n panelState?: string\n activeBranch?: string | null\n}\n\nexport interface ConversationSendOptions {\n conversationId?: string\n context?: ConversationContext\n}\n\nexport interface ConversationToolResult {\n id: string\n name: string\n result: unknown\n}\n\nexport interface ConversationUsage {\n inputTokens: number\n outputTokens: number\n}\n\nexport interface ConversationResponse {\n conversationId: string\n message: string\n toolResults?: ConversationToolResult[]\n usage: ConversationUsage\n}\n\nexport interface ConversationMessage {\n id: string\n role: 'user' | 'assistant'\n content: string | unknown[]\n toolCalls?: unknown[]\n model?: string\n usage?: ConversationUsage\n createdAt: string\n}\n\nexport interface ConversationHistory {\n conversationId: string\n messages: ConversationMessage[]\n}\n\nexport interface ConversationClientConfig {\n baseUrl: string\n projectId: string\n apiKey: string\n}\n\nexport class ConversationClient {\n private _baseUrl: string\n private _projectId: string\n private _apiKey: string\n\n constructor(config: ConversationClientConfig) {\n this._baseUrl = config.baseUrl.replace(/\\/+$/, '')\n this._projectId = config.projectId\n this._apiKey = config.apiKey\n }\n\n async send(message: string, options?: ConversationSendOptions): Promise<ConversationResponse> {\n const url = `${this._baseUrl}/${this._projectId}/message`\n\n const body: Record<string, unknown> = { message }\n if (options?.conversationId) body.conversationId = options.conversationId\n if (options?.context) body.context = options.context\n\n const res = await globalThis.fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${this._apiKey}`,\n },\n body: JSON.stringify(body),\n })\n\n if (!res.ok) {\n throw new ContentrainError(res.status, await res.text())\n }\n\n return (await res.json()) as ConversationResponse\n }\n\n async history(conversationId: string, options?: { limit?: number }): Promise<ConversationHistory> {\n const params = new URLSearchParams({ conversationId })\n if (options?.limit) params.set('limit', String(options.limit))\n\n const url = `${this._baseUrl}/${this._projectId}/history?${params}`\n\n const res = await globalThis.fetch(url, {\n headers: {\n 'Authorization': `Bearer ${this._apiKey}`,\n },\n })\n\n if (!res.ok) {\n throw new ContentrainError(res.status, await res.text())\n }\n\n return (await res.json()) as ConversationHistory\n }\n}\n","import { HttpTransport } from './http-transport.js'\nimport { CdnCollectionQuery } from './collection-query.js'\nimport { CdnSingletonAccessor } from './singleton-accessor.js'\nimport { CdnDictionaryAccessor } from './dictionary-accessor.js'\nimport { CdnDocumentQuery } from './document-query.js'\nimport { MediaAccessor } from './media-accessor.js'\nimport { FormsClient } from './forms-client.js'\nimport { ConversationClient } from './conversation-client.js'\n\nexport interface ContentrainCDNConfig {\n projectId: string\n apiKey: string\n baseUrl?: string\n defaultLocale?: string\n}\n\nexport type ContentrainCDNClient = ReturnType<typeof createContentrain>\n\nexport function createContentrain(config: ContentrainCDNConfig) {\n const transport = new HttpTransport({\n baseUrl: config.baseUrl ?? 'https://studio.contentrain.io/api/cdn/v1',\n projectId: config.projectId,\n apiKey: config.apiKey,\n })\n const defaultLocale = config.defaultLocale\n\n return {\n collection: <T extends object = Record<string, unknown>>(modelId: string) =>\n new CdnCollectionQuery<T>(transport, modelId, defaultLocale),\n\n singleton: <T extends Record<string, unknown> = Record<string, unknown>>(modelId: string) =>\n new CdnSingletonAccessor<T>(transport.singleton<T>(modelId), defaultLocale),\n\n dictionary: (modelId: string) =>\n new CdnDictionaryAccessor(transport.dictionary(modelId), defaultLocale),\n\n document: <T extends object = Record<string, unknown>>(modelId: string) =>\n new CdnDocumentQuery<T>(transport.document<T>(modelId), defaultLocale),\n\n media: () => new MediaAccessor(transport),\n\n form: () => new FormsClient({\n baseUrl: (config.baseUrl ?? 'https://studio.contentrain.io/api/cdn/v1').replace('/cdn/v1', '/forms/v1'),\n projectId: config.projectId,\n apiKey: config.apiKey,\n }),\n\n conversation: () => new ConversationClient({\n baseUrl: (config.baseUrl ?? 'https://studio.contentrain.io/api/cdn/v1').replace('/cdn/v1', '/conversation/v1'),\n projectId: config.projectId,\n apiKey: config.apiKey,\n }),\n\n manifest: () => transport.fetch<unknown>('_manifest.json'),\n models: () => transport.fetch<unknown[]>('models/_index.json'),\n model: (id: string) => transport.fetch<unknown>(`models/${id}.json`),\n }\n}\n\n// Re-exports\nexport { ContentrainError } from './errors.js'\nexport type { CollectionDataSource, SingletonDataSource, DictionaryDataSource, DocumentDataSource } from './data-source.js'\nexport { HttpTransport } from './http-transport.js'\nexport { CdnCollectionQuery } from './collection-query.js'\nexport { CdnSingletonAccessor } from './singleton-accessor.js'\nexport { CdnDictionaryAccessor } from './dictionary-accessor.js'\nexport { CdnDocumentQuery } from './document-query.js'\nexport { MediaAccessor } from './media-accessor.js'\nexport type { MediaAsset, MediaAssetMeta, MediaManifest } from './media-accessor.js'\nexport { FormsClient } from './forms-client.js'\nexport type { FormConfig, FormFieldConfig, FormSubmitResult, FormsClientConfig } from './forms-client.js'\nexport { ConversationClient } from './conversation-client.js'\nexport type {\n ConversationClientConfig,\n ConversationContext,\n ConversationSendOptions,\n ConversationResponse,\n ConversationToolResult,\n ConversationUsage,\n ConversationMessage,\n ConversationHistory,\n} from './conversation-client.js'\n"],"mappings":"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"}
|
package/dist/cli.cjs
CHANGED
package/dist/cli.mjs
CHANGED
|
@@ -152,6 +152,7 @@ function emitTypes(models) {
|
|
|
152
152
|
"// Re-generate with: npx contentrain-query generate",
|
|
153
153
|
"",
|
|
154
154
|
"export type ContentStatus = 'draft' | 'published' | 'in_review' | 'rejected' | 'archived'",
|
|
155
|
+
"export type WhereOp = 'eq' | 'ne' | 'gt' | 'gte' | 'lt' | 'lte' | 'in' | 'contains'",
|
|
155
156
|
""
|
|
156
157
|
];
|
|
157
158
|
for (const model of models) {
|
|
@@ -175,10 +176,12 @@ function emitTypes(models) {
|
|
|
175
176
|
lines.push(`export interface QueryBuilder<T> {
|
|
176
177
|
locale(lang: string): QueryBuilder<T>
|
|
177
178
|
where<K extends keyof T>(field: K, value: T[K]): QueryBuilder<T>
|
|
179
|
+
where<K extends keyof T>(field: K, op: WhereOp, value: unknown): QueryBuilder<T>
|
|
178
180
|
sort<K extends keyof T>(field: K, order?: 'asc' | 'desc'): QueryBuilder<T>
|
|
179
181
|
limit(n: number): QueryBuilder<T>
|
|
180
182
|
offset(n: number): QueryBuilder<T>
|
|
181
183
|
include(...fields: string[]): QueryBuilder<T>
|
|
184
|
+
count(): number
|
|
182
185
|
first(): T | undefined
|
|
183
186
|
all(): T[]
|
|
184
187
|
}`);
|
|
@@ -199,8 +202,10 @@ function emitTypes(models) {
|
|
|
199
202
|
lines.push(`export interface DocumentQuery<T> {
|
|
200
203
|
locale(lang: string): DocumentQuery<T>
|
|
201
204
|
where<K extends keyof T>(field: K, value: T[K]): DocumentQuery<T>
|
|
205
|
+
where<K extends keyof T>(field: K, op: WhereOp, value: unknown): DocumentQuery<T>
|
|
202
206
|
include(...fields: string[]): DocumentQuery<T>
|
|
203
207
|
bySlug(slug: string): T | undefined
|
|
208
|
+
count(): number
|
|
204
209
|
first(): T | undefined
|
|
205
210
|
all(): T[]
|
|
206
211
|
}`);
|
|
@@ -690,19 +695,41 @@ function parseDataFileName(fileName) {
|
|
|
690
695
|
};
|
|
691
696
|
}
|
|
692
697
|
const RUNTIME_CODE = `
|
|
698
|
+
// ─── Runtime Helpers ───
|
|
699
|
+
|
|
700
|
+
function _applyWhere(item, clause) {
|
|
701
|
+
const val = item[clause.field];
|
|
702
|
+
switch (clause.op) {
|
|
703
|
+
case 'eq': return Array.isArray(val) ? val.includes(clause.value) : val === clause.value;
|
|
704
|
+
case 'ne': return val !== clause.value;
|
|
705
|
+
case 'gt': return val > clause.value;
|
|
706
|
+
case 'gte': return val >= clause.value;
|
|
707
|
+
case 'lt': return val < clause.value;
|
|
708
|
+
case 'lte': return val <= clause.value;
|
|
709
|
+
case 'in': return Array.isArray(clause.value) && clause.value.includes(val);
|
|
710
|
+
case 'contains': {
|
|
711
|
+
if (typeof val === 'string') return val.includes(clause.value);
|
|
712
|
+
if (Array.isArray(val)) return val.includes(clause.value);
|
|
713
|
+
return false;
|
|
714
|
+
}
|
|
715
|
+
default: return true;
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
|
|
693
719
|
// ─── Runtime Classes ───
|
|
694
720
|
|
|
695
721
|
class QueryBuilder {
|
|
696
722
|
constructor(data, relationMeta, resolver, defaultLocale) { this._data = data; this._filters = []; this._sortField = null; this._sortOrder = 'asc'; this._limit = null; this._offset = 0; this._locale = null; this._includes = []; this._relationMeta = relationMeta || {}; this._resolver = resolver || null; this._defaultLocale = defaultLocale || null; }
|
|
697
723
|
locale(lang) { this._locale = lang; return this; }
|
|
698
|
-
where(field, value) { this._filters.push(
|
|
724
|
+
where(field, opOrValue, value) { if (value !== undefined) { this._filters.push({ field, op: opOrValue, value }); } else { this._filters.push({ field, op: 'eq', value: opOrValue }); } return this; }
|
|
699
725
|
sort(field, order = 'asc') { this._sortField = field; this._sortOrder = order; return this; }
|
|
700
726
|
limit(n) { this._limit = n; return this; }
|
|
701
727
|
offset(n) { this._offset = n; return this; }
|
|
702
728
|
include(...fields) { this._includes.push(...fields); return this; }
|
|
729
|
+
count() { return this.all().length; }
|
|
703
730
|
all() {
|
|
704
731
|
let items; if (this._locale) { items = [...(this._data.get(this._locale) ?? [])]; } else if (this._defaultLocale && this._data.has(this._defaultLocale)) { items = [...this._data.get(this._defaultLocale)]; } else { items = [...(this._data.get(this._data.keys().next().value) ?? [])]; }
|
|
705
|
-
for (const
|
|
732
|
+
for (const clause of this._filters) items = items.filter(item => _applyWhere(item, clause));
|
|
706
733
|
if (this._sortField) { const sf = this._sortField; const d = this._sortOrder === 'asc' ? 1 : -1; items.sort((a, b) => { const va = a[sf], vb = b[sf]; if (va == null && vb == null) return 0; if (va == null) return d; if (vb == null) return -d; return va < vb ? -d : va > vb ? d : 0; }); }
|
|
707
734
|
if (this._offset > 0 || this._limit !== null) { const end = this._limit !== null ? this._offset + this._limit : undefined; items = items.slice(this._offset, end); }
|
|
708
735
|
if (this._includes.length > 0 && this._resolver) { items = items.map(item => this._resolveIncludes(item)); }
|
|
@@ -761,15 +788,16 @@ class DictionaryAccessor {
|
|
|
761
788
|
class DocumentQuery {
|
|
762
789
|
constructor(data, relationMeta, resolver, defaultLocale) { this._data = data; this._filters = []; this._locale = null; this._includes = []; this._relationMeta = relationMeta || {}; this._resolver = resolver || null; this._defaultLocale = defaultLocale || null; }
|
|
763
790
|
locale(lang) { this._locale = lang; return this; }
|
|
764
|
-
where(field, value) { this._filters.push(
|
|
791
|
+
where(field, opOrValue, value) { if (value !== undefined) { this._filters.push({ field, op: opOrValue, value }); } else { this._filters.push({ field, op: 'eq', value: opOrValue }); } return this; }
|
|
765
792
|
include(...fields) { this._includes.push(...fields); return this; }
|
|
766
793
|
bySlug(slug) {
|
|
767
794
|
const items = this._resolveData(); const item = items.find(x => x.slug === slug);
|
|
768
795
|
if (item && this._includes.length > 0 && this._resolver) return this._resolveIncludes(item);
|
|
769
796
|
return item;
|
|
770
797
|
}
|
|
798
|
+
count() { return this.all().length; }
|
|
771
799
|
first() { return this.all()[0]; }
|
|
772
|
-
all() { let items = this._resolveData(); for (const
|
|
800
|
+
all() { let items = this._resolveData(); for (const clause of this._filters) items = items.filter(item => _applyWhere(item, clause)); if (this._includes.length > 0 && this._resolver) { items = items.map(item => this._resolveIncludes(item)); } return items; }
|
|
773
801
|
_resolveData() { let key; if (this._locale) { key = this._locale; } else if (this._defaultLocale && this._data.has(this._defaultLocale)) { key = this._defaultLocale; } else { key = this._data.keys().next().value; } return [...(this._data.get(key) ?? [])]; }
|
|
774
802
|
_resolveIncludes(item) {
|
|
775
803
|
const resolved = { ...item };
|
|
@@ -852,4 +880,4 @@ async function generate(options) {
|
|
|
852
880
|
//#endregion
|
|
853
881
|
export { generate as t };
|
|
854
882
|
|
|
855
|
-
//# sourceMappingURL=generate-
|
|
883
|
+
//# sourceMappingURL=generate-B5P14n43.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generate-B5P14n43.mjs","names":[],"sources":["../src/generator/utils.ts","../src/generator/config-reader.ts","../src/generator/type-emitter.ts","../src/generator/data-emitter.ts","../src/generator/runtime-emitter.ts","../src/generator/package-json.ts","../src/generator/generate.ts"],"sourcesContent":["import { readFile, readdir, writeFile, mkdir } from 'node:fs/promises'\nimport { join, dirname } from 'node:path'\n\nexport async function readJson<T>(filePath: string): Promise<T | null> {\n try {\n const raw = await readFile(filePath, 'utf-8')\n return JSON.parse(raw) as T\n } catch {\n return null\n }\n}\n\nexport async function readDir(dirPath: string): Promise<string[]> {\n try {\n return await readdir(dirPath)\n } catch {\n return []\n }\n}\n\nexport async function readText(filePath: string): Promise<string | null> {\n try {\n return await readFile(filePath, 'utf-8')\n } catch {\n return null\n }\n}\n\nexport async function writeText(filePath: string, content: string): Promise<void> {\n await mkdir(dirname(filePath), { recursive: true })\n await writeFile(filePath, content, 'utf-8')\n}\n\nexport function contentrainDir(projectRoot: string): string {\n return join(projectRoot, '.contentrain')\n}\n","import type { ContentrainConfig, ModelDefinition, LocaleStrategy } from '@contentrain/types'\nimport { join } from 'node:path'\nimport { readJson, readDir, readText, contentrainDir } from './utils.js'\n\nexport interface ContentFileRef {\n modelId: string\n locale: string | null\n filePath: string\n kind: ModelDefinition['kind']\n /** Extracted slug for document kind (from filename, not frontmatter) */\n slug?: string\n}\n\nexport interface ProjectManifest {\n config: ContentrainConfig\n models: ModelDefinition[]\n contentFiles: ContentFileRef[]\n}\n\nexport async function readProjectManifest(projectRoot: string): Promise<ProjectManifest> {\n const crDir = contentrainDir(projectRoot)\n\n // 1. Read config\n const rawConfig = await readJson<Partial<ContentrainConfig>>(join(crDir, 'config.json'))\n const config: ContentrainConfig = {\n version: rawConfig?.version ?? 1,\n stack: (rawConfig?.stack ?? 'other') as ContentrainConfig['stack'],\n workflow: (rawConfig?.workflow ?? 'auto-merge') as ContentrainConfig['workflow'],\n locales: {\n default: rawConfig?.locales?.default ?? 'en',\n supported: rawConfig?.locales?.supported ?? [rawConfig?.locales?.default ?? 'en'],\n },\n domains: rawConfig?.domains ?? [],\n repository: rawConfig?.repository,\n assets_path: rawConfig?.assets_path,\n branchRetention: rawConfig?.branchRetention,\n }\n\n // 2. Read all models (parallel)\n const modelsDir = join(crDir, 'models')\n const modelFiles = (await readDir(modelsDir)).filter(f => f.endsWith('.json'))\n const modelResults = await Promise.all(\n modelFiles.map(file => readJson<ModelDefinition>(join(modelsDir, file))),\n )\n const models = modelResults\n .filter((m): m is ModelDefinition => m != null && Boolean(m.id))\n .toSorted((a, b) => a.id.localeCompare(b.id, 'en'))\n\n // 3. Map content files (parallel per model)\n const allRefs = await Promise.all(\n models.map(model => mapContentFiles(projectRoot, model, config)),\n )\n const contentFiles = allRefs.flat()\n\n return { config, models, contentFiles }\n}\n\nfunction getContentDir(projectRoot: string, model: ModelDefinition): string {\n if (model.content_path) return join(projectRoot, model.content_path)\n return join(contentrainDir(projectRoot), 'content', model.domain, model.id)\n}\n\nfunction getLocaleStrategy(model: ModelDefinition): LocaleStrategy {\n return model.locale_strategy ?? 'file'\n}\n\nfunction jsonFilePath(dir: string, model: ModelDefinition, locale: string): string {\n const strategy = getLocaleStrategy(model)\n switch (strategy) {\n case 'suffix': return join(dir, `${model.id}.${locale}.json`)\n case 'directory': return join(dir, locale, `${model.id}.json`)\n case 'none': return join(dir, `${model.id}.json`)\n case 'file':\n default: return join(dir, `${locale}.json`)\n }\n}\n\nasync function mapContentFiles(\n projectRoot: string,\n model: ModelDefinition,\n config: ContentrainConfig,\n): Promise<ContentFileRef[]> {\n const dir = getContentDir(projectRoot, model)\n\n if (model.kind === 'document') {\n return mapDocumentFiles(dir, model, config)\n }\n\n // JSON-based models (singleton, collection, dictionary)\n if (model.i18n) {\n const results = await Promise.all(\n config.locales.supported.map(async (locale) => {\n const filePath = jsonFilePath(dir, model, locale)\n const content = await readJson(filePath)\n if (content === null) return null\n return { modelId: model.id, locale, filePath, kind: model.kind } as ContentFileRef\n }),\n )\n return results.filter(Boolean) as ContentFileRef[]\n }\n\n // Non-i18n: always data.json\n const filePath = join(dir, 'data.json')\n const content = await readJson(filePath)\n if (content === null) return []\n return [{ modelId: model.id, locale: null, filePath, kind: model.kind }]\n}\n\nasync function mapDocumentFiles(\n dir: string,\n model: ModelDefinition,\n config: ContentrainConfig,\n): Promise<ContentFileRef[]> {\n const strategy = getLocaleStrategy(model)\n\n if (!model.i18n) {\n // Non-i18n documents: {dir}/{slug}.md\n const files = (await readDir(dir)).filter(f => f.endsWith('.md'))\n return files.map(f => ({\n modelId: model.id,\n locale: null,\n filePath: join(dir, f),\n kind: 'document' as const,\n slug: f.replace('.md', ''),\n }))\n }\n\n // i18n documents — resolve per locale in parallel\n const allLocaleRefs = await Promise.all(\n config.locales.supported.map(locale => mapDocumentLocale(dir, model, locale, strategy)),\n )\n return allLocaleRefs.flat()\n}\n\nasync function mapDocumentLocale(\n dir: string,\n model: ModelDefinition,\n locale: string,\n strategy: LocaleStrategy,\n): Promise<ContentFileRef[]> {\n if (strategy === 'file') {\n // Each slug is a directory: {dir}/{slug}/{locale}.md\n const entries = await readDir(dir)\n const results = await Promise.all(\n entries.map(async (entry) => {\n const filePath = join(dir, entry, `${locale}.md`)\n const content = await readText(filePath)\n if (content === null) return null\n return { modelId: model.id, locale, filePath, kind: 'document', slug: entry } as ContentFileRef\n }),\n )\n return results.filter(Boolean) as ContentFileRef[]\n }\n\n if (strategy === 'directory') {\n // {dir}/{locale}/{slug}.md\n const localeDir = join(dir, locale)\n const files = (await readDir(localeDir)).filter(f => f.endsWith('.md'))\n return files.map(f => ({\n modelId: model.id,\n locale,\n filePath: join(localeDir, f),\n kind: 'document' as const,\n slug: f.replace('.md', ''),\n }))\n }\n\n if (strategy === 'suffix') {\n // {dir}/{slug}.{locale}.md\n const suffix = `.${locale}.md`\n const files = (await readDir(dir)).filter(f => f.endsWith(suffix))\n return files.map(f => ({\n modelId: model.id,\n locale,\n filePath: join(dir, f),\n kind: 'document' as const,\n slug: f.slice(0, -suffix.length),\n }))\n }\n\n return []\n}\n","import type { ModelDefinition, FieldDef } from '@contentrain/types'\n\nexport function emitTypes(models: ModelDefinition[]): string {\n const lines: string[] = [\n '/* eslint-disable */',\n '/* oxlint-disable */',\n '// Auto-generated by @contentrain/query — do not edit manually',\n '// Re-generate with: npx contentrain-query generate',\n '',\n \"export type ContentStatus = 'draft' | 'published' | 'in_review' | 'rejected' | 'archived'\",\n \"export type WhereOp = 'eq' | 'ne' | 'gt' | 'gte' | 'lt' | 'lte' | 'in' | 'contains'\",\n '',\n ]\n\n // Model interfaces\n for (const model of models) {\n if (model.kind === 'dictionary') {\n lines.push(`export type ${kebabToPascal(model.id)} = Record<string, string>`)\n } else {\n lines.push(`export interface ${kebabToPascal(model.id)} {`)\n // System fields by kind\n if (model.kind === 'collection') {\n lines.push(' id: string')\n }\n if (model.kind === 'document') {\n lines.push(' slug: string')\n lines.push(' content: string')\n }\n // User fields\n if (model.fields) {\n for (const [name, field] of Object.entries(model.fields)) {\n const tsType = fieldToTS(field)\n const optional = field.required ? '' : '?'\n lines.push(` ${name}${optional}: ${tsType}`)\n }\n }\n lines.push('}')\n }\n lines.push('')\n }\n\n // Query interfaces\n lines.push(`export interface QueryBuilder<T> {\n locale(lang: string): QueryBuilder<T>\n where<K extends keyof T>(field: K, value: T[K]): QueryBuilder<T>\n where<K extends keyof T>(field: K, op: WhereOp, value: unknown): QueryBuilder<T>\n sort<K extends keyof T>(field: K, order?: 'asc' | 'desc'): QueryBuilder<T>\n limit(n: number): QueryBuilder<T>\n offset(n: number): QueryBuilder<T>\n include(...fields: string[]): QueryBuilder<T>\n count(): number\n first(): T | undefined\n all(): T[]\n}`)\n lines.push('')\n\n lines.push(`export interface SingletonAccessor<T> {\n locale(lang: string): SingletonAccessor<T>\n include(...fields: string[]): SingletonAccessor<T>\n get(): T\n}`)\n lines.push('')\n\n lines.push(`export interface DictionaryAccessor {\n locale(lang: string): DictionaryAccessor\n get(): Record<string, string>\n get(key: string): string | undefined\n get(key: string, params: Record<string, string | number>): string\n}`)\n lines.push('')\n\n lines.push(`export interface DocumentQuery<T> {\n locale(lang: string): DocumentQuery<T>\n where<K extends keyof T>(field: K, value: T[K]): DocumentQuery<T>\n where<K extends keyof T>(field: K, op: WhereOp, value: unknown): DocumentQuery<T>\n include(...fields: string[]): DocumentQuery<T>\n bySlug(slug: string): T | undefined\n count(): number\n first(): T | undefined\n all(): T[]\n}`)\n lines.push('')\n\n // Overloaded entry points\n const collections = models.filter(m => m.kind === 'collection')\n const singletons = models.filter(m => m.kind === 'singleton')\n const dictionaries = models.filter(m => m.kind === 'dictionary')\n const documents = models.filter(m => m.kind === 'document')\n\n // query() overloads\n for (const m of collections) {\n lines.push(`export declare function query(model: '${m.id}'): QueryBuilder<${kebabToPascal(m.id)}>`)\n }\n lines.push('export declare function query(model: string): QueryBuilder<Record<string, unknown>>')\n lines.push('')\n\n // singleton() overloads\n for (const m of singletons) {\n lines.push(`export declare function singleton(model: '${m.id}'): SingletonAccessor<${kebabToPascal(m.id)}>`)\n }\n lines.push('export declare function singleton(model: string): SingletonAccessor<Record<string, unknown>>')\n lines.push('')\n\n // dictionary() overloads\n for (const m of dictionaries) {\n lines.push(`export declare function dictionary(model: '${m.id}'): DictionaryAccessor`)\n }\n lines.push('export declare function dictionary(model: string): DictionaryAccessor')\n lines.push('')\n\n // document() overloads\n for (const m of documents) {\n lines.push(`export declare function document(model: '${m.id}'): DocumentQuery<${kebabToPascal(m.id)}>`)\n }\n lines.push('export declare function document(model: string): DocumentQuery<Record<string, unknown>>')\n lines.push('')\n\n // Typed client interface\n lines.push('export interface ContentrainClient {')\n for (const m of collections) {\n lines.push(` query(model: '${m.id}'): QueryBuilder<${kebabToPascal(m.id)}>`)\n }\n lines.push(' query(model: string): QueryBuilder<Record<string, unknown>>')\n for (const m of singletons) {\n lines.push(` singleton(model: '${m.id}'): SingletonAccessor<${kebabToPascal(m.id)}>`)\n }\n lines.push(' singleton(model: string): SingletonAccessor<Record<string, unknown>>')\n for (const m of dictionaries) {\n lines.push(` dictionary(model: '${m.id}'): DictionaryAccessor`)\n }\n lines.push(' dictionary(model: string): DictionaryAccessor')\n for (const m of documents) {\n lines.push(` document(model: '${m.id}'): DocumentQuery<${kebabToPascal(m.id)}>`)\n }\n lines.push(' document(model: string): DocumentQuery<Record<string, unknown>>')\n lines.push('}')\n lines.push('')\n lines.push('export declare function createContentrainClient(): ContentrainClient')\n lines.push('')\n\n return lines.join('\\n') + '\\n'\n}\n\nfunction fieldToTS(field: FieldDef): string {\n switch (field.type) {\n case 'string': case 'text': case 'email': case 'url': case 'slug':\n case 'color': case 'phone': case 'code': case 'icon':\n case 'markdown': case 'richtext':\n case 'date': case 'datetime':\n case 'image': case 'video': case 'file':\n case 'relation':\n if (Array.isArray(field.model) && field.model.length > 1) {\n const union = field.model.map(m => `'${m}'`).join(' | ')\n return `{ model: ${union}; ref: string }`\n }\n return 'string'\n\n case 'relations':\n if (Array.isArray(field.model) && field.model.length > 1) {\n const union = field.model.map(m => `'${m}'`).join(' | ')\n return `Array<{ model: ${union}; ref: string }>`\n }\n return 'string[]'\n\n case 'number': case 'integer': case 'decimal': case 'percent': case 'rating':\n return 'number'\n\n case 'boolean':\n return 'boolean'\n\n case 'select':\n if (field.options && field.options.length > 0) {\n return field.options.map(o => `'${o}'`).join(' | ')\n }\n return 'string'\n\n case 'array':\n if (field.items) {\n if (typeof field.items === 'string') {\n return `${primitiveToTS(field.items)}[]`\n }\n // items is a FieldDef\n return `${fieldToTS(field.items)}[]`\n }\n return 'unknown[]'\n\n case 'object':\n if (field.fields) {\n const entries = Object.entries(field.fields)\n .map(([k, v]) => `${k}${v.required ? '' : '?'}: ${fieldToTS(v)}`)\n .join('; ')\n return `{ ${entries} }`\n }\n return 'Record<string, unknown>'\n\n default:\n return 'unknown'\n }\n}\n\nfunction primitiveToTS(type: string): string {\n if (['string', 'text', 'email', 'url', 'slug', 'color', 'phone', 'code', 'icon',\n 'markdown', 'richtext', 'date', 'datetime', 'image', 'video', 'file', 'relation'].includes(type)) {\n return 'string'\n }\n if (['number', 'integer', 'decimal', 'percent', 'rating'].includes(type)) {\n return 'number'\n }\n if (type === 'boolean') return 'boolean'\n return 'unknown'\n}\n\nfunction kebabToPascal(s: string): string {\n return s.split('-').map(part => part.charAt(0).toUpperCase() + part.slice(1)).join('')\n}\n","import type { ModelDefinition } from '@contentrain/types'\nimport type { ContentFileRef } from './config-reader.js'\nimport { readJson, readText } from './utils.js'\n\n/** Deterministic JSON: sorted keys, 2-space indent, trailing newline */\nfunction canonicalStringify(data: unknown): string {\n return JSON.stringify(data, (_, v) => {\n if (v && typeof v === 'object' && !Array.isArray(v)) {\n return Object.keys(v).toSorted().reduce<Record<string, unknown>>((acc, k) => {\n acc[k] = (v as Record<string, unknown>)[k]\n return acc\n }, {})\n }\n return v\n }, 2)\n}\n\nexport interface DataModule {\n fileName: string\n content: string\n}\n\nexport async function emitDataModules(\n models: ModelDefinition[],\n contentFiles: ContentFileRef[],\n): Promise<DataModule[]> {\n const results = await Promise.all(\n contentFiles.map(ref => emitSingleModule(ref, models)),\n )\n return results.filter((r): r is DataModule => r !== null)\n}\n\nasync function emitSingleModule(\n ref: ContentFileRef,\n models: ModelDefinition[],\n): Promise<DataModule | null> {\n const model = models.find(m => m.id === ref.modelId)\n if (!model) return null\n\n const localeSuffix = ref.locale ? `.${ref.locale}` : ''\n\n switch (model.kind) {\n case 'collection': {\n const raw = await readJson<Record<string, Record<string, unknown>>>(ref.filePath)\n if (!raw) return null\n const entries = Object.entries(raw)\n .toSorted(([a], [b]) => a.localeCompare(b, 'en'))\n .map(([id, fields]) => Object.assign({ id }, fields))\n return { fileName: `${model.id}${localeSuffix}.mjs`, content: `export default ${canonicalStringify(entries)}\\n` }\n }\n\n case 'singleton': {\n const raw = await readJson<Record<string, unknown>>(ref.filePath)\n if (!raw) return null\n return { fileName: `${model.id}${localeSuffix}.mjs`, content: `export default ${canonicalStringify(raw)}\\n` }\n }\n\n case 'dictionary': {\n const raw = await readJson<Record<string, string>>(ref.filePath)\n if (!raw) return null\n return { fileName: `${model.id}${localeSuffix}.mjs`, content: `export default ${canonicalStringify(raw)}\\n` }\n }\n\n case 'document': {\n const rawText = await readText(ref.filePath)\n if (!rawText) return null\n const { frontmatter, body } = parseFrontmatter(rawText)\n const slug = ref.slug ?? model.id\n const data = { slug, ...frontmatter, content: body }\n return { fileName: `${model.id}--${slug}${localeSuffix}.mjs`, content: `export default ${canonicalStringify(data)}\\n` }\n }\n\n default:\n return null\n }\n}\n\n// Minimal frontmatter parser (replicated from MCP pattern)\nfunction parseFrontmatter(text: string): { frontmatter: Record<string, unknown>; body: string } {\n const normalized = text.replace(/\\r\\n/g, '\\n')\n const match = normalized.match(/^---\\n([\\s\\S]*?)\\n---\\n?([\\s\\S]*)$/)\n if (!match) return { frontmatter: {}, body: normalized }\n\n const fmStr = match[1]!\n const body = match[2]!.trim()\n const frontmatter: Record<string, unknown> = {}\n\n // Stack-based parser that handles nested objects and arrays\n const lines = fmStr.split('\\n')\n const stack: Array<{ obj: Record<string, unknown>; indent: number }> = [{ obj: frontmatter, indent: -1 }]\n\n for (const line of lines) {\n // Skip empty lines\n if (line.trim() === '') continue\n\n // Array item\n const arrayMatch = line.match(/^(\\s*)-\\s+(.*)$/)\n if (arrayMatch) {\n const arrIndent = arrayMatch[1]!.length\n const value = arrayMatch[2]!.trim()\n // Find the parent that owns this array\n while (stack.length > 1 && stack[stack.length - 1]!.indent >= arrIndent) {\n stack.pop()\n }\n const parent = stack[stack.length - 1]!.obj\n const lastKey = Object.keys(parent).pop()\n if (lastKey && Array.isArray(parent[lastKey])) {\n (parent[lastKey] as unknown[]).push(parseValue(value))\n }\n continue\n }\n\n // Key-value pair\n const kvMatch = line.match(/^(\\s*)([\\w][\\w.-]*)\\s*:\\s*(.*)$/)\n if (!kvMatch) continue\n\n const kvIndent = kvMatch[1]!.length\n const key = kvMatch[2]!\n const rawValue = kvMatch[3]!.trim()\n\n // Pop stack to find correct parent based on indentation\n while (stack.length > 1 && stack[stack.length - 1]!.indent >= kvIndent) {\n stack.pop()\n }\n const current = stack[stack.length - 1]!.obj\n\n if (rawValue === '') {\n // Could be nested object or array — peek next line\n const nextLineIdx = lines.indexOf(line) + 1\n const nextLine = nextLineIdx < lines.length ? lines[nextLineIdx]! : ''\n if (nextLine.trim().startsWith('-')) {\n current[key] = []\n } else {\n const nested: Record<string, unknown> = {}\n current[key] = nested\n stack.push({ obj: nested, indent: kvIndent })\n }\n continue\n }\n\n if (rawValue.startsWith('[') && rawValue.endsWith(']')) {\n current[key] = rawValue.slice(1, -1).split(',').map(s => s.trim()).filter(Boolean)\n continue\n }\n\n current[key] = parseValue(rawValue)\n }\n\n return { frontmatter, body }\n}\n\nfunction parseValue(raw: string): unknown {\n if (raw === 'true') return true\n if (raw === 'false') return false\n if (raw === 'null') return null\n if (/^-?\\d+$/.test(raw)) return parseInt(raw, 10)\n if (/^-?\\d+\\.\\d+$/.test(raw)) return parseFloat(raw)\n if ((raw.startsWith('\"') && raw.endsWith('\"')) || (raw.startsWith(\"'\") && raw.endsWith(\"'\"))) {\n return raw.slice(1, -1)\n }\n return raw\n}\n","import type { ModelDefinition } from '@contentrain/types'\nimport type { DataModule } from './data-emitter.js'\n\nexport function emitRuntimeModule(models: ModelDefinition[], dataModules: DataModule[], defaultLocale?: string): string {\n const lines: string[] = [\n '/* eslint-disable */',\n '/* oxlint-disable */',\n '// Auto-generated by @contentrain/query — do not edit manually',\n '',\n ]\n\n // Emit default locale constant if provided\n if (defaultLocale) {\n lines.push(`const _defaultLocale = '${defaultLocale}'`)\n lines.push('')\n }\n\n // Import data modules\n for (const dm of dataModules) {\n const varName = fileNameToVar(dm.fileName)\n lines.push(`import ${varName} from './data/${dm.fileName}'`)\n }\n lines.push('')\n\n // Inline minimal runtime classes\n lines.push(RUNTIME_CODE)\n lines.push('')\n\n // Build registry\n lines.push('// ─── Data Registry ───')\n lines.push('')\n\n // Group data modules by modelId\n const modelDataMap = new Map<string, { varName: string; locale: string | null }[]>()\n for (const dm of dataModules) {\n const { modelId, locale } = parseDataFileName(dm.fileName)\n if (!modelDataMap.has(modelId)) modelDataMap.set(modelId, [])\n modelDataMap.get(modelId)!.push({ varName: fileNameToVar(dm.fileName), locale })\n }\n\n // Create factory functions for each kind\n const collections = models.filter(m => m.kind === 'collection')\n const singletons = models.filter(m => m.kind === 'singleton')\n const dictionaries = models.filter(m => m.kind === 'dictionary')\n const documents = models.filter(m => m.kind === 'document')\n\n // Generate relation metadata for models that have relation fields\n const relationMetaMap = buildRelationMetaMap(models)\n\n // Generate _resolveEntry helper (needed if any model has relations)\n if (relationMetaMap.size > 0) {\n lines.push('// ─── Relation Resolver ───')\n lines.push('')\n lines.push('function _resolveEntry(model, id, locale) {')\n lines.push(' const localeKey = locale ?? \\'_default\\'')\n // Search in collection registry\n if (collections.length > 0) {\n lines.push(' const colData = _collectionRegistry[model]?.get(localeKey)')\n lines.push(' if (colData) { const e = colData.find(x => x.id === id); if (e) return e; }')\n }\n // Search in document registry\n if (documents.length > 0) {\n lines.push(' const docData = _documentRegistry[model]?.get(localeKey)')\n lines.push(' if (docData) { const e = docData.find(x => x.slug === id); if (e) return e; }')\n }\n lines.push(' return undefined')\n lines.push('}')\n lines.push('')\n\n // Emit relation meta objects\n lines.push('const _relationMeta = {')\n for (const [modelId, meta] of relationMetaMap) {\n lines.push(` '${modelId}': {`)\n for (const [field, info] of Object.entries(meta)) {\n const targetStr = Array.isArray(info.target)\n ? `[${info.target.map(t => `'${t}'`).join(', ')}]`\n : `'${info.target}'`\n lines.push(` '${field}': { target: ${targetStr}, multi: ${info.multi} },`)\n }\n lines.push(' },')\n }\n lines.push('}')\n lines.push('')\n }\n\n // query() function\n if (collections.length > 0) {\n lines.push('const _collectionRegistry = {')\n for (const m of collections) {\n const entries = modelDataMap.get(m.id) ?? []\n lines.push(` '${m.id}': new Map([`)\n for (const e of entries) {\n const localeKey = e.locale ?? '_default'\n lines.push(` ['${localeKey}', ${e.varName}],`)\n }\n lines.push(' ]),')\n }\n lines.push('}')\n lines.push('')\n lines.push('export function query(model) {')\n lines.push(' const data = _collectionRegistry[model]')\n lines.push(' if (!data) throw new Error(`Unknown collection model: \"${model}\"`)')\n if (relationMetaMap.size > 0 && defaultLocale) {\n lines.push(' return new QueryBuilder(data, _relationMeta[model], _resolveEntry, _defaultLocale)')\n } else if (relationMetaMap.size > 0) {\n lines.push(' return new QueryBuilder(data, _relationMeta[model], _resolveEntry)')\n } else if (defaultLocale) {\n lines.push(' return new QueryBuilder(data, undefined, undefined, _defaultLocale)')\n } else {\n lines.push(' return new QueryBuilder(data)')\n }\n lines.push('}')\n lines.push('')\n }\n\n // singleton() function\n if (singletons.length > 0) {\n lines.push('const _singletonRegistry = {')\n for (const m of singletons) {\n const entries = modelDataMap.get(m.id) ?? []\n lines.push(` '${m.id}': new Map([`)\n for (const e of entries) {\n const localeKey = e.locale ?? '_default'\n lines.push(` ['${localeKey}', ${e.varName}],`)\n }\n lines.push(' ]),')\n }\n lines.push('}')\n lines.push('')\n lines.push('export function singleton(model) {')\n lines.push(' const data = _singletonRegistry[model]')\n lines.push(' if (!data) throw new Error(`Unknown singleton model: \"${model}\"`)')\n if (relationMetaMap.size > 0 && defaultLocale) {\n lines.push(' return new SingletonAccessor(data, _defaultLocale, _relationMeta[model], _resolveEntry)')\n } else if (relationMetaMap.size > 0) {\n lines.push(' return new SingletonAccessor(data, undefined, _relationMeta[model], _resolveEntry)')\n } else if (defaultLocale) {\n lines.push(' return new SingletonAccessor(data, _defaultLocale)')\n } else {\n lines.push(' return new SingletonAccessor(data)')\n }\n lines.push('}')\n lines.push('')\n }\n\n // dictionary() function\n if (dictionaries.length > 0) {\n lines.push('const _dictionaryRegistry = {')\n for (const m of dictionaries) {\n const entries = modelDataMap.get(m.id) ?? []\n lines.push(` '${m.id}': new Map([`)\n for (const e of entries) {\n const localeKey = e.locale ?? '_default'\n lines.push(` ['${localeKey}', ${e.varName}],`)\n }\n lines.push(' ]),')\n }\n lines.push('}')\n lines.push('')\n lines.push('export function dictionary(model) {')\n lines.push(' const data = _dictionaryRegistry[model]')\n lines.push(' if (!data) throw new Error(`Unknown dictionary model: \"${model}\"`)')\n lines.push(defaultLocale ? ' return new DictionaryAccessor(data, _defaultLocale)' : ' return new DictionaryAccessor(data)')\n lines.push('}')\n lines.push('')\n }\n\n // document() function\n if (documents.length > 0) {\n // Group document data modules by model+locale and merge into arrays\n for (const m of documents) {\n const entries = modelDataMap.get(m.id) ?? []\n // Group entries by locale\n const byLocale = new Map<string, string[]>()\n for (const e of entries) {\n const localeKey = e.locale ?? '_default'\n if (!byLocale.has(localeKey)) byLocale.set(localeKey, [])\n byLocale.get(localeKey)!.push(e.varName)\n }\n lines.push(`const _doc_${m.id.replace(/-/g, '_')} = new Map([`)\n for (const [localeKey, varNames] of byLocale) {\n lines.push(` ['${localeKey}', [${varNames.join(', ')}]],`)\n }\n lines.push('])')\n }\n lines.push('')\n lines.push('const _documentRegistry = {')\n for (const m of documents) {\n lines.push(` '${m.id}': _doc_${m.id.replace(/-/g, '_')},`)\n }\n lines.push('}')\n lines.push('')\n lines.push('export function document(model) {')\n lines.push(' const data = _documentRegistry[model]')\n lines.push(' if (!data) throw new Error(`Unknown document model: \"${model}\"`)')\n if (relationMetaMap.size > 0 && defaultLocale) {\n lines.push(' return new DocumentQuery(data, _relationMeta[model], _resolveEntry, _defaultLocale)')\n } else if (relationMetaMap.size > 0) {\n lines.push(' return new DocumentQuery(data, _relationMeta[model], _resolveEntry)')\n } else if (defaultLocale) {\n lines.push(' return new DocumentQuery(data, undefined, undefined, _defaultLocale)')\n } else {\n lines.push(' return new DocumentQuery(data)')\n }\n lines.push('}')\n lines.push('')\n }\n\n return lines.join('\\n') + '\\n'\n}\n\nexport function emitCjsWrapper(models: ModelDefinition[]): string {\n const exports: string[] = []\n if (models.some(m => m.kind === 'collection')) exports.push('query')\n if (models.some(m => m.kind === 'singleton')) exports.push('singleton')\n if (models.some(m => m.kind === 'dictionary')) exports.push('dictionary')\n if (models.some(m => m.kind === 'document')) exports.push('document')\n\n return `/* eslint-disable */\n/* oxlint-disable */\n// Auto-generated CJS proxy — delegates to ESM via dynamic import()\n// Sync usage: const client = require('#contentrain'); client.query('model')\n// Async usage: const client = await require('#contentrain').init()\n'use strict'\nlet _mod = null\nlet _promise = null\n\nfunction _ensure() {\n if (_mod) return _mod\n throw new Error(\n 'Contentrain client not initialized. Call .init() first, then access exports.\\\\n'\n + 'Example: require(\"#contentrain\").init().then(c => c.query(\"model\"))'\n )\n}\n\nmodule.exports.init = function() {\n if (!_promise) _promise = import('./index.mjs').then(function(m) {\n _mod = m\n${exports.map(e => ` module.exports.${e} = m.${e}`).join('\\n')}\n return module.exports\n })\n return _promise\n}\n\n// Eagerly start loading so subsequent sync calls work after first await\n_promise = import('./index.mjs').then(function(m) {\n _mod = m\n${exports.map(e => ` module.exports.${e} = m.${e}`).join('\\n')}\n return module.exports\n}).catch(function() { _promise = null; /* retry on next init() call */ })\n`\n}\n\nfunction buildRelationMetaMap(\n models: ModelDefinition[],\n): Map<string, Record<string, { target: string | string[]; multi: boolean }>> {\n const result = new Map<string, Record<string, { target: string | string[]; multi: boolean }>>()\n\n for (const model of models) {\n if (!model.fields) continue\n const meta: Record<string, { target: string | string[]; multi: boolean }> = {}\n let hasRelations = false\n\n for (const [fieldName, field] of Object.entries(model.fields)) {\n if (field.type === 'relation' && field.model) {\n meta[fieldName] = { target: field.model, multi: false }\n hasRelations = true\n } else if (field.type === 'relations' && field.model) {\n meta[fieldName] = { target: field.model, multi: true }\n hasRelations = true\n }\n }\n\n if (hasRelations) {\n result.set(model.id, meta)\n }\n }\n\n return result\n}\n\nfunction fileNameToVar(fileName: string): string {\n // blog-post.en.mjs → _blogPostEn\n const base = fileName.replace('.mjs', '')\n const parts = base.split(/[-.]/)\n return '_' + parts.map((p, i) => i === 0 ? p : p.charAt(0).toUpperCase() + p.slice(1)).join('')\n}\n\nfunction parseDataFileName(fileName: string): { modelId: string; locale: string | null } {\n const base = fileName.replace('.mjs', '')\n\n // Document files use \"modelId--slug.locale\" or \"modelId--slug\" format\n // Extract modelId from before \"--\", ignore slug part\n let nameForLocale = base\n if (base.includes('--')) {\n nameForLocale = base // locale is still the last dot-segment\n }\n\n // Extract locale from last dot-segment (e.g., \"blog-post.en\" → locale \"en\")\n const parts = nameForLocale.split('.')\n let locale: string | null = null\n let nameWithoutLocale = nameForLocale\n if (parts.length >= 2) {\n const possibleLocale = parts[parts.length - 1]!\n if (possibleLocale.length === 2 || possibleLocale.includes('-')) {\n locale = possibleLocale\n nameWithoutLocale = parts.slice(0, -1).join('.')\n }\n }\n\n // Extract modelId: if \"--\" present, it's the part before \"--\"\n const modelId = nameWithoutLocale.includes('--')\n ? nameWithoutLocale.split('--')[0]!\n : nameWithoutLocale\n\n return { modelId, locale }\n}\n\n// Inlined runtime code — zero dependencies\nconst RUNTIME_CODE = `\n// ─── Runtime Helpers ───\n\nfunction _applyWhere(item, clause) {\n const val = item[clause.field];\n switch (clause.op) {\n case 'eq': return Array.isArray(val) ? val.includes(clause.value) : val === clause.value;\n case 'ne': return val !== clause.value;\n case 'gt': return val > clause.value;\n case 'gte': return val >= clause.value;\n case 'lt': return val < clause.value;\n case 'lte': return val <= clause.value;\n case 'in': return Array.isArray(clause.value) && clause.value.includes(val);\n case 'contains': {\n if (typeof val === 'string') return val.includes(clause.value);\n if (Array.isArray(val)) return val.includes(clause.value);\n return false;\n }\n default: return true;\n }\n}\n\n// ─── Runtime Classes ───\n\nclass QueryBuilder {\n constructor(data, relationMeta, resolver, defaultLocale) { this._data = data; this._filters = []; this._sortField = null; this._sortOrder = 'asc'; this._limit = null; this._offset = 0; this._locale = null; this._includes = []; this._relationMeta = relationMeta || {}; this._resolver = resolver || null; this._defaultLocale = defaultLocale || null; }\n locale(lang) { this._locale = lang; return this; }\n where(field, opOrValue, value) { if (value !== undefined) { this._filters.push({ field, op: opOrValue, value }); } else { this._filters.push({ field, op: 'eq', value: opOrValue }); } return this; }\n sort(field, order = 'asc') { this._sortField = field; this._sortOrder = order; return this; }\n limit(n) { this._limit = n; return this; }\n offset(n) { this._offset = n; return this; }\n include(...fields) { this._includes.push(...fields); return this; }\n count() { return this.all().length; }\n all() {\n let items; if (this._locale) { items = [...(this._data.get(this._locale) ?? [])]; } else if (this._defaultLocale && this._data.has(this._defaultLocale)) { items = [...this._data.get(this._defaultLocale)]; } else { items = [...(this._data.get(this._data.keys().next().value) ?? [])]; }\n for (const clause of this._filters) items = items.filter(item => _applyWhere(item, clause));\n if (this._sortField) { const sf = this._sortField; const d = this._sortOrder === 'asc' ? 1 : -1; items.sort((a, b) => { const va = a[sf], vb = b[sf]; if (va == null && vb == null) return 0; if (va == null) return d; if (vb == null) return -d; return va < vb ? -d : va > vb ? d : 0; }); }\n if (this._offset > 0 || this._limit !== null) { const end = this._limit !== null ? this._offset + this._limit : undefined; items = items.slice(this._offset, end); }\n if (this._includes.length > 0 && this._resolver) { items = items.map(item => this._resolveIncludes(item)); }\n return items;\n }\n first() { return this.all()[0]; }\n _resolveIncludes(item) {\n const resolved = { ...item };\n for (const field of this._includes) {\n const meta = this._relationMeta[field]; if (!meta) continue;\n const targets = Array.isArray(meta.target) ? meta.target : [meta.target];\n if (meta.multi) { const ids = item[field]; if (Array.isArray(ids)) { resolved[field] = ids.map(id => { if (typeof id === 'string') { for (const t of targets) { const r = this._resolver(t, id, this._locale); if (r) return r; } return id; } if (typeof id === 'object' && id !== null && 'model' in id && 'ref' in id) { const r = this._resolver(id.model, id.ref, this._locale); if (r) return r; } return id; }); } }\n else { const id = item[field]; if (typeof id === 'string') { for (const t of targets) { const r = this._resolver(t, id, this._locale); if (r) { resolved[field] = r; break; } } } else if (typeof id === 'object' && id !== null && 'model' in id && 'ref' in id) { const r = this._resolver(id.model, id.ref, this._locale); if (r) resolved[field] = r; } }\n }\n return resolved;\n }\n}\n\nclass SingletonAccessor {\n constructor(data, defaultLocale, relationMeta, resolveEntry) { this._data = data; this._locale = null; this._defaultLocale = defaultLocale || null; this._includes = []; this._relationMeta = relationMeta || {}; this._resolver = resolveEntry; }\n locale(lang) { this._locale = lang; return this; }\n include(...fields) { this._includes.push(...fields); return this; }\n get() {\n const locale = this._locale || this._defaultLocale;\n let d = locale ? this._data.get(locale) : undefined;\n if (!d) { const key = this._data.keys().next().value; d = key !== undefined ? this._data.get(key) : undefined; }\n if (!d) throw new Error('No data available');\n if (this._includes.length > 0 && this._resolver) return this._resolveIncludes(d, locale || 'en');\n return d;\n }\n _resolveIncludes(item, locale) {\n const resolved = { ...item };\n for (const field of this._includes) {\n const meta = this._relationMeta[field]; if (!meta) continue;\n const targets = Array.isArray(meta.target) ? meta.target : [meta.target];\n if (meta.multi) { const ids = item[field]; if (Array.isArray(ids)) { resolved[field] = ids.map(id => { if (typeof id === 'string') { for (const t of targets) { const r = this._resolver(t, id, locale); if (r) return r; } return id; } if (typeof id === 'object' && id !== null && 'model' in id && 'ref' in id) { const r = this._resolver(id.model, id.ref, locale); if (r) return r; } return id; }); } }\n else { const id = item[field]; if (typeof id === 'string') { for (const t of targets) { const r = this._resolver(t, id, locale); if (r) { resolved[field] = r; break; } } } else if (typeof id === 'object' && id !== null && 'model' in id && 'ref' in id) { const r = this._resolver(id.model, id.ref, locale); if (r) resolved[field] = r; } }\n }\n return resolved;\n }\n}\n\nclass DictionaryAccessor {\n constructor(data, defaultLocale) { this._data = data; this._locale = null; this._defaultLocale = defaultLocale || null; }\n locale(lang) { this._locale = lang; return this; }\n get(key, params) {\n let dict; if (this._locale) { dict = this._data.get(this._locale) ?? {}; } else if (this._defaultLocale && this._data.has(this._defaultLocale)) { dict = this._data.get(this._defaultLocale); } else { const loc = this._data.keys().next().value; dict = this._data.get(loc) ?? {}; }\n if (key === undefined) return dict;\n const val = dict[key];\n if (val === undefined) return undefined;\n if (params) return val.replace(/{(w+)}/g, (m, k) => { const v = params[k]; return v !== undefined ? String(v) : m; });\n return val;\n }\n}\n\nclass DocumentQuery {\n constructor(data, relationMeta, resolver, defaultLocale) { this._data = data; this._filters = []; this._locale = null; this._includes = []; this._relationMeta = relationMeta || {}; this._resolver = resolver || null; this._defaultLocale = defaultLocale || null; }\n locale(lang) { this._locale = lang; return this; }\n where(field, opOrValue, value) { if (value !== undefined) { this._filters.push({ field, op: opOrValue, value }); } else { this._filters.push({ field, op: 'eq', value: opOrValue }); } return this; }\n include(...fields) { this._includes.push(...fields); return this; }\n bySlug(slug) {\n const items = this._resolveData(); const item = items.find(x => x.slug === slug);\n if (item && this._includes.length > 0 && this._resolver) return this._resolveIncludes(item);\n return item;\n }\n count() { return this.all().length; }\n first() { return this.all()[0]; }\n all() { let items = this._resolveData(); for (const clause of this._filters) items = items.filter(item => _applyWhere(item, clause)); if (this._includes.length > 0 && this._resolver) { items = items.map(item => this._resolveIncludes(item)); } return items; }\n _resolveData() { let key; if (this._locale) { key = this._locale; } else if (this._defaultLocale && this._data.has(this._defaultLocale)) { key = this._defaultLocale; } else { key = this._data.keys().next().value; } return [...(this._data.get(key) ?? [])]; }\n _resolveIncludes(item) {\n const resolved = { ...item };\n for (const field of this._includes) {\n const meta = this._relationMeta[field]; if (!meta) continue;\n const targets = Array.isArray(meta.target) ? meta.target : [meta.target];\n if (meta.multi) { const ids = item[field]; if (Array.isArray(ids)) { resolved[field] = ids.map(id => { if (typeof id === 'string') { for (const t of targets) { const r = this._resolver(t, id, this._locale); if (r) return r; } return id; } if (typeof id === 'object' && id !== null && 'model' in id && 'ref' in id) { const r = this._resolver(id.model, id.ref, this._locale); if (r) return r; } return id; }); } }\n else { const id = item[field]; if (typeof id === 'string') { for (const t of targets) { const r = this._resolver(t, id, this._locale); if (r) { resolved[field] = r; break; } } } else if (typeof id === 'object' && id !== null && 'model' in id && 'ref' in id) { const r = this._resolver(id.model, id.ref, this._locale); if (r) resolved[field] = r; } }\n }\n return resolved;\n }\n}\n`.trim()\n","import { join } from 'node:path'\nimport { readJson, writeText } from './utils.js'\n\nconst IMPORTS_CONFIG = {\n '#contentrain': {\n types: './.contentrain/client/index.d.ts',\n import: './.contentrain/client/index.mjs',\n require: './.contentrain/client/index.cjs',\n default: './.contentrain/client/index.mjs',\n },\n '#contentrain/*': {\n types: './.contentrain/client/*.d.ts',\n import: './.contentrain/client/*.mjs',\n require: './.contentrain/client/*.cjs',\n default: './.contentrain/client/*.mjs',\n },\n}\n\nexport async function injectImports(projectRoot: string): Promise<boolean> {\n const pkgPath = join(projectRoot, 'package.json')\n const pkg = await readJson<Record<string, unknown>>(pkgPath)\n if (!pkg) return false\n\n const existing = (pkg['imports'] as Record<string, unknown>) ?? {}\n const updated = { ...existing, ...IMPORTS_CONFIG }\n\n // Check if already matches\n if (JSON.stringify(existing['#contentrain']) === JSON.stringify(IMPORTS_CONFIG['#contentrain']) &&\n JSON.stringify(existing['#contentrain/*']) === JSON.stringify(IMPORTS_CONFIG['#contentrain/*'])) {\n return false // No change needed\n }\n\n pkg['imports'] = updated\n await writeText(pkgPath, JSON.stringify(pkg, null, 2) + '\\n')\n return true\n}\n","import { join } from 'node:path'\nimport { rm } from 'node:fs/promises'\nimport { readProjectManifest } from './config-reader.js'\nimport { emitTypes } from './type-emitter.js'\nimport { emitDataModules } from './data-emitter.js'\nimport { emitRuntimeModule, emitCjsWrapper } from './runtime-emitter.js'\nimport { injectImports } from './package-json.js'\nimport { readDir, writeText } from './utils.js'\n\nexport interface GenerateOptions {\n projectRoot: string\n}\n\nexport interface GenerateResult {\n generatedFiles: string[]\n typesCount: number\n dataModulesCount: number\n packageJsonUpdated: boolean\n}\n\nexport async function generate(options: GenerateOptions): Promise<GenerateResult> {\n const { projectRoot } = options\n const clientDir = join(projectRoot, '.contentrain', 'client')\n const dataDir = join(clientDir, 'data')\n\n // 1. Read project manifest\n const manifest = await readProjectManifest(projectRoot)\n\n // 2. Generate data modules (async — reads content files)\n const dataModules = await emitDataModules(manifest.models, manifest.contentFiles)\n\n // 3. Generate all output content (sync — pure string transforms)\n const typesContent = emitTypes(manifest.models)\n const runtimeContent = emitRuntimeModule(manifest.models, dataModules, manifest.config.locales.default)\n const cjsContent = emitCjsWrapper(manifest.models)\n\n // 4. Clean stale data modules\n const newFileNames = new Set(dataModules.map(dm => dm.fileName))\n try {\n const existing = await readDir(dataDir)\n await Promise.all(\n existing\n .filter(f => !newFileNames.has(f))\n .map(f => rm(join(dataDir, f), { force: true })),\n )\n } catch { /* dataDir may not exist yet */ }\n\n // 5. Write all files in parallel\n const dataFileNames = dataModules.map(dm => `data/${dm.fileName}`)\n await Promise.all([\n writeText(join(clientDir, 'index.d.ts'), typesContent),\n writeText(join(clientDir, 'index.mjs'), runtimeContent),\n writeText(join(clientDir, 'index.cjs'), cjsContent),\n ...dataModules.map(dm => writeText(join(dataDir, dm.fileName), dm.content)),\n ])\n\n // 6. Inject #imports into package.json\n const packageJsonUpdated = await injectImports(projectRoot)\n\n return {\n generatedFiles: ['index.d.ts', ...dataFileNames, 'index.mjs', 'index.cjs'],\n typesCount: manifest.models.length,\n dataModulesCount: dataModules.length,\n packageJsonUpdated,\n }\n}\n"],"mappings":"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"}
|