@tailor-platform/sdk 1.17.1 → 1.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/CHANGELOG.md +37 -0
  2. package/dist/{application-BMDE8KqK.mjs → application-A6PZjujv.mjs} +192 -1673
  3. package/dist/application-A6PZjujv.mjs.map +1 -0
  4. package/dist/application-nPS5veK6.mjs +9 -0
  5. package/dist/brand-BZJCv6UY.mjs +28 -0
  6. package/dist/brand-BZJCv6UY.mjs.map +1 -0
  7. package/dist/cli/index.mjs +40 -20
  8. package/dist/cli/index.mjs.map +1 -1
  9. package/dist/cli/lib.d.mts +16 -33
  10. package/dist/cli/lib.mjs +12 -5
  11. package/dist/cli/lib.mjs.map +1 -1
  12. package/dist/configure/index.d.mts +4 -4
  13. package/dist/configure/index.mjs +10 -19
  14. package/dist/configure/index.mjs.map +1 -1
  15. package/dist/enum-constants-CGVvu3dd.mjs +115 -0
  16. package/dist/enum-constants-CGVvu3dd.mjs.map +1 -0
  17. package/dist/file-utils-GX_tGWl4.mjs +139 -0
  18. package/dist/file-utils-GX_tGWl4.mjs.map +1 -0
  19. package/dist/index-B6pvy1MK.d.mts +20 -0
  20. package/dist/index-B91ZpOcd.d.mts +18 -0
  21. package/dist/index-CPzbMghQ.d.mts +18 -0
  22. package/dist/{index-CVcYqZSf.d.mts → index-ClLZCbcm.d.mts} +18 -5
  23. package/dist/index-DDqKNFh4.d.mts +18 -0
  24. package/dist/interceptor-D8MeZOxX.mjs +33 -0
  25. package/dist/interceptor-D8MeZOxX.mjs.map +1 -0
  26. package/dist/{jiti-BrELlEYT.mjs → jiti-DfS9jItj.mjs} +2 -2
  27. package/dist/{jiti-BrELlEYT.mjs.map → jiti-DfS9jItj.mjs.map} +1 -1
  28. package/dist/{job-CULA2Pvf.mjs → job-2Q82qQ6N.mjs} +27 -5
  29. package/dist/job-2Q82qQ6N.mjs.map +1 -0
  30. package/dist/kysely-type-Cpq5TNGY.mjs +260 -0
  31. package/dist/kysely-type-Cpq5TNGY.mjs.map +1 -0
  32. package/dist/package-json-DUY2kB6z.mjs +17 -0
  33. package/dist/package-json-DUY2kB6z.mjs.map +1 -0
  34. package/dist/package-json-Dd1AnA5F.mjs +3 -0
  35. package/dist/plugin/builtin/enum-constants/index.d.mts +4 -0
  36. package/dist/plugin/builtin/enum-constants/index.mjs +3 -0
  37. package/dist/plugin/builtin/file-utils/index.d.mts +4 -0
  38. package/dist/plugin/builtin/file-utils/index.mjs +3 -0
  39. package/dist/plugin/builtin/kysely-type/index.d.mts +4 -0
  40. package/dist/plugin/builtin/kysely-type/index.mjs +3 -0
  41. package/dist/plugin/builtin/seed/index.d.mts +4 -0
  42. package/dist/plugin/builtin/seed/index.mjs +3 -0
  43. package/dist/plugin/index.d.mts +3 -3
  44. package/dist/plugin/index.mjs +11 -11
  45. package/dist/plugin/index.mjs.map +1 -1
  46. package/dist/{schema-R5TxC5Pn.mjs → schema-D5Cpd8fQ.mjs} +48 -5
  47. package/dist/schema-D5Cpd8fQ.mjs.map +1 -0
  48. package/dist/seed-CeUEANfQ.mjs +1050 -0
  49. package/dist/seed-CeUEANfQ.mjs.map +1 -0
  50. package/dist/{src-DMROgdcL.mjs → src-Bb1UVstT.mjs} +2 -2
  51. package/dist/{src-DMROgdcL.mjs.map → src-Bb1UVstT.mjs.map} +1 -1
  52. package/dist/telemetry-9A1BZqbl.mjs +3 -0
  53. package/dist/telemetry-rFq0QdvJ.mjs +84 -0
  54. package/dist/telemetry-rFq0QdvJ.mjs.map +1 -0
  55. package/dist/types-CJF3Y1x8.d.mts +158 -0
  56. package/dist/{types-CZZBCaxB.d.mts → types-CblXasFV.d.mts} +1405 -1045
  57. package/dist/{types-b-ig8nW_.mjs → types-ClK_HJ0G.mjs} +1 -1
  58. package/dist/{types-b-ig8nW_.mjs.map → types-ClK_HJ0G.mjs.map} +1 -1
  59. package/dist/{update-CUBVjZbL.mjs → update-Cr5c7h1r.mjs} +485 -244
  60. package/dist/update-Cr5c7h1r.mjs.map +1 -0
  61. package/dist/utils/test/index.d.mts +4 -4
  62. package/dist/utils/test/index.mjs +3 -2
  63. package/dist/utils/test/index.mjs.map +1 -1
  64. package/docs/cli/application.md +106 -14
  65. package/docs/cli/auth.md +92 -12
  66. package/docs/cli/completion.md +18 -2
  67. package/docs/cli/executor.md +122 -14
  68. package/docs/cli/function.md +32 -4
  69. package/docs/cli/secret.md +134 -18
  70. package/docs/cli/staticwebsite.md +60 -8
  71. package/docs/cli/tailordb.md +148 -20
  72. package/docs/cli/user.md +154 -22
  73. package/docs/cli/workflow.md +100 -12
  74. package/docs/cli/workspace.md +274 -38
  75. package/docs/generator/custom.md +2 -2
  76. package/docs/plugin/custom.md +270 -163
  77. package/docs/plugin/index.md +48 -2
  78. package/package.json +28 -2
  79. package/dist/application-BMDE8KqK.mjs.map +0 -1
  80. package/dist/application-Dni_W16P.mjs +0 -4
  81. package/dist/job-CULA2Pvf.mjs.map +0 -1
  82. package/dist/schema-R5TxC5Pn.mjs.map +0 -1
  83. package/dist/types-DthzUFfx.d.mts +0 -372
  84. package/dist/update-CUBVjZbL.mjs.map +0 -1
  85. /package/dist/{chunk-GMkBE123.mjs → chunk-CqAI0b6X.mjs} +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["fs","namespace","cacheKey"],"sources":["../../src/plugin/with-context.ts","../../src/plugin/get-generated-type.ts"],"sourcesContent":["/**\n * Plugin executor context support for defining plugin executors in separate files.\n * This module provides utilities for creating type-safe plugin executors that receive\n * context (like type references and namespace) at runtime.\n */\n\nimport type { TailorActor, TailorEnv } from \"@/parser/types\";\n\n/**\n * Plugin executor factory function type.\n * Takes context and returns an executor configuration.\n * Returns unknown since the exact return type depends on createExecutor's generic params.\n */\nexport type PluginExecutorFactory<Ctx> = (ctx: Ctx) => unknown;\n\n// ============================================================================\n// Plugin Executor Args Types\n// ============================================================================\n\n/**\n * Base args for plugin executor function operations.\n * Provides typed access to runtime context without requiring specific record types.\n */\nexport interface PluginFunctionArgs {\n /** Workspace ID where the executor runs */\n workspaceId: string;\n /** Application namespace */\n appNamespace: string;\n /** Environment variables */\n env: TailorEnv;\n /** Actor (user) who triggered the event, null for system events */\n actor: TailorActor | null;\n /** Name of the TailorDB type */\n typeName: string;\n /** TailorDB connections by namespace */\n tailordb: Record<string, unknown>;\n}\n\n/**\n * Args for plugin executors triggered on record creation.\n */\nexport interface PluginRecordCreatedArgs extends PluginFunctionArgs {\n /** The newly created record */\n newRecord: Record<string, unknown>;\n}\n\n/**\n * Args for plugin executors triggered on record update.\n */\nexport interface PluginRecordUpdatedArgs extends PluginFunctionArgs {\n /** The record after update */\n newRecord: Record<string, unknown>;\n /** The record before update */\n oldRecord: Record<string, unknown>;\n}\n\n/**\n * Args for plugin executors triggered on record deletion.\n */\nexport interface PluginRecordDeletedArgs extends PluginFunctionArgs {\n /** The deleted record */\n oldRecord: Record<string, unknown>;\n}\n\n/**\n * Database schema type for plugins.\n * Since plugins work with dynamic types, the schema uses Record types.\n */\nexport type PluginDBSchema = Record<string, Record<string, unknown>>;\n\n/**\n * Base record type for TailorDB records.\n * All records have an id field.\n */\nexport type PluginRecord = { id: string } & Record<string, unknown>;\n\n/**\n * Define a plugin executor that receives context at runtime.\n * This allows executor definitions to be in separate files while\n * still receiving dynamic values like typeName, generated types, and namespace.\n * @param factory - Function that takes context and returns executor configuration\n * @returns The same factory function (for type inference)\n * @example\n * ```typescript\n * // executors/on-create.ts\n * import { withPluginContext } from \"@tailor-platform/sdk/plugin\";\n * import { createExecutor, recordCreatedTrigger } from \"@tailor-platform/sdk\";\n * import { getDB } from \"@tailor-platform/function-kysely-tailordb\";\n *\n * interface MyContext {\n * sourceType: TailorAnyDBType;\n * historyType: TailorAnyDBType;\n * namespace: string;\n * }\n *\n * export default withPluginContext<MyContext>((ctx) =>\n * createExecutor({\n * name: `${ctx.sourceType.name.toLowerCase()}-on-create`,\n * trigger: recordCreatedTrigger({ type: ctx.sourceType }),\n * operation: {\n * kind: \"function\",\n * body: async (args) => {\n * const db = getDB(ctx.namespace);\n * await db.insertInto(ctx.historyType.name).values({\n * recordId: args.newRecord.id,\n * // ...\n * }).execute();\n * },\n * },\n * })\n * );\n * ```\n */\nexport function withPluginContext<Ctx>(\n factory: PluginExecutorFactory<Ctx>,\n): PluginExecutorFactory<Ctx> {\n return factory;\n}\n","import * as fs from \"node:fs\";\nimport { pathToFileURL } from \"node:url\";\nimport * as path from \"pathe\";\nimport type { Plugin, PluginOutput, TypePluginOutput } from \"@/parser/plugin-config/types\";\nimport type { TailorAnyDBType } from \"@/parser/service/tailordb/types\";\n\n// ========================================\n// Config loading and caching\n// ========================================\n\ninterface PluginEntry {\n plugin: Plugin;\n pluginConfig: unknown;\n}\n\ninterface ConfigCache {\n config: { db?: Record<string, unknown> };\n plugins: Map<string, PluginEntry>;\n configDir: string;\n}\n\n/** Cache: resolved config path -> loaded config data */\nconst configCacheMap = new Map<string, ConfigCache>();\n\n/**\n * Check if a value is a Plugin instance.\n * @param value - Value to check\n * @returns True if value has the shape of Plugin\n */\nfunction isPlugin(value: unknown): value is Plugin {\n return (\n typeof value === \"object\" &&\n value !== null &&\n typeof (value as Record<string, unknown>).id === \"string\" &&\n typeof (value as Record<string, unknown>).importPath === \"string\"\n );\n}\n\n/**\n * Load and cache config module from the given path.\n * Extracts plugins from all array exports using definePlugins() format.\n * Returns null if the config file does not exist (e.g., in bundled executor on platform server).\n * @param configPath - Absolute or relative path to tailor.config.ts\n * @returns Cached config data with plugins map, or null if config file is not available\n */\nasync function loadAndCacheConfig(configPath: string): Promise<ConfigCache | null> {\n const resolvedPath = path.resolve(configPath);\n\n const cached = configCacheMap.get(resolvedPath);\n if (cached) return cached;\n\n // Config file may not exist in bundled environments (e.g., platform server)\n if (!fs.existsSync(resolvedPath)) {\n return null;\n }\n\n const configModule = await import(pathToFileURL(resolvedPath).href);\n if (!configModule?.default) {\n throw new Error(`Invalid config module at \"${resolvedPath}\": default export not found`);\n }\n\n const config = configModule.default as { db?: Record<string, unknown> };\n const configDir = path.dirname(resolvedPath);\n const plugins = new Map<string, PluginEntry>();\n\n // Find plugin arrays from exports (definePlugins returns PluginConfig[])\n for (const value of Object.values(configModule)) {\n if (!Array.isArray(value)) continue;\n\n for (const item of value) {\n if (isPlugin(item)) {\n plugins.set(item.id, { plugin: item, pluginConfig: item.pluginConfig });\n }\n }\n }\n\n const result: ConfigCache = { config, plugins, configDir };\n configCacheMap.set(resolvedPath, result);\n return result;\n}\n\n// ========================================\n// Namespace resolution\n// ========================================\n\ninterface DbNamespaceConfig {\n files?: string[];\n external?: boolean;\n}\n\n/**\n * Resolve the namespace for a type-attached sourceType by checking config.db file patterns.\n * Uses ESM module cache identity: same file path yields same object references.\n * @param config - App config with db namespace definitions\n * @param config.db - DB namespace definitions\n * @param configDir - Directory containing the config file\n * @param sourceType - The TailorDB type to look up\n * @returns The namespace name\n */\nasync function resolveNamespaceForType(\n config: { db?: Record<string, unknown> },\n configDir: string,\n sourceType: TailorAnyDBType,\n): Promise<string> {\n if (!config.db) {\n throw new Error(`No db configuration found in config`);\n }\n\n for (const [namespace, nsConfig] of Object.entries(config.db)) {\n const dbConfig = nsConfig as DbNamespaceConfig;\n // Skip external namespaces (no files to resolve)\n if (dbConfig.external || !dbConfig.files) continue;\n\n for (const pattern of dbConfig.files) {\n const absolutePattern = path.resolve(configDir, pattern);\n let matchedFiles: string[];\n try {\n matchedFiles = fs.globSync(absolutePattern);\n } catch {\n continue;\n }\n\n for (const file of matchedFiles) {\n const mod = await import(pathToFileURL(file).href);\n for (const exported of Object.values(mod)) {\n if (exported === sourceType) {\n return namespace;\n }\n }\n }\n }\n }\n\n throw new Error(\n `Could not resolve namespace for type \"${sourceType.name}\". ` +\n `Ensure the type file is included in a db namespace's files pattern.`,\n );\n}\n\n/**\n * Resolve the namespace for a namespace plugin by trying each namespace.\n * Calls processNamespace() for each and returns the first whose output contains the requested kind.\n * @param config - App config with db namespace definitions\n * @param config.db - DB namespace definitions\n * @param plugin - Plugin instance\n * @param kind - The generated type kind to look for\n * @param pluginConfig - Plugin-level configuration\n * @returns The namespace name\n */\nasync function resolveNamespaceForNamespacePlugin(\n config: { db?: Record<string, unknown> },\n plugin: Plugin,\n kind: string,\n pluginConfig: unknown,\n): Promise<{ namespace: string; output: PluginOutput }> {\n if (!config.db) {\n throw new Error(`No db configuration found in config`);\n }\n\n if (!plugin.processNamespace) {\n throw new Error(`Plugin \"${plugin.id}\" does not have a processNamespace() method`);\n }\n\n for (const namespace of Object.keys(config.db)) {\n const dbConfig = config.db[namespace] as DbNamespaceConfig;\n if (dbConfig.external) continue;\n\n const output = await plugin.processNamespace({\n pluginConfig,\n namespace,\n });\n\n if (output.types?.[kind]) {\n return { namespace, output };\n }\n }\n\n throw new Error(\n `Could not resolve namespace for plugin \"${plugin.id}\" with kind \"${kind}\". ` +\n `No namespace produced a type with that kind.`,\n );\n}\n\n// ========================================\n// Process caching\n// ========================================\n\n// Cache: plugin -> cacheKey -> TypePluginOutput\nconst processCache = new WeakMap<Plugin, Map<string, TypePluginOutput>>();\n\n// Cache for namespace plugins: plugin -> cacheKey -> PluginOutput\nconst namespaceProcessCache = new WeakMap<Plugin, Map<string, PluginOutput>>();\n\n/**\n * Generate a cache key that includes pluginConfig.\n * @param baseKey - Base key for the cache\n * @param pluginConfig - Plugin configuration to include in the key\n * @returns Cache key string\n */\nfunction getCacheKey(baseKey: string, pluginConfig: unknown): string {\n if (pluginConfig === undefined) {\n return baseKey;\n }\n try {\n return `${baseKey}:${JSON.stringify(pluginConfig)}`;\n } catch {\n throw new Error(\n `pluginConfig must be JSON-serializable for caching. Received non-serializable value.`,\n );\n }\n}\n\n// ========================================\n// Main API\n// ========================================\n\n/**\n * Get a generated type from a plugin by loading the config and resolving everything automatically.\n * For type-attached plugins, calls processType() with the sourceType.\n * For namespace plugins, calls processNamespace() with auto-resolved namespace.\n * Results are cached per config path, plugin, namespace, and pluginConfig to avoid redundant processing.\n * @param configPath - Path to tailor.config.ts (absolute or relative to cwd)\n * @param pluginId - The plugin's unique identifier\n * @param sourceType - The source TailorDB type (null for namespace plugins)\n * @param kind - The generated type kind (e.g., \"request\", \"step\")\n * @returns The generated TailorDB type\n */\nexport async function getGeneratedType(\n configPath: string,\n pluginId: string,\n sourceType: TailorAnyDBType | null,\n kind: string,\n): Promise<TailorAnyDBType> {\n const cache = await loadAndCacheConfig(configPath);\n\n if (!cache) {\n // Config not available (e.g., running in bundled executor on platform server).\n // Return a placeholder. The actual type is resolved at generate/apply time.\n return { name: `__placeholder_${kind}__`, fields: {} } as TailorAnyDBType;\n }\n\n const { config, configDir, plugins } = cache;\n\n const pluginEntry = plugins.get(pluginId);\n if (!pluginEntry) {\n throw new Error(\n `Plugin \"${pluginId}\" not found in config at \"${configPath}\". ` +\n `Ensure the plugin is registered via definePlugins().`,\n );\n }\n\n const { plugin, pluginConfig } = pluginEntry;\n\n if (sourceType === null) {\n return getGeneratedTypeForNamespacePlugin(config, plugin, kind, pluginConfig);\n }\n\n const namespace = await resolveNamespaceForType(config, configDir, sourceType);\n return getGeneratedTypeForTypeAttachedPlugin(plugin, sourceType, kind, pluginConfig, namespace);\n}\n\n/**\n * Get a generated type from a type-attached plugin.\n * @param plugin - The plugin instance (must have processType() method)\n * @param sourceType - The source TailorDB type\n * @param kind - The generated type kind\n * @param pluginConfig - Plugin-level configuration\n * @param namespace - Resolved namespace\n * @returns The generated TailorDB type\n */\nasync function getGeneratedTypeForTypeAttachedPlugin(\n plugin: Plugin,\n sourceType: TailorAnyDBType,\n kind: string,\n pluginConfig: unknown,\n namespace: string,\n): Promise<TailorAnyDBType> {\n if (!plugin.processType) {\n throw new Error(`Plugin \"${plugin.id}\" does not have a processType() method`);\n }\n\n // Check cache first\n let pluginCache = processCache.get(plugin);\n if (!pluginCache) {\n pluginCache = new Map();\n processCache.set(plugin, pluginCache);\n }\n\n const cacheKey = getCacheKey(`${sourceType.name}:ns=${namespace}`, pluginConfig);\n let output = pluginCache.get(cacheKey);\n\n if (!output) {\n const typeConfig = sourceType.plugins?.find((p) => p.pluginId === plugin.id)?.config;\n output = await plugin.processType({\n type: sourceType,\n typeConfig: typeConfig ?? {},\n pluginConfig,\n namespace,\n });\n pluginCache.set(cacheKey, output);\n }\n\n const generatedType = output.types?.[kind];\n if (!generatedType) {\n throw new Error(\n `Generated type not found: plugin=${plugin.id}, sourceType=${sourceType.name}, kind=${kind}`,\n );\n }\n\n return generatedType as TailorAnyDBType;\n}\n\n/**\n * Get a generated type from a namespace plugin.\n * Auto-resolves the namespace by trying each one.\n * @param config - App config with db namespace definitions\n * @param config.db - DB namespace definitions\n * @param plugin - The plugin instance (must have processNamespace() method)\n * @param kind - The generated type kind\n * @param pluginConfig - Plugin-level configuration\n * @returns The generated TailorDB type\n */\nasync function getGeneratedTypeForNamespacePlugin(\n config: { db?: Record<string, unknown> },\n plugin: Plugin,\n kind: string,\n pluginConfig: unknown,\n): Promise<TailorAnyDBType> {\n if (!plugin.processNamespace) {\n throw new Error(`Plugin \"${plugin.id}\" does not have a processNamespace() method`);\n }\n\n // Check cache first - try all namespaces\n let pluginCache = namespaceProcessCache.get(plugin);\n if (!pluginCache) {\n pluginCache = new Map();\n namespaceProcessCache.set(plugin, pluginCache);\n }\n\n // Try cached results first\n if (config.db) {\n for (const namespace of Object.keys(config.db)) {\n const dbConfig = config.db[namespace] as DbNamespaceConfig;\n if (dbConfig.external) continue;\n\n const cacheKey = getCacheKey(`namespace:ns=${namespace}`, pluginConfig);\n const cached = pluginCache.get(cacheKey);\n if (cached?.types?.[kind]) {\n return cached.types[kind] as TailorAnyDBType;\n }\n }\n }\n\n // Not in cache - resolve namespace and process\n const { namespace, output } = await resolveNamespaceForNamespacePlugin(\n config,\n plugin,\n kind,\n pluginConfig,\n );\n\n const cacheKey = getCacheKey(`namespace:ns=${namespace}`, pluginConfig);\n pluginCache.set(cacheKey, output);\n\n const generatedType = output.types?.[kind];\n if (!generatedType) {\n throw new Error(`Generated type not found: plugin=${plugin.id}, kind=${kind}`);\n }\n\n return generatedType as TailorAnyDBType;\n}\n\n/**\n * Clear all internal caches. For testing only.\n * @lintignore\n */\nexport function _clearCacheForTesting(): void {\n configCacheMap.clear();\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiHA,SAAgB,kBACd,SAC4B;AAC5B,QAAO;;;;;;AC9FT,MAAM,iCAAiB,IAAI,KAA0B;;;;;;AAOrD,SAAS,SAAS,OAAiC;AACjD,QACE,OAAO,UAAU,YACjB,UAAU,QACV,OAAQ,MAAkC,OAAO,YACjD,OAAQ,MAAkC,eAAe;;;;;;;;;AAW7D,eAAe,mBAAmB,YAAiD;CACjF,MAAM,eAAe,KAAK,QAAQ,WAAW;CAE7C,MAAM,SAAS,eAAe,IAAI,aAAa;AAC/C,KAAI,OAAQ,QAAO;AAGnB,KAAI,CAACA,KAAG,WAAW,aAAa,CAC9B,QAAO;CAGT,MAAM,eAAe,MAAM,OAAO,cAAc,aAAa,CAAC;AAC9D,KAAI,CAAC,cAAc,QACjB,OAAM,IAAI,MAAM,6BAA6B,aAAa,6BAA6B;CAGzF,MAAM,SAAS,aAAa;CAC5B,MAAM,YAAY,KAAK,QAAQ,aAAa;CAC5C,MAAM,0BAAU,IAAI,KAA0B;AAG9C,MAAK,MAAM,SAAS,OAAO,OAAO,aAAa,EAAE;AAC/C,MAAI,CAAC,MAAM,QAAQ,MAAM,CAAE;AAE3B,OAAK,MAAM,QAAQ,MACjB,KAAI,SAAS,KAAK,CAChB,SAAQ,IAAI,KAAK,IAAI;GAAE,QAAQ;GAAM,cAAc,KAAK;GAAc,CAAC;;CAK7E,MAAM,SAAsB;EAAE;EAAQ;EAAS;EAAW;AAC1D,gBAAe,IAAI,cAAc,OAAO;AACxC,QAAO;;;;;;;;;;;AAqBT,eAAe,wBACb,QACA,WACA,YACiB;AACjB,KAAI,CAAC,OAAO,GACV,OAAM,IAAI,MAAM,sCAAsC;AAGxD,MAAK,MAAM,CAAC,WAAW,aAAa,OAAO,QAAQ,OAAO,GAAG,EAAE;EAC7D,MAAM,WAAW;AAEjB,MAAI,SAAS,YAAY,CAAC,SAAS,MAAO;AAE1C,OAAK,MAAM,WAAW,SAAS,OAAO;GACpC,MAAM,kBAAkB,KAAK,QAAQ,WAAW,QAAQ;GACxD,IAAI;AACJ,OAAI;AACF,mBAAeA,KAAG,SAAS,gBAAgB;WACrC;AACN;;AAGF,QAAK,MAAM,QAAQ,cAAc;IAC/B,MAAM,MAAM,MAAM,OAAO,cAAc,KAAK,CAAC;AAC7C,SAAK,MAAM,YAAY,OAAO,OAAO,IAAI,CACvC,KAAI,aAAa,WACf,QAAO;;;;AAOjB,OAAM,IAAI,MACR,yCAAyC,WAAW,KAAK,wEAE1D;;;;;;;;;;;;AAaH,eAAe,mCACb,QACA,QACA,MACA,cACsD;AACtD,KAAI,CAAC,OAAO,GACV,OAAM,IAAI,MAAM,sCAAsC;AAGxD,KAAI,CAAC,OAAO,iBACV,OAAM,IAAI,MAAM,WAAW,OAAO,GAAG,6CAA6C;AAGpF,MAAK,MAAM,aAAa,OAAO,KAAK,OAAO,GAAG,EAAE;AAE9C,MADiB,OAAO,GAAG,WACd,SAAU;EAEvB,MAAM,SAAS,MAAM,OAAO,iBAAiB;GAC3C;GACA;GACD,CAAC;AAEF,MAAI,OAAO,QAAQ,MACjB,QAAO;GAAE;GAAW;GAAQ;;AAIhC,OAAM,IAAI,MACR,2CAA2C,OAAO,GAAG,eAAe,KAAK,iDAE1E;;AAQH,MAAM,+BAAe,IAAI,SAAgD;AAGzE,MAAM,wCAAwB,IAAI,SAA4C;;;;;;;AAQ9E,SAAS,YAAY,SAAiB,cAA+B;AACnE,KAAI,iBAAiB,OACnB,QAAO;AAET,KAAI;AACF,SAAO,GAAG,QAAQ,GAAG,KAAK,UAAU,aAAa;SAC3C;AACN,QAAM,IAAI,MACR,uFACD;;;;;;;;;;;;;;AAmBL,eAAsB,iBACpB,YACA,UACA,YACA,MAC0B;CAC1B,MAAM,QAAQ,MAAM,mBAAmB,WAAW;AAElD,KAAI,CAAC,MAGH,QAAO;EAAE,MAAM,iBAAiB,KAAK;EAAK,QAAQ,EAAE;EAAE;CAGxD,MAAM,EAAE,QAAQ,WAAW,YAAY;CAEvC,MAAM,cAAc,QAAQ,IAAI,SAAS;AACzC,KAAI,CAAC,YACH,OAAM,IAAI,MACR,WAAW,SAAS,4BAA4B,WAAW,yDAE5D;CAGH,MAAM,EAAE,QAAQ,iBAAiB;AAEjC,KAAI,eAAe,KACjB,QAAO,mCAAmC,QAAQ,QAAQ,MAAM,aAAa;AAI/E,QAAO,sCAAsC,QAAQ,YAAY,MAAM,cADrD,MAAM,wBAAwB,QAAQ,WAAW,WAAW,CACiB;;;;;;;;;;;AAYjG,eAAe,sCACb,QACA,YACA,MACA,cACA,WAC0B;AAC1B,KAAI,CAAC,OAAO,YACV,OAAM,IAAI,MAAM,WAAW,OAAO,GAAG,wCAAwC;CAI/E,IAAI,cAAc,aAAa,IAAI,OAAO;AAC1C,KAAI,CAAC,aAAa;AAChB,gCAAc,IAAI,KAAK;AACvB,eAAa,IAAI,QAAQ,YAAY;;CAGvC,MAAM,WAAW,YAAY,GAAG,WAAW,KAAK,MAAM,aAAa,aAAa;CAChF,IAAI,SAAS,YAAY,IAAI,SAAS;AAEtC,KAAI,CAAC,QAAQ;EACX,MAAM,aAAa,WAAW,SAAS,MAAM,MAAM,EAAE,aAAa,OAAO,GAAG,EAAE;AAC9E,WAAS,MAAM,OAAO,YAAY;GAChC,MAAM;GACN,YAAY,cAAc,EAAE;GAC5B;GACA;GACD,CAAC;AACF,cAAY,IAAI,UAAU,OAAO;;CAGnC,MAAM,gBAAgB,OAAO,QAAQ;AACrC,KAAI,CAAC,cACH,OAAM,IAAI,MACR,oCAAoC,OAAO,GAAG,eAAe,WAAW,KAAK,SAAS,OACvF;AAGH,QAAO;;;;;;;;;;;;AAaT,eAAe,mCACb,QACA,QACA,MACA,cAC0B;AAC1B,KAAI,CAAC,OAAO,iBACV,OAAM,IAAI,MAAM,WAAW,OAAO,GAAG,6CAA6C;CAIpF,IAAI,cAAc,sBAAsB,IAAI,OAAO;AACnD,KAAI,CAAC,aAAa;AAChB,gCAAc,IAAI,KAAK;AACvB,wBAAsB,IAAI,QAAQ,YAAY;;AAIhD,KAAI,OAAO,GACT,MAAK,MAAMC,eAAa,OAAO,KAAK,OAAO,GAAG,EAAE;AAE9C,MADiB,OAAO,GAAGA,aACd,SAAU;EAEvB,MAAMC,aAAW,YAAY,gBAAgBD,eAAa,aAAa;EACvE,MAAM,SAAS,YAAY,IAAIC,WAAS;AACxC,MAAI,QAAQ,QAAQ,MAClB,QAAO,OAAO,MAAM;;CAM1B,MAAM,EAAE,WAAW,WAAW,MAAM,mCAClC,QACA,QACA,MACA,aACD;CAED,MAAM,WAAW,YAAY,gBAAgB,aAAa,aAAa;AACvE,aAAY,IAAI,UAAU,OAAO;CAEjC,MAAM,gBAAgB,OAAO,QAAQ;AACrC,KAAI,CAAC,cACH,OAAM,IAAI,MAAM,oCAAoC,OAAO,GAAG,SAAS,OAAO;AAGhF,QAAO"}
