@codixus/server 0.1.2 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/db/connection.ts","../src/auth/jwt.ts","../src/auth/ban.ts","../src/auth/guard.ts","../src/auth/router.ts","../src/db/query.ts","../src/db/model.ts","../src/db/transaction.ts","../src/middleware/signing.ts","../src/middleware/rate-limit.ts","../src/db/rest.ts","../src/codixus-server.ts","../src/middleware/validate.ts","../src/index.ts"],"sourcesContent":["import { MongoClient, type Db } from \"mongodb\";\n\nexport class ConnectionManager {\n private client: MongoClient | null = null;\n private db: Db | null = null;\n\n constructor(\n private uri: string,\n private dbName: string,\n ) {}\n\n async connect(): Promise<Db> {\n if (this.db) return this.db;\n\n this.client = new MongoClient(this.uri, {\n serverSelectionTimeoutMS: 5000,\n maxPoolSize: 10,\n retryWrites: true,\n retryReads: true,\n });\n await this.client.connect();\n this.db = this.client.db(this.dbName);\n return this.db;\n }\n\n getDb(): Db {\n if (!this.db) {\n throw new Error(\n \"Database not connected. Call codixus.connect() first.\",\n );\n }\n return this.db;\n }\n\n getClient(): MongoClient {\n if (!this.client) {\n throw new Error(\n \"Database not connected. Call codixus.connect() first.\",\n );\n }\n return this.client;\n }\n\n async disconnect(): Promise<void> {\n if (this.client) {\n await this.client.close();\n this.client = null;\n this.db = null;\n }\n }\n}\n","import { SignJWT, jwtVerify, type JWTPayload } from \"jose\";\nimport type { TokenPair } from \"@codixus/shared\";\nimport { CodixusError } from \"@codixus/shared\";\nimport crypto from \"node:crypto\";\n\nexport interface JwtConfig {\n secret: string;\n refreshSecret?: string;\n accessTokenTtl: string;\n refreshTokenTtl: string;\n}\n\nexport class JwtService {\n private secretKey: Uint8Array;\n private refreshSecretKey: Uint8Array;\n private accessTtl: string;\n private refreshTtl: string;\n\n constructor(config: JwtConfig) {\n this.secretKey = new TextEncoder().encode(config.secret);\n // Derive refresh secret via HMAC if not explicitly provided\n const refreshSecret = config.refreshSecret\n ?? crypto.createHmac(\"sha256\", config.secret).update(\"codixus:refresh\").digest(\"hex\");\n this.refreshSecretKey = new TextEncoder().encode(refreshSecret);\n this.accessTtl = config.accessTokenTtl;\n this.refreshTtl = config.refreshTokenTtl;\n }\n\n async sign(\n subject: string,\n claims: Record<string, unknown> = {},\n ): Promise<TokenPair> {\n const jti = crypto.randomUUID();\n\n const accessToken = await new SignJWT({\n ...claims,\n type: \"access\",\n deviceId: subject,\n })\n .setProtectedHeader({ alg: \"HS256\" })\n .setSubject(subject)\n .setIssuedAt()\n .setExpirationTime(this.accessTtl)\n .sign(this.secretKey);\n\n const refreshToken = await new SignJWT({\n type: \"refresh\",\n deviceId: subject,\n })\n .setProtectedHeader({ alg: \"HS256\" })\n .setSubject(subject)\n .setJti(jti)\n .setIssuedAt()\n .setExpirationTime(this.refreshTtl)\n .sign(this.refreshSecretKey);\n\n return { accessToken, refreshToken };\n }\n\n async verify(token: string): Promise<JWTPayload & { deviceId: string }> {\n try {\n const { payload } = await jwtVerify(token, this.secretKey);\n return payload as JWTPayload & { deviceId: string };\n } catch (error: unknown) {\n const message =\n error instanceof Error ? error.message : \"Token verification failed\";\n if (message.includes(\"exp\")) {\n throw new CodixusError(\"TOKEN_EXPIRED\", \"Access token expired\", 401);\n }\n throw new CodixusError(\"TOKEN_INVALID\", \"Invalid access token\", 401);\n }\n }\n\n async verifyRefresh(\n token: string,\n ): Promise<JWTPayload & { deviceId: string }> {\n try {\n const { payload } = await jwtVerify(token, this.refreshSecretKey);\n return payload as JWTPayload & { deviceId: string };\n } catch {\n throw new CodixusError(\n \"REFRESH_TOKEN_INVALID\",\n \"Invalid refresh token\",\n 401,\n );\n }\n }\n\n static hashToken(token: string): string {\n return crypto.createHash(\"sha256\").update(token).digest(\"hex\");\n }\n}\n","import type { Collection, Db } from \"mongodb\";\n\ninterface BannedDevice {\n _id: string;\n reason?: string;\n bannedAt: Date;\n}\n\nexport class BanService {\n private collection: Collection<BannedDevice>;\n private refreshTokensCol: Collection;\n\n constructor(db: Db) {\n this.collection = db.collection<BannedDevice>(\"banned_devices\");\n this.refreshTokensCol = db.collection(\"refresh_tokens\");\n }\n\n async ban(deviceId: string, reason?: string): Promise<void> {\n // Revoke all refresh tokens for this device\n await this.refreshTokensCol.updateMany(\n { deviceId, revokedAt: { $exists: false } },\n { $set: { revokedAt: new Date() } },\n );\n\n await this.collection.updateOne(\n { _id: deviceId },\n {\n $set: { reason, bannedAt: new Date() },\n $setOnInsert: { _id: deviceId },\n },\n { upsert: true },\n );\n }\n\n async unban(deviceId: string): Promise<void> {\n await this.collection.deleteOne({ _id: deviceId });\n }\n\n async isBanned(deviceId: string): Promise<boolean> {\n const doc = await this.collection.findOne({ _id: deviceId });\n return doc !== null;\n }\n\n async list(\n options: { limit?: number; offset?: number } = {},\n ): Promise<BannedDevice[]> {\n return this.collection\n .find()\n .sort({ bannedAt: -1 })\n .skip(options.offset ?? 0)\n .limit(options.limit ?? 50)\n .toArray();\n }\n}\n","import type { Request, Response, NextFunction } from \"express\";\nimport type { AuthUser } from \"@codixus/shared\";\nimport type { JwtService } from \"./jwt.js\";\n\ndeclare global {\n namespace Express {\n interface Request {\n user?: AuthUser;\n }\n }\n}\n\nexport interface GuardOptions {\n optional?: boolean;\n}\n\nexport function createGuard(jwt: JwtService) {\n return function guard(options: GuardOptions = {}) {\n return async (\n req: Request,\n res: Response,\n next: NextFunction,\n ): Promise<void> => {\n const authHeader = req.headers.authorization;\n\n if (!authHeader || !authHeader.startsWith(\"Bearer \")) {\n if (options.optional) {\n next();\n return;\n }\n res\n .status(401)\n .json({ success: false, error: \"Missing authorization header\" });\n return;\n }\n\n const token = authHeader.substring(7);\n\n try {\n const payload = await jwt.verify(token);\n req.user = {\n uid: payload.sub as string,\n deviceId: payload.deviceId,\n };\n next();\n } catch (error) {\n if (options.optional) {\n next();\n return;\n }\n res\n .status(401)\n .json({ success: false, error: \"Invalid or expired token\" });\n }\n };\n };\n}\n","import { Router, type Request, type Response } from \"express\";\nimport { authTokenRequestSchema, refreshTokenRequestSchema } from \"@codixus/shared\";\nimport { CodixusError } from \"@codixus/shared\";\nimport type { JwtService } from \"./jwt.js\";\nimport { JwtService as JwtServiceClass } from \"./jwt.js\";\nimport type { BanService } from \"./ban.js\";\nimport type { Db, Collection } from \"mongodb\";\n\nexport interface AuthRouterConfig {\n usersCollection: string;\n onRegister: (\n deviceId: string,\n body: { deviceInfo: { model: string; brand: string }; metadata?: Record<string, unknown> },\n ) => Record<string, unknown>;\n deviceBinding?: boolean;\n}\n\ninterface RefreshTokenDoc {\n _id?: unknown;\n deviceId: string;\n tokenHash: string;\n expiresAt: Date;\n revokedAt?: Date;\n createdAt: Date;\n}\n\nexport function createAuthRouter(\n jwt: JwtService,\n banService: BanService,\n db: Db,\n config: AuthRouterConfig,\n) {\n const router = Router();\n const usersCol = db.collection(config.usersCollection);\n const refreshTokensCol: Collection<RefreshTokenDoc> = db.collection(\"refresh_tokens\");\n\n router.post(\"/token\", async (req: Request, res: Response): Promise<void> => {\n try {\n const parsed = authTokenRequestSchema.safeParse(req.body);\n if (!parsed.success) {\n res.status(400).json({ success: false, error: \"Invalid request body\" });\n return;\n }\n\n const { deviceId, deviceInfo, metadata } = parsed.data;\n\n // Check ban\n const banned = await banService.isBanned(deviceId);\n if (banned) {\n res.status(403).json({\n success: false,\n error: \"DEVICE_BANNED\",\n message: \"Your device has been banned from using this application\",\n });\n return;\n }\n\n // Find or create user\n const existingUser = await usersCol.findOne({ _id: deviceId } as any);\n let isNewUser = false;\n let userData: Record<string, unknown>;\n\n if (!existingUser) {\n // New user\n userData = {\n _id: deviceId,\n ...config.onRegister(deviceId, { deviceInfo, metadata }),\n };\n await usersCol.insertOne(userData as any);\n isNewUser = true;\n } else {\n userData = existingUser as Record<string, unknown>;\n\n // Device binding check\n if (config.deviceBinding !== false) {\n const binding = existingUser.deviceBinding as\n | { model: string; brand: string }\n | undefined;\n if (binding) {\n if (\n binding.brand !== deviceInfo.brand ||\n binding.model !== deviceInfo.model\n ) {\n res.status(403).json({\n success: false,\n error: \"DEVICE_BINDING_MISMATCH\",\n message: \"This account is bound to a different device\",\n });\n return;\n }\n } else {\n await usersCol.updateOne(\n { _id: deviceId } as any,\n { $set: { deviceBinding: deviceInfo } },\n );\n }\n }\n\n // Update metadata if provided\n if (metadata) {\n await usersCol.updateOne(\n { _id: deviceId } as any,\n {\n $set: {\n metadata: { ...metadata, lastUpdated: Date.now() },\n },\n },\n );\n }\n }\n\n // Sign tokens\n const tokens = await jwt.sign(deviceId);\n\n // Store refresh token hash\n const tokenHash = JwtServiceClass.hashToken(tokens.refreshToken);\n await refreshTokensCol.insertOne({\n deviceId,\n tokenHash,\n expiresAt: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000), // 30 days\n createdAt: new Date(),\n });\n\n // Remove internal fields from response\n const { _id, ...userResponse } = userData;\n\n res.json({\n success: true,\n accessToken: tokens.accessToken,\n refreshToken: tokens.refreshToken,\n user: { ...userResponse, deviceId },\n isNewUser,\n });\n } catch (error) {\n console.error(\"Auth token error:\", error);\n res.status(500).json({\n success: false,\n error: \"Failed to create authentication token\",\n });\n }\n });\n\n router.post(\n \"/refresh\",\n async (req: Request, res: Response): Promise<void> => {\n try {\n const parsed = refreshTokenRequestSchema.safeParse(req.body);\n if (!parsed.success) {\n res\n .status(400)\n .json({ success: false, error: \"refreshToken is required\" });\n return;\n }\n\n const { refreshToken } = parsed.data;\n\n // Verify JWT\n const payload = await jwt.verifyRefresh(refreshToken);\n const deviceId = payload.sub as string;\n\n // Check ban\n const banned = await banService.isBanned(deviceId);\n if (banned) {\n res.status(403).json({\n success: false,\n error: \"DEVICE_BANNED\",\n });\n return;\n }\n\n // Atomically find and revoke old token (prevents race condition)\n const tokenHash = JwtServiceClass.hashToken(refreshToken);\n const storedToken = await refreshTokensCol.findOneAndUpdate(\n { tokenHash, revokedAt: { $exists: false } },\n { $set: { revokedAt: new Date() } },\n );\n\n if (!storedToken) {\n res.status(401).json({\n success: false,\n error: \"REFRESH_TOKEN_REVOKED\",\n });\n return;\n }\n\n // Issue new pair\n const tokens = await jwt.sign(deviceId);\n const newTokenHash = JwtServiceClass.hashToken(tokens.refreshToken);\n await refreshTokensCol.insertOne({\n deviceId,\n tokenHash: newTokenHash,\n expiresAt: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000),\n createdAt: new Date(),\n });\n\n res.json({\n success: true,\n accessToken: tokens.accessToken,\n refreshToken: tokens.refreshToken,\n });\n } catch (error) {\n if (error instanceof CodixusError) {\n res\n .status(error.statusCode)\n .json({ success: false, error: error.code });\n return;\n }\n console.error(\"Auth refresh error:\", error);\n res\n .status(500)\n .json({ success: false, error: \"Failed to refresh token\" });\n }\n },\n );\n\n router.post(\n \"/logout\",\n async (req: Request, res: Response): Promise<void> => {\n try {\n const { refreshToken } = req.body ?? {};\n if (refreshToken) {\n const tokenHash = JwtServiceClass.hashToken(refreshToken);\n await refreshTokensCol.updateOne(\n { tokenHash },\n { $set: { revokedAt: new Date() } },\n );\n }\n res.json({ success: true });\n } catch {\n res.json({ success: true }); // Logout is idempotent\n }\n },\n );\n\n return router;\n}\n","import type {\n Collection,\n Filter,\n Sort,\n Document,\n FindOptions,\n} from \"mongodb\";\n\nexport class Query<T extends Document> {\n private _filter: Filter<T>;\n private _sort: Sort | undefined;\n private _limit: number | undefined;\n private _skip: number | undefined;\n private _projection: Document | undefined;\n private _startAfterFilter: Filter<T> | undefined;\n private collection: Collection<T>;\n\n constructor(collection: Collection<T>, filter: Filter<T> = {}) {\n this.collection = collection;\n this._filter = filter;\n }\n\n sort(sort: Sort): this {\n this._sort = sort;\n return this;\n }\n\n limit(n: number): this {\n this._limit = n;\n return this;\n }\n\n skip(n: number): this {\n this._skip = n;\n return this;\n }\n\n select(projection: Document): this {\n this._projection = projection;\n return this;\n }\n\n /**\n * Cursor-based pagination.\n * Pass the last document from the previous page.\n * Requires sort() to be called first.\n *\n * Example:\n * const page1 = await Post.find({}).sort({ createdAt: -1 }).limit(20);\n * const page2 = await Post.find({}).sort({ createdAt: -1 }).startAfter(page1.at(-1)!).limit(20);\n */\n startAfter(doc: Record<string, unknown>): this {\n if (!this._sort) {\n throw new Error(\"startAfter() requires sort() to be called first\");\n }\n\n const sortEntries = Object.entries(this._sort as Record<string, number>);\n if (sortEntries.length === 0) {\n throw new Error(\"startAfter() requires at least one sort field\");\n }\n\n // Build cursor filter based on sort direction\n // For { createdAt: -1 } with lastDoc.createdAt = X → { createdAt: { $lt: X } }\n // For { createdAt: 1 } with lastDoc.createdAt = X → { createdAt: { $gt: X } }\n const conditions: Record<string, unknown>[] = [];\n for (const [field, direction] of sortEntries) {\n const value = doc[field];\n if (value === undefined) continue;\n const op = direction === -1 ? \"$lt\" : \"$gt\";\n conditions.push({ [field]: { [op]: value } });\n }\n\n if (conditions.length === 1) {\n this._startAfterFilter = conditions[0] as Filter<T>;\n } else if (conditions.length > 1) {\n this._startAfterFilter = { $or: conditions } as Filter<T>;\n }\n\n return this;\n }\n\n async exec(): Promise<T[]> {\n let filter = this._filter;\n\n // Merge startAfter filter\n if (this._startAfterFilter) {\n filter = { $and: [filter, this._startAfterFilter] } as Filter<T>;\n }\n\n const options: FindOptions = {};\n if (this._sort) options.sort = this._sort;\n if (this._limit) options.limit = this._limit;\n if (this._skip) options.skip = this._skip;\n if (this._projection) options.projection = this._projection;\n\n return this.collection.find(filter, options).toArray() as Promise<T[]>;\n }\n\n // Allow awaiting the query directly\n then<TResult1 = T[], TResult2 = never>(\n onfulfilled?: ((value: T[]) => TResult1 | PromiseLike<TResult1>) | null,\n onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null,\n ): Promise<TResult1 | TResult2> {\n return this.exec().then(onfulfilled, onrejected);\n }\n}\n","import type {\n Collection,\n Db,\n Filter,\n UpdateFilter,\n Document,\n BulkWriteOptions,\n AnyBulkWriteOperation,\n ClientSession,\n IndexDescription,\n} from \"mongodb\";\nimport type { z } from \"zod\";\nimport { Query } from \"./query.js\";\nimport crypto from \"node:crypto\";\n\nexport interface ModelDefinition<S extends z.ZodType> {\n schema: S;\n indexes?: Record<string, 1 | -1>[];\n timestamps?: boolean;\n}\n\nexport interface ModelOptions {\n session?: ClientSession;\n}\n\nexport interface FindAndUpdateOptions extends ModelOptions {\n returnNew?: boolean;\n}\n\nexport type ModelType<S extends z.ZodType> = z.infer<S> & { _id: string };\n\nexport class Model<S extends z.ZodType> {\n private collection!: Collection;\n private definition: ModelDefinition<S>;\n private _db: Db | null = null;\n private _boundTo: symbol | null = null;\n public readonly collectionName: string;\n\n constructor(collectionName: string, definition: ModelDefinition<S>) {\n this.collectionName = collectionName;\n this.definition = definition;\n }\n\n /** @internal - bind to a specific server instance */\n _bind(db: Db, instanceId: symbol): void {\n // Skip if already bound to this instance\n if (this._boundTo === instanceId) return;\n this._db = db;\n this.collection = db.collection(this.collectionName);\n this._boundTo = instanceId;\n }\n\n /** @internal */\n async _ensureIndexes(): Promise<void> {\n if (!this.definition.indexes?.length) return;\n const indexSpecs: IndexDescription[] = this.definition.indexes.map(\n (fields) => ({ key: fields }),\n );\n await this.collection.createIndexes(indexSpecs);\n }\n\n private getCol(): Collection {\n if (!this.collection) {\n throw new Error(\n `Model \"${this.collectionName}\" not bound to a database. Call codixus.connect() first.`,\n );\n }\n return this.collection;\n }\n\n private validate(data: unknown): z.infer<S> {\n return this.definition.schema.parse(data);\n }\n\n async create(\n data: z.input<S> & { _id?: string },\n options?: ModelOptions,\n ): Promise<ModelType<S>> {\n const validated = this.validate(data) as Record<string, unknown>;\n const id = data._id ?? crypto.randomUUID();\n const doc = { ...validated, _id: id } as any;\n if (this.definition.timestamps) {\n doc.createdAt = new Date();\n doc.updatedAt = new Date();\n }\n await this.getCol().insertOne(doc, { session: options?.session });\n return doc as ModelType<S>;\n }\n\n async findById(\n id: string,\n options?: ModelOptions,\n ): Promise<ModelType<S> | null> {\n const doc = await this.getCol().findOne(\n { _id: id as any },\n { session: options?.session },\n );\n return (doc as ModelType<S>) ?? null;\n }\n\n async findOne(\n filter: Filter<Document>,\n options?: ModelOptions,\n ): Promise<ModelType<S> | null> {\n const doc = await this.getCol().findOne(filter, {\n session: options?.session,\n });\n return (doc as ModelType<S>) ?? null;\n }\n\n find(filter: Filter<Document> = {}): Query<ModelType<S>> {\n return new Query<ModelType<S>>(this.getCol() as any, filter as any);\n }\n\n async updateById(\n id: string,\n update: UpdateFilter<Document>,\n options?: ModelOptions,\n ): Promise<boolean> {\n const timestampUpdate = this.definition.timestamps\n ? { $set: { updatedAt: new Date() }, ...update }\n : update;\n const result = await this.getCol().updateOne(\n { _id: id as any },\n timestampUpdate as any,\n { session: options?.session },\n );\n return result.matchedCount > 0;\n }\n\n async findByIdAndUpdate(\n id: string,\n update: UpdateFilter<Document>,\n options?: FindAndUpdateOptions,\n ): Promise<ModelType<S> | null> {\n const timestampUpdate = this.definition.timestamps\n ? { $set: { updatedAt: new Date() }, ...update }\n : update;\n const result = await this.getCol().findOneAndUpdate(\n { _id: id as any },\n timestampUpdate as any,\n {\n returnDocument: options?.returnNew ? \"after\" : \"before\",\n session: options?.session,\n },\n );\n return (result as ModelType<S>) ?? null;\n }\n\n async updateMany(\n filter: Filter<Document>,\n update: UpdateFilter<Document>,\n options?: ModelOptions,\n ): Promise<number> {\n const result = await this.getCol().updateMany(filter, update as any, {\n session: options?.session,\n });\n return result.modifiedCount;\n }\n\n async deleteById(id: string, options?: ModelOptions): Promise<boolean> {\n const result = await this.getCol().deleteOne(\n { _id: id as any },\n { session: options?.session },\n );\n return result.deletedCount > 0;\n }\n\n async deleteMany(\n filter: Filter<Document>,\n options?: ModelOptions,\n ): Promise<number> {\n const result = await this.getCol().deleteMany(filter, {\n session: options?.session,\n });\n return result.deletedCount;\n }\n\n async count(\n filter: Filter<Document> = {},\n options?: ModelOptions,\n ): Promise<number> {\n return this.getCol().countDocuments(filter, {\n session: options?.session,\n });\n }\n\n async exists(\n filter: Filter<Document>,\n options?: ModelOptions,\n ): Promise<boolean> {\n const doc = await this.getCol().findOne(filter, {\n projection: { _id: 1 },\n session: options?.session,\n });\n return doc !== null;\n }\n\n async bulk(\n operations: AnyBulkWriteOperation<Document>[],\n options?: BulkWriteOptions,\n ) {\n return this.getCol().bulkWrite(operations, options);\n }\n\n async aggregate(pipeline: Document[]): Promise<Document[]> {\n return this.getCol().aggregate(pipeline).toArray();\n }\n\n /**\n * Create a subcollection accessor.\n * Maps Firestore subcollections to separate MongoDB collections.\n * e.g. User.sub(\"user-123\", \"decisions\") → \"users__decisions\" collection\n * with { _parentId: \"user-123\", ... } on each document\n */\n sub<SubS extends z.ZodType>(\n parentId: string,\n subName: string,\n definition?: ModelDefinition<SubS>,\n ): SubCollection<SubS> {\n const subColName = `${this.collectionName}__${subName}`;\n return new SubCollection<SubS>(\n this.getCol().dbName ? this._db! : this._db!,\n subColName,\n parentId,\n definition,\n );\n }\n}\n\n/**\n * Subcollection maps Firestore subcollections to MongoDB.\n * e.g. users/{uid}/decisions → \"users__decisions\" collection\n * Each doc gets a _parentId field.\n */\nexport class SubCollection<S extends z.ZodType> {\n private collection: Collection;\n private parentId: string;\n private definition?: ModelDefinition<S>;\n\n constructor(\n db: Db,\n collectionName: string,\n parentId: string,\n definition?: ModelDefinition<S>,\n ) {\n this.collection = db.collection(collectionName);\n this.parentId = parentId;\n this.definition = definition;\n }\n\n async create(\n data: (S extends z.ZodType ? z.input<S> : Record<string, unknown>) & { _id?: string },\n options?: ModelOptions,\n ): Promise<any> {\n let validated: Record<string, unknown>;\n if (this.definition) {\n validated = this.definition.schema.parse(data) as Record<string, unknown>;\n } else {\n validated = data as Record<string, unknown>;\n }\n const id = data._id ?? crypto.randomUUID();\n const doc = { ...validated, _id: id, _parentId: this.parentId } as any;\n await this.collection.insertOne(doc, { session: options?.session });\n return doc;\n }\n\n async findById(id: string, options?: ModelOptions): Promise<any> {\n return this.collection.findOne(\n { _id: id as any, _parentId: this.parentId },\n { session: options?.session },\n );\n }\n\n async findOne(filter: Filter<Document> = {}, options?: ModelOptions): Promise<any> {\n return this.collection.findOne(\n { ...filter, _parentId: this.parentId },\n { session: options?.session },\n );\n }\n\n find(filter: Filter<Document> = {}): Query<any> {\n return new Query(this.collection as any, {\n ...filter,\n _parentId: this.parentId,\n } as any);\n }\n\n async updateById(\n id: string,\n update: UpdateFilter<Document>,\n options?: ModelOptions,\n ): Promise<boolean> {\n const result = await this.collection.updateOne(\n { _id: id as any, _parentId: this.parentId },\n update as any,\n { session: options?.session },\n );\n return result.matchedCount > 0;\n }\n\n async deleteById(id: string, options?: ModelOptions): Promise<boolean> {\n const result = await this.collection.deleteOne(\n { _id: id as any, _parentId: this.parentId },\n { session: options?.session },\n );\n return result.deletedCount > 0;\n }\n\n async count(filter: Filter<Document> = {}, options?: ModelOptions): Promise<number> {\n return this.collection.countDocuments(\n { ...filter, _parentId: this.parentId },\n { session: options?.session },\n );\n }\n}\n\n// Model registry - per instance via symbol\nconst modelRegistry: Model<any>[] = [];\n\nexport function model<S extends z.ZodType>(\n collectionName: string,\n definition: ModelDefinition<S>,\n): Model<S> {\n const m = new Model<S>(collectionName, definition);\n modelRegistry.push(m);\n return m;\n}\n\nexport function getModelRegistry(): Model<any>[] {\n return modelRegistry;\n}\n","import type { MongoClient, ClientSession } from \"mongodb\";\n\nexport async function runTransaction<T>(\n client: MongoClient,\n fn: (session: ClientSession) => Promise<T>,\n): Promise<T> {\n const session = client.startSession();\n try {\n let result: T;\n await session.withTransaction(async () => {\n result = await fn(session);\n });\n return result!;\n } finally {\n await session.endSession();\n }\n}\n","import type { Request, Response, NextFunction } from \"express\";\nimport crypto from \"node:crypto\";\n\nexport interface SigningConfig {\n appSecret: string;\n timestampWindowMs?: number;\n}\n\nconst DEFAULT_WINDOW_MS = 5 * 60 * 1000; // 5 minutes\nconst NONCE_CLEANUP_INTERVAL = 60 * 1000; // 1 minute\n\n// In-memory nonce store with automatic TTL cleanup\nconst usedNonces = new Map<string, number>();\n\nsetInterval(() => {\n const cutoff = Date.now() - DEFAULT_WINDOW_MS * 2;\n for (const [nonce, timestamp] of usedNonces) {\n if (timestamp < cutoff) {\n usedNonces.delete(nonce);\n }\n }\n}, NONCE_CLEANUP_INTERVAL).unref();\n\nfunction computeSignature(\n secret: string,\n method: string,\n path: string,\n timestamp: string,\n nonce: string,\n body: string,\n): string {\n const bodyHash = body\n ? crypto.createHash(\"sha256\").update(body).digest(\"hex\")\n : \"\";\n const payload = [method.toUpperCase(), path, timestamp, nonce, bodyHash].join(\n \"\\n\",\n );\n return crypto.createHmac(\"sha256\", secret).update(payload).digest(\"hex\");\n}\n\nexport function createSigningMiddleware(config: SigningConfig) {\n const { appSecret, timestampWindowMs = DEFAULT_WINDOW_MS } = config;\n\n return (req: Request, res: Response, next: NextFunction): void => {\n const timestamp = req.headers[\"x-codixus-timestamp\"] as string | undefined;\n const nonce = req.headers[\"x-codixus-nonce\"] as string | undefined;\n const signature = req.headers[\"x-codixus-signature\"] as string | undefined;\n\n // 1. All headers present?\n if (!timestamp || !nonce || !signature) {\n res.status(401).json({\n success: false,\n error: \"Missing signing headers\",\n });\n return;\n }\n\n // 2. Timestamp within window?\n const ts = Number(timestamp);\n if (Number.isNaN(ts)) {\n res.status(401).json({\n success: false,\n error: \"Invalid timestamp\",\n });\n return;\n }\n const now = Date.now();\n if (Math.abs(now - ts) > timestampWindowMs) {\n res.status(401).json({\n success: false,\n error: \"Request timestamp expired\",\n });\n return;\n }\n\n // 3. Nonce already used?\n if (usedNonces.has(nonce)) {\n res.status(401).json({\n success: false,\n error: \"Nonce already used\",\n });\n return;\n }\n\n // 4. Verify signature\n const rawBody =\n req.body && Object.keys(req.body).length > 0\n ? JSON.stringify(req.body)\n : \"\";\n\n // Use req.url (not req.originalUrl) so path matches client's relative URL\n // e.g. mounted at /api/v1 → req.url = /auth/token, req.originalUrl = /api/v1/auth/token\n const expectedSignature = computeSignature(\n appSecret,\n req.method,\n req.url,\n timestamp,\n nonce,\n rawBody,\n );\n\n const sigBuffer = Buffer.from(signature, \"hex\");\n const expectedBuffer = Buffer.from(expectedSignature, \"hex\");\n\n if (\n sigBuffer.length !== expectedBuffer.length ||\n !crypto.timingSafeEqual(sigBuffer, expectedBuffer)\n ) {\n if (process.env.NODE_ENV === \"development\") {\n console.warn(\"[Signing] Mismatch:\", {\n method: req.method,\n url: req.url,\n originalUrl: req.originalUrl,\n bodyLength: rawBody.length,\n clientSig: signature.slice(0, 16) + \"...\",\n serverSig: expectedSignature.slice(0, 16) + \"...\",\n });\n }\n res.status(401).json({\n success: false,\n error: \"Invalid signature\",\n });\n return;\n }\n\n // Mark nonce as used\n usedNonces.set(nonce, ts);\n\n next();\n };\n}\n\n// Exported for client-side use and testing\nexport { computeSignature };\n","import type { Request, Response, NextFunction } from \"express\";\n\nexport interface RateLimitConfig {\n windowMs?: number;\n maxRequests?: number;\n keyGenerator?: (req: Request) => string;\n message?: string;\n}\n\ninterface WindowEntry {\n count: number;\n resetAt: number;\n}\n\nconst CLEANUP_INTERVAL = 60 * 1000;\n\nexport function createRateLimit(config: RateLimitConfig = {}) {\n const {\n windowMs = 60_000,\n maxRequests = 60,\n keyGenerator = defaultKeyGenerator,\n message = \"Too many requests, please try again later\",\n } = config;\n\n const store = new Map<string, WindowEntry>();\n\n // Cleanup expired entries\n const cleanup = setInterval(() => {\n const now = Date.now();\n for (const [key, entry] of store) {\n if (entry.resetAt <= now) {\n store.delete(key);\n }\n }\n }, CLEANUP_INTERVAL);\n cleanup.unref();\n\n return (req: Request, res: Response, next: NextFunction): void => {\n const key = keyGenerator(req);\n const now = Date.now();\n let entry = store.get(key);\n\n if (!entry || entry.resetAt <= now) {\n entry = { count: 0, resetAt: now + windowMs };\n store.set(key, entry);\n }\n\n entry.count++;\n\n // Set rate limit headers\n const remaining = Math.max(0, maxRequests - entry.count);\n res.setHeader(\"X-RateLimit-Limit\", maxRequests);\n res.setHeader(\"X-RateLimit-Remaining\", remaining);\n res.setHeader(\"X-RateLimit-Reset\", Math.ceil(entry.resetAt / 1000));\n\n if (entry.count > maxRequests) {\n const retryAfter = Math.ceil((entry.resetAt - now) / 1000);\n res.setHeader(\"Retry-After\", retryAfter);\n res.status(429).json({\n success: false,\n error: message,\n retryAfter,\n });\n return;\n }\n\n next();\n };\n}\n\nfunction defaultKeyGenerator(req: Request): string {\n const ip =\n (req.headers[\"x-forwarded-for\"] as string)?.split(\",\")[0]?.trim() ||\n req.socket?.remoteAddress ||\n \"unknown\";\n const deviceId = (req as any).user?.deviceId || \"anonymous\";\n return `${ip}:${deviceId}`;\n}\n","import { Router, type Request, type Response } from \"express\";\nimport type { z } from \"zod\";\nimport type { Model } from \"./model.js\";\nimport crypto from \"node:crypto\";\n\nexport interface RestOptions {\n allowCreate?: boolean;\n allowUpdate?: boolean;\n allowDelete?: boolean | ((req: Request, doc: Record<string, unknown>) => boolean);\n maxLimit?: number;\n defaultLimit?: number;\n defaultSort?: Record<string, 1 | -1>;\n}\n\n// Update operator whitelist (same as old proxy sanitizer)\nconst SAFE_UPDATE_OPS = new Set([\n \"$set\", \"$unset\", \"$inc\", \"$push\", \"$pull\",\n \"$addToSet\", \"$pop\", \"$min\", \"$max\", \"$mul\",\n \"$currentDate\", \"$setOnInsert\",\n]);\n\nconst BLOCKED_OPS = new Set([\n \"$where\", \"$function\", \"$accumulator\", \"$expr\",\n \"$jsonSchema\", \"$comment\",\n]);\n\nfunction sanitizeObject(obj: unknown, depth = 0): Record<string, unknown> {\n if (depth > 10) throw new Error(\"Object too deeply nested\");\n if (obj === null || obj === undefined) return {};\n if (typeof obj !== \"object\" || Array.isArray(obj)) throw new Error(\"Expected object\");\n\n const result: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(obj as Record<string, unknown>)) {\n if (BLOCKED_OPS.has(key)) throw new Error(`Operator \"${key}\" is not allowed`);\n if (value !== null && typeof value === \"object\" && !Array.isArray(value) && !(value instanceof Date)) {\n result[key] = sanitizeObject(value, depth + 1);\n } else {\n result[key] = value;\n }\n }\n return result;\n}\n\nfunction sanitizeUpdate(obj: unknown): Record<string, unknown> {\n if (!obj || typeof obj !== \"object\") throw new Error(\"Update must be an object\");\n for (const key of Object.keys(obj as Record<string, unknown>)) {\n if (key.startsWith(\"$\") && !SAFE_UPDATE_OPS.has(key)) {\n throw new Error(`Update operator \"${key}\" is not allowed`);\n }\n }\n return sanitizeObject(obj);\n}\n\nfunction param(req: Request, name: string): string {\n const val = req.params[name];\n return Array.isArray(val) ? val[0]! : (val ?? \"\");\n}\n\nexport function createRestRouter<S extends z.ZodType>(\n model: Model<S>,\n options: RestOptions = {},\n): Router {\n const {\n allowCreate = true,\n allowUpdate = true,\n allowDelete = true,\n maxLimit = 100,\n defaultLimit = 20,\n defaultSort,\n } = options;\n\n const router = Router();\n\n // GET / — find\n router.get(\"/\", async (req: Request, res: Response): Promise<void> => {\n try {\n const filterStr = req.query.filter as string | undefined;\n const sortStr = req.query.sort as string | undefined;\n const limitStr = req.query.limit as string | undefined;\n const skipStr = req.query.skip as string | undefined;\n const cursor = req.query.cursor as string | undefined;\n\n let filter = {};\n if (filterStr) {\n filter = sanitizeObject(JSON.parse(filterStr));\n }\n\n const sort = sortStr ? JSON.parse(sortStr) : defaultSort;\n const limit = Math.min(Number(limitStr) || defaultLimit, maxLimit);\n const skip = Number(skipStr) || 0;\n\n let query = model.find(filter);\n if (sort) query = query.sort(sort);\n if (cursor && sort) {\n // Use first sort field for cursor pagination\n const sortField = Object.keys(sort)[0]!;\n const cursorValue = Number.isNaN(Number(cursor)) ? cursor : Number(cursor);\n query = query.startAfter({ [sortField]: cursorValue });\n }\n if (skip) query = query.skip(skip);\n query = query.limit(limit);\n\n const docs = await query.exec();\n let nextCursor: unknown = null;\n if (docs.length === limit && sort) {\n const sortField = Object.keys(sort)[0]!;\n nextCursor = (docs[docs.length - 1] as any)?.[sortField] ?? null;\n }\n\n res.json({ success: true, data: docs, nextCursor });\n } catch (error: any) {\n res.status(400).json({ success: false, error: error.message });\n }\n });\n\n // GET /:id — findById\n router.get(\"/:id\", async (req: Request, res: Response): Promise<void> => {\n const id = param(req, \"id\");\n const doc = await model.findById(id);\n if (!doc) {\n res.status(404).json({ success: false, error: \"Not found\" });\n return;\n }\n res.json({ success: true, data: doc });\n });\n\n // POST / — create\n router.post(\"/\", async (req: Request, res: Response): Promise<void> => {\n if (!allowCreate) {\n res.status(403).json({ success: false, error: \"Create not allowed\" });\n return;\n }\n try {\n const data = req.body;\n if (!data._id) data._id = crypto.randomUUID();\n const doc = await model.create(data);\n res.status(201).json({ success: true, data: doc });\n } catch (error: any) {\n res.status(400).json({ success: false, error: error.message });\n }\n });\n\n // POST /count — count\n router.post(\"/count\", async (req: Request, res: Response): Promise<void> => {\n try {\n const filter = req.body.filter ? sanitizeObject(req.body.filter) : {};\n const count = await model.count(filter);\n res.json({ success: true, count });\n } catch (error: any) {\n res.status(400).json({ success: false, error: error.message });\n }\n });\n\n // PATCH /:id — updateById\n router.patch(\"/:id\", async (req: Request, res: Response): Promise<void> => {\n if (!allowUpdate) {\n res.status(403).json({ success: false, error: \"Update not allowed\" });\n return;\n }\n const id = param(req, \"id\");\n try {\n const update = sanitizeUpdate(req.body.update ?? req.body);\n const success = await model.updateById(id, update);\n if (!success) {\n res.status(404).json({ success: false, error: \"Not found\" });\n return;\n }\n const doc = await model.findById(id);\n res.json({ success: true, data: doc });\n } catch (error: any) {\n res.status(400).json({ success: false, error: error.message });\n }\n });\n\n // DELETE /:id — deleteById\n router.delete(\"/:id\", async (req: Request, res: Response): Promise<void> => {\n const id = param(req, \"id\");\n\n if (typeof allowDelete === \"function\") {\n const doc = await model.findById(id);\n if (!doc) {\n res.status(404).json({ success: false, error: \"Not found\" });\n return;\n }\n if (!allowDelete(req, doc as Record<string, unknown>)) {\n res.status(403).json({ success: false, error: \"Delete not allowed\" });\n return;\n }\n } else if (!allowDelete) {\n res.status(403).json({ success: false, error: \"Delete not allowed\" });\n return;\n }\n\n const success = await model.deleteById(id);\n if (!success) {\n res.status(404).json({ success: false, error: \"Not found\" });\n return;\n }\n res.json({ success: true });\n });\n\n return router;\n}\n","import type { Request, Response, NextFunction, Router } from \"express\";\nimport type { ClientSession, Db } from \"mongodb\";\nimport { ConnectionManager } from \"./db/connection.js\";\nimport { JwtService } from \"./auth/jwt.js\";\nimport { BanService } from \"./auth/ban.js\";\nimport { createGuard, type GuardOptions } from \"./auth/guard.js\";\nimport { createAuthRouter, type AuthRouterConfig } from \"./auth/router.js\";\nimport { getModelRegistry, type Model } from \"./db/model.js\";\nimport { runTransaction } from \"./db/transaction.js\";\nimport {\n createSigningMiddleware,\n type SigningConfig,\n} from \"./middleware/signing.js\";\nimport {\n createRateLimit,\n type RateLimitConfig,\n} from \"./middleware/rate-limit.js\";\nimport { createRestRouter, type RestOptions } from \"./db/rest.js\";\nimport type { z } from \"zod\";\n\nexport interface CodixusServerConfig {\n mongoUri: string;\n jwtSecret: string;\n jwtRefreshSecret?: string;\n accessTokenTtl?: string;\n refreshTokenTtl?: string;\n dbName: string;\n appSecret?: string;\n}\n\nexport class CodixusServer {\n private connection: ConnectionManager;\n private jwt: JwtService;\n private banService!: BanService;\n private guardFn!: ReturnType<typeof createGuard>;\n private _db!: Db;\n private readonly instanceId = Symbol(\"codixus-server\");\n private _appSecret: string | undefined;\n\n auth!: {\n sign: (\n subject: string,\n claims?: Record<string, unknown>,\n ) => Promise<{ accessToken: string; refreshToken: string }>;\n verify: (\n token: string,\n ) => Promise<{\n sub?: string;\n deviceId: string;\n iat?: number;\n exp?: number;\n [key: string]: unknown;\n }>;\n refresh: (\n refreshToken: string,\n ) => Promise<{ accessToken: string; refreshToken: string }>;\n guard: (\n options?: GuardOptions,\n ) => ReturnType<ReturnType<typeof createGuard>>;\n router: (config: AuthRouterConfig) => Router;\n ban: (deviceId: string, reason?: string) => Promise<void>;\n unban: (deviceId: string) => Promise<void>;\n isBanned: (deviceId: string) => Promise<boolean>;\n };\n\n db!: {\n transaction: <T>(\n fn: (session: ClientSession) => Promise<T>,\n ) => Promise<T>;\n getDb: () => Db;\n };\n\n constructor(private config: CodixusServerConfig) {\n this.connection = new ConnectionManager(config.mongoUri, config.dbName);\n this._appSecret = config.appSecret;\n this.jwt = new JwtService({\n secret: config.jwtSecret,\n refreshSecret: config.jwtRefreshSecret,\n accessTokenTtl: config.accessTokenTtl ?? \"15m\",\n refreshTokenTtl: config.refreshTokenTtl ?? \"30d\",\n });\n }\n\n async connect(): Promise<void> {\n this._db = await this.connection.connect();\n this.banService = new BanService(this._db);\n this.guardFn = createGuard(this.jwt);\n\n // Bind all registered models to this DB instance\n for (const m of getModelRegistry()) {\n m._bind(this._db, this.instanceId);\n await m._ensureIndexes();\n }\n\n // Ensure auth indexes\n const refreshTokensCol = this._db.collection(\"refresh_tokens\");\n await refreshTokensCol.createIndex({ tokenHash: 1 }, { unique: true });\n await refreshTokensCol.createIndex({ deviceId: 1 });\n await refreshTokensCol.createIndex(\n { expiresAt: 1 },\n { expireAfterSeconds: 0 },\n );\n\n // Setup auth namespace\n this.auth = {\n sign: (subject, claims) => this.jwt.sign(subject, claims),\n verify: (token) => this.jwt.verify(token),\n refresh: async (refreshToken) => {\n const payload = await this.jwt.verifyRefresh(refreshToken);\n const deviceId = payload.sub as string;\n const tokens = await this.jwt.sign(deviceId);\n return tokens;\n },\n guard: (options) => this.guardFn(options),\n router: (config) =>\n createAuthRouter(this.jwt, this.banService, this._db, config),\n ban: (deviceId, reason) => this.banService.ban(deviceId, reason),\n unban: (deviceId) => this.banService.unban(deviceId),\n isBanned: (deviceId) => this.banService.isBanned(deviceId),\n };\n\n // Setup db namespace\n this.db = {\n transaction: <T>(fn: (session: ClientSession) => Promise<T>) =>\n runTransaction(this.connection.getClient(), fn),\n getDb: () => this._db,\n };\n }\n\n /**\n * HMAC request signing middleware.\n * Verifies that requests come from a client with the correct appSecret.\n */\n signing(\n overrides?: Partial<SigningConfig>,\n ): (req: Request, res: Response, next: NextFunction) => void {\n const secret = overrides?.appSecret ?? this._appSecret;\n if (!secret) {\n throw new Error(\n \"appSecret is required for signing. Set it in CodixusServer config or pass it to signing().\",\n );\n }\n return createSigningMiddleware({\n appSecret: secret,\n timestampWindowMs: overrides?.timestampWindowMs,\n });\n }\n\n /**\n * Rate limiting middleware.\n */\n rateLimit(config?: RateLimitConfig) {\n return createRateLimit(config);\n }\n\n /**\n * Auto REST router for a model.\n * Generates CRUD endpoints: GET /, GET /:id, POST /, PATCH /:id, DELETE /:id, POST /count\n */\n rest<S extends z.ZodType>(m: Model<S>, options?: RestOptions) {\n return createRestRouter(m, options);\n }\n\n async disconnect(): Promise<void> {\n await this.connection.disconnect();\n }\n}\n","import type { Request, Response, NextFunction } from \"express\";\nimport type { z } from \"zod\";\n\nexport function validate<T extends z.ZodType>(schema: T) {\n return (req: Request, res: Response, next: NextFunction): void => {\n const result = schema.safeParse(req.body);\n if (!result.success) {\n res.status(400).json({\n success: false,\n error: \"VALIDATION_ERROR\",\n details: result.error.issues,\n });\n return;\n }\n req.body = result.data;\n next();\n };\n}\n","export { CodixusServer, type CodixusServerConfig } from \"./codixus-server.js\";\nexport { model, Model, SubCollection, type ModelDefinition, type ModelType } from \"./db/model.js\";\nexport { Query } from \"./db/query.js\";\nexport { validate } from \"./middleware/validate.js\";\nexport { type RestOptions } from \"./db/rest.js\";\nexport { type SigningConfig } from \"./middleware/signing.js\";\nexport { type RateLimitConfig } from \"./middleware/rate-limit.js\";\nexport { type GuardOptions } from \"./auth/guard.js\";\nexport { type AuthRouterConfig } from \"./auth/router.js\";\n\n// Re-export shared types\nexport {\n type AuthUser,\n type TokenPayload,\n type TokenPair,\n type DeviceInfo,\n type DeviceMetadata,\n type AuthTokenRequest,\n type AuthTokenResponse,\n type ApiResponse,\n CodixusError,\n ErrorCodes,\n} from \"@codixus/shared\";\n"],"mappings":"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","names":["CodixusError","CodixusError","crypto","crypto","Router","crypto","model","CodixusError"]}
1
+ {"version":3,"sources":["../src/db/connection.ts","../src/auth/jwt.ts","../src/auth/ban.ts","../src/auth/guard.ts","../src/auth/router.ts","../src/db/query.ts","../src/db/model.ts","../src/db/transaction.ts","../src/middleware/signing.ts","../src/middleware/rate-limit.ts","../src/db/rest.ts","../src/codixus-server.ts","../src/middleware/validate.ts","../src/index.ts"],"sourcesContent":["import { MongoClient, type Db } from \"mongodb\";\n\nexport class ConnectionManager {\n private client: MongoClient | null = null;\n private db: Db | null = null;\n\n constructor(\n private uri: string,\n private dbName: string,\n ) {}\n\n async connect(): Promise<Db> {\n if (this.db) return this.db;\n\n this.client = new MongoClient(this.uri, {\n serverSelectionTimeoutMS: 5000,\n maxPoolSize: 10,\n retryWrites: true,\n retryReads: true,\n });\n await this.client.connect();\n this.db = this.client.db(this.dbName);\n return this.db;\n }\n\n getDb(): Db {\n if (!this.db) {\n throw new Error(\n \"Database not connected. Call codixus.connect() first.\",\n );\n }\n return this.db;\n }\n\n getClient(): MongoClient {\n if (!this.client) {\n throw new Error(\n \"Database not connected. Call codixus.connect() first.\",\n );\n }\n return this.client;\n }\n\n async disconnect(): Promise<void> {\n if (this.client) {\n await this.client.close();\n this.client = null;\n this.db = null;\n }\n }\n}\n","import { SignJWT, jwtVerify, type JWTPayload } from \"jose\";\nimport type { TokenPair } from \"@codixus/shared\";\nimport { CodixusError } from \"@codixus/shared\";\nimport crypto from \"node:crypto\";\n\nexport interface JwtConfig {\n secret: string;\n refreshSecret?: string;\n accessTokenTtl: string;\n refreshTokenTtl: string;\n}\n\nexport class JwtService {\n private secretKey: Uint8Array;\n private refreshSecretKey: Uint8Array;\n private accessTtl: string;\n private refreshTtl: string;\n\n constructor(config: JwtConfig) {\n this.secretKey = new TextEncoder().encode(config.secret);\n // Derive refresh secret via HMAC if not explicitly provided\n const refreshSecret = config.refreshSecret\n ?? crypto.createHmac(\"sha256\", config.secret).update(\"codixus:refresh\").digest(\"hex\");\n this.refreshSecretKey = new TextEncoder().encode(refreshSecret);\n this.accessTtl = config.accessTokenTtl;\n this.refreshTtl = config.refreshTokenTtl;\n }\n\n async sign(\n subject: string,\n claims: Record<string, unknown> = {},\n ): Promise<TokenPair> {\n const jti = crypto.randomUUID();\n\n const accessToken = await new SignJWT({\n ...claims,\n type: \"access\",\n deviceId: subject,\n })\n .setProtectedHeader({ alg: \"HS256\" })\n .setSubject(subject)\n .setIssuedAt()\n .setExpirationTime(this.accessTtl)\n .sign(this.secretKey);\n\n const refreshToken = await new SignJWT({\n type: \"refresh\",\n deviceId: subject,\n })\n .setProtectedHeader({ alg: \"HS256\" })\n .setSubject(subject)\n .setJti(jti)\n .setIssuedAt()\n .setExpirationTime(this.refreshTtl)\n .sign(this.refreshSecretKey);\n\n return { accessToken, refreshToken };\n }\n\n async verify(token: string): Promise<JWTPayload & { deviceId: string }> {\n try {\n const { payload } = await jwtVerify(token, this.secretKey);\n return payload as JWTPayload & { deviceId: string };\n } catch (error: unknown) {\n const message =\n error instanceof Error ? error.message : \"Token verification failed\";\n if (message.includes(\"exp\")) {\n throw new CodixusError(\"TOKEN_EXPIRED\", \"Access token expired\", 401);\n }\n throw new CodixusError(\"TOKEN_INVALID\", \"Invalid access token\", 401);\n }\n }\n\n async verifyRefresh(\n token: string,\n ): Promise<JWTPayload & { deviceId: string }> {\n try {\n const { payload } = await jwtVerify(token, this.refreshSecretKey);\n return payload as JWTPayload & { deviceId: string };\n } catch {\n throw new CodixusError(\n \"REFRESH_TOKEN_INVALID\",\n \"Invalid refresh token\",\n 401,\n );\n }\n }\n\n static hashToken(token: string): string {\n return crypto.createHash(\"sha256\").update(token).digest(\"hex\");\n }\n}\n","import type { Collection, Db } from \"mongodb\";\n\ninterface BannedDevice {\n _id: string;\n reason?: string;\n bannedAt: Date;\n}\n\nexport class BanService {\n private collection: Collection<BannedDevice>;\n private refreshTokensCol: Collection;\n\n constructor(db: Db) {\n this.collection = db.collection<BannedDevice>(\"banned_devices\");\n this.refreshTokensCol = db.collection(\"refresh_tokens\");\n }\n\n async ban(deviceId: string, reason?: string): Promise<void> {\n // Revoke all refresh tokens for this device\n await this.refreshTokensCol.updateMany(\n { deviceId, revokedAt: { $exists: false } },\n { $set: { revokedAt: new Date() } },\n );\n\n await this.collection.updateOne(\n { _id: deviceId },\n {\n $set: { reason, bannedAt: new Date() },\n $setOnInsert: { _id: deviceId },\n },\n { upsert: true },\n );\n }\n\n async unban(deviceId: string): Promise<void> {\n await this.collection.deleteOne({ _id: deviceId });\n }\n\n async isBanned(deviceId: string): Promise<boolean> {\n const doc = await this.collection.findOne({ _id: deviceId });\n return doc !== null;\n }\n\n async list(\n options: { limit?: number; offset?: number } = {},\n ): Promise<BannedDevice[]> {\n return this.collection\n .find()\n .sort({ bannedAt: -1 })\n .skip(options.offset ?? 0)\n .limit(options.limit ?? 50)\n .toArray();\n }\n}\n","import type { Request, Response, NextFunction } from \"express\";\nimport type { AuthUser } from \"@codixus/shared\";\nimport type { JwtService } from \"./jwt.js\";\nimport type { BanService } from \"./ban.js\";\n\ndeclare global {\n namespace Express {\n interface Request {\n user?: AuthUser;\n }\n }\n}\n\nexport interface GuardOptions {\n optional?: boolean;\n}\n\nexport function createGuard(jwt: JwtService, banService?: BanService) {\n return function guard(options: GuardOptions = {}) {\n return async (\n req: Request,\n res: Response,\n next: NextFunction,\n ): Promise<void> => {\n const authHeader = req.headers.authorization;\n\n if (!authHeader || !authHeader.startsWith(\"Bearer \")) {\n if (options.optional) {\n next();\n return;\n }\n res\n .status(401)\n .json({ success: false, error: \"Missing authorization header\" });\n return;\n }\n\n const token = authHeader.substring(7);\n\n try {\n const payload = await jwt.verify(token);\n const deviceId = payload.deviceId;\n\n if (banService && (await banService.isBanned(deviceId))) {\n res\n .status(403)\n .json({ success: false, error: \"DEVICE_BANNED\" });\n return;\n }\n\n req.user = {\n uid: payload.sub as string,\n deviceId,\n };\n next();\n } catch (error) {\n if (options.optional) {\n next();\n return;\n }\n res\n .status(401)\n .json({ success: false, error: \"Invalid or expired token\" });\n }\n };\n };\n}\n","import { Router, type Request, type Response } from \"express\";\nimport { authTokenRequestSchema, refreshTokenRequestSchema } from \"@codixus/shared\";\nimport { CodixusError } from \"@codixus/shared\";\nimport type { JwtService } from \"./jwt.js\";\nimport { JwtService as JwtServiceClass } from \"./jwt.js\";\nimport type { BanService } from \"./ban.js\";\nimport type { Db, Collection } from \"mongodb\";\n\nexport interface AuthRouterConfig {\n usersCollection: string;\n onRegister: (\n deviceId: string,\n body: { deviceInfo: { model: string; brand: string }; metadata?: Record<string, unknown> },\n ) => Record<string, unknown>;\n deviceBinding?: boolean;\n}\n\ninterface RefreshTokenDoc {\n _id?: unknown;\n deviceId: string;\n tokenHash: string;\n expiresAt: Date;\n revokedAt?: Date;\n createdAt: Date;\n}\n\nexport function createAuthRouter(\n jwt: JwtService,\n banService: BanService,\n db: Db,\n config: AuthRouterConfig,\n) {\n const router = Router();\n const usersCol = db.collection(config.usersCollection);\n const refreshTokensCol: Collection<RefreshTokenDoc> = db.collection(\"refresh_tokens\");\n\n router.post(\"/token\", async (req: Request, res: Response): Promise<void> => {\n try {\n const parsed = authTokenRequestSchema.safeParse(req.body);\n if (!parsed.success) {\n res.status(400).json({ success: false, error: \"Invalid request body\" });\n return;\n }\n\n const { deviceId, deviceInfo, metadata } = parsed.data;\n\n // Check ban\n const banned = await banService.isBanned(deviceId);\n if (banned) {\n res.status(403).json({\n success: false,\n error: \"DEVICE_BANNED\",\n message: \"Your device has been banned from using this application\",\n });\n return;\n }\n\n // Find or create user\n const existingUser = await usersCol.findOne({ _id: deviceId } as any);\n let isNewUser = false;\n let userData: Record<string, unknown>;\n\n if (!existingUser) {\n // New user\n userData = {\n _id: deviceId,\n ...config.onRegister(deviceId, { deviceInfo, metadata }),\n };\n await usersCol.insertOne(userData as any);\n isNewUser = true;\n } else {\n userData = existingUser as Record<string, unknown>;\n\n // Device binding check\n if (config.deviceBinding !== false) {\n const binding = existingUser.deviceBinding as\n | { model: string; brand: string }\n | undefined;\n if (binding) {\n if (\n binding.brand !== deviceInfo.brand ||\n binding.model !== deviceInfo.model\n ) {\n res.status(403).json({\n success: false,\n error: \"DEVICE_BINDING_MISMATCH\",\n message: \"This account is bound to a different device\",\n });\n return;\n }\n } else {\n await usersCol.updateOne(\n { _id: deviceId } as any,\n { $set: { deviceBinding: deviceInfo } },\n );\n }\n }\n\n // Update metadata if provided\n if (metadata) {\n await usersCol.updateOne(\n { _id: deviceId } as any,\n {\n $set: {\n metadata: { ...metadata, lastUpdated: Date.now() },\n },\n },\n );\n }\n }\n\n // Sign tokens\n const tokens = await jwt.sign(deviceId);\n\n // Store refresh token hash\n const tokenHash = JwtServiceClass.hashToken(tokens.refreshToken);\n await refreshTokensCol.insertOne({\n deviceId,\n tokenHash,\n expiresAt: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000), // 30 days\n createdAt: new Date(),\n });\n\n // Remove internal fields from response\n const { _id, ...userResponse } = userData;\n\n res.json({\n success: true,\n accessToken: tokens.accessToken,\n refreshToken: tokens.refreshToken,\n user: { ...userResponse, deviceId },\n isNewUser,\n });\n } catch (error) {\n console.error(\"Auth token error:\", error);\n res.status(500).json({\n success: false,\n error: \"Failed to create authentication token\",\n });\n }\n });\n\n router.post(\n \"/refresh\",\n async (req: Request, res: Response): Promise<void> => {\n try {\n const parsed = refreshTokenRequestSchema.safeParse(req.body);\n if (!parsed.success) {\n res\n .status(400)\n .json({ success: false, error: \"refreshToken is required\" });\n return;\n }\n\n const { refreshToken } = parsed.data;\n\n // Verify JWT\n const payload = await jwt.verifyRefresh(refreshToken);\n const deviceId = payload.sub as string;\n\n // Check ban\n const banned = await banService.isBanned(deviceId);\n if (banned) {\n res.status(403).json({\n success: false,\n error: \"DEVICE_BANNED\",\n });\n return;\n }\n\n // Atomically find and revoke old token (prevents race condition)\n const tokenHash = JwtServiceClass.hashToken(refreshToken);\n const storedToken = await refreshTokensCol.findOneAndUpdate(\n { tokenHash, revokedAt: { $exists: false } },\n { $set: { revokedAt: new Date() } },\n );\n\n if (!storedToken) {\n res.status(401).json({\n success: false,\n error: \"REFRESH_TOKEN_REVOKED\",\n });\n return;\n }\n\n // Issue new pair\n const tokens = await jwt.sign(deviceId);\n const newTokenHash = JwtServiceClass.hashToken(tokens.refreshToken);\n await refreshTokensCol.insertOne({\n deviceId,\n tokenHash: newTokenHash,\n expiresAt: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000),\n createdAt: new Date(),\n });\n\n res.json({\n success: true,\n accessToken: tokens.accessToken,\n refreshToken: tokens.refreshToken,\n });\n } catch (error) {\n if (error instanceof CodixusError) {\n res\n .status(error.statusCode)\n .json({ success: false, error: error.code });\n return;\n }\n console.error(\"Auth refresh error:\", error);\n res\n .status(500)\n .json({ success: false, error: \"Failed to refresh token\" });\n }\n },\n );\n\n router.post(\n \"/logout\",\n async (req: Request, res: Response): Promise<void> => {\n try {\n const { refreshToken } = req.body ?? {};\n if (refreshToken) {\n const tokenHash = JwtServiceClass.hashToken(refreshToken);\n await refreshTokensCol.updateOne(\n { tokenHash },\n { $set: { revokedAt: new Date() } },\n );\n }\n res.json({ success: true });\n } catch {\n res.json({ success: true }); // Logout is idempotent\n }\n },\n );\n\n return router;\n}\n","import type {\n Collection,\n Filter,\n Sort,\n Document,\n FindOptions,\n} from \"mongodb\";\n\nexport class Query<T extends Document> {\n private _filter: Filter<T>;\n private _sort: Sort | undefined;\n private _limit: number | undefined;\n private _skip: number | undefined;\n private _projection: Document | undefined;\n private _startAfterFilter: Filter<T> | undefined;\n private collection: Collection<T>;\n\n constructor(collection: Collection<T>, filter: Filter<T> = {}) {\n this.collection = collection;\n this._filter = filter;\n }\n\n sort(sort: Sort): this {\n this._sort = sort;\n return this;\n }\n\n limit(n: number): this {\n this._limit = n;\n return this;\n }\n\n skip(n: number): this {\n this._skip = n;\n return this;\n }\n\n select(projection: Document): this {\n this._projection = projection;\n return this;\n }\n\n /**\n * Cursor-based pagination.\n * Pass the last document from the previous page.\n * Requires sort() to be called first.\n *\n * Example:\n * const page1 = await Post.find({}).sort({ createdAt: -1 }).limit(20);\n * const page2 = await Post.find({}).sort({ createdAt: -1 }).startAfter(page1.at(-1)!).limit(20);\n */\n startAfter(doc: Record<string, unknown>): this {\n if (!this._sort) {\n throw new Error(\"startAfter() requires sort() to be called first\");\n }\n\n const sortEntries = Object.entries(this._sort as Record<string, number>);\n if (sortEntries.length === 0) {\n throw new Error(\"startAfter() requires at least one sort field\");\n }\n\n // Build cursor filter based on sort direction\n // For { createdAt: -1 } with lastDoc.createdAt = X → { createdAt: { $lt: X } }\n // For { createdAt: 1 } with lastDoc.createdAt = X → { createdAt: { $gt: X } }\n const conditions: Record<string, unknown>[] = [];\n for (const [field, direction] of sortEntries) {\n const value = doc[field];\n if (value === undefined) continue;\n const op = direction === -1 ? \"$lt\" : \"$gt\";\n conditions.push({ [field]: { [op]: value } });\n }\n\n if (conditions.length === 1) {\n this._startAfterFilter = conditions[0] as Filter<T>;\n } else if (conditions.length > 1) {\n this._startAfterFilter = { $or: conditions } as Filter<T>;\n }\n\n return this;\n }\n\n async exec(): Promise<T[]> {\n let filter = this._filter;\n\n // Merge startAfter filter\n if (this._startAfterFilter) {\n filter = { $and: [filter, this._startAfterFilter] } as Filter<T>;\n }\n\n const options: FindOptions = {};\n if (this._sort) options.sort = this._sort;\n if (this._limit) options.limit = this._limit;\n if (this._skip) options.skip = this._skip;\n if (this._projection) options.projection = this._projection;\n\n return this.collection.find(filter, options).toArray() as Promise<T[]>;\n }\n\n // Allow awaiting the query directly\n then<TResult1 = T[], TResult2 = never>(\n onfulfilled?: ((value: T[]) => TResult1 | PromiseLike<TResult1>) | null,\n onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null,\n ): Promise<TResult1 | TResult2> {\n return this.exec().then(onfulfilled, onrejected);\n }\n}\n","import type {\n Collection,\n Db,\n Filter,\n UpdateFilter,\n Document,\n BulkWriteOptions,\n AnyBulkWriteOperation,\n ClientSession,\n IndexDescription,\n} from \"mongodb\";\nimport type { z } from \"zod\";\nimport { Query } from \"./query.js\";\nimport crypto from \"node:crypto\";\n\nexport interface ModelDefinition<S extends z.ZodType> {\n schema: S;\n indexes?: Record<string, 1 | -1>[];\n timestamps?: boolean;\n}\n\nexport interface ModelOptions {\n session?: ClientSession;\n}\n\nexport interface FindAndUpdateOptions extends ModelOptions {\n returnNew?: boolean;\n}\n\nexport type ModelType<S extends z.ZodType> = z.infer<S> & { _id: string };\n\nexport class Model<S extends z.ZodType> {\n private collection!: Collection;\n private definition: ModelDefinition<S>;\n private _db: Db | null = null;\n private _boundTo: symbol | null = null;\n public readonly collectionName: string;\n\n constructor(collectionName: string, definition: ModelDefinition<S>) {\n this.collectionName = collectionName;\n this.definition = definition;\n }\n\n /** @internal - bind to a specific server instance */\n _bind(db: Db, instanceId: symbol): void {\n // Skip if already bound to this instance\n if (this._boundTo === instanceId) return;\n this._db = db;\n this.collection = db.collection(this.collectionName);\n this._boundTo = instanceId;\n }\n\n /** @internal */\n async _ensureIndexes(): Promise<void> {\n if (!this.definition.indexes?.length) return;\n const indexSpecs: IndexDescription[] = this.definition.indexes.map(\n (fields) => ({ key: fields }),\n );\n await this.collection.createIndexes(indexSpecs);\n }\n\n private getCol(): Collection {\n if (!this.collection) {\n throw new Error(\n `Model \"${this.collectionName}\" not bound to a database. Call codixus.connect() first.`,\n );\n }\n return this.collection;\n }\n\n private validate(data: unknown): z.infer<S> {\n return this.definition.schema.parse(data);\n }\n\n async create(\n data: z.input<S> & { _id?: string },\n options?: ModelOptions,\n ): Promise<ModelType<S>> {\n const validated = this.validate(data) as Record<string, unknown>;\n const id = data._id ?? crypto.randomUUID();\n const doc = { ...validated, _id: id } as any;\n if (this.definition.timestamps) {\n doc.createdAt = new Date();\n doc.updatedAt = new Date();\n }\n await this.getCol().insertOne(doc, { session: options?.session });\n return doc as ModelType<S>;\n }\n\n async findById(\n id: string,\n options?: ModelOptions,\n ): Promise<ModelType<S> | null> {\n const doc = await this.getCol().findOne(\n { _id: id as any },\n { session: options?.session },\n );\n return (doc as ModelType<S>) ?? null;\n }\n\n async findOne(\n filter: Filter<Document>,\n options?: ModelOptions,\n ): Promise<ModelType<S> | null> {\n const doc = await this.getCol().findOne(filter, {\n session: options?.session,\n });\n return (doc as ModelType<S>) ?? null;\n }\n\n find(filter: Filter<Document> = {}): Query<ModelType<S>> {\n return new Query<ModelType<S>>(this.getCol() as any, filter as any);\n }\n\n async updateById(\n id: string,\n update: UpdateFilter<Document>,\n options?: ModelOptions,\n ): Promise<boolean> {\n const timestampUpdate = this.definition.timestamps\n ? { $set: { updatedAt: new Date() }, ...update }\n : update;\n const result = await this.getCol().updateOne(\n { _id: id as any },\n timestampUpdate as any,\n { session: options?.session },\n );\n return result.matchedCount > 0;\n }\n\n async findByIdAndUpdate(\n id: string,\n update: UpdateFilter<Document>,\n options?: FindAndUpdateOptions,\n ): Promise<ModelType<S> | null> {\n const timestampUpdate = this.definition.timestamps\n ? { $set: { updatedAt: new Date() }, ...update }\n : update;\n const result = await this.getCol().findOneAndUpdate(\n { _id: id as any },\n timestampUpdate as any,\n {\n returnDocument: options?.returnNew ? \"after\" : \"before\",\n session: options?.session,\n },\n );\n return (result as ModelType<S>) ?? null;\n }\n\n async updateMany(\n filter: Filter<Document>,\n update: UpdateFilter<Document>,\n options?: ModelOptions,\n ): Promise<number> {\n const result = await this.getCol().updateMany(filter, update as any, {\n session: options?.session,\n });\n return result.modifiedCount;\n }\n\n async deleteById(id: string, options?: ModelOptions): Promise<boolean> {\n const result = await this.getCol().deleteOne(\n { _id: id as any },\n { session: options?.session },\n );\n return result.deletedCount > 0;\n }\n\n async deleteMany(\n filter: Filter<Document>,\n options?: ModelOptions,\n ): Promise<number> {\n const result = await this.getCol().deleteMany(filter, {\n session: options?.session,\n });\n return result.deletedCount;\n }\n\n async count(\n filter: Filter<Document> = {},\n options?: ModelOptions,\n ): Promise<number> {\n return this.getCol().countDocuments(filter, {\n session: options?.session,\n });\n }\n\n async exists(\n filter: Filter<Document>,\n options?: ModelOptions,\n ): Promise<boolean> {\n const doc = await this.getCol().findOne(filter, {\n projection: { _id: 1 },\n session: options?.session,\n });\n return doc !== null;\n }\n\n async bulk(\n operations: AnyBulkWriteOperation<Document>[],\n options?: BulkWriteOptions,\n ) {\n return this.getCol().bulkWrite(operations, options);\n }\n\n async aggregate(pipeline: Document[]): Promise<Document[]> {\n return this.getCol().aggregate(pipeline).toArray();\n }\n\n /**\n * Create a subcollection accessor.\n * Maps Firestore subcollections to separate MongoDB collections.\n * e.g. User.sub(\"user-123\", \"decisions\") → \"users__decisions\" collection\n * with { _parentId: \"user-123\", ... } on each document\n */\n sub<SubS extends z.ZodType>(\n parentId: string,\n subName: string,\n definition?: ModelDefinition<SubS>,\n ): SubCollection<SubS> {\n const subColName = `${this.collectionName}__${subName}`;\n return new SubCollection<SubS>(\n this.getCol().dbName ? this._db! : this._db!,\n subColName,\n parentId,\n definition,\n );\n }\n}\n\n/**\n * Subcollection maps Firestore subcollections to MongoDB.\n * e.g. users/{uid}/decisions → \"users__decisions\" collection\n * Each doc gets a _parentId field.\n */\nexport class SubCollection<S extends z.ZodType> {\n private collection: Collection;\n private parentId: string;\n private definition?: ModelDefinition<S>;\n\n constructor(\n db: Db,\n collectionName: string,\n parentId: string,\n definition?: ModelDefinition<S>,\n ) {\n this.collection = db.collection(collectionName);\n this.parentId = parentId;\n this.definition = definition;\n }\n\n async create(\n data: (S extends z.ZodType ? z.input<S> : Record<string, unknown>) & { _id?: string },\n options?: ModelOptions,\n ): Promise<any> {\n let validated: Record<string, unknown>;\n if (this.definition) {\n validated = this.definition.schema.parse(data) as Record<string, unknown>;\n } else {\n validated = data as Record<string, unknown>;\n }\n const id = data._id ?? crypto.randomUUID();\n const doc = { ...validated, _id: id, _parentId: this.parentId } as any;\n await this.collection.insertOne(doc, { session: options?.session });\n return doc;\n }\n\n async findById(id: string, options?: ModelOptions): Promise<any> {\n return this.collection.findOne(\n { _id: id as any, _parentId: this.parentId },\n { session: options?.session },\n );\n }\n\n async findOne(filter: Filter<Document> = {}, options?: ModelOptions): Promise<any> {\n return this.collection.findOne(\n { ...filter, _parentId: this.parentId },\n { session: options?.session },\n );\n }\n\n find(filter: Filter<Document> = {}): Query<any> {\n return new Query(this.collection as any, {\n ...filter,\n _parentId: this.parentId,\n } as any);\n }\n\n async updateById(\n id: string,\n update: UpdateFilter<Document>,\n options?: ModelOptions,\n ): Promise<boolean> {\n const result = await this.collection.updateOne(\n { _id: id as any, _parentId: this.parentId },\n update as any,\n { session: options?.session },\n );\n return result.matchedCount > 0;\n }\n\n async deleteById(id: string, options?: ModelOptions): Promise<boolean> {\n const result = await this.collection.deleteOne(\n { _id: id as any, _parentId: this.parentId },\n { session: options?.session },\n );\n return result.deletedCount > 0;\n }\n\n async count(filter: Filter<Document> = {}, options?: ModelOptions): Promise<number> {\n return this.collection.countDocuments(\n { ...filter, _parentId: this.parentId },\n { session: options?.session },\n );\n }\n}\n\n// Model registry - per instance via symbol\nconst modelRegistry: Model<any>[] = [];\n\nexport function model<S extends z.ZodType>(\n collectionName: string,\n definition: ModelDefinition<S>,\n): Model<S> {\n const m = new Model<S>(collectionName, definition);\n modelRegistry.push(m);\n return m;\n}\n\nexport function getModelRegistry(): Model<any>[] {\n return modelRegistry;\n}\n","import type { MongoClient, ClientSession } from \"mongodb\";\n\nexport async function runTransaction<T>(\n client: MongoClient,\n fn: (session: ClientSession) => Promise<T>,\n): Promise<T> {\n const session = client.startSession();\n try {\n let result: T;\n await session.withTransaction(async () => {\n result = await fn(session);\n });\n return result!;\n } finally {\n await session.endSession();\n }\n}\n","import type { Request, Response, NextFunction } from \"express\";\nimport crypto from \"node:crypto\";\n\nexport interface SigningConfig {\n appSecret: string;\n timestampWindowMs?: number;\n}\n\nconst DEFAULT_WINDOW_MS = 5 * 60 * 1000; // 5 minutes\nconst NONCE_CLEANUP_INTERVAL = 60 * 1000; // 1 minute\n\n// In-memory nonce store with automatic TTL cleanup\nconst usedNonces = new Map<string, number>();\n\nsetInterval(() => {\n const cutoff = Date.now() - DEFAULT_WINDOW_MS * 2;\n for (const [nonce, timestamp] of usedNonces) {\n if (timestamp < cutoff) {\n usedNonces.delete(nonce);\n }\n }\n}, NONCE_CLEANUP_INTERVAL).unref();\n\nfunction computeSignature(\n secret: string,\n method: string,\n path: string,\n timestamp: string,\n nonce: string,\n body: string,\n): string {\n const bodyHash = body\n ? crypto.createHash(\"sha256\").update(body).digest(\"hex\")\n : \"\";\n const payload = [method.toUpperCase(), path, timestamp, nonce, bodyHash].join(\n \"\\n\",\n );\n return crypto.createHmac(\"sha256\", secret).update(payload).digest(\"hex\");\n}\n\nexport function createSigningMiddleware(config: SigningConfig) {\n const { appSecret, timestampWindowMs = DEFAULT_WINDOW_MS } = config;\n\n return (req: Request, res: Response, next: NextFunction): void => {\n const timestamp = req.headers[\"x-codixus-timestamp\"] as string | undefined;\n const nonce = req.headers[\"x-codixus-nonce\"] as string | undefined;\n const signature = req.headers[\"x-codixus-signature\"] as string | undefined;\n\n // 1. All headers present?\n if (!timestamp || !nonce || !signature) {\n res.status(401).json({\n success: false,\n error: \"Missing signing headers\",\n });\n return;\n }\n\n // 2. Timestamp within window?\n const ts = Number(timestamp);\n if (Number.isNaN(ts)) {\n res.status(401).json({\n success: false,\n error: \"Invalid timestamp\",\n });\n return;\n }\n const now = Date.now();\n if (Math.abs(now - ts) > timestampWindowMs) {\n res.status(401).json({\n success: false,\n error: \"Request timestamp expired\",\n });\n return;\n }\n\n // 3. Nonce already used?\n if (usedNonces.has(nonce)) {\n res.status(401).json({\n success: false,\n error: \"Nonce already used\",\n });\n return;\n }\n\n // 4. Verify signature\n const rawBody =\n req.body && Object.keys(req.body).length > 0\n ? JSON.stringify(req.body)\n : \"\";\n\n // Use req.url (not req.originalUrl) so path matches client's relative URL\n // e.g. mounted at /api/v1 → req.url = /auth/token, req.originalUrl = /api/v1/auth/token\n const expectedSignature = computeSignature(\n appSecret,\n req.method,\n req.url,\n timestamp,\n nonce,\n rawBody,\n );\n\n const sigBuffer = Buffer.from(signature, \"hex\");\n const expectedBuffer = Buffer.from(expectedSignature, \"hex\");\n\n if (\n sigBuffer.length !== expectedBuffer.length ||\n !crypto.timingSafeEqual(sigBuffer, expectedBuffer)\n ) {\n if (process.env.NODE_ENV === \"development\") {\n console.warn(\"[Signing] Mismatch:\", {\n method: req.method,\n url: req.url,\n originalUrl: req.originalUrl,\n bodyLength: rawBody.length,\n clientSig: signature.slice(0, 16) + \"...\",\n serverSig: expectedSignature.slice(0, 16) + \"...\",\n });\n }\n res.status(401).json({\n success: false,\n error: \"Invalid signature\",\n });\n return;\n }\n\n // Mark nonce as used\n usedNonces.set(nonce, ts);\n\n next();\n };\n}\n\n// Exported for client-side use and testing\nexport { computeSignature };\n","import type { Request, Response, NextFunction } from \"express\";\n\nexport interface RateLimitConfig {\n windowMs?: number;\n maxRequests?: number;\n keyGenerator?: (req: Request) => string;\n message?: string;\n}\n\ninterface WindowEntry {\n count: number;\n resetAt: number;\n}\n\nconst CLEANUP_INTERVAL = 60 * 1000;\n\nexport function createRateLimit(config: RateLimitConfig = {}) {\n const {\n windowMs = 60_000,\n maxRequests = 60,\n keyGenerator = defaultKeyGenerator,\n message = \"Too many requests, please try again later\",\n } = config;\n\n const store = new Map<string, WindowEntry>();\n\n // Cleanup expired entries\n const cleanup = setInterval(() => {\n const now = Date.now();\n for (const [key, entry] of store) {\n if (entry.resetAt <= now) {\n store.delete(key);\n }\n }\n }, CLEANUP_INTERVAL);\n cleanup.unref();\n\n return (req: Request, res: Response, next: NextFunction): void => {\n const key = keyGenerator(req);\n const now = Date.now();\n let entry = store.get(key);\n\n if (!entry || entry.resetAt <= now) {\n entry = { count: 0, resetAt: now + windowMs };\n store.set(key, entry);\n }\n\n entry.count++;\n\n // Set rate limit headers\n const remaining = Math.max(0, maxRequests - entry.count);\n res.setHeader(\"X-RateLimit-Limit\", String(maxRequests));\n res.setHeader(\"X-RateLimit-Remaining\", String(remaining));\n res.setHeader(\"X-RateLimit-Reset\", String(Math.ceil(entry.resetAt / 1000)));\n\n if (entry.count > maxRequests) {\n const retryAfter = Math.ceil((entry.resetAt - now) / 1000);\n res.setHeader(\"Retry-After\", String(retryAfter));\n res.status(429).json({\n success: false,\n error: message,\n retryAfter,\n });\n return;\n }\n\n next();\n };\n}\n\nfunction defaultKeyGenerator(req: Request): string {\n const ip =\n (req.headers[\"x-forwarded-for\"] as string)?.split(\",\")[0]?.trim() ||\n req.socket?.remoteAddress ||\n \"unknown\";\n const deviceId = (req as any).user?.deviceId || \"anonymous\";\n return `${ip}:${deviceId}`;\n}\n","import { Router, type Request, type Response } from \"express\";\nimport type { z } from \"zod\";\nimport type { AuthUser } from \"@codixus/shared\";\nimport type { Model } from \"./model.js\";\nimport crypto from \"node:crypto\";\n\n/**\n * A Request on which `req.user` has been populated by `auth.guard()`. Used in\n * `allowRead` / `allowWrite` / `allowDelete` hook signatures so consumers\n * don't need `req.user!` non-null assertions at the call site.\n */\nexport type AuthenticatedRequest = Request & { user: AuthUser };\n\ntype HookResult = boolean | Promise<boolean>;\n\n/**\n * Stable machine-readable codes returned alongside human-readable `error`\n * strings. Consumers should switch on `code`, not the message.\n */\nexport const RestErrorCode = {\n CreateDisabled: \"CREATE_DISABLED\",\n UpdateDisabled: \"UPDATE_DISABLED\",\n DeleteDisabled: \"DELETE_DISABLED\",\n ReadForbidden: \"READ_FORBIDDEN\",\n WriteForbidden: \"WRITE_FORBIDDEN\",\n DeleteForbidden: \"DELETE_FORBIDDEN\",\n NotFound: \"NOT_FOUND\",\n InvalidFilter: \"INVALID_FILTER\",\n InvalidSort: \"INVALID_SORT\",\n InvalidCursor: \"INVALID_CURSOR\",\n InvalidUpdate: \"INVALID_UPDATE\",\n InvalidBody: \"INVALID_BODY\",\n AuthRequired: \"AUTH_REQUIRED\",\n} as const;\nexport type RestErrorCode = (typeof RestErrorCode)[keyof typeof RestErrorCode];\n\nexport interface RestOptions {\n allowCreate?: boolean;\n allowUpdate?: boolean;\n /**\n * `true`/`false` toggles delete. A function form receives the current doc\n * and returns whether the caller is allowed to delete it (useful for\n * \"author can delete own post\" rules).\n */\n allowDelete?:\n | boolean\n | ((req: AuthenticatedRequest, doc: Record<string, unknown>) => HookResult);\n maxLimit?: number;\n defaultLimit?: number;\n defaultSort?: Record<string, 1 | -1>;\n\n /**\n * Field used to scope rows to a tenant/owner. When set, every\n * GET /:id, PATCH /:id, DELETE /:id, and list/count filter is forced\n * to include `{ [ownershipField]: req.user.deviceId }`. Without this\n * option the handlers are unscoped (IDOR-prone). Set to `\"_id\"` for\n * self-only collections (like users), or `\"authorId\"` for per-author data.\n *\n * @example\n * // Users can only read/update/delete themselves\n * codixus.rest(User, { ownershipField: \"_id\" })\n *\n * // Posts are scoped by authorId\n * codixus.rest(Post, { ownershipField: \"authorId\" })\n */\n ownershipField?: string;\n\n /** Top-level keys allowed inside the filter query parameter. */\n queryableFields?: string[];\n\n /** Field names allowed as sort keys (for `?sort=` and cursor pagination). */\n sortableFields?: string[];\n\n /** Whitelist of fields writable through PATCH. Reject any others. */\n writableFields?: string[];\n\n /** Projection for GET responses. Only these fields are returned (plus `_id`). */\n publicFields?: string[];\n\n /**\n * Comparison operators allowed inside filter values. Defaults to a safe set:\n * `$eq, $ne, $in, $nin, $gt, $gte, $lt, $lte`. Dangerous operators like\n * `$where`, `$regex`, `$expr` are rejected by default.\n */\n allowedOperators?: string[];\n\n /**\n * Optional hook — return `false` (or a Promise resolving to `false`) to deny\n * GET /:id after ownership passes. Async is supported so consumers can do\n * role/team lookups against the DB. Note: if guard middleware didn't run,\n * `req.user` may be undefined; check before relying on it.\n */\n allowRead?: (\n req: AuthenticatedRequest,\n doc: Record<string, unknown>,\n ) => HookResult;\n /**\n * Optional hook — return `false` (or a Promise resolving to `false`) to deny\n * PATCH /:id after ownership passes. See `allowRead` for async notes.\n */\n allowWrite?: (\n req: AuthenticatedRequest,\n doc: Record<string, unknown>,\n patch: Record<string, unknown>,\n ) => HookResult;\n}\n\nconst DEFAULT_ALLOWED_OPS = new Set([\n \"$eq\", \"$ne\", \"$in\", \"$nin\", \"$gt\", \"$gte\", \"$lt\", \"$lte\",\n]);\n\nconst SAFE_UPDATE_OPS = new Set([\n \"$set\", \"$unset\", \"$inc\", \"$push\", \"$pull\",\n \"$addToSet\", \"$pop\", \"$min\", \"$max\", \"$mul\",\n \"$currentDate\", \"$setOnInsert\",\n]);\n\nclass RestError extends Error {\n constructor(public code: RestErrorCode, message: string) {\n super(message);\n }\n}\n\nfunction param(req: Request, name: string): string {\n const val = req.params[name];\n return Array.isArray(val) ? val[0]! : (val ?? \"\");\n}\n\nfunction fail(\n res: Response,\n status: number,\n code: RestErrorCode,\n error: string,\n): void {\n res.status(status).json({ success: false, error, code });\n}\n\nfunction handleCaught(res: Response, err: unknown): void {\n if (err instanceof RestError) {\n const status = err.code === RestErrorCode.AuthRequired ? 401 : 400;\n fail(res, status, err.code, err.message);\n return;\n }\n const message = err instanceof Error ? err.message : String(err);\n fail(res, 400, RestErrorCode.InvalidBody, message);\n}\n\nfunction buildFilterValidator(\n queryableFields: Set<string> | null,\n allowedOps: Set<string>,\n) {\n return function sanitizeFilter(\n obj: unknown,\n depth = 0,\n ): Record<string, unknown> {\n if (depth > 10)\n throw new RestError(RestErrorCode.InvalidFilter, \"Filter too deeply nested\");\n if (obj === null || obj === undefined) return {};\n if (typeof obj !== \"object\" || Array.isArray(obj))\n throw new RestError(RestErrorCode.InvalidFilter, \"Filter must be an object\");\n\n const result: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(obj as Record<string, unknown>)) {\n if (key.startsWith(\"$\")) {\n if (!allowedOps.has(key)) {\n throw new RestError(\n RestErrorCode.InvalidFilter,\n `Operator \"${key}\" is not allowed`,\n );\n }\n result[key] = sanitizeFilterValue(value, allowedOps, depth + 1);\n } else {\n if (queryableFields && !queryableFields.has(key)) {\n throw new RestError(\n RestErrorCode.InvalidFilter,\n `Field \"${key}\" is not queryable`,\n );\n }\n result[key] = sanitizeFilterValue(value, allowedOps, depth + 1);\n }\n }\n return result;\n };\n}\n\nfunction sanitizeFilterValue(\n value: unknown,\n allowedOps: Set<string>,\n depth: number,\n): unknown {\n if (depth > 10)\n throw new RestError(RestErrorCode.InvalidFilter, \"Filter too deeply nested\");\n if (value === null) return null;\n if (Array.isArray(value)) {\n return value.map((v) => sanitizeFilterValue(v, allowedOps, depth + 1));\n }\n if (value instanceof Date) return value;\n if (typeof value !== \"object\") return value;\n\n const result: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(value as Record<string, unknown>)) {\n if (k.startsWith(\"$\") && !allowedOps.has(k)) {\n throw new RestError(\n RestErrorCode.InvalidFilter,\n `Operator \"${k}\" is not allowed`,\n );\n }\n result[k] = sanitizeFilterValue(v, allowedOps, depth + 1);\n }\n return result;\n}\n\nfunction assertNoNestedOperators(\n value: unknown,\n path: string,\n depth = 0,\n): void {\n if (depth > 10) return;\n if (value === null || typeof value !== \"object\") return;\n if (value instanceof Date) return;\n if (Array.isArray(value)) {\n for (const v of value) assertNoNestedOperators(v, path, depth + 1);\n return;\n }\n for (const [k, v] of Object.entries(value as Record<string, unknown>)) {\n if (k.startsWith(\"$\")) {\n throw new RestError(\n RestErrorCode.InvalidUpdate,\n `Nested operator \"${k}\" is not allowed inside update value for \"${path}\"`,\n );\n }\n assertNoNestedOperators(v, path, depth + 1);\n }\n}\n\nfunction sanitizeUpdate(\n obj: unknown,\n writableFields: Set<string> | null,\n): Record<string, unknown> {\n if (!obj || typeof obj !== \"object\" || Array.isArray(obj))\n throw new RestError(RestErrorCode.InvalidUpdate, \"Update must be an object\");\n\n const input = obj as Record<string, unknown>;\n const hasOperators = Object.keys(input).some((k) => k.startsWith(\"$\"));\n\n // If the body uses no operators, treat it as an implicit $set.\n const wrapped = hasOperators ? input : { $set: input };\n\n const result: Record<string, unknown> = {};\n for (const [op, fields] of Object.entries(wrapped)) {\n if (!op.startsWith(\"$\")) {\n throw new RestError(\n RestErrorCode.InvalidUpdate,\n \"Update must use $-prefixed operators\",\n );\n }\n if (!SAFE_UPDATE_OPS.has(op)) {\n throw new RestError(\n RestErrorCode.InvalidUpdate,\n `Update operator \"${op}\" is not allowed`,\n );\n }\n if (!fields || typeof fields !== \"object\" || Array.isArray(fields)) {\n throw new RestError(\n RestErrorCode.InvalidUpdate,\n `Operator \"${op}\" requires an object`,\n );\n }\n const validatedFields: Record<string, unknown> = {};\n for (const [field, value] of Object.entries(\n fields as Record<string, unknown>,\n )) {\n if (field.startsWith(\"$\")) {\n throw new RestError(\n RestErrorCode.InvalidUpdate,\n `Nested operator \"${field}\" is not allowed`,\n );\n }\n if (writableFields) {\n // Exact-match allowlist. A dotted path like \"profile.role\" must\n // appear verbatim in writableFields — otherwise \"profile\" as a\n // writable parent would silently grant write access to every\n // sub-key including privileged ones (role, stripeCustomerId, …).\n if (!writableFields.has(field)) {\n throw new RestError(\n RestErrorCode.InvalidUpdate,\n `Field \"${field}\" is not writable`,\n );\n }\n }\n // Even without writableFields, dotted-path writes are ambiguous\n // and can bypass Zod schema validation on nested objects, so\n // require the consumer to opt in explicitly via the allowlist.\n if (!writableFields && field.includes(\".\")) {\n throw new RestError(\n RestErrorCode.InvalidUpdate,\n `Dotted-path writes require explicit writableFields`,\n );\n }\n // Block nested-object payloads that themselves contain $-operators\n // (e.g. { profile: { $set: { role: \"admin\" } } } or a replacement\n // object carrying $where / $expr into a downstream validator).\n assertNoNestedOperators(value, field);\n validatedFields[field] = value;\n }\n result[op] = validatedFields;\n }\n return result;\n}\n\nfunction projectDoc(\n doc: Record<string, unknown> | null,\n publicFields: Set<string> | null,\n): Record<string, unknown> | null {\n if (!doc || !publicFields) return doc;\n const out: Record<string, unknown> = {};\n for (const f of publicFields) {\n if (f in doc) out[f] = doc[f];\n }\n // Always keep _id so callers can still reference the row.\n if (\"_id\" in doc) out._id = doc._id;\n return out;\n}\n\n// AES-256-GCM cursor encoding. Unlike HMAC-only signatures, the payload is\n// not recoverable in plaintext — this prevents an attacker from decoding\n// the `nextCursor` to read the terminal row's sort-field value (which would\n// leak field contents if a consumer sorts by a sensitive column).\nfunction encodeCursor(key: Buffer, payload: unknown): string {\n const iv = crypto.randomBytes(12);\n const cipher = crypto.createCipheriv(\"aes-256-gcm\", key, iv);\n const plaintext = Buffer.from(JSON.stringify(payload), \"utf8\");\n const ciphertext = Buffer.concat([cipher.update(plaintext), cipher.final()]);\n const tag = cipher.getAuthTag();\n return [\n iv.toString(\"base64url\"),\n tag.toString(\"base64url\"),\n ciphertext.toString(\"base64url\"),\n ].join(\".\");\n}\n\nfunction decodeCursor(key: Buffer, token: string): unknown {\n const parts = token.split(\".\");\n if (parts.length !== 3)\n throw new RestError(RestErrorCode.InvalidCursor, \"Invalid cursor\");\n const [ivB64, tagB64, ctB64] = parts as [string, string, string];\n let iv: Buffer, tag: Buffer, ct: Buffer;\n try {\n iv = Buffer.from(ivB64, \"base64url\");\n tag = Buffer.from(tagB64, \"base64url\");\n ct = Buffer.from(ctB64, \"base64url\");\n } catch {\n throw new RestError(RestErrorCode.InvalidCursor, \"Invalid cursor encoding\");\n }\n if (iv.length !== 12 || tag.length !== 16) {\n throw new RestError(RestErrorCode.InvalidCursor, \"Invalid cursor\");\n }\n try {\n const decipher = crypto.createDecipheriv(\"aes-256-gcm\", key, iv);\n decipher.setAuthTag(tag);\n const plaintext = Buffer.concat([decipher.update(ct), decipher.final()]);\n return JSON.parse(plaintext.toString(\"utf8\"));\n } catch {\n throw new RestError(RestErrorCode.InvalidCursor, \"Invalid cursor signature\");\n }\n}\n\nexport function createRestRouter<S extends z.ZodType>(\n model: Model<S>,\n options: RestOptions = {},\n): Router {\n const {\n allowCreate = true,\n allowUpdate = true,\n allowDelete = true,\n maxLimit = 100,\n defaultLimit = 20,\n defaultSort,\n ownershipField,\n queryableFields,\n sortableFields,\n writableFields,\n publicFields,\n allowedOperators,\n allowRead,\n allowWrite,\n } = options;\n\n const queryableSet = queryableFields ? new Set(queryableFields) : null;\n const sortableSet = sortableFields ? new Set(sortableFields) : null;\n const writableSet = writableFields ? new Set(writableFields) : null;\n const publicSet = publicFields ? new Set(publicFields) : null;\n const opsSet = allowedOperators\n ? new Set(allowedOperators)\n : DEFAULT_ALLOWED_OPS;\n const sanitizeFilter = buildFilterValidator(queryableSet, opsSet);\n\n // Per-router AES-256-GCM key. Rotates on process restart, which is\n // acceptable: cursors are ephemeral pagination tokens, not bookmarkable URLs.\n const cursorKey = crypto.randomBytes(32);\n\n function scopedFilter(\n req: Request,\n filter: Record<string, unknown>,\n ): Record<string, unknown> {\n if (!ownershipField) return filter;\n const owner = req.user?.deviceId;\n if (!owner)\n throw new RestError(\n RestErrorCode.AuthRequired,\n \"Authentication required\",\n );\n // Reject client-supplied filters that touch the ownership field.\n // We would overwrite them anyway, but silently doing so is surprising\n // DX and hides a very common mistake (consumer listed the ownership\n // field in `queryableFields`, expected filtering by it to work).\n if (ownershipField in filter) {\n throw new RestError(\n RestErrorCode.InvalidFilter,\n `Field \"${ownershipField}\" cannot be used in filter (auto-scoped to caller)`,\n );\n }\n return { ...filter, [ownershipField]: owner };\n }\n\n function validateSort(\n sort: Record<string, 1 | -1> | undefined,\n ): Record<string, 1 | -1> | undefined {\n if (!sort) return undefined;\n if (typeof sort !== \"object\" || Array.isArray(sort))\n throw new RestError(RestErrorCode.InvalidSort, \"Sort must be an object\");\n const out: Record<string, 1 | -1> = {};\n for (const [field, direction] of Object.entries(sort)) {\n if (field.startsWith(\"$\"))\n throw new RestError(\n RestErrorCode.InvalidSort,\n `Invalid sort field \"${field}\"`,\n );\n if (sortableSet && !sortableSet.has(field))\n throw new RestError(\n RestErrorCode.InvalidSort,\n `Field \"${field}\" is not sortable`,\n );\n if (direction !== 1 && direction !== -1)\n throw new RestError(\n RestErrorCode.InvalidSort,\n `Sort direction for \"${field}\" must be 1 or -1`,\n );\n out[field] = direction;\n }\n return out;\n }\n\n const router = Router();\n\n // GET / — find\n router.get(\"/\", async (req: Request, res: Response): Promise<void> => {\n try {\n const filterStr = req.query.filter as string | undefined;\n const sortStr = req.query.sort as string | undefined;\n const limitStr = req.query.limit as string | undefined;\n const skipStr = req.query.skip as string | undefined;\n const cursorToken = req.query.cursor as string | undefined;\n\n const rawFilter = filterStr ? JSON.parse(filterStr) : {};\n let filter = sanitizeFilter(rawFilter);\n filter = scopedFilter(req, filter);\n\n const rawSort = sortStr ? JSON.parse(sortStr) : defaultSort;\n const sort = validateSort(rawSort);\n const limit = Math.min(Number(limitStr) || defaultLimit, maxLimit);\n const skip = Number(skipStr) || 0;\n\n let query = model.find(filter);\n if (sort) query = query.sort(sort);\n if (cursorToken && sort) {\n const decoded = decodeCursor(cursorKey, cursorToken) as Record<\n string,\n unknown\n >;\n query = query.startAfter(decoded);\n }\n if (skip) query = query.skip(skip);\n query = query.limit(limit);\n\n const docs = (await query.exec()) as Record<string, unknown>[];\n\n let nextCursor: string | null = null;\n if (docs.length === limit && sort) {\n const last = docs[docs.length - 1]!;\n const cursorPayload: Record<string, unknown> = {};\n for (const field of Object.keys(sort)) {\n cursorPayload[field] = last[field];\n }\n nextCursor = encodeCursor(cursorKey, cursorPayload);\n }\n\n const projected = publicSet\n ? docs.map((d) => projectDoc(d, publicSet))\n : docs;\n\n res.json({ success: true, data: projected, nextCursor });\n } catch (error) {\n handleCaught(res, error);\n }\n });\n\n // GET /:id — findById\n router.get(\"/:id\", async (req: Request, res: Response): Promise<void> => {\n try {\n const id = param(req, \"id\");\n const doc = (await model.findById(id)) as Record<string, unknown> | null;\n if (!doc) {\n fail(res, 404, RestErrorCode.NotFound, \"Not found\");\n return;\n }\n if (ownershipField) {\n const owner = req.user?.deviceId;\n if (!owner || doc[ownershipField] !== owner) {\n // Return 404 not 403 so existence of other users' docs isn't leaked.\n fail(res, 404, RestErrorCode.NotFound, \"Not found\");\n return;\n }\n }\n if (allowRead && !(await allowRead(req as AuthenticatedRequest, doc))) {\n fail(res, 403, RestErrorCode.ReadForbidden, \"Read not allowed\");\n return;\n }\n res.json({ success: true, data: projectDoc(doc, publicSet) });\n } catch (error) {\n handleCaught(res, error);\n }\n });\n\n // POST / — create\n router.post(\"/\", async (req: Request, res: Response): Promise<void> => {\n if (!allowCreate) {\n fail(res, 403, RestErrorCode.CreateDisabled, \"Create not allowed\");\n return;\n }\n try {\n const data = { ...req.body };\n // If scoped, the row must belong to the caller — ignore any client-supplied owner.\n if (ownershipField) {\n const owner = req.user?.deviceId;\n if (!owner) {\n fail(res, 401, RestErrorCode.AuthRequired, \"Authentication required\");\n return;\n }\n data[ownershipField] = owner;\n }\n if (!data._id) data._id = crypto.randomUUID();\n const doc = await model.create(data);\n res\n .status(201)\n .json({ success: true, data: projectDoc(doc as any, publicSet) });\n } catch (error) {\n handleCaught(res, error);\n }\n });\n\n // POST /count — count\n router.post(\"/count\", async (req: Request, res: Response): Promise<void> => {\n try {\n const rawFilter = req.body.filter ?? {};\n let filter = sanitizeFilter(rawFilter);\n filter = scopedFilter(req, filter);\n const count = await model.count(filter);\n res.json({ success: true, count });\n } catch (error) {\n handleCaught(res, error);\n }\n });\n\n // PATCH /:id — updateById\n router.patch(\"/:id\", async (req: Request, res: Response): Promise<void> => {\n if (!allowUpdate) {\n fail(res, 403, RestErrorCode.UpdateDisabled, \"Update not allowed\");\n return;\n }\n const id = param(req, \"id\");\n try {\n const update = sanitizeUpdate(req.body.update ?? req.body, writableSet);\n\n // Ownership + optional custom write gate both need the existing doc.\n if (ownershipField || allowWrite) {\n const existing = (await model.findById(id)) as Record<\n string,\n unknown\n > | null;\n if (!existing) {\n fail(res, 404, RestErrorCode.NotFound, \"Not found\");\n return;\n }\n if (ownershipField) {\n const owner = req.user?.deviceId;\n if (!owner || existing[ownershipField] !== owner) {\n fail(res, 404, RestErrorCode.NotFound, \"Not found\");\n return;\n }\n }\n if (\n allowWrite &&\n !(await allowWrite(req as AuthenticatedRequest, existing, update))\n ) {\n fail(res, 403, RestErrorCode.WriteForbidden, \"Write not allowed\");\n return;\n }\n }\n\n const success = await model.updateById(id, update);\n if (!success) {\n fail(res, 404, RestErrorCode.NotFound, \"Not found\");\n return;\n }\n const doc = (await model.findById(id)) as Record<string, unknown> | null;\n res.json({ success: true, data: projectDoc(doc, publicSet) });\n } catch (error) {\n handleCaught(res, error);\n }\n });\n\n // DELETE /:id — deleteById\n router.delete(\"/:id\", async (req: Request, res: Response): Promise<void> => {\n // Short-circuit the globally-disabled case BEFORE touching the DB.\n // If we did the doc fetch first, the 404 vs 200 timing would leak\n // existence / ownership even though nobody is allowed to delete.\n if (allowDelete === false) {\n fail(res, 403, RestErrorCode.DeleteDisabled, \"Delete not allowed\");\n return;\n }\n\n const id = param(req, \"id\");\n\n try {\n const needsDoc = !!ownershipField || typeof allowDelete === \"function\";\n\n if (needsDoc) {\n const doc = (await model.findById(id)) as Record<\n string,\n unknown\n > | null;\n if (!doc) {\n fail(res, 404, RestErrorCode.NotFound, \"Not found\");\n return;\n }\n if (ownershipField) {\n const owner = req.user?.deviceId;\n if (!owner || doc[ownershipField] !== owner) {\n fail(res, 404, RestErrorCode.NotFound, \"Not found\");\n return;\n }\n }\n if (\n typeof allowDelete === \"function\" &&\n !(await allowDelete(req as AuthenticatedRequest, doc))\n ) {\n fail(\n res,\n 403,\n RestErrorCode.DeleteForbidden,\n \"Delete not allowed\",\n );\n return;\n }\n }\n\n const success = await model.deleteById(id);\n if (!success) {\n fail(res, 404, RestErrorCode.NotFound, \"Not found\");\n return;\n }\n res.json({ success: true });\n } catch (error) {\n handleCaught(res, error);\n }\n });\n\n return router;\n}\n","import type { Request, Response, NextFunction, Router } from \"express\";\nimport type { ClientSession, Db } from \"mongodb\";\nimport { ConnectionManager } from \"./db/connection.js\";\nimport { JwtService } from \"./auth/jwt.js\";\nimport { BanService } from \"./auth/ban.js\";\nimport { createGuard, type GuardOptions } from \"./auth/guard.js\";\nimport { createAuthRouter, type AuthRouterConfig } from \"./auth/router.js\";\nimport { getModelRegistry, type Model } from \"./db/model.js\";\nimport { runTransaction } from \"./db/transaction.js\";\nimport {\n createSigningMiddleware,\n type SigningConfig,\n} from \"./middleware/signing.js\";\nimport {\n createRateLimit,\n type RateLimitConfig,\n} from \"./middleware/rate-limit.js\";\nimport { createRestRouter, type RestOptions } from \"./db/rest.js\";\nimport type { z } from \"zod\";\n\nexport interface CodixusServerConfig {\n mongoUri: string;\n jwtSecret: string;\n jwtRefreshSecret?: string;\n accessTokenTtl?: string;\n refreshTokenTtl?: string;\n dbName: string;\n appSecret?: string;\n}\n\nexport class CodixusServer {\n private connection: ConnectionManager;\n private jwt: JwtService;\n private banService!: BanService;\n private guardFn!: ReturnType<typeof createGuard>;\n private _db!: Db;\n private readonly instanceId = Symbol(\"codixus-server\");\n private _appSecret: string | undefined;\n\n auth!: {\n sign: (\n subject: string,\n claims?: Record<string, unknown>,\n ) => Promise<{ accessToken: string; refreshToken: string }>;\n verify: (\n token: string,\n ) => Promise<{\n sub?: string;\n deviceId: string;\n iat?: number;\n exp?: number;\n [key: string]: unknown;\n }>;\n refresh: (\n refreshToken: string,\n ) => Promise<{ accessToken: string; refreshToken: string }>;\n guard: (\n options?: GuardOptions,\n ) => ReturnType<ReturnType<typeof createGuard>>;\n router: (config: AuthRouterConfig) => Router;\n ban: (deviceId: string, reason?: string) => Promise<void>;\n unban: (deviceId: string) => Promise<void>;\n isBanned: (deviceId: string) => Promise<boolean>;\n };\n\n db!: {\n transaction: <T>(\n fn: (session: ClientSession) => Promise<T>,\n ) => Promise<T>;\n getDb: () => Db;\n };\n\n constructor(private config: CodixusServerConfig) {\n this.connection = new ConnectionManager(config.mongoUri, config.dbName);\n this._appSecret = config.appSecret;\n this.jwt = new JwtService({\n secret: config.jwtSecret,\n refreshSecret: config.jwtRefreshSecret,\n accessTokenTtl: config.accessTokenTtl ?? \"15m\",\n refreshTokenTtl: config.refreshTokenTtl ?? \"30d\",\n });\n }\n\n async connect(): Promise<void> {\n this._db = await this.connection.connect();\n this.banService = new BanService(this._db);\n this.guardFn = createGuard(this.jwt, this.banService);\n\n // Bind all registered models to this DB instance\n for (const m of getModelRegistry()) {\n m._bind(this._db, this.instanceId);\n await m._ensureIndexes();\n }\n\n // Ensure auth indexes\n const refreshTokensCol = this._db.collection(\"refresh_tokens\");\n await refreshTokensCol.createIndex({ tokenHash: 1 }, { unique: true });\n await refreshTokensCol.createIndex({ deviceId: 1 });\n await refreshTokensCol.createIndex(\n { expiresAt: 1 },\n { expireAfterSeconds: 0 },\n );\n\n // Setup auth namespace\n this.auth = {\n sign: (subject, claims) => this.jwt.sign(subject, claims),\n verify: (token) => this.jwt.verify(token),\n refresh: async (refreshToken) => {\n const payload = await this.jwt.verifyRefresh(refreshToken);\n const deviceId = payload.sub as string;\n const tokens = await this.jwt.sign(deviceId);\n return tokens;\n },\n guard: (options) => this.guardFn(options),\n router: (config) =>\n createAuthRouter(this.jwt, this.banService, this._db, config),\n ban: (deviceId, reason) => this.banService.ban(deviceId, reason),\n unban: (deviceId) => this.banService.unban(deviceId),\n isBanned: (deviceId) => this.banService.isBanned(deviceId),\n };\n\n // Setup db namespace\n this.db = {\n transaction: <T>(fn: (session: ClientSession) => Promise<T>) =>\n runTransaction(this.connection.getClient(), fn),\n getDb: () => this._db,\n };\n }\n\n /**\n * HMAC request signing middleware.\n * Verifies that requests come from a client with the correct appSecret.\n */\n signing(\n overrides?: Partial<SigningConfig>,\n ): (req: Request, res: Response, next: NextFunction) => void {\n const secret = overrides?.appSecret ?? this._appSecret;\n if (!secret) {\n throw new Error(\n \"appSecret is required for signing. Set it in CodixusServer config or pass it to signing().\",\n );\n }\n return createSigningMiddleware({\n appSecret: secret,\n timestampWindowMs: overrides?.timestampWindowMs,\n });\n }\n\n /**\n * Rate limiting middleware.\n */\n rateLimit(config?: RateLimitConfig) {\n return createRateLimit(config);\n }\n\n /**\n * Auto REST router for a model.\n * Generates CRUD endpoints: GET /, GET /:id, POST /, PATCH /:id, DELETE /:id, POST /count\n */\n rest<S extends z.ZodType>(m: Model<S>, options?: RestOptions) {\n return createRestRouter(m, options);\n }\n\n async disconnect(): Promise<void> {\n await this.connection.disconnect();\n }\n}\n","import type { Request, Response, NextFunction } from \"express\";\nimport type { z } from \"zod\";\n\nexport function validate<T extends z.ZodType>(schema: T) {\n return (req: Request, res: Response, next: NextFunction): void => {\n const result = schema.safeParse(req.body);\n if (!result.success) {\n res.status(400).json({\n success: false,\n error: \"VALIDATION_ERROR\",\n details: result.error.issues,\n });\n return;\n }\n req.body = result.data;\n next();\n };\n}\n","export { CodixusServer, type CodixusServerConfig } from \"./codixus-server.js\";\nexport { model, Model, SubCollection, type ModelDefinition, type ModelType } from \"./db/model.js\";\nexport { Query } from \"./db/query.js\";\nexport { validate } from \"./middleware/validate.js\";\nexport {\n type RestOptions,\n type AuthenticatedRequest,\n RestErrorCode,\n} from \"./db/rest.js\";\nexport { type SigningConfig } from \"./middleware/signing.js\";\nexport { type RateLimitConfig } from \"./middleware/rate-limit.js\";\nexport { type GuardOptions } from \"./auth/guard.js\";\nexport { type AuthRouterConfig } from \"./auth/router.js\";\n\n// Re-export shared types\nexport {\n type AuthUser,\n type TokenPayload,\n type TokenPair,\n type DeviceInfo,\n type DeviceMetadata,\n type AuthTokenRequest,\n type AuthTokenResponse,\n type ApiResponse,\n CodixusError,\n ErrorCodes,\n} from \"@codixus/shared\";\n"],"mappings":"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","names":["CodixusError","CodixusError","crypto","crypto","Router","crypto","model","CodixusError"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codixus/server",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "description": "Server SDK for Express — JWT auth, MongoDB ORM, request signing, rate limiting",
5
5
  "type": "module",
6
6
  "license": "SEE LICENSE IN LICENSE",