diff --git a/package.json b/package.json index 7e0b831a..4ccdc3c6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "zenstack-v3", - "version": "3.0.0-beta.23", + "version": "3.0.0-beta.24", "description": "ZenStack", "packageManager": "pnpm@10.20.0", "scripts": { diff --git a/packages/auth-adapters/better-auth/eslint.config.js b/packages/auth-adapters/better-auth/eslint.config.js new file mode 100644 index 00000000..f04dc9fe --- /dev/null +++ b/packages/auth-adapters/better-auth/eslint.config.js @@ -0,0 +1,9 @@ +import config from '@zenstackhq/eslint-config/base.js'; +import tseslint from 'typescript-eslint'; + +/** @type {import("eslint").Linter.Config} */ +export default tseslint.config(config, { + rules: { + '@typescript-eslint/no-unused-expressions': 'off', + }, +}); diff --git a/packages/dialects/sql.js/package.json b/packages/auth-adapters/better-auth/package.json similarity index 58% rename from packages/dialects/sql.js/package.json rename to packages/auth-adapters/better-auth/package.json index 1dbd834f..455426cf 100644 --- a/packages/dialects/sql.js/package.json +++ b/packages/auth-adapters/better-auth/package.json @@ -1,7 +1,7 @@ { - "name": "@zenstackhq/kysely-sql-js", - "version": "3.0.0-beta.23", - "description": "Kysely dialect for sql.js", + "name": "@zenstackhq/better-auth", + "version": "3.0.0-beta.24", + "description": "ZenStack Better Auth Adapter. This adapter is modified from better-auth's Prisma adapter.", "type": "module", "scripts": { "build": "tsc --noEmit && tsup-node", @@ -9,7 +9,10 @@ "lint": "eslint src --ext ts", "pack": "pnpm pack" }, - "keywords": [], + "keywords": [ + "better-auth", + "auth" + ], "author": "ZenStack Team", "license": "MIT", "files": [ @@ -31,16 +34,21 @@ "require": "./package.json" } }, + "dependencies": { + "@zenstackhq/orm": "workspace:*", + "@zenstackhq/language": "workspace:*", + "@zenstackhq/common-helpers": "workspace:*", + "ts-pattern": "catalog:" + }, + "peerDependencies": { + "@better-auth/core": "^1.3.0", + "better-auth": "^1.3.0" + }, "devDependencies": { - "@types/sql.js": "^1.4.9", + "@better-auth/core": "^1.3.0", + "better-auth": "^1.3.0", "@zenstackhq/eslint-config": "workspace:*", "@zenstackhq/typescript-config": "workspace:*", - "@zenstackhq/vitest-config": "workspace:*", - "sql.js": "^1.13.0", - "kysely": "catalog:" - }, - "peerDependencies": { - "sql.js": "^1.13.0", - "kysely": "catalog:" + "@zenstackhq/vitest-config": "workspace:*" } } diff --git a/packages/auth-adapters/better-auth/src/adapter.ts b/packages/auth-adapters/better-auth/src/adapter.ts new file mode 100644 index 00000000..935f5fde --- /dev/null +++ b/packages/auth-adapters/better-auth/src/adapter.ts @@ -0,0 +1,240 @@ +import type { BetterAuthOptions } from '@better-auth/core'; +import type { DBAdapter, DBAdapterDebugLogOption, Where } from '@better-auth/core/db/adapter'; +import { BetterAuthError } from '@better-auth/core/error'; +import type { ClientContract, ModelOperations, UpdateInput } from '@zenstackhq/orm'; +import type { GetModels, SchemaDef } from '@zenstackhq/orm/schema'; +import { + createAdapterFactory, + type AdapterFactoryCustomizeAdapterCreator, + type AdapterFactoryOptions, +} from 'better-auth/adapters'; +import { generateSchema } from './schema-generator'; + +/** + * Options for the ZenStack adapter factory. + */ +export interface AdapterConfig { + /** + * Database provider + */ + provider: 'sqlite' | 'postgresql'; + + /** + * Enable debug logs for the adapter + * + * @default false + */ + debugLogs?: DBAdapterDebugLogOption | undefined; + + /** + * Use plural table names + * + * @default false + */ + usePlural?: boolean | undefined; +} + +/** + * Create a Better-Auth adapter for ZenStack ORM. + * @param db ZenStack ORM client instance + * @param config adapter configuration options + */ +export const zenstackAdapter = (db: ClientContract, config: AdapterConfig) => { + let lazyOptions: BetterAuthOptions | null = null; + const createCustomAdapter = + (db: ClientContract): AdapterFactoryCustomizeAdapterCreator => + ({ getFieldName, options }) => { + const convertSelect = (select?: string[], model?: string) => { + if (!select || !model) return undefined; + return select.reduce((prev, cur) => { + return { + ...prev, + [getFieldName({ model, field: cur })]: true, + }; + }, {}); + }; + function operatorToORMOperator(operator: string) { + switch (operator) { + case 'starts_with': + return 'startsWith'; + case 'ends_with': + return 'endsWith'; + case 'ne': + return 'not'; + case 'not_in': + return 'notIn'; + default: + return operator; + } + } + const convertWhereClause = (model: string, where?: Where[]): any => { + if (!where || !where.length) return {}; + if (where.length === 1) { + const w = where[0]!; + if (!w) { + throw new BetterAuthError('Invalid where clause'); + } + return { + [getFieldName({ model, field: w.field })]: + w.operator === 'eq' || !w.operator + ? w.value + : { + [operatorToORMOperator(w.operator)]: w.value, + }, + }; + } + const and = where.filter((w) => w.connector === 'AND' || !w.connector); + const or = where.filter((w) => w.connector === 'OR'); + const andClause = and.map((w) => { + return { + [getFieldName({ model, field: w.field })]: + w.operator === 'eq' || !w.operator + ? w.value + : { + [operatorToORMOperator(w.operator)]: w.value, + }, + }; + }); + const orClause = or.map((w) => { + return { + [getFieldName({ model, field: w.field })]: + w.operator === 'eq' || !w.operator + ? w.value + : { + [operatorToORMOperator(w.operator)]: w.value, + }, + }; + }); + + return { + ...(andClause.length ? { AND: andClause } : {}), + ...(orClause.length ? { OR: orClause } : {}), + }; + }; + + function requireModelDb(db: ClientContract, model: string) { + const modelDb = db[model as keyof typeof db]; + if (!modelDb) { + throw new BetterAuthError( + `Model ${model} does not exist in the database. If you haven't generated the ZenStack schema, you need to run 'npx zen generate'`, + ); + } + return modelDb as unknown as ModelOperations>; + } + + return { + async create({ model, data: values, select }): Promise { + const modelDb = requireModelDb(db, model); + return await modelDb.create({ + data: values, + select: convertSelect(select, model), + }); + }, + + async findOne({ model, where, select }): Promise { + const modelDb = requireModelDb(db, model); + const whereClause = convertWhereClause(model, where); + return await modelDb.findFirst({ + where: whereClause, + select: convertSelect(select, model), + }); + }, + + async findMany({ model, where, limit, offset, sortBy }): Promise { + const modelDb = requireModelDb(db, model); + const whereClause = convertWhereClause(model, where); + return await modelDb.findMany({ + where: whereClause, + take: limit || 100, + skip: offset || 0, + ...(sortBy?.field + ? { + orderBy: { + [getFieldName({ model, field: sortBy.field })]: + sortBy.direction === 'desc' ? 'desc' : 'asc', + } as any, + } + : {}), + }); + }, + + async count({ model, where }) { + const modelDb = requireModelDb(db, model); + const whereClause = convertWhereClause(model, where); + return await modelDb.count({ + where: whereClause, + }); + }, + + async update({ model, where, update }): Promise { + const modelDb = requireModelDb(db, model); + const whereClause = convertWhereClause(model, where); + return await modelDb.update({ + where: whereClause, + data: update as UpdateInput>, + }); + }, + + async updateMany({ model, where, update }) { + const modelDb = requireModelDb(db, model); + const whereClause = convertWhereClause(model, where); + const result = await modelDb.updateMany({ + where: whereClause, + data: update, + }); + return result ? (result.count as number) : 0; + }, + + async delete({ model, where }): Promise { + const modelDb = requireModelDb(db, model); + const whereClause = convertWhereClause(model, where); + try { + await modelDb.delete({ + where: whereClause, + }); + } catch { + // If the record doesn't exist, we don't want to throw an error + } + }, + + async deleteMany({ model, where }) { + const modelDb = requireModelDb(db, model); + const whereClause = convertWhereClause(model, where); + const result = await modelDb.deleteMany({ + where: whereClause, + }); + return result ? (result.count as number) : 0; + }, + + options: config, + + createSchema: async ({ file, tables }) => { + return generateSchema(file, tables, config, options); + }, + }; + }; + + const adapterOptions: AdapterFactoryOptions = { + config: { + adapterId: 'zenstack', + adapterName: 'ZenStack Adapter', + usePlural: config.usePlural ?? false, + debugLogs: config.debugLogs ?? false, + transaction: (cb) => + db.$transaction((tx) => { + const adapter = createAdapterFactory({ + config: adapterOptions!.config, + adapter: createCustomAdapter(tx as ClientContract), + })(lazyOptions!); + return cb(adapter); + }), + }, + adapter: createCustomAdapter(db), + }; + + const adapter = createAdapterFactory(adapterOptions); + return (options: BetterAuthOptions): DBAdapter => { + lazyOptions = options; + return adapter(options); + }; +}; diff --git a/packages/auth-adapters/better-auth/src/index.ts b/packages/auth-adapters/better-auth/src/index.ts new file mode 100644 index 00000000..92d8b5cc --- /dev/null +++ b/packages/auth-adapters/better-auth/src/index.ts @@ -0,0 +1 @@ +export { zenstackAdapter, type AdapterConfig } from './adapter'; diff --git a/packages/auth-adapters/better-auth/src/schema-generator.ts b/packages/auth-adapters/better-auth/src/schema-generator.ts new file mode 100644 index 00000000..ea7ac4e0 --- /dev/null +++ b/packages/auth-adapters/better-auth/src/schema-generator.ts @@ -0,0 +1,551 @@ +import { lowerCaseFirst, upperCaseFirst } from '@zenstackhq/common-helpers'; +import { formatDocument, loadDocument, ZModelCodeGenerator } from '@zenstackhq/language'; +import { + Argument, + ArrayExpr, + AttributeArg, + BooleanLiteral, + ConfigExpr, + ConfigField, + DataField, + DataFieldAttribute, + DataFieldType, + DataModel, + DataModelAttribute, + DataSource, + InvocationExpr, + isDataModel, + Model, + ReferenceExpr, + StringLiteral, +} from '@zenstackhq/language/ast'; +import { hasAttribute } from '@zenstackhq/language/utils'; +import { type BetterAuthOptions } from 'better-auth'; +import type { DBAdapterSchemaCreation } from 'better-auth/adapters'; +import type { BetterAuthDBSchema, DBFieldAttribute, DBFieldType } from 'better-auth/db'; +import fs from 'node:fs'; +import { match } from 'ts-pattern'; +import type { AdapterConfig } from './adapter'; + +export async function generateSchema( + file: string | undefined, + tables: BetterAuthDBSchema, + config: AdapterConfig, + options: BetterAuthOptions, +): Promise { + let filePath = file; + + if (!filePath) { + // TODO: respect "zenstack" entry in package.json for default schema file path + if (fs.existsSync('./schema.zmodel')) { + filePath = './schema.zmodel'; + } else { + filePath = './zenstack/schema.zmodel'; + } + } + + const schemaExists = fs.existsSync(filePath); + + const schema = await updateSchema(filePath, tables, config, options); + + return { + code: schema ?? '', + path: filePath, + overwrite: schemaExists && !!schema, + }; +} + +async function updateSchema( + schemaPath: string, + tables: BetterAuthDBSchema, + config: AdapterConfig, + options: BetterAuthOptions, +) { + let zmodel: Model | undefined; + if (fs.existsSync(schemaPath)) { + const loadResult = await loadDocument(schemaPath); + if (!loadResult.success) { + throw new Error(`Failed to load existing schema at ${schemaPath}: ${loadResult.errors.join(', ')}`); + } + zmodel = loadResult.model; + } else { + zmodel = initializeZmodel(config); + } + + // collect to-many relations + const toManyRelations = new Map(); + for (const [tableName, table] of Object.entries(tables)) { + const fields = tables[tableName]?.fields; + for (const field in fields) { + const attr = fields[field]!; + if (attr.references) { + const referencedOriginalModel = attr.references.model; + const referencedCustomModel = tables[referencedOriginalModel]?.modelName || referencedOriginalModel; + const referencedModelNameCap = upperCaseFirst(referencedCustomModel); + if (!toManyRelations.has(referencedModelNameCap)) { + toManyRelations.set(referencedModelNameCap, new Set()); + } + const currentCustomModel = table.modelName ?? tableName; + const currentModelNameCap = upperCaseFirst(currentCustomModel); + toManyRelations.get(referencedModelNameCap).add(currentModelNameCap); + } + } + } + + let changed = false; + + for (const [name, table] of Object.entries(tables)) { + const c = addOrUpdateModel( + name, + table, + zmodel, + tables, + toManyRelations, + !!options.advanced?.database?.useNumberId, + ); + changed = changed || c; + } + + if (!changed) { + return undefined; + } + + const generator = new ZModelCodeGenerator(); + let content = generator.generate(zmodel); + + try { + content = await formatDocument(content); + } catch { + // ignore formatting errors + } + + return content; +} + +// @default(now()) +function addDefaultNow(df: DataField) { + const nowArg: AttributeArg = { + $type: 'AttributeArg', + } as any; + const nowExpr: InvocationExpr = { + $type: 'InvocationExpr', + function: { $refText: 'now' }, + args: [], + $container: nowArg, + }; + nowArg.value = nowExpr; + addFieldAttribute(df, '@default', [nowArg]); +} + +function createDataModel(modelName: string, zmodel: Model, numericId: boolean) { + const dataModel: DataModel = { + $type: 'DataModel', + name: modelName, + fields: [], + attributes: [], + mixins: [], + comments: [], + isView: false, + $container: zmodel, + }; + + let idField: DataField; + if (numericId) { + idField = addModelField(dataModel, 'id', 'Int', false, false); + } else { + idField = addModelField(dataModel, 'id', 'String', false, false); + } + addFieldAttribute(idField, '@id'); + + return dataModel; +} + +function addModelField(dataModel: DataModel, fieldName: string, fieldType: string, array: boolean, optional: boolean) { + const field: DataField = { + $type: 'DataField', + name: fieldName, + attributes: [], + comments: [], + $container: dataModel, + } as any; + field.type = { + $type: 'DataFieldType', + type: fieldType as any, + array, + optional, + $container: field, + }; + dataModel.fields.push(field); + return field; +} + +function initializeZmodel(config: AdapterConfig) { + const zmodel: Model = { + $type: 'Model', + declarations: [], + imports: [], + }; + + // datasource db { ... } + const ds: DataSource = { + $type: 'DataSource', + name: 'db', + fields: [], + $container: zmodel, + }; + zmodel.declarations.push(ds); + + // provider = 'sqlite' | 'postgresql' + const providerField: ConfigField = { + $type: 'ConfigField', + name: 'provider', + $container: ds, + } as any; + providerField.value = { + $type: 'StringLiteral', + value: config.provider, + $container: providerField, + } satisfies ConfigExpr; + + const urlField: ConfigField = { + $type: 'ConfigField', + name: 'url', + $container: ds, + } as any; + + // env('DATABASE_URL') + const envCall: InvocationExpr = { + $type: 'InvocationExpr', + function: { + $refText: 'env', + }, + args: [], + $container: urlField, + }; + + // 'DATABASE_URL' arg + const dbUrlArg: Argument = { + $type: 'Argument', + } as any; + dbUrlArg.value = { + $type: 'StringLiteral', + value: 'DATABASE_URL', + $container: dbUrlArg, + } satisfies ConfigExpr; + + envCall.args = [dbUrlArg]; + + urlField.value = + config.provider === 'sqlite' + ? { + $type: 'StringLiteral', + value: 'file:./dev.db', + $container: urlField, + } + : envCall; + + ds.fields.push(providerField); + ds.fields.push(urlField); + + return zmodel; +} + +function getMappedFieldType({ bigint, type }: DBFieldAttribute) { + return match(type) + .with('string', () => ({ type: 'String' })) + .with('number', () => (bigint ? { type: 'BigInt' } : { type: 'Int' })) + .with('boolean', () => ({ type: 'Boolean' })) + .with('date', () => ({ type: 'DateTime' })) + .with('json', () => ({ type: 'Json' })) + .with('string[]', () => ({ type: 'String', array: true })) + .with('number[]', () => ({ type: 'Int', array: true })) + .otherwise(() => { + throw new Error(`Unsupported field type: ${type}`); + }); +} + +function addOrUpdateModel( + tableName: string, + table: BetterAuthDBSchema[string], + zmodel: Model, + tables: BetterAuthDBSchema, + toManyRelations: Map>, + numericId: boolean, +): boolean { + let changed = false; + const customModelName = tables[tableName]?.modelName ?? tableName; + const modelName = upperCaseFirst(customModelName); + + let dataModel = zmodel.declarations.find((d): d is DataModel => isDataModel(d) && d.name === modelName); + if (!dataModel) { + changed = true; + dataModel = createDataModel(modelName, zmodel, numericId); + zmodel.declarations.push(dataModel); + } + + if (modelName !== tableName && !hasAttribute(dataModel, '@@map')) { + addModelAttribute(dataModel, '@@map', [createStringAttributeArg(tableName)]); + } + + for (const [fName, field] of Object.entries(table.fields)) { + const fieldName = field.fieldName ?? fName; + if (dataModel.fields.some((f) => f.name === fieldName)) { + continue; + } + + changed = true; + + if (!field.references) { + // scalar field + const { array, type } = getMappedFieldType(field); + + const df: DataField = { + $type: 'DataField', + name: fieldName, + attributes: [], + comments: [], + $container: dataModel, + } as any; + df.type = { + $type: 'DataFieldType', + type: type as any, + array: !!array, + optional: !field.required, + $container: df, + }; + dataModel.fields.push(df); + + // @id + if (fieldName === 'id') { + addFieldAttribute(df, '@id'); + } + + // @unique + if (field.unique) { + addFieldAttribute(df, '@unique'); + } + + // @default + if (field.defaultValue !== undefined) { + if (fieldName === 'createdAt') { + // @default(now()) + addDefaultNow(df); + } else if (typeof field.defaultValue === 'boolean') { + addFieldAttribute(df, '@default', [createBooleanAttributeArg(field.defaultValue)]); + } else if (typeof field.defaultValue === 'function') { + // For other function-based defaults, we'll need to check what they return + const defaultVal = field.defaultValue(); + if (defaultVal instanceof Date) { + // @default(now()) + addDefaultNow(df); + } else { + console.warn( + `Warning: Unsupported default function for field ${fieldName} in model ${table.modelName}. Please adjust manually.`, + ); + } + } + } + + // This is a special handling for updatedAt fields + if (fieldName === 'updatedAt' && field.onUpdate) { + addFieldAttribute(df, '@updatedAt'); + } else if (field.onUpdate) { + console.warn( + `Warning: 'onUpdate' is only supported on 'updatedAt' fields. Please adjust manually for field ${fieldName} in model ${table.modelName}.`, + ); + } + } else { + // relation + + // fk field + addModelField(dataModel, fieldName, numericId ? 'Int' : 'String', false, !field.required); + + // relation field + const referencedOriginalModelName = field.references.model; + const referencedCustomModelName = + tables[referencedOriginalModelName]?.modelName || referencedOriginalModelName; + + const relationField: DataField = { + $type: 'DataField', + name: lowerCaseFirst(referencedCustomModelName), + attributes: [], + comments: [], + $container: dataModel, + } as any; + relationField.type = { + $type: 'DataFieldType', + reference: { + $refText: upperCaseFirst(referencedCustomModelName), + }, + array: (field.type as string).endsWith('[]'), + optional: !field.required, + $container: relationField, + } satisfies DataFieldType; + + let action = 'Cascade'; + if (field.references.onDelete === 'no action') action = 'NoAction'; + else if (field.references.onDelete === 'set null') action = 'SetNull'; + else if (field.references.onDelete === 'set default') action = 'SetDefault'; + else if (field.references.onDelete === 'restrict') action = 'Restrict'; + + // @relation(fields: [field], references: [referencedField], onDelete: action) + const relationAttr: DataFieldAttribute = { + $type: 'DataFieldAttribute', + decl: { + $refText: '@relation', + }, + args: [], + $container: relationField, + }; + + // fields: [field] + const fieldsArg: AttributeArg = { + $type: 'AttributeArg', + name: 'fields', + $container: relationAttr, + } as any; + const fieldsExpr: ArrayExpr = { + $type: 'ArrayExpr', + items: [], + $container: fieldsArg, + }; + const fkRefExpr: ReferenceExpr = { + $type: 'ReferenceExpr', + args: [], + $container: fieldsExpr, + target: { + $refText: fieldName, + }, + }; + fieldsExpr.items.push(fkRefExpr); + fieldsArg.value = fieldsExpr; + + // references: [referencedField] + const referencesArg: AttributeArg = { + $type: 'AttributeArg', + name: 'references', + $container: relationAttr, + } as any; + const referencesExpr: ArrayExpr = { + $type: 'ArrayExpr', + items: [], + $container: referencesArg, + }; + const pkRefExpr: ReferenceExpr = { + $type: 'ReferenceExpr', + args: [], + $container: referencesExpr, + target: { + $refText: field.references.field, + }, + }; + referencesExpr.items.push(pkRefExpr); + referencesArg.value = referencesExpr; + + // onDelete: action + const onDeleteArg: AttributeArg = { + $type: 'AttributeArg', + name: 'onDelete', + $container: relationAttr, + } as any; + const onDeleteValueExpr: ReferenceExpr = { + $type: 'ReferenceExpr', + target: { $refText: action }, + args: [], + $container: onDeleteArg, + }; + onDeleteArg.value = onDeleteValueExpr; + + relationAttr.args.push(...[fieldsArg, referencesArg, onDeleteArg]); + relationField.attributes.push(relationAttr); + + dataModel.fields.push(relationField); + } + } + + // add to-many relations + if (toManyRelations.has(modelName)) { + const relations = toManyRelations.get(modelName)!; + for (const relatedModel of relations) { + const relationName = `${lowerCaseFirst(relatedModel)}s`; + if (!dataModel.fields.some((f) => f.name === relationName)) { + const relationField: DataField = { + $type: 'DataField', + name: relationName, + attributes: [], + comments: [], + $container: dataModel, + } as any; + const relationType: DataFieldType = { + $type: 'DataFieldType', + reference: { + $refText: relatedModel, + }, + array: true, + optional: false, + $container: relationField, + }; + relationField.type = relationType; + dataModel.fields.push(relationField); + } + } + } + + return changed; +} + +function addModelAttribute(dataModel: DataModel, name: string, args: Omit[] = []) { + const attr: DataModelAttribute = { + $type: 'DataModelAttribute', + decl: { $refText: name }, + $container: dataModel, + args: [], + }; + const finalArgs = args.map((arg) => ({ + ...arg, + $container: attr, + })); + attr.args.push(...finalArgs); + dataModel.attributes.push(attr); +} + +function addFieldAttribute(dataField: DataField, name: string, args: Omit[] = []) { + const attr: DataFieldAttribute = { + $type: 'DataFieldAttribute', + decl: { $refText: name }, + $container: dataField, + args: [], + }; + const finalArgs = args.map((arg) => ({ + ...arg, + $container: attr, + })); + attr.args.push(...finalArgs); + dataField.attributes.push(attr); +} + +function createBooleanAttributeArg(value: boolean) { + const arg: AttributeArg = { + $type: 'AttributeArg', + } as any; + const expr: BooleanLiteral = { + $type: 'BooleanLiteral', + value, + $container: arg, + }; + arg.value = expr; + return arg; +} + +function createStringAttributeArg(value: string) { + const arg: AttributeArg = { + $type: 'AttributeArg', + } as any; + const expr: StringLiteral = { + $type: 'StringLiteral', + value, + $container: arg, + }; + arg.value = expr; + return arg; +} diff --git a/packages/auth-adapters/better-auth/tsconfig.json b/packages/auth-adapters/better-auth/tsconfig.json new file mode 100644 index 00000000..8784ef54 --- /dev/null +++ b/packages/auth-adapters/better-auth/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "@zenstackhq/typescript-config/base.json", + "compilerOptions": { + "rootDir": ".", + "noPropertyAccessFromIndexSignature": false + }, + "include": ["src/**/*"] +} diff --git a/packages/dialects/sql.js/tsup.config.ts b/packages/auth-adapters/better-auth/tsup.config.ts similarity index 100% rename from packages/dialects/sql.js/tsup.config.ts rename to packages/auth-adapters/better-auth/tsup.config.ts diff --git a/packages/dialects/sql.js/vitest.config.ts b/packages/auth-adapters/better-auth/vitest.config.ts similarity index 100% rename from packages/dialects/sql.js/vitest.config.ts rename to packages/auth-adapters/better-auth/vitest.config.ts index 23c01e72..75a9f709 100644 --- a/packages/dialects/sql.js/vitest.config.ts +++ b/packages/auth-adapters/better-auth/vitest.config.ts @@ -1,4 +1,4 @@ -import { defineConfig, mergeConfig } from 'vitest/config'; import base from '@zenstackhq/vitest-config/base'; +import { defineConfig, mergeConfig } from 'vitest/config'; export default mergeConfig(base, defineConfig({})); diff --git a/packages/cli/package.json b/packages/cli/package.json index eaee0674..74c3d43f 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -3,7 +3,7 @@ "publisher": "zenstack", "displayName": "ZenStack CLI", "description": "FullStack database toolkit with built-in access control and automatic API generation.", - "version": "3.0.0-beta.23", + "version": "3.0.0-beta.24", "type": "module", "author": { "name": "ZenStack Team" diff --git a/packages/cli/src/actions/action-utils.ts b/packages/cli/src/actions/action-utils.ts index fa2bb0a5..a96bdb89 100644 --- a/packages/cli/src/actions/action-utils.ts +++ b/packages/cli/src/actions/action-utils.ts @@ -30,13 +30,13 @@ export function getSchemaFile(file?: string) { } } - if (fs.existsSync('./zenstack/schema.zmodel')) { - return './zenstack/schema.zmodel'; - } else if (fs.existsSync('./schema.zmodel')) { + if (fs.existsSync('./schema.zmodel')) { return './schema.zmodel'; + } else if (fs.existsSync('./zenstack/schema.zmodel')) { + return './zenstack/schema.zmodel'; } else { throw new CliError( - 'Schema file not found in default locations ("./zenstack/schema.zmodel" or "./schema.zmodel").', + 'Schema file not found in default locations ("./schema.zmodel" or "./zenstack/schema.zmodel").', ); } } diff --git a/packages/cli/src/actions/format.ts b/packages/cli/src/actions/format.ts new file mode 100644 index 00000000..5cb9b087 --- /dev/null +++ b/packages/cli/src/actions/format.ts @@ -0,0 +1,27 @@ +import { formatDocument } from '@zenstackhq/language'; +import colors from 'colors'; +import fs from 'node:fs'; +import { getSchemaFile } from './action-utils'; + +type Options = { + schema?: string; +}; + +/** + * CLI action for formatting a ZModel schema file. + */ +export async function run(options: Options) { + const schemaFile = getSchemaFile(options.schema); + let formattedContent: string; + + try { + formattedContent = await formatDocument(fs.readFileSync(schemaFile, 'utf-8')); + } catch (error) { + console.error(colors.red('✗ Schema formatting failed.')); + // Re-throw to maintain CLI exit code behavior + throw error; + } + + fs.writeFileSync(schemaFile, formattedContent, 'utf-8'); + console.log(colors.green('✓ Schema formatting completed successfully.')); +} diff --git a/packages/cli/src/actions/generate.ts b/packages/cli/src/actions/generate.ts index b8aedcb5..bd11c622 100644 --- a/packages/cli/src/actions/generate.ts +++ b/packages/cli/src/actions/generate.ts @@ -86,7 +86,19 @@ async function runPlugins(schemaFile: string, model: Model, outputPath: string, } if (cliPlugin) { - processedPlugins.push({ cliPlugin, pluginOptions: getPluginOptions(plugin) }); + const pluginOptions = getPluginOptions(plugin); + + // merge CLI options + if (provider === '@core/typescript') { + if (pluginOptions['lite'] === undefined) { + pluginOptions['lite'] = options.lite; + } + if (pluginOptions['liteOnly'] === undefined) { + pluginOptions['liteOnly'] = options.liteOnly; + } + } + + processedPlugins.push({ cliPlugin, pluginOptions }); } } diff --git a/packages/cli/src/actions/index.ts b/packages/cli/src/actions/index.ts index f2238829..f878bac0 100644 --- a/packages/cli/src/actions/index.ts +++ b/packages/cli/src/actions/index.ts @@ -1,8 +1,9 @@ +import { run as check } from './check'; import { run as db } from './db'; +import { run as format } from './format'; import { run as generate } from './generate'; import { run as info } from './info'; import { run as init } from './init'; import { run as migrate } from './migrate'; -import { run as check } from './check'; -export { db, generate, info, init, migrate, check }; +export { check, db, format, generate, info, init, migrate }; diff --git a/packages/cli/src/index.ts b/packages/cli/src/index.ts index a4119dfe..89eb6fcd 100644 --- a/packages/cli/src/index.ts +++ b/packages/cli/src/index.ts @@ -30,10 +30,15 @@ const checkAction = async (options: Parameters[0]): Promis await telemetry.trackCommand('check', () => actions.check(options)); }; -function createProgram() { - const program = new Command('zen'); +const formatAction = async (options: Parameters[0]): Promise => { + await telemetry.trackCommand('format', () => actions.format(options)); +}; - program.version(getVersion()!, '-v --version', 'display CLI version'); +function createProgram() { + const program = new Command('zen') + .alias('zenstack') + .helpOption('-h, --help', 'Show this help message') + .version(getVersion()!, '-v --version', 'Show CLI version'); const schemaExtensions = ZModelLanguageMetaData.fileExtensions.join(', '); @@ -55,7 +60,7 @@ function createProgram() { program .command('generate') - .description('Run code generation plugins.') + .description('Run code generation plugins') .addOption(schemaOption) .addOption(noVersionCheckOption) .addOption(new Option('-o, --output ', 'default output directory for code generation')) @@ -74,7 +79,7 @@ function createProgram() { .addOption(new Option('-n, --name ', 'migration name')) .addOption(new Option('--create-only', 'only create migration, do not apply')) .addOption(migrationsOption) - .description('Create a migration from changes in schema and apply it to the database.') + .description('Create a migration from changes in schema and apply it to the database') .action((options) => migrateAction('dev', options)); migrateCommand @@ -83,7 +88,7 @@ function createProgram() { .addOption(new Option('--force', 'skip the confirmation prompt')) .addOption(migrationsOption) .addOption(noVersionCheckOption) - .description('Reset your database and apply all migrations, all data will be lost.') + .description('Reset your database and apply all migrations, all data will be lost') .action((options) => migrateAction('reset', options)); migrateCommand @@ -91,7 +96,7 @@ function createProgram() { .addOption(schemaOption) .addOption(noVersionCheckOption) .addOption(migrationsOption) - .description('Deploy your pending migrations to your production/staging database.') + .description('Deploy your pending migrations to your production/staging database') .action((options) => migrateAction('deploy', options)); migrateCommand @@ -99,7 +104,7 @@ function createProgram() { .addOption(schemaOption) .addOption(noVersionCheckOption) .addOption(migrationsOption) - .description('Check the status of your database migrations.') + .description('Check the status of your database migrations') .action((options) => migrateAction('status', options)); migrateCommand @@ -109,14 +114,14 @@ function createProgram() { .addOption(migrationsOption) .addOption(new Option('--applied ', 'record a specific migration as applied')) .addOption(new Option('--rolled-back ', 'record a specific migration as rolled back')) - .description('Resolve issues with database migrations in deployment databases.') + .description('Resolve issues with database migrations in deployment databases') .action((options) => migrateAction('resolve', options)); - const dbCommand = program.command('db').description('Manage your database schema during development.'); + const dbCommand = program.command('db').description('Manage your database schema during development'); dbCommand .command('push') - .description('Push the state from your schema to your database.') + .description('Push the state from your schema to your database') .addOption(schemaOption) .addOption(noVersionCheckOption) .addOption(new Option('--accept-data-loss', 'ignore data loss warnings')) @@ -125,25 +130,34 @@ function createProgram() { program .command('info') - .description('Get information of installed ZenStack packages.') + .description('Get information of installed ZenStack packages') .argument('[path]', 'project path', '.') .addOption(noVersionCheckOption) .action(infoAction); program .command('init') - .description('Initialize an existing project for ZenStack.') + .description('Initialize an existing project for ZenStack') .argument('[path]', 'project path', '.') .addOption(noVersionCheckOption) .action(initAction); program .command('check') - .description('Check a ZModel schema for syntax or semantic errors.') + .description('Check a ZModel schema for syntax or semantic errors') .addOption(schemaOption) .addOption(noVersionCheckOption) .action(checkAction); + program + .command('format') + .description('Format a ZModel schema file') + .addOption(schemaOption) + .addOption(noVersionCheckOption) + .action(formatAction); + + program.addHelpCommand('help [command]', 'Display help for a command'); + program.hook('preAction', async (_thisCommand, actionCommand) => { if (actionCommand.getOptionValue('versionCheck') !== false) { await checkNewVersion(); diff --git a/packages/cli/src/plugins/typescript.ts b/packages/cli/src/plugins/typescript.ts index 25f950ab..8b3465e8 100644 --- a/packages/cli/src/plugins/typescript.ts +++ b/packages/cli/src/plugins/typescript.ts @@ -22,7 +22,18 @@ const plugin: CliPlugin = { // liteOnly mode const liteOnly = pluginOptions['liteOnly'] === true; - await new TsSchemaGenerator().generate(model, { outDir, lite, liteOnly }); + // add .js extension when importing + const importWithFileExtension = pluginOptions['importWithFileExtension']; + if (importWithFileExtension && typeof importWithFileExtension !== 'string') { + throw new Error('The "importWithFileExtension" option must be a string if specified.'); + } + + await new TsSchemaGenerator().generate(model, { + outDir, + lite, + liteOnly, + importWithFileExtension: importWithFileExtension as string | undefined, + }); }, }; diff --git a/packages/cli/src/utils/exec-utils.ts b/packages/cli/src/utils/exec-utils.ts index 2ef0e26d..0e4ad3ed 100644 --- a/packages/cli/src/utils/exec-utils.ts +++ b/packages/cli/src/utils/exec-utils.ts @@ -30,13 +30,24 @@ export function execPackage( * Utility for running prisma commands */ export function execPrisma(args: string, options?: Omit & { env?: Record }) { - let prismaPath: string; - if (typeof import.meta.resolve === 'function') { - // esm - prismaPath = fileURLToPath(import.meta.resolve('prisma/build/index.js')); - } else { - // cjs - prismaPath = require.resolve('prisma/build/index.js'); + let prismaPath: string | undefined; + try { + if (typeof import.meta.resolve === 'function') { + // esm + prismaPath = fileURLToPath(import.meta.resolve('prisma/build/index.js')); + } else { + // cjs + prismaPath = require.resolve('prisma/build/index.js'); + } + } catch { + // ignore and fallback } + + if (!prismaPath) { + // fallback to npx/bunx execute + execPackage(`prisma ${args}`, options); + return; + } + execSync(`node ${prismaPath} ${args}`, options); } diff --git a/packages/cli/test/format.test.ts b/packages/cli/test/format.test.ts new file mode 100644 index 00000000..9c95960a --- /dev/null +++ b/packages/cli/test/format.test.ts @@ -0,0 +1,33 @@ +import { describe, expect, it } from 'vitest'; +import { createProject, runCli } from './utils'; +import fs from 'node:fs'; + +const model = ` +model User { + id String @id @default(cuid()) + email String @unique +} +`; + +describe('CLI format command test', () => { + it('should format a valid schema successfully', () => { + const workDir = createProject(model); + expect(() => runCli('format', workDir)).not.toThrow(); + const updatedContent = fs.readFileSync(`${workDir}/zenstack/schema.zmodel`, 'utf-8'); + expect( + updatedContent.includes(`model User { + id String @id @default(cuid()) + email String @unique +}`), + ).toBeTruthy(); + }); + + it('should silently ignore invalid schema', () => { + const invalidModel = ` +model User { + id String @id @default(cuid()) +`; + const workDir = createProject(invalidModel); + expect(() => runCli('format', workDir)).not.toThrow(); + }); +}); diff --git a/packages/clients/tanstack-query/package.json b/packages/clients/tanstack-query/package.json index 4986ff92..ce745fcf 100644 --- a/packages/clients/tanstack-query/package.json +++ b/packages/clients/tanstack-query/package.json @@ -1,6 +1,6 @@ { "name": "@zenstackhq/tanstack-query", - "version": "3.0.0-beta.23", + "version": "3.0.0-beta.24", "description": "TanStack Query Client for consuming ZenStack v3's CRUD service", "main": "index.js", "type": "module", diff --git a/packages/common-helpers/package.json b/packages/common-helpers/package.json index a2d508f5..1d3261ef 100644 --- a/packages/common-helpers/package.json +++ b/packages/common-helpers/package.json @@ -1,6 +1,6 @@ { "name": "@zenstackhq/common-helpers", - "version": "3.0.0-beta.23", + "version": "3.0.0-beta.24", "description": "ZenStack Common Helpers", "type": "module", "scripts": { diff --git a/packages/config/eslint-config/package.json b/packages/config/eslint-config/package.json index c608b08b..79d3c626 100644 --- a/packages/config/eslint-config/package.json +++ b/packages/config/eslint-config/package.json @@ -1,6 +1,6 @@ { "name": "@zenstackhq/eslint-config", - "version": "3.0.0-beta.23", + "version": "3.0.0-beta.24", "type": "module", "private": true, "license": "MIT" diff --git a/packages/config/typescript-config/package.json b/packages/config/typescript-config/package.json index 4745bf17..3532e5c9 100644 --- a/packages/config/typescript-config/package.json +++ b/packages/config/typescript-config/package.json @@ -1,6 +1,6 @@ { "name": "@zenstackhq/typescript-config", - "version": "3.0.0-beta.23", + "version": "3.0.0-beta.24", "private": true, "license": "MIT" } diff --git a/packages/config/vitest-config/package.json b/packages/config/vitest-config/package.json index 6c4ad162..70e98df2 100644 --- a/packages/config/vitest-config/package.json +++ b/packages/config/vitest-config/package.json @@ -1,7 +1,7 @@ { "name": "@zenstackhq/vitest-config", "type": "module", - "version": "3.0.0-beta.23", + "version": "3.0.0-beta.24", "private": true, "license": "MIT", "exports": { diff --git a/packages/create-zenstack/package.json b/packages/create-zenstack/package.json index ead69cce..c147237d 100644 --- a/packages/create-zenstack/package.json +++ b/packages/create-zenstack/package.json @@ -1,6 +1,6 @@ { "name": "create-zenstack", - "version": "3.0.0-beta.23", + "version": "3.0.0-beta.24", "description": "Create a new ZenStack project", "type": "module", "scripts": { diff --git a/packages/dialects/sql.js/README.md b/packages/dialects/sql.js/README.md deleted file mode 100644 index e5ff101f..00000000 --- a/packages/dialects/sql.js/README.md +++ /dev/null @@ -1,25 +0,0 @@ -Forked from https://github.com/betarixm/kysely-sql-js - -## Usage - -```ts -import { type GeneratedAlways, Kysely } from 'kysely'; -import initSqlJs from 'sql.js'; - -import { SqlJsDialect } from '@zenstackhq/kysely-sql-js'; - -interface Database { - person: { - id: GeneratedAlways; - first_name: string | null; - last_name: string | null; - age: number; - }; -} - -const SqlJsStatic = await initSqlJs(); - -export const db = new Kysely({ - dialect: new SqlJsDialect({ sqlJs: new SqlJsStatic.Database() }), -}); -``` diff --git a/packages/dialects/sql.js/eslint.config.js b/packages/dialects/sql.js/eslint.config.js deleted file mode 100644 index 5698b991..00000000 --- a/packages/dialects/sql.js/eslint.config.js +++ /dev/null @@ -1,4 +0,0 @@ -import config from '@zenstackhq/eslint-config/base.js'; - -/** @type {import("eslint").Linter.Config} */ -export default config; diff --git a/packages/dialects/sql.js/src/index.ts b/packages/dialects/sql.js/src/index.ts deleted file mode 100644 index 096b4fc0..00000000 --- a/packages/dialects/sql.js/src/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export * from './connection'; -export * from './dialect'; -export * from './driver'; -export * from './types'; diff --git a/packages/dialects/sql.js/test/getting-started/database.ts b/packages/dialects/sql.js/test/getting-started/database.ts deleted file mode 100644 index 7ab61248..00000000 --- a/packages/dialects/sql.js/test/getting-started/database.ts +++ /dev/null @@ -1,12 +0,0 @@ -import type { Database } from './types'; - -import { Kysely } from 'kysely'; -import initSqlJs from 'sql.js'; - -import { SqlJsDialect } from '../../src'; - -const SqlJsStatic = await initSqlJs(); - -export const db = new Kysely({ - dialect: new SqlJsDialect({ sqlJs: new SqlJsStatic.Database() }), -}); diff --git a/packages/dialects/sql.js/test/getting-started/person-repository.test.ts b/packages/dialects/sql.js/test/getting-started/person-repository.test.ts deleted file mode 100644 index 4d00eb1f..00000000 --- a/packages/dialects/sql.js/test/getting-started/person-repository.test.ts +++ /dev/null @@ -1,94 +0,0 @@ -import { sql } from 'kysely'; -import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it } from 'vitest'; -import { db } from './database'; -import * as PersonRepository from './person-repository'; - -describe('person-repository', () => { - beforeEach(async () => { - await db - .insertInto('person') - .values({ - id: 123, - first_name: 'Arnold', - last_name: 'Schwarzenegger', - gender: 'other', - }) - .executeTakeFirstOrThrow(); - }); - - beforeAll(async () => { - await db.schema - .createTable('person') - .addColumn('id', 'integer', (cb) => cb.primaryKey().autoIncrement().notNull()) - .addColumn('first_name', 'varchar(255)', (cb) => cb.notNull()) - .addColumn('last_name', 'varchar(255)') - .addColumn('gender', 'varchar(50)', (cb) => cb.notNull()) - .addColumn('created_at', 'timestamp', (cb) => cb.notNull().defaultTo(sql`current_timestamp`)) - .execute(); - }); - - afterEach(async () => { - await sql`delete from ${sql.table('person')}`.execute(db); - }); - - afterAll(async () => { - await db.schema.dropTable('person').execute(); - }); - - it('should find a person with a given id', async () => { - expect(await PersonRepository.findPersonById(123)).toMatchObject({ - id: 123, - first_name: 'Arnold', - last_name: 'Schwarzenegger', - gender: 'other', - }); - }); - - it('should find all people named Arnold', async () => { - const people = await PersonRepository.findPeople({ first_name: 'Arnold' }); - - expect(people).toHaveLength(1); - expect(people[0]).toMatchObject({ - id: 123, - first_name: 'Arnold', - last_name: 'Schwarzenegger', - gender: 'other', - }); - }); - - it('should update gender of a person with a given id', async () => { - await PersonRepository.updatePerson(123, { gender: 'woman' }); - - expect(await PersonRepository.findPersonById(123)).toMatchObject({ - id: 123, - first_name: 'Arnold', - last_name: 'Schwarzenegger', - gender: 'woman', - }); - }); - - it('should create a person', async () => { - await PersonRepository.createPerson({ - first_name: 'Jennifer', - last_name: 'Aniston', - gender: 'woman', - }); - - expect(await PersonRepository.findPeople({ first_name: 'Jennifer' })).toHaveLength(1); - }); - - it('should create multiple persons', async () => { - const created = await PersonRepository.createPersons([ - { first_name: 'Brad', last_name: 'Pitt', gender: 'man' }, - { first_name: 'Angelina', last_name: 'Jolie', gender: 'woman' }, - ]); - await expect(PersonRepository.findPeople({ first_name: 'Brad' })).resolves.toBeTruthy(); - await expect(PersonRepository.findPeople({ first_name: 'Angelina' })).resolves.toBeTruthy(); - }); - - it('should delete a person with a given id', async () => { - await PersonRepository.deletePerson(123); - - expect(await PersonRepository.findPersonById(123)).toBeUndefined(); - }); -}); diff --git a/packages/dialects/sql.js/test/getting-started/person-repository.ts b/packages/dialects/sql.js/test/getting-started/person-repository.ts deleted file mode 100644 index f062a816..00000000 --- a/packages/dialects/sql.js/test/getting-started/person-repository.ts +++ /dev/null @@ -1,48 +0,0 @@ -import type { PersonUpdate, Person, NewPerson } from './types'; - -import { db } from './database'; - -export async function findPersonById(id: number) { - return await db.selectFrom('person').where('id', '=', id).selectAll().executeTakeFirst(); -} - -export async function findPeople(criteria: Partial) { - let query = db.selectFrom('person'); - - if (criteria.id) { - query = query.where('id', '=', criteria.id); // Kysely is immutable, you must re-assign! - } - - if (criteria.first_name) { - query = query.where('first_name', '=', criteria.first_name); - } - - if (criteria.last_name !== undefined) { - query = query.where('last_name', criteria.last_name === null ? 'is' : '=', criteria.last_name); - } - - if (criteria.gender) { - query = query.where('gender', '=', criteria.gender); - } - - if (criteria.created_at) { - query = query.where('created_at', '=', criteria.created_at); - } - - return await query.selectAll().execute(); -} - -export async function updatePerson(id: number, updateWith: PersonUpdate) { - await db.updateTable('person').set(updateWith).where('id', '=', id).execute(); -} - -export async function createPerson(person: NewPerson) { - return await db.insertInto('person').values(person).returningAll().executeTakeFirstOrThrow(); -} - -export async function createPersons(persons: NewPerson[]) { - return await db.insertInto('person').values(persons).executeTakeFirstOrThrow(); -} -export async function deletePerson(id: number) { - return await db.deleteFrom('person').where('id', '=', id).returningAll().executeTakeFirst(); -} diff --git a/packages/dialects/sql.js/test/getting-started/types.ts b/packages/dialects/sql.js/test/getting-started/types.ts deleted file mode 100644 index abe8bee2..00000000 --- a/packages/dialects/sql.js/test/getting-started/types.ts +++ /dev/null @@ -1,53 +0,0 @@ -import type { ColumnType, Generated, Insertable, Selectable, Updateable } from 'kysely'; - -export interface Database { - person: PersonTable; - pet: PetTable; -} - -// This interface describes the `person` table to Kysely. Table -// interfaces should only be used in the `Database` type above -// and never as a result type of a query!. See the `Person`, -// `NewPerson` and `PersonUpdate` types below. -export interface PersonTable { - // Columns that are generated by the database should be marked - // using the `Generated` type. This way they are automatically - // made optional in inserts and updates. - id: Generated; - - first_name: string; - gender: 'man' | 'woman' | 'other'; - - // If the column is nullable in the database, make its type nullable. - // Don't use optional properties. Optionality is always determined - // automatically by Kysely. - last_name: string | null; - - // You can specify a different type for each operation (select, insert and - // update) using the `ColumnType` - // wrapper. Here we define a column `created_at` that is selected as - // a `Date`, can optionally be provided as a `string` in inserts and - // can never be updated: - created_at: ColumnType; -} - -// You should not use the table schema interfaces directly. Instead, you should -// use the `Selectable`, `Insertable` and `Updateable` wrappers. These wrappers -// make sure that the correct types are used in each operation. -// -// Most of the time you should trust the type inference and not use explicit -// types at all. These types can be useful when typing function arguments. -export type Person = Selectable; -export type NewPerson = Insertable; -export type PersonUpdate = Updateable; - -export interface PetTable { - id: Generated; - name: string; - owner_id: number; - species: 'dog' | 'cat'; -} - -export type Pet = Selectable; -export type NewPet = Insertable; -export type PetUpdate = Updateable; diff --git a/packages/dialects/sql.js/tsconfig.json b/packages/dialects/sql.js/tsconfig.json deleted file mode 100644 index 41472d08..00000000 --- a/packages/dialects/sql.js/tsconfig.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "extends": "@zenstackhq/typescript-config/base.json", - "include": ["src/**/*"] -} diff --git a/packages/language/package.json b/packages/language/package.json index 1c08b647..78dd4b31 100644 --- a/packages/language/package.json +++ b/packages/language/package.json @@ -1,7 +1,7 @@ { "name": "@zenstackhq/language", "description": "ZenStack ZModel language specification", - "version": "3.0.0-beta.23", + "version": "3.0.0-beta.24", "license": "MIT", "author": "ZenStack Team", "files": [ diff --git a/packages/language/src/document.ts b/packages/language/src/document.ts index b8405c48..17146f85 100644 --- a/packages/language/src/document.ts +++ b/packages/language/src/document.ts @@ -1,4 +1,12 @@ -import { isAstNode, URI, type AstNode, type LangiumDocument, type LangiumDocuments, type Mutable } from 'langium'; +import { + isAstNode, + TextDocument, + URI, + type AstNode, + type LangiumDocument, + type LangiumDocuments, + type Mutable, +} from 'langium'; import fs from 'node:fs'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; @@ -6,6 +14,7 @@ import { isDataSource, type Model } from './ast'; import { STD_LIB_MODULE_NAME } from './constants'; import { createZModelServices } from './module'; import { getDataModelAndTypeDefs, getDocument, hasAttribute, resolveImport, resolveTransitiveImports } from './utils'; +import type { ZModelFormatter } from './zmodel-formatter'; /** * Loads ZModel document from the given file name. Include the additional document @@ -200,3 +209,20 @@ function validationAfterImportMerge(model: Model) { } return errors; } + +/** + * Formats the given ZModel content. + */ +export async function formatDocument(content: string) { + const services = createZModelServices().ZModelLanguage; + const langiumDocuments = services.shared.workspace.LangiumDocuments; + const document = langiumDocuments.createDocument(URI.parse('memory://schema.zmodel'), content); + const formatter = services.lsp.Formatter as ZModelFormatter; + const identifier = { uri: document.uri.toString() }; + const options = formatter.getFormatOptions() ?? { + insertSpaces: true, + tabSize: 4, + }; + const edits = await formatter.formatDocument(document, { options, textDocument: identifier }); + return TextDocument.applyEdits(document.textDocument, edits); +} diff --git a/packages/language/src/index.ts b/packages/language/src/index.ts index f11ede5e..4096fb96 100644 --- a/packages/language/src/index.ts +++ b/packages/language/src/index.ts @@ -1,3 +1,3 @@ -export { loadDocument } from './document'; +export { formatDocument, loadDocument } from './document'; export * from './module'; export { ZModelCodeGenerator } from './zmodel-code-generator'; diff --git a/packages/language/src/zmodel-code-generator.ts b/packages/language/src/zmodel-code-generator.ts index 2a63969f..55efb5fc 100644 --- a/packages/language/src/zmodel-code-generator.ts +++ b/packages/language/src/zmodel-code-generator.ts @@ -41,7 +41,6 @@ import { UnaryExpr, type AstNode, } from './ast'; -import { resolved } from './utils'; /** * Options for the generator. @@ -161,7 +160,7 @@ ${ast.fields.map((x) => this.indent + this.generate(x)).join('\n')} @gen(DataModel) private _generateDataModel(ast: DataModel) { return `${ast.isView ? 'view' : 'model'} ${ast.name}${ - ast.mixins.length > 0 ? ' mixes ' + ast.mixins.map((x) => x.ref?.name).join(', ') : '' + ast.mixins.length > 0 ? ' mixes ' + ast.mixins.map((x) => x.$refText).join(', ') : '' } { ${ast.fields.map((x) => this.indent + this.generate(x)).join('\n')}${ ast.attributes.length > 0 @@ -199,7 +198,7 @@ ${ast.fields.map((x) => this.indent + this.generate(x)).join('\n')}${ private attribute(ast: DataModelAttribute | DataFieldAttribute) { const args = ast.args.length ? `(${ast.args.map((x) => this.generate(x)).join(', ')})` : ''; - return `${resolved(ast.decl).name}${args}`; + return `${ast.decl.$refText}${args}`; } @gen(AttributeArg) @@ -265,7 +264,7 @@ ${ast.fields.map((x) => this.indent + this.generate(x)).join('\n')}${ @gen(ReferenceExpr) private _generateReferenceExpr(ast: ReferenceExpr) { const args = ast.args.length ? `(${ast.args.map((x) => this.generate(x)).join(', ')})` : ''; - return `${ast.target.ref?.name}${args}`; + return `${ast.target.$refText}${args}`; } @gen(ReferenceArg) @@ -275,12 +274,12 @@ ${ast.fields.map((x) => this.indent + this.generate(x)).join('\n')}${ @gen(MemberAccessExpr) private _generateMemberExpr(ast: MemberAccessExpr) { - return `${this.generate(ast.operand)}.${ast.member.ref?.name}`; + return `${this.generate(ast.operand)}.${ast.member.$refText}`; } @gen(InvocationExpr) private _generateInvocationExpr(ast: InvocationExpr) { - return `${ast.function.ref?.name}(${ast.args.map((x) => this.argument(x)).join(', ')})`; + return `${ast.function.$refText}(${ast.args.map((x) => this.argument(x)).join(', ')})`; } @gen(NullExpr) diff --git a/packages/orm/package.json b/packages/orm/package.json index 4e8ff9e0..69a860a8 100644 --- a/packages/orm/package.json +++ b/packages/orm/package.json @@ -1,6 +1,6 @@ { "name": "@zenstackhq/orm", - "version": "3.0.0-beta.23", + "version": "3.0.0-beta.24", "description": "ZenStack ORM", "type": "module", "scripts": { @@ -36,24 +36,44 @@ "default": "./dist/schema.cjs" } }, - "./helpers": { + "./dialects/sqlite": { "import": { - "types": "./dist/helpers.d.ts", - "default": "./dist/helpers.js" + "types": "./dist/dialects/sqlite.d.ts", + "default": "./dist/dialects/sqlite.js" }, "require": { - "types": "./dist/helpers.d.cts", - "default": "./dist/helpers.cjs" + "types": "./dist/dialects/sqlite.d.cts", + "default": "./dist/dialects/sqlite.cjs" + } + }, + "./dialects/postgres": { + "import": { + "types": "./dist/dialects/postgres.d.ts", + "default": "./dist/dialects/postgres.js" + }, + "require": { + "types": "./dist/dialects/postgres.d.cts", + "default": "./dist/dialects/postgres.cjs" + } + }, + "./dialects/sql.js": { + "import": { + "types": "./dist/dialects/sql.js.d.ts", + "default": "./dist/dialects/sql.js.js" + }, + "require": { + "types": "./dist/dialects/sql.js.d.cts", + "default": "./dist/dialects/sql.js.cjs" } }, - "./plugins/policy": { + "./helpers": { "import": { - "types": "./dist/plugins/policy/index.d.ts", - "default": "./dist/plugins/policy/index.js" + "types": "./dist/helpers.d.ts", + "default": "./dist/helpers.js" }, "require": { - "types": "./dist/plugins/policy/index.d.cts", - "default": "./dist/plugins/policy/index.cjs" + "types": "./dist/helpers.d.cts", + "default": "./dist/helpers.cjs" } }, "./package.json": { @@ -78,7 +98,8 @@ "peerDependencies": { "better-sqlite3": "catalog:", "pg": "catalog:", - "zod": "catalog:" + "zod": "catalog:", + "sql.js": "catalog:" }, "peerDependenciesMeta": { "better-sqlite3": { @@ -86,6 +107,9 @@ }, "pg": { "optional": true + }, + "sql.js": { + "optional": true } }, "devDependencies": { @@ -96,6 +120,7 @@ "@zenstackhq/typescript-config": "workspace:*", "@zenstackhq/vitest-config": "workspace:*", "tsx": "^4.19.2", - "zod": "^4.1.0" + "zod": "^4.1.0", + "@types/sql.js": "^1.4.9" } } diff --git a/packages/orm/src/client/crud-types.ts b/packages/orm/src/client/crud-types.ts index 7f5defdf..934c0139 100644 --- a/packages/orm/src/client/crud-types.ts +++ b/packages/orm/src/client/crud-types.ts @@ -778,15 +778,20 @@ type ConnectOrCreatePayload< create: CreateInput; }; -type CreateManyInput, Without extends string = never> = { +export type CreateManyInput< + Schema extends SchemaDef, + Model extends GetModels, + Without extends string = never, +> = { data: OrArray, Without> & Omit, Without>>; skipDuplicates?: boolean; }; -type CreateInput, Without extends string = never> = XOR< - Omit, Without>, - Omit, Without> ->; +export type CreateInput< + Schema extends SchemaDef, + Model extends GetModels, + Without extends string = never, +> = XOR, Without>, Omit, Without>>; type NestedCreateInput< Schema extends SchemaDef, @@ -882,7 +887,7 @@ type UpdateRelationInput< Without >; -type UpdateInput< +export type UpdateInput< Schema extends SchemaDef, Model extends GetModels, Without extends string = never, diff --git a/packages/orm/src/dialects/postgres.ts b/packages/orm/src/dialects/postgres.ts new file mode 100644 index 00000000..0c52590b --- /dev/null +++ b/packages/orm/src/dialects/postgres.ts @@ -0,0 +1 @@ +export { PostgresDialect, type PostgresDialectConfig } from 'kysely'; diff --git a/packages/dialects/sql.js/src/connection.ts b/packages/orm/src/dialects/sql.js/connection.ts similarity index 100% rename from packages/dialects/sql.js/src/connection.ts rename to packages/orm/src/dialects/sql.js/connection.ts diff --git a/packages/dialects/sql.js/src/dialect.ts b/packages/orm/src/dialects/sql.js/dialect.ts similarity index 100% rename from packages/dialects/sql.js/src/dialect.ts rename to packages/orm/src/dialects/sql.js/dialect.ts diff --git a/packages/dialects/sql.js/src/driver.ts b/packages/orm/src/dialects/sql.js/driver.ts similarity index 100% rename from packages/dialects/sql.js/src/driver.ts rename to packages/orm/src/dialects/sql.js/driver.ts diff --git a/packages/orm/src/dialects/sql.js/index.ts b/packages/orm/src/dialects/sql.js/index.ts new file mode 100644 index 00000000..d28411d4 --- /dev/null +++ b/packages/orm/src/dialects/sql.js/index.ts @@ -0,0 +1,4 @@ +// This module is ported from https://github.com/betarixm/kysely-sql-js by @betarixm + +export { SqlJsDialect } from './dialect'; +export type { SqlJsDialectConfig } from './types'; diff --git a/packages/dialects/sql.js/src/types.ts b/packages/orm/src/dialects/sql.js/types.ts similarity index 100% rename from packages/dialects/sql.js/src/types.ts rename to packages/orm/src/dialects/sql.js/types.ts diff --git a/packages/orm/src/dialects/sqlite.ts b/packages/orm/src/dialects/sqlite.ts new file mode 100644 index 00000000..2a3e6e68 --- /dev/null +++ b/packages/orm/src/dialects/sqlite.ts @@ -0,0 +1 @@ +export { SqliteDialect, type SqliteDialectConfig } from 'kysely'; diff --git a/packages/orm/tsup.config.ts b/packages/orm/tsup.config.ts index f4168f61..14ebdca2 100644 --- a/packages/orm/tsup.config.ts +++ b/packages/orm/tsup.config.ts @@ -5,6 +5,9 @@ export default defineConfig({ index: 'src/index.ts', schema: 'src/schema.ts', helpers: 'src/helpers.ts', + 'dialects/sqlite': 'src/dialects/sqlite.ts', + 'dialects/postgres': 'src/dialects/postgres.ts', + 'dialects/sql.js': 'src/dialects/sql.js/index.ts', }, outDir: 'dist', splitting: false, diff --git a/packages/plugins/policy/package.json b/packages/plugins/policy/package.json index 3b81ed48..5ddf89da 100644 --- a/packages/plugins/policy/package.json +++ b/packages/plugins/policy/package.json @@ -1,6 +1,6 @@ { "name": "@zenstackhq/plugin-policy", - "version": "3.0.0-beta.23", + "version": "3.0.0-beta.24", "description": "ZenStack Policy Plugin", "type": "module", "scripts": { diff --git a/packages/schema/package.json b/packages/schema/package.json index 4ca75c78..e94c946c 100644 --- a/packages/schema/package.json +++ b/packages/schema/package.json @@ -1,6 +1,6 @@ { "name": "@zenstackhq/schema", - "version": "3.0.0-beta.23", + "version": "3.0.0-beta.24", "description": "ZenStack Runtime Schema", "type": "module", "scripts": { diff --git a/packages/sdk/package.json b/packages/sdk/package.json index 28fa6c64..3fcce31d 100644 --- a/packages/sdk/package.json +++ b/packages/sdk/package.json @@ -1,6 +1,6 @@ { "name": "@zenstackhq/sdk", - "version": "3.0.0-beta.23", + "version": "3.0.0-beta.24", "description": "ZenStack SDK", "type": "module", "scripts": { diff --git a/packages/sdk/src/ts-schema-generator.ts b/packages/sdk/src/ts-schema-generator.ts index d1d19fe1..7a62e757 100644 --- a/packages/sdk/src/ts-schema-generator.ts +++ b/packages/sdk/src/ts-schema-generator.ts @@ -55,6 +55,7 @@ export type TsSchemaGeneratorOptions = { outDir: string; lite?: boolean; liteOnly?: boolean; + importWithFileExtension?: string; }; export class TsSchemaGenerator { @@ -117,6 +118,7 @@ export class TsSchemaGenerator { const schemaObject = this.createSchemaObject(model, lite); // Now generate the import declaration with the correct imports + // import { type SchemaDef, type OperandExpression, ExpressionUtils } from '@zenstackhq/orm/schema'; const runtimeImportDecl = ts.factory.createImportDeclaration( undefined, ts.factory.createImportClause( @@ -1072,7 +1074,7 @@ export class TsSchemaGenerator { : typeof arg === 'string' ? ts.factory.createStringLiteral(arg) : typeof arg === 'number' - ? ts.factory.createNumericLiteral(arg) + ? this.createNumberLiteral(arg) : arg === true ? ts.factory.createTrue() : arg === false @@ -1080,6 +1082,12 @@ export class TsSchemaGenerator { : undefined; } + private createNumberLiteral(arg: number) { + return arg < 0 + ? ts.factory.createPrefixUnaryExpression(ts.SyntaxKind.MinusToken, ts.factory.createNumericLiteral(-arg)) + : ts.factory.createNumericLiteral(arg); + } + private createProceduresObject(procedures: Procedure[]) { return ts.factory.createObjectLiteralExpression( procedures.map((proc) => ts.factory.createPropertyAssignment(proc.name, this.createProcedureObject(proc))), @@ -1290,7 +1298,15 @@ export class TsSchemaGenerator { const statements: ts.Statement[] = []; // generate: import { schema as $schema, type SchemaType as $Schema } from './schema'; - statements.push(this.generateSchemaImport(model, true, true, !!(options.lite || options.liteOnly))); + statements.push( + this.generateSchemaImport( + model, + true, + true, + !!(options.lite || options.liteOnly), + options.importWithFileExtension, + ), + ); // generate: import type { ModelResult as $ModelResult } from '@zenstackhq/orm'; statements.push( @@ -1416,7 +1432,13 @@ export class TsSchemaGenerator { fs.writeFileSync(outputFile, result); } - private generateSchemaImport(model: Model, schemaObject: boolean, schemaType: boolean, useLite: boolean) { + private generateSchemaImport( + model: Model, + schemaObject: boolean, + schemaType: boolean, + useLite: boolean, + importWithFileExtension: string | undefined, + ) { const importSpecifiers = []; if (schemaObject) { @@ -1442,10 +1464,18 @@ export class TsSchemaGenerator { ); } + let importFrom = useLite ? './schema-lite' : './schema'; + if (importWithFileExtension) { + importFrom += importWithFileExtension.startsWith('.') + ? importWithFileExtension + : `.${importWithFileExtension}`; + } + + // import { schema as $schema, type SchemaType as $Schema } from './schema'; return ts.factory.createImportDeclaration( undefined, ts.factory.createImportClause(false, undefined, ts.factory.createNamedImports(importSpecifiers)), - ts.factory.createStringLiteral(useLite ? './schema-lite' : './schema'), + ts.factory.createStringLiteral(importFrom), ); } @@ -1466,7 +1496,15 @@ export class TsSchemaGenerator { const statements: ts.Statement[] = []; // generate: import { SchemaType as $Schema } from './schema'; - statements.push(this.generateSchemaImport(model, false, true, !!(options.lite || options.liteOnly))); + statements.push( + this.generateSchemaImport( + model, + false, + true, + !!(options.lite || options.liteOnly), + options.importWithFileExtension, + ), + ); // generate: import { CreateArgs as $CreateArgs, ... } from '@zenstackhq/orm'; const inputTypes = [ diff --git a/packages/server/package.json b/packages/server/package.json index 84e47382..eb38a7e8 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -1,6 +1,6 @@ { "name": "@zenstackhq/server", - "version": "3.0.0-beta.23", + "version": "3.0.0-beta.24", "description": "ZenStack automatic CRUD API handlers and server adapters", "type": "module", "scripts": { diff --git a/packages/testtools/package.json b/packages/testtools/package.json index 8df7009f..cf73d043 100644 --- a/packages/testtools/package.json +++ b/packages/testtools/package.json @@ -1,6 +1,6 @@ { "name": "@zenstackhq/testtools", - "version": "3.0.0-beta.23", + "version": "3.0.0-beta.24", "description": "ZenStack Test Tools", "type": "module", "scripts": { diff --git a/packages/zod/package.json b/packages/zod/package.json index 8d25df38..5bceb659 100644 --- a/packages/zod/package.json +++ b/packages/zod/package.json @@ -1,6 +1,6 @@ { "name": "@zenstackhq/zod", - "version": "3.0.0-beta.23", + "version": "3.0.0-beta.24", "description": "", "type": "module", "main": "index.js", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5f2fdc5a..4eb5eaf2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -54,6 +54,9 @@ catalogs: react-dom: specifier: 19.2.0 version: 19.2.0 + sql.js: + specifier: ^1.13.0 + version: 1.13.0 svelte: specifier: 5.43.3 version: 5.43.3 @@ -117,6 +120,37 @@ importers: specifier: ^2.8.0 version: 2.8.0 + packages/auth-adapters/better-auth: + dependencies: + '@zenstackhq/common-helpers': + specifier: workspace:* + version: link:../../common-helpers + '@zenstackhq/language': + specifier: workspace:* + version: link:../../language + '@zenstackhq/orm': + specifier: workspace:* + version: link:../../orm + ts-pattern: + specifier: 'catalog:' + version: 5.7.1 + devDependencies: + '@better-auth/core': + specifier: ^1.3.0 + version: 1.3.34(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.18)(better-call@1.0.19)(jose@6.1.2)(kysely@0.28.8)(nanostores@1.0.1) + '@zenstackhq/eslint-config': + specifier: workspace:* + version: link:../../config/eslint-config + '@zenstackhq/typescript-config': + specifier: workspace:* + version: link:../../config/typescript-config + '@zenstackhq/vitest-config': + specifier: workspace:* + version: link:../../config/vitest-config + better-auth: + specifier: ^1.3.0 + version: 1.3.34 + packages/cli: dependencies: '@zenstackhq/common-helpers': @@ -288,27 +322,6 @@ importers: specifier: workspace:* version: link:../config/typescript-config - packages/dialects/sql.js: - devDependencies: - '@types/sql.js': - specifier: ^1.4.9 - version: 1.4.9 - '@zenstackhq/eslint-config': - specifier: workspace:* - version: link:../../config/eslint-config - '@zenstackhq/typescript-config': - specifier: workspace:* - version: link:../../config/typescript-config - '@zenstackhq/vitest-config': - specifier: workspace:* - version: link:../../config/vitest-config - kysely: - specifier: 'catalog:' - version: 0.28.8 - sql.js: - specifier: ^1.13.0 - version: 1.13.0 - packages/ide/vscode: dependencies: '@zenstackhq/language': @@ -406,6 +419,9 @@ importers: pg: specifier: 'catalog:' version: 8.16.3 + sql.js: + specifier: 'catalog:' + version: 1.13.0 toposort: specifier: ^2.0.2 version: 2.0.2 @@ -428,6 +444,9 @@ importers: '@types/pg': specifier: ^8.0.0 version: 8.11.11 + '@types/sql.js': + specifier: ^1.4.9 + version: 1.4.9 '@types/toposort': specifier: ^2.0.7 version: 2.0.7 @@ -599,7 +618,7 @@ importers: version: 16.0.1(@babel/core@7.28.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) nuxt: specifier: ^4.2.0 - version: 4.2.0(@parcel/watcher@2.5.1)(@types/node@20.19.24)(@vue/compiler-sfc@3.5.22)(better-sqlite3@12.2.0)(db0@0.3.4(better-sqlite3@12.2.0))(eslint@9.29.0(jiti@2.6.1))(ioredis@5.8.2)(lightningcss@1.30.2)(magicast@0.3.5)(optionator@0.9.4)(rollup@4.52.5)(terser@5.44.0)(tsx@4.20.3)(typescript@5.8.3)(vite@7.1.12(@types/node@20.19.24)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.3)(yaml@2.8.1))(yaml@2.8.1) + version: 4.2.0(@parcel/watcher@2.5.1)(@types/node@20.19.24)(@vue/compiler-sfc@3.5.22)(better-sqlite3@12.2.0)(db0@0.3.4(better-sqlite3@12.2.0))(eslint@9.29.0(jiti@2.6.1))(ioredis@5.8.2)(lightningcss@1.30.2)(magicast@0.5.0)(optionator@0.9.4)(rollup@4.52.5)(terser@5.44.0)(tsx@4.20.3)(typescript@5.8.3)(vite@7.1.12(@types/node@20.19.24)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.3)(yaml@2.8.1))(yaml@2.8.1) supertest: specifier: ^7.1.4 version: 7.1.4 @@ -1001,6 +1020,25 @@ packages: resolution: {integrity: sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==} engines: {node: '>=6.9.0'} + '@better-auth/core@1.3.34': + resolution: {integrity: sha512-rt/Bgl0Xa8OQ2DUMKCZEJ8vL9kUw4NCJsBP9Sj9uRhbsK8NEMPiznUOFMkUY2FvrslvfKN7H/fivwyHz9c7HzQ==} + peerDependencies: + '@better-auth/utils': 0.3.0 + '@better-fetch/fetch': 1.1.18 + better-call: 1.0.19 + jose: ^6.1.0 + kysely: ^0.28.5 + nanostores: ^1.0.1 + + '@better-auth/telemetry@1.3.34': + resolution: {integrity: sha512-aQZ3wN90YMqV49diWxAMe1k7s2qb55KCsedCZne5PlgCjU4s3YtnqyjC5FEpzw2KY8l8rvR7DMAsDl13NjObKA==} + + '@better-auth/utils@0.3.0': + resolution: {integrity: sha512-W+Adw6ZA6mgvnSnhOki270rwJ42t4XzSK6YWGF//BbVXL6SwCLWfyzBc1lN2m/4RM28KubdBKQ4X5VMoLRNPQw==} + + '@better-fetch/fetch@1.1.18': + resolution: {integrity: sha512-rEFOE1MYIsBmoMJtQbl32PGHHXuG2hDxvEd7rUHE0vCBoFQVSDqaVs9hkZEtHCxRoY+CljXKFCOuJ8uxqw1LcA==} + '@borewit/text-codec@0.1.1': resolution: {integrity: sha512-5L/uBxmjaCIX5h8Z+uu+kA9BQLkc/Wl06UGR5ajNRxu+/XjonB5i8JpgFMrPj3LXTCPA0pv8yxUvbUi+QthGGA==} @@ -1436,6 +1474,9 @@ packages: '@fastify/proxy-addr@5.1.0': resolution: {integrity: sha512-INS+6gh91cLUjB+PVHfu1UqcB76Sqtpyp7bnL+FYojhjygvOPA9ctiD/JDKsyD9Xgu4hUhCSJBPig/w7duNajw==} + '@hexagon/base64@1.1.28': + resolution: {integrity: sha512-lhqDEAvWixy3bZ+UOYbPwUbBkwBq5C1LAJ/xPC8Oi+lL54oyakv/npbA0aU2hgCsx/1NUd4IBvV03+aUBWxerw==} + '@humanfs/core@0.19.1': resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} engines: {node: '>=18.18.0'} @@ -1632,6 +1673,9 @@ packages: '@kwsites/promise-deferred@1.1.1': resolution: {integrity: sha512-GaHYm+c0O9MjZRu0ongGBRbinu8gVAMd2UZjji6jVmqKtZluZnptXGWhz1E8j8D2HJ3f/yMxKAUC0b+57wncIw==} + '@levischuck/tiny-cbor@0.2.11': + resolution: {integrity: sha512-llBRm4dT4Z89aRsm6u2oEZ8tfwL/2l6BwpZ7JcyieouniDECM5AqNgr/y08zalEIvW3RSK4upYyybDcmjXqAow==} + '@mapbox/node-pre-gyp@2.0.0': resolution: {integrity: sha512-llMXd39jtP0HpQLVI37Bf1m2ADlEb35GYSh1SDSLsBhR+5iCxiNGlT31yqbNtVHygHAtMy6dWFERpU2JgufhPg==} engines: {node: '>=18'} @@ -1701,10 +1745,18 @@ packages: cpu: [x64] os: [win32] + '@noble/ciphers@2.0.1': + resolution: {integrity: sha512-xHK3XHPUW8DTAobU+G0XT+/w+JLM7/8k1UFdB5xg/zTFPnFCobhftzw8wl4Lw2aq/Rvir5pxfZV5fEazmeCJ2g==} + engines: {node: '>= 20.19.0'} + '@noble/hashes@1.7.1': resolution: {integrity: sha512-B8XBPsn4vT/KJAGqDzbwztd+6Yte3P4V7iafm24bxgDe/mlRuK6xmWPuCNrKt2vDafZ8MfJLlchDG/vYafQEjQ==} engines: {node: ^14.21.3 || >=16} + '@noble/hashes@2.0.1': + resolution: {integrity: sha512-XlOlEbQcE9fmuXxrVTXCTlG2nlRXa9Rj3rr5Ue/+tX+nmkgbX720YHh0VR3hBF9xDvwnb8D2shVGOwNx+ulArw==} + engines: {node: '>= 20.19.0'} + '@nodelib/fs.scandir@2.1.5': resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} @@ -2148,6 +2200,43 @@ packages: resolution: {integrity: sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==} engines: {node: '>= 10.0.0'} + '@peculiar/asn1-android@2.6.0': + resolution: {integrity: sha512-cBRCKtYPF7vJGN76/yG8VbxRcHLPF3HnkoHhKOZeHpoVtbMYfY9ROKtH3DtYUY9m8uI1Mh47PRhHf2hSK3xcSQ==} + + '@peculiar/asn1-cms@2.6.0': + resolution: {integrity: sha512-2uZqP+ggSncESeUF/9Su8rWqGclEfEiz1SyU02WX5fUONFfkjzS2Z/F1Li0ofSmf4JqYXIOdCAZqIXAIBAT1OA==} + + '@peculiar/asn1-csr@2.6.0': + resolution: {integrity: sha512-BeWIu5VpTIhfRysfEp73SGbwjjoLL/JWXhJ/9mo4vXnz3tRGm+NGm3KNcRzQ9VMVqwYS2RHlolz21svzRXIHPQ==} + + '@peculiar/asn1-ecc@2.6.0': + resolution: {integrity: sha512-FF3LMGq6SfAOwUG2sKpPXblibn6XnEIKa+SryvUl5Pik+WR9rmRA3OCiwz8R3lVXnYnyRkSZsSLdml8H3UiOcw==} + + '@peculiar/asn1-pfx@2.6.0': + resolution: {integrity: sha512-rtUvtf+tyKGgokHHmZzeUojRZJYPxoD/jaN1+VAB4kKR7tXrnDCA/RAWXAIhMJJC+7W27IIRGe9djvxKgsldCQ==} + + '@peculiar/asn1-pkcs8@2.6.0': + resolution: {integrity: sha512-KyQ4D8G/NrS7Fw3XCJrngxmjwO/3htnA0lL9gDICvEQ+GJ+EPFqldcJQTwPIdvx98Tua+WjkdKHSC0/Km7T+lA==} + + '@peculiar/asn1-pkcs9@2.6.0': + resolution: {integrity: sha512-b78OQ6OciW0aqZxdzliXGYHASeCvvw5caqidbpQRYW2mBtXIX2WhofNXTEe7NyxTb0P6J62kAAWLwn0HuMF1Fw==} + + '@peculiar/asn1-rsa@2.6.0': + resolution: {integrity: sha512-Nu4C19tsrTsCp9fDrH+sdcOKoVfdfoQQ7S3VqjJU6vedR7tY3RLkQ5oguOIB3zFW33USDUuYZnPEQYySlgha4w==} + + '@peculiar/asn1-schema@2.6.0': + resolution: {integrity: sha512-xNLYLBFTBKkCzEZIw842BxytQQATQv+lDTCEMZ8C196iJcJJMBUZxrhSTxLaohMyKK8QlzRNTRkUmanucnDSqg==} + + '@peculiar/asn1-x509-attr@2.6.0': + resolution: {integrity: sha512-MuIAXFX3/dc8gmoZBkwJWxUWOSvG4MMDntXhrOZpJVMkYX+MYc/rUAU2uJOved9iJEoiUx7//3D8oG83a78UJA==} + + '@peculiar/asn1-x509@2.6.0': + resolution: {integrity: sha512-uzYbPEpoQiBoTq0/+jZtpM6Gq6zADBx+JNFP3yqRgziWBxQ/Dt/HcuvRfm9zJTPdRcBqPNdaRHTVwpyiq6iNMA==} + + '@peculiar/x509@1.14.2': + resolution: {integrity: sha512-r2w1Hg6pODDs0zfAKHkSS5HLkOLSeburtcgwvlLLWWCixw+MmW3U6kD5ddyvc2Y2YdbGuVwCF2S2ASoU1cFAag==} + engines: {node: '>=22.0.0'} + '@pinojs/redact@0.4.0': resolution: {integrity: sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg==} @@ -2479,6 +2568,13 @@ packages: '@sec-ant/readable-stream@0.4.1': resolution: {integrity: sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==} + '@simplewebauthn/browser@13.2.2': + resolution: {integrity: sha512-FNW1oLQpTJyqG5kkDg5ZsotvWgmBaC6jCHR7Ej0qUNep36Wl9tj2eZu7J5rP+uhXgHaLk+QQ3lqcw2vS5MX1IA==} + + '@simplewebauthn/server@13.2.2': + resolution: {integrity: sha512-HcWLW28yTMGXpwE9VLx9J+N2KEUaELadLrkPEEI9tpI5la70xNEVEsu/C+m3u7uoq4FulLqZQhgBCzR9IZhFpA==} + engines: {node: '>=20.0.0'} + '@sinclair/typebox@0.34.41': resolution: {integrity: sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==} @@ -3361,6 +3457,10 @@ packages: asap@2.0.6: resolution: {integrity: sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==} + asn1js@3.0.6: + resolution: {integrity: sha512-UOCGPYbl0tv8+006qks/dTgV9ajs97X2p0FAbyS2iyCRrmLSRolDaHdp+v/CLgnzHc3fVB+CwYiUmei7ndFcgA==} + engines: {node: '>=12.0.0'} + assertion-error@2.0.1: resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} engines: {node: '>=12'} @@ -3441,6 +3541,38 @@ packages: resolution: {integrity: sha512-JU0h5APyQNsHOlAM7HnQnPToSDQoEBZqzu/YBlqDnEeymPnZDREeXJA3KBMQee+dKteAxZ2AtvQEvVYdZf241Q==} hasBin: true + better-auth@1.3.34: + resolution: {integrity: sha512-LWA52SlvnUBJRbN8VLSTLILPomZY3zZAiLxVJCeSQ5uVmaIKkMBhERitkfJcXB9RJcfl4uP+3EqKkb6hX1/uiw==} + peerDependencies: + '@lynx-js/react': '*' + '@sveltejs/kit': '*' + next: '*' + react: '*' + react-dom: '*' + solid-js: '*' + svelte: '*' + vue: '*' + peerDependenciesMeta: + '@lynx-js/react': + optional: true + '@sveltejs/kit': + optional: true + next: + optional: true + react: + optional: true + react-dom: + optional: true + solid-js: + optional: true + svelte: + optional: true + vue: + optional: true + + better-call@1.0.19: + resolution: {integrity: sha512-sI3GcA1SCVa3H+CDHl8W8qzhlrckwXOTKhqq3OOPXjgn5aTOMIqGY34zLY/pHA6tRRMjTUC3lz5Mi7EbDA24Kw==} + better-sqlite3@12.2.0: resolution: {integrity: sha512-eGbYq2CT+tos1fBwLQ/tkBt9J5M3JEHjku4hbvQUePCckkvVf14xWj+1m7dGoK81M/fOjFT7yM9UMeKT/+vFLQ==} engines: {node: 20.x || 22.x || 23.x || 24.x} @@ -4944,6 +5076,9 @@ packages: resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} hasBin: true + jose@6.1.2: + resolution: {integrity: sha512-MpcPtHLE5EmztuFIqB0vzHAWJPpmN1E6L4oo+kze56LIs3MyXIj9ZHMDxqOvkP38gBR7K1v3jqd4WU2+nrfONQ==} + joycon@3.1.1: resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} engines: {node: '>=10'} @@ -5400,6 +5535,10 @@ packages: engines: {node: ^18 || >=20} hasBin: true + nanostores@1.0.1: + resolution: {integrity: sha512-kNZ9xnoJYKg/AfxjrVL4SS0fKX++4awQReGqWnwTRHxeHGZ1FJFVgTqr/eMrNQdp0Tz7M7tG/TDaX8QfHDwVCw==} + engines: {node: ^20.0.0 || >=22.0.0} + nanotar@0.2.0: resolution: {integrity: sha512-9ca1h0Xjvo9bEkE4UOxgAzLV0jHKe6LMaxo37ND2DAhhAtd0j8pR1Wxz+/goMrZO8AEZTWCmyaOsFI/W5AdpCQ==} @@ -6120,6 +6259,13 @@ packages: pure-rand@6.1.0: resolution: {integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==} + pvtsutils@1.3.6: + resolution: {integrity: sha512-PLgQXQ6H2FWCaeRak8vvk1GW462lMxB5s3Jm673N82zI4vqtVUPuZdffdZbPDFRoU8kAhItWFtPCWiPpp4/EDg==} + + pvutils@1.1.5: + resolution: {integrity: sha512-KTqnxsgGiQ6ZAzZCVlJH5eOjSnvlyEgx1m8bkRJfOhmGRqfo5KLvmAlACQkrjEtOQ4B7wF9TdSLIs9O90MX9xA==} + engines: {node: '>=16.0.0'} + qs@6.13.0: resolution: {integrity: sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==} engines: {node: '>=0.6'} @@ -6206,6 +6352,9 @@ packages: resolution: {integrity: sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==} engines: {node: '>=4'} + reflect-metadata@0.2.2: + resolution: {integrity: sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==} + reflect.getprototypeof@1.0.10: resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==} engines: {node: '>= 0.4'} @@ -6287,6 +6436,9 @@ packages: engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true + rou3@0.5.1: + resolution: {integrity: sha512-OXMmJ3zRk2xeXFGfA3K+EOPHC5u7RDFG7lIOx0X1pdnhUkI8MdVrbV+sNsD80ElpUZ+MRHdyxPnFthq9VHs8uQ==} + router@2.2.0: resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==} engines: {node: '>= 18'} @@ -6817,6 +6969,9 @@ packages: tsconfig-paths@3.15.0: resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} + tslib@1.14.1: + resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} + tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} @@ -6844,6 +6999,10 @@ packages: engines: {node: '>=18.0.0'} hasBin: true + tsyringe@4.10.0: + resolution: {integrity: sha512-axr3IdNuVIxnaK5XGEUFTu3YmAQ6lllgrvqfEoR16g/HGnYY/6We4oWENtAnzK6/LpJ2ur9PAb80RBt7/U4ugw==} + engines: {node: '>= 6.0.0'} + tunnel-agent@0.6.0: resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} @@ -7723,6 +7882,31 @@ snapshots: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.28.5 + '@better-auth/core@1.3.34(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.18)(better-call@1.0.19)(jose@6.1.2)(kysely@0.28.8)(nanostores@1.0.1)': + dependencies: + '@better-auth/utils': 0.3.0 + '@better-fetch/fetch': 1.1.18 + better-call: 1.0.19 + jose: 6.1.2 + kysely: 0.28.8 + nanostores: 1.0.1 + zod: 4.1.12 + + '@better-auth/telemetry@1.3.34(better-call@1.0.19)(jose@6.1.2)(kysely@0.28.8)(nanostores@1.0.1)': + dependencies: + '@better-auth/core': 1.3.34(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.18)(better-call@1.0.19)(jose@6.1.2)(kysely@0.28.8)(nanostores@1.0.1) + '@better-auth/utils': 0.3.0 + '@better-fetch/fetch': 1.1.18 + transitivePeerDependencies: + - better-call + - jose + - kysely + - nanostores + + '@better-auth/utils@0.3.0': {} + + '@better-fetch/fetch@1.1.18': {} + '@borewit/text-codec@0.1.1': {} '@chevrotain/cst-dts-gen@11.0.3': @@ -7774,10 +7958,10 @@ snapshots: '@csstools/css-tokenizer@3.0.4': optional: true - '@dxup/nuxt@0.2.0(magicast@0.3.5)': + '@dxup/nuxt@0.2.0(magicast@0.5.0)': dependencies: '@dxup/unimport': 0.1.0 - '@nuxt/kit': 4.2.0(magicast@0.3.5) + '@nuxt/kit': 4.2.0(magicast@0.5.0) chokidar: 4.0.3 pathe: 2.0.3 tinyglobby: 0.2.15 @@ -8026,6 +8210,8 @@ snapshots: '@fastify/forwarded': 3.0.1 ipaddr.js: 2.2.0 + '@hexagon/base64@1.1.28': {} + '@humanfs/core@0.19.1': {} '@humanfs/node@0.16.6': @@ -8190,6 +8376,8 @@ snapshots: '@kwsites/promise-deferred@1.1.1': {} + '@levischuck/tiny-cbor@0.2.11': {} + '@mapbox/node-pre-gyp@2.0.0': dependencies: consola: 3.4.2 @@ -8256,8 +8444,12 @@ snapshots: '@next/swc-win32-x64-msvc@16.0.1': optional: true + '@noble/ciphers@2.0.1': {} + '@noble/hashes@1.7.1': {} + '@noble/hashes@2.0.1': {} + '@nodelib/fs.scandir@2.1.5': dependencies: '@nodelib/fs.stat': 2.0.5 @@ -8272,9 +8464,9 @@ snapshots: '@nolyfill/is-core-module@1.0.39': {} - '@nuxt/cli@3.29.3(magicast@0.3.5)': + '@nuxt/cli@3.29.3(magicast@0.5.0)': dependencies: - c12: 3.3.1(magicast@0.3.5) + c12: 3.3.1(magicast@0.5.0) citty: 0.1.6 clipboardy: 5.0.0 confbox: 0.2.2 @@ -8392,9 +8584,35 @@ snapshots: transitivePeerDependencies: - magicast - '@nuxt/kit@4.2.0(magicast@0.3.5)': + '@nuxt/kit@3.20.0(magicast@0.5.0)': dependencies: - c12: 3.3.1(magicast@0.3.5) + c12: 3.3.1(magicast@0.5.0) + consola: 3.4.2 + defu: 6.1.4 + destr: 2.0.5 + errx: 0.1.0 + exsolve: 1.0.7 + ignore: 7.0.5 + jiti: 2.6.1 + klona: 2.0.6 + knitwork: 1.2.0 + mlly: 1.8.0 + ohash: 2.0.11 + pathe: 2.0.3 + pkg-types: 2.3.0 + rc9: 2.1.2 + scule: 1.3.0 + semver: 7.7.3 + tinyglobby: 0.2.15 + ufo: 1.6.1 + unctx: 2.4.1 + untyped: 2.0.0 + transitivePeerDependencies: + - magicast + + '@nuxt/kit@4.2.0(magicast@0.5.0)': + dependencies: + c12: 3.3.1(magicast@0.5.0) consola: 3.4.2 defu: 6.1.4 destr: 2.0.5 @@ -8417,10 +8635,10 @@ snapshots: transitivePeerDependencies: - magicast - '@nuxt/nitro-server@4.2.0(better-sqlite3@12.2.0)(db0@0.3.4(better-sqlite3@12.2.0))(ioredis@5.8.2)(magicast@0.3.5)(nuxt@4.2.0(@parcel/watcher@2.5.1)(@types/node@20.19.24)(@vue/compiler-sfc@3.5.22)(better-sqlite3@12.2.0)(db0@0.3.4(better-sqlite3@12.2.0))(eslint@9.29.0(jiti@2.6.1))(ioredis@5.8.2)(lightningcss@1.30.2)(magicast@0.3.5)(optionator@0.9.4)(rollup@4.52.5)(terser@5.44.0)(tsx@4.20.3)(typescript@5.8.3)(vite@7.1.12(@types/node@20.19.24)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.3)(yaml@2.8.1))(yaml@2.8.1))(typescript@5.8.3)': + '@nuxt/nitro-server@4.2.0(better-sqlite3@12.2.0)(db0@0.3.4(better-sqlite3@12.2.0))(ioredis@5.8.2)(magicast@0.5.0)(nuxt@4.2.0(@parcel/watcher@2.5.1)(@types/node@20.19.24)(@vue/compiler-sfc@3.5.22)(better-sqlite3@12.2.0)(db0@0.3.4(better-sqlite3@12.2.0))(eslint@9.29.0(jiti@2.6.1))(ioredis@5.8.2)(lightningcss@1.30.2)(magicast@0.5.0)(optionator@0.9.4)(rollup@4.52.5)(terser@5.44.0)(tsx@4.20.3)(typescript@5.8.3)(vite@7.1.12(@types/node@20.19.24)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.3)(yaml@2.8.1))(yaml@2.8.1))(typescript@5.8.3)': dependencies: '@nuxt/devalue': 2.0.2 - '@nuxt/kit': 4.2.0(magicast@0.3.5) + '@nuxt/kit': 4.2.0(magicast@0.5.0) '@unhead/vue': 2.0.19(vue@3.5.22(typescript@5.8.3)) '@vue/shared': 3.5.22 consola: 3.4.2 @@ -8435,7 +8653,7 @@ snapshots: klona: 2.0.6 mocked-exports: 0.1.1 nitropack: 2.12.9(better-sqlite3@12.2.0) - nuxt: 4.2.0(@parcel/watcher@2.5.1)(@types/node@20.19.24)(@vue/compiler-sfc@3.5.22)(better-sqlite3@12.2.0)(db0@0.3.4(better-sqlite3@12.2.0))(eslint@9.29.0(jiti@2.6.1))(ioredis@5.8.2)(lightningcss@1.30.2)(magicast@0.3.5)(optionator@0.9.4)(rollup@4.52.5)(terser@5.44.0)(tsx@4.20.3)(typescript@5.8.3)(vite@7.1.12(@types/node@20.19.24)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.3)(yaml@2.8.1))(yaml@2.8.1) + nuxt: 4.2.0(@parcel/watcher@2.5.1)(@types/node@20.19.24)(@vue/compiler-sfc@3.5.22)(better-sqlite3@12.2.0)(db0@0.3.4(better-sqlite3@12.2.0))(eslint@9.29.0(jiti@2.6.1))(ioredis@5.8.2)(lightningcss@1.30.2)(magicast@0.5.0)(optionator@0.9.4)(rollup@4.52.5)(terser@5.44.0)(tsx@4.20.3)(typescript@5.8.3)(vite@7.1.12(@types/node@20.19.24)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.3)(yaml@2.8.1))(yaml@2.8.1) pathe: 2.0.3 pkg-types: 2.3.0 radix3: 1.1.2 @@ -8489,9 +8707,9 @@ snapshots: pkg-types: 2.3.0 std-env: 3.10.0 - '@nuxt/telemetry@2.6.6(magicast@0.3.5)': + '@nuxt/telemetry@2.6.6(magicast@0.5.0)': dependencies: - '@nuxt/kit': 3.20.0(magicast@0.3.5) + '@nuxt/kit': 3.20.0(magicast@0.5.0) citty: 0.1.6 consola: 3.4.2 destr: 2.0.5 @@ -8506,9 +8724,9 @@ snapshots: transitivePeerDependencies: - magicast - '@nuxt/vite-builder@4.2.0(@types/node@20.19.24)(eslint@9.29.0(jiti@2.6.1))(lightningcss@1.30.2)(magicast@0.3.5)(nuxt@4.2.0(@parcel/watcher@2.5.1)(@types/node@20.19.24)(@vue/compiler-sfc@3.5.22)(better-sqlite3@12.2.0)(db0@0.3.4(better-sqlite3@12.2.0))(eslint@9.29.0(jiti@2.6.1))(ioredis@5.8.2)(lightningcss@1.30.2)(magicast@0.3.5)(optionator@0.9.4)(rollup@4.52.5)(terser@5.44.0)(tsx@4.20.3)(typescript@5.8.3)(vite@7.1.12(@types/node@20.19.24)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.3)(yaml@2.8.1))(yaml@2.8.1))(optionator@0.9.4)(rollup@4.52.5)(terser@5.44.0)(tsx@4.20.3)(typescript@5.8.3)(vue@3.5.22(typescript@5.8.3))(yaml@2.8.1)': + '@nuxt/vite-builder@4.2.0(@types/node@20.19.24)(eslint@9.29.0(jiti@2.6.1))(lightningcss@1.30.2)(magicast@0.5.0)(nuxt@4.2.0(@parcel/watcher@2.5.1)(@types/node@20.19.24)(@vue/compiler-sfc@3.5.22)(better-sqlite3@12.2.0)(db0@0.3.4(better-sqlite3@12.2.0))(eslint@9.29.0(jiti@2.6.1))(ioredis@5.8.2)(lightningcss@1.30.2)(magicast@0.5.0)(optionator@0.9.4)(rollup@4.52.5)(terser@5.44.0)(tsx@4.20.3)(typescript@5.8.3)(vite@7.1.12(@types/node@20.19.24)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.3)(yaml@2.8.1))(yaml@2.8.1))(optionator@0.9.4)(rollup@4.52.5)(terser@5.44.0)(tsx@4.20.3)(typescript@5.8.3)(vue@3.5.22(typescript@5.8.3))(yaml@2.8.1)': dependencies: - '@nuxt/kit': 4.2.0(magicast@0.3.5) + '@nuxt/kit': 4.2.0(magicast@0.5.0) '@rollup/plugin-replace': 6.0.3(rollup@4.52.5) '@vitejs/plugin-vue': 6.0.1(vite@7.1.12(@types/node@20.19.24)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.3)(yaml@2.8.1))(vue@3.5.22(typescript@5.8.3)) '@vitejs/plugin-vue-jsx': 5.1.1(vite@7.1.12(@types/node@20.19.24)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.3)(yaml@2.8.1))(vue@3.5.22(typescript@5.8.3)) @@ -8526,7 +8744,7 @@ snapshots: magic-string: 0.30.21 mlly: 1.8.0 mocked-exports: 0.1.1 - nuxt: 4.2.0(@parcel/watcher@2.5.1)(@types/node@20.19.24)(@vue/compiler-sfc@3.5.22)(better-sqlite3@12.2.0)(db0@0.3.4(better-sqlite3@12.2.0))(eslint@9.29.0(jiti@2.6.1))(ioredis@5.8.2)(lightningcss@1.30.2)(magicast@0.3.5)(optionator@0.9.4)(rollup@4.52.5)(terser@5.44.0)(tsx@4.20.3)(typescript@5.8.3)(vite@7.1.12(@types/node@20.19.24)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.3)(yaml@2.8.1))(yaml@2.8.1) + nuxt: 4.2.0(@parcel/watcher@2.5.1)(@types/node@20.19.24)(@vue/compiler-sfc@3.5.22)(better-sqlite3@12.2.0)(db0@0.3.4(better-sqlite3@12.2.0))(eslint@9.29.0(jiti@2.6.1))(ioredis@5.8.2)(lightningcss@1.30.2)(magicast@0.5.0)(optionator@0.9.4)(rollup@4.52.5)(terser@5.44.0)(tsx@4.20.3)(typescript@5.8.3)(vite@7.1.12(@types/node@20.19.24)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.3)(yaml@2.8.1))(yaml@2.8.1) pathe: 2.0.3 pkg-types: 2.3.0 postcss: 8.5.6 @@ -8786,6 +9004,102 @@ snapshots: '@parcel/watcher-win32-ia32': 2.5.1 '@parcel/watcher-win32-x64': 2.5.1 + '@peculiar/asn1-android@2.6.0': + dependencies: + '@peculiar/asn1-schema': 2.6.0 + asn1js: 3.0.6 + tslib: 2.8.1 + + '@peculiar/asn1-cms@2.6.0': + dependencies: + '@peculiar/asn1-schema': 2.6.0 + '@peculiar/asn1-x509': 2.6.0 + '@peculiar/asn1-x509-attr': 2.6.0 + asn1js: 3.0.6 + tslib: 2.8.1 + + '@peculiar/asn1-csr@2.6.0': + dependencies: + '@peculiar/asn1-schema': 2.6.0 + '@peculiar/asn1-x509': 2.6.0 + asn1js: 3.0.6 + tslib: 2.8.1 + + '@peculiar/asn1-ecc@2.6.0': + dependencies: + '@peculiar/asn1-schema': 2.6.0 + '@peculiar/asn1-x509': 2.6.0 + asn1js: 3.0.6 + tslib: 2.8.1 + + '@peculiar/asn1-pfx@2.6.0': + dependencies: + '@peculiar/asn1-cms': 2.6.0 + '@peculiar/asn1-pkcs8': 2.6.0 + '@peculiar/asn1-rsa': 2.6.0 + '@peculiar/asn1-schema': 2.6.0 + asn1js: 3.0.6 + tslib: 2.8.1 + + '@peculiar/asn1-pkcs8@2.6.0': + dependencies: + '@peculiar/asn1-schema': 2.6.0 + '@peculiar/asn1-x509': 2.6.0 + asn1js: 3.0.6 + tslib: 2.8.1 + + '@peculiar/asn1-pkcs9@2.6.0': + dependencies: + '@peculiar/asn1-cms': 2.6.0 + '@peculiar/asn1-pfx': 2.6.0 + '@peculiar/asn1-pkcs8': 2.6.0 + '@peculiar/asn1-schema': 2.6.0 + '@peculiar/asn1-x509': 2.6.0 + '@peculiar/asn1-x509-attr': 2.6.0 + asn1js: 3.0.6 + tslib: 2.8.1 + + '@peculiar/asn1-rsa@2.6.0': + dependencies: + '@peculiar/asn1-schema': 2.6.0 + '@peculiar/asn1-x509': 2.6.0 + asn1js: 3.0.6 + tslib: 2.8.1 + + '@peculiar/asn1-schema@2.6.0': + dependencies: + asn1js: 3.0.6 + pvtsutils: 1.3.6 + tslib: 2.8.1 + + '@peculiar/asn1-x509-attr@2.6.0': + dependencies: + '@peculiar/asn1-schema': 2.6.0 + '@peculiar/asn1-x509': 2.6.0 + asn1js: 3.0.6 + tslib: 2.8.1 + + '@peculiar/asn1-x509@2.6.0': + dependencies: + '@peculiar/asn1-schema': 2.6.0 + asn1js: 3.0.6 + pvtsutils: 1.3.6 + tslib: 2.8.1 + + '@peculiar/x509@1.14.2': + dependencies: + '@peculiar/asn1-cms': 2.6.0 + '@peculiar/asn1-csr': 2.6.0 + '@peculiar/asn1-ecc': 2.6.0 + '@peculiar/asn1-pkcs9': 2.6.0 + '@peculiar/asn1-rsa': 2.6.0 + '@peculiar/asn1-schema': 2.6.0 + '@peculiar/asn1-x509': 2.6.0 + pvtsutils: 1.3.6 + reflect-metadata: 0.2.2 + tslib: 2.8.1 + tsyringe: 4.10.0 + '@pinojs/redact@0.4.0': {} '@pkgjs/parseargs@0.11.0': @@ -9032,6 +9346,19 @@ snapshots: '@sec-ant/readable-stream@0.4.1': {} + '@simplewebauthn/browser@13.2.2': {} + + '@simplewebauthn/server@13.2.2': + dependencies: + '@hexagon/base64': 1.1.28 + '@levischuck/tiny-cbor': 0.2.11 + '@peculiar/asn1-android': 2.6.0 + '@peculiar/asn1-ecc': 2.6.0 + '@peculiar/asn1-rsa': 2.6.0 + '@peculiar/asn1-schema': 2.6.0 + '@peculiar/asn1-x509': 2.6.0 + '@peculiar/x509': 1.14.2 + '@sinclair/typebox@0.34.41': {} '@sindresorhus/is@7.1.0': {} @@ -10048,6 +10375,12 @@ snapshots: asap@2.0.6: {} + asn1js@3.0.6: + dependencies: + pvtsutils: 1.3.6 + pvutils: 1.1.5 + tslib: 2.8.1 + assertion-error@2.0.1: {} ast-kit@2.1.3: @@ -10105,6 +10438,31 @@ snapshots: baseline-browser-mapping@2.8.21: {} + better-auth@1.3.34: + dependencies: + '@better-auth/core': 1.3.34(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.18)(better-call@1.0.19)(jose@6.1.2)(kysely@0.28.8)(nanostores@1.0.1) + '@better-auth/telemetry': 1.3.34(better-call@1.0.19)(jose@6.1.2)(kysely@0.28.8)(nanostores@1.0.1) + '@better-auth/utils': 0.3.0 + '@better-fetch/fetch': 1.1.18 + '@noble/ciphers': 2.0.1 + '@noble/hashes': 2.0.1 + '@simplewebauthn/browser': 13.2.2 + '@simplewebauthn/server': 13.2.2 + better-call: 1.0.19 + defu: 6.1.4 + jose: 6.1.2 + kysely: 0.28.8 + nanostores: 1.0.1 + zod: 4.1.12 + + better-call@1.0.19: + dependencies: + '@better-auth/utils': 0.3.0 + '@better-fetch/fetch': 1.1.18 + rou3: 0.5.1 + set-cookie-parser: 2.7.2 + uncrypto: 0.1.3 + better-sqlite3@12.2.0: dependencies: bindings: 1.5.0 @@ -10901,7 +11259,7 @@ snapshots: eslint: 9.29.0(jiti@2.6.1) eslint-import-resolver-node: 0.3.9 eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.46.2(eslint@9.29.0(jiti@2.6.1))(typescript@5.8.3))(eslint@9.29.0(jiti@2.6.1)))(eslint@9.29.0(jiti@2.6.1)) - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.46.2(eslint@9.29.0(jiti@2.6.1))(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.29.0(jiti@2.6.1)) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.46.2(eslint@9.29.0(jiti@2.6.1))(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.46.2(eslint@9.29.0(jiti@2.6.1))(typescript@5.8.3))(eslint@9.29.0(jiti@2.6.1)))(eslint@9.29.0(jiti@2.6.1)))(eslint@9.29.0(jiti@2.6.1)) eslint-plugin-jsx-a11y: 6.10.2(eslint@9.29.0(jiti@2.6.1)) eslint-plugin-react: 7.37.5(eslint@9.29.0(jiti@2.6.1)) eslint-plugin-react-hooks: 7.0.1(eslint@9.29.0(jiti@2.6.1)) @@ -10934,7 +11292,7 @@ snapshots: tinyglobby: 0.2.15 unrs-resolver: 1.11.1 optionalDependencies: - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.46.2(eslint@9.29.0(jiti@2.6.1))(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.29.0(jiti@2.6.1)) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.46.2(eslint@9.29.0(jiti@2.6.1))(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.46.2(eslint@9.29.0(jiti@2.6.1))(typescript@5.8.3))(eslint@9.29.0(jiti@2.6.1)))(eslint@9.29.0(jiti@2.6.1)))(eslint@9.29.0(jiti@2.6.1)) transitivePeerDependencies: - supports-color @@ -10949,7 +11307,7 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.46.2(eslint@9.29.0(jiti@2.6.1))(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.29.0(jiti@2.6.1)): + eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.46.2(eslint@9.29.0(jiti@2.6.1))(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.46.2(eslint@9.29.0(jiti@2.6.1))(typescript@5.8.3))(eslint@9.29.0(jiti@2.6.1)))(eslint@9.29.0(jiti@2.6.1)))(eslint@9.29.0(jiti@2.6.1)): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.9 @@ -11874,6 +12232,8 @@ snapshots: jiti@2.6.1: {} + jose@6.1.2: {} + joycon@3.1.1: {} js-tokens@4.0.0: {} @@ -12305,6 +12665,8 @@ snapshots: nanoid@5.1.6: {} + nanostores@1.0.1: {} + nanotar@0.2.0: {} napi-build-utils@2.0.0: {} @@ -12487,19 +12849,19 @@ snapshots: dependencies: boolbase: 1.0.0 - nuxt@4.2.0(@parcel/watcher@2.5.1)(@types/node@20.19.24)(@vue/compiler-sfc@3.5.22)(better-sqlite3@12.2.0)(db0@0.3.4(better-sqlite3@12.2.0))(eslint@9.29.0(jiti@2.6.1))(ioredis@5.8.2)(lightningcss@1.30.2)(magicast@0.3.5)(optionator@0.9.4)(rollup@4.52.5)(terser@5.44.0)(tsx@4.20.3)(typescript@5.8.3)(vite@7.1.12(@types/node@20.19.24)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.3)(yaml@2.8.1))(yaml@2.8.1): + nuxt@4.2.0(@parcel/watcher@2.5.1)(@types/node@20.19.24)(@vue/compiler-sfc@3.5.22)(better-sqlite3@12.2.0)(db0@0.3.4(better-sqlite3@12.2.0))(eslint@9.29.0(jiti@2.6.1))(ioredis@5.8.2)(lightningcss@1.30.2)(magicast@0.5.0)(optionator@0.9.4)(rollup@4.52.5)(terser@5.44.0)(tsx@4.20.3)(typescript@5.8.3)(vite@7.1.12(@types/node@20.19.24)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.3)(yaml@2.8.1))(yaml@2.8.1): dependencies: - '@dxup/nuxt': 0.2.0(magicast@0.3.5) - '@nuxt/cli': 3.29.3(magicast@0.3.5) + '@dxup/nuxt': 0.2.0(magicast@0.5.0) + '@nuxt/cli': 3.29.3(magicast@0.5.0) '@nuxt/devtools': 2.7.0(vite@7.1.12(@types/node@20.19.24)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.3)(yaml@2.8.1))(vue@3.5.22(typescript@5.8.3)) - '@nuxt/kit': 4.2.0(magicast@0.3.5) - '@nuxt/nitro-server': 4.2.0(better-sqlite3@12.2.0)(db0@0.3.4(better-sqlite3@12.2.0))(ioredis@5.8.2)(magicast@0.3.5)(nuxt@4.2.0(@parcel/watcher@2.5.1)(@types/node@20.19.24)(@vue/compiler-sfc@3.5.22)(better-sqlite3@12.2.0)(db0@0.3.4(better-sqlite3@12.2.0))(eslint@9.29.0(jiti@2.6.1))(ioredis@5.8.2)(lightningcss@1.30.2)(magicast@0.3.5)(optionator@0.9.4)(rollup@4.52.5)(terser@5.44.0)(tsx@4.20.3)(typescript@5.8.3)(vite@7.1.12(@types/node@20.19.24)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.3)(yaml@2.8.1))(yaml@2.8.1))(typescript@5.8.3) + '@nuxt/kit': 4.2.0(magicast@0.5.0) + '@nuxt/nitro-server': 4.2.0(better-sqlite3@12.2.0)(db0@0.3.4(better-sqlite3@12.2.0))(ioredis@5.8.2)(magicast@0.5.0)(nuxt@4.2.0(@parcel/watcher@2.5.1)(@types/node@20.19.24)(@vue/compiler-sfc@3.5.22)(better-sqlite3@12.2.0)(db0@0.3.4(better-sqlite3@12.2.0))(eslint@9.29.0(jiti@2.6.1))(ioredis@5.8.2)(lightningcss@1.30.2)(magicast@0.5.0)(optionator@0.9.4)(rollup@4.52.5)(terser@5.44.0)(tsx@4.20.3)(typescript@5.8.3)(vite@7.1.12(@types/node@20.19.24)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.3)(yaml@2.8.1))(yaml@2.8.1))(typescript@5.8.3) '@nuxt/schema': 4.2.0 - '@nuxt/telemetry': 2.6.6(magicast@0.3.5) - '@nuxt/vite-builder': 4.2.0(@types/node@20.19.24)(eslint@9.29.0(jiti@2.6.1))(lightningcss@1.30.2)(magicast@0.3.5)(nuxt@4.2.0(@parcel/watcher@2.5.1)(@types/node@20.19.24)(@vue/compiler-sfc@3.5.22)(better-sqlite3@12.2.0)(db0@0.3.4(better-sqlite3@12.2.0))(eslint@9.29.0(jiti@2.6.1))(ioredis@5.8.2)(lightningcss@1.30.2)(magicast@0.3.5)(optionator@0.9.4)(rollup@4.52.5)(terser@5.44.0)(tsx@4.20.3)(typescript@5.8.3)(vite@7.1.12(@types/node@20.19.24)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.3)(yaml@2.8.1))(yaml@2.8.1))(optionator@0.9.4)(rollup@4.52.5)(terser@5.44.0)(tsx@4.20.3)(typescript@5.8.3)(vue@3.5.22(typescript@5.8.3))(yaml@2.8.1) + '@nuxt/telemetry': 2.6.6(magicast@0.5.0) + '@nuxt/vite-builder': 4.2.0(@types/node@20.19.24)(eslint@9.29.0(jiti@2.6.1))(lightningcss@1.30.2)(magicast@0.5.0)(nuxt@4.2.0(@parcel/watcher@2.5.1)(@types/node@20.19.24)(@vue/compiler-sfc@3.5.22)(better-sqlite3@12.2.0)(db0@0.3.4(better-sqlite3@12.2.0))(eslint@9.29.0(jiti@2.6.1))(ioredis@5.8.2)(lightningcss@1.30.2)(magicast@0.5.0)(optionator@0.9.4)(rollup@4.52.5)(terser@5.44.0)(tsx@4.20.3)(typescript@5.8.3)(vite@7.1.12(@types/node@20.19.24)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.3)(yaml@2.8.1))(yaml@2.8.1))(optionator@0.9.4)(rollup@4.52.5)(terser@5.44.0)(tsx@4.20.3)(typescript@5.8.3)(vue@3.5.22(typescript@5.8.3))(yaml@2.8.1) '@unhead/vue': 2.0.19(vue@3.5.22(typescript@5.8.3)) '@vue/shared': 3.5.22 - c12: 3.3.1(magicast@0.3.5) + c12: 3.3.1(magicast@0.5.0) chokidar: 4.0.3 compatx: 0.2.0 consola: 3.4.2 @@ -13243,6 +13605,12 @@ snapshots: pure-rand@6.1.0: {} + pvtsutils@1.3.6: + dependencies: + tslib: 2.8.1 + + pvutils@1.1.5: {} + qs@6.13.0: dependencies: side-channel: 1.1.0 @@ -13335,6 +13703,8 @@ snapshots: dependencies: redis-errors: 1.2.0 + reflect-metadata@0.2.2: {} + reflect.getprototypeof@1.0.10: dependencies: call-bind: 1.0.8 @@ -13455,6 +13825,8 @@ snapshots: '@rollup/rollup-win32-x64-msvc': 4.52.5 fsevents: 2.3.3 + rou3@0.5.1: {} + router@2.2.0: dependencies: debug: 4.4.1 @@ -14081,6 +14453,8 @@ snapshots: minimist: 1.2.8 strip-bom: 3.0.0 + tslib@1.14.1: {} + tslib@2.8.1: {} tsup@8.5.0(@swc/core@1.12.5)(jiti@2.6.1)(postcss@8.5.6)(tsx@4.20.3)(typescript@5.8.3)(yaml@2.8.0): @@ -14119,6 +14493,10 @@ snapshots: optionalDependencies: fsevents: 2.3.3 + tsyringe@4.10.0: + dependencies: + tslib: 1.14.1 + tunnel-agent@0.6.0: dependencies: safe-buffer: 5.2.1 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 50f3e3fb..11104af6 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -17,6 +17,7 @@ catalog: 'better-sqlite3': ^12.2.0 '@types/better-sqlite3': ^7.6.13 'pg': ^8.13.1 + 'sql.js': ^1.13.0 'decimal.js': '^10.4.3' react: 19.2.0 '@types/react': 19.2.0 diff --git a/samples/next.js/package.json b/samples/next.js/package.json index 97538659..bd3c4049 100644 --- a/samples/next.js/package.json +++ b/samples/next.js/package.json @@ -1,6 +1,6 @@ { "name": "next.js", - "version": "3.0.0-beta.23", + "version": "3.0.0-beta.24", "private": true, "scripts": { "generate": "zen generate --lite", diff --git a/samples/orm/package.json b/samples/orm/package.json index 626e1f25..b61e998e 100644 --- a/samples/orm/package.json +++ b/samples/orm/package.json @@ -1,6 +1,6 @@ { "name": "sample-blog", - "version": "3.0.0-beta.23", + "version": "3.0.0-beta.24", "description": "", "main": "index.js", "private": true, diff --git a/tests/e2e/package.json b/tests/e2e/package.json index 422de543..9dcabf63 100644 --- a/tests/e2e/package.json +++ b/tests/e2e/package.json @@ -1,6 +1,6 @@ { "name": "e2e", - "version": "3.0.0-beta.23", + "version": "3.0.0-beta.24", "private": true, "type": "module", "scripts": { diff --git a/tests/regression/package.json b/tests/regression/package.json index e2dea7b7..a1c2fe39 100644 --- a/tests/regression/package.json +++ b/tests/regression/package.json @@ -1,6 +1,6 @@ { "name": "regression", - "version": "3.0.0-beta.23", + "version": "3.0.0-beta.24", "private": true, "type": "module", "scripts": { diff --git a/tests/regression/test/issue-393.test.ts b/tests/regression/test/issue-393.test.ts new file mode 100644 index 00000000..89d8c0b9 --- /dev/null +++ b/tests/regression/test/issue-393.test.ts @@ -0,0 +1,15 @@ +import { createTestClient } from '@zenstackhq/testtools'; +import { describe, expect, it } from 'vitest'; + +describe('Regression for issue #393', () => { + it('verifies issue 393', async () => { + const db = await createTestClient( + ` +model users { + id String @id() @default(cuid()) + tz Int @default(-6) @db.SmallInt() +}`, + ); + await expect(db.users.create({ data: {} })).resolves.toMatchObject({ tz: -6 }); + }); +});