1
+ {"version":3,"file":"index.mjs","names":["fs","namespace","cacheKey"],"sources":["../../src/plugin/with-context.ts","../../src/plugin/get-generated-type.ts"],"sourcesContent":["/**\n * Plugin executor context support for defining plugin executors in separate files.\n * This module provides utilities for creating type-safe plugin executors that receive\n * context (like type references and namespace) at runtime.\n */\n\nimport type { TailorActor, TailorEnv } from \"@/parser/types\";\n\n/**\n * Plugin executor factory function type.\n * Takes context and returns an executor configuration.\n * Returns unknown since the exact return type depends on createExecutor's generic params.\n */\nexport type PluginExecutorFactory<Ctx> = (ctx: Ctx) => unknown;\n\n// ============================================================================\n// Plugin Executor Args Types\n// ============================================================================\n\n/**\n * Base args for plugin executor function operations.\n * Provides typed access to runtime context without requiring specific record types.\n */\nexport interface PluginFunctionArgs {\n /** Workspace ID where the executor runs */\n workspaceId: string;\n /** Application namespace */\n appNamespace: string;\n /** Environment variables */\n env: TailorEnv;\n /** Actor (user) who triggered the event, null for system events */\n actor: TailorActor | null;\n /** Name of the TailorDB type */\n typeName: string;\n /** TailorDB connections by namespace */\n tailordb: Record<string, unknown>;\n}\n\n/**\n * Args for plugin executors triggered on record creation.\n */\nexport interface PluginRecordCreatedArgs extends PluginFunctionArgs {\n /** The newly created record */\n newRecord: Record<string, unknown>;\n}\n\n/**\n * Args for plugin executors triggered on record update.\n */\nexport interface PluginRecordUpdatedArgs extends PluginFunctionArgs {\n /** The record after update */\n newRecord: Record<string, unknown>;\n /** The record before update */\n oldRecord: Record<string, unknown>;\n}\n\n/**\n * Args for plugin executors triggered on record deletion.\n */\nexport interface PluginRecordDeletedArgs extends PluginFunctionArgs {\n /** The deleted record */\n oldRecord: Record<string, unknown>;\n}\n\n/**\n * Database schema type for plugins.\n * Since plugins work with dynamic types, the schema uses Record types.\n */\nexport type PluginDBSchema = Record<string, Record<string, unknown>>;\n\n/**\n * Base record type for TailorDB records.\n * All records have an id field.\n */\nexport type PluginRecord = { id: string } & Record<string, unknown>;\n\n/**\n * Define a plugin executor that receives context at runtime.\n * This allows executor definitions to be in separate files while\n * still receiving dynamic values like typeName, generated types, and namespace.\n * @param factory - Function that takes context and returns executor configuration\n * @returns The same factory function (for type inference)\n * @example\n * ```typescript\n * // executors/on-create.ts\n * import { withPluginContext } from \"@tailor-platform/sdk/plugin\";\n * import { createExecutor, recordCreatedTrigger } from \"@tailor-platform/sdk\";\n * import { getDB } from \"@tailor-platform/function-kysely-tailordb\";\n *\n * interface MyContext {\n * sourceType: TailorAnyDBType;\n * historyType: TailorAnyDBType;\n * namespace: string;\n * }\n *\n * export default withPluginContext<MyContext>((ctx) =>\n * createExecutor({\n * name: `${ctx.sourceType.name.toLowerCase()}-on-create`,\n * trigger: recordCreatedTrigger({ type: ctx.sourceType }),\n * operation: {\n * kind: \"function\",\n * body: async (args) => {\n * const db = getDB(ctx.namespace);\n * await db.insertInto(ctx.historyType.name).values({\n * recordId: args.newRecord.id,\n * // ...\n * }).execute();\n * },\n * },\n * })\n * );\n * ```\n */\nexport function withPluginContext<Ctx>(\n factory: PluginExecutorFactory<Ctx>,\n): PluginExecutorFactory<Ctx> {\n return factory;\n}\n","import * as fs from \"node:fs\";\nimport { pathToFileURL } from \"node:url\";\nimport * as path from \"pathe\";\nimport type { Plugin, PluginOutput, TypePluginOutput } from \"@/parser/plugin-config/types\";\nimport type { TailorAnyDBType } from \"@/parser/service/tailordb/types\";\n\n// ========================================\n// Config loading and caching\n// ========================================\n\ninterface PluginEntry {\n plugin: Plugin;\n pluginConfig: unknown;\n}\n\ninterface ConfigCache {\n config: { db?: Record<string, unknown> };\n plugins: Map<string, PluginEntry>;\n configDir: string;\n}\n\n/** Cache: resolved config path -> loaded config data */\nconst configCacheMap = new Map<string, ConfigCache>();\n\n/**\n * Check if a value is a Plugin instance.\n * @param value - Value to check\n * @returns True if value has the shape of Plugin\n */\nfunction isPlugin(value: unknown): value is Plugin {\n return (\n typeof value === \"object\" &&\n value !== null &&\n typeof (value as Record<string, unknown>).id === \"string\" &&\n typeof (value as Record<string, unknown>).description === \"string\"\n );\n}\n\n/**\n * Load and cache config module from the given path.\n * Extracts plugins from all array exports using definePlugins() format.\n * Returns null if the config file does not exist (e.g., in bundled executor on platform server).\n * @param configPath - Absolute or relative path to tailor.config.ts\n * @returns Cached config data with plugins map, or null if config file is not available\n */\nasync function loadAndCacheConfig(configPath: string): Promise<ConfigCache | null> {\n const resolvedPath = path.resolve(configPath);\n\n const cached = configCacheMap.get(resolvedPath);\n if (cached) return cached;\n\n // Config file may not exist in bundled environments (e.g., platform server)\n if (!fs.existsSync(resolvedPath)) {\n return null;\n }\n\n const configModule = await import(pathToFileURL(resolvedPath).href);\n if (!configModule?.default) {\n throw new Error(`Invalid config module at \"${resolvedPath}\": default export not found`);\n }\n\n const config = configModule.default as { db?: Record<string, unknown> };\n const configDir = path.dirname(resolvedPath);\n const plugins = new Map<string, PluginEntry>();\n\n // Find plugin arrays from exports (definePlugins returns PluginConfig[])\n for (const value of Object.values(configModule)) {\n if (!Array.isArray(value)) continue;\n\n for (const item of value) {\n if (isPlugin(item)) {\n plugins.set(item.id, { plugin: item, pluginConfig: item.pluginConfig });\n }\n }\n }\n\n const result: ConfigCache = { config, plugins, configDir };\n configCacheMap.set(resolvedPath, result);\n return result;\n}\n\n// ========================================\n// Namespace resolution\n// ========================================\n\ninterface DbNamespaceConfig {\n files?: string[];\n external?: boolean;\n}\n\n/**\n * Resolve the namespace for a type-attached sourceType by checking config.db file patterns.\n * Uses ESM module cache identity: same file path yields same object references.\n * @param config - App config with db namespace definitions\n * @param config.db - DB namespace definitions\n * @param configDir - Directory containing the config file\n * @param sourceType - The TailorDB type to look up\n * @returns The namespace name\n */\nasync function resolveNamespaceForType(\n config: { db?: Record<string, unknown> },\n configDir: string,\n sourceType: TailorAnyDBType,\n): Promise<string> {\n if (!config.db) {\n throw new Error(`No db configuration found in config`);\n }\n\n for (const [namespace, nsConfig] of Object.entries(config.db)) {\n const dbConfig = nsConfig as DbNamespaceConfig;\n // Skip external namespaces (no files to resolve)\n if (dbConfig.external || !dbConfig.files) continue;\n\n for (const pattern of dbConfig.files) {\n const absolutePattern = path.resolve(configDir, pattern);\n let matchedFiles: string[];\n try {\n matchedFiles = fs.globSync(absolutePattern);\n } catch {\n continue;\n }\n\n for (const file of matchedFiles) {\n const mod = await import(pathToFileURL(file).href);\n for (const exported of Object.values(mod)) {\n if (exported === sourceType) {\n return namespace;\n }\n }\n }\n }\n }\n\n throw new Error(\n `Could not resolve namespace for type \"${sourceType.name}\". ` +\n `Ensure the type file is included in a db namespace's files pattern.`,\n );\n}\n\n/**\n * Resolve the namespace for a namespace plugin by trying each namespace.\n * Calls onNamespaceLoaded() for each and returns the first whose output contains the requested kind.\n * @param config - App config with db namespace definitions\n * @param config.db - DB namespace definitions\n * @param plugin - Plugin instance\n * @param kind - The generated type kind to look for\n * @param pluginConfig - Plugin-level configuration\n * @returns The namespace name\n */\nasync function resolveNamespaceForNamespacePlugin(\n config: { db?: Record<string, unknown> },\n plugin: Plugin,\n kind: string,\n pluginConfig: unknown,\n): Promise<{ namespace: string; output: PluginOutput }> {\n if (!config.db) {\n throw new Error(`No db configuration found in config`);\n }\n\n if (!plugin.onNamespaceLoaded) {\n throw new Error(`Plugin \"${plugin.id}\" does not have a onNamespaceLoaded() method`);\n }\n\n for (const namespace of Object.keys(config.db)) {\n const dbConfig = config.db[namespace] as DbNamespaceConfig;\n if (dbConfig.external) continue;\n\n const output = await plugin.onNamespaceLoaded({\n pluginConfig,\n namespace,\n });\n\n if (output.types?.[kind]) {\n return { namespace, output };\n }\n }\n\n throw new Error(\n `Could not resolve namespace for plugin \"${plugin.id}\" with kind \"${kind}\". ` +\n `No namespace produced a type with that kind.`,\n );\n}\n\n// ========================================\n// Process caching\n// ========================================\n\n// Cache: plugin -> cacheKey -> TypePluginOutput\nconst processCache = new WeakMap<Plugin, Map<string, TypePluginOutput>>();\n\n// Cache for namespace plugins: plugin -> cacheKey -> PluginOutput\nconst namespaceProcessCache = new WeakMap<Plugin, Map<string, PluginOutput>>();\n\n/**\n * Generate a cache key that includes pluginConfig.\n * @param baseKey - Base key for the cache\n * @param pluginConfig - Plugin configuration to include in the key\n * @returns Cache key string\n */\nfunction getCacheKey(baseKey: string, pluginConfig: unknown): string {\n if (pluginConfig === undefined) {\n return baseKey;\n }\n try {\n return `${baseKey}:${JSON.stringify(pluginConfig)}`;\n } catch {\n throw new Error(\n `pluginConfig must be JSON-serializable for caching. Received non-serializable value.`,\n );\n }\n}\n\n// ========================================\n// Main API\n// ========================================\n\n/**\n * Get a generated type from a plugin by loading the config and resolving everything automatically.\n * For type-attached plugins, calls onTypeLoaded() with the sourceType.\n * For namespace plugins, calls onNamespaceLoaded() with auto-resolved namespace.\n * Results are cached per config path, plugin, namespace, and pluginConfig to avoid redundant processing.\n * @param configPath - Path to tailor.config.ts (absolute or relative to cwd)\n * @param pluginId - The plugin's unique identifier\n * @param sourceType - The source TailorDB type (null for namespace plugins)\n * @param kind - The generated type kind (e.g., \"request\", \"step\")\n * @returns The generated TailorDB type\n */\nexport async function getGeneratedType(\n configPath: string,\n pluginId: string,\n sourceType: TailorAnyDBType | null,\n kind: string,\n): Promise<TailorAnyDBType> {\n const cache = await loadAndCacheConfig(configPath);\n\n if (!cache) {\n // Config not available (e.g., running in bundled executor on platform server).\n // Return a placeholder. The actual type is resolved at generate/apply time.\n return { name: `__placeholder_${kind}__`, fields: {} } as TailorAnyDBType;\n }\n\n const { config, configDir, plugins } = cache;\n\n const pluginEntry = plugins.get(pluginId);\n if (!pluginEntry) {\n throw new Error(\n `Plugin \"${pluginId}\" not found in config at \"${configPath}\". ` +\n `Ensure the plugin is registered via definePlugins().`,\n );\n }\n\n const { plugin, pluginConfig } = pluginEntry;\n\n if (sourceType === null) {\n return getGeneratedTypeForNamespacePlugin(config, plugin, kind, pluginConfig);\n }\n\n const namespace = await resolveNamespaceForType(config, configDir, sourceType);\n return getGeneratedTypeForTypeAttachedPlugin(plugin, sourceType, kind, pluginConfig, namespace);\n}\n\n/**\n * Get a generated type from a type-attached plugin.\n * @param plugin - The plugin instance (must have onTypeLoaded() method)\n * @param sourceType - The source TailorDB type\n * @param kind - The generated type kind\n * @param pluginConfig - Plugin-level configuration\n * @param namespace - Resolved namespace\n * @returns The generated TailorDB type\n */\nasync function getGeneratedTypeForTypeAttachedPlugin(\n plugin: Plugin,\n sourceType: TailorAnyDBType,\n kind: string,\n pluginConfig: unknown,\n namespace: string,\n): Promise<TailorAnyDBType> {\n if (!plugin.onTypeLoaded) {\n throw new Error(`Plugin \"${plugin.id}\" does not have a onTypeLoaded() method`);\n }\n\n // Check cache first\n let pluginCache = processCache.get(plugin);\n if (!pluginCache) {\n pluginCache = new Map();\n processCache.set(plugin, pluginCache);\n }\n\n const cacheKey = getCacheKey(`${sourceType.name}:ns=${namespace}`, pluginConfig);\n let output = pluginCache.get(cacheKey);\n\n if (!output) {\n const typeConfig = sourceType.plugins?.find((p) => p.pluginId === plugin.id)?.config;\n output = await plugin.onTypeLoaded({\n type: sourceType,\n typeConfig: typeConfig ?? {},\n pluginConfig,\n namespace,\n });\n pluginCache.set(cacheKey, output);\n }\n\n const generatedType = output.types?.[kind];\n if (!generatedType) {\n throw new Error(\n `Generated type not found: plugin=${plugin.id}, sourceType=${sourceType.name}, kind=${kind}`,\n );\n }\n\n return generatedType as TailorAnyDBType;\n}\n\n/**\n * Get a generated type from a namespace plugin.\n * Auto-resolves the namespace by trying each one.\n * @param config - App config with db namespace definitions\n * @param config.db - DB namespace definitions\n * @param plugin - The plugin instance (must have onNamespaceLoaded() method)\n * @param kind - The generated type kind\n * @param pluginConfig - Plugin-level configuration\n * @returns The generated TailorDB type\n */\nasync function getGeneratedTypeForNamespacePlugin(\n config: { db?: Record<string, unknown> },\n plugin: Plugin,\n kind: string,\n pluginConfig: unknown,\n): Promise<TailorAnyDBType> {\n if (!plugin.onNamespaceLoaded) {\n throw new Error(`Plugin \"${plugin.id}\" does not have a onNamespaceLoaded() method`);\n }\n\n // Check cache first - try all namespaces\n let pluginCache = namespaceProcessCache.get(plugin);\n if (!pluginCache) {\n pluginCache = new Map();\n namespaceProcessCache.set(plugin, pluginCache);\n }\n\n // Try cached results first\n if (config.db) {\n for (const namespace of Object.keys(config.db)) {\n const dbConfig = config.db[namespace] as DbNamespaceConfig;\n if (dbConfig.external) continue;\n\n const cacheKey = getCacheKey(`namespace:ns=${namespace}`, pluginConfig);\n const cached = pluginCache.get(cacheKey);\n if (cached?.types?.[kind]) {\n return cached.types[kind] as TailorAnyDBType;\n }\n }\n }\n\n // Not in cache - resolve namespace and process\n const { namespace, output } = await resolveNamespaceForNamespacePlugin(\n config,\n plugin,\n kind,\n pluginConfig,\n );\n\n const cacheKey = getCacheKey(`namespace:ns=${namespace}`, pluginConfig);\n pluginCache.set(cacheKey, output);\n\n const generatedType = output.types?.[kind];\n if (!generatedType) {\n throw new Error(`Generated type not found: plugin=${plugin.id}, kind=${kind}`);\n }\n\n return generatedType as TailorAnyDBType;\n}\n\n/**\n * Clear all internal caches. For testing only.\n */\nexport function _clearCacheForTesting(): void {\n configCacheMap.clear();\n}\n"],"mappings":"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"}
@@ -1,3 +1,4 @@
1
+ import { t as brandValue } from "./brand-BZJCv6UY.mjs";
1
2
  import { cloneDeep } from "es-toolkit";
