@kuckit/sdk 1.0.1 → 1.0.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.
Files changed (65) hide show
  1. package/dist/config/define-config.d.ts +3 -0
  2. package/dist/config/define-config.js +3 -0
  3. package/dist/config/index.d.ts +5 -0
  4. package/dist/config/index.js +5 -0
  5. package/dist/config/loader.d.ts +3 -0
  6. package/dist/config/loader.js +3 -0
  7. package/dist/config/types.d.ts +2 -0
  8. package/dist/config/types.js +1 -0
  9. package/dist/config-BeiJJZGf.js +1 -0
  10. package/dist/container-D0DK003A.js +50 -0
  11. package/dist/container-D0DK003A.js.map +1 -0
  12. package/dist/container-Ngzcb6LI.d.ts +49 -0
  13. package/dist/core/container.d.ts +3 -0
  14. package/dist/core/container.js +4 -0
  15. package/dist/core/core.module.d.ts +3 -0
  16. package/dist/core/core.module.js +3 -0
  17. package/dist/core.module-Ckt9iPWn.d.ts +22 -0
  18. package/dist/core.module-Ctm2stcL.js +48 -0
  19. package/dist/core.module-Ctm2stcL.js.map +1 -0
  20. package/dist/define-config-GYI_W9K6.js +34 -0
  21. package/dist/define-config-GYI_W9K6.js.map +1 -0
  22. package/dist/define-config-yzb59aTs.d.ts +34 -0
  23. package/dist/define-module-B83hUzJz.js +58 -0
  24. package/dist/define-module-B83hUzJz.js.map +1 -0
  25. package/dist/define-module-Cw7q13EE.d.ts +56 -0
  26. package/dist/index-CDDzqahH.d.ts +1 -0
  27. package/dist/index-Dfcz46Ma.d.ts +2 -0
  28. package/dist/index-Dw5cCt-A.d.ts +1 -0
  29. package/dist/index.d.ts +15 -616
  30. package/dist/index.js +12 -633
  31. package/dist/loader-Ct4ZivZz.js +177 -0
  32. package/dist/loader-Ct4ZivZz.js.map +1 -0
  33. package/dist/loader-DCNm6pZB.d.ts +73 -0
  34. package/dist/loader-YEqdtcKI.d.ts +29 -0
  35. package/dist/loader-lCPWCMYx.js +75 -0
  36. package/dist/loader-lCPWCMYx.js.map +1 -0
  37. package/dist/modules/define-module.d.ts +4 -0
  38. package/dist/modules/define-module.js +3 -0
  39. package/dist/modules/index.d.ts +7 -0
  40. package/dist/modules/index.js +8 -0
  41. package/dist/modules/loader.d.ts +4 -0
  42. package/dist/modules/loader.js +6 -0
  43. package/dist/modules/registry.d.ts +4 -0
  44. package/dist/modules/registry.js +3 -0
  45. package/dist/modules/types.d.ts +3 -0
  46. package/dist/modules/types.js +1 -0
  47. package/dist/modules-BDQBjAbp.js +1 -0
  48. package/dist/registry-BPYpBtYx.js +83 -0
  49. package/dist/registry-BPYpBtYx.js.map +1 -0
  50. package/dist/registry-CL_5erME.js +132 -0
  51. package/dist/registry-CL_5erME.js.map +1 -0
  52. package/dist/registry-CfpVCPcW.d.ts +68 -0
  53. package/dist/registry-DrTkgmtH.d.ts +90 -0
  54. package/dist/schema/index.d.ts +3 -0
  55. package/dist/schema/index.js +4 -0
  56. package/dist/schema/registry.d.ts +2 -0
  57. package/dist/schema/registry.js +3 -0
  58. package/dist/schema-BuA2HF_H.js +1 -0
  59. package/dist/types-ByO301S-.d.ts +112 -0
  60. package/dist/types-DKCy16X1.d.ts +51 -0
  61. package/dist/types-DxaDmkQo.d.ts +87 -0
  62. package/dist/types.d.ts +2 -0
  63. package/dist/types.js +1 -0
  64. package/package.json +14 -28
  65. package/src/index.ts +0 -62
