db4ai 0.3.0 → 0.3.1

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 (89) hide show
  1. package/dist/chunk-3DWAMVV5.js +305 -0
  2. package/dist/chunk-3DWAMVV5.js.map +1 -0
  3. package/dist/chunk-COTPYBYM.js +618 -0
  4. package/dist/chunk-COTPYBYM.js.map +1 -0
  5. package/dist/chunk-EERD6CDF.js +735 -0
  6. package/dist/chunk-EERD6CDF.js.map +1 -0
  7. package/dist/chunk-FUF4HJTC.js +758 -0
  8. package/dist/chunk-FUF4HJTC.js.map +1 -0
  9. package/dist/chunk-JLL6FH5L.js +16 -0
  10. package/dist/chunk-JLL6FH5L.js.map +1 -0
  11. package/dist/chunk-JXFW6AIT.js +192 -0
  12. package/dist/chunk-JXFW6AIT.js.map +1 -0
  13. package/dist/chunk-XLSYCQPG.js +854 -0
  14. package/dist/chunk-XLSYCQPG.js.map +1 -0
  15. package/dist/chunk-Y5IXAS7F.js +569 -0
  16. package/dist/chunk-Y5IXAS7F.js.map +1 -0
  17. package/dist/cli/bin.d.ts +13 -12
  18. package/dist/cli/bin.js +277 -307
  19. package/dist/cli/bin.js.map +1 -1
  20. package/dist/cli/dashboard/index.d.ts +295 -14
  21. package/dist/cli/dashboard/index.js +60 -15
  22. package/dist/cli/dashboard/index.js.map +1 -1
  23. package/dist/cli/index.d.ts +10 -16
  24. package/dist/cli/index.js +94 -47
  25. package/dist/cli/index.js.map +1 -1
  26. package/dist/cli/runtime/index.d.ts +52 -23
  27. package/dist/cli/runtime/index.js +10 -704
  28. package/dist/cli/runtime/index.js.map +1 -1
  29. package/dist/cli/scanner/index.d.ts +17 -15
  30. package/dist/cli/scanner/index.js +8 -639
  31. package/dist/cli/scanner/index.js.map +1 -1
  32. package/dist/cli/seed/index.d.ts +16 -12
  33. package/dist/cli/seed/index.js +12 -773
  34. package/dist/cli/seed/index.js.map +1 -1
  35. package/dist/cli/sync/index.d.ts +54 -53
  36. package/dist/cli/sync/index.js +23 -704
  37. package/dist/cli/sync/index.js.map +1 -1
  38. package/dist/cli/terminal.d.ts +9 -8
  39. package/dist/cli/terminal.js +6 -209
  40. package/dist/cli/terminal.js.map +1 -1
  41. package/dist/cli/workflow/index.d.ts +18 -10
  42. package/dist/cli/workflow/index.js +6 -307
  43. package/dist/cli/workflow/index.js.map +1 -1
  44. package/dist/handlers.d.ts +10 -9
  45. package/dist/handlers.js +6 -38
  46. package/dist/handlers.js.map +1 -1
  47. package/dist/index.d.ts +120 -118
  48. package/dist/index.js +1963 -3125
  49. package/dist/index.js.map +1 -1
  50. package/package.json +3 -4
  51. package/dist/cli/bin.d.ts.map +0 -1
  52. package/dist/cli/dashboard/App.d.ts +0 -16
  53. package/dist/cli/dashboard/App.d.ts.map +0 -1
  54. package/dist/cli/dashboard/App.js +0 -116
  55. package/dist/cli/dashboard/App.js.map +0 -1
  56. package/dist/cli/dashboard/components/index.d.ts +0 -70
  57. package/dist/cli/dashboard/components/index.d.ts.map +0 -1
  58. package/dist/cli/dashboard/components/index.js +0 -192
  59. package/dist/cli/dashboard/components/index.js.map +0 -1
  60. package/dist/cli/dashboard/hooks/index.d.ts +0 -76
  61. package/dist/cli/dashboard/hooks/index.d.ts.map +0 -1
  62. package/dist/cli/dashboard/hooks/index.js +0 -201
  63. package/dist/cli/dashboard/hooks/index.js.map +0 -1
  64. package/dist/cli/dashboard/index.d.ts.map +0 -1
  65. package/dist/cli/dashboard/types.d.ts +0 -84
  66. package/dist/cli/dashboard/types.d.ts.map +0 -1
  67. package/dist/cli/dashboard/types.js +0 -5
  68. package/dist/cli/dashboard/types.js.map +0 -1
  69. package/dist/cli/dashboard/views/index.d.ts +0 -51
  70. package/dist/cli/dashboard/views/index.d.ts.map +0 -1
  71. package/dist/cli/dashboard/views/index.js +0 -72
  72. package/dist/cli/dashboard/views/index.js.map +0 -1
  73. package/dist/cli/index.d.ts.map +0 -1
  74. package/dist/cli/runtime/index.d.ts.map +0 -1
  75. package/dist/cli/scanner/index.d.ts.map +0 -1
  76. package/dist/cli/seed/index.d.ts.map +0 -1
  77. package/dist/cli/sync/index.d.ts.map +0 -1
  78. package/dist/cli/terminal.d.ts.map +0 -1
  79. package/dist/cli/workflow/index.d.ts.map +0 -1
  80. package/dist/errors.d.ts +0 -43
  81. package/dist/errors.d.ts.map +0 -1
  82. package/dist/errors.js +0 -47
  83. package/dist/errors.js.map +0 -1
  84. package/dist/handlers.d.ts.map +0 -1
  85. package/dist/index.d.ts.map +0 -1
  86. package/dist/types.d.ts +0 -276
  87. package/dist/types.d.ts.map +0 -1
  88. package/dist/types.js +0 -12
  89. package/dist/types.js.map +0 -1
