convex-verify 0.1.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 (43) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +403 -0
  3. package/dist/configs/index.d.mts +51 -0
  4. package/dist/configs/index.d.ts +51 -0
  5. package/dist/configs/index.js +38 -0
  6. package/dist/configs/index.js.map +1 -0
  7. package/dist/configs/index.mjs +11 -0
  8. package/dist/configs/index.mjs.map +1 -0
  9. package/dist/core/index.d.mts +58 -0
  10. package/dist/core/index.d.ts +58 -0
  11. package/dist/core/index.js +144 -0
  12. package/dist/core/index.js.map +1 -0
  13. package/dist/core/index.mjs +113 -0
  14. package/dist/core/index.mjs.map +1 -0
  15. package/dist/index.d.mts +9 -0
  16. package/dist/index.d.ts +9 -0
  17. package/dist/index.js +442 -0
  18. package/dist/index.js.map +1 -0
  19. package/dist/index.mjs +404 -0
  20. package/dist/index.mjs.map +1 -0
  21. package/dist/plugin-BjJ7yjrc.d.ts +141 -0
  22. package/dist/plugin-mHMV2-SG.d.mts +141 -0
  23. package/dist/plugins/index.d.mts +85 -0
  24. package/dist/plugins/index.d.ts +85 -0
  25. package/dist/plugins/index.js +317 -0
  26. package/dist/plugins/index.js.map +1 -0
  27. package/dist/plugins/index.mjs +289 -0
  28. package/dist/plugins/index.mjs.map +1 -0
  29. package/dist/transforms/index.d.mts +38 -0
  30. package/dist/transforms/index.d.ts +38 -0
  31. package/dist/transforms/index.js +46 -0
  32. package/dist/transforms/index.js.map +1 -0
  33. package/dist/transforms/index.mjs +19 -0
  34. package/dist/transforms/index.mjs.map +1 -0
  35. package/dist/types-_64SXyva.d.mts +151 -0
  36. package/dist/types-_64SXyva.d.ts +151 -0
  37. package/dist/utils/index.d.mts +36 -0
  38. package/dist/utils/index.d.ts +36 -0
  39. package/dist/utils/index.js +113 -0
  40. package/dist/utils/index.js.map +1 -0
  41. package/dist/utils/index.mjs +83 -0
  42. package/dist/utils/index.mjs.map +1 -0
  43. package/package.json +75 -0
