@forklaunch/core 1.5.16 → 1.5.18

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 (33) hide show
  1. package/lib/http/index.js +31 -20
  2. package/lib/http/index.js.map +1 -1
  3. package/lib/http/index.mjs +30 -20
  4. package/lib/http/index.mjs.map +1 -1
  5. package/lib/http/middleware/request/auth.middleware.d.ts.map +1 -1
  6. package/lib/http/router/expressLikeRouter.d.ts +3 -1
  7. package/lib/http/router/expressLikeRouter.d.ts.map +1 -1
  8. package/lib/persistence/complianceTypes.d.ts +51 -2
  9. package/lib/persistence/complianceTypes.d.ts.map +1 -1
  10. package/lib/persistence/defineComplianceEntity.d.ts +3 -3
  11. package/lib/persistence/defineComplianceEntity.d.ts.map +1 -1
  12. package/lib/persistence/encryptionSafeEm.d.ts +82 -0
  13. package/lib/persistence/encryptionSafeEm.d.ts.map +1 -0
  14. package/lib/persistence/forgivingDecryptionEm.d.ts +12 -0
  15. package/lib/persistence/forgivingDecryptionEm.d.ts.map +1 -0
  16. package/lib/persistence/index.d.ts +3 -1
  17. package/lib/persistence/index.d.ts.map +1 -1
  18. package/lib/persistence/index.js +88 -6
  19. package/lib/persistence/index.js.map +1 -1
  20. package/lib/persistence/index.mjs +86 -6
  21. package/lib/persistence/index.mjs.map +1 -1
  22. package/lib/persistence/mikroOrm.types.d.ts +7 -1
  23. package/lib/persistence/mikroOrm.types.d.ts.map +1 -1
  24. package/lib/services/configInjector.d.ts.map +1 -1
  25. package/lib/services/index.js +6 -0
  26. package/lib/services/index.js.map +1 -1
  27. package/lib/services/index.mjs +6 -0
  28. package/lib/services/index.mjs.map +1 -1
  29. package/lib/services/retentionService.d.ts +3 -2
  30. package/lib/services/retentionService.d.ts.map +1 -1
  31. package/lib/services/runRetentionEnforcement.d.ts +2 -1
  32. package/lib/services/runRetentionEnforcement.d.ts.map +1 -1
  33. package/package.json +11 -12
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/services/index.ts","../../src/environment/loadCascadingEnv.ts","../../src/services/configInjector.ts","../../src/services/guards/isConstructed.ts","../../src/services/types/configInjector.types.ts","../../src/services/guards/isConstructedSingleton.ts","../../src/services/guards/isConstructor.ts","../../src/persistence/complianceTypes.ts","../../src/services/retentionService.ts","../../src/services/complianceDataService.ts","../../src/services/runRetentionEnforcement.ts"],"sourcesContent":["export { getEnvVar } from '@forklaunch/common';\nexport * from '../environment';\nexport { createConfigInjector } from './configInjector';\nexport type { ConfigInjector, ValidConfigInjector } from './configInjector';\nexport * from './types/configInjector.types';\nexport * from './types/entityManager.types';\nexport * from './types/service.types';\nexport {\n RetentionService,\n type EnforcementOptions,\n type EnforcementResult\n} from './retentionService';\nexport {\n ComplianceDataService,\n type EraseResult,\n type ExportResult,\n type UserIdFieldOverrides\n} from './complianceDataService';\nexport { runRetentionEnforcement } from './runRetentionEnforcement';\n","import dotenv from 'dotenv';\nimport { existsSync } from 'fs';\nimport { dirname, resolve } from 'path';\n\n/**\n * Gets cascading environment file paths: collects all .env.local files from project directory up to root\n * Root detection uses: .forklaunch/manifest.toml\n */\nexport function getCascadingEnvPaths(\n projectEnvPath: string | undefined,\n projectRoot: string = process.cwd()\n): {\n rootEnvExists: boolean;\n projectEnvExists: boolean;\n rootEnvPath?: string;\n projectEnvFilePath?: string;\n loadOrder: string[];\n} {\n const result = {\n rootEnvExists: false,\n projectEnvExists: false,\n rootEnvPath: undefined as string | undefined,\n projectEnvFilePath: undefined as string | undefined,\n loadOrder: [] as string[]\n };\n\n const applicationRoot = findApplicationRoot(projectRoot);\n\n const envLocalFiles = collectEnvLocalFiles(projectRoot, applicationRoot);\n result.loadOrder.push(...envLocalFiles);\n\n const rootEnvPath = resolve(applicationRoot, '.env.local');\n if (envLocalFiles.includes(rootEnvPath)) {\n result.rootEnvExists = true;\n result.rootEnvPath = rootEnvPath;\n }\n\n if (projectEnvPath) {\n const fullProjectEnvPath = resolve(projectRoot, projectEnvPath);\n if (existsSync(fullProjectEnvPath)) {\n result.projectEnvExists = true;\n result.projectEnvFilePath = fullProjectEnvPath;\n if (!result.loadOrder.includes(fullProjectEnvPath)) {\n result.loadOrder.push(fullProjectEnvPath);\n }\n }\n }\n\n return result;\n}\n\n/**\n * Loads environment variables with cascading precedence: all .env.local files from root to project, then project env file\n */\nexport function loadCascadingEnv(\n projectEnvPath: string | undefined,\n projectRoot: string = process.cwd()\n): {\n rootEnvLoaded: boolean;\n projectEnvLoaded: boolean;\n rootEnvPath?: string;\n projectEnvFilePath?: string;\n envFilesLoaded: string[];\n totalEnvFilesLoaded: number;\n} {\n const paths = getCascadingEnvPaths(projectEnvPath, projectRoot);\n const result = {\n rootEnvLoaded: false,\n projectEnvLoaded: false,\n rootEnvPath: paths.rootEnvPath,\n projectEnvFilePath: paths.projectEnvFilePath,\n envFilesLoaded: [] as string[],\n totalEnvFilesLoaded: 0\n };\n\n const seen = new Set<string>();\n for (const envPath of paths.loadOrder) {\n if (seen.has(envPath)) {\n continue;\n }\n seen.add(envPath);\n\n const envResult = dotenv.config({\n path: envPath,\n override: true\n });\n\n if (!envResult?.error) {\n result.envFilesLoaded.push(envPath);\n result.totalEnvFilesLoaded++;\n\n if (envPath === paths.rootEnvPath) {\n result.rootEnvLoaded = true;\n }\n if (envPath === paths.projectEnvFilePath) {\n result.projectEnvLoaded = true;\n }\n }\n }\n\n return result;\n}\n\n/**\n * Collects all .env.local files from project directory up to application root\n * Returns paths in order from root to project (for proper precedence)\n */\nfunction collectEnvLocalFiles(\n projectRoot: string,\n applicationRoot: string\n): string[] {\n const envLocalPaths: string[] = [];\n\n let currentPath = resolve(projectRoot);\n const normalizedAppRoot = resolve(applicationRoot);\n\n while (currentPath.length >= normalizedAppRoot.length) {\n const envLocalPath = resolve(currentPath, '.env.local');\n if (existsSync(envLocalPath)) {\n envLocalPaths.push(envLocalPath);\n }\n\n if (currentPath === normalizedAppRoot) {\n break;\n }\n\n const parentPath = dirname(currentPath);\n if (parentPath === currentPath) {\n break;\n }\n\n currentPath = parentPath;\n }\n\n return envLocalPaths.reverse();\n}\n\n/**\n * Finds application root by looking for .forklaunch/manifest.toml\n */\nexport function findApplicationRoot(startPath: string): string {\n let currentPath = resolve(startPath);\n const originalStart = currentPath;\n const maxDepth = 10;\n let depth = 0;\n\n while (depth < maxDepth) {\n const forklaunchManifest = resolve(\n currentPath,\n '.forklaunch',\n 'manifest.toml'\n );\n if (existsSync(forklaunchManifest)) {\n return currentPath;\n }\n\n const parentPath = dirname(currentPath);\n if (parentPath === currentPath) {\n break;\n }\n\n currentPath = parentPath;\n depth++;\n }\n\n return originalStart;\n}\n","import { extractArgumentNames, isNever } from '@forklaunch/common';\nimport {\n AnySchemaValidator,\n IdiomaticSchema,\n ParseResult,\n prettyPrintParseErrors,\n SchemaValidator\n} from '@forklaunch/validator';\nimport { isConstructed } from './guards/isConstructed';\nimport { isConstructedSingleton } from './guards/isConstructedSingleton';\nimport { isConstructor } from './guards/isConstructor';\nimport {\n ConfigValidator,\n Constructed,\n ConstructedSingleton,\n Lifetime,\n ResolvedConfigValidator,\n SchemaConstructor,\n SchemaFunction,\n Singleton\n} from './types/configInjector.types';\n\nexport function createConfigInjector<\n SV extends AnySchemaValidator,\n CV extends ConfigValidator<SV>\n>(\n schemaValidator: SV,\n dependenciesDefinition: {\n [K in keyof CV]:\n | Singleton<\n CV[K],\n Omit<ResolvedConfigValidator<SV, CV>, K>,\n ResolvedConfigValidator<SV, CV>[K]\n >\n | Constructed<\n CV[K],\n Omit<ResolvedConfigValidator<SV, CV>, K>,\n ResolvedConfigValidator<SV, CV>[K]\n >;\n }\n) {\n return new ConfigInjector<SV, CV>(\n schemaValidator,\n dependenciesDefinition\n ).load();\n}\n\nexport class ConfigInjector<\n SV extends AnySchemaValidator,\n CV extends ConfigValidator<SV>\n> {\n instances: {\n [K in keyof CV]?: ResolvedConfigValidator<SV, CV>[K];\n } = {};\n\n readonly configShapes: CV;\n\n load(inheritedScopeInstances?: {\n [K in keyof CV]?: ResolvedConfigValidator<SV, CV>[K];\n }): this {\n for (const token in inheritedScopeInstances) {\n this.instances[token] = inheritedScopeInstances[token];\n }\n\n for (const token in this.dependenciesDefinition) {\n const definition = this.dependenciesDefinition[token];\n if (\n definition.lifetime === Lifetime.Singleton &&\n !this.instances[token]\n ) {\n if (\n isConstructedSingleton<\n CV[typeof token],\n Omit<ResolvedConfigValidator<SV, CV>, typeof token>,\n ResolvedConfigValidator<SV, CV>[typeof token]\n >(definition)\n ) {\n this.instances[token] = this.resolveInstance<typeof token>(\n token,\n definition\n );\n } else {\n this.instances[token] = definition.value;\n }\n }\n }\n return this;\n }\n\n private resolveInstance<T extends keyof CV>(\n token: T,\n definition:\n | ConstructedSingleton<\n CV[T],\n Omit<ResolvedConfigValidator<SV, CV>, T>,\n ResolvedConfigValidator<SV, CV>[T]\n >\n | Constructed<\n CV[T],\n Omit<ResolvedConfigValidator<SV, CV>, T>,\n ResolvedConfigValidator<SV, CV>[T]\n >,\n context?: Record<string, unknown>,\n resolutionPath: (keyof CV)[] = []\n ): ResolvedConfigValidator<SV, CV>[T] {\n if (process.env.FORKLAUNCH_MODE === 'openapi') {\n const noopProxy: Record<string, unknown> = new Proxy(\n function () {} as unknown as Record<string, unknown>,\n {\n get(_target, prop) {\n if (prop === Symbol.toPrimitive) return () => '';\n if (prop === 'toString' || prop === 'valueOf') return () => '';\n if (prop === 'then') return undefined;\n if (prop === Symbol.iterator) return function* () {};\n if (prop === Symbol.asyncIterator) return async function* () {};\n return noopProxy;\n },\n set() {\n return true;\n },\n has() {\n return true;\n },\n deleteProperty() {\n return true;\n },\n ownKeys() {\n return ['prototype'];\n },\n getOwnPropertyDescriptor(_target, prop) {\n if (prop === 'prototype') {\n return { configurable: false, enumerable: false, writable: true };\n }\n return { configurable: true, enumerable: true };\n },\n apply() {\n return noopProxy;\n },\n construct() {\n return noopProxy as object;\n }\n }\n );\n return noopProxy as ResolvedConfigValidator<SV, CV>[T];\n }\n\n const rawInjectorArgument = extractArgumentNames(definition.factory)[0];\n // short circuit as no args\n if (!rawInjectorArgument || rawInjectorArgument === '_args') {\n return definition.factory(\n {} as Omit<ResolvedConfigValidator<SV, CV>, T>,\n context ?? {},\n this.resolve.bind(this)\n );\n }\n\n // Normalize whitespace to handle both single-line and multiline formatting\n const injectorArgument = rawInjectorArgument.replace(/\\s+/g, '');\n\n if (!injectorArgument.startsWith('{') || !injectorArgument.endsWith('}')) {\n throw new Error(\n `Invalid injector argument for ${String(\n token\n )}: ${injectorArgument}. Please use object destructuring syntax: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment.`\n );\n }\n const resolvedArguments = Object.fromEntries(\n injectorArgument\n .slice(1, -1)\n .split(',')\n .filter((arg) => arg.length > 0)\n .map((arg) => arg.split(':')[0].trim())\n .map((arg) => {\n const newResolutionPath = [...resolutionPath, token];\n if (resolutionPath.includes(arg)) {\n throw new Error(\n `Circular dependency detected: ${newResolutionPath.join(\n ' -> '\n )} -> ${arg}`\n );\n }\n const resolvedArg = this.resolve(arg, context, newResolutionPath);\n return [arg, resolvedArg];\n })\n ) as unknown as Omit<ResolvedConfigValidator<SV, CV>, T>;\n return definition.factory(\n resolvedArguments,\n context ?? {},\n this.resolve.bind(this)\n );\n }\n\n constructor(\n private schemaValidator: SV,\n private dependenciesDefinition: {\n [K in keyof CV]: (\n | Singleton<\n CV[K],\n Omit<ResolvedConfigValidator<SV, CV>, K>,\n ResolvedConfigValidator<SV, CV>[K]\n >\n | Constructed<\n CV[K],\n Omit<ResolvedConfigValidator<SV, CV>, K>,\n ResolvedConfigValidator<SV, CV>[K]\n >\n ) & {\n type: CV[K];\n };\n }\n ) {\n this.configShapes = Object.entries(this.dependenciesDefinition).reduce(\n (acc, [key, { type }]) => ({\n ...acc,\n [key]: type\n }),\n {} as Record<keyof CV, CV[keyof CV]>\n ) as CV;\n }\n\n safeValidateConfigSingletons(): ParseResult<ValidConfigInjector<SV, CV>> {\n const validNonSchemaSingletons = Object.entries(this.configShapes).reduce<\n ParseResult<ResolvedConfigValidator<SV, CV>>\n >(\n (acc, [key, value]) => {\n if (\n this.dependenciesDefinition[key].lifetime === Lifetime.Singleton &&\n !(this.schemaValidator as SchemaValidator).isSchema<\n SchemaFunction<SV> | SchemaConstructor<SV> | IdiomaticSchema<SV>\n >(value) &&\n isConstructor(value)\n ) {\n if (!(this.instances[key] instanceof value)) {\n const expected = value.name;\n const receivedValue: unknown = this.instances[key];\n const received = isConstructed(receivedValue)\n ? receivedValue.constructor.name\n : typeof receivedValue;\n\n if (acc.ok) {\n acc = {\n ok: false,\n errors: []\n };\n }\n acc.errors?.push({\n message: `Expected ${expected}, received ${received}`,\n path: [key]\n });\n } else {\n if (acc.ok) {\n acc = {\n ok: true,\n value: {\n ...acc.value,\n [key]: this.instances[key]\n }\n };\n }\n }\n return acc;\n }\n return acc;\n },\n {\n ok: true,\n value: {} as ResolvedConfigValidator<SV, CV>\n }\n );\n\n const singletons = Object.fromEntries(\n Object.entries(this.configShapes).filter(\n ([key, value]) =>\n this.dependenciesDefinition[key].lifetime === Lifetime.Singleton &&\n (this.schemaValidator as SchemaValidator).isSchema(value)\n )\n );\n const schemaSingletonParseResult = (\n this.schemaValidator as SchemaValidator\n ).parse(\n (this.schemaValidator as SchemaValidator).schemify(singletons),\n Object.fromEntries(\n Object.keys(singletons).map((key) => {\n const dependency = this.dependenciesDefinition[key];\n return [\n key,\n dependency.lifetime === Lifetime.Singleton\n ? this.instances[key]\n : undefined\n ];\n })\n )\n );\n\n const configKeys = Object.keys(this.configShapes);\n\n return validNonSchemaSingletons.ok && schemaSingletonParseResult.ok\n ? {\n ok: true as const,\n value: new ValidConfigInjector<SV, CV>(\n this.schemaValidator,\n this.dependenciesDefinition\n ).load({ ...this.instances })\n }\n : {\n ok: false as const,\n errors: [\n ...(!validNonSchemaSingletons.ok && validNonSchemaSingletons.errors\n ? validNonSchemaSingletons.errors\n : []),\n ...(!schemaSingletonParseResult.ok &&\n schemaSingletonParseResult.errors\n ? schemaSingletonParseResult.errors\n : [])\n ].sort(\n (a, b) =>\n configKeys.indexOf(a.path[0]) - configKeys.indexOf(b.path[0])\n )\n };\n }\n\n validateConfigSingletons(configName: string): ValidConfigInjector<SV, CV> {\n if (process.env.FORKLAUNCH_MODE === 'openapi') {\n return this.createScope() as ValidConfigInjector<SV, CV>;\n }\n\n const safeValidateResult = this.safeValidateConfigSingletons();\n\n if (safeValidateResult.ok) {\n return safeValidateResult.value;\n }\n\n throw new Error(\n prettyPrintParseErrors(safeValidateResult.errors, configName)\n );\n }\n\n resolve<T extends keyof CV>(\n token: T,\n context?: Record<string, unknown>,\n resolutionPath: (keyof CV)[] = []\n ): ResolvedConfigValidator<SV, CV>[T] {\n const instance = this.instances[token];\n if (!instance) {\n const definition = this.dependenciesDefinition[token];\n\n if (!definition) {\n throw new Error(`Unable to resolve dependency ${String(token)}`);\n }\n\n switch (definition.lifetime) {\n case Lifetime.Singleton: {\n if (\n isConstructedSingleton<\n CV[T],\n Omit<ResolvedConfigValidator<SV, CV>, T>,\n ResolvedConfigValidator<SV, CV>[T]\n >(definition) &&\n !this.instances[token]\n ) {\n this.instances[token] = this.resolveInstance<T>(\n token,\n definition,\n context,\n resolutionPath\n );\n }\n return this.instances[token] as ResolvedConfigValidator<SV, CV>[T];\n }\n case Lifetime.Scoped: {\n if (\n !isConstructed<\n CV[T],\n Omit<ResolvedConfigValidator<SV, CV>, T>,\n ResolvedConfigValidator<SV, CV>[T]\n >(definition)\n ) {\n throw new Error(\n `Invalid dependency definition for ${String(token)}`\n );\n }\n\n const scopedInstance = this.resolveInstance<T>(\n token,\n definition,\n context,\n resolutionPath\n );\n this.instances[token] = scopedInstance;\n return scopedInstance;\n }\n case Lifetime.Transient: {\n if (\n !isConstructed<\n CV[T],\n Omit<ResolvedConfigValidator<SV, CV>, T>,\n ResolvedConfigValidator<SV, CV>[T]\n >(definition)\n ) {\n throw new Error(\n `Invalid dependency definition for ${String(token)}`\n );\n }\n\n return this.resolveInstance<T>(\n token,\n definition,\n context,\n resolutionPath\n );\n }\n default: {\n isNever(definition);\n throw new Error(\n `Unable to resolve lifetime for dependency ${String(\n token\n )}, ${resolutionPath}`\n );\n }\n }\n } else {\n return instance;\n }\n }\n\n scopedResolver<T extends keyof CV>(\n token: T,\n context?: Record<string, unknown>,\n resolutionPath: (keyof CV)[] = []\n ): (options?: {\n scope?: ConfigInjector<SV, CV>;\n context?: Record<string, unknown>;\n }) => ResolvedConfigValidator<SV, CV>[T] {\n return (options) =>\n (options?.scope ?? this.createScope()).resolve<T>(\n token,\n options?.context ? { ...context, ...options.context } : context,\n resolutionPath\n );\n }\n\n createScope(): ConfigInjector<SV, CV> {\n const singletons: Record<string, unknown> = {};\n for (const dependency in this.dependenciesDefinition) {\n if (\n this.dependenciesDefinition[dependency].lifetime === Lifetime.Singleton\n ) {\n singletons[dependency] = this.instances[dependency];\n }\n }\n return new ConfigInjector<SV, CV>(\n this.schemaValidator,\n this.dependenciesDefinition\n ).load(singletons as ResolvedConfigValidator<SV, CV>);\n }\n\n dispose(): void {\n this.instances = {};\n this.load();\n }\n\n chain<ChainedCV extends ConfigValidator<SV>>(dependenciesDefinition: {\n [K in keyof ChainedCV]: {\n type: ChainedCV[K];\n } & (\n | Singleton<\n ChainedCV[K],\n Omit<ResolvedConfigValidator<SV, CV & ChainedCV>, K>,\n ResolvedConfigValidator<SV, ChainedCV>[K]\n >\n | Constructed<\n ChainedCV[K],\n Omit<ResolvedConfigValidator<SV, CV & ChainedCV>, K>,\n ResolvedConfigValidator<SV, ChainedCV>[K]\n >\n );\n }): ConfigInjector<SV, CV & ChainedCV> {\n return new ConfigInjector<SV, CV>(this.schemaValidator, {\n ...this.dependenciesDefinition,\n ...dependenciesDefinition\n }).load({ ...this.instances }) as unknown as ConfigInjector<\n SV,\n CV & ChainedCV\n >;\n }\n\n tokens(): {\n [K in keyof CV]: K;\n } {\n return Object.fromEntries(\n Object.keys(this.dependenciesDefinition).map((key) => [key, key])\n ) as {\n [K in keyof CV]: K;\n };\n }\n}\n\nexport class ValidConfigInjector<\n SV extends AnySchemaValidator,\n CV extends ConfigValidator<SV>\n> extends ConfigInjector<SV, CV> {\n validConfigInjector!: void;\n}\n","import { Constructed } from '../types/configInjector.types';\n\nexport function isConstructed<Type, Args, Return>(\n value: unknown\n): value is Constructed<Type, Args, Return> {\n return (\n typeof value === 'object' &&\n value != null &&\n 'constructor' in value &&\n value.constructor != null\n );\n}\n","import {\n AnySchemaValidator,\n IdiomaticSchema,\n Schema\n} from '@forklaunch/validator';\nimport { ConfigInjector } from '../configInjector';\n\nexport const Lifetime = {\n Singleton: 0,\n Transient: 1,\n Scoped: 2\n} as const;\nexport type Lifetime = (typeof Lifetime)[keyof typeof Lifetime];\n\nexport type Singleton<Type, Args, Value> =\n | {\n lifetime: typeof Lifetime.Singleton;\n type: Type;\n value: Value;\n }\n | ConstructedSingleton<Type, Args, Value>;\n\nexport type ConstructedSingleton<Type, Args, Return> = {\n lifetime: typeof Lifetime.Singleton;\n type: Type;\n factory: (\n args: Args,\n context: Record<string, unknown>,\n resolve: <T extends keyof Args>(\n token: T,\n context?: Record<string, unknown>\n ) => Args[T]\n ) => Return;\n};\n\nexport type Constructed<Type, Args, Return> = {\n lifetime: typeof Lifetime.Transient | typeof Lifetime.Scoped;\n type: Type;\n factory: (\n args: Args,\n context: Record<string, unknown>,\n resolve: <T extends keyof Args>(\n token: T,\n context?: Record<string, unknown>\n ) => Args[T]\n ) => Return;\n};\n\nexport type Constructor = new (...args: never[]) => unknown;\nexport type SchemaConstructor<SV extends AnySchemaValidator> = new (\n ...args: unknown[]\n) => IdiomaticSchema<SV>;\nexport type Function = (...args: never[]) => unknown;\nexport type FunctionToConstructor = (\n ...args: never[]\n) => new (...args: never[]) => unknown;\nexport type SchemaFunction<SV extends AnySchemaValidator> = (\n args: unknown\n) => IdiomaticSchema<SV>;\n\nexport type ConfigTypes<SV extends AnySchemaValidator> =\n | Function\n | SchemaFunction<SV>\n | Constructor\n | SchemaConstructor<SV>\n | IdiomaticSchema<SV>;\n\nexport type ConfigValidator<SV extends AnySchemaValidator> = Record<\n string,\n ConfigTypes<SV> | Record<string, ConfigTypes<SV>>\n>;\n\ntype ResolveConfigValue<SV extends AnySchemaValidator, T> =\n T extends SchemaConstructor<SV>\n ? Schema<InstanceType<T>, SV>\n : T extends SchemaFunction<SV>\n ? (...args: Parameters<T>) => Schema<ReturnType<T>, SV>\n : T extends FunctionToConstructor\n ? (...args: Parameters<T>) => InstanceType<ReturnType<T>>\n : T extends Function\n ? (...args: Parameters<T>) => ReturnType<T>\n : T extends Constructor\n ? InstanceType<T>\n : T extends IdiomaticSchema<SV>\n ? Schema<T, SV>\n : T extends Record<string, ConfigTypes<SV>>\n ? {\n [K in keyof T]: ResolveConfigValue<SV, T[K]>;\n }\n : Schema<T, SV>;\n\nexport type ResolvedConfigValidator<\n SV extends AnySchemaValidator,\n CV extends ConfigValidator<SV>\n> = {\n [M in keyof CV]: ResolveConfigValue<SV, CV[M]>;\n};\n\nexport type ScopedDependencyFactory<\n SV extends AnySchemaValidator,\n CV extends ConfigValidator<SV>,\n M extends keyof CV\n> = (scope?: ConfigInjector<SV, CV>) => ResolvedConfigValidator<SV, CV>[M];\n","import { ConstructedSingleton, Lifetime } from '../types/configInjector.types';\n\nexport function isConstructedSingleton<Type, Args, Return>(\n value: unknown\n): value is ConstructedSingleton<Type, Args, Return> {\n return (\n typeof value === 'object' &&\n value != null &&\n 'lifetime' in value &&\n value.lifetime === Lifetime.Singleton &&\n 'factory' in value\n );\n}\n","import { Constructor } from '../types/configInjector.types';\n\nexport function isConstructor(value: unknown): value is Constructor {\n return (\n typeof value === 'function' &&\n value.constructor != null &&\n value.prototype != null\n );\n}\n","export const ComplianceLevel = {\n pii: 'pii',\n phi: 'phi',\n pci: 'pci',\n none: 'none'\n} as const;\nexport type ComplianceLevel =\n (typeof ComplianceLevel)[keyof typeof ComplianceLevel];\n\nexport const COMPLIANCE_KEY = '~compliance' as const;\n\n// ---------------------------------------------------------------------------\n// Registry\n// ---------------------------------------------------------------------------\n\nconst complianceRegistry = new Map<string, Map<string, ComplianceLevel>>();\n\nexport function registerEntityCompliance(\n entityName: string,\n fields: Map<string, ComplianceLevel>\n): void {\n complianceRegistry.set(entityName, fields);\n}\n\nexport function getComplianceMetadata(\n entityName: string,\n fieldName: string\n): ComplianceLevel {\n return complianceRegistry.get(entityName)?.get(fieldName) ?? 'none';\n}\n\nexport function getEntityComplianceFields(\n entityName: string\n): Map<string, ComplianceLevel> | undefined {\n return complianceRegistry.get(entityName);\n}\n\nexport function entityHasEncryptedFields(entityName: string): boolean {\n const fields = complianceRegistry.get(entityName);\n if (!fields) return false;\n for (const level of fields.values()) {\n if (level === 'phi' || level === 'pci') return true;\n }\n return false;\n}\n\n// ---------------------------------------------------------------------------\n// Retention types and registry\n// ---------------------------------------------------------------------------\n\nexport const RetentionAction = {\n delete: 'delete',\n anonymize: 'anonymize'\n} as const;\nexport type RetentionAction =\n (typeof RetentionAction)[keyof typeof RetentionAction];\n\nexport interface RetentionPolicy {\n duration: string;\n action: RetentionAction;\n}\n\nexport const RetentionDuration = {\n days: (n: number): string => `P${n}D`,\n months: (n: number): string => `P${n}M`,\n years: (n: number): string => `P${n}Y`\n} as const;\n\nexport interface ParsedDuration {\n years: number;\n months: number;\n days: number;\n}\n\nconst DURATION_REGEX = /^P(?:(\\d+)Y)?(?:(\\d+)M)?(?:(\\d+)D)?$/;\n\n/**\n * Parse an ISO 8601 duration string into calendar units.\n * Returns structured units to enable calendar-aware date arithmetic.\n */\nexport function parseDuration(iso: string): ParsedDuration {\n const match = DURATION_REGEX.exec(iso);\n if (!match) {\n throw new Error(\n `Invalid ISO 8601 duration: '${iso}'. Expected format: P[n]Y[n]M[n]D`\n );\n }\n const years = parseInt(match[1] || '0', 10);\n const months = parseInt(match[2] || '0', 10);\n const days = parseInt(match[3] || '0', 10);\n\n // Approximate total days for minimum validation only\n const approxDays = years * 365 + months * 30 + days;\n if (approxDays < 1) {\n throw new Error(\n `Retention duration must be >= 1 day (P1D). Got: '${iso}' (${approxDays} approx days)`\n );\n }\n\n return { years, months, days };\n}\n\n/**\n * Subtract a parsed duration from a date using calendar-aware arithmetic.\n * Handles month-end clamping and leap years correctly.\n */\nexport function subtractDuration(from: Date, duration: ParsedDuration): Date {\n const result = new Date(from);\n result.setFullYear(result.getFullYear() - duration.years);\n result.setMonth(result.getMonth() - duration.months);\n result.setDate(result.getDate() - duration.days);\n return result;\n}\n\nconst retentionRegistry = new Map<string, RetentionPolicy>();\n\n// ---------------------------------------------------------------------------\n// User ID field registry — maps entity name to the field linking records to a user\n// ---------------------------------------------------------------------------\n\nconst DEFAULT_USER_ID_FIELD = 'userId';\nconst userIdFieldRegistry = new Map<string, string>();\n\nexport function registerEntityUserIdField(\n entityName: string,\n field: string\n): void {\n userIdFieldRegistry.set(entityName, field);\n}\n\nexport function getEntityUserIdField(entityName: string): string {\n return userIdFieldRegistry.get(entityName) ?? DEFAULT_USER_ID_FIELD;\n}\n\nexport function getAllUserIdFields(): ReadonlyMap<string, string> {\n return userIdFieldRegistry;\n}\n\nexport function registerEntityRetention(\n entityName: string,\n policy: RetentionPolicy\n): void {\n retentionRegistry.set(entityName, policy);\n}\n\nexport function getEntityRetention(\n entityName: string\n): RetentionPolicy | undefined {\n return retentionRegistry.get(entityName);\n}\n\nexport function getAllRetentionPolicies(): ReadonlyMap<\n string,\n RetentionPolicy\n> {\n return retentionRegistry;\n}\n\n// ---------------------------------------------------------------------------\n// Module augmentation — adds .compliance() via PropertyOptions\n// ---------------------------------------------------------------------------\n\n/**\n * Adds `compliance` to PropertyOptions, which flows into IncludeKeys\n * for all scalar/enum/embedded builders (PropertyOptions is extended by\n * EnumOptions and EmbeddedOptions). Relation builders use ReferenceOptions\n * instead, so they don't get .compliance() — which is what we want.\n */\ndeclare module '@mikro-orm/core' {\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n interface PropertyOptions<Owner> {\n compliance?: ComplianceLevel;\n }\n\n interface UniversalPropertyOptionsBuilder<Value, Options, IncludeKeys> {\n compliance(\n level: ComplianceLevel\n ): Pick<\n UniversalPropertyOptionsBuilder<\n Value,\n Options & { readonly '~c': true },\n IncludeKeys\n >,\n IncludeKeys & keyof UniversalPropertyOptionsBuilder<never, never, never>\n >;\n }\n}\n","import type { OpenTelemetryCollector } from '../http/telemetry/openTelemetryCollector';\nimport type { ComplianceOrm } from './complianceDataService';\nimport {\n getAllRetentionPolicies,\n getEntityComplianceFields,\n parseDuration,\n subtractDuration,\n type RetentionPolicy\n} from '../persistence/complianceTypes';\n\nexport interface EnforcementOptions {\n /** Filter to specific entity names (default: all with retention policies) */\n entities?: string[];\n /** Records per batch (default: 1000) */\n batchSize?: number;\n /** Log what would happen without mutating */\n dryRun?: boolean;\n}\n\nexport interface EnforcementResult {\n processed: number;\n deleted: number;\n anonymized: number;\n errors: number;\n byEntity: Record<\n string,\n { deleted: number; anonymized: number; errors: number }\n >;\n durationMs: number;\n}\n\nexport class RetentionService {\n private readonly DEFAULT_BATCH_SIZE = 1000;\n\n constructor(\n private readonly orm: ComplianceOrm,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n private readonly otel: OpenTelemetryCollector<any>\n ) {}\n\n async enforce(options?: EnforcementOptions): Promise<EnforcementResult> {\n const start = Date.now();\n const batchSize = options?.batchSize ?? this.DEFAULT_BATCH_SIZE;\n const dryRun = options?.dryRun ?? false;\n const policies = getAllRetentionPolicies();\n const result: EnforcementResult = {\n processed: 0,\n deleted: 0,\n anonymized: 0,\n errors: 0,\n byEntity: {},\n durationMs: 0\n };\n\n if (policies.size === 0) {\n this.otel.info('[RetentionService] No retention policies registered');\n result.durationMs = Date.now() - start;\n return result;\n }\n\n this.otel.info('[RetentionService] Starting enforcement', {\n entityCount: policies.size,\n batchSize,\n dryRun\n });\n\n for (const [entityName, policy] of policies) {\n if (options?.entities && !options.entities.includes(entityName)) continue;\n\n const entityResult = { deleted: 0, anonymized: 0, errors: 0 };\n\n try {\n await this.enforceEntity(\n entityName,\n policy,\n batchSize,\n entityResult,\n dryRun\n );\n } catch (err) {\n entityResult.errors++;\n this.otel.error('[RetentionService] Entity-level failure', {\n entityName,\n error: String(err)\n });\n }\n\n result.byEntity[entityName] = entityResult;\n result.deleted += entityResult.deleted;\n result.anonymized += entityResult.anonymized;\n result.errors += entityResult.errors;\n result.processed += entityResult.deleted + entityResult.anonymized;\n }\n\n result.durationMs = Date.now() - start;\n this.otel.info('[RetentionService] Enforcement complete', {\n processed: result.processed,\n deleted: result.deleted,\n anonymized: result.anonymized,\n errors: result.errors,\n durationMs: result.durationMs\n });\n\n return result;\n }\n\n private async enforceEntity(\n entityName: string,\n policy: RetentionPolicy,\n batchSize: number,\n stats: { deleted: number; anonymized: number; errors: number },\n dryRun: boolean\n ): Promise<void> {\n const metadata = [...this.orm.getMetadata().getAll().values()].find(\n (m) => m.className === entityName\n );\n\n if (!metadata) {\n this.otel.warn(\n '[RetentionService] Entity not in MikroORM metadata — skipping',\n { entityName }\n );\n return;\n }\n\n const duration = parseDuration(policy.duration);\n const cutoff = subtractDuration(new Date(), duration);\n const entityClass = metadata.class ?? metadata.className;\n\n // For anonymize: only null out PII/PHI/PCI fields that are nullable.\n // Non-nullable fields are skipped to avoid flush errors.\n const piiFieldNames: string[] = [];\n if (policy.action === 'anonymize') {\n const complianceFields = getEntityComplianceFields(entityName);\n if (complianceFields) {\n for (const [fieldName, level] of complianceFields) {\n if (level === 'none') continue;\n const prop = metadata.properties[fieldName];\n if (prop && prop.nullable) {\n piiFieldNames.push(fieldName);\n } else {\n this.otel.warn(\n '[RetentionService] Skipping non-nullable PII field for anonymize',\n { entityName, fieldName, level }\n );\n }\n }\n }\n }\n\n const filter: Record<string, unknown> = {\n createdAt: { $lt: cutoff }\n };\n if (policy.action === 'anonymize') {\n filter['retentionAnonymizedAt'] = null;\n }\n\n // Dry run: use count instead of fetching records\n if (dryRun) {\n const em = this.orm.em.fork();\n try {\n const count = await em.count(entityClass, filter);\n this.otel.info('[RetentionService] Dry run — would process', {\n entityName,\n action: policy.action,\n count\n });\n if (policy.action === 'delete') stats.deleted += count;\n else stats.anonymized += count;\n } catch (err) {\n stats.errors++;\n this.otel.error('[RetentionService] Dry run count failed', {\n entityName,\n error: String(err)\n });\n }\n return;\n }\n\n let batchNum = 0;\n\n while (true) {\n batchNum++;\n const em = this.orm.em.fork();\n\n try {\n const records = await em.find(entityClass, filter, {\n limit: batchSize,\n orderBy: { createdAt: 'ASC' }\n });\n\n if (records.length === 0) break;\n\n if (policy.action === 'delete') {\n records.forEach((r) => em.remove(r));\n await em.flush();\n stats.deleted += records.length;\n } else {\n for (const record of records) {\n const rec = record as Record<string, unknown>;\n for (const field of piiFieldNames) {\n rec[field] = null;\n }\n rec['retentionAnonymizedAt'] = new Date();\n }\n await em.flush();\n stats.anonymized += records.length;\n }\n\n this.otel.info('[RetentionService] Batch processed', {\n entityName,\n action: policy.action,\n batch: batchNum,\n count: records.length\n });\n } catch (err) {\n stats.errors++;\n this.otel.error('[RetentionService] Batch failed', {\n entityName,\n batch: batchNum,\n error: String(err)\n });\n break; // stop batching this entity, continue to next\n }\n }\n }\n}\n","import type { EntityManager, MetadataStorage } from '@mikro-orm/core';\nimport type { OpenTelemetryCollector } from '../http/telemetry/openTelemetryCollector';\n\n/**\n * Structural subset of `MikroORM` used by the compliance services. Typed\n * structurally (rather than as `MikroORM`) because the class's `Entities`\n * type parameter defaults to a mutable array while `MikroORM.init()` returns\n * a readonly one, making concrete instances unassignable to a bare\n * `MikroORM` parameter.\n */\nexport interface ComplianceOrm {\n em: Pick<EntityManager, 'fork'>;\n getMetadata(): MetadataStorage;\n}\nimport { MetricsDefinition } from '../http/types/openTelemetryCollector.types';\nimport {\n getEntityComplianceFields,\n getEntityUserIdField\n} from '../persistence/complianceTypes';\n\nexport interface EraseResult {\n entitiesAffected: string[];\n recordsDeleted: number;\n}\n\nexport interface ExportResult {\n userId: string;\n entities: Record<string, unknown[]>;\n}\n\n/**\n * Per-entity userIdField overrides.\n * Keys are entity names, values are the field name linking records to a user.\n *\n * @example\n * {\n * User: 'id', // the User entity IS the user record\n * Subscription: 'partyId', // billing links via partyId\n * Account: 'userId', // default, can be omitted\n * }\n */\nexport type UserIdFieldOverrides = Record<string, string>;\n\n/**\n * Common field names that link an entity to a user, tried in order.\n * Used for optimistic search when no explicit userIdField is configured.\n */\nconst CANDIDATE_USER_FIELDS = [\n 'userId',\n 'user',\n 'id',\n 'partyId',\n 'customerId',\n 'ownerId',\n 'createdBy',\n 'email'\n];\n\n/**\n * Generic compliance data service that walks all compliance-registered entities\n * and erases or exports PII/PHI/PCI data for a given user.\n *\n * Resolution order for userIdField per entity:\n * 1. Constructor overrides (highest priority)\n * 2. defineComplianceEntity({ userIdField }) registry\n * 3. Optimistic search: first CANDIDATE_USER_FIELDS match in entity metadata\n * 4. Skip entity (no user link found)\n */\nexport class ComplianceDataService {\n private readonly userIdFieldOverrides: UserIdFieldOverrides;\n\n constructor(\n private readonly orm: ComplianceOrm,\n private readonly otel: OpenTelemetryCollector<MetricsDefinition>,\n userIdFieldOverrides?: UserIdFieldOverrides\n ) {\n this.userIdFieldOverrides = userIdFieldOverrides ?? {};\n }\n\n /**\n * Resolve the field linking an entity to a user.\n * Returns undefined if no link can be determined.\n */\n private resolveUserIdField(\n entityName: string,\n entityProperties: Record<string, unknown>\n ): string | undefined {\n // 1. Constructor override\n const override = this.userIdFieldOverrides[entityName];\n if (override) return override;\n\n // 2. Registry (from defineComplianceEntity({ userIdField }))\n const registered = getEntityUserIdField(entityName);\n if (registered !== 'userId' || entityProperties['userId']) {\n // Registry returned a non-default value, or the default 'userId' exists\n if (entityProperties[registered]) return registered;\n }\n\n // 3. Optimistic search\n for (const candidate of CANDIDATE_USER_FIELDS) {\n if (entityProperties[candidate]) return candidate;\n }\n\n // 4. No link found\n return undefined;\n }\n\n async erase(userId: string): Promise<EraseResult> {\n const em = this.orm.em.fork();\n const entitiesAffected: string[] = [];\n let recordsDeleted = 0;\n\n const allMetadata = [...this.orm.getMetadata().getAll().values()];\n\n for (const metadata of allMetadata) {\n const entityName = metadata.className;\n const fields = getEntityComplianceFields(entityName);\n if (!fields) continue;\n\n const hasPii = [...fields.values()].some(\n (level) => level === 'pii' || level === 'phi' || level === 'pci'\n );\n if (!hasPii) continue;\n\n const userIdField = this.resolveUserIdField(\n entityName,\n metadata.properties\n );\n\n if (!userIdField) {\n this.otel.warn(\n '[ComplianceDataService] No user-linking field found — skipping',\n { entityName, candidates: CANDIDATE_USER_FIELDS }\n );\n continue;\n }\n\n try {\n const entityClass = metadata.class ?? metadata.className;\n const records = await em.find(entityClass, {\n [userIdField]: userId\n });\n\n if (records.length > 0) {\n entitiesAffected.push(entityName);\n recordsDeleted += records.length;\n records.forEach((r) => em.remove(r));\n }\n } catch (err) {\n this.otel.error('[ComplianceDataService] Failed to erase entity', {\n entityName,\n userIdField,\n error: String(err)\n });\n }\n }\n\n if (recordsDeleted > 0) {\n await em.flush();\n }\n\n this.otel.info('[ComplianceDataService] Erase complete', {\n userId,\n entitiesAffected: entitiesAffected.join(','),\n recordsDeleted\n });\n\n return { entitiesAffected, recordsDeleted };\n }\n\n async export(userId: string): Promise<ExportResult> {\n const em = this.orm.em.fork();\n const entities: Record<string, unknown[]> = {};\n\n const allMetadata = [...this.orm.getMetadata().getAll().values()];\n\n for (const metadata of allMetadata) {\n const entityName = metadata.className;\n const fields = getEntityComplianceFields(entityName);\n if (!fields) continue;\n\n const hasPii = [...fields.values()].some(\n (level) => level === 'pii' || level === 'phi' || level === 'pci'\n );\n if (!hasPii) continue;\n\n const userIdField = this.resolveUserIdField(\n entityName,\n metadata.properties\n );\n\n if (!userIdField) {\n continue;\n }\n\n try {\n const entityClass = metadata.class ?? metadata.className;\n const records = await em.find(entityClass, {\n [userIdField]: userId\n });\n\n if (records.length > 0) {\n const piiFieldNames = [...fields.entries()]\n .filter(([, level]) => level !== 'none')\n .map(([name]) => name);\n\n entities[entityName] = records.map((record) => {\n const filtered: Record<string, unknown> = {};\n filtered['id'] = (record as Record<string, unknown>)['id'];\n for (const fieldName of piiFieldNames) {\n filtered[fieldName] = (record as Record<string, unknown>)[\n fieldName\n ];\n }\n return filtered;\n });\n }\n } catch (err) {\n this.otel.error('[ComplianceDataService] Failed to export entity', {\n entityName,\n userIdField,\n error: String(err)\n });\n }\n }\n\n this.otel.info('[ComplianceDataService] Export complete', {\n userId,\n entityCount: Object.keys(entities).length\n });\n\n return { userId, entities };\n }\n}\n","import type { OpenTelemetryCollector } from '../http/telemetry/openTelemetryCollector';\nimport type { RetentionService } from './retentionService';\n\n/**\n * Shared retention enforcement runner.\n * Designed to be called from a one-shot script (ECS RunTask / cron).\n *\n * @example\n * ```ts\n * import { ci, tokens } from '../bootstrapper';\n * import { runRetentionEnforcement } from '@myapp/core';\n *\n * runRetentionEnforcement(\n * ci.resolve(tokens.RetentionService),\n * ci.resolve(tokens.OtelCollector)\n * );\n * ```\n */\nexport async function runRetentionEnforcement(\n retentionService: RetentionService,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n otel: OpenTelemetryCollector<any>\n): Promise<void> {\n const dryRun = process.argv.includes('--dry-run');\n\n otel.info('[RetentionEnforcement] Starting', { dryRun });\n\n const result = await retentionService.enforce({ dryRun });\n\n otel.info('[RetentionEnforcement] Complete', {\n processed: result.processed,\n deleted: result.deleted,\n anonymized: result.anonymized,\n errors: result.errors,\n durationMs: result.durationMs\n });\n\n if (result.errors > 0) {\n otel.warn('[RetentionEnforcement] Completed with errors', {\n errors: result.errors,\n byEntity: result.byEntity\n });\n process.exit(1);\n }\n\n process.exit(0);\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/services/index.ts","../../src/environment/loadCascadingEnv.ts","../../src/services/configInjector.ts","../../src/services/guards/isConstructed.ts","../../src/services/types/configInjector.types.ts","../../src/services/guards/isConstructedSingleton.ts","../../src/services/guards/isConstructor.ts","../../src/persistence/complianceTypes.ts","../../src/services/retentionService.ts","../../src/services/complianceDataService.ts","../../src/services/runRetentionEnforcement.ts"],"sourcesContent":["export { getEnvVar } from '@forklaunch/common';\nexport * from '../environment';\nexport { createConfigInjector } from './configInjector';\nexport type { ConfigInjector, ValidConfigInjector } from './configInjector';\nexport * from './types/configInjector.types';\nexport * from './types/entityManager.types';\nexport * from './types/service.types';\nexport {\n RetentionService,\n type EnforcementOptions,\n type EnforcementResult\n} from './retentionService';\nexport {\n ComplianceDataService,\n type EraseResult,\n type ExportResult,\n type UserIdFieldOverrides\n} from './complianceDataService';\nexport { runRetentionEnforcement } from './runRetentionEnforcement';\n","import dotenv from 'dotenv';\nimport { existsSync } from 'fs';\nimport { dirname, resolve } from 'path';\n\n/**\n * Gets cascading environment file paths: collects all .env.local files from project directory up to root\n * Root detection uses: .forklaunch/manifest.toml\n */\nexport function getCascadingEnvPaths(\n projectEnvPath: string | undefined,\n projectRoot: string = process.cwd()\n): {\n rootEnvExists: boolean;\n projectEnvExists: boolean;\n rootEnvPath?: string;\n projectEnvFilePath?: string;\n loadOrder: string[];\n} {\n const result = {\n rootEnvExists: false,\n projectEnvExists: false,\n rootEnvPath: undefined as string | undefined,\n projectEnvFilePath: undefined as string | undefined,\n loadOrder: [] as string[]\n };\n\n const applicationRoot = findApplicationRoot(projectRoot);\n\n const envLocalFiles = collectEnvLocalFiles(projectRoot, applicationRoot);\n result.loadOrder.push(...envLocalFiles);\n\n const rootEnvPath = resolve(applicationRoot, '.env.local');\n if (envLocalFiles.includes(rootEnvPath)) {\n result.rootEnvExists = true;\n result.rootEnvPath = rootEnvPath;\n }\n\n if (projectEnvPath) {\n const fullProjectEnvPath = resolve(projectRoot, projectEnvPath);\n if (existsSync(fullProjectEnvPath)) {\n result.projectEnvExists = true;\n result.projectEnvFilePath = fullProjectEnvPath;\n if (!result.loadOrder.includes(fullProjectEnvPath)) {\n result.loadOrder.push(fullProjectEnvPath);\n }\n }\n }\n\n return result;\n}\n\n/**\n * Loads environment variables with cascading precedence: all .env.local files from root to project, then project env file\n */\nexport function loadCascadingEnv(\n projectEnvPath: string | undefined,\n projectRoot: string = process.cwd()\n): {\n rootEnvLoaded: boolean;\n projectEnvLoaded: boolean;\n rootEnvPath?: string;\n projectEnvFilePath?: string;\n envFilesLoaded: string[];\n totalEnvFilesLoaded: number;\n} {\n const paths = getCascadingEnvPaths(projectEnvPath, projectRoot);\n const result = {\n rootEnvLoaded: false,\n projectEnvLoaded: false,\n rootEnvPath: paths.rootEnvPath,\n projectEnvFilePath: paths.projectEnvFilePath,\n envFilesLoaded: [] as string[],\n totalEnvFilesLoaded: 0\n };\n\n const seen = new Set<string>();\n for (const envPath of paths.loadOrder) {\n if (seen.has(envPath)) {\n continue;\n }\n seen.add(envPath);\n\n const envResult = dotenv.config({\n path: envPath,\n override: true\n });\n\n if (!envResult?.error) {\n result.envFilesLoaded.push(envPath);\n result.totalEnvFilesLoaded++;\n\n if (envPath === paths.rootEnvPath) {\n result.rootEnvLoaded = true;\n }\n if (envPath === paths.projectEnvFilePath) {\n result.projectEnvLoaded = true;\n }\n }\n }\n\n return result;\n}\n\n/**\n * Collects all .env.local files from project directory up to application root\n * Returns paths in order from root to project (for proper precedence)\n */\nfunction collectEnvLocalFiles(\n projectRoot: string,\n applicationRoot: string\n): string[] {\n const envLocalPaths: string[] = [];\n\n let currentPath = resolve(projectRoot);\n const normalizedAppRoot = resolve(applicationRoot);\n\n while (currentPath.length >= normalizedAppRoot.length) {\n const envLocalPath = resolve(currentPath, '.env.local');\n if (existsSync(envLocalPath)) {\n envLocalPaths.push(envLocalPath);\n }\n\n if (currentPath === normalizedAppRoot) {\n break;\n }\n\n const parentPath = dirname(currentPath);\n if (parentPath === currentPath) {\n break;\n }\n\n currentPath = parentPath;\n }\n\n return envLocalPaths.reverse();\n}\n\n/**\n * Finds application root by looking for .forklaunch/manifest.toml\n */\nexport function findApplicationRoot(startPath: string): string {\n let currentPath = resolve(startPath);\n const originalStart = currentPath;\n const maxDepth = 10;\n let depth = 0;\n\n while (depth < maxDepth) {\n const forklaunchManifest = resolve(\n currentPath,\n '.forklaunch',\n 'manifest.toml'\n );\n if (existsSync(forklaunchManifest)) {\n return currentPath;\n }\n\n const parentPath = dirname(currentPath);\n if (parentPath === currentPath) {\n break;\n }\n\n currentPath = parentPath;\n depth++;\n }\n\n return originalStart;\n}\n","import { extractArgumentNames, isNever } from '@forklaunch/common';\nimport {\n AnySchemaValidator,\n IdiomaticSchema,\n ParseResult,\n prettyPrintParseErrors,\n SchemaValidator\n} from '@forklaunch/validator';\nimport { isConstructed } from './guards/isConstructed';\nimport { isConstructedSingleton } from './guards/isConstructedSingleton';\nimport { isConstructor } from './guards/isConstructor';\nimport {\n ConfigValidator,\n Constructed,\n ConstructedSingleton,\n Lifetime,\n ResolvedConfigValidator,\n SchemaConstructor,\n SchemaFunction,\n Singleton\n} from './types/configInjector.types';\n\nexport function createConfigInjector<\n SV extends AnySchemaValidator,\n CV extends ConfigValidator<SV>\n>(\n schemaValidator: SV,\n dependenciesDefinition: {\n [K in keyof CV]:\n | Singleton<\n CV[K],\n Omit<ResolvedConfigValidator<SV, CV>, K>,\n ResolvedConfigValidator<SV, CV>[K]\n >\n | Constructed<\n CV[K],\n Omit<ResolvedConfigValidator<SV, CV>, K>,\n ResolvedConfigValidator<SV, CV>[K]\n >;\n }\n) {\n return new ConfigInjector<SV, CV>(\n schemaValidator,\n dependenciesDefinition\n ).load();\n}\n\nexport class ConfigInjector<\n SV extends AnySchemaValidator,\n CV extends ConfigValidator<SV>\n> {\n instances: {\n [K in keyof CV]?: ResolvedConfigValidator<SV, CV>[K];\n } = {};\n\n readonly configShapes: CV;\n\n load(inheritedScopeInstances?: {\n [K in keyof CV]?: ResolvedConfigValidator<SV, CV>[K];\n }): this {\n for (const token in inheritedScopeInstances) {\n this.instances[token] = inheritedScopeInstances[token];\n }\n\n for (const token in this.dependenciesDefinition) {\n const definition = this.dependenciesDefinition[token];\n if (\n definition.lifetime === Lifetime.Singleton &&\n !this.instances[token]\n ) {\n if (\n isConstructedSingleton<\n CV[typeof token],\n Omit<ResolvedConfigValidator<SV, CV>, typeof token>,\n ResolvedConfigValidator<SV, CV>[typeof token]\n >(definition)\n ) {\n this.instances[token] = this.resolveInstance<typeof token>(\n token,\n definition\n );\n } else {\n this.instances[token] = definition.value;\n }\n }\n }\n return this;\n }\n\n private resolveInstance<T extends keyof CV>(\n token: T,\n definition:\n | ConstructedSingleton<\n CV[T],\n Omit<ResolvedConfigValidator<SV, CV>, T>,\n ResolvedConfigValidator<SV, CV>[T]\n >\n | Constructed<\n CV[T],\n Omit<ResolvedConfigValidator<SV, CV>, T>,\n ResolvedConfigValidator<SV, CV>[T]\n >,\n context?: Record<string, unknown>,\n resolutionPath: (keyof CV)[] = []\n ): ResolvedConfigValidator<SV, CV>[T] {\n if (process.env.FORKLAUNCH_MODE === 'openapi') {\n // The handler below installs `apply` and `construct` traps, which are\n // only valid on a callable target — hence a function rather than `{}`.\n // The proxy is what makes every string key resolve; the target itself\n // has none, so this shape cannot be inferred and has to be asserted.\n // Named and asserted once, rather than laundered through `unknown`.\n type NoopTarget = ((...args: never[]) => unknown) &\n Record<string, unknown>;\n const noopProxy: Record<string, unknown> = new Proxy(\n function () {} as NoopTarget,\n {\n get(_target, prop) {\n if (prop === Symbol.toPrimitive) return () => '';\n if (prop === 'toString' || prop === 'valueOf') return () => '';\n if (prop === 'then') return undefined;\n if (prop === Symbol.iterator) return function* () {};\n if (prop === Symbol.asyncIterator) return async function* () {};\n return noopProxy;\n },\n set() {\n return true;\n },\n has() {\n return true;\n },\n deleteProperty() {\n return true;\n },\n ownKeys() {\n return ['prototype'];\n },\n getOwnPropertyDescriptor(_target, prop) {\n if (prop === 'prototype') {\n return { configurable: false, enumerable: false, writable: true };\n }\n return { configurable: true, enumerable: true };\n },\n apply() {\n return noopProxy;\n },\n construct() {\n return noopProxy as object;\n }\n }\n );\n return noopProxy as ResolvedConfigValidator<SV, CV>[T];\n }\n\n const rawInjectorArgument = extractArgumentNames(definition.factory)[0];\n // short circuit as no args\n if (!rawInjectorArgument || rawInjectorArgument === '_args') {\n return definition.factory(\n {} as Omit<ResolvedConfigValidator<SV, CV>, T>,\n context ?? {},\n this.resolve.bind(this)\n );\n }\n\n // Normalize whitespace to handle both single-line and multiline formatting\n const injectorArgument = rawInjectorArgument.replace(/\\s+/g, '');\n\n if (!injectorArgument.startsWith('{') || !injectorArgument.endsWith('}')) {\n throw new Error(\n `Invalid injector argument for ${String(\n token\n )}: ${injectorArgument}. Please use object destructuring syntax: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment.`\n );\n }\n const resolvedArguments = Object.fromEntries(\n injectorArgument\n .slice(1, -1)\n .split(',')\n .filter((arg) => arg.length > 0)\n .map((arg) => arg.split(':')[0].trim())\n .map((arg) => {\n const newResolutionPath = [...resolutionPath, token];\n if (resolutionPath.includes(arg)) {\n throw new Error(\n `Circular dependency detected: ${newResolutionPath.join(\n ' -> '\n )} -> ${arg}`\n );\n }\n const resolvedArg = this.resolve(arg, context, newResolutionPath);\n return [arg, resolvedArg];\n })\n ) as Omit<ResolvedConfigValidator<SV, CV>, T>;\n return definition.factory(\n resolvedArguments,\n context ?? {},\n this.resolve.bind(this)\n );\n }\n\n constructor(\n private schemaValidator: SV,\n private dependenciesDefinition: {\n [K in keyof CV]: (\n | Singleton<\n CV[K],\n Omit<ResolvedConfigValidator<SV, CV>, K>,\n ResolvedConfigValidator<SV, CV>[K]\n >\n | Constructed<\n CV[K],\n Omit<ResolvedConfigValidator<SV, CV>, K>,\n ResolvedConfigValidator<SV, CV>[K]\n >\n ) & {\n type: CV[K];\n };\n }\n ) {\n this.configShapes = Object.entries(this.dependenciesDefinition).reduce(\n (acc, [key, { type }]) => ({\n ...acc,\n [key]: type\n }),\n {} as Record<keyof CV, CV[keyof CV]>\n ) as CV;\n }\n\n safeValidateConfigSingletons(): ParseResult<ValidConfigInjector<SV, CV>> {\n const validNonSchemaSingletons = Object.entries(this.configShapes).reduce<\n ParseResult<ResolvedConfigValidator<SV, CV>>\n >(\n (acc, [key, value]) => {\n if (\n this.dependenciesDefinition[key].lifetime === Lifetime.Singleton &&\n !(this.schemaValidator as SchemaValidator).isSchema<\n SchemaFunction<SV> | SchemaConstructor<SV> | IdiomaticSchema<SV>\n >(value) &&\n isConstructor(value)\n ) {\n if (!(this.instances[key] instanceof value)) {\n const expected = value.name;\n const receivedValue: unknown = this.instances[key];\n const received = isConstructed(receivedValue)\n ? receivedValue.constructor.name\n : typeof receivedValue;\n\n if (acc.ok) {\n acc = {\n ok: false,\n errors: []\n };\n }\n acc.errors?.push({\n message: `Expected ${expected}, received ${received}`,\n path: [key]\n });\n } else {\n if (acc.ok) {\n acc = {\n ok: true,\n value: {\n ...acc.value,\n [key]: this.instances[key]\n }\n };\n }\n }\n return acc;\n }\n return acc;\n },\n {\n ok: true,\n value: {} as ResolvedConfigValidator<SV, CV>\n }\n );\n\n const singletons = Object.fromEntries(\n Object.entries(this.configShapes).filter(\n ([key, value]) =>\n this.dependenciesDefinition[key].lifetime === Lifetime.Singleton &&\n (this.schemaValidator as SchemaValidator).isSchema(value)\n )\n );\n const schemaSingletonParseResult = (\n this.schemaValidator as SchemaValidator\n ).parse(\n (this.schemaValidator as SchemaValidator).schemify(singletons),\n Object.fromEntries(\n Object.keys(singletons).map((key) => {\n const dependency = this.dependenciesDefinition[key];\n return [\n key,\n dependency.lifetime === Lifetime.Singleton\n ? this.instances[key]\n : undefined\n ];\n })\n )\n );\n\n const configKeys = Object.keys(this.configShapes);\n\n return validNonSchemaSingletons.ok && schemaSingletonParseResult.ok\n ? {\n ok: true as const,\n value: new ValidConfigInjector<SV, CV>(\n this.schemaValidator,\n this.dependenciesDefinition\n ).load({ ...this.instances })\n }\n : {\n ok: false as const,\n errors: [\n ...(!validNonSchemaSingletons.ok && validNonSchemaSingletons.errors\n ? validNonSchemaSingletons.errors\n : []),\n ...(!schemaSingletonParseResult.ok &&\n schemaSingletonParseResult.errors\n ? schemaSingletonParseResult.errors\n : [])\n ].sort(\n (a, b) =>\n configKeys.indexOf(a.path[0]) - configKeys.indexOf(b.path[0])\n )\n };\n }\n\n validateConfigSingletons(configName: string): ValidConfigInjector<SV, CV> {\n if (process.env.FORKLAUNCH_MODE === 'openapi') {\n return this.createScope() as ValidConfigInjector<SV, CV>;\n }\n\n const safeValidateResult = this.safeValidateConfigSingletons();\n\n if (safeValidateResult.ok) {\n return safeValidateResult.value;\n }\n\n throw new Error(\n prettyPrintParseErrors(safeValidateResult.errors, configName)\n );\n }\n\n resolve<T extends keyof CV>(\n token: T,\n context?: Record<string, unknown>,\n resolutionPath: (keyof CV)[] = []\n ): ResolvedConfigValidator<SV, CV>[T] {\n const instance = this.instances[token];\n if (!instance) {\n const definition = this.dependenciesDefinition[token];\n\n if (!definition) {\n throw new Error(`Unable to resolve dependency ${String(token)}`);\n }\n\n switch (definition.lifetime) {\n case Lifetime.Singleton: {\n if (\n isConstructedSingleton<\n CV[T],\n Omit<ResolvedConfigValidator<SV, CV>, T>,\n ResolvedConfigValidator<SV, CV>[T]\n >(definition) &&\n !this.instances[token]\n ) {\n this.instances[token] = this.resolveInstance<T>(\n token,\n definition,\n context,\n resolutionPath\n );\n }\n return this.instances[token] as ResolvedConfigValidator<SV, CV>[T];\n }\n case Lifetime.Scoped: {\n if (\n !isConstructed<\n CV[T],\n Omit<ResolvedConfigValidator<SV, CV>, T>,\n ResolvedConfigValidator<SV, CV>[T]\n >(definition)\n ) {\n throw new Error(\n `Invalid dependency definition for ${String(token)}`\n );\n }\n\n const scopedInstance = this.resolveInstance<T>(\n token,\n definition,\n context,\n resolutionPath\n );\n this.instances[token] = scopedInstance;\n return scopedInstance;\n }\n case Lifetime.Transient: {\n if (\n !isConstructed<\n CV[T],\n Omit<ResolvedConfigValidator<SV, CV>, T>,\n ResolvedConfigValidator<SV, CV>[T]\n >(definition)\n ) {\n throw new Error(\n `Invalid dependency definition for ${String(token)}`\n );\n }\n\n return this.resolveInstance<T>(\n token,\n definition,\n context,\n resolutionPath\n );\n }\n default: {\n isNever(definition);\n throw new Error(\n `Unable to resolve lifetime for dependency ${String(\n token\n )}, ${resolutionPath}`\n );\n }\n }\n } else {\n return instance;\n }\n }\n\n scopedResolver<T extends keyof CV>(\n token: T,\n context?: Record<string, unknown>,\n resolutionPath: (keyof CV)[] = []\n ): (options?: {\n scope?: ConfigInjector<SV, CV>;\n context?: Record<string, unknown>;\n }) => ResolvedConfigValidator<SV, CV>[T] {\n return (options) =>\n (options?.scope ?? this.createScope()).resolve<T>(\n token,\n options?.context ? { ...context, ...options.context } : context,\n resolutionPath\n );\n }\n\n createScope(): ConfigInjector<SV, CV> {\n const singletons: Record<string, unknown> = {};\n for (const dependency in this.dependenciesDefinition) {\n if (\n this.dependenciesDefinition[dependency].lifetime === Lifetime.Singleton\n ) {\n singletons[dependency] = this.instances[dependency];\n }\n }\n return new ConfigInjector<SV, CV>(\n this.schemaValidator,\n this.dependenciesDefinition\n ).load(singletons as ResolvedConfigValidator<SV, CV>);\n }\n\n dispose(): void {\n this.instances = {};\n this.load();\n }\n\n chain<ChainedCV extends ConfigValidator<SV>>(dependenciesDefinition: {\n [K in keyof ChainedCV]: {\n type: ChainedCV[K];\n } & (\n | Singleton<\n ChainedCV[K],\n Omit<ResolvedConfigValidator<SV, CV & ChainedCV>, K>,\n ResolvedConfigValidator<SV, ChainedCV>[K]\n >\n | Constructed<\n ChainedCV[K],\n Omit<ResolvedConfigValidator<SV, CV & ChainedCV>, K>,\n ResolvedConfigValidator<SV, ChainedCV>[K]\n >\n );\n }): ConfigInjector<SV, CV & ChainedCV> {\n return new ConfigInjector<SV, CV>(this.schemaValidator, {\n ...this.dependenciesDefinition,\n ...dependenciesDefinition\n // The hop through unknown is required, not habitual. A direct assertion\n // makes the compiler structurally compare two deeply recursive\n // ConfigInjector instantiations and it gives up with TS2589, \"type\n // instantiation is excessively deep and possibly infinite\". Going via\n // unknown stops that comparison. The widening itself is sound: the\n // dependencies of both injectors are merged immediately above.\n }).load({ ...this.instances }) as unknown as ConfigInjector<\n SV,\n CV & ChainedCV\n >;\n }\n\n tokens(): {\n [K in keyof CV]: K;\n } {\n return Object.fromEntries(\n Object.keys(this.dependenciesDefinition).map((key) => [key, key])\n ) as {\n [K in keyof CV]: K;\n };\n }\n}\n\nexport class ValidConfigInjector<\n SV extends AnySchemaValidator,\n CV extends ConfigValidator<SV>\n> extends ConfigInjector<SV, CV> {\n validConfigInjector!: void;\n}\n","import { Constructed } from '../types/configInjector.types';\n\nexport function isConstructed<Type, Args, Return>(\n value: unknown\n): value is Constructed<Type, Args, Return> {\n return (\n typeof value === 'object' &&\n value != null &&\n 'constructor' in value &&\n value.constructor != null\n );\n}\n","import {\n AnySchemaValidator,\n IdiomaticSchema,\n Schema\n} from '@forklaunch/validator';\nimport { ConfigInjector } from '../configInjector';\n\nexport const Lifetime = {\n Singleton: 0,\n Transient: 1,\n Scoped: 2\n} as const;\nexport type Lifetime = (typeof Lifetime)[keyof typeof Lifetime];\n\nexport type Singleton<Type, Args, Value> =\n | {\n lifetime: typeof Lifetime.Singleton;\n type: Type;\n value: Value;\n }\n | ConstructedSingleton<Type, Args, Value>;\n\nexport type ConstructedSingleton<Type, Args, Return> = {\n lifetime: typeof Lifetime.Singleton;\n type: Type;\n factory: (\n args: Args,\n context: Record<string, unknown>,\n resolve: <T extends keyof Args>(\n token: T,\n context?: Record<string, unknown>\n ) => Args[T]\n ) => Return;\n};\n\nexport type Constructed<Type, Args, Return> = {\n lifetime: typeof Lifetime.Transient | typeof Lifetime.Scoped;\n type: Type;\n factory: (\n args: Args,\n context: Record<string, unknown>,\n resolve: <T extends keyof Args>(\n token: T,\n context?: Record<string, unknown>\n ) => Args[T]\n ) => Return;\n};\n\nexport type Constructor = new (...args: never[]) => unknown;\nexport type SchemaConstructor<SV extends AnySchemaValidator> = new (\n ...args: unknown[]\n) => IdiomaticSchema<SV>;\nexport type Function = (...args: never[]) => unknown;\nexport type FunctionToConstructor = (\n ...args: never[]\n) => new (...args: never[]) => unknown;\nexport type SchemaFunction<SV extends AnySchemaValidator> = (\n args: unknown\n) => IdiomaticSchema<SV>;\n\nexport type ConfigTypes<SV extends AnySchemaValidator> =\n | Function\n | SchemaFunction<SV>\n | Constructor\n | SchemaConstructor<SV>\n | IdiomaticSchema<SV>;\n\nexport type ConfigValidator<SV extends AnySchemaValidator> = Record<\n string,\n ConfigTypes<SV> | Record<string, ConfigTypes<SV>>\n>;\n\ntype ResolveConfigValue<SV extends AnySchemaValidator, T> =\n T extends SchemaConstructor<SV>\n ? Schema<InstanceType<T>, SV>\n : T extends SchemaFunction<SV>\n ? (...args: Parameters<T>) => Schema<ReturnType<T>, SV>\n : T extends FunctionToConstructor\n ? (...args: Parameters<T>) => InstanceType<ReturnType<T>>\n : T extends Function\n ? (...args: Parameters<T>) => ReturnType<T>\n : T extends Constructor\n ? InstanceType<T>\n : T extends IdiomaticSchema<SV>\n ? Schema<T, SV>\n : T extends Record<string, ConfigTypes<SV>>\n ? {\n [K in keyof T]: ResolveConfigValue<SV, T[K]>;\n }\n : Schema<T, SV>;\n\nexport type ResolvedConfigValidator<\n SV extends AnySchemaValidator,\n CV extends ConfigValidator<SV>\n> = {\n [M in keyof CV]: ResolveConfigValue<SV, CV[M]>;\n};\n\nexport type ScopedDependencyFactory<\n SV extends AnySchemaValidator,\n CV extends ConfigValidator<SV>,\n M extends keyof CV\n> = (scope?: ConfigInjector<SV, CV>) => ResolvedConfigValidator<SV, CV>[M];\n","import { ConstructedSingleton, Lifetime } from '../types/configInjector.types';\n\nexport function isConstructedSingleton<Type, Args, Return>(\n value: unknown\n): value is ConstructedSingleton<Type, Args, Return> {\n return (\n typeof value === 'object' &&\n value != null &&\n 'lifetime' in value &&\n value.lifetime === Lifetime.Singleton &&\n 'factory' in value\n );\n}\n","import { Constructor } from '../types/configInjector.types';\n\nexport function isConstructor(value: unknown): value is Constructor {\n return (\n typeof value === 'function' &&\n value.constructor != null &&\n value.prototype != null\n );\n}\n","export const ComplianceLevel = {\n pii: 'pii',\n phi: 'phi',\n pci: 'pci',\n none: 'none'\n} as const;\nexport type ComplianceLevel =\n (typeof ComplianceLevel)[keyof typeof ComplianceLevel];\n\nexport const COMPLIANCE_KEY = '~compliance' as const;\n\n// ---------------------------------------------------------------------------\n// Registry\n// ---------------------------------------------------------------------------\n\nconst complianceRegistry = new Map<string, Map<string, ComplianceLevel>>();\n\nexport function registerEntityCompliance(\n entityName: string,\n fields: Map<string, ComplianceLevel>\n): void {\n complianceRegistry.set(entityName, fields);\n}\n\nexport function getComplianceMetadata(\n entityName: string,\n fieldName: string\n): ComplianceLevel {\n return complianceRegistry.get(entityName)?.get(fieldName) ?? 'none';\n}\n\nexport function getEntityComplianceFields(\n entityName: string\n): Map<string, ComplianceLevel> | undefined {\n return complianceRegistry.get(entityName);\n}\n\nexport function entityHasEncryptedFields(entityName: string): boolean {\n const fields = complianceRegistry.get(entityName);\n if (!fields) return false;\n for (const level of fields.values()) {\n if (level === 'phi' || level === 'pci') return true;\n }\n return false;\n}\n\n// ---------------------------------------------------------------------------\n// Retention types and registry\n// ---------------------------------------------------------------------------\n\nexport const RetentionAction = {\n delete: 'delete',\n anonymize: 'anonymize'\n} as const;\nexport type RetentionAction =\n (typeof RetentionAction)[keyof typeof RetentionAction];\n\nexport interface RetentionPolicy {\n duration: string;\n action: RetentionAction;\n}\n\nexport const RetentionDuration = {\n days: (n: number): string => `P${n}D`,\n months: (n: number): string => `P${n}M`,\n years: (n: number): string => `P${n}Y`\n} as const;\n\nexport interface ParsedDuration {\n years: number;\n months: number;\n days: number;\n}\n\nconst DURATION_REGEX = /^P(?:(\\d+)Y)?(?:(\\d+)M)?(?:(\\d+)D)?$/;\n\n/**\n * Parse an ISO 8601 duration string into calendar units.\n * Returns structured units to enable calendar-aware date arithmetic.\n */\nexport function parseDuration(iso: string): ParsedDuration {\n const match = DURATION_REGEX.exec(iso);\n if (!match) {\n throw new Error(\n `Invalid ISO 8601 duration: '${iso}'. Expected format: P[n]Y[n]M[n]D`\n );\n }\n const years = parseInt(match[1] || '0', 10);\n const months = parseInt(match[2] || '0', 10);\n const days = parseInt(match[3] || '0', 10);\n\n // Approximate total days for minimum validation only\n const approxDays = years * 365 + months * 30 + days;\n if (approxDays < 1) {\n throw new Error(\n `Retention duration must be >= 1 day (P1D). Got: '${iso}' (${approxDays} approx days)`\n );\n }\n\n return { years, months, days };\n}\n\n/**\n * Subtract a parsed duration from a date using calendar-aware arithmetic.\n * Handles month-end clamping and leap years correctly.\n */\nexport function subtractDuration(from: Date, duration: ParsedDuration): Date {\n const result = new Date(from);\n result.setFullYear(result.getFullYear() - duration.years);\n result.setMonth(result.getMonth() - duration.months);\n result.setDate(result.getDate() - duration.days);\n return result;\n}\n\nconst retentionRegistry = new Map<string, RetentionPolicy>();\n\n// ---------------------------------------------------------------------------\n// User ID field registry — maps entity name to the field linking records to a user\n// ---------------------------------------------------------------------------\n\nconst DEFAULT_USER_ID_FIELD = 'userId';\nconst userIdFieldRegistry = new Map<string, string>();\n\nexport function registerEntityUserIdField(\n entityName: string,\n field: string\n): void {\n userIdFieldRegistry.set(entityName, field);\n}\n\nexport function getEntityUserIdField(entityName: string): string {\n return userIdFieldRegistry.get(entityName) ?? DEFAULT_USER_ID_FIELD;\n}\n\nexport function getAllUserIdFields(): ReadonlyMap<string, string> {\n return userIdFieldRegistry;\n}\n\nexport function registerEntityRetention(\n entityName: string,\n policy: RetentionPolicy\n): void {\n retentionRegistry.set(entityName, policy);\n}\n\nexport function getEntityRetention(\n entityName: string\n): RetentionPolicy | undefined {\n return retentionRegistry.get(entityName);\n}\n\nexport function getAllRetentionPolicies(): ReadonlyMap<\n string,\n RetentionPolicy\n> {\n return retentionRegistry;\n}\n\n// ---------------------------------------------------------------------------\n// Module augmentation — adds .compliance() via PropertyOptions\n// ---------------------------------------------------------------------------\n\n/**\n * Adds `compliance` to PropertyOptions, which flows into IncludeKeys\n * for all scalar/enum/embedded builders (PropertyOptions is extended by\n * EnumOptions and EmbeddedOptions). Relation builders use ReferenceOptions\n * instead, so they don't get .compliance() — which is what we want.\n */\ndeclare module '@mikro-orm/core' {\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n interface PropertyOptions<Owner> {\n compliance?: ComplianceLevel;\n }\n\n interface UniversalPropertyOptionsBuilder<Value, Options, IncludeKeys> {\n /**\n * The level is captured as a literal type parameter rather than widened to\n * `ComplianceLevel`, so the marker records WHICH classification a property\n * carries and not merely that it has one.\n *\n * That distinction is what makes {@link EncryptedKeysOf} possible: `pii`,\n * `phi` and `pci` are encrypted at rest and `none` is not, and a `true`\n * marker cannot tell them apart. See {@link RequiresEncryptionContext} for\n * why the difference matters at a call site.\n */\n compliance<const L extends ComplianceLevel>(\n level: L\n ): Pick<\n UniversalPropertyOptionsBuilder<\n Value,\n Options & { readonly '~c': L },\n IncludeKeys\n >,\n IncludeKeys & keyof UniversalPropertyOptionsBuilder<never, never, never>\n >;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Type-level compliance introspection\n// ---------------------------------------------------------------------------\n\n/**\n * The classifications that cause a column to be encrypted at rest by\n * `EncryptedType`. `none` is deliberately excluded — it is a real, deliberate\n * classification, just not an encrypting one.\n */\nexport type EncryptedComplianceLevel = Extract<\n ComplianceLevel,\n 'pii' | 'phi' | 'pci'\n>;\n\n/**\n * The property names of `TProperties` whose classification means the column is\n * encrypted at rest.\n *\n * Reading such a column requires the same encryption context it was written\n * under, because `FieldEncryptor` derives its key per tenant. When a read\n * happens BEFORE that context is known — a lookup whose whole purpose is to\n * discover which organisation a row belongs to — hydrating these columns cannot\n * succeed, and fails with \"ciphertext is corrupted or the wrong key was used\".\n *\n * The remedy at such a call site is a partial select that omits these keys, so\n * hydration never touches them. This type is what lets that be checked rather\n * than remembered.\n */\nexport type EncryptedKeysOf<TProperties> = {\n [K in keyof TProperties]: TProperties[K] extends {\n '~options': { readonly '~c': infer L };\n }\n ? L extends EncryptedComplianceLevel\n ? K\n : never\n : never;\n}[keyof TProperties];\n\n/**\n * True when reading `TProperties` in full would decrypt something, and so\n * requires an encryption context to already be established.\n */\nexport type RequiresEncryptionContext<TProperties> = [\n EncryptedKeysOf<TProperties>\n] extends [never]\n ? false\n : true;\n\n/**\n * True when `TFields` is a selection that provably avoids every encrypted\n * column of `TProperties` — the shape that makes a context-free read safe.\n */\nexport type SelectionAvoidsEncryptedColumns<\n TProperties,\n TFields extends readonly PropertyKey[]\n> = [Extract<TFields[number], EncryptedKeysOf<TProperties>>] extends [never]\n ? true\n : false;\n","import type { MetricsDefinition } from '../http/types/openTelemetryCollector.types';\nimport type { OpenTelemetryCollector } from '../http/telemetry/openTelemetryCollector';\nimport type { ComplianceOrm } from './complianceDataService';\nimport {\n getAllRetentionPolicies,\n getEntityComplianceFields,\n parseDuration,\n subtractDuration,\n type RetentionPolicy\n} from '../persistence/complianceTypes';\n\nexport interface EnforcementOptions {\n /** Filter to specific entity names (default: all with retention policies) */\n entities?: string[];\n /** Records per batch (default: 1000) */\n batchSize?: number;\n /** Log what would happen without mutating */\n dryRun?: boolean;\n}\n\nexport interface EnforcementResult {\n processed: number;\n deleted: number;\n anonymized: number;\n errors: number;\n byEntity: Record<\n string,\n { deleted: number; anonymized: number; errors: number }\n >;\n durationMs: number;\n}\n\n// Parameterised on the metrics definition rather than typed against\n// `OpenTelemetryCollector<any>`. This service only logs — info, warn, error —\n// and never touches a metric, so it has no reason to know the definition; but\n// `any` there switched off checking on every call through this collector, and\n// the collector's generic appears in its own method parameters, so widening to\n// the base constraint would not have been sound either. The default keeps\n// existing construction sites inferring exactly as before.\nexport class RetentionService<\n AppliedMetricsDefinition extends MetricsDefinition = MetricsDefinition\n> {\n private readonly DEFAULT_BATCH_SIZE = 1000;\n\n constructor(\n private readonly orm: ComplianceOrm,\n private readonly otel: OpenTelemetryCollector<AppliedMetricsDefinition>\n ) {}\n\n async enforce(options?: EnforcementOptions): Promise<EnforcementResult> {\n const start = Date.now();\n const batchSize = options?.batchSize ?? this.DEFAULT_BATCH_SIZE;\n const dryRun = options?.dryRun ?? false;\n const policies = getAllRetentionPolicies();\n const result: EnforcementResult = {\n processed: 0,\n deleted: 0,\n anonymized: 0,\n errors: 0,\n byEntity: {},\n durationMs: 0\n };\n\n if (policies.size === 0) {\n this.otel.info('[RetentionService] No retention policies registered');\n result.durationMs = Date.now() - start;\n return result;\n }\n\n this.otel.info('[RetentionService] Starting enforcement', {\n entityCount: policies.size,\n batchSize,\n dryRun\n });\n\n for (const [entityName, policy] of policies) {\n if (options?.entities && !options.entities.includes(entityName)) continue;\n\n const entityResult = { deleted: 0, anonymized: 0, errors: 0 };\n\n try {\n await this.enforceEntity(\n entityName,\n policy,\n batchSize,\n entityResult,\n dryRun\n );\n } catch (err) {\n entityResult.errors++;\n this.otel.error('[RetentionService] Entity-level failure', {\n entityName,\n error: String(err)\n });\n }\n\n result.byEntity[entityName] = entityResult;\n result.deleted += entityResult.deleted;\n result.anonymized += entityResult.anonymized;\n result.errors += entityResult.errors;\n result.processed += entityResult.deleted + entityResult.anonymized;\n }\n\n result.durationMs = Date.now() - start;\n this.otel.info('[RetentionService] Enforcement complete', {\n processed: result.processed,\n deleted: result.deleted,\n anonymized: result.anonymized,\n errors: result.errors,\n durationMs: result.durationMs\n });\n\n return result;\n }\n\n private async enforceEntity(\n entityName: string,\n policy: RetentionPolicy,\n batchSize: number,\n stats: { deleted: number; anonymized: number; errors: number },\n dryRun: boolean\n ): Promise<void> {\n const metadata = [...this.orm.getMetadata().getAll().values()].find(\n (m) => m.className === entityName\n );\n\n if (!metadata) {\n this.otel.warn(\n '[RetentionService] Entity not in MikroORM metadata — skipping',\n { entityName }\n );\n return;\n }\n\n const duration = parseDuration(policy.duration);\n const cutoff = subtractDuration(new Date(), duration);\n const entityClass = metadata.class ?? metadata.className;\n\n // For anonymize: only null out PII/PHI/PCI fields that are nullable.\n // Non-nullable fields are skipped to avoid flush errors.\n const piiFieldNames: string[] = [];\n if (policy.action === 'anonymize') {\n const complianceFields = getEntityComplianceFields(entityName);\n if (complianceFields) {\n for (const [fieldName, level] of complianceFields) {\n if (level === 'none') continue;\n const prop = metadata.properties[fieldName];\n if (prop && prop.nullable) {\n piiFieldNames.push(fieldName);\n } else {\n this.otel.warn(\n '[RetentionService] Skipping non-nullable PII field for anonymize',\n { entityName, fieldName, level }\n );\n }\n }\n }\n }\n\n const filter: Record<string, unknown> = {\n createdAt: { $lt: cutoff }\n };\n if (policy.action === 'anonymize') {\n filter['retentionAnonymizedAt'] = null;\n }\n\n // Dry run: use count instead of fetching records\n if (dryRun) {\n const em = this.orm.em.fork();\n try {\n const count = await em.count(entityClass, filter);\n this.otel.info('[RetentionService] Dry run — would process', {\n entityName,\n action: policy.action,\n count\n });\n if (policy.action === 'delete') stats.deleted += count;\n else stats.anonymized += count;\n } catch (err) {\n stats.errors++;\n this.otel.error('[RetentionService] Dry run count failed', {\n entityName,\n error: String(err)\n });\n }\n return;\n }\n\n let batchNum = 0;\n\n while (true) {\n batchNum++;\n const em = this.orm.em.fork();\n\n try {\n const records = await em.find(entityClass, filter, {\n limit: batchSize,\n orderBy: { createdAt: 'ASC' }\n });\n\n if (records.length === 0) break;\n\n if (policy.action === 'delete') {\n records.forEach((r) => em.remove(r));\n await em.flush();\n stats.deleted += records.length;\n } else {\n for (const record of records) {\n const rec = record as Record<string, unknown>;\n for (const field of piiFieldNames) {\n rec[field] = null;\n }\n rec['retentionAnonymizedAt'] = new Date();\n }\n await em.flush();\n stats.anonymized += records.length;\n }\n\n this.otel.info('[RetentionService] Batch processed', {\n entityName,\n action: policy.action,\n batch: batchNum,\n count: records.length\n });\n } catch (err) {\n stats.errors++;\n this.otel.error('[RetentionService] Batch failed', {\n entityName,\n batch: batchNum,\n error: String(err)\n });\n break; // stop batching this entity, continue to next\n }\n }\n }\n}\n","import type { EntityManager, MetadataStorage } from '@mikro-orm/core';\nimport type { OpenTelemetryCollector } from '../http/telemetry/openTelemetryCollector';\n\n/**\n * Structural subset of `MikroORM` used by the compliance services. Typed\n * structurally (rather than as `MikroORM`) because the class's `Entities`\n * type parameter defaults to a mutable array while `MikroORM.init()` returns\n * a readonly one, making concrete instances unassignable to a bare\n * `MikroORM` parameter.\n */\nexport interface ComplianceOrm {\n em: Pick<EntityManager, 'fork'>;\n getMetadata(): MetadataStorage;\n}\nimport { MetricsDefinition } from '../http/types/openTelemetryCollector.types';\nimport {\n getEntityComplianceFields,\n getEntityUserIdField\n} from '../persistence/complianceTypes';\n\nexport interface EraseResult {\n entitiesAffected: string[];\n recordsDeleted: number;\n}\n\nexport interface ExportResult {\n userId: string;\n entities: Record<string, unknown[]>;\n}\n\n/**\n * Per-entity userIdField overrides.\n * Keys are entity names, values are the field name linking records to a user.\n *\n * @example\n * {\n * User: 'id', // the User entity IS the user record\n * Subscription: 'partyId', // billing links via partyId\n * Account: 'userId', // default, can be omitted\n * }\n */\nexport type UserIdFieldOverrides = Record<string, string>;\n\n/**\n * Common field names that link an entity to a user, tried in order.\n * Used for optimistic search when no explicit userIdField is configured.\n */\nconst CANDIDATE_USER_FIELDS = [\n 'userId',\n 'user',\n 'id',\n 'partyId',\n 'customerId',\n 'ownerId',\n 'createdBy',\n 'email'\n];\n\n/**\n * Generic compliance data service that walks all compliance-registered entities\n * and erases or exports PII/PHI/PCI data for a given user.\n *\n * Resolution order for userIdField per entity:\n * 1. Constructor overrides (highest priority)\n * 2. defineComplianceEntity({ userIdField }) registry\n * 3. Optimistic search: first CANDIDATE_USER_FIELDS match in entity metadata\n * 4. Skip entity (no user link found)\n */\nexport class ComplianceDataService {\n private readonly userIdFieldOverrides: UserIdFieldOverrides;\n\n constructor(\n private readonly orm: ComplianceOrm,\n private readonly otel: OpenTelemetryCollector<MetricsDefinition>,\n userIdFieldOverrides?: UserIdFieldOverrides\n ) {\n this.userIdFieldOverrides = userIdFieldOverrides ?? {};\n }\n\n /**\n * Resolve the field linking an entity to a user.\n * Returns undefined if no link can be determined.\n */\n private resolveUserIdField(\n entityName: string,\n entityProperties: Record<string, unknown>\n ): string | undefined {\n // 1. Constructor override\n const override = this.userIdFieldOverrides[entityName];\n if (override) return override;\n\n // 2. Registry (from defineComplianceEntity({ userIdField }))\n const registered = getEntityUserIdField(entityName);\n if (registered !== 'userId' || entityProperties['userId']) {\n // Registry returned a non-default value, or the default 'userId' exists\n if (entityProperties[registered]) return registered;\n }\n\n // 3. Optimistic search\n for (const candidate of CANDIDATE_USER_FIELDS) {\n if (entityProperties[candidate]) return candidate;\n }\n\n // 4. No link found\n return undefined;\n }\n\n async erase(userId: string): Promise<EraseResult> {\n const em = this.orm.em.fork();\n const entitiesAffected: string[] = [];\n let recordsDeleted = 0;\n\n const allMetadata = [...this.orm.getMetadata().getAll().values()];\n\n for (const metadata of allMetadata) {\n const entityName = metadata.className;\n const fields = getEntityComplianceFields(entityName);\n if (!fields) continue;\n\n const hasPii = [...fields.values()].some(\n (level) => level === 'pii' || level === 'phi' || level === 'pci'\n );\n if (!hasPii) continue;\n\n const userIdField = this.resolveUserIdField(\n entityName,\n metadata.properties\n );\n\n if (!userIdField) {\n this.otel.warn(\n '[ComplianceDataService] No user-linking field found — skipping',\n { entityName, candidates: CANDIDATE_USER_FIELDS }\n );\n continue;\n }\n\n try {\n const entityClass = metadata.class ?? metadata.className;\n const records = await em.find(entityClass, {\n [userIdField]: userId\n });\n\n if (records.length > 0) {\n entitiesAffected.push(entityName);\n recordsDeleted += records.length;\n records.forEach((r) => em.remove(r));\n }\n } catch (err) {\n this.otel.error('[ComplianceDataService] Failed to erase entity', {\n entityName,\n userIdField,\n error: String(err)\n });\n }\n }\n\n if (recordsDeleted > 0) {\n await em.flush();\n }\n\n this.otel.info('[ComplianceDataService] Erase complete', {\n userId,\n entitiesAffected: entitiesAffected.join(','),\n recordsDeleted\n });\n\n return { entitiesAffected, recordsDeleted };\n }\n\n async export(userId: string): Promise<ExportResult> {\n const em = this.orm.em.fork();\n const entities: Record<string, unknown[]> = {};\n\n const allMetadata = [...this.orm.getMetadata().getAll().values()];\n\n for (const metadata of allMetadata) {\n const entityName = metadata.className;\n const fields = getEntityComplianceFields(entityName);\n if (!fields) continue;\n\n const hasPii = [...fields.values()].some(\n (level) => level === 'pii' || level === 'phi' || level === 'pci'\n );\n if (!hasPii) continue;\n\n const userIdField = this.resolveUserIdField(\n entityName,\n metadata.properties\n );\n\n if (!userIdField) {\n continue;\n }\n\n try {\n const entityClass = metadata.class ?? metadata.className;\n const records = await em.find(entityClass, {\n [userIdField]: userId\n });\n\n if (records.length > 0) {\n const piiFieldNames = [...fields.entries()]\n .filter(([, level]) => level !== 'none')\n .map(([name]) => name);\n\n entities[entityName] = records.map((record) => {\n const filtered: Record<string, unknown> = {};\n filtered['id'] = (record as Record<string, unknown>)['id'];\n for (const fieldName of piiFieldNames) {\n filtered[fieldName] = (record as Record<string, unknown>)[\n fieldName\n ];\n }\n return filtered;\n });\n }\n } catch (err) {\n this.otel.error('[ComplianceDataService] Failed to export entity', {\n entityName,\n userIdField,\n error: String(err)\n });\n }\n }\n\n this.otel.info('[ComplianceDataService] Export complete', {\n userId,\n entityCount: Object.keys(entities).length\n });\n\n return { userId, entities };\n }\n}\n","import type { MetricsDefinition } from '../http/types/openTelemetryCollector.types';\nimport type { OpenTelemetryCollector } from '../http/telemetry/openTelemetryCollector';\nimport type { RetentionService } from './retentionService';\n\n/**\n * Shared retention enforcement runner.\n * Designed to be called from a one-shot script (ECS RunTask / cron).\n *\n * @example\n * ```ts\n * import { ci, tokens } from '../bootstrapper';\n * import { runRetentionEnforcement } from '@myapp/core';\n *\n * runRetentionEnforcement(\n * ci.resolve(tokens.RetentionService),\n * ci.resolve(tokens.OtelCollector)\n * );\n * ```\n */\nexport async function runRetentionEnforcement<\n AppliedMetricsDefinition extends MetricsDefinition = MetricsDefinition\n>(\n retentionService: RetentionService<AppliedMetricsDefinition>,\n otel: OpenTelemetryCollector<AppliedMetricsDefinition>\n): Promise<void> {\n const dryRun = process.argv.includes('--dry-run');\n\n otel.info('[RetentionEnforcement] Starting', { dryRun });\n\n const result = await retentionService.enforce({ dryRun });\n\n otel.info('[RetentionEnforcement] Complete', {\n processed: result.processed,\n deleted: result.deleted,\n anonymized: result.anonymized,\n errors: result.errors,\n durationMs: result.durationMs\n });\n\n if (result.errors > 0) {\n otel.warn('[RetentionEnforcement] Completed with errors', {\n errors: result.errors,\n byEntity: result.byEntity\n });\n process.exit(1);\n }\n\n process.exit(0);\n}\n"],"mappings":"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","names":[]}
@@ -1,3 +1,4 @@
1
+ import type { MetricsDefinition } from '../http/types/openTelemetryCollector.types';
1
2
  import type { OpenTelemetryCollector } from '../http/telemetry/openTelemetryCollector';
2
3
  import type { ComplianceOrm } from './complianceDataService';
3
4
  export interface EnforcementOptions {
@@ -20,11 +21,11 @@ export interface EnforcementResult {
20
21
  }>;
21
22
  durationMs: number;
22
23
  }
23
- export declare class RetentionService {
24
+ export declare class RetentionService<AppliedMetricsDefinition extends MetricsDefinition = MetricsDefinition> {
24
25
  private readonly orm;
25
26
  private readonly otel;
26
27
  private readonly DEFAULT_BATCH_SIZE;
27
- constructor(orm: ComplianceOrm, otel: OpenTelemetryCollector<any>);
28
+ constructor(orm: ComplianceOrm, otel: OpenTelemetryCollector<AppliedMetricsDefinition>);
28
29
  enforce(options?: EnforcementOptions): Promise<EnforcementResult>;
29
30
  private enforceEntity;
30
31
  }
@@ -1 +1 @@
1
- {"version":3,"file":"retentionService.d.ts","sourceRoot":"","sources":["../../src/services/retentionService.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,0CAA0C,CAAC;AACvF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAS7D,MAAM,WAAW,kBAAkB;IACjC,6EAA6E;IAC7E,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,wCAAwC;IACxC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,6CAA6C;IAC7C,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CACd,MAAM,EACN;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CACxD,CAAC;IACF,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,qBAAa,gBAAgB;IAIzB,OAAO,CAAC,QAAQ,CAAC,GAAG;IAEpB,OAAO,CAAC,QAAQ,CAAC,IAAI;IALvB,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAQ;IAE3C,YACmB,GAAG,EAAE,aAAa,EAElB,IAAI,EAAE,sBAAsB,CAAC,GAAG,CAAC,EAChD;IAEE,OAAO,CAAC,OAAO,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAgEtE;YAEa,aAAa;CAwH5B"}
1
+ {"version":3,"file":"retentionService.d.ts","sourceRoot":"","sources":["../../src/services/retentionService.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,4CAA4C,CAAC;AACpF,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,0CAA0C,CAAC;AACvF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAS7D,MAAM,WAAW,kBAAkB;IACjC,6EAA6E;IAC7E,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,wCAAwC;IACxC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,6CAA6C;IAC7C,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CACd,MAAM,EACN;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CACxD,CAAC;IACF,UAAU,EAAE,MAAM,CAAC;CACpB;AASD,qBAAa,gBAAgB,CAC3B,wBAAwB,SAAS,iBAAiB,GAAG,iBAAiB;IAKpE,OAAO,CAAC,QAAQ,CAAC,GAAG;IACpB,OAAO,CAAC,QAAQ,CAAC,IAAI;IAJvB,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAQ;IAE3C,YACmB,GAAG,EAAE,aAAa,EAClB,IAAI,EAAE,sBAAsB,CAAC,wBAAwB,CAAC,EACrE;IAEE,OAAO,CAAC,OAAO,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAgEtE;YAEa,aAAa;CAwH5B"}
@@ -1,3 +1,4 @@
1
+ import type { MetricsDefinition } from '../http/types/openTelemetryCollector.types';
1
2
  import type { OpenTelemetryCollector } from '../http/telemetry/openTelemetryCollector';
2
3
  import type { RetentionService } from './retentionService';
3
4
  /**
@@ -15,5 +16,5 @@ import type { RetentionService } from './retentionService';
15
16
  * );
16
17
  * ```
17
18
  */
18
- export declare function runRetentionEnforcement(retentionService: RetentionService, otel: OpenTelemetryCollector<any>): Promise<void>;
19
+ export declare function runRetentionEnforcement<AppliedMetricsDefinition extends MetricsDefinition = MetricsDefinition>(retentionService: RetentionService<AppliedMetricsDefinition>, otel: OpenTelemetryCollector<AppliedMetricsDefinition>): Promise<void>;
19
20
  //# sourceMappingURL=runRetentionEnforcement.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"runRetentionEnforcement.d.ts","sourceRoot":"","sources":["../../src/services/runRetentionEnforcement.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,0CAA0C,CAAC;AACvF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAE3D;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,uBAAuB,CAC3C,gBAAgB,EAAE,gBAAgB,EAElC,IAAI,EAAE,sBAAsB,CAAC,GAAG,CAAC,GAChC,OAAO,CAAC,IAAI,CAAC,CAwBf"}
1
+ {"version":3,"file":"runRetentionEnforcement.d.ts","sourceRoot":"","sources":["../../src/services/runRetentionEnforcement.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,4CAA4C,CAAC;AACpF,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,0CAA0C,CAAC;AACvF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAE3D;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,uBAAuB,CAC3C,wBAAwB,SAAS,iBAAiB,GAAG,iBAAiB,EAEtE,gBAAgB,EAAE,gBAAgB,CAAC,wBAAwB,CAAC,EAC5D,IAAI,EAAE,sBAAsB,CAAC,wBAAwB,CAAC,GACrD,OAAO,CAAC,IAAI,CAAC,CAwBf"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@forklaunch/core",
3
- "version": "1.5.16",
3
+ "version": "1.5.18",
4
4
  "description": "forklaunch-js core package. Contains useful building blocks.",
5
5
  "homepage": "https://github.com/forklaunch/forklaunch-js#readme",
6
6
  "bugs": {
@@ -81,8 +81,8 @@
81
81
  "dependencies": {
82
82
  "@asyncapi/parser": "^3.6.3",
83
83
  "@forklaunch/opentelemetry-instrumentation-hyper-express": "0.0.5",
84
- "@mikro-orm/core": "^7.1.14",
85
- "@mikro-orm/mongodb": "^7.1.14",
84
+ "@mikro-orm/core": "7.1.15",
85
+ "@mikro-orm/mongodb": "7.1.15",
86
86
  "@opentelemetry/api": "^1.9.1",
87
87
  "@opentelemetry/api-logs": "^0.221.0",
88
88
  "@opentelemetry/exporter-logs-otlp-http": "^0.221.0",
@@ -99,7 +99,7 @@
99
99
  "@opentelemetry/semantic-conventions": "^1.43.0",
100
100
  "cors": "^2.8.6",
101
101
  "dotenv": "^17.4.2",
102
- "fastmcp": "^4.16.10",
102
+ "fastmcp": "^4.17.1",
103
103
  "jose": "6.2.10",
104
104
  "openapi3-ts": "^4.6.1",
105
105
  "pino": "^10.3.1",
@@ -107,20 +107,19 @@
107
107
  "pino-pretty": "^13.1.3",
108
108
  "redis": "^6.2.1",
109
109
  "uuid": "^14.0.2",
110
- "zod": "^4.4.3",
111
- "@forklaunch/validator": "^1.2.25",
112
- "@forklaunch/common": "^1.2.24"
110
+ "zod": "^4.5.4",
111
+ "@forklaunch/common": "^1.2.25",
112
+ "@forklaunch/validator": "^1.2.26"
113
113
  },
114
114
  "devDependencies": {
115
115
  "@eslint/js": "^10.0.1",
116
- "@scalar/express-api-reference": "^0.10.16",
116
+ "@scalar/express-api-reference": "^0.10.17",
117
117
  "@types/cors": "^2.8.19",
118
118
  "@types/jest": "^30.0.0",
119
119
  "@types/qs": "^6.15.1",
120
120
  "@types/uuid": "^11.0.0",
121
- "@typescript/native-preview": "7.0.0-dev.20260707.2",
122
121
  "globals": "^17.11.0",
123
- "jest": "^30.4.2",
122
+ "jest": "^30.5.0",
124
123
  "jose": "6.1.3",
125
124
  "prettier": "^3.9.6",
126
125
  "testcontainers": "^12.1.0",
@@ -128,11 +127,11 @@
128
127
  "ts-node": "^10.9.2",
129
128
  "tsup": "^8.5.1",
130
129
  "typedoc": "^0.28.20",
131
- "typescript": "npm:@typescript/typescript6@^6.0.2",
130
+ "typescript": "^7.0.2",
132
131
  "typescript-eslint": "^8.68.0"
133
132
  },
134
133
  "scripts": {
135
- "build": "tsgo --noEmit && tsup ./src/cache/index.ts ./src/controllers/index.ts ./src/mappers/index.ts ./src/objectstore/index.ts ./src/persistence/index.ts ./src/http/index.ts ./src/services/index.ts ./src/environment/index.ts ./src/ws/index.ts --format cjs,esm --no-splitting --tsconfig tsconfig.json --out-dir lib --clean --sourcemap && tsgo -p tsconfig.build.json --emitDeclarationOnly",
134
+ "build": "tsc --noEmit && tsup ./src/cache/index.ts ./src/controllers/index.ts ./src/mappers/index.ts ./src/objectstore/index.ts ./src/persistence/index.ts ./src/http/index.ts ./src/services/index.ts ./src/environment/index.ts ./src/ws/index.ts --format cjs,esm --no-splitting --tsconfig tsconfig.json --out-dir lib --clean --sourcemap && tsc -p tsconfig.build.json --emitDeclarationOnly",
136
135
  "clean": "rm -rf lib pnpm.lock.yaml node_modules",
137
136
  "docs": "typedoc --out docs *",
138
137
  "format": "prettier --ignore-path=.prettierignore --config .prettierrc '**/*.{ts,tsx,json}' --write",