2
3
 
3
4
  //#region src/configure/types/field.ts
@@ -25,7 +26,8 @@ const regex$1 = {
25
26
  uuid: /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i,
26
27
  date: /^(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})$/,
27
28
  time: /^(?<hour>\d{2}):(?<minute>\d{2})$/,
28
- datetime: /^(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})T(?<hour>\d{2}):(?<minute>\d{2}):(?<second>\d{2})(.(?<millisec>\d{3}))?Z$/
29
+ datetime: /^(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})T(?<hour>\d{2}):(?<minute>\d{2}):(?<second>\d{2})(.(?<millisec>\d{3}))?Z$/,
30
+ decimal: /^-?(\d+\.?\d*|\.\d+)([eE][+-]?\d+)?$/
29
31
  };
30
32
  /**
31
33
  * Creates a new TailorField instance.
@@ -109,6 +111,12 @@ function createTailorField(type, options, fields, values) {
109
111
  path: pathArray.length > 0 ? pathArray : void 0
110
112
  });
111
113
  break;
114
+ case "decimal":
115
+ if (typeof value !== "string" || !regex$1.decimal.test(value)) issues.push({
116
+ message: `Expected a decimal string: received ${String(value)}`,
117
+ path: pathArray.length > 0 ? pathArray : void 0
118
+ });
119
+ break;
112
120
  case "enum":
113
121
  if (field._metadata.allowedValues) {
114
122
  const allowedValues = field._metadata.allowedValues.map((v) => v.value);
@@ -284,6 +292,16 @@ function float$1(options) {
284
292
  return createTailorField("float", options);
285
293
  }
286
294
  /**
295
+ * Create a decimal field for resolver input/output (stored as string for precision).
296
+ * @param options - Field configuration options
297
+ * @returns A decimal field
298
+ * @example t.decimal()
299
+ * @example t.decimal({ optional: true })
300
+ */
301
+ function decimal$1(options) {
302
+ return createTailorField("decimal", options);
303
+ }
304
+ /**
287
305
  * Create a date field for resolver input/output.
288
306
  * @param options - Field configuration options
289
307
  * @returns A date field
@@ -341,6 +359,7 @@ const t = {
341
359
  bool: bool$1,
342
360
  int: int$1,
343
361
  float: float$1,
362
+ decimal: decimal$1,
344
363
  date: date$1,
345
364
  datetime: datetime$1,
346
365
  time: time$1,
@@ -397,7 +416,8 @@ const regex = {
397
416
  uuid: /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i,
398
417
  date: /^(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})$/,
399
418
  time: /^(?<hour>\d{2}):(?<minute>\d{2})$/,
400
- datetime: /^(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})T(?<hour>\d{2}):(?<minute>\d{2}):(?<second>\d{2})(.(?<millisec>\d{3}))?Z$/
419
+ datetime: /^(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})T(?<hour>\d{2}):(?<minute>\d{2}):(?<second>\d{2})(.(?<millisec>\d{3}))?Z$/,
420
+ decimal: /^-?(\d+\.?\d*|\.\d+)([eE][+-]?\d+)?$/
401
421
  };
402
422
  /**
403
423
  * Creates a new TailorDBField instance.
@@ -473,6 +493,12 @@ function createTailorDBField(type, options, fields, values) {
473
493
  path: pathArray.length > 0 ? pathArray : void 0
474
494
  });
475
495
  break;
496
+ case "decimal":
497
+ if (typeof value !== "string" || !regex.decimal.test(value)) issues.push({
498
+ message: `Expected a decimal string: received ${String(value)}`,
499
+ path: pathArray.length > 0 ? pathArray : void 0
500
+ });
501
+ break;
476
502
  case "enum":
477
503
  if (field._metadata.allowedValues) {
478
504
  const allowedValues = field._metadata.allowedValues.map((v) => v.value);
@@ -715,6 +741,22 @@ function float(options) {
715
741
  return createField("float", options);
716
742
  }
717
743
  /**
744
+ * Create a decimal field (stored as string for precision).
745
+ * @param options - Field configuration options including optional scale (0-12)
746
+ * @returns A decimal field
747
+ * @example db.decimal()
748
+ * @example db.decimal({ scale: 2 })
749
+ * @example db.decimal({ scale: 2, optional: true })
750
+ */
751
+ function decimal(options) {
752
+ if (options?.scale !== void 0) {
753
+ if (!Number.isInteger(options.scale) || options.scale < 0 || options.scale > 12) throw new Error("scale must be an integer between 0 and 12");
754
+ }
755
+ const field = createField("decimal", options);
756
+ if (options?.scale !== void 0) field._metadata.scale = options.scale;
757
+ return field;
758
+ }
759
+ /**
718
760
  * Create a date field (date only, no time component).
719
761
  * Format: "yyyy-MM-dd"
720
762
  * @param options - Field configuration options
@@ -786,7 +828,7 @@ function createTailorDBType(name, fields, options) {
786
828
  if (name === options.pluralForm) throw new Error(`The name and the plural form must be different. name=${name}`);
787
829
  _settings.pluralForm = options.pluralForm;
788
830
  }
789
- return {
831
+ return brandValue({
790
832
  name,
791
833
  fields: { ...fields },
792
834
  _output: null,
@@ -883,7 +925,7 @@ function createTailorDBType(name, fields, options) {
883
925
  });
884
926
  return this;
885
927
  }
886
- };
928
+ });
887
929
  }
888
930
  const idField = uuid();
889
931
  function dbType(name, fieldsOrDescription, fields) {
@@ -910,6 +952,7 @@ const db = {
910
952
  bool,
911
953
  int,
912
954
  float,
955
+ decimal,
913
956
  date,
914
957
  datetime,
915
958
  time,
@@ -923,4 +966,4 @@ const db = {
923
966
 
924
967
  //#endregion
925
968
  export { t as i, unsafeAllowAllGqlPermission as n, unsafeAllowAllTypePermission as r, db as t };
926
- //# sourceMappingURL=schema-R5TxC5Pn.mjs.map
969
+ //# sourceMappingURL=schema-D5Cpd8fQ.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema-D5Cpd8fQ.mjs","names":["regex","uuid","string","bool","int","float","decimal","date","datetime","time","_enum","object","field","validators","options"],"sources":["../src/configure/types/field.ts","../src/configure/types/type.ts","../src/configure/services/tailordb/permission.ts","../src/configure/services/tailordb/schema.ts"],"sourcesContent":["import { type EnumValue } from \"@/parser/service/tailordb/types\";\n\nexport type AllowedValue = EnumValue;\n\nexport type AllowedValues = [string | EnumValue, ...(string | EnumValue)[]];\n\n/**\n * Normalize allowed values into EnumValue objects with descriptions.\n * @param values - Allowed values as strings or EnumValue objects\n * @returns Normalized allowed values\n */\nexport function mapAllowedValues(values: AllowedValues): AllowedValue[] {\n return values.map((value) => {\n if (typeof value === \"string\") {\n return { value, description: \"\" };\n }\n return { ...value, description: value.description ?? \"\" };\n });\n}\n\nexport type AllowedValuesOutput<V extends AllowedValues> = V[number] extends infer T\n ? T extends string\n ? T\n : T extends { value: infer K }\n ? K\n : never\n : never;\n","import { type AllowedValues, type AllowedValuesOutput, mapAllowedValues } from \"./field\";\nimport {\n type TailorFieldType,\n type TailorToTs,\n type FieldMetadata,\n type DefinedFieldMetadata,\n type FieldOptions,\n type FieldOutput,\n} from \"./types\";\nimport type { Prettify, InferFieldsOutput } from \"./helpers\";\nimport type { FieldValidateInput } from \"./validation\";\nimport type { TailorUser } from \"@/configure/types\";\nimport type { TailorFieldInput } from \"@/parser/service/resolver/types\";\nimport type { StandardSchemaV1 } from \"@standard-schema/spec\";\n\nconst regex = {\n uuid: /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i,\n date: /^(?<year>\\d{4})-(?<month>\\d{2})-(?<day>\\d{2})$/,\n time: /^(?<hour>\\d{2}):(?<minute>\\d{2})$/,\n datetime:\n /^(?<year>\\d{4})-(?<month>\\d{2})-(?<day>\\d{2})T(?<hour>\\d{2}):(?<minute>\\d{2}):(?<second>\\d{2})(.(?<millisec>\\d{3}))?Z$/,\n decimal: /^-?(\\d+\\.?\\d*|\\.\\d+)([eE][+-]?\\d+)?$/,\n} as const;\n\n// This helper type intentionally uses `any` as a placeholder for unknown field output.\n// oxlint-disable-next-line no-explicit-any\nexport type TailorAnyField = TailorField<any>;\n\ntype FieldParseArgs = {\n value: unknown;\n data: unknown;\n user: TailorUser;\n};\n\ntype FieldValidateValueArgs<T extends TailorFieldType> = {\n value: TailorToTs[T];\n data: unknown;\n user: TailorUser;\n pathArray: string[];\n};\n\ntype FieldParseInternalArgs = {\n // Runtime input is unknown/untyped; we validate and narrow it inside the parser.\n // oxlint-disable-next-line no-explicit-any\n value: any;\n data: unknown;\n user: TailorUser;\n pathArray: string[];\n};\n\n/**\n * TailorField interface representing a field with metadata, type information, and optional nested fields.\n * This is the base field type used by both resolver types and TailorDB types.\n * Using interface to allow self-referencing in the fields property.\n */\nexport interface TailorField<\n Defined extends DefinedFieldMetadata = DefinedFieldMetadata,\n // Generic default output type (kept loose on purpose for library ergonomics).\n // oxlint-disable-next-line no-explicit-any\n Output = any,\n M extends FieldMetadata = FieldMetadata,\n T extends TailorFieldType = TailorFieldType,\n> extends TailorFieldInput {\n readonly type: T;\n readonly fields: Record<string, TailorAnyField>;\n readonly _defined: Defined;\n readonly _output: Output;\n _metadata: M;\n\n /** Returns a shallow copy of the metadata */\n readonly metadata: M;\n\n /**\n * Set a description for the field\n * @param description - The description text\n * @returns The field with updated metadata\n */\n description<CurrentDefined extends Defined>(\n this: CurrentDefined extends { description: unknown }\n ? never\n : TailorField<CurrentDefined, Output>,\n description: string,\n ): TailorField<Prettify<CurrentDefined & { description: true }>, Output>;\n\n /**\n * Set a custom type name for enum or nested types\n * @param typeName - The custom type name\n * @returns The field with updated metadata\n */\n typeName<CurrentDefined extends Defined>(\n this: CurrentDefined extends { typeName: unknown }\n ? never\n : CurrentDefined extends { type: \"enum\" | \"nested\" }\n ? TailorField<CurrentDefined, Output>\n : never,\n typeName: string,\n ): TailorField<Prettify<CurrentDefined & { typeName: true }>, Output>;\n\n /**\n * Add validation functions to the field\n * @param validate - One or more validation functions\n * @returns The field with updated metadata\n */\n validate<CurrentDefined extends Defined>(\n this: CurrentDefined extends { validate: unknown }\n ? never\n : TailorField<CurrentDefined, Output>,\n ...validate: FieldValidateInput<Output>[]\n ): TailorField<Prettify<CurrentDefined & { validate: true }>, Output>;\n\n /**\n * Parse and validate a value against this field's validation rules\n * Returns StandardSchema Result type with success or failure\n * @param args - Value, context data, and user\n * @returns Validation result\n */\n parse(args: FieldParseArgs): StandardSchemaV1.Result<Output>;\n\n /**\n * Internal parse method that tracks field path for nested validation\n * @private\n * @param args - Parse arguments\n * @returns Validation result\n */\n _parseInternal(args: FieldParseInternalArgs): StandardSchemaV1.Result<Output>;\n}\n\n/**\n * Creates a new TailorField instance.\n * @param type - Field type\n * @param options - Field options\n * @param fields - Nested fields for object-like types\n * @param values - Allowed values for enum-like fields\n * @returns A new TailorField\n */\nfunction createTailorField<\n const T extends TailorFieldType,\n const TOptions extends FieldOptions,\n const OutputBase = TailorToTs[T],\n>(\n type: T,\n options?: TOptions,\n fields?: Record<string, TailorAnyField>,\n values?: AllowedValues,\n): TailorField<\n { type: T; array: TOptions extends { array: true } ? true : false },\n FieldOutput<OutputBase, TOptions>\n> {\n const _metadata: FieldMetadata = { required: true };\n\n if (options) {\n const hasRequired = Object.prototype.hasOwnProperty.call(options, \"required\");\n const hasOptional = Object.prototype.hasOwnProperty.call(options, \"optional\");\n\n if (hasRequired) {\n const isRequired = options.required === true;\n _metadata.required = isRequired;\n if (isRequired) {\n _metadata.requiredExplicit = true;\n }\n } else if (hasOptional) {\n const isOptional = options.optional === true;\n _metadata.required = !isOptional;\n if (options.optional === false) {\n _metadata.requiredExplicit = true;\n }\n }\n if (options.array === true) {\n _metadata.array = true;\n }\n }\n if (values) {\n _metadata.allowedValues = mapAllowedValues(values);\n }\n\n /**\n * Validate a single value (not an array element)\n * Used internally for array element validation\n * @param args - Value, context data, and user\n * @returns Array of validation issues\n */\n function validateValue(args: FieldValidateValueArgs<T>): StandardSchemaV1.Issue[] {\n const { value, data, user, pathArray } = args;\n const issues: StandardSchemaV1.Issue[] = [];\n\n // Type-specific validation\n switch (type) {\n case \"string\":\n if (typeof value !== \"string\") {\n issues.push({\n message: `Expected a string: received ${String(value)}`,\n path: pathArray.length > 0 ? pathArray : undefined,\n });\n }\n break;\n\n case \"integer\":\n if (typeof value !== \"number\" || !Number.isInteger(value)) {\n issues.push({\n message: `Expected an integer: received ${String(value)}`,\n path: pathArray.length > 0 ? pathArray : undefined,\n });\n }\n break;\n\n case \"float\":\n if (typeof value !== \"number\" || !Number.isFinite(value)) {\n issues.push({\n message: `Expected a number: received ${String(value)}`,\n path: pathArray.length > 0 ? pathArray : undefined,\n });\n }\n break;\n\n case \"boolean\":\n if (typeof value !== \"boolean\") {\n issues.push({\n message: `Expected a boolean: received ${String(value)}`,\n path: pathArray.length > 0 ? pathArray : undefined,\n });\n }\n break;\n\n case \"uuid\":\n if (typeof value !== \"string\" || !regex.uuid.test(value)) {\n issues.push({\n message: `Expected a valid UUID: received ${String(value)}`,\n path: pathArray.length > 0 ? pathArray : undefined,\n });\n }\n break;\n case \"date\":\n if (typeof value !== \"string\" || !regex.date.test(value)) {\n issues.push({\n message: `Expected to match \"yyyy-MM-dd\" format: received ${String(value)}`,\n path: pathArray.length > 0 ? pathArray : undefined,\n });\n }\n break;\n case \"datetime\":\n if (typeof value !== \"string\" || !regex.datetime.test(value)) {\n issues.push({\n message: `Expected to match ISO format: received ${String(value)}`,\n path: pathArray.length > 0 ? pathArray : undefined,\n });\n }\n break;\n case \"time\":\n if (typeof value !== \"string\" || !regex.time.test(value)) {\n issues.push({\n message: `Expected to match \"HH:mm\" format: received ${String(value)}`,\n path: pathArray.length > 0 ? pathArray : undefined,\n });\n }\n break;\n case \"decimal\":\n if (typeof value !== \"string\" || !regex.decimal.test(value)) {\n issues.push({\n message: `Expected a decimal string: received ${String(value)}`,\n path: pathArray.length > 0 ? pathArray : undefined,\n });\n }\n break;\n\n case \"enum\":\n if (field._metadata.allowedValues) {\n const allowedValues = field._metadata.allowedValues.map((v) => v.value);\n if (typeof value !== \"string\" || !allowedValues.includes(value)) {\n issues.push({\n message: `Must be one of [${allowedValues.join(\", \")}]: received ${String(value)}`,\n path: pathArray.length > 0 ? pathArray : undefined,\n });\n }\n }\n break;\n\n case \"nested\":\n // Validate nested object fields\n if (\n typeof value !== \"object\" ||\n value === null ||\n Array.isArray(value) ||\n value instanceof Date\n ) {\n issues.push({\n message: `Expected an object: received ${String(value)}`,\n path: pathArray.length > 0 ? pathArray : undefined,\n });\n } else if (field.fields && Object.keys(field.fields).length > 0) {\n for (const [fieldName, nestedField] of Object.entries(field.fields)) {\n const fieldValue = value?.[fieldName];\n const result = nestedField._parseInternal({\n value: fieldValue,\n data,\n user,\n pathArray: pathArray.concat(fieldName),\n });\n if (result.issues) {\n issues.push(...result.issues);\n }\n }\n }\n break;\n }\n\n // Custom validation functions\n const validateFns = field._metadata.validate;\n if (validateFns && validateFns.length > 0) {\n for (const validateInput of validateFns) {\n const { fn, message } =\n typeof validateInput === \"function\"\n ? { fn: validateInput, message: \"Validation failed\" }\n : { fn: validateInput[0], message: validateInput[1] };\n\n if (!fn({ value, data, user })) {\n issues.push({\n message,\n path: pathArray.length > 0 ? pathArray : undefined,\n });\n }\n }\n }\n\n return issues;\n }\n\n /**\n * Internal parse method that tracks field path for nested validation\n * @param args - Parse arguments\n * @returns Parse result with value or issues\n */\n function parseInternal(\n args: FieldParseInternalArgs,\n ): StandardSchemaV1.Result<FieldOutput<OutputBase, TOptions>> {\n const { value, data, user, pathArray } = args;\n const issues: StandardSchemaV1.Issue[] = [];\n\n // 1. Check required/optional\n const isNullOrUndefined = value === null || value === undefined;\n if (field._metadata.required && isNullOrUndefined) {\n issues.push({\n message: \"Required field is missing\",\n path: pathArray.length > 0 ? pathArray : undefined,\n });\n return { issues };\n }\n\n // If optional and null/undefined, skip further validation and normalize to null\n if (!field._metadata.required && isNullOrUndefined) {\n return { value: value ?? null };\n }\n\n // 2. Check array type\n if (field._metadata.array) {\n if (!Array.isArray(value)) {\n issues.push({\n message: \"Expected an array\",\n path: pathArray.length > 0 ? pathArray : undefined,\n });\n return { issues };\n }\n\n // Validate each array element (without array flag)\n for (let i = 0; i < value.length; i++) {\n const elementValue = value[i];\n const elementPath = pathArray.concat(`[${i}]`);\n\n // Validate element with same type but without array flag\n const elementIssues = validateValue({\n value: elementValue,\n data,\n user,\n pathArray: elementPath,\n });\n if (elementIssues.length > 0) {\n issues.push(...elementIssues);\n }\n }\n\n if (issues.length > 0) {\n return { issues };\n }\n return { value: value as FieldOutput<OutputBase, TOptions> };\n }\n\n // 3. Type-specific validation and custom validation\n const valueIssues = validateValue({ value, data, user, pathArray });\n issues.push(...valueIssues);\n\n if (issues.length > 0) {\n return { issues };\n }\n\n return { value };\n }\n\n const field: TailorField<\n { type: T; array: TOptions extends { array: true } ? true : false },\n FieldOutput<OutputBase, TOptions>\n > = {\n type,\n fields: fields ?? {},\n _defined: undefined as unknown as {\n type: T;\n array: TOptions extends { array: true } ? true : false;\n },\n _output: undefined as FieldOutput<OutputBase, TOptions>,\n _metadata,\n\n get metadata() {\n return { ...this._metadata };\n },\n\n description(description: string) {\n this._metadata.description = description;\n // Fluent API returns this with updated type\n // oxlint-disable-next-line no-explicit-any\n return this as any;\n },\n\n typeName(typeName: string) {\n this._metadata.typeName = typeName;\n // Fluent API returns this with updated type\n // oxlint-disable-next-line no-explicit-any\n return this as any;\n },\n\n validate(...validateInputs: FieldValidateInput<FieldOutput<OutputBase, TOptions>>[]) {\n this._metadata.validate = validateInputs;\n // Fluent API returns this with updated type\n // oxlint-disable-next-line no-explicit-any\n return this as any;\n },\n\n parse(args: FieldParseArgs): StandardSchemaV1.Result<FieldOutput<OutputBase, TOptions>> {\n return parseInternal({\n value: args.value,\n data: args.data,\n user: args.user,\n pathArray: [],\n });\n },\n\n _parseInternal: parseInternal,\n };\n\n return field;\n}\n\n/**\n * Create a UUID field for resolver input/output.\n * @param options - Field configuration options\n * @returns A UUID field\n * @example t.uuid()\n */\nfunction uuid<const Opt extends FieldOptions>(options?: Opt) {\n return createTailorField(\"uuid\", options);\n}\n\n/**\n * Create a string field for resolver input/output.\n * @param options - Field configuration options\n * @returns A string field\n * @example t.string()\n * @example t.string({ optional: true })\n * @example t.string({ array: true })\n */\nfunction string<const Opt extends FieldOptions>(options?: Opt) {\n return createTailorField(\"string\", options);\n}\n\n/**\n * Create a boolean field for resolver input/output.\n * @param options - Field configuration options\n * @returns A boolean field\n * @example t.bool()\n */\nfunction bool<const Opt extends FieldOptions>(options?: Opt) {\n return createTailorField(\"boolean\", options);\n}\n\n/**\n * Create an integer field for resolver input/output.\n * @param options - Field configuration options\n * @returns An integer field\n * @example t.int()\n */\nfunction int<const Opt extends FieldOptions>(options?: Opt) {\n return createTailorField(\"integer\", options);\n}\n\n/**\n * Create a float field for resolver input/output.\n * @param options - Field configuration options\n * @returns A float field\n * @example t.float()\n */\nfunction float<const Opt extends FieldOptions>(options?: Opt) {\n return createTailorField(\"float\", options);\n}\n\n/**\n * Create a decimal field for resolver input/output (stored as string for precision).\n * @param options - Field configuration options\n * @returns A decimal field\n * @example t.decimal()\n * @example t.decimal({ optional: true })\n */\nfunction decimal<const Opt extends FieldOptions>(options?: Opt) {\n return createTailorField(\"decimal\", options);\n}\n\n/**\n * Create a date field for resolver input/output.\n * @param options - Field configuration options\n * @returns A date field\n * @example t.date()\n */\nfunction date<const Opt extends FieldOptions>(options?: Opt) {\n return createTailorField(\"date\", options);\n}\n\n/**\n * Create a datetime field for resolver input/output.\n * @param options - Field configuration options\n * @returns A datetime field\n * @example t.datetime()\n */\nfunction datetime<const Opt extends FieldOptions>(options?: Opt) {\n return createTailorField(\"datetime\", options);\n}\n\n/**\n * Create a time field for resolver input/output.\n * @param options - Field configuration options\n * @returns A time field\n * @example t.time()\n */\nfunction time<const Opt extends FieldOptions>(options?: Opt) {\n return createTailorField(\"time\", options);\n}\n\n/**\n * Create an enum field for resolver input/output.\n * @param values - Array of allowed string values\n * @param options - Field configuration options\n * @returns An enum field\n * @example t.enum([\"active\", \"inactive\"])\n */\nfunction _enum<const V extends AllowedValues, const Opt extends FieldOptions>(\n values: V,\n options?: Opt,\n): TailorField<\n { type: \"enum\"; array: Opt extends { array: true } ? true : false },\n FieldOutput<AllowedValuesOutput<V>, Opt>\n> {\n return createTailorField<\"enum\", Opt, AllowedValuesOutput<V>>(\"enum\", options, undefined, values);\n}\n\n/**\n * Create a nested object field for resolver input/output.\n * @param fields - Record of field definitions\n * @param options - Field options (optional, array)\n * @returns A nested object field\n * @example\n * // Single object:\n * output: t.object({ name: t.string(), email: t.string() })\n * @example\n * // Array of objects:\n * items: t.object({ name: t.string() }, { array: true })\n */\nfunction object<const F extends Record<string, TailorAnyField>, const Opt extends FieldOptions>(\n fields: F,\n options?: Opt,\n) {\n const objectField = createTailorField(\"nested\", options, fields) as TailorField<\n { type: \"nested\"; array: Opt extends { array: true } ? true : false },\n FieldOutput<InferFieldsOutput<F>, Opt>\n >;\n return objectField;\n}\n\nexport const t = {\n uuid,\n string,\n bool,\n int,\n float,\n decimal,\n date,\n datetime,\n time,\n enum: _enum,\n object,\n};\n","import type { InferredAttributeMap } from \"../../types\";\n\n/**\n * Record-level permission configuration for a TailorDB type.\n * Defines create, read, update, and delete permissions.\n *\n * Prefer object format with explicit `conditions` and `permit` for readability.\n * Shorthand array format is supported for compatibility, but less readable.\n *\n * For update operations, use `newRecord`/`oldRecord` operands instead of `record`.\n * @example\n * const permission: TailorTypePermission = {\n * create: [{ conditions: [[{ user: \"_loggedIn\" }, \"=\", true]], permit: true }],\n * read: [{ conditions: [[{ record: \"isPublic\" }, \"=\", true]], permit: true }],\n * update: [{ conditions: [[{ newRecord: \"ownerId\" }, \"=\", { user: \"id\" }]], permit: true }],\n * delete: [{ conditions: [[{ record: \"ownerId\" }, \"=\", { user: \"id\" }]], permit: true }],\n * };\n */\nexport type TailorTypePermission<\n User extends object = InferredAttributeMap,\n Type extends object = object,\n> = {\n create: readonly ActionPermission<\"record\", User, Type, false>[];\n read: readonly ActionPermission<\"record\", User, Type, false>[];\n update: readonly ActionPermission<\"record\", User, Type, true>[];\n delete: readonly ActionPermission<\"record\", User, Type, false>[];\n};\n\ntype ActionPermission<\n Level extends \"record\" | \"gql\" = \"record\" | \"gql\",\n User extends object = InferredAttributeMap,\n Type extends object = object,\n Update extends boolean = boolean,\n> =\n | {\n conditions:\n | PermissionCondition<Level, User, Update, Type>\n | readonly PermissionCondition<Level, User, Update, Type>[];\n description?: string | undefined;\n permit?: boolean;\n }\n | readonly [...PermissionCondition<Level, User, Update, Type>, ...([] | [boolean])] // single array condition\n | readonly [...PermissionCondition<Level, User, Update, Type>[], ...([] | [boolean])]; // multiple array condition\n\nexport type TailorTypeGqlPermission<\n User extends object = InferredAttributeMap,\n Type extends object = object,\n> = readonly GqlPermissionPolicy<User, Type>[];\n\ntype GqlPermissionPolicy<\n User extends object = InferredAttributeMap,\n Type extends object = object,\n> = {\n conditions: readonly PermissionCondition<\"gql\", User, boolean, Type>[];\n actions: \"all\" | readonly GqlPermissionAction[];\n permit?: boolean;\n description?: string;\n};\n\ntype GqlPermissionAction = \"read\" | \"create\" | \"update\" | \"delete\" | \"aggregate\" | \"bulkUpsert\";\n\ntype EqualityOperator = \"=\" | \"!=\";\ntype ContainsOperator = \"in\" | \"not in\";\ntype HasAnyOperator = \"hasAny\" | \"not hasAny\";\n\n// Helper types for User field extraction\ntype StringFieldKeys<User extends object> = {\n [K in keyof User]: User[K] extends string ? K : never;\n}[keyof User];\n\ntype StringArrayFieldKeys<User extends object> = {\n [K in keyof User]: User[K] extends string[] ? K : never;\n}[keyof User];\n\ntype BooleanFieldKeys<User extends object> = {\n [K in keyof User]: User[K] extends boolean ? K : never;\n}[keyof User];\n\ntype BooleanArrayFieldKeys<User extends object> = {\n [K in keyof User]: User[K] extends boolean[] ? K : never;\n}[keyof User];\n\ntype UserStringOperand<User extends object = InferredAttributeMap> = {\n user: StringFieldKeys<User> | \"id\";\n};\n\ntype UserStringArrayOperand<User extends object = InferredAttributeMap> = {\n user: StringArrayFieldKeys<User>;\n};\n\ntype UserBooleanOperand<User extends object = InferredAttributeMap> = {\n user: BooleanFieldKeys<User> | \"_loggedIn\";\n};\n\ntype UserBooleanArrayOperand<User extends object = InferredAttributeMap> = {\n user: BooleanArrayFieldKeys<User>;\n};\n\ntype RecordOperand<Type extends object, Update extends boolean = false> = Update extends true\n ? { oldRecord: (keyof Type & string) | \"id\" } | { newRecord: (keyof Type & string) | \"id\" }\n : { record: (keyof Type & string) | \"id\" };\n\ntype StringEqualityCondition<\n Level extends \"record\" | \"gql\",\n User extends object,\n Update extends boolean,\n Type extends object,\n> =\n | (Level extends \"gql\" ? readonly [string, EqualityOperator, boolean] : never)\n | readonly [string, EqualityOperator, string]\n | readonly [UserStringOperand<User>, EqualityOperator, string]\n | readonly [string, EqualityOperator, UserStringOperand<User>]\n | (Level extends \"record\"\n ?\n | readonly [\n RecordOperand<Type, Update>,\n EqualityOperator,\n string | UserStringOperand<User>,\n ]\n | readonly [\n string | UserStringOperand<User>,\n EqualityOperator,\n RecordOperand<Type, Update>,\n ]\n : never);\n\ntype BooleanEqualityCondition<\n Level extends \"record\" | \"gql\",\n User extends object,\n Update extends boolean,\n Type extends object,\n> =\n | readonly [boolean, EqualityOperator, boolean]\n | readonly [UserBooleanOperand<User>, EqualityOperator, boolean]\n | readonly [boolean, EqualityOperator, UserBooleanOperand<User>]\n | (Level extends \"record\"\n ?\n | readonly [\n RecordOperand<Type, Update>,\n EqualityOperator,\n boolean | UserBooleanOperand<User>,\n ]\n | readonly [\n boolean | UserBooleanOperand<User>,\n EqualityOperator,\n RecordOperand<Type, Update>,\n ]\n : never);\n\ntype EqualityCondition<\n Level extends \"record\" | \"gql\" = \"record\",\n User extends object = InferredAttributeMap,\n Update extends boolean = boolean,\n Type extends object = object,\n> =\n | StringEqualityCondition<Level, User, Update, Type>\n | BooleanEqualityCondition<Level, User, Update, Type>;\n\ntype StringContainsCondition<\n Level extends \"record\" | \"gql\",\n User extends object,\n Update extends boolean,\n Type extends object,\n> =\n | readonly [string, ContainsOperator, string[]]\n | readonly [UserStringOperand<User>, ContainsOperator, string[]]\n | readonly [string, ContainsOperator, UserStringArrayOperand<User>]\n | (Level extends \"record\"\n ?\n | readonly [\n RecordOperand<Type, Update>,\n ContainsOperator,\n string[] | UserStringArrayOperand<User>,\n ]\n | readonly [\n string | UserStringOperand<User>,\n ContainsOperator,\n RecordOperand<Type, Update>,\n ]\n : never);\n\ntype BooleanContainsCondition<\n Level extends \"record\" | \"gql\",\n User extends object,\n Update extends boolean,\n Type extends object,\n> =\n | (Level extends \"gql\" ? readonly [string, ContainsOperator, boolean[]] : never)\n | readonly [boolean, ContainsOperator, boolean[]]\n | readonly [UserBooleanOperand<User>, ContainsOperator, boolean[]]\n | readonly [boolean, ContainsOperator, UserBooleanArrayOperand<User>]\n | (Level extends \"record\"\n ?\n | readonly [\n RecordOperand<Type, Update>,\n ContainsOperator,\n boolean[] | UserBooleanArrayOperand<User>,\n ]\n | readonly [\n boolean | UserBooleanOperand<User>,\n ContainsOperator,\n RecordOperand<Type, Update>,\n ]\n : never);\n\ntype ContainsCondition<\n Level extends \"record\" | \"gql\" = \"record\",\n User extends object = InferredAttributeMap,\n Update extends boolean = boolean,\n Type extends object = object,\n> =\n | StringContainsCondition<Level, User, Update, Type>\n | BooleanContainsCondition<Level, User, Update, Type>;\n\ntype HasAnyCondition<\n Level extends \"record\" | \"gql\",\n User extends object,\n Update extends boolean,\n Type extends object,\n> =\n | readonly [\n string[] | UserStringArrayOperand<User>,\n HasAnyOperator,\n string[] | UserStringArrayOperand<User>,\n ]\n | (Level extends \"record\"\n ?\n | readonly [\n RecordOperand<Type, Update>,\n HasAnyOperator,\n string[] | UserStringArrayOperand<User>,\n ]\n | readonly [\n string[] | UserStringArrayOperand<User>,\n HasAnyOperator,\n RecordOperand<Type, Update>,\n ]\n : never);\n\n/**\n * Type representing a permission condition that combines user attributes, record fields, and literal values using comparison operators.\n *\n * The User type is extended by `user-defined.d.ts`, which is automatically generated when running `tailor-sdk generate`.\n * Attributes enabled in the config file's `auth.userProfile.attributes` (or\n * `auth.machineUserAttributes` when userProfile is omitted) become available as types.\n * @example\n * ```ts\n * // tailor.config.ts\n * export const auth = defineAuth(\"my-auth\", {\n * userProfile: {\n * type: user,\n * attributes: {\n * isAdmin: true,\n * roles: true,\n * }\n * }\n * });\n * ```\n */\nexport type PermissionCondition<\n Level extends \"record\" | \"gql\" = \"record\",\n User extends object = InferredAttributeMap,\n Update extends boolean = boolean,\n Type extends object = object,\n> =\n | EqualityCondition<Level, User, Update, Type>\n | ContainsCondition<Level, User, Update, Type>\n | HasAnyCondition<Level, User, Update, Type>;\n\n/**\n * Grants full record-level access without any conditions.\n *\n * Unsafe and intended only for local development, prototyping, or tests.\n * Do not use this in production environments, as it effectively disables\n * authorization checks.\n */\nexport const unsafeAllowAllTypePermission: TailorTypePermission = {\n create: [{ conditions: [], permit: true }],\n read: [{ conditions: [], permit: true }],\n update: [{ conditions: [], permit: true }],\n delete: [{ conditions: [], permit: true }],\n};\n\n/**\n * Grants full GraphQL access (all actions) without any conditions.\n *\n * Unsafe and intended only for local development, prototyping, or tests.\n * Do not use this in production environments, as it effectively disables\n * authorization checks.\n */\nexport const unsafeAllowAllGqlPermission: TailorTypeGqlPermission = [\n { conditions: [], actions: \"all\", permit: true },\n];\n","import { cloneDeep } from \"es-toolkit\";\nimport {\n type AllowedValues,\n type AllowedValuesOutput,\n mapAllowedValues,\n} from \"@/configure/types/field\";\nimport { type TailorField, type TailorAnyField } from \"@/configure/types/type\";\nimport {\n type FieldOptions,\n type FieldOutput,\n type TailorFieldType,\n type TailorToTs,\n} from \"@/configure/types/types\";\nimport {\n type TailorDBTypeMetadata,\n type RawPermissions,\n type RawRelationConfig,\n type RelationType,\n} from \"@/parser/service/tailordb/types\";\nimport { brandValue } from \"@/utils/brand\";\nimport { type TailorTypeGqlPermission, type TailorTypePermission } from \"./permission\";\nimport {\n type DBFieldMetadata,\n type DefinedDBFieldMetadata,\n type Hooks,\n type Hook,\n type SerialConfig,\n type IndexDef,\n type TypeFeatures,\n type ExcludeNestedDBFields,\n} from \"./types\";\nimport type { InferredAttributeMap, TailorUser } from \"@/configure/types\";\nimport type { Prettify, output, InferFieldsOutput } from \"@/configure/types/helpers\";\nimport type { FieldValidateInput, ValidateConfig, Validators } from \"@/configure/types/validation\";\nimport type { PluginAttachment, PluginConfigs } from \"@/parser/plugin-config/types\";\nimport type { StandardSchemaV1 } from \"@standard-schema/spec\";\n\ninterface RelationConfig<S extends RelationType, T extends TailorDBType> {\n type: S;\n toward: {\n type: T;\n as?: string;\n key?: keyof T[\"fields\"] & string;\n };\n backward?: string;\n}\n\n// Special config variant for self-referencing relations\ntype RelationSelfConfig = {\n type: RelationType;\n toward: {\n type: \"self\";\n as?: string;\n key?: string;\n };\n backward?: string;\n};\n\nfunction isRelationSelfConfig(\n config: RelationConfig<RelationType, TailorDBType> | RelationSelfConfig,\n): config is RelationSelfConfig {\n return config.toward.type === \"self\";\n}\n\n// Helper alias: DB fields can be arbitrarily nested, so we intentionally keep this loose.\n// oxlint-disable-next-line no-explicit-any\nexport type TailorAnyDBField = TailorDBField<any, any>;\n\n// Helper alias\n// oxlint-disable-next-line no-explicit-any\nexport type TailorAnyDBType = TailorDBType<any, any>;\n\nconst regex = {\n uuid: /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i,\n date: /^(?<year>\\d{4})-(?<month>\\d{2})-(?<day>\\d{2})$/,\n time: /^(?<hour>\\d{2}):(?<minute>\\d{2})$/,\n datetime:\n /^(?<year>\\d{4})-(?<month>\\d{2})-(?<day>\\d{2})T(?<hour>\\d{2}):(?<minute>\\d{2}):(?<second>\\d{2})(.(?<millisec>\\d{3}))?Z$/,\n decimal: /^-?(\\d+\\.?\\d*|\\.\\d+)([eE][+-]?\\d+)?$/,\n} as const;\n\ntype FieldParseArgs = {\n value: unknown;\n data: unknown;\n user: TailorUser;\n};\n\ntype FieldValidateValueArgs<T extends TailorFieldType> = {\n value: TailorToTs[T];\n data: unknown;\n user: TailorUser;\n pathArray: string[];\n};\n\ntype FieldParseInternalArgs = {\n // Runtime input is unknown/untyped; we validate and narrow it inside the parser.\n // oxlint-disable-next-line no-explicit-any\n value: any;\n data: unknown;\n user: TailorUser;\n pathArray: string[];\n};\n\n/**\n * TailorDBField interface representing a database field with extended metadata.\n * Extends TailorField with database-specific features like relations, indexes, and hooks.\n */\nexport interface TailorDBField<Defined extends DefinedDBFieldMetadata, Output> extends Omit<\n TailorField<Defined, Output, DBFieldMetadata, Defined[\"type\"]>,\n \"description\" | \"validate\"\n> {\n /** Returns a shallow copy of the raw relation config if set */\n readonly rawRelation: Readonly<RawRelationConfig> | undefined;\n\n /**\n * Set a description for the field\n * @param description - The description text\n * @returns The field with updated metadata\n */\n description<CurrentDefined extends Defined>(\n this: CurrentDefined extends { description: unknown }\n ? never\n : TailorField<CurrentDefined, Output>,\n description: string,\n ): TailorDBField<Prettify<CurrentDefined & { description: true }>, Output>;\n\n /**\n * Define a relation to another type.\n * Relation types: \"n-1\" (many-to-one), \"1-1\" (one-to-one), \"keyOnly\" (key only).\n * Aliases \"manyToOne\", \"oneToOne\", and \"N-1\" are also accepted.\n * @example db.uuid().relation({ type: \"n-1\", toward: { type: otherModel } })\n * @example db.uuid().relation({ type: \"1-1\", toward: { type: profile } })\n */\n relation<S extends RelationType, T extends TailorAnyDBType, CurrentDefined extends Defined>(\n this: CurrentDefined extends { relation: unknown }\n ? never\n : TailorDBField<CurrentDefined, Output>,\n config: RelationConfig<S, T>,\n ): TailorDBField<\n S extends \"oneToOne\" | \"1-1\"\n ? Prettify<CurrentDefined & { unique: true; index: true; relation: true }>\n : Prettify<CurrentDefined & { index: true; relation: true }>,\n Output\n >;\n\n /**\n * Define a self-referencing relation\n */\n relation<S extends RelationSelfConfig, CurrentDefined extends Defined>(\n this: CurrentDefined extends { relation: unknown }\n ? never\n : TailorDBField<CurrentDefined, Output>,\n config: S,\n ): TailorDBField<\n S[\"type\"] extends \"oneToOne\" | \"1-1\"\n ? Prettify<CurrentDefined & { unique: true; index: true; relation: true }>\n : Prettify<CurrentDefined & { index: true; relation: true }>,\n Output\n >;\n\n /**\n * Add an index to the field\n */\n index<CurrentDefined extends Defined>(\n this: CurrentDefined extends { index: unknown }\n ? never\n : CurrentDefined extends { array: true }\n ? never\n : TailorDBField<CurrentDefined, Output>,\n ): TailorDBField<Prettify<CurrentDefined & { index: true }>, Output>;\n\n /**\n * Make the field unique (also adds an index)\n */\n unique<CurrentDefined extends Defined>(\n this: CurrentDefined extends { unique: unknown }\n ? never\n : CurrentDefined extends { array: true }\n ? never\n : TailorDBField<CurrentDefined, Output>,\n ): TailorDBField<Prettify<CurrentDefined & { unique: true; index: true }>, Output>;\n\n /**\n * Enable vector search on the field (string type only)\n */\n vector<CurrentDefined extends Defined>(\n this: CurrentDefined extends { vector: unknown }\n ? never\n : CurrentDefined extends { type: \"string\"; array: false }\n ? TailorDBField<CurrentDefined, Output>\n : never,\n ): TailorDBField<Prettify<CurrentDefined & { vector: true }>, Output>;\n\n /**\n * Add hooks for create/update operations on this field.\n * The hook function receives `{ value, data, user }` and returns the computed value.\n * @example db.string().hooks({ create: ({ data }) => data.firstName + \" \" + data.lastName })\n * @example db.datetime().hooks({ create: () => new Date(), update: () => new Date() })\n */\n hooks<CurrentDefined extends Defined, const H extends Hook<unknown, Output>>(\n this: CurrentDefined extends { hooks: unknown }\n ? never\n : CurrentDefined extends { type: \"nested\" }\n ? never\n : TailorDBField<CurrentDefined, Output>,\n hooks: H,\n ): TailorDBField<\n Prettify<\n CurrentDefined & {\n hooks?: {\n create: H extends { create: unknown } ? true : false;\n update: H extends { update: unknown } ? true : false;\n };\n serial: false;\n }\n >,\n Output\n >;\n\n /**\n * Add validation functions to the field.\n * Accepts a function or a tuple of [function, errorMessage].\n * Prefer the tuple form for diagnosable errors.\n * @example\n * // Function form (default error message):\n * db.int().validate(({ value }) => value >= 0)\n * @example\n * // Tuple form with custom error message (recommended):\n * db.string().validate([({ value }) => value.length >= 8, \"Must be at least 8 characters\"])\n */\n validate<CurrentDefined extends Defined>(\n this: CurrentDefined extends { validate: unknown }\n ? never\n : TailorDBField<CurrentDefined, Output>,\n ...validate: FieldValidateInput<Output>[]\n ): TailorDBField<Prettify<CurrentDefined & { validate: true }>, Output>;\n\n /**\n * Configure serial/auto-increment behavior\n */\n serial<CurrentDefined extends Defined>(\n this: CurrentDefined extends { serial: unknown }\n ? never\n : Output extends null\n ? never\n : CurrentDefined extends { type: \"integer\" | \"string\"; array: false }\n ? TailorDBField<CurrentDefined, Output>\n : never,\n config: SerialConfig<CurrentDefined[\"type\"] & (\"integer\" | \"string\")>,\n ): TailorDBField<\n Prettify<\n CurrentDefined & {\n serial: true;\n hooks: { create: false; update: false };\n }\n >,\n Output\n >;\n\n /**\n * Clone the field with optional overrides for field options\n * @param options - Optional field options to override\n * @returns A new TailorDBField instance with the same configuration\n */\n clone<const NewOpt extends FieldOptions>(\n options?: NewOpt,\n ): TailorDBField<\n Prettify<\n Omit<Defined, \"array\"> & {\n array: NewOpt extends { array: true } ? true : Defined[\"array\"];\n }\n >,\n FieldOutput<TailorToTs[Defined[\"type\"]], NewOpt>\n >;\n}\n\n/**\n * Creates a new TailorDBField instance.\n * @param type - Field type\n * @param options - Field options\n * @param fields - Nested fields for object-like types\n * @param values - Allowed values for enum-like fields\n * @returns A new TailorDBField\n */\nfunction createTailorDBField<\n const T extends TailorFieldType,\n const TOptions extends FieldOptions,\n const OutputBase = TailorToTs[T],\n>(\n type: T,\n options?: TOptions,\n fields?: Record<string, TailorAnyDBField>,\n values?: AllowedValues,\n): TailorDBField<\n { type: T; array: TOptions extends { array: true } ? true : false },\n FieldOutput<OutputBase, TOptions>\n> {\n type FieldType = TailorDBField<\n { type: T; array: TOptions extends { array: true } ? true : false },\n FieldOutput<OutputBase, TOptions>\n >;\n\n const _metadata: DBFieldMetadata = { required: true };\n let _rawRelation: RawRelationConfig | undefined;\n\n if (options) {\n if (options.optional === true) {\n _metadata.required = false;\n }\n if (options.array === true) {\n _metadata.array = true;\n }\n }\n if (values) {\n _metadata.allowedValues = mapAllowedValues(values);\n }\n\n /**\n * Validate a single value (not an array element)\n * Used internally for array element validation\n * @param args - Value, context data, and user\n * @returns Array of validation issues\n */\n function validateValue(args: FieldValidateValueArgs<T>): StandardSchemaV1.Issue[] {\n const { value, data, user, pathArray } = args;\n const issues: StandardSchemaV1.Issue[] = [];\n\n // Type-specific validation\n switch (type) {\n case \"string\":\n if (typeof value !== \"string\") {\n issues.push({\n message: `Expected a string: received ${String(value)}`,\n path: pathArray.length > 0 ? pathArray : undefined,\n });\n }\n break;\n\n case \"integer\":\n if (typeof value !== \"number\" || !Number.isInteger(value)) {\n issues.push({\n message: `Expected an integer: received ${String(value)}`,\n path: pathArray.length > 0 ? pathArray : undefined,\n });\n }\n break;\n\n case \"float\":\n if (typeof value !== \"number\" || !Number.isFinite(value)) {\n issues.push({\n message: `Expected a number: received ${String(value)}`,\n path: pathArray.length > 0 ? pathArray : undefined,\n });\n }\n break;\n\n case \"boolean\":\n if (typeof value !== \"boolean\") {\n issues.push({\n message: `Expected a boolean: received ${String(value)}`,\n path: pathArray.length > 0 ? pathArray : undefined,\n });\n }\n break;\n\n case \"uuid\":\n if (typeof value !== \"string\" || !regex.uuid.test(value)) {\n issues.push({\n message: `Expected a valid UUID: received ${String(value)}`,\n path: pathArray.length > 0 ? pathArray : undefined,\n });\n }\n break;\n case \"date\":\n if (typeof value !== \"string\" || !regex.date.test(value)) {\n issues.push({\n message: `Expected to match \"yyyy-MM-dd\" format: received ${String(value)}`,\n path: pathArray.length > 0 ? pathArray : undefined,\n });\n }\n break;\n case \"datetime\":\n if (typeof value !== \"string\" || !regex.datetime.test(value)) {\n issues.push({\n message: `Expected to match ISO format: received ${String(value)}`,\n path: pathArray.length > 0 ? pathArray : undefined,\n });\n }\n break;\n case \"time\":\n if (typeof value !== \"string\" || !regex.time.test(value)) {\n issues.push({\n message: `Expected to match \"HH:mm\" format: received ${String(value)}`,\n path: pathArray.length > 0 ? pathArray : undefined,\n });\n }\n break;\n case \"decimal\":\n if (typeof value !== \"string\" || !regex.decimal.test(value)) {\n issues.push({\n message: `Expected a decimal string: received ${String(value)}`,\n path: pathArray.length > 0 ? pathArray : undefined,\n });\n }\n break;\n\n case \"enum\":\n if (field._metadata.allowedValues) {\n const allowedValues = field._metadata.allowedValues.map((v) => v.value);\n if (typeof value !== \"string\" || !allowedValues.includes(value)) {\n issues.push({\n message: `Must be one of [${allowedValues.join(\", \")}]: received ${String(value)}`,\n path: pathArray.length > 0 ? pathArray : undefined,\n });\n }\n }\n break;\n\n case \"nested\":\n // Validate nested object fields\n if (\n typeof value !== \"object\" ||\n value === null ||\n Array.isArray(value) ||\n value instanceof Date\n ) {\n issues.push({\n message: `Expected an object: received ${String(value)}`,\n path: pathArray.length > 0 ? pathArray : undefined,\n });\n } else if (field.fields && Object.keys(field.fields).length > 0) {\n for (const [fieldName, nestedField] of Object.entries(field.fields)) {\n const fieldValue = value?.[fieldName];\n const result = nestedField._parseInternal({\n value: fieldValue,\n data,\n user,\n pathArray: pathArray.concat(fieldName),\n });\n if (result.issues) {\n issues.push(...result.issues);\n }\n }\n }\n break;\n }\n\n // Custom validation functions\n const validateFns = field._metadata.validate;\n if (validateFns && validateFns.length > 0) {\n for (const validateInput of validateFns) {\n const { fn, message } =\n typeof validateInput === \"function\"\n ? { fn: validateInput, message: \"Validation failed\" }\n : { fn: validateInput[0], message: validateInput[1] };\n\n if (!fn({ value, data, user })) {\n issues.push({\n message,\n path: pathArray.length > 0 ? pathArray : undefined,\n });\n }\n }\n }\n\n return issues;\n }\n\n /**\n * Internal parse method that tracks field path for nested validation\n * @param args - Parse arguments\n * @returns Parse result with value or issues\n */\n function parseInternal(\n args: FieldParseInternalArgs,\n ): StandardSchemaV1.Result<FieldOutput<OutputBase, TOptions>> {\n const { value, data, user, pathArray } = args;\n const issues: StandardSchemaV1.Issue[] = [];\n\n // 1. Check required/optional\n const isNullOrUndefined = value === null || value === undefined;\n if (field._metadata.required && isNullOrUndefined) {\n issues.push({\n message: \"Required field is missing\",\n path: pathArray.length > 0 ? pathArray : undefined,\n });\n return { issues };\n }\n\n // If optional and null/undefined, skip further validation and normalize to null\n if (!field._metadata.required && isNullOrUndefined) {\n return { value: value ?? null };\n }\n\n // 2. Check array type\n if (field._metadata.array) {\n if (!Array.isArray(value)) {\n issues.push({\n message: \"Expected an array\",\n path: pathArray.length > 0 ? pathArray : undefined,\n });\n return { issues };\n }\n\n // Validate each array element (without array flag)\n for (let i = 0; i < value.length; i++) {\n const elementValue = value[i];\n const elementPath = pathArray.concat(`[${i}]`);\n\n // Validate element with same type but without array flag\n const elementIssues = validateValue({\n value: elementValue,\n data,\n user,\n pathArray: elementPath,\n });\n if (elementIssues.length > 0) {\n issues.push(...elementIssues);\n }\n }\n\n if (issues.length > 0) {\n return { issues };\n }\n return { value: value as FieldOutput<OutputBase, TOptions> };\n }\n\n // 3. Type-specific validation and custom validation\n const valueIssues = validateValue({ value, data, user, pathArray });\n issues.push(...valueIssues);\n\n if (issues.length > 0) {\n return { issues };\n }\n\n return { value };\n }\n\n function cloneWith(metadataUpdates: Partial<DBFieldMetadata>) {\n const cloned = field.clone();\n Object.assign(cloned._metadata, metadataUpdates);\n return cloned;\n }\n\n const field: FieldType = {\n type,\n fields: (fields ?? {}) as Record<string, TailorAnyField>,\n _defined: undefined as unknown as {\n type: T;\n array: TOptions extends { array: true } ? true : false;\n },\n _output: undefined as FieldOutput<OutputBase, TOptions>,\n _metadata,\n\n get metadata() {\n return { ...this._metadata };\n },\n\n get rawRelation(): Readonly<RawRelationConfig> | undefined {\n return _rawRelation ? { ..._rawRelation, toward: { ..._rawRelation.toward } } : undefined;\n },\n\n description(description: string) {\n // oxlint-disable-next-line no-explicit-any\n return cloneWith({ description }) as any;\n },\n\n typeName(typeName: string) {\n // oxlint-disable-next-line no-explicit-any\n return cloneWith({ typeName }) as any;\n },\n\n validate(...validateInputs: FieldValidateInput<FieldOutput<OutputBase, TOptions>>[]) {\n // oxlint-disable-next-line no-explicit-any\n return cloneWith({ validate: validateInputs }) as any;\n },\n\n parse(args: FieldParseArgs): StandardSchemaV1.Result<FieldOutput<OutputBase, TOptions>> {\n return parseInternal({\n value: args.value,\n data: args.data,\n user: args.user,\n pathArray: [],\n });\n },\n\n _parseInternal: parseInternal,\n\n // TailorDBField specific methods\n relation(config: RelationConfig<RelationType, TailorDBType> | RelationSelfConfig) {\n const cloned = field.clone();\n const targetType = isRelationSelfConfig(config) ? \"self\" : config.toward.type.name;\n // oxlint-disable-next-line no-explicit-any\n (cloned as any)._setRawRelation({\n type: config.type,\n toward: {\n type: targetType,\n as: config.toward.as,\n key: config.toward.key,\n },\n backward: config.backward,\n });\n // oxlint-disable-next-line no-explicit-any\n return cloned as any;\n },\n\n index() {\n // oxlint-disable-next-line no-explicit-any\n return cloneWith({ index: true }) as any;\n },\n\n unique() {\n // oxlint-disable-next-line no-explicit-any\n return cloneWith({ unique: true, index: true }) as any;\n },\n\n vector() {\n // oxlint-disable-next-line no-explicit-any\n return cloneWith({ vector: true }) as any;\n },\n\n hooks(hooks: Hook<unknown, FieldOutput<OutputBase, TOptions>>) {\n // oxlint-disable-next-line no-explicit-any\n return cloneWith({ hooks }) as any;\n },\n\n serial(config: SerialConfig) {\n // oxlint-disable-next-line no-explicit-any\n return cloneWith({ serial: config }) as any;\n },\n\n clone(cloneOptions?: FieldOptions) {\n // Deep clone nested object fields if present\n let clonedFields = fields;\n if (fields) {\n const cloned: Record<string, TailorAnyDBField> = {};\n for (const [key, field] of Object.entries(fields)) {\n cloned[key] = field.clone();\n }\n clonedFields = cloned;\n }\n\n // Create a new field with cloned configuration\n const clonedField = createTailorDBField(type, options, clonedFields, values);\n\n // Deep copy metadata using cloneDeep (preserves function references)\n Object.assign(clonedField._metadata, cloneDeep(this._metadata));\n\n // Apply new options if provided\n if (cloneOptions) {\n if (cloneOptions.optional !== undefined) {\n clonedField._metadata.required = !cloneOptions.optional;\n }\n if (cloneOptions.array !== undefined) {\n clonedField._metadata.array = cloneOptions.array;\n }\n }\n\n // Copy raw relation if exists\n if (_rawRelation) {\n const clonedRawRelation = cloneDeep(_rawRelation);\n // oxlint-disable-next-line no-explicit-any\n (clonedField as any)._setRawRelation(clonedRawRelation);\n }\n\n // oxlint-disable-next-line no-explicit-any\n return clonedField as any;\n },\n\n // Internal method for clone to set rawRelation\n // @ts-ignore - Internal method not in interface\n _setRawRelation(relation: RawRelationConfig) {\n _rawRelation = relation;\n },\n };\n\n return field;\n}\n\nconst createField = createTailorDBField;\n\n/**\n * Create a UUID field.\n * @param options - Field configuration options\n * @returns A UUID field\n * @example db.uuid()\n * @example db.uuid({ optional: true })\n */\nfunction uuid<const Opt extends FieldOptions>(options?: Opt) {\n return createField(\"uuid\", options);\n}\n\n/**\n * Create a string field.\n * @param options - Field configuration options\n * @returns A string field\n * @example db.string()\n * @example db.string({ optional: true })\n */\nfunction string<const Opt extends FieldOptions>(options?: Opt) {\n return createField(\"string\", options);\n}\n\n/**\n * Create a boolean field.\n * Note: The method name is `bool` but creates a `boolean` type field.\n * @param options - Field configuration options\n * @returns A boolean field\n * @example db.bool()\n * @example db.bool({ optional: true })\n */\nfunction bool<const Opt extends FieldOptions>(options?: Opt) {\n return createField(\"boolean\", options);\n}\n\n/**\n * Create an integer field.\n * @param options - Field configuration options\n * @returns An integer field\n * @example db.int()\n * @example db.int({ optional: true })\n */\nfunction int<const Opt extends FieldOptions>(options?: Opt) {\n return createField(\"integer\", options);\n}\n\n/**\n * Create a float (decimal number) field.\n * @param options - Field configuration options\n * @returns A float field\n * @example db.float()\n * @example db.float({ optional: true })\n */\nfunction float<const Opt extends FieldOptions>(options?: Opt) {\n return createField(\"float\", options);\n}\n\ninterface DecimalFieldOptions extends FieldOptions {\n scale?: number;\n}\n\n/**\n * Create a decimal field (stored as string for precision).\n * @param options - Field configuration options including optional scale (0-12)\n * @returns A decimal field\n * @example db.decimal()\n * @example db.decimal({ scale: 2 })\n * @example db.decimal({ scale: 2, optional: true })\n */\nfunction decimal<const Opt extends DecimalFieldOptions>(options?: Opt) {\n if (options?.scale !== undefined) {\n if (!Number.isInteger(options.scale) || options.scale < 0 || options.scale > 12) {\n throw new Error(\"scale must be an integer between 0 and 12\");\n }\n }\n const field = createField(\"decimal\", options);\n if (options?.scale !== undefined) {\n field._metadata.scale = options.scale;\n }\n return field;\n}\n\n/**\n * Create a date field (date only, no time component).\n * Format: \"yyyy-MM-dd\"\n * @param options - Field configuration options\n * @returns A date field\n * @example db.date()\n */\nfunction date<const Opt extends FieldOptions>(options?: Opt) {\n return createField(\"date\", options);\n}\n\n/**\n * Create a datetime field (date and time).\n * Format: ISO 8601 \"yyyy-MM-ddTHH:mm:ssZ\"\n * @param options - Field configuration options\n * @returns A datetime field\n * @example db.datetime()\n */\nfunction datetime<const Opt extends FieldOptions>(options?: Opt) {\n return createField(\"datetime\", options);\n}\n\n/**\n * Create a time field (time only, no date component).\n * Format: \"HH:mm\"\n * @param options - Field configuration options\n * @returns A time field\n * @example db.time()\n */\nfunction time<const Opt extends FieldOptions>(options?: Opt) {\n return createField(\"time\", options);\n}\n\n/**\n * Create an enum field with a fixed set of allowed string values.\n * @param values - Array of allowed string values, or array of `{ value, description }` objects\n * @param options - Field configuration options\n * @returns An enum field\n * @example db.enum([\"active\", \"inactive\", \"suspended\"])\n * @example db.enum([\"small\", \"medium\", \"large\"], { optional: true })\n */\nfunction _enum<const V extends AllowedValues, const Opt extends FieldOptions>(\n values: V,\n options?: Opt,\n): TailorDBField<\n { type: \"enum\"; array: Opt extends { array: true } ? true : false },\n FieldOutput<AllowedValuesOutput<V>, Opt>\n> {\n return createField<\"enum\", Opt, AllowedValuesOutput<V>>(\"enum\", options, undefined, values);\n}\n\n/**\n * Create a nested object field with sub-fields.\n * @param fields - Record of nested field definitions\n * @param options - Field configuration options\n * @returns A nested object field\n * @example db.object({ street: db.string(), city: db.string(), zip: db.string() })\n * @example db.object({ name: db.string() }, { optional: true })\n */\nfunction object<\n const F extends Record<string, TailorAnyDBField> & ExcludeNestedDBFields<F>,\n const Opt extends FieldOptions,\n>(fields: F, options?: Opt) {\n return createField(\"nested\", options, fields) as unknown as TailorDBField<\n { type: \"nested\"; array: Opt extends { array: true } ? true : false },\n FieldOutput<InferFieldsOutput<F>, Opt>\n >;\n}\n\n/**\n * TailorDBType interface representing a database type definition with fields, permissions, and settings.\n */\nexport interface TailorDBType<\n // Default kept loose to avoid forcing callers to supply generics.\n // oxlint-disable-next-line no-explicit-any\n Fields extends Record<string, TailorAnyDBField> = any,\n User extends object = InferredAttributeMap,\n> {\n readonly name: string;\n readonly fields: Fields;\n readonly _output: InferFieldsOutput<Fields>;\n _description?: string;\n\n /** Returns metadata for the type */\n readonly metadata: TailorDBTypeMetadata;\n\n /**\n * Add hooks for fields at the type level.\n * Each key is a field name, and the value defines create/update hooks.\n * @example\n * db.type(\"Order\", {\n * total: db.float(),\n * tax: db.float(),\n * ...db.fields.timestamps(),\n * }).hooks({\n * tax: { create: ({ data }) => data.total * 0.1, update: ({ data }) => data.total * 0.1 },\n * })\n */\n hooks(hooks: Hooks<Fields>): TailorDBType<Fields, User>;\n\n /**\n * Add validators for fields at the type level.\n * Each key is a field name, and the value is a validator or array of validators.\n * Prefer the tuple form [function, message] for diagnosable errors.\n * @example\n * db.type(\"User\", { email: db.string() }).validate({\n * email: [({ value }) => value.includes(\"@\"), \"Email must contain @\"],\n * })\n */\n validate(validators: Validators<Fields>): TailorDBType<Fields, User>;\n\n /**\n * Configure type features\n */\n features(features: Omit<TypeFeatures, \"pluralForm\">): TailorDBType<Fields, User>;\n\n /**\n * Define composite indexes\n */\n indexes(...indexes: IndexDef<TailorDBType<Fields, User>>[]): TailorDBType<Fields, User>;\n\n /**\n * Define file fields\n */\n files<const F extends string>(\n files: Record<F, string> & Partial<Record<keyof output<TailorDBType<Fields, User>>, never>>,\n ): TailorDBType<Fields, User>;\n\n /**\n * Set record-level permissions for create, read, update, and delete operations.\n * Prefer object format with explicit `conditions` and `permit` for readability.\n * For update operations, use `newRecord` and `oldRecord` operands.\n * @example\n * .permission({\n * create: [{ conditions: [[{ user: \"_loggedIn\" }, \"=\", true]], permit: true }],\n * read: [{ conditions: [[{ record: \"isPublic\" }, \"=\", true]], permit: true }],\n * update: [{ conditions: [[{ newRecord: \"ownerId\" }, \"=\", { user: \"id\" }]], permit: true }],\n * delete: [{ conditions: [[{ record: \"ownerId\" }, \"=\", { user: \"id\" }]], permit: true }],\n * })\n */\n permission<\n U extends object = User,\n P extends TailorTypePermission<U, output<TailorDBType<Fields, User>>> = TailorTypePermission<\n U,\n output<TailorDBType<Fields, User>>\n >,\n >(\n permission: P,\n ): TailorDBType<Fields, U>;\n\n /**\n * Set GraphQL-level permissions controlling access to GraphQL operations.\n * @example\n * .gqlPermission([\n * {\n * conditions: [[{ user: \"_loggedIn\" }, \"=\", true]],\n * actions: \"all\",\n * permit: true,\n * },\n * ])\n */\n gqlPermission<\n U extends object = User,\n P extends TailorTypeGqlPermission<U> = TailorTypeGqlPermission<U>,\n >(\n permission: P,\n ): TailorDBType<Fields, U>;\n\n /**\n * Set type description\n */\n description(description: string): TailorDBType<Fields, User>;\n\n /**\n * Pick specific fields from the type\n */\n pickFields<K extends keyof Fields, const Opt extends FieldOptions>(\n keys: K[],\n options: Opt,\n ): {\n [P in K]: Fields[P] extends TailorDBField<infer D, infer _O>\n ? TailorDBField<\n Omit<D, \"array\"> & {\n array: Opt extends { array: true } ? true : D[\"array\"];\n },\n FieldOutput<TailorToTs[D[\"type\"]], Opt>\n >\n : never;\n };\n\n /**\n * Omit specific fields from the type\n */\n omitFields<K extends keyof Fields>(keys: K[]): Omit<Fields, K>;\n\n /**\n * Plugin attachments for this type\n */\n readonly plugins: PluginAttachment[];\n\n /**\n * Attach a plugin to this type\n * @param config - Plugin configuration in the format { pluginId: config }\n * @returns The type with the plugin attached\n */\n plugin<P extends keyof PluginConfigs<keyof Fields & string>>(config: {\n [K in P]: PluginConfigs<keyof Fields & string>[K];\n }): TailorDBType<Fields, User>;\n}\n\n/**\n * Creates a new TailorDBType instance.\n * @param name - Type name\n * @param fields - Field definitions\n * @param options - Type options\n * @param options.pluralForm - Optional plural form\n * @param options.description - Optional description\n * @returns A new TailorDBType\n */\nfunction createTailorDBType<\n // oxlint-disable-next-line no-explicit-any\n const Fields extends Record<string, TailorAnyDBField> = any,\n User extends object = InferredAttributeMap,\n>(\n name: string,\n fields: Fields,\n options: { pluralForm?: string; description?: string },\n): TailorDBType<Fields, User> {\n let _description = options.description;\n let _settings: TypeFeatures = {};\n let _indexes: IndexDef<TailorDBType<Fields, User>>[] = [];\n const _permissions: RawPermissions = {};\n let _files: Record<string, string> = {};\n const _plugins: PluginAttachment[] = [];\n\n if (options.pluralForm) {\n if (name === options.pluralForm) {\n throw new Error(`The name and the plural form must be different. name=${name}`);\n }\n _settings.pluralForm = options.pluralForm;\n }\n\n const dbType: TailorDBType<Fields, User> = {\n name,\n fields: { ...fields },\n _output: null as unknown as InferFieldsOutput<Fields>,\n _description,\n\n get metadata(): TailorDBTypeMetadata {\n // Convert indexes to the format expected by the manifest\n const indexes: Record<string, { fields: string[]; unique?: boolean }> = {};\n if (_indexes && _indexes.length > 0) {\n _indexes.forEach((index) => {\n const fieldNames = index.fields.map((field) => String(field));\n const key = index.name || `idx_${fieldNames.join(\"_\")}`;\n indexes[key] = {\n fields: fieldNames,\n unique: index.unique,\n };\n });\n }\n\n return {\n name: this.name,\n description: _description,\n settings: _settings,\n permissions: _permissions,\n files: _files,\n ...(Object.keys(indexes).length > 0 && { indexes }),\n };\n },\n\n hooks(hooks: Hooks<Fields>) {\n // `Hooks<Fields>` is strongly typed, but `Object.entries()` loses that information.\n // oxlint-disable-next-line no-explicit-any\n Object.entries(hooks).forEach(([fieldName, fieldHooks]: [string, any]) => {\n (this.fields as Record<string, TailorAnyDBField>)[fieldName] =\n this.fields[fieldName].hooks(fieldHooks);\n });\n return this;\n },\n\n validate(validators: Validators<Fields>) {\n Object.entries(validators).forEach(([fieldName, fieldValidators]) => {\n const field = this.fields[fieldName] as TailorAnyDBField;\n\n const validators = fieldValidators as\n | FieldValidateInput<unknown>\n | FieldValidateInput<unknown>[];\n\n const isValidateConfig = (v: unknown): v is ValidateConfig<unknown> => {\n return Array.isArray(v) && v.length === 2 && typeof v[1] === \"string\";\n };\n\n let updatedField: TailorAnyDBField;\n if (Array.isArray(validators)) {\n if (isValidateConfig(validators)) {\n updatedField = field.validate(validators);\n } else {\n updatedField = field.validate(...validators);\n }\n } else {\n updatedField = field.validate(validators);\n }\n (this.fields as Record<string, TailorAnyDBField>)[fieldName] = updatedField;\n });\n return this;\n },\n\n features(features: Omit<TypeFeatures, \"pluralForm\">) {\n _settings = {\n ..._settings,\n ...features,\n };\n return this;\n },\n\n indexes(...indexes: IndexDef<TailorDBType<Fields, User>>[]) {\n _indexes = indexes;\n return this;\n },\n\n files<const F extends string>(\n files: Record<F, string> & Partial<Record<keyof output<TailorDBType<Fields, User>>, never>>,\n ) {\n _files = files;\n return this;\n },\n\n permission<\n U extends object = User,\n P extends TailorTypePermission<U, output<TailorDBType<Fields, User>>> = TailorTypePermission<\n U,\n output<TailorDBType<Fields, User>>\n >,\n >(permission: P) {\n const ret = this as TailorDBType<Fields, U>;\n _permissions.record = permission as RawPermissions[\"record\"];\n return ret;\n },\n\n gqlPermission<\n U extends object = User,\n P extends TailorTypeGqlPermission<U> = TailorTypeGqlPermission<U>,\n >(permission: P) {\n const ret = this as TailorDBType<Fields, U>;\n _permissions.gql = permission as RawPermissions[\"gql\"];\n return ret;\n },\n\n description(description: string) {\n _description = description;\n this._description = description;\n return this;\n },\n\n pickFields<K extends keyof Fields, const Opt extends FieldOptions>(keys: K[], options: Opt) {\n const result = {} as Record<K, TailorAnyDBField>;\n for (const key of keys) {\n if (options) {\n result[key] = this.fields[key].clone(options);\n } else {\n result[key] = this.fields[key];\n }\n }\n return result as {\n [P in K]: Fields[P] extends TailorDBField<infer D, infer _O>\n ? TailorDBField<\n Omit<D, \"array\"> & {\n array: Opt extends { array: true } ? true : D[\"array\"];\n },\n FieldOutput<TailorToTs[D[\"type\"]], Opt>\n >\n : never;\n };\n },\n\n omitFields<K extends keyof Fields>(keys: K[]): Omit<Fields, K> {\n const keysSet = new Set(keys);\n const result = {} as Record<string, TailorAnyDBField>;\n for (const key in this.fields) {\n if (Object.hasOwn(this.fields, key) && !keysSet.has(key as unknown as K)) {\n result[key] = this.fields[key];\n }\n }\n return result as Omit<Fields, K>;\n },\n\n get plugins(): PluginAttachment[] {\n return _plugins;\n },\n\n plugin<P extends keyof PluginConfigs<keyof Fields & string>>(config: {\n [K in P]: PluginConfigs<keyof Fields & string>[K];\n }): TailorDBType<Fields, User> {\n for (const [pluginId, pluginConfig] of Object.entries(config)) {\n _plugins.push({ pluginId, config: pluginConfig });\n }\n return this;\n },\n };\n\n return brandValue(dbType);\n}\n\nexport type TailorDBInstance<\n // Default kept loose for convenience; callers still get fully inferred types from `db.type()`.\n // oxlint-disable-next-line no-explicit-any\n Fields extends Record<string, TailorAnyDBField> = any,\n User extends object = InferredAttributeMap,\n> = TailorDBType<Fields, User>;\n\nconst idField = uuid();\ntype idField = typeof idField;\ntype DBType<F extends { id?: never } & Record<string, TailorAnyDBField>> = TailorDBInstance<\n { id: idField } & F\n>;\n\n/**\n * Creates a new database type with the specified fields.\n * An `id` field (UUID) is automatically added to every type.\n * @param name - The name of the type, or a tuple of [name, pluralForm]\n * @param fields - The field definitions for the type\n * @returns A new TailorDBType instance\n * @example\n * export const user = db.type(\"User\", {\n * name: db.string(),\n * email: db.string(),\n * age: db.int({ optional: true }),\n * role: db.enum([\"admin\", \"member\"]),\n * ...db.fields.timestamps(),\n * });\n * // Always export both the value and type:\n * export type user = typeof user;\n */\nfunction dbType<const F extends { id?: never } & Record<string, TailorAnyDBField>>(\n name: string | [string, string],\n fields: F,\n): DBType<F>;\n/**\n * Creates a new database type with the specified fields and description.\n * An `id` field (UUID) is automatically added to every type.\n * @param name - The name of the type, or a tuple of [name, pluralForm]\n * @param description - A description of the type\n * @param fields - The field definitions for the type\n * @returns A new TailorDBType instance\n */\nfunction dbType<const F extends { id?: never } & Record<string, TailorAnyDBField>>(\n name: string | [string, string],\n description: string,\n fields: F,\n): DBType<F>;\nfunction dbType<const F extends { id?: never } & Record<string, TailorAnyDBField>>(\n name: string | [string, string],\n fieldsOrDescription: string | F,\n fields?: F,\n): DBType<F> {\n const typeName = Array.isArray(name) ? name[0] : name;\n const pluralForm = Array.isArray(name) ? name[1] : undefined;\n\n let description: string | undefined;\n let fieldDef: F;\n if (typeof fieldsOrDescription === \"string\") {\n description = fieldsOrDescription;\n fieldDef = fields as F;\n } else {\n fieldDef = fieldsOrDescription;\n }\n return createTailorDBType<{ id: idField } & F>(\n typeName,\n {\n id: idField,\n ...fieldDef,\n },\n { pluralForm, description },\n ) as DBType<F>;\n}\n\nexport const db = {\n type: dbType,\n uuid,\n string,\n bool,\n int,\n float,\n decimal,\n date,\n datetime,\n time,\n enum: _enum,\n object,\n fields: {\n /**\n * Creates standard timestamp fields (createdAt, updatedAt) with auto-hooks.\n * createdAt is set on create, updatedAt is set on update.\n * @returns An object with createdAt and updatedAt fields\n * @example\n * const model = db.type(\"Model\", {\n * name: db.string(),\n * ...db.fields.timestamps(),\n * });\n */\n timestamps: () => ({\n createdAt: datetime()\n .hooks({ create: () => new Date() })\n .description(\"Record creation timestamp\"),\n updatedAt: datetime({ optional: true })\n .hooks({ update: () => new Date() })\n .description(\"Record last update timestamp\"),\n }),\n },\n};\n"],"mappings":"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"}