@@ -0,0 +1,58 @@
1
+ import { SchemaDefinition, GenericSchema, DataModelFromSchemaDefinition, TableNamesInDataModel, DocumentByName, GenericMutationCtx, WithoutSystemFields } from 'convex/server';
2
+ import { GenericId } from 'convex/values';
3
+ import { a as ValidatePlugin } from '../plugin-BjJ7yjrc.js';
4
+ export { V as ValidateContext, b as ValidatePluginRecord, c as createValidatePlugin, i as isValidatePlugin, r as runValidatePlugins } from '../plugin-BjJ7yjrc.js';
5
+ import { V as VerifyConfigInput, H as HasKey, M as MakeOptional, b as OptionalKeysForTable, a as OnFailCallback, d as ProtectedKeysForTable } from '../types-_64SXyva.js';
6
+ export { B as BaseConfigReturn, k as DMGeneric, D as DefaultValuesConfigData, l as DefaultValuesInput, E as ExtractDefaultValuesConfig, c as ExtractProtectedColumnsConfig, I as IndexConfigBaseOptions, j as IndexConfigEntry, N as NormalizedIndexConfig, O as OnFailArgs, P as Prettify, m as ProtectedColumnsInput, g as UniqueColumnConfigData, h as UniqueColumnConfigEntry, i as UniqueColumnConfigOptions, U as UniqueRowConfigData, e as UniqueRowConfigEntry, f as UniqueRowConfigOptions, n as normalizeIndexConfigEntry } from '../types-_64SXyva.js';
7
+
8
+ /**
9
+ * Extended config input that includes optional validate plugins
10
+ */
11
+ type VerifyConfigInputWithPlugins = VerifyConfigInput & {
12
+ /**
13
+ * Validate plugins to run after transforms.
14
+ * These plugins can validate data but don't affect input types.
15
+ */
16
+ plugins?: ValidatePlugin[];
17
+ };
18
+ /**
19
+ * Configure type-safe insert and patch functions with validation and transforms.
20
+ *
21
+ * @param schema - Your Convex schema definition
22
+ * @param configs - Configuration object with transforms, configs, and plugins
23
+ * @returns Object with `insert`, `patch`, and `dangerouslyPatch` functions
24
+ *
25
+ * @example
26
+ * ```ts
27
+ * import { verifyConfig, defaultValuesConfig, protectedColumnsConfig, uniqueRowConfig } from 'convex-verify';
28
+ * import schema from './schema';
29
+ *
30
+ * export const { insert, patch, dangerouslyPatch } = verifyConfig(schema, {
31
+ * defaultValues: defaultValuesConfig(schema, () => ({
32
+ * posts: { status: 'draft', views: 0 },
33
+ * })),
34
+ * protectedColumns: protectedColumnsConfig(schema, {
35
+ * posts: ['authorId'],
36
+ * }),
37
+ * plugins: [
38
+ * uniqueRowConfig(schema, {
39
+ * posts: ['by_slug'],
40
+ * }),
41
+ * ],
42
+ * });
43
+ * ```
44
+ */
45
+ declare const verifyConfig: <S extends SchemaDefinition<GenericSchema, boolean>, DataModel extends DataModelFromSchemaDefinition<S>, const VC extends VerifyConfigInputWithPlugins>(_schema: S, configs: VC) => {
46
+ insert: <const TN extends TableNamesInDataModel<DataModel>, const D extends DocumentByName<DataModel, TN>>(ctx: Omit<GenericMutationCtx<DataModel>, never>, tableName: TN, data: HasKey<VC, "defaultValues"> extends true ? MakeOptional<WithoutSystemFields<D>, OptionalKeysForTable<VC, TN> & keyof WithoutSystemFields<D>> : WithoutSystemFields<D>, options?: {
47
+ onFail?: OnFailCallback<D>;
48
+ }) => Promise<GenericId<TN>>;
49
+ patch: <const TN extends TableNamesInDataModel<DataModel>, const D_1 extends DocumentByName<DataModel, TN>>(ctx: Omit<GenericMutationCtx<DataModel>, never>, tableName: TN, id: GenericId<TN>, data: HasKey<VC, "protectedColumns"> extends true ? Omit<Partial<WithoutSystemFields<D_1>>, ProtectedKeysForTable<VC, TN> & keyof WithoutSystemFields<D_1>> : Partial<WithoutSystemFields<D_1>>, options?: {
50
+ onFail?: OnFailCallback<D_1>;
51
+ }) => Promise<void>;
52
+ dangerouslyPatch: <const TN extends TableNamesInDataModel<DataModel>, const D_2 extends DocumentByName<DataModel, TN>>(ctx: Omit<GenericMutationCtx<DataModel>, never>, tableName: TN, id: GenericId<TN>, data: Partial<WithoutSystemFields<D_2>>, options?: {
53
+ onFail?: OnFailCallback<D_2>;
54
+ }) => Promise<void>;
55
+ configs: VC;
56
+ };
57
+
58
+ export { HasKey, MakeOptional, OnFailCallback, OptionalKeysForTable, ProtectedKeysForTable, ValidatePlugin, VerifyConfigInput, verifyConfig };
@@ -0,0 +1,144 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/core/index.ts
21
+ var core_exports = {};
22
+ __export(core_exports, {
23
+ createValidatePlugin: () => createValidatePlugin,
24
+ isValidatePlugin: () => isValidatePlugin,
25
+ normalizeIndexConfigEntry: () => normalizeIndexConfigEntry,
26
+ runValidatePlugins: () => runValidatePlugins,
27
+ verifyConfig: () => verifyConfig
28
+ });
29
+ module.exports = __toCommonJS(core_exports);
30
+
31
+ // src/core/plugin.ts
32
+ function isValidatePlugin(obj) {
33
+ return typeof obj === "object" && obj !== null && "_type" in obj && typeof obj._type === "string" && "verify" in obj && typeof obj.verify === "object";
34
+ }
35
+ async function runValidatePlugins(plugins, context, data) {
36
+ let result = data;
37
+ for (const plugin of plugins) {
38
+ const verifyFn = context.operation === "insert" ? plugin.verify.insert : plugin.verify.patch;
39
+ if (verifyFn) {
40
+ result = await verifyFn(context, result);
41
+ }
42
+ }
43
+ return result;
44
+ }
45
+ function createValidatePlugin(type, config, verify) {
46
+ return {
47
+ _type: type,
48
+ config,
49
+ verify
50
+ };
51
+ }
52
+
53
+ // src/core/verifyConfig.ts
54
+ var verifyConfig = (_schema, configs) => {
55
+ const validatePlugins = configs.plugins ?? [];
56
+ const insert = async (ctx, tableName, data, options) => {
57
+ let verifiedData = data;
58
+ if (configs.defaultValues) {
59
+ verifiedData = await configs.defaultValues.verify(tableName, verifiedData);
60
+ }
61
+ if (validatePlugins.length > 0) {
62
+ verifiedData = await runValidatePlugins(
63
+ validatePlugins,
64
+ {
65
+ ctx,
66
+ tableName,
67
+ operation: "insert",
68
+ onFail: options?.onFail,
69
+ schema: _schema
70
+ },
71
+ verifiedData
72
+ );
73
+ }
74
+ return await ctx.db.insert(tableName, verifiedData);
75
+ };
76
+ const patch = async (ctx, tableName, id, data, options) => {
77
+ let verifiedData = data;
78
+ if (validatePlugins.length > 0) {
79
+ verifiedData = await runValidatePlugins(
80
+ validatePlugins,
81
+ {
82
+ ctx,
83
+ tableName,
84
+ operation: "patch",
85
+ patchId: id,
86
+ onFail: options?.onFail,
87
+ schema: _schema
88
+ },
89
+ verifiedData
90
+ );
91
+ }
92
+ await ctx.db.patch(id, verifiedData);
93
+ };
94
+ const dangerouslyPatch = async (ctx, tableName, id, data, options) => {
95
+ let verifiedData = data;
96
+ if (validatePlugins.length > 0) {
97
+ verifiedData = await runValidatePlugins(
98
+ validatePlugins,
99
+ {
100
+ ctx,
101
+ tableName,
102
+ operation: "patch",
103
+ patchId: id,
104
+ onFail: options?.onFail,
105
+ schema: _schema
106
+ },
107
+ verifiedData
108
+ );
109
+ }
110
+ await ctx.db.patch(id, verifiedData);
111
+ };
112
+ return {
113
+ insert,
114
+ patch,
115
+ dangerouslyPatch,
116
+ // Expose configs for debugging/advanced usage
117
+ configs
118
+ };
119
+ };
120
+
121
+ // src/core/types.ts
122
+ function normalizeIndexConfigEntry(entry, defaultIdentifiers = ["_id"]) {
123
+ if (typeof entry === "string") {
124
+ return {
125
+ index: entry,
126
+ identifiers: defaultIdentifiers
127
+ };
128
+ }
129
+ const { index, identifiers, ...rest } = entry;
130
+ return {
131
+ index: String(index),
132
+ identifiers: identifiers?.map(String) ?? defaultIdentifiers,
133
+ ...rest
134
+ };
135
+ }
136
+ // Annotate the CommonJS export names for ESM import in node:
137
+ 0 && (module.exports = {
138
+ createValidatePlugin,
139
+ isValidatePlugin,
140
+ normalizeIndexConfigEntry,
141
+ runValidatePlugins,
142
+ verifyConfig
143
+ });
144
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/core/index.ts","../../src/core/plugin.ts","../../src/core/verifyConfig.ts","../../src/core/types.ts"],"sourcesContent":["// Main verifyConfig function\nexport { verifyConfig } from './verifyConfig';\n\n// Plugin system\nexport { createValidatePlugin, isValidatePlugin, runValidatePlugins } from './plugin';\nexport type { ValidateContext, ValidatePlugin, ValidatePluginRecord } from './plugin';\n\n// All types\nexport type {\n\t// Utility types\n\tPrettify,\n\tMakeOptional,\n\t// Base types\n\tBaseConfigReturn,\n\t// OnFail types\n\tOnFailArgs,\n\tOnFailCallback,\n\t// Config data types\n\tDMGeneric,\n\tDefaultValuesConfigData,\n\t// Index-based config types\n\tIndexConfigBaseOptions,\n\tIndexConfigEntry,\n\tNormalizedIndexConfig,\n\t// UniqueRow types\n\tUniqueRowConfigOptions,\n\tUniqueRowConfigEntry,\n\tUniqueRowConfigData,\n\t// UniqueColumn types\n\tUniqueColumnConfigOptions,\n\tUniqueColumnConfigEntry,\n\tUniqueColumnConfigData,\n\t// Input types\n\tDefaultValuesInput,\n\tProtectedColumnsInput,\n\t// VerifyConfig types\n\tVerifyConfigInput,\n\t// Type extraction helpers\n\tExtractDefaultValuesConfig,\n\tOptionalKeysForTable,\n\tHasKey,\n\tExtractProtectedColumnsConfig,\n\tProtectedKeysForTable,\n} from './types';\n\n// Utility function\nexport { normalizeIndexConfigEntry } from './types';\n","import { GenericMutationCtx, GenericSchema, SchemaDefinition } from 'convex/server';\nimport { GenericId } from 'convex/values';\n\nimport { OnFailCallback } from './types';\n\n// =============================================================================\n// Plugin Types\n// =============================================================================\n\n/**\n * Context passed to validate plugin functions.\n *\n * Provides access to:\n * - `ctx` - Full Convex mutation context (includes `ctx.db` for queries)\n * - `tableName` - The table being operated on\n * - `operation` - 'insert' or 'patch'\n * - `patchId` - Document ID (only for patch operations)\n * - `onFail` - Callback to report validation failures before throwing\n * - `schema` - Optional schema reference (if provided by verifyConfig)\n */\nexport type ValidateContext<TN extends string = string> = {\n\t/** Full Convex mutation context - use ctx.db for database queries */\n\tctx: Omit<GenericMutationCtx<any>, never>;\n\t/** Table name being operated on */\n\ttableName: TN;\n\t/** Operation type: 'insert' or 'patch' */\n\toperation: 'insert' | 'patch';\n\t/** Document ID (only available for patch operations) */\n\tpatchId?: GenericId<any>;\n\t/** Callback for validation failures - call before throwing to provide details */\n\tonFail?: OnFailCallback<any>;\n\t/** Schema reference (if provided to verifyConfig) */\n\tschema?: SchemaDefinition<GenericSchema, boolean>;\n};\n\n/**\n * A validate plugin that can check data during insert/patch operations.\n *\n * Validate plugins:\n * - Run AFTER transform plugins (like defaultValues)\n * - Can be async (use await for API calls, db queries, etc.)\n * - Can throw errors to prevent the operation\n * - Should return the data unchanged (validation only, no transformation)\n * - Do NOT affect the TypeScript types of the input data\n *\n * @example\n * ```ts\n * // Simple sync plugin\n * const requiredFields = createValidatePlugin(\n * 'requiredFields',\n * { fields: ['title', 'content'] },\n * {\n * insert: (context, data) => {\n * for (const field of config.fields) {\n * if (!data[field]) {\n * throw new ConvexError({ message: `Missing required field: ${field}` });\n * }\n * }\n * return data;\n * },\n * }\n * );\n *\n * // Async plugin with database query\n * const checkOwnership = createValidatePlugin(\n * 'checkOwnership',\n * {},\n * {\n * patch: async (context, data) => {\n * const existing = await context.ctx.db.get(context.patchId);\n * if (existing?.ownerId !== getCurrentUserId()) {\n * throw new ConvexError({ message: 'Not authorized' });\n * }\n * return data;\n * },\n * }\n * );\n * ```\n */\nexport interface ValidatePlugin<Type extends string = string, Config = unknown> {\n\t/** Unique identifier for this plugin */\n\treadonly _type: Type;\n\n\t/** Plugin configuration */\n\treadonly config: Config;\n\n\t/** Verify functions for insert and/or patch operations */\n\tverify: {\n\t\t/**\n\t\t * Validate data for insert operations.\n\t\t * Can be sync or async.\n\t\t *\n\t\t * @param context - Plugin context with ctx, tableName, schema, etc.\n\t\t * @param data - The data to validate (after transforms applied)\n\t\t * @returns The data unchanged (or Promise resolving to data)\n\t\t * @throws ConvexError if validation fails\n\t\t */\n\t\tinsert?: (context: ValidateContext, data: any) => Promise<any> | any;\n\n\t\t/**\n\t\t * Validate data for patch operations.\n\t\t * Can be sync or async.\n\t\t *\n\t\t * @param context - Plugin context with ctx, tableName, patchId, schema, etc.\n\t\t * @param data - The partial data to validate\n\t\t * @returns The data unchanged (or Promise resolving to data)\n\t\t * @throws ConvexError if validation fails\n\t\t */\n\t\tpatch?: (context: ValidateContext, data: any) => Promise<any> | any;\n\t};\n}\n\n/**\n * Type guard to check if something is a ValidatePlugin\n */\nexport function isValidatePlugin(obj: unknown): obj is ValidatePlugin {\n\treturn (\n\t\ttypeof obj === 'object' &&\n\t\tobj !== null &&\n\t\t'_type' in obj &&\n\t\ttypeof (obj as any)._type === 'string' &&\n\t\t'verify' in obj &&\n\t\ttypeof (obj as any).verify === 'object'\n\t);\n}\n\n// =============================================================================\n// Plugin Collection Types\n// =============================================================================\n\n/**\n * A collection of validate plugins\n */\nexport type ValidatePluginRecord = Record<string, ValidatePlugin>;\n\n// =============================================================================\n// Plugin Helpers\n// =============================================================================\n\n/**\n * Run all validate plugins for an operation.\n * Plugins are run in order and each receives the output of the previous.\n * All plugin verify functions are awaited (supports async plugins).\n */\nexport async function runValidatePlugins(\n\tplugins: ValidatePlugin[],\n\tcontext: ValidateContext,\n\tdata: any\n): Promise<any> {\n\tlet result = data;\n\n\tfor (const plugin of plugins) {\n\t\tconst verifyFn = context.operation === 'insert' ? plugin.verify.insert : plugin.verify.patch;\n\n\t\tif (verifyFn) {\n\t\t\t// Always await - works for both sync and async functions\n\t\t\tresult = await verifyFn(context, result);\n\t\t}\n\t}\n\n\treturn result;\n}\n\n/**\n * Helper to create a validate plugin with proper typing.\n *\n * @param type - Unique identifier for this plugin type\n * @param config - Plugin configuration data\n * @param verify - Object with insert and/or patch verify functions\n * @returns A ValidatePlugin instance\n *\n * @example\n * ```ts\n * const myPlugin = createValidatePlugin(\n * 'myPlugin',\n * { maxLength: 100 },\n * {\n * insert: async (context, data) => {\n * // Validation logic here\n * return data;\n * },\n * }\n * );\n * ```\n */\nexport function createValidatePlugin<Type extends string, Config>(\n\ttype: Type,\n\tconfig: Config,\n\tverify: ValidatePlugin<Type, Config>['verify']\n): ValidatePlugin<Type, Config> {\n\treturn {\n\t\t_type: type,\n\t\tconfig,\n\t\tverify,\n\t};\n}\n","import {\n\tDataModelFromSchemaDefinition,\n\tDocumentByName,\n\tGenericMutationCtx,\n\tGenericSchema,\n\tSchemaDefinition,\n\tTableNamesInDataModel,\n\tWithoutSystemFields,\n} from 'convex/server';\nimport { GenericId } from 'convex/values';\n\nimport { runValidatePlugins, ValidatePlugin } from './plugin';\nimport {\n\tHasKey,\n\tMakeOptional,\n\tOnFailCallback,\n\tOptionalKeysForTable,\n\tProtectedKeysForTable,\n\tVerifyConfigInput,\n} from './types';\n\n/**\n * Extended config input that includes optional validate plugins\n */\ntype VerifyConfigInputWithPlugins = VerifyConfigInput & {\n\t/**\n\t * Validate plugins to run after transforms.\n\t * These plugins can validate data but don't affect input types.\n\t */\n\tplugins?: ValidatePlugin[];\n};\n\n/**\n * Configure type-safe insert and patch functions with validation and transforms.\n *\n * @param schema - Your Convex schema definition\n * @param configs - Configuration object with transforms, configs, and plugins\n * @returns Object with `insert`, `patch`, and `dangerouslyPatch` functions\n *\n * @example\n * ```ts\n * import { verifyConfig, defaultValuesConfig, protectedColumnsConfig, uniqueRowConfig } from 'convex-verify';\n * import schema from './schema';\n *\n * export const { insert, patch, dangerouslyPatch } = verifyConfig(schema, {\n * defaultValues: defaultValuesConfig(schema, () => ({\n * posts: { status: 'draft', views: 0 },\n * })),\n * protectedColumns: protectedColumnsConfig(schema, {\n * posts: ['authorId'],\n * }),\n * plugins: [\n * uniqueRowConfig(schema, {\n * posts: ['by_slug'],\n * }),\n * ],\n * });\n * ```\n */\nexport const verifyConfig = <\n\tS extends SchemaDefinition<GenericSchema, boolean>,\n\tDataModel extends DataModelFromSchemaDefinition<S>,\n\tconst VC extends VerifyConfigInputWithPlugins,\n>(\n\t_schema: S,\n\tconfigs: VC\n) => {\n\t// Get all validate plugins\n\tconst validatePlugins = configs.plugins ?? [];\n\n\t/**\n\t * Insert a document with all configured verifications applied.\n\t *\n\t * Execution order:\n\t * 1. Transform: defaultValues (makes fields optional, applies defaults)\n\t * 2. Validate: plugins (in order provided)\n\t * 3. Insert into database\n\t */\n\tconst insert = async <\n\t\tconst TN extends TableNamesInDataModel<DataModel>,\n\t\tconst D extends DocumentByName<DataModel, TN>,\n\t>(\n\t\tctx: Omit<GenericMutationCtx<DataModel>, never>,\n\t\ttableName: TN,\n\t\tdata: HasKey<VC, 'defaultValues'> extends true\n\t\t\t? MakeOptional<\n\t\t\t\t\tWithoutSystemFields<D>,\n\t\t\t\t\tOptionalKeysForTable<VC, TN> & keyof WithoutSystemFields<D>\n\t\t\t\t>\n\t\t\t: WithoutSystemFields<D>,\n\t\toptions?: {\n\t\t\tonFail?: OnFailCallback<D>;\n\t\t}\n\t): Promise<GenericId<TN>> => {\n\t\tlet verifiedData = data as WithoutSystemFields<DocumentByName<DataModel, TN>>;\n\n\t\t// === TRANSFORM PHASE ===\n\n\t\t// Apply default values (transforms data)\n\t\tif (configs.defaultValues) {\n\t\t\tverifiedData = await configs.defaultValues.verify(tableName, verifiedData);\n\t\t}\n\n\t\t// === VALIDATE PHASE ===\n\n\t\t// Run all validate plugins\n\t\tif (validatePlugins.length > 0) {\n\t\t\tverifiedData = await runValidatePlugins(\n\t\t\t\tvalidatePlugins,\n\t\t\t\t{\n\t\t\t\t\tctx,\n\t\t\t\t\ttableName: tableName as string,\n\t\t\t\t\toperation: 'insert',\n\t\t\t\t\tonFail: options?.onFail,\n\t\t\t\t\tschema: _schema,\n\t\t\t\t},\n\t\t\t\tverifiedData\n\t\t\t);\n\t\t}\n\n\t\t// Final insert\n\t\treturn await ctx.db.insert(tableName, verifiedData);\n\t};\n\n\t/**\n\t * Patch a document with all configured verifications applied.\n\t *\n\t * Protected columns (if configured) are removed from the input type.\n\t * Use dangerouslyPatch() to bypass protected column restrictions.\n\t *\n\t * Execution order:\n\t * 1. Validate: plugins (in order provided)\n\t * 2. Patch in database\n\t *\n\t * Note: defaultValues is skipped for patch operations\n\t */\n\tconst patch = async <\n\t\tconst TN extends TableNamesInDataModel<DataModel>,\n\t\tconst D extends DocumentByName<DataModel, TN>,\n\t>(\n\t\tctx: Omit<GenericMutationCtx<DataModel>, never>,\n\t\ttableName: TN,\n\t\tid: GenericId<TN>,\n\t\tdata: HasKey<VC, 'protectedColumns'> extends true\n\t\t\t? Omit<\n\t\t\t\t\tPartial<WithoutSystemFields<D>>,\n\t\t\t\t\tProtectedKeysForTable<VC, TN> & keyof WithoutSystemFields<D>\n\t\t\t\t>\n\t\t\t: Partial<WithoutSystemFields<D>>,\n\t\toptions?: {\n\t\t\tonFail?: OnFailCallback<D>;\n\t\t}\n\t): Promise<void> => {\n\t\tlet verifiedData = data as Partial<WithoutSystemFields<DocumentByName<DataModel, TN>>>;\n\n\t\t// === VALIDATE PHASE ===\n\n\t\t// Run all validate plugins\n\t\tif (validatePlugins.length > 0) {\n\t\t\tverifiedData = await runValidatePlugins(\n\t\t\t\tvalidatePlugins,\n\t\t\t\t{\n\t\t\t\t\tctx,\n\t\t\t\t\ttableName: tableName as string,\n\t\t\t\t\toperation: 'patch',\n\t\t\t\t\tpatchId: id,\n\t\t\t\t\tonFail: options?.onFail,\n\t\t\t\t\tschema: _schema,\n\t\t\t\t},\n\t\t\t\tverifiedData\n\t\t\t);\n\t\t}\n\n\t\tawait ctx.db.patch(id, verifiedData);\n\t};\n\n\t/**\n\t * Patch a document bypassing protected column restrictions.\n\t *\n\t * WARNING: This allows patching ANY column, including protected ones.\n\t * Only use this when you explicitly need to update a protected column.\n\t *\n\t * Validation plugins still run - only type restrictions are bypassed.\n\t */\n\tconst dangerouslyPatch = async <\n\t\tconst TN extends TableNamesInDataModel<DataModel>,\n\t\tconst D extends DocumentByName<DataModel, TN>,\n\t>(\n\t\tctx: Omit<GenericMutationCtx<DataModel>, never>,\n\t\ttableName: TN,\n\t\tid: GenericId<TN>,\n\t\tdata: Partial<WithoutSystemFields<D>>,\n\t\toptions?: {\n\t\t\tonFail?: OnFailCallback<D>;\n\t\t}\n\t): Promise<void> => {\n\t\tlet verifiedData = data;\n\n\t\t// === VALIDATE PHASE ===\n\n\t\t// Run all validate plugins (protection is bypassed, but validation still runs)\n\t\tif (validatePlugins.length > 0) {\n\t\t\tverifiedData = await runValidatePlugins(\n\t\t\t\tvalidatePlugins,\n\t\t\t\t{\n\t\t\t\t\tctx,\n\t\t\t\t\ttableName: tableName as string,\n\t\t\t\t\toperation: 'patch',\n\t\t\t\t\tpatchId: id,\n\t\t\t\t\tonFail: options?.onFail,\n\t\t\t\t\tschema: _schema,\n\t\t\t\t},\n\t\t\t\tverifiedData\n\t\t\t);\n\t\t}\n\n\t\tawait ctx.db.patch(id, verifiedData);\n\t};\n\n\treturn {\n\t\tinsert,\n\t\tpatch,\n\t\tdangerouslyPatch,\n\t\t// Expose configs for debugging/advanced usage\n\t\tconfigs,\n\t};\n};\n","import {\n\tDataModelFromSchemaDefinition,\n\tIndexes,\n\tNamedTableInfo,\n\tSchemaDefinition,\n\tWithoutSystemFields,\n} from 'convex/server';\n\n// =============================================================================\n// Utility Types\n// =============================================================================\n\nexport type Prettify<T> = { [K in keyof T]: T[K] } & {};\n\nexport type MakeOptional<T, K extends PropertyKey> = Prettify<\n\tOmit<T, K & keyof T> & Partial<Pick<T, K & keyof T>>\n>;\n\n// =============================================================================\n// Base Types for Config Functions\n// =============================================================================\n\n/**\n * Base interface that all config functions should return.\n * Each config type can have its own `verify` signature and additional properties.\n */\nexport type BaseConfigReturn = {\n\tconfig: Record<string, any>;\n};\n\n// =============================================================================\n// OnFail Types\n// =============================================================================\n\nexport type OnFailArgs<D> = {\n\tuniqueColumn?: {\n\t\tconflictingColumn: keyof D;\n\t\texistingData: D;\n\t};\n\tuniqueRow?: {\n\t\texistingData: D | null;\n\t};\n\teditableColumn?: {\n\t\tremovedColumns: string[];\n\t\tfilteredData: D;\n\t};\n\trequiredColumn?: {\n\t\tmissingColumn: keyof D;\n\t};\n};\n\nexport type OnFailCallback<D> = (args: OnFailArgs<D>) => void;\n\n// =============================================================================\n// Config Data Types (what the user provides)\n// =============================================================================\n\nexport type DMGeneric = DataModelFromSchemaDefinition<SchemaDefinition<any, boolean>>;\n\nexport type DefaultValuesConfigData<DM extends DMGeneric> = {\n\t[K in keyof DM]?: {\n\t\t[column in keyof WithoutSystemFields<DM[K]['document']>]?: DM[K]['document'][column];\n\t};\n};\n\n// =============================================================================\n// Index-Based Config Types (shared between uniqueRow, uniqueColumn, etc.)\n// =============================================================================\n\n/**\n * Base options shared by all index-based config entries.\n * Individual plugins can extend this with their own options.\n */\nexport type IndexConfigBaseOptions = {\n\t/** Additional identifiers to check if the existing row is the same document being updated */\n\tidentifiers?: string[];\n};\n\n/**\n * A config entry that can be either:\n * - A string (index name) for shorthand\n * - An object with `index` and additional options\n *\n * @example\n * ```ts\n * // These are equivalent:\n * 'by_username'\n * { index: 'by_username' }\n *\n * // With options:\n * { index: 'by_username', identifiers: ['_id', 'userId'] }\n * ```\n */\nexport type IndexConfigEntry<\n\tDM extends DMGeneric,\n\tK extends keyof DM,\n\tOptions extends IndexConfigBaseOptions = IndexConfigBaseOptions,\n> =\n\t| keyof Indexes<NamedTableInfo<DM, K>>\n\t| ({\n\t\t\tindex: keyof Indexes<NamedTableInfo<DM, K>>;\n\t\t\tidentifiers?: (keyof NamedTableInfo<DM, K>['document'])[];\n\t } & Omit<Options, 'identifiers'>);\n\n/**\n * Normalized form of an index config entry (always an object)\n */\nexport type NormalizedIndexConfig<Options extends IndexConfigBaseOptions = IndexConfigBaseOptions> =\n\t{\n\t\tindex: string;\n\t\tidentifiers: string[];\n\t} & Omit<Options, 'identifiers'>;\n\n/**\n * Normalize a config entry to always have index and identifiers.\n * Works for both string shorthand and full object configs.\n */\nexport function normalizeIndexConfigEntry<\n\tOptions extends IndexConfigBaseOptions = IndexConfigBaseOptions,\n>(\n\tentry: string | ({ index: string; identifiers?: string[] } & Omit<Options, 'identifiers'>),\n\tdefaultIdentifiers: string[] = ['_id']\n): NormalizedIndexConfig<Options> {\n\tif (typeof entry === 'string') {\n\t\treturn {\n\t\t\tindex: entry,\n\t\t\tidentifiers: defaultIdentifiers,\n\t\t} as NormalizedIndexConfig<Options>;\n\t}\n\n\tconst { index, identifiers, ...rest } = entry;\n\treturn {\n\t\tindex: String(index),\n\t\tidentifiers: identifiers?.map(String) ?? defaultIdentifiers,\n\t\t...rest,\n\t} as NormalizedIndexConfig<Options>;\n}\n\n// =============================================================================\n// UniqueRow Config Types\n// =============================================================================\n\nexport type UniqueRowConfigOptions = IndexConfigBaseOptions & {\n\tqueryExistingWithNullish?: boolean;\n};\n\nexport type UniqueRowConfigEntry<DM extends DMGeneric, K extends keyof DM> = IndexConfigEntry<\n\tDM,\n\tK,\n\tUniqueRowConfigOptions\n>;\n\nexport type UniqueRowConfigData<DM extends DMGeneric> = {\n\t[K in keyof DM]?: UniqueRowConfigEntry<DM, K>[];\n};\n\n// =============================================================================\n// UniqueColumn Config Types\n// =============================================================================\n\nexport type UniqueColumnConfigOptions = IndexConfigBaseOptions;\n\nexport type UniqueColumnConfigEntry<DM extends DMGeneric, K extends keyof DM> = IndexConfigEntry<\n\tDM,\n\tK,\n\tUniqueColumnConfigOptions\n>;\n\nexport type UniqueColumnConfigData<DM extends DMGeneric> = {\n\t[K in keyof DM]?: UniqueColumnConfigEntry<DM, K>[];\n};\n\n// =============================================================================\n// Input Types (loose types for verifyConfig to accept)\n// =============================================================================\n\n/**\n * Loose input types that accept any return from config functions.\n * We use loose types here to avoid complex generic matching,\n * then extract the specific config types using conditional types.\n */\nexport type DefaultValuesInput = {\n\t_type: 'defaultValues';\n\tverify: (tableName: any, data: any) => Promise<any>;\n\tconfig:\n\t\t| Record<string, Record<string, any>>\n\t\t| (() => Record<string, Record<string, any>> | Promise<Record<string, Record<string, any>>>);\n};\n\n/**\n * Loose input type for protectedColumnsConfig return value.\n */\nexport type ProtectedColumnsInput = {\n\t_type: 'protectedColumns';\n\tconfig: Record<string, string[]>;\n};\n\n// =============================================================================\n// Object-Based Types (for verifyConfig)\n// =============================================================================\n\n/**\n * Config input for verifyConfig.\n *\n * - `defaultValues`: Transform plugin that makes fields optional (affects types)\n * - `protectedColumns`: Columns that cannot be patched (affects patch() types)\n * - `plugins`: Array of validate plugins (use for uniqueRow, uniqueColumn, custom plugins, etc.)\n */\nexport type VerifyConfigInput = {\n\tdefaultValues?: DefaultValuesInput;\n\tprotectedColumns?: ProtectedColumnsInput;\n};\n\n// =============================================================================\n// Type Extraction Helpers\n// =============================================================================\n\n/**\n * Extract the config type from defaultValues.config.\n * Handles both direct object and function forms.\n */\nexport type ExtractDefaultValuesConfig<VC> = VC extends {\n\tdefaultValues: { config: infer C };\n}\n\t? C extends () => infer R\n\t\t? Awaited<R>\n\t\t: C\n\t: Record<string, never>;\n\n/**\n * Compute which keys should be optional for a given table based on all configs.\n * Currently only defaultValues affects optionality.\n */\nexport type OptionalKeysForTable<VC, TN> = TN extends keyof ExtractDefaultValuesConfig<VC>\n\t? keyof ExtractDefaultValuesConfig<VC>[TN]\n\t: never;\n\n/**\n * Helper to check if a key exists in a type\n */\nexport type HasKey<T, K extends PropertyKey> = K extends keyof T ? true : false;\n\n// =============================================================================\n// Protected Columns Type Extraction\n// =============================================================================\n\n/**\n * Extract the config type from protectedColumns.config\n */\nexport type ExtractProtectedColumnsConfig<VC> = VC extends {\n\tprotectedColumns: { config: infer C };\n}\n\t? C\n\t: Record<string, never>;\n\n/**\n * Get protected column keys for a specific table.\n * Returns the column names that should be omitted from patch() input.\n */\nexport type ProtectedKeysForTable<VC, TN> = TN extends keyof ExtractProtectedColumnsConfig<VC>\n\t? ExtractProtectedColumnsConfig<VC>[TN] extends readonly (infer K)[]\n\t\t? K\n\t\t: never\n\t: never;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACmHO,SAAS,iBAAiB,KAAqC;AACrE,SACC,OAAO,QAAQ,YACf,QAAQ,QACR,WAAW,OACX,OAAQ,IAAY,UAAU,YAC9B,YAAY,OACZ,OAAQ,IAAY,WAAW;AAEjC;AAoBA,eAAsB,mBACrB,SACA,SACA,MACe;AACf,MAAI,SAAS;AAEb,aAAW,UAAU,SAAS;AAC7B,UAAM,WAAW,QAAQ,cAAc,WAAW,OAAO,OAAO,SAAS,OAAO,OAAO;AAEvF,QAAI,UAAU;AAEb,eAAS,MAAM,SAAS,SAAS,MAAM;AAAA,IACxC;AAAA,EACD;AAEA,SAAO;AACR;AAwBO,SAAS,qBACf,MACA,QACA,QAC+B;AAC/B,SAAO;AAAA,IACN,OAAO;AAAA,IACP;AAAA,IACA;AAAA,EACD;AACD;;;ACxIO,IAAM,eAAe,CAK3B,SACA,YACI;AAEJ,QAAM,kBAAkB,QAAQ,WAAW,CAAC;AAU5C,QAAM,SAAS,OAId,KACA,WACA,MAMA,YAG4B;AAC5B,QAAI,eAAe;AAKnB,QAAI,QAAQ,eAAe;AAC1B,qBAAe,MAAM,QAAQ,cAAc,OAAO,WAAW,YAAY;AAAA,IAC1E;AAKA,QAAI,gBAAgB,SAAS,GAAG;AAC/B,qBAAe,MAAM;AAAA,QACpB;AAAA,QACA;AAAA,UACC;AAAA,UACA;AAAA,UACA,WAAW;AAAA,UACX,QAAQ,SAAS;AAAA,UACjB,QAAQ;AAAA,QACT;AAAA,QACA;AAAA,MACD;AAAA,IACD;AAGA,WAAO,MAAM,IAAI,GAAG,OAAO,WAAW,YAAY;AAAA,EACnD;AAcA,QAAM,QAAQ,OAIb,KACA,WACA,IACA,MAMA,YAGmB;AACnB,QAAI,eAAe;AAKnB,QAAI,gBAAgB,SAAS,GAAG;AAC/B,qBAAe,MAAM;AAAA,QACpB;AAAA,QACA;AAAA,UACC;AAAA,UACA;AAAA,UACA,WAAW;AAAA,UACX,SAAS;AAAA,UACT,QAAQ,SAAS;AAAA,UACjB,QAAQ;AAAA,QACT;AAAA,QACA;AAAA,MACD;AAAA,IACD;AAEA,UAAM,IAAI,GAAG,MAAM,IAAI,YAAY;AAAA,EACpC;AAUA,QAAM,mBAAmB,OAIxB,KACA,WACA,IACA,MACA,YAGmB;AACnB,QAAI,eAAe;AAKnB,QAAI,gBAAgB,SAAS,GAAG;AAC/B,qBAAe,MAAM;AAAA,QACpB;AAAA,QACA;AAAA,UACC;AAAA,UACA;AAAA,UACA,WAAW;AAAA,UACX,SAAS;AAAA,UACT,QAAQ,SAAS;AAAA,UACjB,QAAQ;AAAA,QACT;AAAA,QACA;AAAA,MACD;AAAA,IACD;AAEA,UAAM,IAAI,GAAG,MAAM,IAAI,YAAY;AAAA,EACpC;AAEA,SAAO;AAAA,IACN;AAAA,IACA;AAAA,IACA;AAAA;AAAA,IAEA;AAAA,EACD;AACD;;;AC7GO,SAAS,0BAGf,OACA,qBAA+B,CAAC,KAAK,GACJ;AACjC,MAAI,OAAO,UAAU,UAAU;AAC9B,WAAO;AAAA,MACN,OAAO;AAAA,MACP,aAAa;AAAA,IACd;AAAA,EACD;AAEA,QAAM,EAAE,OAAO,aAAa,GAAG,KAAK,IAAI;AACxC,SAAO;AAAA,IACN,OAAO,OAAO,KAAK;AAAA,IACnB,aAAa,aAAa,IAAI,MAAM,KAAK;AAAA,IACzC,GAAG;AAAA,EACJ;AACD;","names":[]}
@@ -0,0 +1,113 @@
1
+ // src/core/plugin.ts
2
+ function isValidatePlugin(obj) {
3
+ return typeof obj === "object" && obj !== null && "_type" in obj && typeof obj._type === "string" && "verify" in obj && typeof obj.verify === "object";
4
+ }
5
+ async function runValidatePlugins(plugins, context, data) {
6
+ let result = data;
7
+ for (const plugin of plugins) {
8
+ const verifyFn = context.operation === "insert" ? plugin.verify.insert : plugin.verify.patch;
9
+ if (verifyFn) {
10
+ result = await verifyFn(context, result);
11
+ }
12
+ }
13
+ return result;
14
+ }
15
+ function createValidatePlugin(type, config, verify) {
16
+ return {
17
+ _type: type,
18
+ config,
19
+ verify
20
+ };
21
+ }
22
+
23
+ // src/core/verifyConfig.ts
24
+ var verifyConfig = (_schema, configs) => {
25
+ const validatePlugins = configs.plugins ?? [];
26
+ const insert = async (ctx, tableName, data, options) => {
27
+ let verifiedData = data;
28
+ if (configs.defaultValues) {
29
+ verifiedData = await configs.defaultValues.verify(tableName, verifiedData);
30
+ }
31
+ if (validatePlugins.length > 0) {
32
+ verifiedData = await runValidatePlugins(
33
+ validatePlugins,
34
+ {
35
+ ctx,
36
+ tableName,
37
+ operation: "insert",
38
+ onFail: options?.onFail,
39
+ schema: _schema
40
+ },
41
+ verifiedData
42
+ );
43
+ }
44
+ return await ctx.db.insert(tableName, verifiedData);
45
+ };
46
+ const patch = async (ctx, tableName, id, data, options) => {
47
+ let verifiedData = data;
48
+ if (validatePlugins.length > 0) {
49
+ verifiedData = await runValidatePlugins(
50
+ validatePlugins,
51
+ {
52
+ ctx,
53
+ tableName,
54
+ operation: "patch",
55
+ patchId: id,
56
+ onFail: options?.onFail,
57
+ schema: _schema
58
+ },
59
+ verifiedData
60
+ );
61
+ }
62
+ await ctx.db.patch(id, verifiedData);
63
+ };
64
+ const dangerouslyPatch = async (ctx, tableName, id, data, options) => {
65
+ let verifiedData = data;
66
+ if (validatePlugins.length > 0) {
67
+ verifiedData = await runValidatePlugins(
68
+ validatePlugins,
69
+ {
70
+ ctx,
71
+ tableName,
72
+ operation: "patch",
73
+ patchId: id,
74
+ onFail: options?.onFail,
75
+ schema: _schema
76
+ },
77
+ verifiedData
78
+ );
79
+ }
80
+ await ctx.db.patch(id, verifiedData);
81
+ };
82
+ return {
83
+ insert,
84
+ patch,
85
+ dangerouslyPatch,
86
+ // Expose configs for debugging/advanced usage
87
+ configs
88
+ };
89
+ };
90
+
91
+ // src/core/types.ts
92
+ function normalizeIndexConfigEntry(entry, defaultIdentifiers = ["_id"]) {
93
+ if (typeof entry === "string") {
94
+ return {
95
+ index: entry,
96
+ identifiers: defaultIdentifiers
97
+ };
98
+ }
99
+ const { index, identifiers, ...rest } = entry;
100
+ return {
101
+ index: String(index),
102
+ identifiers: identifiers?.map(String) ?? defaultIdentifiers,
103
+ ...rest
104
+ };
105
+ }
106
+ export {
107
+ createValidatePlugin,
108
+ isValidatePlugin,
109
+ normalizeIndexConfigEntry,
110
+ runValidatePlugins,
111
+ verifyConfig
112
+ };
113
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/core/plugin.ts","../../src/core/verifyConfig.ts","../../src/core/types.ts"],"sourcesContent":["import { GenericMutationCtx, GenericSchema, SchemaDefinition } from 'convex/server';\nimport { GenericId } from 'convex/values';\n\nimport { OnFailCallback } from './types';\n\n// =============================================================================\n// Plugin Types\n// =============================================================================\n\n/**\n * Context passed to validate plugin functions.\n *\n * Provides access to:\n * - `ctx` - Full Convex mutation context (includes `ctx.db` for queries)\n * - `tableName` - The table being operated on\n * - `operation` - 'insert' or 'patch'\n * - `patchId` - Document ID (only for patch operations)\n * - `onFail` - Callback to report validation failures before throwing\n * - `schema` - Optional schema reference (if provided by verifyConfig)\n */\nexport type ValidateContext<TN extends string = string> = {\n\t/** Full Convex mutation context - use ctx.db for database queries */\n\tctx: Omit<GenericMutationCtx<any>, never>;\n\t/** Table name being operated on */\n\ttableName: TN;\n\t/** Operation type: 'insert' or 'patch' */\n\toperation: 'insert' | 'patch';\n\t/** Document ID (only available for patch operations) */\n\tpatchId?: GenericId<any>;\n\t/** Callback for validation failures - call before throwing to provide details */\n\tonFail?: OnFailCallback<any>;\n\t/** Schema reference (if provided to verifyConfig) */\n\tschema?: SchemaDefinition<GenericSchema, boolean>;\n};\n\n/**\n * A validate plugin that can check data during insert/patch operations.\n *\n * Validate plugins:\n * - Run AFTER transform plugins (like defaultValues)\n * - Can be async (use await for API calls, db queries, etc.)\n * - Can throw errors to prevent the operation\n * - Should return the data unchanged (validation only, no transformation)\n * - Do NOT affect the TypeScript types of the input data\n *\n * @example\n * ```ts\n * // Simple sync plugin\n * const requiredFields = createValidatePlugin(\n * 'requiredFields',\n * { fields: ['title', 'content'] },\n * {\n * insert: (context, data) => {\n * for (const field of config.fields) {\n * if (!data[field]) {\n * throw new ConvexError({ message: `Missing required field: ${field}` });\n * }\n * }\n * return data;\n * },\n * }\n * );\n *\n * // Async plugin with database query\n * const checkOwnership = createValidatePlugin(\n * 'checkOwnership',\n * {},\n * {\n * patch: async (context, data) => {\n * const existing = await context.ctx.db.get(context.patchId);\n * if (existing?.ownerId !== getCurrentUserId()) {\n * throw new ConvexError({ message: 'Not authorized' });\n * }\n * return data;\n * },\n * }\n * );\n * ```\n */\nexport interface ValidatePlugin<Type extends string = string, Config = unknown> {\n\t/** Unique identifier for this plugin */\n\treadonly _type: Type;\n\n\t/** Plugin configuration */\n\treadonly config: Config;\n\n\t/** Verify functions for insert and/or patch operations */\n\tverify: {\n\t\t/**\n\t\t * Validate data for insert operations.\n\t\t * Can be sync or async.\n\t\t *\n\t\t * @param context - Plugin context with ctx, tableName, schema, etc.\n\t\t * @param data - The data to validate (after transforms applied)\n\t\t * @returns The data unchanged (or Promise resolving to data)\n\t\t * @throws ConvexError if validation fails\n\t\t */\n\t\tinsert?: (context: ValidateContext, data: any) => Promise<any> | any;\n\n\t\t/**\n\t\t * Validate data for patch operations.\n\t\t * Can be sync or async.\n\t\t *\n\t\t * @param context - Plugin context with ctx, tableName, patchId, schema, etc.\n\t\t * @param data - The partial data to validate\n\t\t * @returns The data unchanged (or Promise resolving to data)\n\t\t * @throws ConvexError if validation fails\n\t\t */\n\t\tpatch?: (context: ValidateContext, data: any) => Promise<any> | any;\n\t};\n}\n\n/**\n * Type guard to check if something is a ValidatePlugin\n */\nexport function isValidatePlugin(obj: unknown): obj is ValidatePlugin {\n\treturn (\n\t\ttypeof obj === 'object' &&\n\t\tobj !== null &&\n\t\t'_type' in obj &&\n\t\ttypeof (obj as any)._type === 'string' &&\n\t\t'verify' in obj &&\n\t\ttypeof (obj as any).verify === 'object'\n\t);\n}\n\n// =============================================================================\n// Plugin Collection Types\n// =============================================================================\n\n/**\n * A collection of validate plugins\n */\nexport type ValidatePluginRecord = Record<string, ValidatePlugin>;\n\n// =============================================================================\n// Plugin Helpers\n// =============================================================================\n\n/**\n * Run all validate plugins for an operation.\n * Plugins are run in order and each receives the output of the previous.\n * All plugin verify functions are awaited (supports async plugins).\n */\nexport async function runValidatePlugins(\n\tplugins: ValidatePlugin[],\n\tcontext: ValidateContext,\n\tdata: any\n): Promise<any> {\n\tlet result = data;\n\n\tfor (const plugin of plugins) {\n\t\tconst verifyFn = context.operation === 'insert' ? plugin.verify.insert : plugin.verify.patch;\n\n\t\tif (verifyFn) {\n\t\t\t// Always await - works for both sync and async functions\n\t\t\tresult = await verifyFn(context, result);\n\t\t}\n\t}\n\n\treturn result;\n}\n\n/**\n * Helper to create a validate plugin with proper typing.\n *\n * @param type - Unique identifier for this plugin type\n * @param config - Plugin configuration data\n * @param verify - Object with insert and/or patch verify functions\n * @returns A ValidatePlugin instance\n *\n * @example\n * ```ts\n * const myPlugin = createValidatePlugin(\n * 'myPlugin',\n * { maxLength: 100 },\n * {\n * insert: async (context, data) => {\n * // Validation logic here\n * return data;\n * },\n * }\n * );\n * ```\n */\nexport function createValidatePlugin<Type extends string, Config>(\n\ttype: Type,\n\tconfig: Config,\n\tverify: ValidatePlugin<Type, Config>['verify']\n): ValidatePlugin<Type, Config> {\n\treturn {\n\t\t_type: type,\n\t\tconfig,\n\t\tverify,\n\t};\n}\n","import {\n\tDataModelFromSchemaDefinition,\n\tDocumentByName,\n\tGenericMutationCtx,\n\tGenericSchema,\n\tSchemaDefinition,\n\tTableNamesInDataModel,\n\tWithoutSystemFields,\n} from 'convex/server';\nimport { GenericId } from 'convex/values';\n\nimport { runValidatePlugins, ValidatePlugin } from './plugin';\nimport {\n\tHasKey,\n\tMakeOptional,\n\tOnFailCallback,\n\tOptionalKeysForTable,\n\tProtectedKeysForTable,\n\tVerifyConfigInput,\n} from './types';\n\n/**\n * Extended config input that includes optional validate plugins\n */\ntype VerifyConfigInputWithPlugins = VerifyConfigInput & {\n\t/**\n\t * Validate plugins to run after transforms.\n\t * These plugins can validate data but don't affect input types.\n\t */\n\tplugins?: ValidatePlugin[];\n};\n\n/**\n * Configure type-safe insert and patch functions with validation and transforms.\n *\n * @param schema - Your Convex schema definition\n * @param configs - Configuration object with transforms, configs, and plugins\n * @returns Object with `insert`, `patch`, and `dangerouslyPatch` functions\n *\n * @example\n * ```ts\n * import { verifyConfig, defaultValuesConfig, protectedColumnsConfig, uniqueRowConfig } from 'convex-verify';\n * import schema from './schema';\n *\n * export const { insert, patch, dangerouslyPatch } = verifyConfig(schema, {\n * defaultValues: defaultValuesConfig(schema, () => ({\n * posts: { status: 'draft', views: 0 },\n * })),\n * protectedColumns: protectedColumnsConfig(schema, {\n * posts: ['authorId'],\n * }),\n * plugins: [\n * uniqueRowConfig(schema, {\n * posts: ['by_slug'],\n * }),\n * ],\n * });\n * ```\n */\nexport const verifyConfig = <\n\tS extends SchemaDefinition<GenericSchema, boolean>,\n\tDataModel extends DataModelFromSchemaDefinition<S>,\n\tconst VC extends VerifyConfigInputWithPlugins,\n>(\n\t_schema: S,\n\tconfigs: VC\n) => {\n\t// Get all validate plugins\n\tconst validatePlugins = configs.plugins ?? [];\n\n\t/**\n\t * Insert a document with all configured verifications applied.\n\t *\n\t * Execution order:\n\t * 1. Transform: defaultValues (makes fields optional, applies defaults)\n\t * 2. Validate: plugins (in order provided)\n\t * 3. Insert into database\n\t */\n\tconst insert = async <\n\t\tconst TN extends TableNamesInDataModel<DataModel>,\n\t\tconst D extends DocumentByName<DataModel, TN>,\n\t>(\n\t\tctx: Omit<GenericMutationCtx<DataModel>, never>,\n\t\ttableName: TN,\n\t\tdata: HasKey<VC, 'defaultValues'> extends true\n\t\t\t? MakeOptional<\n\t\t\t\t\tWithoutSystemFields<D>,\n\t\t\t\t\tOptionalKeysForTable<VC, TN> & keyof WithoutSystemFields<D>\n\t\t\t\t>\n\t\t\t: WithoutSystemFields<D>,\n\t\toptions?: {\n\t\t\tonFail?: OnFailCallback<D>;\n\t\t}\n\t): Promise<GenericId<TN>> => {\n\t\tlet verifiedData = data as WithoutSystemFields<DocumentByName<DataModel, TN>>;\n\n\t\t// === TRANSFORM PHASE ===\n\n\t\t// Apply default values (transforms data)\n\t\tif (configs.defaultValues) {\n\t\t\tverifiedData = await configs.defaultValues.verify(tableName, verifiedData);\n\t\t}\n\n\t\t// === VALIDATE PHASE ===\n\n\t\t// Run all validate plugins\n\t\tif (validatePlugins.length > 0) {\n\t\t\tverifiedData = await runValidatePlugins(\n\t\t\t\tvalidatePlugins,\n\t\t\t\t{\n\t\t\t\t\tctx,\n\t\t\t\t\ttableName: tableName as string,\n\t\t\t\t\toperation: 'insert',\n\t\t\t\t\tonFail: options?.onFail,\n\t\t\t\t\tschema: _schema,\n\t\t\t\t},\n\t\t\t\tverifiedData\n\t\t\t);\n\t\t}\n\n\t\t// Final insert\n\t\treturn await ctx.db.insert(tableName, verifiedData);\n\t};\n\n\t/**\n\t * Patch a document with all configured verifications applied.\n\t *\n\t * Protected columns (if configured) are removed from the input type.\n\t * Use dangerouslyPatch() to bypass protected column restrictions.\n\t *\n\t * Execution order:\n\t * 1. Validate: plugins (in order provided)\n\t * 2. Patch in database\n\t *\n\t * Note: defaultValues is skipped for patch operations\n\t */\n\tconst patch = async <\n\t\tconst TN extends TableNamesInDataModel<DataModel>,\n\t\tconst D extends DocumentByName<DataModel, TN>,\n\t>(\n\t\tctx: Omit<GenericMutationCtx<DataModel>, never>,\n\t\ttableName: TN,\n\t\tid: GenericId<TN>,\n\t\tdata: HasKey<VC, 'protectedColumns'> extends true\n\t\t\t? Omit<\n\t\t\t\t\tPartial<WithoutSystemFields<D>>,\n\t\t\t\t\tProtectedKeysForTable<VC, TN> & keyof WithoutSystemFields<D>\n\t\t\t\t>\n\t\t\t: Partial<WithoutSystemFields<D>>,\n\t\toptions?: {\n\t\t\tonFail?: OnFailCallback<D>;\n\t\t}\n\t): Promise<void> => {\n\t\tlet verifiedData = data as Partial<WithoutSystemFields<DocumentByName<DataModel, TN>>>;\n\n\t\t// === VALIDATE PHASE ===\n\n\t\t// Run all validate plugins\n\t\tif (validatePlugins.length > 0) {\n\t\t\tverifiedData = await runValidatePlugins(\n\t\t\t\tvalidatePlugins,\n\t\t\t\t{\n\t\t\t\t\tctx,\n\t\t\t\t\ttableName: tableName as string,\n\t\t\t\t\toperation: 'patch',\n\t\t\t\t\tpatchId: id,\n\t\t\t\t\tonFail: options?.onFail,\n\t\t\t\t\tschema: _schema,\n\t\t\t\t},\n\t\t\t\tverifiedData\n\t\t\t);\n\t\t}\n\n\t\tawait ctx.db.patch(id, verifiedData);\n\t};\n\n\t/**\n\t * Patch a document bypassing protected column restrictions.\n\t *\n\t * WARNING: This allows patching ANY column, including protected ones.\n\t * Only use this when you explicitly need to update a protected column.\n\t *\n\t * Validation plugins still run - only type restrictions are bypassed.\n\t */\n\tconst dangerouslyPatch = async <\n\t\tconst TN extends TableNamesInDataModel<DataModel>,\n\t\tconst D extends DocumentByName<DataModel, TN>,\n\t>(\n\t\tctx: Omit<GenericMutationCtx<DataModel>, never>,\n\t\ttableName: TN,\n\t\tid: GenericId<TN>,\n\t\tdata: Partial<WithoutSystemFields<D>>,\n\t\toptions?: {\n\t\t\tonFail?: OnFailCallback<D>;\n\t\t}\n\t): Promise<void> => {\n\t\tlet verifiedData = data;\n\n\t\t// === VALIDATE PHASE ===\n\n\t\t// Run all validate plugins (protection is bypassed, but validation still runs)\n\t\tif (validatePlugins.length > 0) {\n\t\t\tverifiedData = await runValidatePlugins(\n\t\t\t\tvalidatePlugins,\n\t\t\t\t{\n\t\t\t\t\tctx,\n\t\t\t\t\ttableName: tableName as string,\n\t\t\t\t\toperation: 'patch',\n\t\t\t\t\tpatchId: id,\n\t\t\t\t\tonFail: options?.onFail,\n\t\t\t\t\tschema: _schema,\n\t\t\t\t},\n\t\t\t\tverifiedData\n\t\t\t);\n\t\t}\n\n\t\tawait ctx.db.patch(id, verifiedData);\n\t};\n\n\treturn {\n\t\tinsert,\n\t\tpatch,\n\t\tdangerouslyPatch,\n\t\t// Expose configs for debugging/advanced usage\n\t\tconfigs,\n\t};\n};\n","import {\n\tDataModelFromSchemaDefinition,\n\tIndexes,\n\tNamedTableInfo,\n\tSchemaDefinition,\n\tWithoutSystemFields,\n} from 'convex/server';\n\n// =============================================================================\n// Utility Types\n// =============================================================================\n\nexport type Prettify<T> = { [K in keyof T]: T[K] } & {};\n\nexport type MakeOptional<T, K extends PropertyKey> = Prettify<\n\tOmit<T, K & keyof T> & Partial<Pick<T, K & keyof T>>\n>;\n\n// =============================================================================\n// Base Types for Config Functions\n// =============================================================================\n\n/**\n * Base interface that all config functions should return.\n * Each config type can have its own `verify` signature and additional properties.\n */\nexport type BaseConfigReturn = {\n\tconfig: Record<string, any>;\n};\n\n// =============================================================================\n// OnFail Types\n// =============================================================================\n\nexport type OnFailArgs<D> = {\n\tuniqueColumn?: {\n\t\tconflictingColumn: keyof D;\n\t\texistingData: D;\n\t};\n\tuniqueRow?: {\n\t\texistingData: D | null;\n\t};\n\teditableColumn?: {\n\t\tremovedColumns: string[];\n\t\tfilteredData: D;\n\t};\n\trequiredColumn?: {\n\t\tmissingColumn: keyof D;\n\t};\n};\n\nexport type OnFailCallback<D> = (args: OnFailArgs<D>) => void;\n\n// =============================================================================\n// Config Data Types (what the user provides)\n// =============================================================================\n\nexport type DMGeneric = DataModelFromSchemaDefinition<SchemaDefinition<any, boolean>>;\n\nexport type DefaultValuesConfigData<DM extends DMGeneric> = {\n\t[K in keyof DM]?: {\n\t\t[column in keyof WithoutSystemFields<DM[K]['document']>]?: DM[K]['document'][column];\n\t};\n};\n\n// =============================================================================\n// Index-Based Config Types (shared between uniqueRow, uniqueColumn, etc.)\n// =============================================================================\n\n/**\n * Base options shared by all index-based config entries.\n * Individual plugins can extend this with their own options.\n */\nexport type IndexConfigBaseOptions = {\n\t/** Additional identifiers to check if the existing row is the same document being updated */\n\tidentifiers?: string[];\n};\n\n/**\n * A config entry that can be either:\n * - A string (index name) for shorthand\n * - An object with `index` and additional options\n *\n * @example\n * ```ts\n * // These are equivalent:\n * 'by_username'\n * { index: 'by_username' }\n *\n * // With options:\n * { index: 'by_username', identifiers: ['_id', 'userId'] }\n * ```\n */\nexport type IndexConfigEntry<\n\tDM extends DMGeneric,\n\tK extends keyof DM,\n\tOptions extends IndexConfigBaseOptions = IndexConfigBaseOptions,\n> =\n\t| keyof Indexes<NamedTableInfo<DM, K>>\n\t| ({\n\t\t\tindex: keyof Indexes<NamedTableInfo<DM, K>>;\n\t\t\tidentifiers?: (keyof NamedTableInfo<DM, K>['document'])[];\n\t } & Omit<Options, 'identifiers'>);\n\n/**\n * Normalized form of an index config entry (always an object)\n */\nexport type NormalizedIndexConfig<Options extends IndexConfigBaseOptions = IndexConfigBaseOptions> =\n\t{\n\t\tindex: string;\n\t\tidentifiers: string[];\n\t} & Omit<Options, 'identifiers'>;\n\n/**\n * Normalize a config entry to always have index and identifiers.\n * Works for both string shorthand and full object configs.\n */\nexport function normalizeIndexConfigEntry<\n\tOptions extends IndexConfigBaseOptions = IndexConfigBaseOptions,\n>(\n\tentry: string | ({ index: string; identifiers?: string[] } & Omit<Options, 'identifiers'>),\n\tdefaultIdentifiers: string[] = ['_id']\n): NormalizedIndexConfig<Options> {\n\tif (typeof entry === 'string') {\n\t\treturn {\n\t\t\tindex: entry,\n\t\t\tidentifiers: defaultIdentifiers,\n\t\t} as NormalizedIndexConfig<Options>;\n\t}\n\n\tconst { index, identifiers, ...rest } = entry;\n\treturn {\n\t\tindex: String(index),\n\t\tidentifiers: identifiers?.map(String) ?? defaultIdentifiers,\n\t\t...rest,\n\t} as NormalizedIndexConfig<Options>;\n}\n\n// =============================================================================\n// UniqueRow Config Types\n// =============================================================================\n\nexport type UniqueRowConfigOptions = IndexConfigBaseOptions & {\n\tqueryExistingWithNullish?: boolean;\n};\n\nexport type UniqueRowConfigEntry<DM extends DMGeneric, K extends keyof DM> = IndexConfigEntry<\n\tDM,\n\tK,\n\tUniqueRowConfigOptions\n>;\n\nexport type UniqueRowConfigData<DM extends DMGeneric> = {\n\t[K in keyof DM]?: UniqueRowConfigEntry<DM, K>[];\n};\n\n// =============================================================================\n// UniqueColumn Config Types\n// =============================================================================\n\nexport type UniqueColumnConfigOptions = IndexConfigBaseOptions;\n\nexport type UniqueColumnConfigEntry<DM extends DMGeneric, K extends keyof DM> = IndexConfigEntry<\n\tDM,\n\tK,\n\tUniqueColumnConfigOptions\n>;\n\nexport type UniqueColumnConfigData<DM extends DMGeneric> = {\n\t[K in keyof DM]?: UniqueColumnConfigEntry<DM, K>[];\n};\n\n// =============================================================================\n// Input Types (loose types for verifyConfig to accept)\n// =============================================================================\n\n/**\n * Loose input types that accept any return from config functions.\n * We use loose types here to avoid complex generic matching,\n * then extract the specific config types using conditional types.\n */\nexport type DefaultValuesInput = {\n\t_type: 'defaultValues';\n\tverify: (tableName: any, data: any) => Promise<any>;\n\tconfig:\n\t\t| Record<string, Record<string, any>>\n\t\t| (() => Record<string, Record<string, any>> | Promise<Record<string, Record<string, any>>>);\n};\n\n/**\n * Loose input type for protectedColumnsConfig return value.\n */\nexport type ProtectedColumnsInput = {\n\t_type: 'protectedColumns';\n\tconfig: Record<string, string[]>;\n};\n\n// =============================================================================\n// Object-Based Types (for verifyConfig)\n// =============================================================================\n\n/**\n * Config input for verifyConfig.\n *\n * - `defaultValues`: Transform plugin that makes fields optional (affects types)\n * - `protectedColumns`: Columns that cannot be patched (affects patch() types)\n * - `plugins`: Array of validate plugins (use for uniqueRow, uniqueColumn, custom plugins, etc.)\n */\nexport type VerifyConfigInput = {\n\tdefaultValues?: DefaultValuesInput;\n\tprotectedColumns?: ProtectedColumnsInput;\n};\n\n// =============================================================================\n// Type Extraction Helpers\n// =============================================================================\n\n/**\n * Extract the config type from defaultValues.config.\n * Handles both direct object and function forms.\n */\nexport type ExtractDefaultValuesConfig<VC> = VC extends {\n\tdefaultValues: { config: infer C };\n}\n\t? C extends () => infer R\n\t\t? Awaited<R>\n\t\t: C\n\t: Record<string, never>;\n\n/**\n * Compute which keys should be optional for a given table based on all configs.\n * Currently only defaultValues affects optionality.\n */\nexport type OptionalKeysForTable<VC, TN> = TN extends keyof ExtractDefaultValuesConfig<VC>\n\t? keyof ExtractDefaultValuesConfig<VC>[TN]\n\t: never;\n\n/**\n * Helper to check if a key exists in a type\n */\nexport type HasKey<T, K extends PropertyKey> = K extends keyof T ? true : false;\n\n// =============================================================================\n// Protected Columns Type Extraction\n// =============================================================================\n\n/**\n * Extract the config type from protectedColumns.config\n */\nexport type ExtractProtectedColumnsConfig<VC> = VC extends {\n\tprotectedColumns: { config: infer C };\n}\n\t? C\n\t: Record<string, never>;\n\n/**\n * Get protected column keys for a specific table.\n * Returns the column names that should be omitted from patch() input.\n */\nexport type ProtectedKeysForTable<VC, TN> = TN extends keyof ExtractProtectedColumnsConfig<VC>\n\t? ExtractProtectedColumnsConfig<VC>[TN] extends readonly (infer K)[]\n\t\t? K\n\t\t: never\n\t: never;\n"],"mappings":";AAmHO,SAAS,iBAAiB,KAAqC;AACrE,SACC,OAAO,QAAQ,YACf,QAAQ,QACR,WAAW,OACX,OAAQ,IAAY,UAAU,YAC9B,YAAY,OACZ,OAAQ,IAAY,WAAW;AAEjC;AAoBA,eAAsB,mBACrB,SACA,SACA,MACe;AACf,MAAI,SAAS;AAEb,aAAW,UAAU,SAAS;AAC7B,UAAM,WAAW,QAAQ,cAAc,WAAW,OAAO,OAAO,SAAS,OAAO,OAAO;AAEvF,QAAI,UAAU;AAEb,eAAS,MAAM,SAAS,SAAS,MAAM;AAAA,IACxC;AAAA,EACD;AAEA,SAAO;AACR;AAwBO,SAAS,qBACf,MACA,QACA,QAC+B;AAC/B,SAAO;AAAA,IACN,OAAO;AAAA,IACP;AAAA,IACA;AAAA,EACD;AACD;;;ACxIO,IAAM,eAAe,CAK3B,SACA,YACI;AAEJ,QAAM,kBAAkB,QAAQ,WAAW,CAAC;AAU5C,QAAM,SAAS,OAId,KACA,WACA,MAMA,YAG4B;AAC5B,QAAI,eAAe;AAKnB,QAAI,QAAQ,eAAe;AAC1B,qBAAe,MAAM,QAAQ,cAAc,OAAO,WAAW,YAAY;AAAA,IAC1E;AAKA,QAAI,gBAAgB,SAAS,GAAG;AAC/B,qBAAe,MAAM;AAAA,QACpB;AAAA,QACA;AAAA,UACC;AAAA,UACA;AAAA,UACA,WAAW;AAAA,UACX,QAAQ,SAAS;AAAA,UACjB,QAAQ;AAAA,QACT;AAAA,QACA;AAAA,MACD;AAAA,IACD;AAGA,WAAO,MAAM,IAAI,GAAG,OAAO,WAAW,YAAY;AAAA,EACnD;AAcA,QAAM,QAAQ,OAIb,KACA,WACA,IACA,MAMA,YAGmB;AACnB,QAAI,eAAe;AAKnB,QAAI,gBAAgB,SAAS,GAAG;AAC/B,qBAAe,MAAM;AAAA,QACpB;AAAA,QACA;AAAA,UACC;AAAA,UACA;AAAA,UACA,WAAW;AAAA,UACX,SAAS;AAAA,UACT,QAAQ,SAAS;AAAA,UACjB,QAAQ;AAAA,QACT;AAAA,QACA;AAAA,MACD;AAAA,IACD;AAEA,UAAM,IAAI,GAAG,MAAM,IAAI,YAAY;AAAA,EACpC;AAUA,QAAM,mBAAmB,OAIxB,KACA,WACA,IACA,MACA,YAGmB;AACnB,QAAI,eAAe;AAKnB,QAAI,gBAAgB,SAAS,GAAG;AAC/B,qBAAe,MAAM;AAAA,QACpB;AAAA,QACA;AAAA,UACC;AAAA,UACA;AAAA,UACA,WAAW;AAAA,UACX,SAAS;AAAA,UACT,QAAQ,SAAS;AAAA,UACjB,QAAQ;AAAA,QACT;AAAA,QACA;AAAA,MACD;AAAA,IACD;AAEA,UAAM,IAAI,GAAG,MAAM,IAAI,YAAY;AAAA,EACpC;AAEA,SAAO;AAAA,IACN;AAAA,IACA;AAAA,IACA;AAAA;AAAA,IAEA;AAAA,EACD;AACD;;;AC7GO,SAAS,0BAGf,OACA,qBAA+B,CAAC,KAAK,GACJ;AACjC,MAAI,OAAO,UAAU,UAAU;AAC9B,WAAO;AAAA,MACN,OAAO;AAAA,MACP,aAAa;AAAA,IACd;AAAA,EACD;AAEA,QAAM,EAAE,OAAO,aAAa,GAAG,KAAK,IAAI;AACxC,SAAO;AAAA,IACN,OAAO,OAAO,KAAK;AAAA,IACnB,aAAa,aAAa,IAAI,MAAM,KAAK;AAAA,IACzC,GAAG;AAAA,EACJ;AACD;","names":[]}
@@ -0,0 +1,9 @@
1
+ export { verifyConfig } from './core/index.mjs';
2
+ export { V as ValidateContext, a as ValidatePlugin, b as ValidatePluginRecord, c as createValidatePlugin, i as isValidatePlugin, r as runValidatePlugins } from './plugin-mHMV2-SG.mjs';
3
+ export { D as DefaultValuesConfigData, E as ExtractDefaultValuesConfig, c as ExtractProtectedColumnsConfig, H as HasKey, I as IndexConfigBaseOptions, j as IndexConfigEntry, M as MakeOptional, N as NormalizedIndexConfig, O as OnFailArgs, a as OnFailCallback, b as OptionalKeysForTable, P as Prettify, d as ProtectedKeysForTable, g as UniqueColumnConfigData, h as UniqueColumnConfigEntry, i as UniqueColumnConfigOptions, U as UniqueRowConfigData, e as UniqueRowConfigEntry, f as UniqueRowConfigOptions, V as VerifyConfigInput, n as normalizeIndexConfigEntry } from './types-_64SXyva.mjs';
4
+ export { defaultValuesConfig } from './transforms/index.mjs';
5
+ export { ProtectedColumnsConfigData, protectedColumnsConfig } from './configs/index.mjs';
6
+ export { uniqueColumnConfig, uniqueRowConfig } from './plugins/index.mjs';
7
+ export { constructColumnData, constructIndexData, getTableIndexes } from './utils/index.mjs';
8
+ import 'convex/server';
9
+ import 'convex/values';
@@ -0,0 +1,9 @@
1
+ export { verifyConfig } from './core/index.js';
2
+ export { V as ValidateContext, a as ValidatePlugin, b as ValidatePluginRecord, c as createValidatePlugin, i as isValidatePlugin, r as runValidatePlugins } from './plugin-BjJ7yjrc.js';
3
+ export { D as DefaultValuesConfigData, E as ExtractDefaultValuesConfig, c as ExtractProtectedColumnsConfig, H as HasKey, I as IndexConfigBaseOptions, j as IndexConfigEntry, M as MakeOptional, N as NormalizedIndexConfig, O as OnFailArgs, a as OnFailCallback, b as OptionalKeysForTable, P as Prettify, d as ProtectedKeysForTable, g as UniqueColumnConfigData, h as UniqueColumnConfigEntry, i as UniqueColumnConfigOptions, U as UniqueRowConfigData, e as UniqueRowConfigEntry, f as UniqueRowConfigOptions, V as VerifyConfigInput, n as normalizeIndexConfigEntry } from './types-_64SXyva.js';
4
+ export { defaultValuesConfig } from './transforms/index.js';
5
+ export { ProtectedColumnsConfigData, protectedColumnsConfig } from './configs/index.js';
6
+ export { uniqueColumnConfig, uniqueRowConfig } from './plugins/index.js';
7
+ export { constructColumnData, constructIndexData, getTableIndexes } from './utils/index.js';
8
+ import 'convex/server';
9
+ import 'convex/values';