@kuckit/sdk 1.0.0

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.
@@ -0,0 +1,620 @@
1
+ import { AwilixContainer, AwilixContainer as AwilixContainer$1, Resolver, Resolver as Resolver$1, asClass, asFunction, asValue } from "awilix";
2
+ import * as Domain from "@kuckit/domain";
3
+ import { CacheStore, Clock, EventBus, Logger, RateLimiterStore } from "@kuckit/domain";
4
+ import { auth } from "@kuckit/auth";
5
+ import * as Application from "@kuckit/application";
6
+ import * as Contracts from "@kuckit/contracts";
7
+ import { PgTable, PgTable as PgTable$1 } from "drizzle-orm/pg-core";
8
+
9
+ //#region src/types.d.ts
10
+ /**
11
+ * Core SDK configuration
12
+ * This is the minimal config needed to bootstrap the SDK
13
+ */
14
+ interface CoreConfig {
15
+ databaseUrl: string;
16
+ enableFileLogging: boolean;
17
+ logDir: string;
18
+ logLevel: 'DEBUG' | 'INFO' | 'WARN' | 'ERROR';
19
+ env: string;
20
+ }
21
+ /**
22
+ * Core cradle interface - the stable contract for all SDK consumers
23
+ * This defines the services available in the DI container after core registration
24
+ *
25
+ * Keep this minimal and stable; breaking changes require major version bumps
26
+ */
27
+ interface CoreCradle {
28
+ config: CoreConfig;
29
+ dbPool: unknown;
30
+ db: unknown;
31
+ clock: Clock;
32
+ logger: Logger;
33
+ errorHandler: unknown;
34
+ auth: typeof auth;
35
+ aiProvider: unknown;
36
+ eventBus: EventBus;
37
+ cacheStore: CacheStore;
38
+ rateLimiterStore: RateLimiterStore;
39
+ requestId?: string;
40
+ session?: {
41
+ user?: {
42
+ id?: string;
43
+ };
44
+ } | null;
45
+ requestLogger?: Logger;
46
+ [key: string]: Resolver$1<any> | any;
47
+ }
48
+ /**
49
+ * Core container type with CoreCradle
50
+ */
51
+ type CoreContainer = AwilixContainer$1<CoreCradle>;
52
+ //#endregion
53
+ //#region src/core/container.d.ts
54
+ interface CreateKuckitOptions {
55
+ /**
56
+ * Core configuration for the SDK
57
+ */
58
+ config: CoreConfig;
59
+ /**
60
+ * Optional callback to register additional services after core registration
61
+ */
62
+ extraRegistrations?: (container: CoreContainer) => void | Promise<void>;
63
+ }
64
+ /**
65
+ * Factory function to create a Kuckit DI container
66
+ *
67
+ * This is the primary entry point for applications using the SDK.
68
+ * It creates an Awilix container with core infrastructure services pre-registered.
69
+ *
70
+ * @example
71
+ * ```ts
72
+ * const container = await createKuckitContainer({
73
+ * config: {
74
+ * databaseUrl: process.env.DATABASE_URL!,
75
+ * enableFileLogging: true,
76
+ * logDir: './logs',
77
+ * logLevel: 'INFO',
78
+ * env: 'production',
79
+ * },
80
+ * extraRegistrations: (container) => {
81
+ * // Register your custom services
82
+ * container.register({
83
+ * myService: asClass(MyService).singleton(),
84
+ * })
85
+ * },
86
+ * })
87
+ * ```
88
+ */
89
+ declare const createKuckitContainer: (opts: CreateKuckitOptions) => Promise<CoreContainer>;
90
+ /**
91
+ * Cleanup container resources gracefully
92
+ *
93
+ * Call this when shutting down your application to close database connections
94
+ * and other resources.
95
+ */
96
+ declare const disposeContainer: (container: CoreContainer) => Promise<void>;
97
+ //#endregion
98
+ //#region src/core/core.module.d.ts
99
+ /**
100
+ * Register core infrastructure services into the container
101
+ *
102
+ * This registers:
103
+ * - Database pool and connection
104
+ * - Clock
105
+ * - Logger (structured, Loki/Prometheus compatible)
106
+ * - AI provider
107
+ * - Auth
108
+ * - Event bus
109
+ * - Cache store
110
+ * - Rate limiter store
111
+ * - Request-scoped logger
112
+ */
113
+ declare const registerCoreModule: (container: CoreContainer) => void;
114
+ //#endregion
115
+ //#region src/modules/types.d.ts
116
+ /**
117
+ * Built-in capability types for common module features
118
+ */
119
+ type BuiltInCapability = 'nav.item' | 'settings.page' | 'dashboard.widget' | 'api.webhook' | 'api.public' | 'slot.provider';
120
+ /**
121
+ * Module capability type - built-in or custom
122
+ * Custom capabilities must be prefixed with 'custom.'
123
+ */
124
+ type ModuleCapability = BuiltInCapability | `custom.${string}`;
125
+ /**
126
+ * Module metadata for discovery and documentation
127
+ */
128
+ interface KuckitModuleMeta {
129
+ /** Unique identifier, e.g., 'kuckit.users' or 'acme.billing' */
130
+ id: string;
131
+ /** Human-readable name */
132
+ displayName?: string;
133
+ /** Module description */
134
+ description?: string;
135
+ /** Module version */
136
+ version?: string;
137
+ /** Capabilities this module provides */
138
+ capabilities?: ModuleCapability[];
139
+ }
140
+ /**
141
+ * Context passed to module hooks
142
+ */
143
+ interface KuckitModuleContext<TConfig = unknown> {
144
+ /** DI container for registering services */
145
+ container: CoreContainer;
146
+ /** Environment name (development, production, etc.) */
147
+ env: string;
148
+ /** Module-specific configuration */
149
+ config: TConfig;
150
+ /** Register a Drizzle schema for this module */
151
+ registerSchema: (tableName: string, schema: PgTable$1) => void;
152
+ }
153
+ /**
154
+ * API registration for oRPC routers or other API handlers
155
+ */
156
+ interface ApiRegistration {
157
+ /** Type of API handler */
158
+ type: 'rpc-router' | 'rest-router' | 'graphql-resolver';
159
+ /** Router/handler name, e.g., 'users' */
160
+ name: string;
161
+ /** The actual router/handler instance */
162
+ router: unknown;
163
+ /** Optional path prefix */
164
+ prefix?: string;
165
+ }
166
+ /**
167
+ * Module lifecycle hooks
168
+ */
169
+ interface KuckitModuleHooks<TConfig = unknown> {
170
+ /**
171
+ * Called early - register DI bindings (repositories, services, use cases)
172
+ * This is where you wire up your module's dependencies
173
+ */
174
+ register?(ctx: KuckitModuleContext<TConfig>): void | Promise<void>;
175
+ /**
176
+ * Called after all modules registered - register API endpoints
177
+ * Use addApiRegistration to contribute routes to the application
178
+ */
179
+ registerApi?(ctx: KuckitModuleContext<TConfig> & {
180
+ addApiRegistration: (reg: ApiRegistration) => void;
181
+ }): void | Promise<void>;
182
+ /**
183
+ * Called after everything is wired - final initialization
184
+ * Good place for startup tasks like cache warming, health checks, etc.
185
+ */
186
+ onBootstrap?(ctx: KuckitModuleContext<TConfig>): void | Promise<void>;
187
+ /**
188
+ * Optional: cleanup on shutdown
189
+ * Close connections, flush buffers, etc.
190
+ */
191
+ onShutdown?(ctx: KuckitModuleContext<TConfig>): void | Promise<void>;
192
+ }
193
+ /**
194
+ * Complete module definition combining metadata and hooks
195
+ */
196
+ interface KuckitModuleDefinition<TConfig = unknown> extends KuckitModuleMeta, KuckitModuleHooks<TConfig> {}
197
+ /**
198
+ * Module specification in application config
199
+ *
200
+ * You can specify a module in two ways:
201
+ * 1. `module`: Direct reference to a module definition (preferred in monorepos)
202
+ * 2. `package`: NPM package name for dynamic import (for published packages)
203
+ */
204
+ interface ModuleSpec<TConfig = unknown> {
205
+ /** Direct module definition (preferred in monorepos for better type safety) */
206
+ module?: KuckitModuleDefinition<TConfig>;
207
+ /** NPM package name or relative path for dynamic import, e.g., '@acme/billing-module' */
208
+ package?: string;
209
+ /** Module-specific configuration */
210
+ config?: TConfig;
211
+ /** Whether to skip this module */
212
+ disabled?: boolean;
213
+ }
214
+ //#endregion
215
+ //#region src/modules/define-module.d.ts
216
+ /**
217
+ * Helper to define a Kuckit module with type safety
218
+ *
219
+ * This is the primary way to create a module for the Kuckit SDK.
220
+ * It provides type inference for the configuration and validates
221
+ * the module structure at compile time.
222
+ *
223
+ * @example
224
+ * ```ts
225
+ * // In your module's main file (e.g., src/module.ts)
226
+ * import { defineKuckitModule, asClass, asFunction } from '@kuckit/sdk'
227
+ *
228
+ * interface BillingModuleConfig {
229
+ * currency: string
230
+ * taxRate: number
231
+ * }
232
+ *
233
+ * export const kuckitModule = defineKuckitModule<BillingModuleConfig>({
234
+ * id: 'acme.billing',
235
+ * displayName: 'Billing',
236
+ * description: 'Invoice and payment processing',
237
+ * version: '1.0.0',
238
+ *
239
+ * register(ctx) {
240
+ * ctx.container.register({
241
+ * invoiceRepository: asClass(DrizzleInvoiceRepository).scoped(),
242
+ * paymentService: asFunction(makePaymentService).singleton(),
243
+ * })
244
+ * },
245
+ *
246
+ * registerApi(ctx) {
247
+ * ctx.addApiRegistration({
248
+ * type: 'rpc-router',
249
+ * name: 'billing',
250
+ * router: createBillingRouter(ctx.container),
251
+ * })
252
+ * },
253
+ *
254
+ * onBootstrap(ctx) {
255
+ * const logger = ctx.container.resolve('logger')
256
+ * logger.info(`Billing module initialized with currency: ${ctx.config.currency}`)
257
+ * },
258
+ * })
259
+ * ```
260
+ *
261
+ * @param mod - The module definition object
262
+ * @returns The same module definition (for type inference)
263
+ */
264
+ declare const defineKuckitModule: <TConfig = unknown>(mod: KuckitModuleDefinition<TConfig>) => KuckitModuleDefinition<TConfig>;
265
+ //#endregion
266
+ //#region src/modules/loader.d.ts
267
+ interface LoadModulesOptions {
268
+ /** DI container to register services into */
269
+ container: CoreContainer;
270
+ /** Environment name (development, production, etc.) */
271
+ env: string;
272
+ /** List of modules to load */
273
+ modules: ModuleSpec[];
274
+ /** Hook to wire collected API registrations into your router */
275
+ onApiRegistrations?: (regs: ApiRegistration[]) => void | Promise<void>;
276
+ /** Hook called when all modules are loaded and bootstrapped */
277
+ onComplete?: () => void | Promise<void>;
278
+ }
279
+ /**
280
+ * Load and initialize Kuckit modules
281
+ *
282
+ * This function orchestrates the module loading lifecycle:
283
+ *
284
+ * 1. **Import Phase**: Dynamic import each module package
285
+ * 2. **Register Phase**: Run register() hooks (DI bindings)
286
+ * 3. **API Phase**: Run registerApi() hooks (API routes)
287
+ * 4. **Wire Phase**: Call onApiRegistrations callback
288
+ * 5. **Bootstrap Phase**: Run onBootstrap() hooks
289
+ * 6. **Complete Phase**: Call onComplete callback
290
+ *
291
+ * @example
292
+ * ```ts
293
+ * await loadKuckitModules({
294
+ * container,
295
+ * env: 'production',
296
+ * modules: [
297
+ * { package: '@kuckit/users-module' },
298
+ * { package: '@acme/billing-module', config: { currency: 'USD' } },
299
+ * { package: './src/modules/custom', disabled: process.env.DISABLE_CUSTOM === 'true' },
300
+ * ],
301
+ * onApiRegistrations: (registrations) => {
302
+ * // Wire up oRPC routers, REST routes, etc.
303
+ * for (const reg of registrations) {
304
+ * if (reg.type === 'rpc-router') {
305
+ * rootRouter.merge(reg.name, reg.router)
306
+ * }
307
+ * }
308
+ * },
309
+ * onComplete: () => {
310
+ * console.log('All modules loaded!')
311
+ * },
312
+ * })
313
+ * ```
314
+ */
315
+ declare const loadKuckitModules: (opts: LoadModulesOptions) => Promise<void>;
316
+ /**
317
+ * Create a shutdown handler for loaded modules
318
+ *
319
+ * Returns a function that calls onShutdown() on all modules in reverse order.
320
+ * Call this during graceful shutdown.
321
+ *
322
+ * @example
323
+ * ```ts
324
+ * const shutdown = createModuleShutdownHandler(loadedModules, container, env)
325
+ *
326
+ * process.on('SIGTERM', async () => {
327
+ * await shutdown()
328
+ * process.exit(0)
329
+ * })
330
+ * ```
331
+ */
332
+ declare const createModuleShutdownHandler: (modules: KuckitModuleDefinition[], container: CoreContainer, env: string) => (() => Promise<void>);
333
+ //#endregion
334
+ //#region src/modules/registry.d.ts
335
+ /**
336
+ * Information about a loaded module
337
+ */
338
+ interface LoadedModuleInfo {
339
+ /** Module unique identifier */
340
+ id: string;
341
+ /** Human-readable name */
342
+ displayName?: string;
343
+ /** Module description */
344
+ description?: string;
345
+ /** Module version */
346
+ version?: string;
347
+ /** Capabilities this module provides */
348
+ capabilities: ModuleCapability[];
349
+ }
350
+ /**
351
+ * Registry for loaded Kuckit modules
352
+ *
353
+ * Tracks all loaded modules and their capabilities for querying.
354
+ */
355
+ declare class ModuleRegistry {
356
+ private modules;
357
+ private frozen;
358
+ /**
359
+ * Register a loaded module
360
+ * @throws Error if registry is frozen or module ID already exists
361
+ */
362
+ register(module: KuckitModuleDefinition): void;
363
+ /**
364
+ * Get all registered modules
365
+ */
366
+ getAll(): LoadedModuleInfo[];
367
+ /**
368
+ * Get a module by ID
369
+ */
370
+ getById(id: string): LoadedModuleInfo | undefined;
371
+ /**
372
+ * Check if a module is registered
373
+ */
374
+ has(id: string): boolean;
375
+ /**
376
+ * Get all modules that have a specific capability
377
+ */
378
+ getWithCapability(capability: ModuleCapability): LoadedModuleInfo[];
379
+ /**
380
+ * Check if a specific module has a capability
381
+ */
382
+ hasCapability(moduleId: string, capability: ModuleCapability): boolean;
383
+ /**
384
+ * Get all unique capabilities across all modules
385
+ */
386
+ getAllCapabilities(): ModuleCapability[];
387
+ /**
388
+ * Freeze the registry to prevent further modifications
389
+ */
390
+ freeze(): void;
391
+ /**
392
+ * Check if registry is frozen
393
+ */
394
+ isFrozen(): boolean;
395
+ /**
396
+ * Get the number of registered modules
397
+ */
398
+ get size(): number;
399
+ /**
400
+ * Clear all modules (only works if not frozen)
401
+ */
402
+ clear(): void;
403
+ }
404
+ /**
405
+ * Get the global module registry
406
+ * Creates one if it doesn't exist
407
+ */
408
+ declare function getModuleRegistry(): ModuleRegistry;
409
+ /**
410
+ * Get all modules that have a specific capability
411
+ * Convenience function that uses the global registry
412
+ */
413
+ declare function getModulesWithCapability(capability: ModuleCapability): LoadedModuleInfo[];
414
+ /**
415
+ * Reset the global registry (mainly for testing)
416
+ */
417
+ declare function resetModuleRegistry(): void;
418
+ //#endregion
419
+ //#region src/config/types.d.ts
420
+ /**
421
+ * Configuration for a single Kuckit module
422
+ */
423
+ interface KuckitModuleConfig<TConfig = unknown> {
424
+ /** NPM package name, e.g., '@kuckit/users-module' or '@acme/billing-module' */
425
+ package: string;
426
+ /** Module-specific configuration */
427
+ config?: TConfig;
428
+ /** Whether this module is enabled (default: true). Can use environment variables. */
429
+ enabled?: boolean;
430
+ }
431
+ /**
432
+ * Discovery configuration for auto-detecting modules
433
+ */
434
+ interface KuckitDiscoveryConfig {
435
+ /** Enable auto-discovery of modules in node_modules (default: false) */
436
+ enabled?: boolean;
437
+ /** Glob patterns for module detection (default: ['@star/kuckit-star-module']) */
438
+ patterns?: string[];
439
+ }
440
+ /**
441
+ * Client-specific configuration
442
+ */
443
+ interface KuckitClientConfig {
444
+ /** Component registry mode: 'global' or 'context' (default: 'context') */
445
+ componentRegistry?: 'global' | 'context';
446
+ /** Enable automatic route injection (default: true) */
447
+ routeInjection?: boolean;
448
+ }
449
+ /**
450
+ * Server-specific configuration
451
+ */
452
+ interface KuckitServerConfig {
453
+ /** API route prefix (default: '/api') */
454
+ apiPrefix?: string;
455
+ }
456
+ /**
457
+ * Unified Kuckit configuration
458
+ *
459
+ * This is the single source of truth for both server and client module configuration.
460
+ * Place this in `kuckit.config.ts` at your project root.
461
+ *
462
+ * @example
463
+ * ```typescript
464
+ * import { defineConfig } from '@kuckit/sdk'
465
+ *
466
+ * export default defineConfig({
467
+ * modules: [
468
+ * { package: '@kuckit/users-module' },
469
+ * { package: '@acme/billing-module', config: { currency: 'USD' } },
470
+ * {
471
+ * package: '@acme/analytics-module',
472
+ * enabled: process.env.NODE_ENV === 'production',
473
+ * },
474
+ * ],
475
+ *
476
+ * server: {
477
+ * apiPrefix: '/api',
478
+ * },
479
+ *
480
+ * client: {
481
+ * routeInjection: true,
482
+ * },
483
+ * })
484
+ * ```
485
+ */
486
+ interface KuckitConfig {
487
+ /** List of modules to load */
488
+ modules: KuckitModuleConfig[];
489
+ /** Auto-discovery settings (Phase 3.2) */
490
+ discovery?: KuckitDiscoveryConfig;
491
+ /** Client-specific settings */
492
+ client?: KuckitClientConfig;
493
+ /** Server-specific settings */
494
+ server?: KuckitServerConfig;
495
+ }
496
+ /**
497
+ * Result of loading a Kuckit config file
498
+ */
499
+ interface LoadedKuckitConfig extends KuckitConfig {
500
+ /** Path to the config file that was loaded */
501
+ _configPath: string;
502
+ }
503
+ //#endregion
504
+ //#region src/config/define-config.d.ts
505
+ /**
506
+ * Define a Kuckit configuration with full type safety.
507
+ *
508
+ * This helper provides IntelliSense support and type checking for your configuration.
509
+ *
510
+ * @example
511
+ * ```typescript
512
+ * // kuckit.config.ts
513
+ * import { defineConfig } from '@kuckit/sdk'
514
+ *
515
+ * export default defineConfig({
516
+ * modules: [
517
+ * { package: '@kuckit/users-module' },
518
+ * { package: '@acme/billing-module', config: { currency: 'USD' } },
519
+ * ],
520
+ *
521
+ * server: {
522
+ * apiPrefix: '/api',
523
+ * },
524
+ *
525
+ * client: {
526
+ * routeInjection: true,
527
+ * },
528
+ * })
529
+ * ```
530
+ */
531
+ declare function defineConfig(config: KuckitConfig): KuckitConfig;
532
+ //#endregion
533
+ //#region src/config/loader.d.ts
534
+ /**
535
+ * Find the config file path by searching from cwd upward
536
+ */
537
+ declare function findConfigFile(cwd?: string): string | null;
538
+ /**
539
+ * Check if a unified config file exists
540
+ */
541
+ declare function hasUnifiedConfig(cwd?: string): boolean;
542
+ /**
543
+ * Load Kuckit configuration from file
544
+ *
545
+ * Uses jiti for TypeScript support at runtime.
546
+ * Falls back to dynamic import for JS/MJS files.
547
+ *
548
+ * @param cwd - Directory to start searching from (default: process.cwd())
549
+ * @throws Error if config file not found or invalid
550
+ */
551
+ declare function loadKuckitConfig(cwd?: string): Promise<LoadedKuckitConfig>;
552
+ /**
553
+ * Try to load config, returning null if not found
554
+ */
555
+ declare function tryLoadKuckitConfig(cwd?: string): Promise<LoadedKuckitConfig | null>;
556
+ //#endregion
557
+ //#region src/schema/registry.d.ts
558
+ /**
559
+ * Entry for a registered schema
560
+ */
561
+ interface SchemaEntry {
562
+ /** Module that owns this schema */
563
+ moduleId: string;
564
+ /** Table name identifier */
565
+ tableName: string;
566
+ /** Drizzle table schema */
567
+ schema: PgTable$1;
568
+ }
569
+ /**
570
+ * Registry for module-owned database schemas
571
+ *
572
+ * Allows modules to register their Drizzle schemas during the register() hook.
573
+ * The CLI uses this registry to aggregate schemas for drizzle-kit operations.
574
+ */
575
+ declare class SchemaRegistry {
576
+ private schemas;
577
+ /**
578
+ * Register a schema from a module
579
+ * @param moduleId - Module identifier (e.g., 'acme.billing')
580
+ * @param tableName - Table name identifier (e.g., 'invoices')
581
+ * @param schema - Drizzle PgTable schema
582
+ */
583
+ register(moduleId: string, tableName: string, schema: PgTable$1): void;
584
+ /**
585
+ * Get all registered schemas
586
+ */
587
+ getAll(): Map<string, SchemaEntry>;
588
+ /**
589
+ * Get schemas registered by a specific module
590
+ */
591
+ getByModule(moduleId: string): SchemaEntry[];
592
+ /**
593
+ * Get all schemas as a flat object for drizzle-kit
594
+ * Keys are table names, values are PgTable schemas
595
+ */
596
+ getAllSchemas(): Record<string, PgTable$1>;
597
+ /**
598
+ * Check if any schemas are registered
599
+ */
600
+ hasSchemas(): boolean;
601
+ /**
602
+ * Get the count of registered schemas
603
+ */
604
+ get size(): number;
605
+ /**
606
+ * Clear all schemas (mainly for testing)
607
+ */
608
+ clear(): void;
609
+ }
610
+ /**
611
+ * Get the global schema registry
612
+ * Creates one if it doesn't exist
613
+ */
614
+ declare function getSchemaRegistry(): SchemaRegistry;
615
+ /**
616
+ * Reset the global schema registry (mainly for testing)
617
+ */
618
+ declare function resetSchemaRegistry(): void;
619
+ //#endregion
620
+ export { type ApiRegistration, Application, type AwilixContainer, type BuiltInCapability, Contracts, type CoreConfig, type CoreContainer, type CoreCradle, type CreateKuckitOptions, Domain, type KuckitClientConfig, type KuckitConfig, type KuckitDiscoveryConfig, type KuckitModuleConfig, type KuckitModuleContext, type KuckitModuleDefinition, type KuckitModuleHooks, type KuckitModuleMeta, type KuckitServerConfig, type LoadModulesOptions, type LoadedKuckitConfig, type LoadedModuleInfo, type ModuleCapability, ModuleRegistry, type ModuleSpec, type PgTable, type Resolver, type SchemaEntry, SchemaRegistry, asClass, asFunction, asValue, createKuckitContainer, createModuleShutdownHandler, defineConfig, defineKuckitModule, disposeContainer, findConfigFile, getModuleRegistry, getModulesWithCapability, getSchemaRegistry, hasUnifiedConfig, loadKuckitConfig, loadKuckitModules, registerCoreModule, resetModuleRegistry, resetSchemaRegistry, tryLoadKuckitConfig };