@rizom/brain 0.2.0-alpha.6 → 0.2.0-alpha.60

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/README.md +1 -1
  2. package/dist/brain.js +4762 -26509
  3. package/dist/deploy.d.ts +17 -26
  4. package/dist/deploy.js +25 -25
  5. package/dist/deploy.js.map +4 -4
  6. package/dist/entities.d.ts +561 -0
  7. package/dist/entities.js +172 -0
  8. package/dist/entities.js.map +242 -0
  9. package/dist/index.d.ts +65 -0
  10. package/dist/index.js +5 -0
  11. package/dist/index.js.map +11 -0
  12. package/dist/interfaces.d.ts +923 -0
  13. package/dist/interfaces.js +172 -0
  14. package/dist/interfaces.js.map +209 -0
  15. package/dist/plugins.d.ts +1195 -0
  16. package/dist/plugins.js +178 -0
  17. package/dist/plugins.js.map +294 -0
  18. package/dist/seed-content/relay/README.md +28 -371
  19. package/dist/seed-content/relay/anchor-profile/anchor-profile.md +8 -11
  20. package/dist/seed-content/relay/brain-character/brain-character.md +5 -4
  21. package/dist/seed-content/relay/site-content/about/about.md +20 -0
  22. package/dist/seed-content/relay/site-content/home/diagram.md +184 -0
  23. package/dist/seed-content/relay/site-info/site-info.md +11 -1
  24. package/dist/services.d.ts +601 -0
  25. package/dist/services.js +172 -0
  26. package/dist/services.js.map +242 -0
  27. package/dist/site.d.ts +56 -157
  28. package/dist/site.js +323 -463
  29. package/dist/site.js.map +131 -249
  30. package/dist/templates.d.ts +302 -0
  31. package/dist/templates.js +172 -0
  32. package/dist/templates.js.map +206 -0
  33. package/dist/themes.d.ts +5 -44
  34. package/dist/themes.js +91 -8
  35. package/dist/themes.js.map +2 -2
  36. package/package.json +35 -4
  37. package/templates/deploy/scripts/provision-server.ts +109 -0
  38. package/templates/deploy/scripts/update-dns.ts +65 -0
  39. package/templates/deploy/scripts/write-ssh-key.ts +17 -0
  40. package/tsconfig.instance.json +31 -0