package/dist/index.js CHANGED
@@ -1,638 +1,17 @@
1
- import { InjectionMode, asClass, asClass as asClass$1, asFunction, asFunction as asFunction$1, asValue, asValue as asValue$1, createContainer } from "awilix";
1
+ import { t as registerCoreModule } from "./core.module-Ctm2stcL.js";
2
+ import { n as disposeContainer, t as createKuckitContainer } from "./container-D0DK003A.js";
3
+ import { t as defineKuckitModule } from "./define-module-B83hUzJz.js";
4
+ import { i as resetModuleRegistry, n as getModuleRegistry, r as getModulesWithCapability, t as ModuleRegistry } from "./registry-CL_5erME.js";
5
+ import { n as getSchemaRegistry, r as resetSchemaRegistry, t as SchemaRegistry } from "./registry-BPYpBtYx.js";
6
+ import "./schema-BuA2HF_H.js";
7
+ import { n as loadKuckitModules, t as createModuleShutdownHandler } from "./loader-Ct4ZivZz.js";
8
+ import "./modules-BDQBjAbp.js";
9
+ import { t as defineConfig } from "./define-config-GYI_W9K6.js";
10
+ import { i as tryLoadKuckitConfig, n as hasUnifiedConfig, r as loadKuckitConfig, t as findConfigFile } from "./loader-lCPWCMYx.js";
11
+ import "./config-BeiJJZGf.js";
12
+ import { asClass, asFunction, asValue } from "awilix";
2
13
  import * as Domain from "@kuckit/domain";
3
- import { SystemClock } from "@kuckit/domain";
4
- import { google } from "@ai-sdk/google";
5
- import { auth } from "@kuckit/auth";
6
- import { InMemoryCacheStore, InMemoryEventBus, InMemoryRateLimiterStore, createDb, createDbPool, makeErrorHandler, makeRequestLogger, makeStructuredLogger } from "@kuckit/infrastructure";
7
- import { existsSync } from "node:fs";
8
- import { dirname, resolve } from "node:path";
9
14
  import * as Application from "@kuckit/application";
10
15
  import * as Contracts from "@kuckit/contracts";
11
16
 
