@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.
- package/README.md +1 -1
- package/dist/brain.js +4762 -26509
- package/dist/deploy.d.ts +17 -26
- package/dist/deploy.js +25 -25
- package/dist/deploy.js.map +4 -4
- package/dist/entities.d.ts +561 -0
- package/dist/entities.js +172 -0
- package/dist/entities.js.map +242 -0
- package/dist/index.d.ts +65 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +11 -0
- package/dist/interfaces.d.ts +923 -0
- package/dist/interfaces.js +172 -0
- package/dist/interfaces.js.map +209 -0
- package/dist/plugins.d.ts +1195 -0
- package/dist/plugins.js +178 -0
- package/dist/plugins.js.map +294 -0
- package/dist/seed-content/relay/README.md +28 -371
- package/dist/seed-content/relay/anchor-profile/anchor-profile.md +8 -11
- package/dist/seed-content/relay/brain-character/brain-character.md +5 -4
- package/dist/seed-content/relay/site-content/about/about.md +20 -0
- package/dist/seed-content/relay/site-content/home/diagram.md +184 -0
- package/dist/seed-content/relay/site-info/site-info.md +11 -1
- package/dist/services.d.ts +601 -0
- package/dist/services.js +172 -0
- package/dist/services.js.map +242 -0
- package/dist/site.d.ts +56 -157
- package/dist/site.js +323 -463
- package/dist/site.js.map +131 -249
- package/dist/templates.d.ts +302 -0
- package/dist/templates.js +172 -0
- package/dist/templates.js.map +206 -0
- package/dist/themes.d.ts +5 -44
- package/dist/themes.js +91 -8
- package/dist/themes.js.map +2 -2
- package/package.json +35 -4
- package/templates/deploy/scripts/provision-server.ts +109 -0
- package/templates/deploy/scripts/update-dns.ts +65 -0
- package/templates/deploy/scripts/write-ssh-key.ts +17 -0
- 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 };
|