@@ -0,0 +1,601 @@
1
+ import { z } from 'zod';
2
+
3
+ /**
4
+ * Logger interface for consistent logging across the application
5
+ * Simplified version without Winston dependency
6
+ */
7
+ /**
8
+ * Log levels
9
+ */
10
+ declare enum LogLevel {
11
+ SILLY = 0,
12
+ VERBOSE = 1,
13
+ DEBUG = 2,
14
+ INFO = 3,
15
+ WARN = 4,
16
+ ERROR = 5,
17
+ NONE = 6
18
+ }
19
+ /**
20
+ * Logger implementation with Component Interface Standardization pattern
21
+ */
22
+ type LogFormat = "text" | "json";
23
+ interface LoggerOptions {
24
+ level?: LogLevel;
25
+ context?: string;
26
+ useStderr?: boolean;
27
+ format?: LogFormat;
28
+ /** Path to a log file. Always writes JSON, one line per entry. */
29
+ logFile?: string;
30
+ }
31
+ declare class Logger {
32
+ /** The singleton instance */
33
+ private static instance;
34
+ private level;
35
+ private context;
36
+ private useStderr;
37
+ private format;
38
+ private logFile;
39
+ private fileHandle;
40
+ /**
41
+ * Private constructor to enforce singleton pattern
42
+ */
43
+ private constructor();
44
+ /**
45
+ * Get the singleton instance of Logger
46
+ */
47
+ static getInstance(options?: LoggerOptions): Logger;
48
+ /**
49
+ * Reset the singleton instance (primarily for testing)
50
+ */
51
+ static resetInstance(): void;
52
+ /**
53
+ * Create a fresh instance without affecting the singleton
54
+ */
55
+ static createFresh(options?: LoggerOptions): Logger;
56
+ /**
57
+ * Format a log entry for output.
58
+ * Text: [timestamp] [context] message
59
+ * JSON: {"ts":"...","level":"...","ctx":"...","msg":"...","data":[...]}
60
+ */
61
+ private formatEntry;
62
+ /**
63
+ * Log a message at the 'silly' level
64
+ */
65
+ /**
66
+ * Write a formatted log entry to the appropriate output stream.
67
+ * JSON format: single string argument (no spread).
68
+ * Text format: message + spread args for console formatting.
69
+ */
70
+ private write;
71
+ /**
72
+ * Format a JSON log entry (used for file output regardless of console format).
73
+ */
74
+ private formatJsonEntry;
75
+ silly(message: string, ...args: unknown[]): void;
76
+ verbose(message: string, ...args: unknown[]): void;
77
+ debug(message: string, ...args: unknown[]): void;
78
+ info(message: string, ...args: unknown[]): void;
79
+ warn(message: string, ...args: unknown[]): void;
80
+ error(message: string, ...args: unknown[]): void;
81
+ /**
82
+ * Create a child logger with a specific context
83
+ */
84
+ child(context: string): Logger;
85
+ /**
86
+ * Configure the logger to use stderr for all output
87
+ * Useful for MCP servers that need stdout for JSON-RPC
88
+ */
89
+ setUseStderr(useStderr: boolean): void;
90
+ }
91
+
92
+ /**
93
+ * Options for entity mutation operations (create, update, upsert)
94
+ */
95
+ interface EntityJobOptions {
96
+ priority?: number;
97
+ maxRetries?: number;
98
+ }
99
+ /**
100
+ * Options for entity creation (extends EntityJobOptions with deduplication)
101
+ */
102
+ interface CreateEntityOptions extends EntityJobOptions {
103
+ deduplicateId?: boolean;
104
+ }
105
+ /**
106
+ * Result of an entity mutation that triggers an embedding job.
107
+ * When skipped is true, content was unchanged — no DB write, no event, no embedding job.
108
+ */
109
+ interface EntityMutationResult {
110
+ entityId: string;
111
+ jobId: string;
112
+ skipped: boolean;
113
+ }
114
+ /**
115
+ * Input for adapter-validated direct creation from finalized markdown.
116
+ */
117
+ interface CreateEntityFromMarkdownInput {
118
+ entityType: string;
119
+ id: string;
120
+ markdown: string;
121
+ }
122
+ /**
123
+ * Data for storing an embedding for an entity
124
+ */
125
+ interface StoreEmbeddingData {
126
+ entityId: string;
127
+ entityType: string;
128
+ embedding: Float32Array;
129
+ contentHash: string;
130
+ }
131
+ /**
132
+ * Base entity type - generic to support typed metadata
133
+ * TMetadata defaults to Record<string, unknown> for backward compatibility
134
+ */
135
+ interface BaseEntity<TMetadata = Record<string, unknown>> {
136
+ id: string;
137
+ entityType: string;
138
+ content: string;
139
+ created: string;
140
+ updated: string;
141
+ metadata: TMetadata;
142
+ /** SHA256 hash of content for change detection */
143
+ contentHash: string;
144
+ }
145
+ /**
146
+ * Entity input type for creation - allows partial entities with optional system fields
147
+ * contentHash is excluded because it's computed automatically by the entity service
148
+ */
149
+ type EntityInput<T extends BaseEntity> = Omit<T, "id" | "created" | "updated" | "contentHash"> & {
150
+ id?: string;
151
+ created?: string;
152
+ updated?: string;
153
+ };
154
+ /**
155
+ * Search result type
156
+ */
157
+ interface SearchResult<T extends BaseEntity = BaseEntity> {
158
+ entity: T;
159
+ score: number;
160
+ excerpt: string;
161
+ }
162
+ /**
163
+ * Sort field specification for multi-field sorting
164
+ */
165
+ interface SortField {
166
+ /** Field to sort by - "created", "updated", or a metadata field name */
167
+ field: string;
168
+ /** Sort direction */
169
+ direction: "asc" | "desc";
170
+ /** Sort NULL values before non-NULL values (default: false / SQLite default) */
171
+ nullsFirst?: boolean;
172
+ }
173
+ /**
174
+ * List entities options
175
+ * Generic over metadata type for type-safe filtering
176
+ */
177
+ interface ListOptions<TMetadata = Record<string, unknown>> {
178
+ limit?: number;
179
+ offset?: number;
180
+ /** Multi-field sorting - supports system fields (created, updated) and metadata fields */
181
+ sortFields?: SortField[];
182
+ filter?: {
183
+ metadata?: Partial<TMetadata>;
184
+ };
185
+ /** Filter to only entities with metadata.status = "published" */
186
+ publishedOnly?: boolean;
187
+ }
188
+ /**
189
+ * Search options
190
+ */
191
+ interface SearchOptions {
192
+ limit?: number;
193
+ offset?: number;
194
+ types?: string[];
195
+ excludeTypes?: string[];
196
+ sortBy?: "relevance" | "created" | "updated";
197
+ sortDirection?: "asc" | "desc";
198
+ /** Score multipliers per entity type - applied after initial search */
199
+ weight?: Record<string, number>;
200
+ }
201
+ /**
202
+ * Core entity service interface for read-only operations
203
+ * Used by core plugins that need entity access but shouldn't modify entities
204
+ */
205
+ interface GetEntityRequest {
206
+ entityType: string;
207
+ id: string;
208
+ }
209
+ type GetEntityRawRequest = GetEntityRequest;
210
+ interface ListEntitiesRequest {
211
+ entityType: string;
212
+ options?: ListOptions | undefined;
213
+ }
214
+ interface CountEntitiesRequest {
215
+ entityType: string;
216
+ options?: Pick<ListOptions, "publishedOnly" | "filter"> | undefined;
217
+ }
218
+ interface CreateEntityRequest<T extends BaseEntity> {
219
+ entity: EntityInput<T>;
220
+ options?: CreateEntityOptions | undefined;
221
+ }
222
+ interface CreateEntityFromMarkdownRequest {
223
+ input: CreateEntityFromMarkdownInput;
224
+ options?: CreateEntityOptions | undefined;
225
+ }
226
+ interface UpdateEntityRequest<T extends BaseEntity> {
227
+ entity: T;
228
+ options?: EntityJobOptions | undefined;
229
+ }
230
+ interface DeleteEntityRequest {
231
+ entityType: string;
232
+ id: string;
233
+ }
234
+ interface UpsertEntityRequest<T extends BaseEntity> {
235
+ entity: T;
236
+ options?: EntityJobOptions | undefined;
237
+ }
238
+ interface EntitySearchRequest {
239
+ query: string;
240
+ options?: SearchOptions | undefined;
241
+ }
242
+ interface SearchWithDistancesRequest {
243
+ query: string;
244
+ }
245
+ interface ICoreEntityService {
246
+ getEntity<T extends BaseEntity>(request: GetEntityRequest): Promise<T | null>;
247
+ /**
248
+ * Get entity without content resolution (raw)
249
+ * Used internally to avoid recursion when resolving image references
250
+ */
251
+ getEntityRaw<T extends BaseEntity>(request: GetEntityRawRequest): Promise<T | null>;
252
+ listEntities<T extends BaseEntity>(request: ListEntitiesRequest): Promise<T[]>;
253
+ search<T extends BaseEntity = BaseEntity>(request: EntitySearchRequest): Promise<SearchResult<T>[]>;
254
+ getEntityTypes(): string[];
255
+ hasEntityType(type: string): boolean;
256
+ countEntities(request: CountEntitiesRequest): Promise<number>;
257
+ getEntityCounts(): Promise<Array<{
258
+ entityType: string;
259
+ count: number;
260
+ }>>;
261
+ /** Get weight map for all registered entity types with non-default weights */
262
+ getWeightMap(): Record<string, number>;
263
+ }
264
+ /**
265
+ * Entity service interface for managing brain entities
266
+ */
267
+ interface EntityService extends ICoreEntityService {
268
+ createEntity<T extends BaseEntity>(request: CreateEntityRequest<T>): Promise<EntityMutationResult>;
269
+ createEntityFromMarkdown(request: CreateEntityFromMarkdownRequest): Promise<EntityMutationResult>;
270
+ updateEntity<T extends BaseEntity>(request: UpdateEntityRequest<T>): Promise<EntityMutationResult>;
271
+ deleteEntity(request: DeleteEntityRequest): Promise<boolean>;
272
+ upsertEntity<T extends BaseEntity>(request: UpsertEntityRequest<T>): Promise<EntityMutationResult & {
273
+ created: boolean;
274
+ }>;
275
+ storeEmbedding(data: StoreEmbeddingData): Promise<void>;
276
+ serializeEntity(entity: BaseEntity): string;
277
+ deserializeEntity(markdown: string, entityType: string): Partial<BaseEntity>;
278
+ countEmbeddings(): Promise<number>;
279
+ searchWithDistances(request: SearchWithDistancesRequest): Promise<Array<{
280
+ entityId: string;
281
+ entityType: string;
282
+ distance: number;
283
+ }>>;
284
+ initialize(): Promise<void>;
285
+ getAsyncJobStatus(jobId: string): Promise<{
286
+ status: "pending" | "processing" | "completed" | "failed";
287
+ error?: string;
288
+ } | null>;
289
+ }
290
+
291
+ /**
292
+ * Context passed to all DataSource operations
293
+ * Contains internal state that should not be mixed with user query parameters
294
+ */
295
+ interface BaseDataSourceContext {
296
+ /**
297
+ * Whether to filter to only published/complete content
298
+ * Set by site-builder: true for production, false for preview
299
+ */
300
+ publishedOnly?: boolean;
301
+ /**
302
+ * Scoped entity service that auto-applies publishedOnly filter
303
+ * Datasources should use this instead of their injected entityService
304
+ * to ensure consistent filtering behavior across environments
305
+ */
306
+ entityService: EntityService;
307
+ }
308
+ /**
309
+ * DataSource Interface
310
+ *
311
+ * Provides data for templates through fetch, generate, or transform operations.
312
+ * DataSources are registered in the DataSourceRegistry and referenced by templates
313
+ * via their dataSourceId property.
314
+ */
315
+ interface DataSource {
316
+ /**
317
+ * Unique identifier for this data source
318
+ */
319
+ id: string;
320
+ /**
321
+ * Human-readable name for this data source
322
+ */
323
+ name: string;
324
+ /**
325
+ * Optional description of what this data source provides
326
+ */
327
+ description?: string;
328
+ /**
329
+ * Optional: Fetch existing data
330
+ * Used by data sources that aggregate or retrieve data (e.g., dashboard stats, API data)
331
+ * DataSources validate output using the provided schema
332
+ * @param query - Query parameters for fetching data
333
+ * @param outputSchema - Schema for validating output data
334
+ * @param context - Context with environment
335
+ */
336
+ fetch?: <T>(query: unknown, outputSchema: z.ZodSchema<T>, context: BaseDataSourceContext) => Promise<T>;
337
+ /**
338
+ * Optional: Generate new content
339
+ * Used by data sources that create content (e.g., AI-generated content, reports)
340
+ */
341
+ generate?: <T>(request: unknown, schema: z.ZodSchema<T>) => Promise<T>;
342
+ /**
343
+ * Optional: Transform content between formats
344
+ * Used by data sources that convert content (e.g., markdown to HTML, data formatting)
345
+ */
346
+ transform?: <T>(content: unknown, format: string, schema: z.ZodSchema<T>) => Promise<T>;
347
+ }
348
+
349
+ /**
350
+ * Schema for pagination information
351
+ * Used by datasources that return paginated lists
352
+ */
353
+ declare const paginationInfoSchema: z.ZodObject<{
354
+ currentPage: z.ZodNumber;
355
+ totalPages: z.ZodNumber;
356
+ totalItems: z.ZodNumber;
357
+ pageSize: z.ZodNumber;
358
+ hasNextPage: z.ZodBoolean;
359
+ hasPrevPage: z.ZodBoolean;
360
+ }, "strip", z.ZodTypeAny, {
361
+ currentPage: number;
362
+ totalPages: number;
363
+ totalItems: number;
364
+ pageSize: number;
365
+ hasNextPage: boolean;
366
+ hasPrevPage: boolean;
367
+ }, {
368
+ currentPage: number;
369
+ totalPages: number;
370
+ totalItems: number;
371
+ pageSize: number;
372
+ hasNextPage: boolean;
373
+ hasPrevPage: boolean;
374
+ }>;
375
+ /**
376
+ * Pagination information type
377
+ */
378
+ type PaginationInfo = z.infer<typeof paginationInfoSchema>;
379
+
380
+ /**
381
+ * Zod schema for the base query fields.
382
+ * Subclasses can extend this with `.extend()` for additional fields.
383
+ */
384
+ declare const baseQuerySchema: z.ZodObject<{
385
+ id: z.ZodOptional<z.ZodString>;
386
+ limit: z.ZodOptional<z.ZodNumber>;
387
+ page: z.ZodOptional<z.ZodNumber>;
388
+ pageSize: z.ZodOptional<z.ZodNumber>;
389
+ baseUrl: z.ZodOptional<z.ZodString>;
390
+ }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
391
+ id: z.ZodOptional<z.ZodString>;
392
+ limit: z.ZodOptional<z.ZodNumber>;
393
+ page: z.ZodOptional<z.ZodNumber>;
394
+ pageSize: z.ZodOptional<z.ZodNumber>;
395
+ baseUrl: z.ZodOptional<z.ZodString>;
396
+ }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
397
+ id: z.ZodOptional<z.ZodString>;
398
+ limit: z.ZodOptional<z.ZodNumber>;
399
+ page: z.ZodOptional<z.ZodNumber>;
400
+ pageSize: z.ZodOptional<z.ZodNumber>;
401
+ baseUrl: z.ZodOptional<z.ZodString>;
402
+ }, z.ZodTypeAny, "passthrough">>;
403
+ /**
404
+ * Zod schema for the outer datasource input (entityType + query).
405
+ * Subclasses can extend the inner query via `baseQuerySchema.extend()`.
406
+ */
407
+ declare const baseInputSchema: z.ZodObject<{
408
+ entityType: z.ZodOptional<z.ZodString>;
409
+ query: z.ZodOptional<z.ZodObject<{
410
+ id: z.ZodOptional<z.ZodString>;
411
+ limit: z.ZodOptional<z.ZodNumber>;
412
+ page: z.ZodOptional<z.ZodNumber>;
413
+ pageSize: z.ZodOptional<z.ZodNumber>;
414
+ baseUrl: z.ZodOptional<z.ZodString>;
415
+ }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
416
+ id: z.ZodOptional<z.ZodString>;
417
+ limit: z.ZodOptional<z.ZodNumber>;
418
+ page: z.ZodOptional<z.ZodNumber>;
419
+ pageSize: z.ZodOptional<z.ZodNumber>;
420
+ baseUrl: z.ZodOptional<z.ZodString>;
421
+ }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
422
+ id: z.ZodOptional<z.ZodString>;
423
+ limit: z.ZodOptional<z.ZodNumber>;
424
+ page: z.ZodOptional<z.ZodNumber>;
425
+ pageSize: z.ZodOptional<z.ZodNumber>;
426
+ baseUrl: z.ZodOptional<z.ZodString>;
427
+ }, z.ZodTypeAny, "passthrough">>>;
428
+ }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
429
+ entityType: z.ZodOptional<z.ZodString>;
430
+ query: z.ZodOptional<z.ZodObject<{
431
+ id: z.ZodOptional<z.ZodString>;
432
+ limit: z.ZodOptional<z.ZodNumber>;
433
+ page: z.ZodOptional<z.ZodNumber>;
434
+ pageSize: z.ZodOptional<z.ZodNumber>;
435
+ baseUrl: z.ZodOptional<z.ZodString>;
436
+ }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
437
+ id: z.ZodOptional<z.ZodString>;
438
+ limit: z.ZodOptional<z.ZodNumber>;
439
+ page: z.ZodOptional<z.ZodNumber>;
440
+ pageSize: z.ZodOptional<z.ZodNumber>;
441
+ baseUrl: z.ZodOptional<z.ZodString>;
442
+ }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
443
+ id: z.ZodOptional<z.ZodString>;
444
+ limit: z.ZodOptional<z.ZodNumber>;
445
+ page: z.ZodOptional<z.ZodNumber>;
446
+ pageSize: z.ZodOptional<z.ZodNumber>;
447
+ baseUrl: z.ZodOptional<z.ZodString>;
448
+ }, z.ZodTypeAny, "passthrough">>>;
449
+ }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
450
+ entityType: z.ZodOptional<z.ZodString>;
451
+ query: z.ZodOptional<z.ZodObject<{
452
+ id: z.ZodOptional<z.ZodString>;
453
+ limit: z.ZodOptional<z.ZodNumber>;
454
+ page: z.ZodOptional<z.ZodNumber>;
455
+ pageSize: z.ZodOptional<z.ZodNumber>;
456
+ baseUrl: z.ZodOptional<z.ZodString>;
457
+ }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
458
+ id: z.ZodOptional<z.ZodString>;
459
+ limit: z.ZodOptional<z.ZodNumber>;
460
+ page: z.ZodOptional<z.ZodNumber>;
461
+ pageSize: z.ZodOptional<z.ZodNumber>;
462
+ baseUrl: z.ZodOptional<z.ZodString>;
463
+ }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
464
+ id: z.ZodOptional<z.ZodString>;
465
+ limit: z.ZodOptional<z.ZodNumber>;
466
+ page: z.ZodOptional<z.ZodNumber>;
467
+ pageSize: z.ZodOptional<z.ZodNumber>;
468
+ baseUrl: z.ZodOptional<z.ZodString>;
469
+ }, z.ZodTypeAny, "passthrough">>>;
470
+ }, z.ZodTypeAny, "passthrough">>;
471
+ /**
472
+ * Parsed base query parameters.
473
+ * Subclasses can extend this with additional fields via `parseQuery()`.
474
+ */
475
+ type BaseQuery = z.infer<typeof baseQuerySchema>;
476
+ /**
477
+ * Navigation context for detail views (prev/next entities).
478
+ */
479
+ interface NavigationResult<T> {
480
+ prev: T | null;
481
+ next: T | null;
482
+ }
483
+ /**
484
+ * Configuration for a BaseEntityDataSource.
485
+ */
486
+ interface EntityDataSourceConfig {
487
+ /** Entity type to query (e.g., "post", "deck", "project") */
488
+ entityType: string;
489
+ /** Default sort order for list and navigation queries */
490
+ defaultSort: SortField[];
491
+ /** Default limit for list queries (defaults to 100) */
492
+ defaultLimit?: number;
493
+ /**
494
+ * How to look up a single entity by the `id` query param.
495
+ * - "slug": filter by `metadata.slug` (default)
496
+ * - "id": direct `getEntity()` lookup
497
+ */
498
+ lookupField?: "slug" | "id";
499
+ /** Enable prev/next navigation on detail views (defaults to false) */
500
+ enableNavigation?: boolean;
501
+ /** Max entities to fetch when resolving prev/next navigation (defaults to 1000) */
502
+ navigationLimit?: number;
503
+ }
504
+ /**
505
+ * Base class for entity datasources that follow the list/detail pattern.
506
+ *
507
+ * Provides:
508
+ * - Query parsing with Zod validation
509
+ * - Detail view: entity lookup (by slug or id), optional prev/next navigation
510
+ * - List view: paginated fetch with sorting
511
+ *
512
+ * Subclasses implement:
513
+ * - `transformEntity()` — convert raw entity to display format
514
+ * - `buildListResult()` — shape the list response
515
+ *
516
+ * Optionally override:
517
+ * - `buildDetailResult()` — shape the detail response (default throws; override
518
+ * this OR override `fetch()` to handle detail views directly)
519
+ *
520
+ * For datasources with extra query cases (e.g., "latest", "series", "nextInQueue"),
521
+ * override `fetch()` to handle those first, then call `super.fetch()` for the standard path.
522
+ */
523
+ declare abstract class BaseEntityDataSource<TEntity extends BaseEntity = BaseEntity, TTransformed = TEntity> implements DataSource {
524
+ protected readonly logger: Logger;
525
+ abstract readonly id: string;
526
+ abstract readonly name: string;
527
+ abstract readonly description: string;
528
+ protected abstract readonly config: EntityDataSourceConfig;
529
+ constructor(logger: Logger);
530
+ /**
531
+ * Transform a raw entity into the display format used by templates.
532
+ * Called for both list items and detail views.
533
+ */
534
+ protected abstract transformEntity(entity: TEntity): TTransformed;
535
+ /**
536
+ * Build the detail response object.
537
+ * Override this if using the base class's standard detail path.
538
+ * Datasources that fully override `fetch()` for detail views need not implement this.
539
+ *
540
+ * @param item - The transformed entity
541
+ * @param navigation - Prev/next entities (null if navigation is disabled)
542
+ */
543
+ protected buildDetailResult(_item: TTransformed, _navigation: NavigationResult<TTransformed> | null): unknown;
544
+ /**
545
+ * Build the list response object.
546
+ * @param items - Transformed entities
547
+ * @param pagination - Pagination info (null if no page param was provided)
548
+ * @param query - The parsed query params (for passing through baseUrl, etc.)
549
+ */
550
+ protected abstract buildListResult(items: TTransformed[], pagination: PaginationInfo | null, query: BaseQuery): unknown;
551
+ /**
552
+ * Parse and validate the incoming query with Zod.
553
+ * Override to support additional query parameters beyond the base set.
554
+ * Use `baseQuerySchema.extend()` or `baseInputSchema` for validation.
555
+ */
556
+ protected parseQuery(query: unknown): {
557
+ entityType: string;
558
+ query: BaseQuery;
559
+ };
560
+ /**
561
+ * Standard fetch implementation: dispatch to detail or list based on query.id.
562
+ *
563
+ * Override to handle custom query cases before falling through to the standard path:
564
+ * ```typescript
565
+ * async fetch<T>(query, outputSchema, context) {
566
+ * const params = this.parseQuery(query);
567
+ * if (params.query.latest) {
568
+ * return this.fetchLatest(outputSchema, context.entityService);
569
+ * }
570
+ * return super.fetch(query, outputSchema, context);
571
+ * }
572
+ * ```
573
+ */
574
+ fetch<T>(query: unknown, outputSchema: z.ZodSchema<T>, context: BaseDataSourceContext): Promise<T>;
575
+ /**
576
+ * Fetch a single entity and optionally resolve prev/next navigation.
577
+ */
578
+ protected fetchDetail(id: string, entityService: EntityService): Promise<{
579
+ item: TTransformed;
580
+ navigation: NavigationResult<TTransformed> | null;
581
+ }>;
582
+ /**
583
+ * Fetch a paginated list of entities.
584
+ */
585
+ protected fetchList(query: BaseQuery, entityService: EntityService, listOptions?: Partial<ListOptions>): Promise<{
586
+ items: TTransformed[];
587
+ pagination: PaginationInfo | null;
588
+ }>;
589
+ /**
590
+ * Resolve prev/next navigation for a given entity within the sorted list.
591
+ */
592
+ protected resolveNavigation(entity: TEntity, entityService: EntityService, sortFields?: SortField[]): Promise<NavigationResult<TTransformed>>;
593
+ /**
594
+ * Look up a single entity by id or slug.
595
+ * Uses `config.lookupField` to determine the strategy.
596
+ */
597
+ protected lookupEntity(id: string, entityService: EntityService): Promise<TEntity>;
598
+ }
599
+
600
+ export { BaseEntityDataSource, baseInputSchema, baseQuerySchema };
601
+ export type { BaseQuery, EntityDataSourceConfig, NavigationResult, SortField };