12
- //#region src/core/core.module.ts
13
- /**
14
- * Register core infrastructure services into the container
15
- *
16
- * This registers:
17
- * - Database pool and connection
18
- * - Clock
19
- * - Logger (structured, Loki/Prometheus compatible)
20
- * - AI provider
21
- * - Auth
22
- * - Event bus
23
- * - Cache store
24
- * - Rate limiter store
25
- * - Request-scoped logger
26
- */
27
- const registerCoreModule = (container) => {
28
- container.register({
29
- dbPool: asFunction$1(({ config }) => createDbPool(config.databaseUrl)).singleton(),
30
- db: asFunction$1(({ dbPool }) => createDb(dbPool)).singleton(),
31
- clock: asValue$1(new SystemClock()),
32
- logger: asFunction$1(({ config }) => makeStructuredLogger({
33
- enableFile: config.enableFileLogging,
34
- logDir: config.logDir,
35
- minLevel: config.logLevel
36
- })).singleton(),
37
- errorHandler: asFunction$1(({ logger }) => makeErrorHandler(logger)).singleton(),
38
- auth: asValue$1(auth),
39
- aiProvider: asFunction$1(() => google("gemini-2.5-flash")).singleton(),
40
- eventBus: asFunction$1(({ logger }) => new InMemoryEventBus(logger)).singleton(),
41
- cacheStore: asClass$1(InMemoryCacheStore).singleton(),
42
- rateLimiterStore: asClass$1(InMemoryRateLimiterStore).singleton(),
43
- requestLogger: asFunction$1(({ logger, requestId, session }) => makeRequestLogger({
44
- requestId,
45
- userId: session?.user?.id,
46
- baseLogger: logger
47
- })).scoped()
48
- });
49
- };
50
-
51
- //#endregion
52
- //#region src/core/container.ts
53
- /**
54
- * Factory function to create a Kuckit DI container
55
- *
56
- * This is the primary entry point for applications using the SDK.
57
- * It creates an Awilix container with core infrastructure services pre-registered.
58
- *
59
- * @example
60
- * ```ts
61
- * const container = await createKuckitContainer({
62
- * config: {
63
- * databaseUrl: process.env.DATABASE_URL!,
64
- * enableFileLogging: true,
65
- * logDir: './logs',
66
- * logLevel: 'INFO',
67
- * env: 'production',
68
- * },
69
- * extraRegistrations: (container) => {
70
- * // Register your custom services
71
- * container.register({
72
- * myService: asClass(MyService).singleton(),
73
- * })
74
- * },
75
- * })
76
- * ```
77
- */
78
- const createKuckitContainer = async (opts) => {
79
- const container = createContainer({ injectionMode: InjectionMode.PROXY });
80
- container.register({ config: asValue$1(opts.config) });
81
- registerCoreModule(container);
82
- if (opts.extraRegistrations) await opts.extraRegistrations(container);
83
- return container;
84
- };
85
- /**
86
- * Cleanup container resources gracefully
87
- *
88
- * Call this when shutting down your application to close database connections
89
- * and other resources.
90
- */
91
- const disposeContainer = async (container) => {
92
- const { dbPool } = container.cradle;
93
- if (dbPool && typeof dbPool === "object" && "end" in dbPool && typeof dbPool.end === "function") await dbPool.end();
94
- };
95
-
96
- //#endregion
97
- //#region src/modules/define-module.ts
98
- /**
99
- * Helper to define a Kuckit module with type safety
100
- *
101
- * This is the primary way to create a module for the Kuckit SDK.
102
- * It provides type inference for the configuration and validates
103
- * the module structure at compile time.
104
- *
105
- * @example
106
- * ```ts
107
- * // In your module's main file (e.g., src/module.ts)
108
- * import { defineKuckitModule, asClass, asFunction } from '@kuckit/sdk'
109
- *
110
- * interface BillingModuleConfig {
111
- * currency: string
112
- * taxRate: number
113
- * }
114
- *
115
- * export const kuckitModule = defineKuckitModule<BillingModuleConfig>({
116
- * id: 'acme.billing',
117
- * displayName: 'Billing',
118
- * description: 'Invoice and payment processing',
119
- * version: '1.0.0',
120
- *
121
- * register(ctx) {
122
- * ctx.container.register({
123
- * invoiceRepository: asClass(DrizzleInvoiceRepository).scoped(),
124
- * paymentService: asFunction(makePaymentService).singleton(),
125
- * })
126
- * },
127
- *
128
- * registerApi(ctx) {
129
- * ctx.addApiRegistration({
130
- * type: 'rpc-router',
131
- * name: 'billing',
132
- * router: createBillingRouter(ctx.container),
133
- * })
134
- * },
135
- *
136
- * onBootstrap(ctx) {
137
- * const logger = ctx.container.resolve('logger')
138
- * logger.info(`Billing module initialized with currency: ${ctx.config.currency}`)
139
- * },
140
- * })
141
- * ```
142
- *
143
- * @param mod - The module definition object
144
- * @returns The same module definition (for type inference)
145
- */
146
- const defineKuckitModule = (mod) => {
147
- if (!mod.id) throw new Error("Module must have an id");
148
- if (typeof mod.id !== "string" || mod.id.trim() === "") throw new Error("Module id must be a non-empty string");
149
- return mod;
150
- };
151
-
152
- //#endregion
153
- //#region src/modules/registry.ts
154
- /**
155
- * Validates that a capability string matches expected patterns
156
- */
157
- const isValidCapability = (cap) => {
158
- if ([
159
- "nav.item",
160
- "settings.page",
161
- "dashboard.widget",
162
- "api.webhook",
163
- "api.public",
164
- "slot.provider"
165
- ].includes(cap)) return true;
166
- if (cap.startsWith("custom.") && cap.length > 7) return true;
167
- return false;
168
- };
169
- /**
170
- * Registry for loaded Kuckit modules
171
- *
172
- * Tracks all loaded modules and their capabilities for querying.
173
- */
174
- var ModuleRegistry = class {
175
- modules = /* @__PURE__ */ new Map();
176
- frozen = false;
177
- /**
178
- * Register a loaded module
179
- * @throws Error if registry is frozen or module ID already exists
180
- */
181
- register(module) {
182
- if (this.frozen) throw new Error(`ModuleRegistry is frozen. Cannot register module "${module.id}" after finalization.`);
183
- if (this.modules.has(module.id)) throw new Error(`Module with ID "${module.id}" is already registered.`);
184
- const capabilities = module.capabilities ?? [];
185
- for (const cap of capabilities) if (!isValidCapability(cap)) throw new Error(`Invalid capability "${cap}" in module "${module.id}". Capabilities must be built-in (nav.item, settings.page, etc.) or custom.* prefixed.`);
186
- this.modules.set(module.id, {
187
- id: module.id,
188
- displayName: module.displayName,
189
- description: module.description,
190
- version: module.version,
191
- capabilities
192
- });
193
- }
194
- /**
195
- * Get all registered modules
196
- */
197
- getAll() {
198
- return Array.from(this.modules.values());
199
- }
200
- /**
201
- * Get a module by ID
202
- */
203
- getById(id) {
204
- return this.modules.get(id);
205
- }
206
- /**
207
- * Check if a module is registered
208
- */
209
- has(id) {
210
- return this.modules.has(id);
211
- }
212
- /**
213
- * Get all modules that have a specific capability
214
- */
215
- getWithCapability(capability) {
216
- return this.getAll().filter((mod) => mod.capabilities.includes(capability));
217
- }
218
- /**
219
- * Check if a specific module has a capability
220
- */
221
- hasCapability(moduleId, capability) {
222
- const module = this.modules.get(moduleId);
223
- return module ? module.capabilities.includes(capability) : false;
224
- }
225
- /**
226
- * Get all unique capabilities across all modules
227
- */
228
- getAllCapabilities() {
229
- const caps = /* @__PURE__ */ new Set();
230
- for (const mod of this.modules.values()) for (const cap of mod.capabilities) caps.add(cap);
231
- return Array.from(caps);
232
- }
233
- /**
234
- * Freeze the registry to prevent further modifications
235
- */
236
- freeze() {
237
- this.frozen = true;
238
- }
239
- /**
240
- * Check if registry is frozen
241
- */
242
- isFrozen() {
243
- return this.frozen;
244
- }
245
- /**
246
- * Get the number of registered modules
247
- */
248
- get size() {
249
- return this.modules.size;
250
- }
251
- /**
252
- * Clear all modules (only works if not frozen)
253
- */
254
- clear() {
255
- if (this.frozen) throw new Error("ModuleRegistry is frozen. Cannot clear modules.");
256
- this.modules.clear();
257
- }
258
- };
259
- let globalRegistry = null;
260
- /**
261
- * Get the global module registry
262
- * Creates one if it doesn't exist
263
- */
264
- function getModuleRegistry() {
265
- if (!globalRegistry) globalRegistry = new ModuleRegistry();
266
- return globalRegistry;
267
- }
268
- /**
269
- * Get all modules that have a specific capability
270
- * Convenience function that uses the global registry
271
- */
272
- function getModulesWithCapability(capability) {
273
- return getModuleRegistry().getWithCapability(capability);
274
- }
275
- /**
276
- * Reset the global registry (mainly for testing)
277
- */
278
- function resetModuleRegistry() {
279
- globalRegistry = null;
280
- }
281
-
282
- //#endregion
283
- //#region src/schema/registry.ts
284
- /**
285
- * Registry for module-owned database schemas
286
- *
287
- * Allows modules to register their Drizzle schemas during the register() hook.
288
- * The CLI uses this registry to aggregate schemas for drizzle-kit operations.
289
- */
290
- var SchemaRegistry = class {
291
- schemas = /* @__PURE__ */ new Map();
292
- /**
293
- * Register a schema from a module
294
- * @param moduleId - Module identifier (e.g., 'acme.billing')
295
- * @param tableName - Table name identifier (e.g., 'invoices')
296
- * @param schema - Drizzle PgTable schema
297
- */
298
- register(moduleId, tableName, schema) {
299
- const key = `${moduleId}:${tableName}`;
300
- if (this.schemas.has(key)) throw new Error(`Schema "${tableName}" already registered by module "${moduleId}"`);
301
- this.schemas.set(key, {
302
- moduleId,
303
- tableName,
304
- schema
305
- });
306
- }
307
- /**
308
- * Get all registered schemas
309
- */
310
- getAll() {
311
- return new Map(this.schemas);
312
- }
313
- /**
314
- * Get schemas registered by a specific module
315
- */
316
- getByModule(moduleId) {
317
- return Array.from(this.schemas.values()).filter((entry) => entry.moduleId === moduleId);
318
- }
319
- /**
320
- * Get all schemas as a flat object for drizzle-kit
321
- * Keys are table names, values are PgTable schemas
322
- */
323
- getAllSchemas() {
324
- const result = {};
325
- for (const entry of this.schemas.values()) result[entry.tableName] = entry.schema;
326
- return result;
327
- }
328
- /**
329
- * Check if any schemas are registered
330
- */
331
- hasSchemas() {
332
- return this.schemas.size > 0;
333
- }
334
- /**
335
- * Get the count of registered schemas
336
- */
337
- get size() {
338
- return this.schemas.size;
339
- }
340
- /**
341
- * Clear all schemas (mainly for testing)
342
- */
343
- clear() {
344
- this.schemas.clear();
345
- }
346
- };
347
- let globalSchemaRegistry = null;
348
- /**
349
- * Get the global schema registry
350
- * Creates one if it doesn't exist
351
- */
352
- function getSchemaRegistry() {
353
- if (!globalSchemaRegistry) globalSchemaRegistry = new SchemaRegistry();
354
- return globalSchemaRegistry;
355
- }
356
- /**
357
- * Reset the global schema registry (mainly for testing)
358
- */
359
- function resetSchemaRegistry() {
360
- globalSchemaRegistry = null;
361
- }
362
-
363
- //#endregion
364
- //#region src/modules/loader.ts
365
- /**
366
- * Validates that a module has the correct shape
367
- */
368
- const validateModule = (candidate, packageName) => {
369
- if (!candidate || typeof candidate !== "object") throw new Error(`Invalid Kuckit module from "${packageName}": expected an object with module definition`);
370
- const mod = candidate;
371
- if (!mod.id || typeof mod.id !== "string") throw new Error(`Invalid Kuckit module from "${packageName}": missing or invalid 'id' property`);
372
- for (const hookName of [
373
- "register",
374
- "registerApi",
375
- "onBootstrap",
376
- "onShutdown"
377
- ]) if (mod[hookName] !== void 0 && typeof mod[hookName] !== "function") throw new Error(`Invalid Kuckit module from "${packageName}": '${hookName}' must be a function`);
378
- return mod;
379
- };
380
- /**
381
- * Load and initialize Kuckit modules
382
- *
383
- * This function orchestrates the module loading lifecycle:
384
- *
385
- * 1. **Import Phase**: Dynamic import each module package
386
- * 2. **Register Phase**: Run register() hooks (DI bindings)
387
- * 3. **API Phase**: Run registerApi() hooks (API routes)
388
- * 4. **Wire Phase**: Call onApiRegistrations callback
389
- * 5. **Bootstrap Phase**: Run onBootstrap() hooks
390
- * 6. **Complete Phase**: Call onComplete callback
391
- *
392
- * @example
393
- * ```ts
394
- * await loadKuckitModules({
395
- * container,
396
- * env: 'production',
397
- * modules: [
398
- * { package: '@kuckit/users-module' },
399
- * { package: '@acme/billing-module', config: { currency: 'USD' } },
400
- * { package: './src/modules/custom', disabled: process.env.DISABLE_CUSTOM === 'true' },
401
- * ],
402
- * onApiRegistrations: (registrations) => {
403
- * // Wire up oRPC routers, REST routes, etc.
404
- * for (const reg of registrations) {
405
- * if (reg.type === 'rpc-router') {
406
- * rootRouter.merge(reg.name, reg.router)
407
- * }
408
- * }
409
- * },
410
- * onComplete: () => {
411
- * console.log('All modules loaded!')
412
- * },
413
- * })
414
- * ```
415
- */
416
- const loadKuckitModules = async (opts) => {
417
- const { container, env, modules, onApiRegistrations, onComplete } = opts;
418
- const apiRegistrations = [];
419
- const loadedModules = [];
420
- const registry = getModuleRegistry();
421
- for (const spec of modules) {
422
- if (spec.disabled) continue;
423
- let validated;
424
- if (spec.module) validated = validateModule(spec.module, spec.module.id ?? "direct-module");
425
- else if (spec.package) {
426
- let imported;
427
- try {
428
- imported = await import(spec.package);
429
- } catch (error) {
430
- const message = error instanceof Error ? error.message : String(error);
431
- throw new Error(`Failed to import module "${spec.package}": ${message}`);
432
- }
433
- validated = validateModule(imported.kuckitModule ?? imported.default, spec.package);
434
- } else throw new Error("ModuleSpec must have either \"module\" or \"package\" property");
435
- registry.register(validated);
436
- loadedModules.push({
437
- ...validated,
438
- _config: spec.config
439
- });
440
- }
441
- for (const mod of loadedModules) if (mod.register) {
442
- const schemaRegistry = getSchemaRegistry();
443
- const ctx = {
444
- container,
445
- env,
446
- config: mod._config ?? {},
447
- registerSchema: (tableName, schema) => {
448
- schemaRegistry.register(mod.id, tableName, schema);
449
- }
450
- };
451
- try {
452
- await mod.register(ctx);
453
- } catch (error) {
454
- const message = error instanceof Error ? error.message : String(error);
455
- throw new Error(`Module "${mod.id}" register() failed: ${message}`);
456
- }
457
- }
458
- for (const mod of loadedModules) if (mod.registerApi) {
459
- const schemaRegistry = getSchemaRegistry();
460
- const ctx = {
461
- container,
462
- env,
463
- config: mod._config ?? {},
464
- registerSchema: (tableName, schema) => {
465
- schemaRegistry.register(mod.id, tableName, schema);
466
- },
467
- addApiRegistration: (reg) => {
468
- apiRegistrations.push(reg);
469
- }
470
- };
471
- try {
472
- await mod.registerApi(ctx);
473
- } catch (error) {
474
- const message = error instanceof Error ? error.message : String(error);
475
- throw new Error(`Module "${mod.id}" registerApi() failed: ${message}`);
476
- }
477
- }
478
- if (onApiRegistrations && apiRegistrations.length > 0) await onApiRegistrations(apiRegistrations);
479
- for (const mod of loadedModules) if (mod.onBootstrap) {
480
- const schemaRegistry = getSchemaRegistry();
481
- const ctx = {
482
- container,
483
- env,
484
- config: mod._config ?? {},
485
- registerSchema: (tableName, schema) => {
486
- schemaRegistry.register(mod.id, tableName, schema);
487
- }
488
- };
489
- try {
490
- await mod.onBootstrap(ctx);
491
- } catch (error) {
492
- const message = error instanceof Error ? error.message : String(error);
493
- throw new Error(`Module "${mod.id}" onBootstrap() failed: ${message}`);
494
- }
495
- }
496
- if (onComplete) await onComplete();
497
- };
498
- /**
499
- * Create a shutdown handler for loaded modules
500
- *
501
- * Returns a function that calls onShutdown() on all modules in reverse order.
502
- * Call this during graceful shutdown.
503
- *
504
- * @example
505
- * ```ts
506
- * const shutdown = createModuleShutdownHandler(loadedModules, container, env)
507
- *
508
- * process.on('SIGTERM', async () => {
509
- * await shutdown()
510
- * process.exit(0)
511
- * })
512
- * ```
513
- */
514
- const createModuleShutdownHandler = (modules, container, env) => {
515
- return async () => {
516
- for (const mod of [...modules].reverse()) if (mod.onShutdown) {
517
- const schemaRegistry = getSchemaRegistry();
518
- const ctx = {
519
- container,
520
- env,
521
- config: {},
522
- registerSchema: (tableName, schema) => {
523
- schemaRegistry.register(mod.id, tableName, schema);
524
- }
525
- };
526
- try {
527
- await mod.onShutdown(ctx);
528
- } catch (error) {
529
- console.error(`Module "${mod.id}" onShutdown() failed:`, error);
530
- }
531
- }
532
- };
533
- };
534
-
535
- //#endregion
536
- //#region src/config/define-config.ts
537
- /**
538
- * Define a Kuckit configuration with full type safety.
539
- *
540
- * This helper provides IntelliSense support and type checking for your configuration.
541
- *
542
- * @example
543
- * ```typescript
544
- * // kuckit.config.ts
545
- * import { defineConfig } from '@kuckit/sdk'
546
- *
547
- * export default defineConfig({
548
- * modules: [
549
- * { package: '@kuckit/users-module' },
550
- * { package: '@acme/billing-module', config: { currency: 'USD' } },
551
- * ],
552
- *
553
- * server: {
554
- * apiPrefix: '/api',
555
- * },
556
- *
557
- * client: {
558
- * routeInjection: true,
559
- * },
560
- * })
561
- * ```
562
- */
563
- function defineConfig(config) {
564
- return config;
565
- }
566
-
567
- //#endregion
568
- //#region src/config/loader.ts
569
- const CONFIG_FILES = [
570
- "kuckit.config.ts",
571
- "kuckit.config.js",
572
- "kuckit.config.mjs"
573
- ];
574
- /**
575
- * Find the config file path by searching from cwd upward
576
- */
577
- function findConfigFile(cwd = process.cwd()) {
578
- let dir = cwd;
579
- while (dir !== dirname(dir)) {
580
- for (const file of CONFIG_FILES) {
581
- const configPath = resolve(dir, file);
582
- if (existsSync(configPath)) return configPath;
583
- }
584
- dir = dirname(dir);
585
- }
586
- for (const file of CONFIG_FILES) {
587
- const configPath = resolve(dir, file);
588
- if (existsSync(configPath)) return configPath;
589
- }
590
- return null;
591
- }
592
- /**
593
- * Check if a unified config file exists
594
- */
595
- function hasUnifiedConfig(cwd = process.cwd()) {
596
- return findConfigFile(cwd) !== null;
597
- }
598
- /**
599
- * Load Kuckit configuration from file
600
- *
601
- * Uses jiti for TypeScript support at runtime.
602
- * Falls back to dynamic import for JS/MJS files.
603
- *
604
- * @param cwd - Directory to start searching from (default: process.cwd())
605
- * @throws Error if config file not found or invalid
606
- */
607
- async function loadKuckitConfig(cwd = process.cwd()) {
608
- const configPath = findConfigFile(cwd);
609
- if (!configPath) throw new Error(`No Kuckit config file found. Create a kuckit.config.ts at your project root.\nSearched from: ${cwd}`);
610
- let config;
611
- if (configPath.endsWith(".ts")) {
612
- const { createJiti } = await import("jiti");
613
- const loaded = await createJiti(cwd, { interopDefault: true }).import(configPath);
614
- config = loaded.default ?? loaded;
615
- } else {
616
- const loaded = await import(configPath);
617
- config = loaded.default ?? loaded;
618
- }
619
- if (!config || typeof config !== "object") throw new Error(`Invalid Kuckit config at ${configPath}: expected an object`);
620
- if (!Array.isArray(config.modules)) throw new Error(`Invalid Kuckit config at ${configPath}: 'modules' must be an array`);
621
- return {
622
- ...config,
623
- _configPath: configPath
624
- };
625
- }
626
- /**
627
- * Try to load config, returning null if not found
628
- */
629
- async function tryLoadKuckitConfig(cwd = process.cwd()) {
630
- try {
631
- return await loadKuckitConfig(cwd);
632
- } catch {
633
- return null;
634
- }
635
- }
636
-
637
- //#endregion
638
17
  export { Application, Contracts, Domain, ModuleRegistry, SchemaRegistry, asClass, asFunction, asValue, createKuckitContainer, createModuleShutdownHandler, defineConfig, defineKuckitModule, disposeContainer, findConfigFile, getModuleRegistry, getModulesWithCapability, getSchemaRegistry, hasUnifiedConfig, loadKuckitConfig, loadKuckitModules, registerCoreModule, resetModuleRegistry, resetSchemaRegistry, tryLoadKuckitConfig };