@vexcms/better-auth 0.0.8 → 0.0.10
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/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -102,7 +102,7 @@ function convertToVexFields(tableSlug, fields) {
|
|
|
102
102
|
case "string[]":
|
|
103
103
|
vexFields[fieldName] = {
|
|
104
104
|
type: "array",
|
|
105
|
-
|
|
105
|
+
items: { type: "text" },
|
|
106
106
|
required,
|
|
107
107
|
...admin && { admin }
|
|
108
108
|
};
|
|
@@ -110,7 +110,7 @@ function convertToVexFields(tableSlug, fields) {
|
|
|
110
110
|
case "number[]":
|
|
111
111
|
vexFields[fieldName] = {
|
|
112
112
|
type: "array",
|
|
113
|
-
|
|
113
|
+
items: { type: "number" },
|
|
114
114
|
required,
|
|
115
115
|
...admin && { admin }
|
|
116
116
|
};
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/extract/collections.ts","../src/index.ts"],"sourcesContent":["import {\n VexAuthConfigError,\n} from \"@vexcms/core\";\nimport type {\n VexCollection,\n VexField,\n FieldAdminConfig,\n} from \"@vexcms/core\";\nimport type { BetterAuthOptions, DBFieldAttribute } from \"better-auth\";\nimport { getAuthTables } from \"better-auth/db\";\n\n/** Fields that are editable per auth table. Everything else is read-only. */\nconst EDITABLE_FIELDS: Record<string, Set<string>> = {\n user: new Set([\"name\", \"image\", \"role\", \"banned\", \"banReason\", \"banExpires\"]),\n};\n\n/** Fields that should be hidden from the admin panel (sensitive data). */\nconst HIDDEN_FIELDS: Record<string, Set<string>> = {\n session: new Set([\"token\"]),\n account: new Set([\"accessToken\", \"refreshToken\", \"idToken\"]),\n verification: new Set([\"value\"]),\n};\n\n/** Labels for auth collections. */\nconst COLLECTION_LABELS: Record<string, { singular: string; plural: string }> = {\n user: { singular: \"User\", plural: \"Users\" },\n session: { singular: \"Session\", plural: \"Sessions\" },\n account: { singular: \"Account\", plural: \"Accounts\" },\n verification: { singular: \"Verification\", plural: \"Verifications\" },\n};\n\n/** Auth collections that should have typed API files generated. */\nconst GENERATE_API: Set<string> = new Set([\"user\"]);\n\n/** Default columns to show in the list view per auth table. */\nconst DEFAULT_COLUMNS: Record<string, string[]> = {\n user: [\"_id\", \"name\", \"email\", \"createdAt\"],\n session: [\"_id\", \"userId\", \"expiresAt\", \"createdAt\"],\n account: [\"_id\", \"providerId\", \"accountId\", \"userId\"],\n verification: [\"_id\", \"identifier\", \"expiresAt\", \"createdAt\"],\n};\n\n/**\n * Resolves the admin config for an auth field based on the table and field name.\n * - Fields in EDITABLE_FIELDS are editable (no readOnly)\n * - Fields in HIDDEN_FIELDS are hidden from the admin panel\n * - All other fields are read-only\n */\nfunction resolveFieldAdminConfig(\n tableSlug: string,\n fieldName: string,\n): FieldAdminConfig | undefined {\n const hidden = HIDDEN_FIELDS[tableSlug]?.has(fieldName);\n if (hidden) return { hidden: true };\n\n const editable = EDITABLE_FIELDS[tableSlug]?.has(fieldName);\n if (!editable) return { readOnly: true };\n\n return undefined;\n}\n\n/**\n * Converts a Record of better-auth DBFieldAttributes into VexField records.\n * Skips the \"id\" field since Convex auto-generates _id.\n *\n * Required fields get appropriate defaultValues for processFieldValueTypeOptions:\n * - text/string → \"\"\n * - number → 0\n * - boolean → false\n * - date → 0 (epoch ms)\n */\nfunction convertToVexFields(\n tableSlug: string,\n fields: Record<string, DBFieldAttribute>,\n): Record<string, VexField> {\n const vexFields: Record<string, VexField> = {};\n\n for (const [fieldName, attribute] of Object.entries(fields)) {\n if (fieldName === \"id\") continue;\n\n const required = attribute.required ?? false;\n const admin = resolveFieldAdminConfig(tableSlug, fieldName);\n\n if (attribute.references) {\n vexFields[fieldName] = {\n type: \"relationship\",\n to: attribute.references.model,\n required,\n ...(admin && { admin }),\n };\n continue;\n }\n\n if (Array.isArray(attribute.type)) {\n vexFields[fieldName] = {\n type: \"select\",\n options: attribute.type.map((val: string) => ({\n label: val.charAt(0).toUpperCase() + val.slice(1),\n value: val,\n })),\n required,\n ...(required && { defaultValue: attribute.type[0] }),\n ...(admin && { admin }),\n };\n continue;\n }\n\n switch (attribute.type) {\n case \"string\":\n vexFields[fieldName] = {\n type: \"text\",\n required,\n ...(required && { defaultValue: \"\" }),\n ...(admin && { admin }),\n };\n break;\n case \"number\":\n vexFields[fieldName] = {\n type: \"number\",\n required,\n ...(required && { defaultValue: 0 }),\n ...(admin && { admin }),\n };\n break;\n case \"boolean\":\n vexFields[fieldName] = {\n type: \"checkbox\",\n required,\n ...(required && { defaultValue: false }),\n ...(admin && { admin }),\n };\n break;\n case \"date\":\n vexFields[fieldName] = {\n type: \"date\",\n required,\n ...(required && { defaultValue: 0 }),\n ...(admin && { admin }),\n };\n break;\n case \"json\":\n vexFields[fieldName] = {\n type: \"json\",\n required,\n ...(admin && { admin }),\n };\n break;\n case \"string[]\":\n vexFields[fieldName] = {\n type: \"array\",\n field: { type: \"text\" },\n required,\n ...(admin && { admin }),\n };\n break;\n case \"number[]\":\n vexFields[fieldName] = {\n type: \"array\",\n field: { type: \"number\" },\n required,\n ...(admin && { admin }),\n };\n break;\n default:\n throw new VexAuthConfigError(\n `Unknown better-auth field type: ${attribute.type}`,\n );\n }\n }\n\n return vexFields;\n}\n\n/**\n * Extracts indexes from better-auth field attributes.\n * Fields with `index: true` or `unique: true` get a `by_<fieldName>` index.\n */\nfunction extractIndexes(\n fields: Record<string, DBFieldAttribute>,\n): { name: string; fields: string[] }[] {\n const indexes: { name: string; fields: string[] }[] = [];\n for (const [fieldName, attribute] of Object.entries(fields)) {\n if (fieldName === \"id\") continue;\n if (attribute.index || attribute.unique) {\n indexes.push({ name: `by_${fieldName}`, fields: [fieldName] });\n }\n }\n return indexes;\n}\n\n/**\n * Extracts all auth collections from a BetterAuthOptions config using\n * better-auth's own `getAuthTables()` to get the full merged schema\n * (base fields + plugin fields + additionalFields for all tables).\n *\n * Each collection is configured with:\n * - Appropriate read-only / hidden / editable admin config per field\n * - Default \"Auth\" sidebar group\n * - Human-readable labels\n *\n * Returns a flat array of VexCollections — all tables are treated\n * uniformly, including the user table. Core's schema generator merges\n * any user-defined collection configs on top of these.\n */\nexport function extractAuthCollections(\n config: BetterAuthOptions,\n): VexCollection[] {\n const authDBSchema = getAuthTables(config);\n const collections: VexCollection[] = [];\n\n for (const [tableSlug, tableDef] of Object.entries(authDBSchema)) {\n const slug = tableDef.modelName ?? tableSlug;\n const fields = convertToVexFields(slug, tableDef.fields);\n const indexes = extractIndexes(tableDef.fields);\n const labels = COLLECTION_LABELS[slug];\n const defaultColumns = DEFAULT_COLUMNS[slug];\n\n collections.push({\n slug,\n fields,\n ...(labels ? { labels } : {}),\n ...(indexes.length > 0 ? { indexes } : {}),\n ...(GENERATE_API.has(slug) ? { generateApi: true } : {}),\n admin: {\n group: \"Auth\",\n useAsTitle: \"_id\",\n ...(defaultColumns ? { defaultColumns } : {}),\n },\n });\n }\n\n return collections;\n}\n","import type { VexAuthAdapter } from \"@vexcms/core\";\nimport type { BetterAuthOptions } from \"better-auth\";\nimport { extractAuthCollections } from \"./extract/collections\";\n\ninterface VexBetterAuthOptions {\n config?: BetterAuthOptions;\n}\n\n// ---------------------------------------------------------------------------\n// Known base fields per better-auth table (always present regardless of plugins)\n// ---------------------------------------------------------------------------\n\ntype UserFields =\n | \"name\"\n | \"email\"\n | \"emailVerified\"\n | \"image\"\n | \"createdAt\"\n | \"updatedAt\";\n\ntype SessionFields =\n | \"expiresAt\"\n | \"token\"\n | \"createdAt\"\n | \"updatedAt\"\n | \"ipAddress\"\n | \"userAgent\"\n | \"userId\";\n\ntype AccountFields =\n | \"accountId\"\n | \"providerId\"\n | \"userId\"\n | \"accessToken\"\n | \"refreshToken\"\n | \"accessTokenExpiresAt\"\n | \"refreshTokenExpiresAt\"\n | \"scope\"\n | \"password\"\n | \"createdAt\"\n | \"updatedAt\";\n\ntype VerificationFields =\n | \"identifier\"\n | \"value\"\n | \"expiresAt\"\n | \"createdAt\"\n | \"updatedAt\";\n\n/**\n * Type-level map from collection slug to field key union.\n * Base fields are always present; plugin-added fields work at runtime\n * but don't get autocomplete.\n */\ntype BetterAuthFieldKeyMap = {\n user: UserFields;\n session: SessionFields;\n account: AccountFields;\n verification: VerificationFields;\n};\n\n/**\n * The typed adapter returned by `vexBetterAuth()`.\n * Base field keys are preserved as string literals\n * for autocomplete in `defineCollection`.\n */\nexport type BetterAuthAdapter = VexAuthAdapter<BetterAuthFieldKeyMap>;\n\n/**\n * Creates a VexAuthAdapter from a BetterAuthOptions config.\n *\n * Accepts the same config object you pass to betterAuth() on the server.\n * Only reads schema-affecting properties (modelNames, additionalFields, plugins).\n * Runtime options (database, secret, baseURL, etc.) are ignored.\n *\n * @example\n * ```ts\n * import { vexBetterAuth } from \"@vexcms/better-auth\";\n * import { admin } from \"better-auth/plugins\";\n *\n * export default defineConfig({\n * auth: vexBetterAuth({\n * user: { modelName: \"users\" },\n * plugins: [admin()],\n * }),\n * // ...\n * });\n * ```\n */\nexport function vexBetterAuth(props?: VexBetterAuthOptions): BetterAuthAdapter {\n const collections = extractAuthCollections(props?.config ?? {});\n\n return {\n name: \"better-auth\",\n collections,\n } as BetterAuthAdapter;\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/extract/collections.ts","../src/index.ts"],"sourcesContent":["import {\n VexAuthConfigError,\n} from \"@vexcms/core\";\nimport type {\n VexCollection,\n VexField,\n FieldAdminConfig,\n} from \"@vexcms/core\";\nimport type { BetterAuthOptions, DBFieldAttribute } from \"better-auth\";\nimport { getAuthTables } from \"better-auth/db\";\n\n/** Fields that are editable per auth table. Everything else is read-only. */\nconst EDITABLE_FIELDS: Record<string, Set<string>> = {\n user: new Set([\"name\", \"image\", \"role\", \"banned\", \"banReason\", \"banExpires\"]),\n};\n\n/** Fields that should be hidden from the admin panel (sensitive data). */\nconst HIDDEN_FIELDS: Record<string, Set<string>> = {\n session: new Set([\"token\"]),\n account: new Set([\"accessToken\", \"refreshToken\", \"idToken\"]),\n verification: new Set([\"value\"]),\n};\n\n/** Labels for auth collections. */\nconst COLLECTION_LABELS: Record<string, { singular: string; plural: string }> = {\n user: { singular: \"User\", plural: \"Users\" },\n session: { singular: \"Session\", plural: \"Sessions\" },\n account: { singular: \"Account\", plural: \"Accounts\" },\n verification: { singular: \"Verification\", plural: \"Verifications\" },\n};\n\n/** Auth collections that should have typed API files generated. */\nconst GENERATE_API: Set<string> = new Set([\"user\"]);\n\n/** Default columns to show in the list view per auth table. */\nconst DEFAULT_COLUMNS: Record<string, string[]> = {\n user: [\"_id\", \"name\", \"email\", \"createdAt\"],\n session: [\"_id\", \"userId\", \"expiresAt\", \"createdAt\"],\n account: [\"_id\", \"providerId\", \"accountId\", \"userId\"],\n verification: [\"_id\", \"identifier\", \"expiresAt\", \"createdAt\"],\n};\n\n/**\n * Resolves the admin config for an auth field based on the table and field name.\n * - Fields in EDITABLE_FIELDS are editable (no readOnly)\n * - Fields in HIDDEN_FIELDS are hidden from the admin panel\n * - All other fields are read-only\n */\nfunction resolveFieldAdminConfig(\n tableSlug: string,\n fieldName: string,\n): FieldAdminConfig | undefined {\n const hidden = HIDDEN_FIELDS[tableSlug]?.has(fieldName);\n if (hidden) return { hidden: true };\n\n const editable = EDITABLE_FIELDS[tableSlug]?.has(fieldName);\n if (!editable) return { readOnly: true };\n\n return undefined;\n}\n\n/**\n * Converts a Record of better-auth DBFieldAttributes into VexField records.\n * Skips the \"id\" field since Convex auto-generates _id.\n *\n * Required fields get appropriate defaultValues for processFieldValueTypeOptions:\n * - text/string → \"\"\n * - number → 0\n * - boolean → false\n * - date → 0 (epoch ms)\n */\nfunction convertToVexFields(\n tableSlug: string,\n fields: Record<string, DBFieldAttribute>,\n): Record<string, VexField> {\n const vexFields: Record<string, VexField> = {};\n\n for (const [fieldName, attribute] of Object.entries(fields)) {\n if (fieldName === \"id\") continue;\n\n const required = attribute.required ?? false;\n const admin = resolveFieldAdminConfig(tableSlug, fieldName);\n\n if (attribute.references) {\n vexFields[fieldName] = {\n type: \"relationship\",\n to: attribute.references.model,\n required,\n ...(admin && { admin }),\n };\n continue;\n }\n\n if (Array.isArray(attribute.type)) {\n vexFields[fieldName] = {\n type: \"select\",\n options: attribute.type.map((val: string) => ({\n label: val.charAt(0).toUpperCase() + val.slice(1),\n value: val,\n })),\n required,\n ...(required && { defaultValue: attribute.type[0] }),\n ...(admin && { admin }),\n };\n continue;\n }\n\n switch (attribute.type) {\n case \"string\":\n vexFields[fieldName] = {\n type: \"text\",\n required,\n ...(required && { defaultValue: \"\" }),\n ...(admin && { admin }),\n };\n break;\n case \"number\":\n vexFields[fieldName] = {\n type: \"number\",\n required,\n ...(required && { defaultValue: 0 }),\n ...(admin && { admin }),\n };\n break;\n case \"boolean\":\n vexFields[fieldName] = {\n type: \"checkbox\",\n required,\n ...(required && { defaultValue: false }),\n ...(admin && { admin }),\n };\n break;\n case \"date\":\n vexFields[fieldName] = {\n type: \"date\",\n required,\n ...(required && { defaultValue: 0 }),\n ...(admin && { admin }),\n };\n break;\n case \"json\":\n vexFields[fieldName] = {\n type: \"json\",\n required,\n ...(admin && { admin }),\n };\n break;\n case \"string[]\":\n vexFields[fieldName] = {\n type: \"array\",\n items: { type: \"text\" },\n required,\n ...(admin && { admin }),\n };\n break;\n case \"number[]\":\n vexFields[fieldName] = {\n type: \"array\",\n items: { type: \"number\" },\n required,\n ...(admin && { admin }),\n };\n break;\n default:\n throw new VexAuthConfigError(\n `Unknown better-auth field type: ${attribute.type}`,\n );\n }\n }\n\n return vexFields;\n}\n\n/**\n * Extracts indexes from better-auth field attributes.\n * Fields with `index: true` or `unique: true` get a `by_<fieldName>` index.\n */\nfunction extractIndexes(\n fields: Record<string, DBFieldAttribute>,\n): { name: string; fields: string[] }[] {\n const indexes: { name: string; fields: string[] }[] = [];\n for (const [fieldName, attribute] of Object.entries(fields)) {\n if (fieldName === \"id\") continue;\n if (attribute.index || attribute.unique) {\n indexes.push({ name: `by_${fieldName}`, fields: [fieldName] });\n }\n }\n return indexes;\n}\n\n/**\n * Extracts all auth collections from a BetterAuthOptions config using\n * better-auth's own `getAuthTables()` to get the full merged schema\n * (base fields + plugin fields + additionalFields for all tables).\n *\n * Each collection is configured with:\n * - Appropriate read-only / hidden / editable admin config per field\n * - Default \"Auth\" sidebar group\n * - Human-readable labels\n *\n * Returns a flat array of VexCollections — all tables are treated\n * uniformly, including the user table. Core's schema generator merges\n * any user-defined collection configs on top of these.\n */\nexport function extractAuthCollections(\n config: BetterAuthOptions,\n): VexCollection[] {\n const authDBSchema = getAuthTables(config);\n const collections: VexCollection[] = [];\n\n for (const [tableSlug, tableDef] of Object.entries(authDBSchema)) {\n const slug = tableDef.modelName ?? tableSlug;\n const fields = convertToVexFields(slug, tableDef.fields);\n const indexes = extractIndexes(tableDef.fields);\n const labels = COLLECTION_LABELS[slug];\n const defaultColumns = DEFAULT_COLUMNS[slug];\n\n collections.push({\n slug,\n fields,\n ...(labels ? { labels } : {}),\n ...(indexes.length > 0 ? { indexes } : {}),\n ...(GENERATE_API.has(slug) ? { generateApi: true } : {}),\n admin: {\n group: \"Auth\",\n useAsTitle: \"_id\",\n ...(defaultColumns ? { defaultColumns } : {}),\n },\n });\n }\n\n return collections;\n}\n","import type { VexAuthAdapter } from \"@vexcms/core\";\nimport type { BetterAuthOptions } from \"better-auth\";\nimport { extractAuthCollections } from \"./extract/collections\";\n\ninterface VexBetterAuthOptions {\n config?: BetterAuthOptions;\n}\n\n// ---------------------------------------------------------------------------\n// Known base fields per better-auth table (always present regardless of plugins)\n// ---------------------------------------------------------------------------\n\ntype UserFields =\n | \"name\"\n | \"email\"\n | \"emailVerified\"\n | \"image\"\n | \"createdAt\"\n | \"updatedAt\";\n\ntype SessionFields =\n | \"expiresAt\"\n | \"token\"\n | \"createdAt\"\n | \"updatedAt\"\n | \"ipAddress\"\n | \"userAgent\"\n | \"userId\";\n\ntype AccountFields =\n | \"accountId\"\n | \"providerId\"\n | \"userId\"\n | \"accessToken\"\n | \"refreshToken\"\n | \"accessTokenExpiresAt\"\n | \"refreshTokenExpiresAt\"\n | \"scope\"\n | \"password\"\n | \"createdAt\"\n | \"updatedAt\";\n\ntype VerificationFields =\n | \"identifier\"\n | \"value\"\n | \"expiresAt\"\n | \"createdAt\"\n | \"updatedAt\";\n\n/**\n * Type-level map from collection slug to field key union.\n * Base fields are always present; plugin-added fields work at runtime\n * but don't get autocomplete.\n */\ntype BetterAuthFieldKeyMap = {\n user: UserFields;\n session: SessionFields;\n account: AccountFields;\n verification: VerificationFields;\n};\n\n/**\n * The typed adapter returned by `vexBetterAuth()`.\n * Base field keys are preserved as string literals\n * for autocomplete in `defineCollection`.\n */\nexport type BetterAuthAdapter = VexAuthAdapter<BetterAuthFieldKeyMap>;\n\n/**\n * Creates a VexAuthAdapter from a BetterAuthOptions config.\n *\n * Accepts the same config object you pass to betterAuth() on the server.\n * Only reads schema-affecting properties (modelNames, additionalFields, plugins).\n * Runtime options (database, secret, baseURL, etc.) are ignored.\n *\n * @example\n * ```ts\n * import { vexBetterAuth } from \"@vexcms/better-auth\";\n * import { admin } from \"better-auth/plugins\";\n *\n * export default defineConfig({\n * auth: vexBetterAuth({\n * user: { modelName: \"users\" },\n * plugins: [admin()],\n * }),\n * // ...\n * });\n * ```\n */\nexport function vexBetterAuth(props?: VexBetterAuthOptions): BetterAuthAdapter {\n const collections = extractAuthCollections(props?.config ?? {});\n\n return {\n name: \"better-auth\",\n collections,\n } as BetterAuthAdapter;\n}\n"],"mappings":";AAAA;AAAA,EACE;AAAA,OACK;AAOP,SAAS,qBAAqB;AAG9B,IAAM,kBAA+C;AAAA,EACnD,MAAM,oBAAI,IAAI,CAAC,QAAQ,SAAS,QAAQ,UAAU,aAAa,YAAY,CAAC;AAC9E;AAGA,IAAM,gBAA6C;AAAA,EACjD,SAAS,oBAAI,IAAI,CAAC,OAAO,CAAC;AAAA,EAC1B,SAAS,oBAAI,IAAI,CAAC,eAAe,gBAAgB,SAAS,CAAC;AAAA,EAC3D,cAAc,oBAAI,IAAI,CAAC,OAAO,CAAC;AACjC;AAGA,IAAM,oBAA0E;AAAA,EAC9E,MAAM,EAAE,UAAU,QAAQ,QAAQ,QAAQ;AAAA,EAC1C,SAAS,EAAE,UAAU,WAAW,QAAQ,WAAW;AAAA,EACnD,SAAS,EAAE,UAAU,WAAW,QAAQ,WAAW;AAAA,EACnD,cAAc,EAAE,UAAU,gBAAgB,QAAQ,gBAAgB;AACpE;AAGA,IAAM,eAA4B,oBAAI,IAAI,CAAC,MAAM,CAAC;AAGlD,IAAM,kBAA4C;AAAA,EAChD,MAAM,CAAC,OAAO,QAAQ,SAAS,WAAW;AAAA,EAC1C,SAAS,CAAC,OAAO,UAAU,aAAa,WAAW;AAAA,EACnD,SAAS,CAAC,OAAO,cAAc,aAAa,QAAQ;AAAA,EACpD,cAAc,CAAC,OAAO,cAAc,aAAa,WAAW;AAC9D;AAQA,SAAS,wBACP,WACA,WAC8B;AAC9B,QAAM,SAAS,cAAc,SAAS,GAAG,IAAI,SAAS;AACtD,MAAI,OAAQ,QAAO,EAAE,QAAQ,KAAK;AAElC,QAAM,WAAW,gBAAgB,SAAS,GAAG,IAAI,SAAS;AAC1D,MAAI,CAAC,SAAU,QAAO,EAAE,UAAU,KAAK;AAEvC,SAAO;AACT;AAYA,SAAS,mBACP,WACA,QAC0B;AAC1B,QAAM,YAAsC,CAAC;AAE7C,aAAW,CAAC,WAAW,SAAS,KAAK,OAAO,QAAQ,MAAM,GAAG;AAC3D,QAAI,cAAc,KAAM;AAExB,UAAM,WAAW,UAAU,YAAY;AACvC,UAAM,QAAQ,wBAAwB,WAAW,SAAS;AAE1D,QAAI,UAAU,YAAY;AACxB,gBAAU,SAAS,IAAI;AAAA,QACrB,MAAM;AAAA,QACN,IAAI,UAAU,WAAW;AAAA,QACzB;AAAA,QACA,GAAI,SAAS,EAAE,MAAM;AAAA,MACvB;AACA;AAAA,IACF;AAEA,QAAI,MAAM,QAAQ,UAAU,IAAI,GAAG;AACjC,gBAAU,SAAS,IAAI;AAAA,QACrB,MAAM;AAAA,QACN,SAAS,UAAU,KAAK,IAAI,CAAC,SAAiB;AAAA,UAC5C,OAAO,IAAI,OAAO,CAAC,EAAE,YAAY,IAAI,IAAI,MAAM,CAAC;AAAA,UAChD,OAAO;AAAA,QACT,EAAE;AAAA,QACF;AAAA,QACA,GAAI,YAAY,EAAE,cAAc,UAAU,KAAK,CAAC,EAAE;AAAA,QAClD,GAAI,SAAS,EAAE,MAAM;AAAA,MACvB;AACA;AAAA,IACF;AAEA,YAAQ,UAAU,MAAM;AAAA,MACtB,KAAK;AACH,kBAAU,SAAS,IAAI;AAAA,UACrB,MAAM;AAAA,UACN;AAAA,UACA,GAAI,YAAY,EAAE,cAAc,GAAG;AAAA,UACnC,GAAI,SAAS,EAAE,MAAM;AAAA,QACvB;AACA;AAAA,MACF,KAAK;AACH,kBAAU,SAAS,IAAI;AAAA,UACrB,MAAM;AAAA,UACN;AAAA,UACA,GAAI,YAAY,EAAE,cAAc,EAAE;AAAA,UAClC,GAAI,SAAS,EAAE,MAAM;AAAA,QACvB;AACA;AAAA,MACF,KAAK;AACH,kBAAU,SAAS,IAAI;AAAA,UACrB,MAAM;AAAA,UACN;AAAA,UACA,GAAI,YAAY,EAAE,cAAc,MAAM;AAAA,UACtC,GAAI,SAAS,EAAE,MAAM;AAAA,QACvB;AACA;AAAA,MACF,KAAK;AACH,kBAAU,SAAS,IAAI;AAAA,UACrB,MAAM;AAAA,UACN;AAAA,UACA,GAAI,YAAY,EAAE,cAAc,EAAE;AAAA,UAClC,GAAI,SAAS,EAAE,MAAM;AAAA,QACvB;AACA;AAAA,MACF,KAAK;AACH,kBAAU,SAAS,IAAI;AAAA,UACrB,MAAM;AAAA,UACN;AAAA,UACA,GAAI,SAAS,EAAE,MAAM;AAAA,QACvB;AACA;AAAA,MACF,KAAK;AACH,kBAAU,SAAS,IAAI;AAAA,UACrB,MAAM;AAAA,UACN,OAAO,EAAE,MAAM,OAAO;AAAA,UACtB;AAAA,UACA,GAAI,SAAS,EAAE,MAAM;AAAA,QACvB;AACA;AAAA,MACF,KAAK;AACH,kBAAU,SAAS,IAAI;AAAA,UACrB,MAAM;AAAA,UACN,OAAO,EAAE,MAAM,SAAS;AAAA,UACxB;AAAA,UACA,GAAI,SAAS,EAAE,MAAM;AAAA,QACvB;AACA;AAAA,MACF;AACE,cAAM,IAAI;AAAA,UACR,mCAAmC,UAAU,IAAI;AAAA,QACnD;AAAA,IACJ;AAAA,EACF;AAEA,SAAO;AACT;AAMA,SAAS,eACP,QACsC;AACtC,QAAM,UAAgD,CAAC;AACvD,aAAW,CAAC,WAAW,SAAS,KAAK,OAAO,QAAQ,MAAM,GAAG;AAC3D,QAAI,cAAc,KAAM;AACxB,QAAI,UAAU,SAAS,UAAU,QAAQ;AACvC,cAAQ,KAAK,EAAE,MAAM,MAAM,SAAS,IAAI,QAAQ,CAAC,SAAS,EAAE,CAAC;AAAA,IAC/D;AAAA,EACF;AACA,SAAO;AACT;AAgBO,SAAS,uBACd,QACiB;AACjB,QAAM,eAAe,cAAc,MAAM;AACzC,QAAM,cAA+B,CAAC;AAEtC,aAAW,CAAC,WAAW,QAAQ,KAAK,OAAO,QAAQ,YAAY,GAAG;AAChE,UAAM,OAAO,SAAS,aAAa;AACnC,UAAM,SAAS,mBAAmB,MAAM,SAAS,MAAM;AACvD,UAAM,UAAU,eAAe,SAAS,MAAM;AAC9C,UAAM,SAAS,kBAAkB,IAAI;AACrC,UAAM,iBAAiB,gBAAgB,IAAI;AAE3C,gBAAY,KAAK;AAAA,MACf;AAAA,MACA;AAAA,MACA,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;AAAA,MAC3B,GAAI,QAAQ,SAAS,IAAI,EAAE,QAAQ,IAAI,CAAC;AAAA,MACxC,GAAI,aAAa,IAAI,IAAI,IAAI,EAAE,aAAa,KAAK,IAAI,CAAC;AAAA,MACtD,OAAO;AAAA,QACL,OAAO;AAAA,QACP,YAAY;AAAA,QACZ,GAAI,iBAAiB,EAAE,eAAe,IAAI,CAAC;AAAA,MAC7C;AAAA,IACF,CAAC;AAAA,EACH;AAEA,SAAO;AACT;;;AC/IO,SAAS,cAAc,OAAiD;AAC7E,QAAM,cAAc,uBAAuB,OAAO,UAAU,CAAC,CAAC;AAE9D,SAAO;AAAA,IACL,MAAM;AAAA,IACN;AAAA,EACF;AACF;","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vexcms/better-auth",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.10",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
],
|
|
16
16
|
"peerDependencies": {
|
|
17
17
|
"better-auth": ">=1.4.9 <1.5.0",
|
|
18
|
-
"@vexcms/core": "0.0.
|
|
18
|
+
"@vexcms/core": "0.0.10"
|
|
19
19
|
},
|
|
20
20
|
"devDependencies": {
|
|
21
21
|
"@vitest/coverage-v8": "^4.0.18",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"tsup": "^8.5.1",
|
|
24
24
|
"typescript": "^5.9.3",
|
|
25
25
|
"vitest": "^4.0.0",
|
|
26
|
-
"@vexcms/core": "0.0.
|
|
26
|
+
"@vexcms/core": "0.0.10",
|
|
27
27
|
"@vexcms/tsconfig": "0.0.0"
|
|
28
28
|
},
|
|
29
29
|
"publishConfig": {
|