@tailor-platform/sdk 1.23.0 → 1.25.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.
- package/CHANGELOG.md +79 -0
- package/dist/app-config-QzNOFnEy.d.mts +197 -0
- package/dist/{application-CTQe2HSB.mjs → application-CxDvCZts.mjs} +226 -220
- package/dist/application-CxDvCZts.mjs.map +1 -0
- package/dist/application-EQCsho6Z.mjs +8 -0
- package/dist/{brand-DyPrAzpM.mjs → brand-j6C6_sGq.mjs} +1 -1
- package/dist/{brand-DyPrAzpM.mjs.map → brand-j6C6_sGq.mjs.map} +1 -1
- package/dist/cli/index.mjs +9 -9
- package/dist/cli/index.mjs.map +1 -1
- package/dist/cli/lib.d.mts +7 -7
- package/dist/cli/lib.mjs +10 -10
- package/dist/cli/lib.mjs.map +1 -1
- package/dist/configure/index.d.mts +5 -4
- package/dist/configure/index.mjs +30 -4
- package/dist/configure/index.mjs.map +1 -1
- package/dist/{enum-constants-B5Nl-yzx.mjs → enum-constants-BxdLbhsW.mjs} +1 -1
- package/dist/enum-constants-BxdLbhsW.mjs.map +1 -0
- package/dist/env-jndw86T4.d.mts +32 -0
- package/dist/{file-utils-sEOwAdJ4.mjs → file-utils-C2r3AVbI.mjs} +1 -1
- package/dist/{file-utils-sEOwAdJ4.mjs.map → file-utils-C2r3AVbI.mjs.map} +1 -1
- package/dist/{index-CU2kZzKa.d.mts → index-BUnLWUKQ.d.mts} +66 -15
- package/dist/{index-BSXclved.d.mts → index-DZRZdh71.d.mts} +2 -2
- package/dist/{index-lIALNMi_.d.mts → index-Do7zo7z-.d.mts} +2 -2
- package/dist/{index-CO-jsOMb.d.mts → index-DoxGF8-i.d.mts} +2 -2
- package/dist/{index-DQlsfhpg.d.mts → index-VZq4IAEK.d.mts} +2 -2
- package/dist/{interceptor-DiARwPfw.mjs → interceptor-DVy32eIG.mjs} +1 -1
- package/dist/{interceptor-DiARwPfw.mjs.map → interceptor-DVy32eIG.mjs.map} +1 -1
- package/dist/{job-CRavYLLk.mjs → job-CnLRQFrk.mjs} +2 -2
- package/dist/{job-CRavYLLk.mjs.map → job-CnLRQFrk.mjs.map} +1 -1
- package/dist/{kysely-type-CSlcwNFH.mjs → kysely-type-DzLBuVp6.mjs} +1 -1
- package/dist/kysely-type-DzLBuVp6.mjs.map +1 -0
- package/dist/package-json-BKA36WTo.mjs +3 -0
- package/dist/{package-json-iVBhE5Ef.mjs → package-json-DnbGCOkg.mjs} +1 -1
- package/dist/{package-json-iVBhE5Ef.mjs.map → package-json-DnbGCOkg.mjs.map} +1 -1
- package/dist/plugin/builtin/enum-constants/index.d.mts +2 -2
- package/dist/plugin/builtin/enum-constants/index.mjs +1 -1
- package/dist/plugin/builtin/file-utils/index.d.mts +2 -2
- package/dist/plugin/builtin/file-utils/index.mjs +1 -1
- package/dist/plugin/builtin/kysely-type/index.d.mts +2 -2
- package/dist/plugin/builtin/kysely-type/index.mjs +1 -1
- package/dist/plugin/builtin/seed/index.d.mts +2 -2
- package/dist/plugin/builtin/seed/index.mjs +1 -1
- package/dist/plugin/index.d.mts +2 -1
- package/dist/plugin/index.mjs.map +1 -1
- package/dist/{types--G4ilVmx.d.mts → plugin-3sT6Tcq0.d.mts} +1068 -1761
- package/dist/{query-BLQBOaAM.mjs → query-c9RCJduH.mjs} +451 -60
- package/dist/query-c9RCJduH.mjs.map +1 -0
- package/dist/{schema-Cjm-OvPF.mjs → schema-DOx_W_s2.mjs} +2 -2
- package/dist/schema-DOx_W_s2.mjs.map +1 -0
- package/dist/seed/index.d.mts +29 -0
- package/dist/seed/index.mjs +89 -0
- package/dist/seed/index.mjs.map +1 -0
- package/dist/{seed-CXvCW3Xc.mjs → seed-DkKAheSe.mjs} +76 -9
- package/dist/seed-DkKAheSe.mjs.map +1 -0
- package/dist/telemetry-J6dpByo2.mjs +3 -0
- package/dist/{telemetry-C46fds1l.mjs → telemetry-d_lgTL33.mjs} +2 -2
- package/dist/{telemetry-C46fds1l.mjs.map → telemetry-d_lgTL33.mjs.map} +1 -1
- package/dist/utils/test/index.d.mts +3 -3
- package/dist/utils/test/index.mjs +2 -2
- package/docs/cli/tailordb.md +1 -1
- package/docs/cli-reference.md +8 -8
- package/package.json +31 -24
- package/dist/application-CTQe2HSB.mjs.map +0 -1
- package/dist/application-DdSu3baZ.mjs +0 -8
- package/dist/enum-constants-B5Nl-yzx.mjs.map +0 -1
- package/dist/kysely-type-CSlcwNFH.mjs.map +0 -1
- package/dist/package-json-BI0ng3_5.mjs +0 -3
- package/dist/query-BLQBOaAM.mjs.map +0 -1
- package/dist/schema-Cjm-OvPF.mjs.map +0 -1
- package/dist/seed-CXvCW3Xc.mjs.map +0 -1
- package/dist/telemetry-BAxP8-PR.mjs +0 -3
- package/dist/types-CBTSg-LK.mjs +0 -13
- package/dist/types-CBTSg-LK.mjs.map +0 -1
- package/dist/types-IR-hw0-y.d.mts +0 -245
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as brandValue } from "./brand-
|
|
1
|
+
import { t as brandValue } from "./brand-j6C6_sGq.mjs";
|
|
2
2
|
import { cloneDeep } from "es-toolkit";
|
|
3
3
|
|
|
4
4
|
//#region src/configure/types/field.ts
|
|
@@ -966,4 +966,4 @@ const db = {
|
|
|
966
966
|
|
|
967
967
|
//#endregion
|
|
968
968
|
export { t as i, unsafeAllowAllGqlPermission as n, unsafeAllowAllTypePermission as r, db as t };
|
|
969
|
-
//# sourceMappingURL=schema-
|
|
969
|
+
//# sourceMappingURL=schema-DOx_W_s2.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema-DOx_W_s2.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 \"@/types/tailordb\";\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 \"@/types/resolver.generated\";\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 `tailor.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 { 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 \"@/types/plugin\";\nimport type { TailorDBTypeMetadata, RawRelationConfig, RelationType } from \"@/types/tailordb\";\nimport type { RawPermissions } from \"@/types/tailordb.generated\";\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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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { ForeignKeyDefinition, IndexDefinition, defineSchema } from "@toiroakr/lines-db";
|
|
2
|
+
|
|
3
|
+
//#region src/seed/index.d.ts
|
|
4
|
+
|
|
5
|
+
type ValidateSeedDataOptions = {
|
|
6
|
+
/** Resolved absolute path to a data directory or a .jsonl file */
|
|
7
|
+
path: string;
|
|
8
|
+
/** Show verbose error output */
|
|
9
|
+
verbose?: boolean;
|
|
10
|
+
};
|
|
11
|
+
type ValidateSeedResult = {
|
|
12
|
+
valid: true;
|
|
13
|
+
output: string;
|
|
14
|
+
} | {
|
|
15
|
+
valid: false;
|
|
16
|
+
output: string;
|
|
17
|
+
error: string;
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Validate JSONL seed data against schema definitions.
|
|
21
|
+
* Resolves the given path (directory or `.jsonl` file), runs LinesDB
|
|
22
|
+
* validation, and returns formatted output and error messages.
|
|
23
|
+
* @param options - Validation options including path and verbose flag
|
|
24
|
+
* @returns Validation result with output messages and optional error details
|
|
25
|
+
*/
|
|
26
|
+
declare function validateSeedData(options: ValidateSeedDataOptions): Promise<ValidateSeedResult>;
|
|
27
|
+
//#endregion
|
|
28
|
+
export { type ForeignKeyDefinition, type IndexDefinition, defineSchema, validateSeedData };
|
|
29
|
+
//# sourceMappingURL=index.d.mts.map
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { stat } from "node:fs/promises";
|
|
2
|
+
import { basename, dirname } from "node:path";
|
|
3
|
+
import { ErrorFormatter, LinesDB, defineSchema } from "@toiroakr/lines-db";
|
|
4
|
+
|
|
5
|
+
//#region src/seed/index.ts
|
|
6
|
+
/**
|
|
7
|
+
* Seed integration module for generated seed code.
|
|
8
|
+
*
|
|
9
|
+
* Re-exports `@toiroakr/lines-db` through a single import path
|
|
10
|
+
* to avoid phantom dependency issues with pnpm, and provides
|
|
11
|
+
* seed-specific utility functions used by the code generator.
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Validate JSONL seed data against schema definitions.
|
|
15
|
+
* Resolves the given path (directory or `.jsonl` file), runs LinesDB
|
|
16
|
+
* validation, and returns formatted output and error messages.
|
|
17
|
+
* @param options - Validation options including path and verbose flag
|
|
18
|
+
* @returns Validation result with output messages and optional error details
|
|
19
|
+
*/
|
|
20
|
+
async function validateSeedData(options) {
|
|
21
|
+
const { path: resolvedPath, verbose = false } = options;
|
|
22
|
+
const stats = await stat(resolvedPath);
|
|
23
|
+
let dataDir;
|
|
24
|
+
let tableName;
|
|
25
|
+
if (stats.isDirectory()) dataDir = resolvedPath;
|
|
26
|
+
else if (stats.isFile() && resolvedPath.endsWith(".jsonl")) {
|
|
27
|
+
dataDir = dirname(resolvedPath);
|
|
28
|
+
tableName = basename(resolvedPath, ".jsonl");
|
|
29
|
+
} else throw new Error(`Invalid path: ${resolvedPath}. Must be a directory or .jsonl file.`);
|
|
30
|
+
const db = LinesDB.create({ dataDir });
|
|
31
|
+
let result;
|
|
32
|
+
try {
|
|
33
|
+
result = await db.initialize({
|
|
34
|
+
tableName,
|
|
35
|
+
detailedValidate: true
|
|
36
|
+
});
|
|
37
|
+
} finally {
|
|
38
|
+
await db.close();
|
|
39
|
+
}
|
|
40
|
+
const outputLines = [];
|
|
41
|
+
if (result.warnings.length > 0) {
|
|
42
|
+
for (const warning of result.warnings) outputLines.push(`⚠ ${warning}`);
|
|
43
|
+
outputLines.push("");
|
|
44
|
+
}
|
|
45
|
+
if (result.valid) {
|
|
46
|
+
outputLines.push("✓ All records are valid");
|
|
47
|
+
return {
|
|
48
|
+
valid: true,
|
|
49
|
+
output: outputLines.join("\n")
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
const formatter = new ErrorFormatter({ verbose });
|
|
53
|
+
const errorLines = [];
|
|
54
|
+
const errorsByFile = /* @__PURE__ */ new Map();
|
|
55
|
+
for (const error of result.errors) {
|
|
56
|
+
const fileErrors = errorsByFile.get(error.file) || [];
|
|
57
|
+
fileErrors.push(error);
|
|
58
|
+
errorsByFile.set(error.file, fileErrors);
|
|
59
|
+
}
|
|
60
|
+
for (const [file, fileErrors] of errorsByFile) {
|
|
61
|
+
errorLines.push(formatter.formatErrorHeader(fileErrors.length, file));
|
|
62
|
+
errorLines.push("");
|
|
63
|
+
const validationErrors = fileErrors.filter((e) => e.type !== "foreignKey" || !e.foreignKeyError);
|
|
64
|
+
const foreignKeyErrors = fileErrors.filter((e) => e.type === "foreignKey" && e.foreignKeyError);
|
|
65
|
+
if (validationErrors.length > 0) errorLines.push(formatter.formatValidationErrors(validationErrors.map((e) => ({
|
|
66
|
+
file: e.file,
|
|
67
|
+
rowIndex: e.rowIndex,
|
|
68
|
+
issues: e.issues
|
|
69
|
+
}))));
|
|
70
|
+
for (const fkError of foreignKeyErrors) if (fkError.foreignKeyError) errorLines.push(formatter.formatForeignKeyError({
|
|
71
|
+
file: fkError.file,
|
|
72
|
+
rowIndex: fkError.rowIndex,
|
|
73
|
+
column: fkError.foreignKeyError.column,
|
|
74
|
+
value: fkError.foreignKeyError.value,
|
|
75
|
+
referencedTable: fkError.foreignKeyError.referencedTable,
|
|
76
|
+
referencedColumn: fkError.foreignKeyError.referencedColumn
|
|
77
|
+
}));
|
|
78
|
+
errorLines.push("");
|
|
79
|
+
}
|
|
80
|
+
return {
|
|
81
|
+
valid: false,
|
|
82
|
+
output: outputLines.join("\n"),
|
|
83
|
+
error: errorLines.join("\n")
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
//#endregion
|
|
88
|
+
export { defineSchema, validateSeedData };
|
|
89
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/seed/index.ts"],"sourcesContent":["/**\n * Seed integration module for generated seed code.\n *\n * Re-exports `@toiroakr/lines-db` through a single import path\n * to avoid phantom dependency issues with pnpm, and provides\n * seed-specific utility functions used by the code generator.\n */\n\nimport { stat } from \"node:fs/promises\";\nimport { basename, dirname } from \"node:path\";\nimport { LinesDB, ErrorFormatter } from \"@toiroakr/lines-db\";\n\nexport { defineSchema } from \"@toiroakr/lines-db\";\nexport type { ForeignKeyDefinition, IndexDefinition } from \"@toiroakr/lines-db\";\n\ntype ValidateSeedDataOptions = {\n /** Resolved absolute path to a data directory or a .jsonl file */\n path: string;\n /** Show verbose error output */\n verbose?: boolean;\n};\n\ntype ValidateSeedResult =\n | { valid: true; output: string }\n | { valid: false; output: string; error: string };\n\n/**\n * Validate JSONL seed data against schema definitions.\n * Resolves the given path (directory or `.jsonl` file), runs LinesDB\n * validation, and returns formatted output and error messages.\n * @param options - Validation options including path and verbose flag\n * @returns Validation result with output messages and optional error details\n */\nexport async function validateSeedData(\n options: ValidateSeedDataOptions,\n): Promise<ValidateSeedResult> {\n const { path: resolvedPath, verbose = false } = options;\n\n const stats = await stat(resolvedPath);\n let dataDir: string;\n let tableName: string | undefined;\n if (stats.isDirectory()) {\n dataDir = resolvedPath;\n } else if (stats.isFile() && resolvedPath.endsWith(\".jsonl\")) {\n dataDir = dirname(resolvedPath);\n tableName = basename(resolvedPath, \".jsonl\");\n } else {\n throw new Error(`Invalid path: ${resolvedPath}. Must be a directory or .jsonl file.`);\n }\n\n const db = LinesDB.create({ dataDir });\n let result;\n try {\n result = await db.initialize({ tableName, detailedValidate: true });\n } finally {\n await db.close();\n }\n\n const outputLines: string[] = [];\n\n if (result.warnings.length > 0) {\n for (const warning of result.warnings) {\n outputLines.push(`⚠ ${warning}`);\n }\n outputLines.push(\"\");\n }\n\n if (result.valid) {\n outputLines.push(\"✓ All records are valid\");\n return { valid: true, output: outputLines.join(\"\\n\") };\n }\n\n const formatter = new ErrorFormatter({ verbose });\n const errorLines: string[] = [];\n const errorsByFile = new Map<string, typeof result.errors>();\n for (const error of result.errors) {\n const fileErrors = errorsByFile.get(error.file) || [];\n fileErrors.push(error);\n errorsByFile.set(error.file, fileErrors);\n }\n for (const [file, fileErrors] of errorsByFile) {\n errorLines.push(formatter.formatErrorHeader(fileErrors.length, file));\n errorLines.push(\"\");\n const validationErrors = fileErrors.filter(\n (e) => e.type !== \"foreignKey\" || !e.foreignKeyError,\n );\n const foreignKeyErrors = fileErrors.filter((e) => e.type === \"foreignKey\" && e.foreignKeyError);\n if (validationErrors.length > 0) {\n errorLines.push(\n formatter.formatValidationErrors(\n validationErrors.map((e) => ({\n file: e.file,\n rowIndex: e.rowIndex,\n issues: e.issues,\n })),\n ),\n );\n }\n for (const fkError of foreignKeyErrors) {\n if (fkError.foreignKeyError) {\n errorLines.push(\n formatter.formatForeignKeyError({\n file: fkError.file,\n rowIndex: fkError.rowIndex,\n column: fkError.foreignKeyError.column,\n value: fkError.foreignKeyError.value,\n referencedTable: fkError.foreignKeyError.referencedTable,\n referencedColumn: fkError.foreignKeyError.referencedColumn,\n }),\n );\n }\n }\n errorLines.push(\"\");\n }\n\n return { valid: false, output: outputLines.join(\"\\n\"), error: errorLines.join(\"\\n\") };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAiCA,eAAsB,iBACpB,SAC6B;CAC7B,MAAM,EAAE,MAAM,cAAc,UAAU,UAAU;CAEhD,MAAM,QAAQ,MAAM,KAAK,aAAa;CACtC,IAAI;CACJ,IAAI;AACJ,KAAI,MAAM,aAAa,CACrB,WAAU;UACD,MAAM,QAAQ,IAAI,aAAa,SAAS,SAAS,EAAE;AAC5D,YAAU,QAAQ,aAAa;AAC/B,cAAY,SAAS,cAAc,SAAS;OAE5C,OAAM,IAAI,MAAM,iBAAiB,aAAa,uCAAuC;CAGvF,MAAM,KAAK,QAAQ,OAAO,EAAE,SAAS,CAAC;CACtC,IAAI;AACJ,KAAI;AACF,WAAS,MAAM,GAAG,WAAW;GAAE;GAAW,kBAAkB;GAAM,CAAC;WAC3D;AACR,QAAM,GAAG,OAAO;;CAGlB,MAAM,cAAwB,EAAE;AAEhC,KAAI,OAAO,SAAS,SAAS,GAAG;AAC9B,OAAK,MAAM,WAAW,OAAO,SAC3B,aAAY,KAAK,KAAK,UAAU;AAElC,cAAY,KAAK,GAAG;;AAGtB,KAAI,OAAO,OAAO;AAChB,cAAY,KAAK,0BAA0B;AAC3C,SAAO;GAAE,OAAO;GAAM,QAAQ,YAAY,KAAK,KAAK;GAAE;;CAGxD,MAAM,YAAY,IAAI,eAAe,EAAE,SAAS,CAAC;CACjD,MAAM,aAAuB,EAAE;CAC/B,MAAM,+BAAe,IAAI,KAAmC;AAC5D,MAAK,MAAM,SAAS,OAAO,QAAQ;EACjC,MAAM,aAAa,aAAa,IAAI,MAAM,KAAK,IAAI,EAAE;AACrD,aAAW,KAAK,MAAM;AACtB,eAAa,IAAI,MAAM,MAAM,WAAW;;AAE1C,MAAK,MAAM,CAAC,MAAM,eAAe,cAAc;AAC7C,aAAW,KAAK,UAAU,kBAAkB,WAAW,QAAQ,KAAK,CAAC;AACrE,aAAW,KAAK,GAAG;EACnB,MAAM,mBAAmB,WAAW,QACjC,MAAM,EAAE,SAAS,gBAAgB,CAAC,EAAE,gBACtC;EACD,MAAM,mBAAmB,WAAW,QAAQ,MAAM,EAAE,SAAS,gBAAgB,EAAE,gBAAgB;AAC/F,MAAI,iBAAiB,SAAS,EAC5B,YAAW,KACT,UAAU,uBACR,iBAAiB,KAAK,OAAO;GAC3B,MAAM,EAAE;GACR,UAAU,EAAE;GACZ,QAAQ,EAAE;GACX,EAAE,CACJ,CACF;AAEH,OAAK,MAAM,WAAW,iBACpB,KAAI,QAAQ,gBACV,YAAW,KACT,UAAU,sBAAsB;GAC9B,MAAM,QAAQ;GACd,UAAU,QAAQ;GAClB,QAAQ,QAAQ,gBAAgB;GAChC,OAAO,QAAQ,gBAAgB;GAC/B,iBAAiB,QAAQ,gBAAgB;GACzC,kBAAkB,QAAQ,gBAAgB;GAC3C,CAAC,CACH;AAGL,aAAW,KAAK,GAAG;;AAGrB,QAAO;EAAE,OAAO;EAAO,QAAQ,YAAY,KAAK,KAAK;EAAE,OAAO,WAAW,KAAK,KAAK;EAAE"}
|
|
@@ -1,7 +1,17 @@
|
|
|
1
|
-
import { t as isPluginGeneratedType } from "./types-CBTSg-LK.mjs";
|
|
2
1
|
import * as path from "pathe";
|
|
3
2
|
import ml from "multiline-ts";
|
|
4
3
|
|
|
4
|
+
//#region src/types/tailordb.ts
|
|
5
|
+
/**
|
|
6
|
+
* Checks if a type source is generated by a plugin.
|
|
7
|
+
* @param source - The type source entry to check.
|
|
8
|
+
* @returns True if the source was generated by a plugin.
|
|
9
|
+
*/
|
|
10
|
+
function isPluginGeneratedType(source) {
|
|
11
|
+
return source.pluginId !== void 0;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
//#endregion
|
|
5
15
|
//#region src/plugin/builtin/seed/idp-user-processor.ts
|
|
6
16
|
/**
|
|
7
17
|
* Processes auth configuration to generate IdP user seed metadata
|
|
@@ -109,8 +119,8 @@ function generateIdpTruncateScriptCode(idpNamespace) {
|
|
|
109
119
|
function generateIdpUserSchemaFile(usernameField, userTypeName) {
|
|
110
120
|
return ml`
|
|
111
121
|
import { t } from "@tailor-platform/sdk";
|
|
122
|
+
import { defineSchema } from "@tailor-platform/sdk/seed";
|
|
112
123
|
import { createStandardSchema } from "@tailor-platform/sdk/test";
|
|
113
|
-
import { defineSchema } from "@toiroakr/lines-db";
|
|
114
124
|
|
|
115
125
|
const schemaType = t.object({
|
|
116
126
|
name: t.string(),
|
|
@@ -260,8 +270,8 @@ function generateLinesDbSchemaFile(metadata, importPath) {
|
|
|
260
270
|
const { exportName, optionalFields, omitFields, foreignKeys, indexes } = metadata;
|
|
261
271
|
return ml`
|
|
262
272
|
import { t } from "@tailor-platform/sdk";
|
|
273
|
+
import { defineSchema } from "@tailor-platform/sdk/seed";
|
|
263
274
|
import { createTailorDBHook, createStandardSchema } from "@tailor-platform/sdk/test";
|
|
264
|
-
import { defineSchema } from "@toiroakr/lines-db";
|
|
265
275
|
import { ${exportName} } from "${importPath}";
|
|
266
276
|
|
|
267
277
|
${ml`
|
|
@@ -301,8 +311,8 @@ function generateLinesDbSchemaFileWithPluginAPI(metadata, params) {
|
|
|
301
311
|
import { join } from "node:path";
|
|
302
312
|
import { t } from "@tailor-platform/sdk";
|
|
303
313
|
import { getGeneratedType } from "@tailor-platform/sdk/plugin";
|
|
314
|
+
import { defineSchema } from "@tailor-platform/sdk/seed";
|
|
304
315
|
import { createTailorDBHook, createStandardSchema } from "@tailor-platform/sdk/test";
|
|
305
|
-
import { defineSchema } from "@toiroakr/lines-db";
|
|
306
316
|
import { ${pluginSource.originalExportName} } from "${originalImportPath}";
|
|
307
317
|
|
|
308
318
|
const configPath = join(import.meta.dirname, "${configImportPath}");
|
|
@@ -322,8 +332,8 @@ function generateLinesDbSchemaFileWithPluginAPI(metadata, params) {
|
|
|
322
332
|
import { join } from "node:path";
|
|
323
333
|
import { t } from "@tailor-platform/sdk";
|
|
324
334
|
import { getGeneratedType } from "@tailor-platform/sdk/plugin";
|
|
335
|
+
import { defineSchema } from "@tailor-platform/sdk/seed";
|
|
325
336
|
import { createTailorDBHook, createStandardSchema } from "@tailor-platform/sdk/test";
|
|
326
|
-
import { defineSchema } from "@toiroakr/lines-db";
|
|
327
337
|
|
|
328
338
|
const configPath = join(import.meta.dirname, "${configImportPath}");
|
|
329
339
|
const ${exportName} = await getGeneratedType(configPath, "${pluginSource.pluginId}", null, "${pluginSource.generatedTypeKind}");
|
|
@@ -552,7 +562,7 @@ function generateExecScript(defaultMachineUserName, relativeConfigPath, namespac
|
|
|
552
562
|
}).join(",\n");
|
|
553
563
|
return ml`
|
|
554
564
|
import { readFileSync } from "node:fs";
|
|
555
|
-
import { join } from "node:path";
|
|
565
|
+
import { join, isAbsolute } from "node:path";
|
|
556
566
|
import { parseArgs, styleText } from "node:util";
|
|
557
567
|
import { createInterface } from "node:readline";
|
|
558
568
|
import {
|
|
@@ -566,6 +576,58 @@ function generateExecScript(defaultMachineUserName, relativeConfigPath, namespac
|
|
|
566
576
|
loadWorkspaceId,
|
|
567
577
|
} from "@tailor-platform/sdk/cli";
|
|
568
578
|
|
|
579
|
+
// Handle "validate" subcommand before parseArgs
|
|
580
|
+
const subcommand = process.argv[2];
|
|
581
|
+
if (subcommand === "validate") {
|
|
582
|
+
const { validateSeedData } = await import("@tailor-platform/sdk/seed");
|
|
583
|
+
const validateArgs = parseArgs({
|
|
584
|
+
args: process.argv.slice(3),
|
|
585
|
+
options: {
|
|
586
|
+
verbose: { type: "boolean", short: "v", default: false },
|
|
587
|
+
help: { type: "boolean", short: "h", default: false },
|
|
588
|
+
},
|
|
589
|
+
allowPositionals: true,
|
|
590
|
+
});
|
|
591
|
+
|
|
592
|
+
if (validateArgs.values.help) {
|
|
593
|
+
console.log(\`
|
|
594
|
+
Usage: node exec.mjs validate [options] [path]
|
|
595
|
+
|
|
596
|
+
Validate JSONL seed data against schema definitions.
|
|
597
|
+
|
|
598
|
+
Arguments:
|
|
599
|
+
path File or directory to validate (default: ./data)
|
|
600
|
+
|
|
601
|
+
Options:
|
|
602
|
+
-v, --verbose Show verbose error output
|
|
603
|
+
-h, --help Show help
|
|
604
|
+
|
|
605
|
+
Examples:
|
|
606
|
+
node exec.mjs validate # Validate all seed data
|
|
607
|
+
node exec.mjs validate ./data/User.jsonl # Validate specific file
|
|
608
|
+
node exec.mjs validate -v # Verbose error output
|
|
609
|
+
\`);
|
|
610
|
+
process.exit(0);
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
const configDir = import.meta.dirname;
|
|
614
|
+
const targetPath = validateArgs.positionals[0] || join(configDir, "data");
|
|
615
|
+
const resolvedPath = isAbsolute(targetPath) ? targetPath : join(process.cwd(), targetPath);
|
|
616
|
+
|
|
617
|
+
try {
|
|
618
|
+
const result = await validateSeedData({ path: resolvedPath, verbose: validateArgs.values.verbose });
|
|
619
|
+
if (result.output) console.log(result.output);
|
|
620
|
+
if (!result.valid) {
|
|
621
|
+
console.error(result.error);
|
|
622
|
+
process.exit(1);
|
|
623
|
+
}
|
|
624
|
+
process.exit(0);
|
|
625
|
+
} catch (error) {
|
|
626
|
+
console.error(styleText("red", \`Error: \${error instanceof Error ? error.message : String(error)}\`));
|
|
627
|
+
process.exit(1);
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
|
|
569
631
|
// Parse command-line arguments
|
|
570
632
|
const { values, positionals } = parseArgs({
|
|
571
633
|
options: {
|
|
@@ -582,7 +644,10 @@ function generateExecScript(defaultMachineUserName, relativeConfigPath, namespac
|
|
|
582
644
|
|
|
583
645
|
if (values.help) {
|
|
584
646
|
console.log(\`
|
|
585
|
-
Usage: node exec.mjs [options] [types...]
|
|
647
|
+
Usage: node exec.mjs [command] [options] [types...]
|
|
648
|
+
|
|
649
|
+
Commands:
|
|
650
|
+
validate [path] Validate seed data against schema (default: ./data)
|
|
586
651
|
|
|
587
652
|
Options:
|
|
588
653
|
-m, --machine-user <name> Machine user name for authentication (required if not configured)
|
|
@@ -602,6 +667,8 @@ function generateExecScript(defaultMachineUserName, relativeConfigPath, namespac
|
|
|
602
667
|
node exec.mjs --truncate --yes # Truncate all tables without confirmation, then seed all
|
|
603
668
|
node exec.mjs --truncate --namespace <namespace> # Truncate tailordb, then seed tailordb
|
|
604
669
|
node exec.mjs --truncate User Order # Truncate User and Order, then seed them
|
|
670
|
+
node exec.mjs validate # Validate all seed data
|
|
671
|
+
node exec.mjs validate ./data/User.jsonl # Validate specific file
|
|
605
672
|
\`);
|
|
606
673
|
process.exit(0);
|
|
607
674
|
}
|
|
@@ -1046,5 +1113,5 @@ function seedPlugin(options) {
|
|
|
1046
1113
|
}
|
|
1047
1114
|
|
|
1048
1115
|
//#endregion
|
|
1049
|
-
export { seedPlugin as n, SeedGeneratorID as t };
|
|
1050
|
-
//# sourceMappingURL=seed-
|
|
1116
|
+
export { seedPlugin as n, isPluginGeneratedType as r, SeedGeneratorID as t };
|
|
1117
|
+
//# sourceMappingURL=seed-DkKAheSe.mjs.map
|