@@ -1,774 +1,13 @@
1
- /**
2
- * Module 15: Seed Runner
3
- *
4
- * Executes static and generated seeds with progress tracking.
5
- *
6
- * Two seed types:
7
- * - Static (Seed()): Load from API or inline data, apply transforms, mark readOnly
8
- * - Generated (Generate()): Use LLM, apply constraints/variations, handle cascading
9
- */
10
- export class SeedError extends Error {
11
- seedName;
12
- type;
13
- position;
14
- constructor(message, context) {
15
- super(message);
16
- this.name = 'SeedError';
17
- if (context) {
18
- this.seedName = context.seedName;
19
- this.type = context.type;
20
- this.position = context.position;
21
- }
22
- }
23
- }
24
- // =============================================================================
25
- // Helper Functions
26
- // =============================================================================
27
- export function Seed(input) {
28
- if (!input.data && !input.source) {
29
- throw new SeedError('Static seed must have data or source');
30
- }
31
- return {
32
- kind: 'static',
33
- type: input.type,
34
- data: input.data,
35
- source: input.source,
36
- headers: input.headers,
37
- dataPath: input.dataPath,
38
- nextPath: input.nextPath,
39
- retries: input.retries,
40
- transform: input.transform,
41
- fieldMapping: input.fieldMapping,
42
- readOnly: input.readOnly,
43
- concurrency: input.concurrency,
44
- };
45
- }
46
- export function Generate(input) {
47
- // Default count to 1 if neither count nor ids is provided
48
- const count = input.count ?? (input.ids ? undefined : 1);
49
- // Validate that at least one of count or ids is resolvable
50
- // Only throw if after defaulting, we still don't have a valid count
51
- if (count === undefined && !input.ids) {
52
- throw new SeedError('Generated seed must have count or ids');
53
- }
54
- return {
55
- kind: 'generated',
56
- type: input.type,
57
- count,
58
- ids: input.ids,
59
- prompt: input.prompt,
60
- constraints: input.constraints,
61
- variations: input.variations,
62
- cascade: input.cascade,
63
- cascadeDepth: input.cascadeDepth,
64
- cascadeReuse: input.cascadeReuse,
65
- readOnly: input.readOnly,
66
- concurrency: input.concurrency,
67
- };
68
- }
69
- // =============================================================================
70
- // Implementation
71
- // =============================================================================
72
- export function createSeedRunner(db, options) {
73
- const { seeds, onProgress, onCheckpoint, onWarning, onEntity, beforeSeed, afterSeed, continueOnError = false, timeout, order, validateSchema = false, concurrency: globalConcurrency = 1, dryRun = false, skipExisting = false, storage, persist = false, } = options;
74
- // Helper: Extract references from schema type definition
75
- function extractReferences(typeDef) {
76
- const refs = [];
77
- if (!typeDef || typeof typeDef !== 'object')
78
- return refs;
79
- for (const [field, value] of Object.entries(typeDef)) {
80
- if (typeof value === 'string') {
81
- // Match patterns like '->Type', '~>Type', '->Type[]', '->Type?'
82
- const hardMatch = value.match(/^->([A-Z][a-zA-Z0-9]*)/);
83
- if (hardMatch) {
84
- refs.push({ type: hardMatch[1], fuzzy: false, field });
85
- }
86
- const fuzzyMatch = value.match(/^~>([A-Z][a-zA-Z0-9]*)/);
87
- if (fuzzyMatch) {
88
- refs.push({ type: fuzzyMatch[1], fuzzy: true, field });
89
- }
90
- }
91
- }
92
- return refs;
93
- }
94
- // Helper: Get reference type names only (for backward compatibility)
95
- function extractReferenceTypes(typeDef) {
96
- return extractReferences(typeDef).map(r => r.type);
97
- }
98
- // Helper: Check if type is readOnly
99
- function isReadOnlyType(typeName) {
100
- const typeDef = db.schema[typeName];
101
- if (typeDef && typeof typeDef === 'object' && '_readOnly' in typeDef) {
102
- return !!typeDef._readOnly;
103
- }
104
- return false;
105
- }
106
- // Helper: Get seed's type name
107
- function getSeedType(config) {
108
- return config.type;
109
- }
110
- // Helper: Topological sort for dependency order
111
- function computeExecutionOrder() {
112
- const seedNames = Object.keys(seeds);
113
- // Build dependency graph
114
- const deps = new Map();
115
- const typeToSeed = new Map();
116
- for (const name of seedNames) {
117
- deps.set(name, new Set());
118
- typeToSeed.set(getSeedType(seeds[name]), name);
119
- }
120
- // Add dependencies based on schema references
121
- for (const name of seedNames) {
122
- const config = seeds[name];
123
- const typeDef = db.schema[config.type];
124
- const refs = extractReferenceTypes(typeDef);
125
- for (const ref of refs) {
126
- const depSeed = typeToSeed.get(ref);
127
- if (depSeed && depSeed !== name) {
128
- deps.get(name).add(depSeed);
129
- }
130
- }
131
- }
132
- // Static seeds should come first (add implicit dependencies)
133
- const staticSeeds = seedNames.filter((n) => seeds[n].kind === 'static');
134
- const generatedSeeds = seedNames.filter((n) => seeds[n].kind === 'generated');
135
- for (const gen of generatedSeeds) {
136
- for (const stat of staticSeeds) {
137
- if (!deps.get(gen).has(stat)) {
138
- // Only add if there's a potential reference or just ordering preference
139
- deps.get(gen).add(stat);
140
- }
141
- }
142
- }
143
- // Topological sort with cycle detection
144
- const result = [];
145
- const visited = new Set();
146
- const visiting = new Set();
147
- function visit(name) {
148
- if (visited.has(name))
149
- return;
150
- if (visiting.has(name)) {
151
- throw new SeedError(`Circular dependency detected involving seed "${name}"`);
152
- }
153
- visiting.add(name);
154
- for (const dep of deps.get(name) || []) {
155
- visit(dep);
156
- }
157
- visiting.delete(name);
158
- visited.add(name);
159
- result.push(name);
160
- }
161
- for (const name of seedNames) {
162
- visit(name);
163
- }
164
- return result;
165
- }
166
- // Helper: Apply field mapping
167
- function applyFieldMapping(data, mapping) {
168
- const result = {};
169
- for (const [from, to] of Object.entries(mapping)) {
170
- if (from in data) {
171
- result[to] = data[from];
172
- }
173
- }
174
- // Copy unmapped fields
175
- for (const [key, value] of Object.entries(data)) {
176
- if (!(key in mapping)) {
177
- result[key] = value;
178
- }
179
- }
180
- return result;
181
- }
182
- // Helper: Extract data from JSON using simple path
183
- function extractDataPath(data, path) {
184
- if (!path.startsWith('$.'))
185
- return Array.isArray(data) ? data : [];
186
- const key = path.slice(2);
187
- if (data && typeof data === 'object' && key in data) {
188
- const result = data[key];
189
- return Array.isArray(result) ? result : [];
190
- }
191
- return [];
192
- }
193
- // Helper: Extract next URL from response
194
- function extractNextPath(data, path) {
195
- if (!path.startsWith('$.'))
196
- return null;
197
- const key = path.slice(2);
198
- if (data && typeof data === 'object' && key in data) {
199
- const result = data[key];
200
- return typeof result === 'string' ? result : null;
201
- }
202
- return null;
203
- }
204
- // Helper: Fetch with retry
205
- async function fetchWithRetry(url, headers, retries = 1) {
206
- let lastError;
207
- for (let i = 0; i < retries; i++) {
208
- try {
209
- // Only pass options if we have headers to avoid passing undefined
210
- const response = headers
211
- ? await fetch(url, { headers })
212
- : await fetch(url);
213
- if (response.ok)
214
- return response;
215
- if (i === retries - 1) {
216
- throw new SeedError(`API request failed: ${response.status} ${response.statusText}`);
217
- }
218
- }
219
- catch (error) {
220
- lastError = error;
221
- if (i === retries - 1) {
222
- throw lastError;
223
- }
224
- }
225
- }
226
- throw lastError || new SeedError('Fetch failed');
227
- }
228
- // Helper: Run with timeout
229
- function withTimeout(promise, ms) {
230
- if (!ms)
231
- return promise;
232
- return new Promise((resolve, reject) => {
233
- const timer = setTimeout(() => {
234
- reject(new SeedError('Operation timeout exceeded'));
235
- }, ms);
236
- promise
237
- .then((result) => {
238
- clearTimeout(timer);
239
- resolve(result);
240
- })
241
- .catch((error) => {
242
- clearTimeout(timer);
243
- reject(error);
244
- });
245
- });
246
- }
247
- // Helper: Run tasks with concurrency limit
248
- async function runWithConcurrency(items, fn, limit) {
249
- const results = new Array(items.length);
250
- let currentIndex = 0;
251
- async function runNext() {
252
- while (currentIndex < items.length) {
253
- const index = currentIndex++;
254
- results[index] = await fn(items[index], index);
255
- }
256
- }
257
- const workers = Array.from({ length: Math.min(limit, items.length) }, () => runNext());
258
- await Promise.all(workers);
259
- return results;
260
- }
261
- // Helper: Select variation based on weights
262
- function selectVariation(variations, index, total) {
263
- if (variations.length === 0)
264
- return {};
265
- // Normalize weights
266
- const totalWeight = variations.reduce((sum, v) => sum + (v.weight ?? 1), 0);
267
- const normalizedWeights = variations.map((v) => (v.weight ?? 1) / totalWeight);
268
- // Distribute evenly based on index when possible
269
- let cumulative = 0;
270
- const position = index / total;
271
- for (let i = 0; i < variations.length; i++) {
272
- cumulative += normalizedWeights[i];
273
- if (position < cumulative || i === variations.length - 1) {
274
- const { weight: _, ...rest } = variations[i];
275
- return rest;
276
- }
277
- }
278
- const { weight: _, ...rest } = variations[0];
279
- return rest;
280
- }
281
- // Helper: Cascade generate referenced entities recursively
282
- async function cascadeGenerate(typeName, result, remainingDepth, reuse, visited) {
283
- if (remainingDepth <= 0)
284
- return;
285
- const typeDef = db.schema[typeName];
286
- const refs = extractReferences(typeDef);
287
- for (const ref of refs) {
288
- // Skip already visited types to prevent infinite loops
289
- const visitKey = `${typeName}:${ref.field}:${ref.type}`;
290
- if (visited.has(visitKey))
291
- continue;
292
- visited.add(visitKey);
293
- // For fuzzy references, list existing entities for matching
294
- // This happens even for readOnly types since we're matching, not generating
295
- if (ref.fuzzy) {
296
- await db.list(ref.type);
297
- // Don't generate for fuzzy references, just list for matching
298
- continue;
299
- }
300
- // Skip readOnly types for hard references (we can't generate them)
301
- if (isReadOnlyType(ref.type))
302
- continue;
303
- // Check if we need to create the referenced entity
304
- const refId = result && typeof result === 'object'
305
- ? result[ref.field]
306
- : undefined;
307
- if (reuse && refId) {
308
- const existing = await db.get(ref.type, refId);
309
- if (existing)
310
- continue;
311
- }
312
- // Generate referenced entity
313
- const generatedRef = await db.generate({
314
- type: ref.type,
315
- prompt: `${ref.type} for ${typeName}`,
316
- });
317
- // Recursively cascade if we have depth left
318
- if (remainingDepth > 1) {
319
- await cascadeGenerate(ref.type, generatedRef, remainingDepth - 1, reuse, visited);
320
- }
321
- }
322
- }
323
- // Helper: Validate schema
324
- function validateSchemaField(typeName, fieldName, strict) {
325
- const typeDef = db.schema[typeName];
326
- if (!typeDef || typeof typeDef !== 'object') {
327
- if (strict) {
328
- throw new SeedError(`Type "${typeName}" not found in schema`);
329
- }
330
- return false;
331
- }
332
- if (fieldName === 'weight')
333
- return true; // Special case for variations
334
- if (!(fieldName in typeDef)) {
335
- if (strict) {
336
- throw new SeedError(`Field "${fieldName}" not found in ${typeName}`);
337
- }
338
- if (onWarning) {
339
- onWarning(`Field "${fieldName}" not found in ${typeName}`);
340
- }
341
- return false;
342
- }
343
- return true;
344
- }
345
- // Run a single seed
346
- async function runSeed(seedName, config, runOpts) {
347
- const startTime = Date.now();
348
- const errors = [];
349
- let created = 0;
350
- let skipped = 0;
351
- let partial = false;
352
- let resumeToken;
353
- // Parse resume token
354
- let startPosition = 0;
355
- if (runOpts?.resume) {
356
- try {
357
- const resumeData = JSON.parse(Buffer.from(runOpts.resume, 'base64').toString());
358
- if (resumeData[seedName]?.position) {
359
- startPosition = resumeData[seedName].position;
360
- }
361
- }
362
- catch {
363
- // Invalid resume token, start from beginning
364
- }
365
- }
366
- // Validate type exists in schema
367
- if (validateSchema === true) {
368
- if (!db.schema[config.type]) {
369
- throw new SeedError(`Type "${config.type}" not found in schema`, {
370
- seedName,
371
- type: config.type,
372
- });
373
- }
374
- }
375
- const phase = config.kind === 'static' ? 'static' : 'generated';
376
- if (config.kind === 'static') {
377
- // Static seed
378
- let data;
379
- if (config.data) {
380
- data = [...config.data];
381
- // Apply transform to inline data
382
- if (config.transform) {
383
- data = (await config.transform(data));
384
- }
385
- }
386
- else if (config.source) {
387
- // Fetch from API
388
- let allData = [];
389
- let url = config.source;
390
- while (url) {
391
- const response = await fetchWithRetry(url, config.headers, config.retries || 1);
392
- const json = await response.json();
393
- // If there's a transform, apply it to the raw response
394
- // The transform is responsible for extracting the data array
395
- if (config.transform) {
396
- const transformed = (await config.transform(json));
397
- allData = allData.concat(transformed);
398
- // Check for pagination after transform
399
- if (config.nextPath) {
400
- url = extractNextPath(json, config.nextPath);
401
- }
402
- else {
403
- url = null;
404
- }
405
- }
406
- else if (config.dataPath) {
407
- const pageData = extractDataPath(json, config.dataPath);
408
- allData = allData.concat(pageData);
409
- // Check for pagination
410
- if (config.nextPath) {
411
- url = extractNextPath(json, config.nextPath);
412
- }
413
- else {
414
- url = null;
415
- }
416
- }
417
- else if (Array.isArray(json)) {
418
- allData = allData.concat(json);
419
- url = null;
420
- }
421
- else if (json.data && Array.isArray(json.data)) {
422
- allData = allData.concat(json.data);
423
- url = null;
424
- }
425
- else {
426
- allData.push(json);
427
- url = null;
428
- }
429
- }
430
- data = allData;
431
- }
432
- else {
433
- data = [];
434
- }
435
- // Apply field mapping
436
- if (config.fieldMapping) {
437
- data = data.map((item) => applyFieldMapping(item, config.fieldMapping));
438
- }
439
- const total = data.length;
440
- const concurrency = config.concurrency ?? globalConcurrency;
441
- // Process items
442
- const processItem = async (item, index) => {
443
- const position = index + 1;
444
- // Check if entity already exists
445
- const id = item.id;
446
- if (id) {
447
- const existing = await db.get(config.type, id);
448
- if (existing) {
449
- skipped++;
450
- return;
451
- }
452
- }
453
- // Add readOnly flag if needed
454
- const entityData = config.readOnly ? { ...item, _readOnly: true } : { ...item };
455
- // Generate ID if not provided
456
- if (!entityData.id) {
457
- const name = entityData.name;
458
- entityData.id = name
459
- ? name.toLowerCase().replace(/\s+/g, '-')
460
- : `${config.type.toLowerCase()}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
461
- }
462
- if (!dryRun) {
463
- await db.create(config.type, entityData);
464
- if (onEntity) {
465
- onEntity(config.type, entityData);
466
- }
467
- }
468
- created++;
469
- if (onCheckpoint) {
470
- onCheckpoint(position);
471
- }
472
- if (onProgress) {
473
- onProgress({
474
- seedName,
475
- type: config.type,
476
- phase,
477
- current: position,
478
- total,
479
- percentage: Math.round((position / total) * 100),
480
- rate: position / ((Date.now() - startTime) / 1000),
481
- eta: total > position
482
- ? Math.round(((Date.now() - startTime) / position) * (total - position))
483
- : 0,
484
- });
485
- }
486
- if (persist && storage) {
487
- await storage.set(`seed:${seedName}:state`, JSON.stringify({ position, total }));
488
- }
489
- };
490
- if (concurrency > 1) {
491
- await runWithConcurrency(data, processItem, concurrency);
492
- }
493
- else {
494
- for (let i = 0; i < data.length; i++) {
495
- await processItem(data[i], i);
496
- }
497
- }
498
- }
499
- else {
500
- // Generated seed
501
- const count = config.ids?.length ?? config.count ?? 1;
502
- const total = count - startPosition;
503
- const concurrency = config.concurrency ?? globalConcurrency;
504
- // Validate constraints
505
- if (validateSchema && config.constraints) {
506
- const strict = validateSchema === true;
507
- for (const field of Object.keys(config.constraints)) {
508
- validateSchemaField(config.type, field, strict);
509
- }
510
- }
511
- // Validate variations
512
- if (validateSchema && config.variations) {
513
- const strict = validateSchema === true;
514
- for (const variation of config.variations) {
515
- for (const field of Object.keys(variation)) {
516
- if (field !== 'weight') {
517
- validateSchemaField(config.type, field, strict);
518
- }
519
- }
520
- }
521
- }
522
- // Resolve reference constraints
523
- let resolvedConstraints = config.constraints ? { ...config.constraints } : undefined;
524
- if (resolvedConstraints) {
525
- for (const [key, value] of Object.entries(resolvedConstraints)) {
526
- if (value && typeof value === 'object' && 'ref' in value) {
527
- const refType = value.ref;
528
- await db.list(refType);
529
- // Keep constraint as-is for generation
530
- }
531
- }
532
- }
533
- // Generate entities
534
- const generateEntity = async (index) => {
535
- const actualIndex = startPosition + index;
536
- const position = actualIndex + 1;
537
- // Get ID (from ids array or generate)
538
- const id = config.ids?.[actualIndex];
539
- // Check if entity already exists
540
- if (skipExisting && id) {
541
- const existing = await db.get(config.type, id);
542
- if (existing) {
543
- skipped++;
544
- return;
545
- }
546
- }
547
- // Apply variation
548
- let variationProps = {};
549
- if (config.variations && config.variations.length > 0) {
550
- variationProps = selectVariation(config.variations, actualIndex, count);
551
- }
552
- try {
553
- const generateConfig = {
554
- type: config.type,
555
- prompt: config.prompt,
556
- constraints: resolvedConstraints,
557
- ...variationProps,
558
- };
559
- if (id) {
560
- generateConfig.id = id;
561
- }
562
- if (!dryRun) {
563
- const result = await withTimeout(db.generate(generateConfig), timeout);
564
- // Handle cascading
565
- if (config.cascade) {
566
- await cascadeGenerate(config.type, result, config.cascadeDepth ?? Infinity, config.cascadeReuse ?? false, new Set());
567
- }
568
- if (onEntity) {
569
- onEntity(config.type, result);
570
- }
571
- }
572
- created++;
573
- if (onCheckpoint) {
574
- onCheckpoint(position);
575
- }
576
- if (onProgress) {
577
- onProgress({
578
- seedName,
579
- type: config.type,
580
- phase,
581
- current: position,
582
- total: count,
583
- percentage: Math.round((position / count) * 100),
584
- rate: position / ((Date.now() - startTime) / 1000),
585
- eta: count > position
586
- ? Math.round(((Date.now() - startTime) / position) * (count - position))
587
- : 0,
588
- });
589
- }
590
- if (persist && storage) {
591
- await storage.set(`seed:${seedName}:state`, JSON.stringify({ position, total: count }));
592
- }
593
- }
594
- catch (error) {
595
- const errorMessage = error instanceof Error ? error.message : String(error);
596
- const errorInfo = {
597
- message: errorMessage,
598
- position,
599
- };
600
- // Check for interrupt
601
- if (error &&
602
- typeof error === 'object' &&
603
- 'code' in error &&
604
- error.code === 'INTERRUPTED') {
605
- partial = true;
606
- resumeToken = Buffer.from(JSON.stringify({ [seedName]: { position } })).toString('base64');
607
- errors.push(errorInfo);
608
- return;
609
- }
610
- if (continueOnError) {
611
- errors.push(errorInfo);
612
- }
613
- else {
614
- throw new SeedError(errorMessage, {
615
- seedName,
616
- type: config.type,
617
- position,
618
- });
619
- }
620
- }
621
- };
622
- if (concurrency > 1) {
623
- const indices = Array.from({ length: total }, (_, i) => i);
624
- await runWithConcurrency(indices, generateEntity, concurrency);
625
- }
626
- else {
627
- for (let i = 0; i < total; i++) {
628
- await generateEntity(i);
629
- }
630
- }
631
- }
632
- return {
633
- success: errors.length === 0,
634
- created,
635
- skipped,
636
- errors,
637
- partial,
638
- duration: Date.now() - startTime,
639
- resumeToken,
640
- };
641
- }
642
- // Run single seed
643
- async function run(seedName, runOpts) {
644
- const config = seeds[seedName];
645
- if (!config) {
646
- throw new SeedError(`Seed "${seedName}" not found`, { seedName });
647
- }
648
- // Validate config
649
- if (!config.kind) {
650
- throw new SeedError(`Invalid seed configuration for "${seedName}"`, { seedName });
651
- }
652
- // Call beforeSeed hook
653
- let effectiveConfig = config;
654
- if (beforeSeed) {
655
- const hookResult = beforeSeed(seedName, config);
656
- if (hookResult === null) {
657
- // Skip this seed
658
- return {
659
- success: true,
660
- created: 0,
661
- skipped: 0,
662
- errors: [],
663
- partial: false,
664
- duration: 0,
665
- };
666
- }
667
- if (hookResult) {
668
- effectiveConfig = hookResult;
669
- }
670
- }
671
- const result = await runSeed(seedName, effectiveConfig, runOpts);
672
- // Call afterSeed hook
673
- if (afterSeed) {
674
- afterSeed(seedName, result);
675
- }
676
- return result;
677
- }
678
- // Run all seeds
679
- async function runAll() {
680
- const startTime = Date.now();
681
- const executionOrder = order ?? computeExecutionOrder();
682
- if (dryRun) {
683
- const wouldCreate = {};
684
- for (const seedName of executionOrder) {
685
- const config = seeds[seedName];
686
- // Validate type exists in schema
687
- if (validateSchema === true) {
688
- if (!db.schema[config.type]) {
689
- throw new SeedError(`Type "${config.type}" not found in schema`, {
690
- seedName,
691
- type: config.type,
692
- });
693
- }
694
- }
695
- if (config.kind === 'static') {
696
- wouldCreate[config.type] = config.data?.length ?? 0;
697
- }
698
- else {
699
- wouldCreate[config.type] = config.ids?.length ?? config.count ?? 1;
700
- }
701
- }
702
- return {
703
- success: true,
704
- created: 0,
705
- skipped: 0,
706
- errors: [],
707
- partial: false,
708
- duration: Date.now() - startTime,
709
- dryRun: true,
710
- wouldCreate,
711
- executionOrder,
712
- };
713
- }
714
- let totalCreated = 0;
715
- let totalSkipped = 0;
716
- const allErrors = [];
717
- for (const seedName of executionOrder) {
718
- const result = await run(seedName);
719
- totalCreated += result.created;
720
- totalSkipped += result.skipped;
721
- allErrors.push(...result.errors);
722
- }
723
- return {
724
- success: allErrors.length === 0,
725
- created: totalCreated,
726
- skipped: totalSkipped,
727
- errors: allErrors,
728
- partial: false,
729
- duration: Date.now() - startTime,
730
- };
731
- }
732
- // Reset single seed
733
- async function reset(seedName, resetOpts) {
734
- const config = seeds[seedName];
735
- if (!config) {
736
- throw new SeedError(`Seed "${seedName}" not found`, { seedName });
737
- }
738
- // Clear the type
739
- await db.clear(config.type);
740
- // Clear cascaded types if requested
741
- if (resetOpts?.cascade) {
742
- const typeDef = db.schema[config.type];
743
- const refs = extractReferenceTypes(typeDef);
744
- for (const refType of refs) {
745
- if (!isReadOnlyType(refType)) {
746
- await db.clear(refType);
747
- }
748
- }
749
- }
750
- // Re-run the seed
751
- return run(seedName);
752
- }
753
- // Reset all seeds
754
- async function resetAll(resetOpts) {
755
- // Clear all types
756
- for (const seedName of Object.keys(seeds)) {
757
- const config = seeds[seedName];
758
- // Skip readOnly if preserveReadOnly is true
759
- if (resetOpts?.preserveReadOnly && config.readOnly) {
760
- continue;
761
- }
762
- await db.clear(config.type);
763
- }
764
- // Run all seeds
765
- return runAll();
766
- }
767
- return {
768
- run,
769
- runAll,
770
- reset,
771
- resetAll,
772
- };
773
- }
1
+ import {
2
+ Generate,
3
+ Seed,
4
+ SeedError,
5
+ createSeedRunner
6
+ } from "../../chunk-EERD6CDF.js";
7
+ export {
8
+ Generate,
9
+ Seed,
10
+ SeedError,
11
+ createSeedRunner
12
+ };
774
13
  //# sourceMappingURL=index.js.map