@codixus/server 0.1.0 → 0.1.1
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.cjs +3 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +3 -4
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -745,10 +745,9 @@ function createSigningMiddleware(config) {
|
|
|
745
745
|
nonce,
|
|
746
746
|
rawBody
|
|
747
747
|
);
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
)) {
|
|
748
|
+
const sigBuffer = Buffer.from(signature, "hex");
|
|
749
|
+
const expectedBuffer = Buffer.from(expectedSignature, "hex");
|
|
750
|
+
if (sigBuffer.length !== expectedBuffer.length || !import_node_crypto3.default.timingSafeEqual(sigBuffer, expectedBuffer)) {
|
|
752
751
|
res.status(401).json({
|
|
753
752
|
success: false,
|
|
754
753
|
error: "Invalid signature"
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../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"],"sourcesContent":["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","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 const expectedSignature = computeSignature(\n appSecret,\n req.method,\n req.originalUrl || req.url,\n timestamp,\n nonce,\n rawBody,\n );\n\n if (\n !crypto.timingSafeEqual(\n Buffer.from(signature, \"hex\"),\n Buffer.from(expectedSignature, \"hex\"),\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"],"mappings":"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","names":["crypto","import_shared","import_node_crypto","crypto","import_node_crypto","crypto","import_express","import_node_crypto","model","crypto","import_shared"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../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"],"sourcesContent":["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","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 const expectedSignature = computeSignature(\n appSecret,\n req.method,\n req.originalUrl || 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 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"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,qBAAqC;AAE9B,IAAM,oBAAN,MAAwB;AAAA,EAI7B,YACU,KACA,QACR;AAFQ;AACA;AAAA,EACP;AAAA,EANK,SAA6B;AAAA,EAC7B,KAAgB;AAAA,EAOxB,MAAM,UAAuB;AAC3B,QAAI,KAAK,GAAI,QAAO,KAAK;AAEzB,SAAK,SAAS,IAAI,2BAAY,KAAK,KAAK;AAAA,MACtC,0BAA0B;AAAA,MAC1B,aAAa;AAAA,MACb,aAAa;AAAA,MACb,YAAY;AAAA,IACd,CAAC;AACD,UAAM,KAAK,OAAO,QAAQ;AAC1B,SAAK,KAAK,KAAK,OAAO,GAAG,KAAK,MAAM;AACpC,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,QAAY;AACV,QAAI,CAAC,KAAK,IAAI;AACZ,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AACA,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,YAAyB;AACvB,QAAI,CAAC,KAAK,QAAQ;AAChB,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AACA,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,MAAM,aAA4B;AAChC,QAAI,KAAK,QAAQ;AACf,YAAM,KAAK,OAAO,MAAM;AACxB,WAAK,SAAS;AACd,WAAK,KAAK;AAAA,IACZ;AAAA,EACF;AACF;;;AClDA,kBAAoD;AAEpD,oBAA6B;AAC7B,yBAAmB;AASZ,IAAM,aAAN,MAAiB;AAAA,EACd;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAER,YAAY,QAAmB;AAC7B,SAAK,YAAY,IAAI,YAAY,EAAE,OAAO,OAAO,MAAM;AAEvD,UAAM,gBAAgB,OAAO,iBACxB,mBAAAA,QAAO,WAAW,UAAU,OAAO,MAAM,EAAE,OAAO,iBAAiB,EAAE,OAAO,KAAK;AACtF,SAAK,mBAAmB,IAAI,YAAY,EAAE,OAAO,aAAa;AAC9D,SAAK,YAAY,OAAO;AACxB,SAAK,aAAa,OAAO;AAAA,EAC3B;AAAA,EAEA,MAAM,KACJ,SACA,SAAkC,CAAC,GACf;AACpB,UAAM,MAAM,mBAAAA,QAAO,WAAW;AAE9B,UAAM,cAAc,MAAM,IAAI,oBAAQ;AAAA,MACpC,GAAG;AAAA,MACH,MAAM;AAAA,MACN,UAAU;AAAA,IACZ,CAAC,EACE,mBAAmB,EAAE,KAAK,QAAQ,CAAC,EACnC,WAAW,OAAO,EAClB,YAAY,EACZ,kBAAkB,KAAK,SAAS,EAChC,KAAK,KAAK,SAAS;AAEtB,UAAM,eAAe,MAAM,IAAI,oBAAQ;AAAA,MACrC,MAAM;AAAA,MACN,UAAU;AAAA,IACZ,CAAC,EACE,mBAAmB,EAAE,KAAK,QAAQ,CAAC,EACnC,WAAW,OAAO,EAClB,OAAO,GAAG,EACV,YAAY,EACZ,kBAAkB,KAAK,UAAU,EACjC,KAAK,KAAK,gBAAgB;AAE7B,WAAO,EAAE,aAAa,aAAa;AAAA,EACrC;AAAA,EAEA,MAAM,OAAO,OAA2D;AACtE,QAAI;AACF,YAAM,EAAE,QAAQ,IAAI,UAAM,uBAAU,OAAO,KAAK,SAAS;AACzD,aAAO;AAAA,IACT,SAAS,OAAgB;AACvB,YAAM,UACJ,iBAAiB,QAAQ,MAAM,UAAU;AAC3C,UAAI,QAAQ,SAAS,KAAK,GAAG;AAC3B,cAAM,IAAI,2BAAa,iBAAiB,wBAAwB,GAAG;AAAA,MACrE;AACA,YAAM,IAAI,2BAAa,iBAAiB,wBAAwB,GAAG;AAAA,IACrE;AAAA,EACF;AAAA,EAEA,MAAM,cACJ,OAC4C;AAC5C,QAAI;AACF,YAAM,EAAE,QAAQ,IAAI,UAAM,uBAAU,OAAO,KAAK,gBAAgB;AAChE,aAAO;AAAA,IACT,QAAQ;AACN,YAAM,IAAI;AAAA,QACR;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EAEA,OAAO,UAAU,OAAuB;AACtC,WAAO,mBAAAA,QAAO,WAAW,QAAQ,EAAE,OAAO,KAAK,EAAE,OAAO,KAAK;AAAA,EAC/D;AACF;;;ACnFO,IAAM,aAAN,MAAiB;AAAA,EACd;AAAA,EACA;AAAA,EAER,YAAY,IAAQ;AAClB,SAAK,aAAa,GAAG,WAAyB,gBAAgB;AAC9D,SAAK,mBAAmB,GAAG,WAAW,gBAAgB;AAAA,EACxD;AAAA,EAEA,MAAM,IAAI,UAAkB,QAAgC;AAE1D,UAAM,KAAK,iBAAiB;AAAA,MAC1B,EAAE,UAAU,WAAW,EAAE,SAAS,MAAM,EAAE;AAAA,MAC1C,EAAE,MAAM,EAAE,WAAW,oBAAI,KAAK,EAAE,EAAE;AAAA,IACpC;AAEA,UAAM,KAAK,WAAW;AAAA,MACpB,EAAE,KAAK,SAAS;AAAA,MAChB;AAAA,QACE,MAAM,EAAE,QAAQ,UAAU,oBAAI,KAAK,EAAE;AAAA,QACrC,cAAc,EAAE,KAAK,SAAS;AAAA,MAChC;AAAA,MACA,EAAE,QAAQ,KAAK;AAAA,IACjB;AAAA,EACF;AAAA,EAEA,MAAM,MAAM,UAAiC;AAC3C,UAAM,KAAK,WAAW,UAAU,EAAE,KAAK,SAAS,CAAC;AAAA,EACnD;AAAA,EAEA,MAAM,SAAS,UAAoC;AACjD,UAAM,MAAM,MAAM,KAAK,WAAW,QAAQ,EAAE,KAAK,SAAS,CAAC;AAC3D,WAAO,QAAQ;AAAA,EACjB;AAAA,EAEA,MAAM,KACJ,UAA+C,CAAC,GACvB;AACzB,WAAO,KAAK,WACT,KAAK,EACL,KAAK,EAAE,UAAU,GAAG,CAAC,EACrB,KAAK,QAAQ,UAAU,CAAC,EACxB,MAAM,QAAQ,SAAS,EAAE,EACzB,QAAQ;AAAA,EACb;AACF;;;ACrCO,SAAS,YAAY,KAAiB;AAC3C,SAAO,SAAS,MAAM,UAAwB,CAAC,GAAG;AAChD,WAAO,OACL,KACA,KACA,SACkB;AAClB,YAAM,aAAa,IAAI,QAAQ;AAE/B,UAAI,CAAC,cAAc,CAAC,WAAW,WAAW,SAAS,GAAG;AACpD,YAAI,QAAQ,UAAU;AACpB,eAAK;AACL;AAAA,QACF;AACA,YACG,OAAO,GAAG,EACV,KAAK,EAAE,SAAS,OAAO,OAAO,+BAA+B,CAAC;AACjE;AAAA,MACF;AAEA,YAAM,QAAQ,WAAW,UAAU,CAAC;AAEpC,UAAI;AACF,cAAM,UAAU,MAAM,IAAI,OAAO,KAAK;AACtC,YAAI,OAAO;AAAA,UACT,KAAK,QAAQ;AAAA,UACb,UAAU,QAAQ;AAAA,QACpB;AACA,aAAK;AAAA,MACP,SAAS,OAAO;AACd,YAAI,QAAQ,UAAU;AACpB,eAAK;AACL;AAAA,QACF;AACA,YACG,OAAO,GAAG,EACV,KAAK,EAAE,SAAS,OAAO,OAAO,2BAA2B,CAAC;AAAA,MAC/D;AAAA,IACF;AAAA,EACF;AACF;;;ACxDA,qBAAoD;AACpD,IAAAC,iBAAkE;AAClE,IAAAA,iBAA6B;AAwBtB,SAAS,iBACd,KACA,YACA,IACA,QACA;AACA,QAAM,aAAS,uBAAO;AACtB,QAAM,WAAW,GAAG,WAAW,OAAO,eAAe;AACrD,QAAM,mBAAgD,GAAG,WAAW,gBAAgB;AAEpF,SAAO,KAAK,UAAU,OAAO,KAAc,QAAiC;AAC1E,QAAI;AACF,YAAM,SAAS,sCAAuB,UAAU,IAAI,IAAI;AACxD,UAAI,CAAC,OAAO,SAAS;AACnB,YAAI,OAAO,GAAG,EAAE,KAAK,EAAE,SAAS,OAAO,OAAO,uBAAuB,CAAC;AACtE;AAAA,MACF;AAEA,YAAM,EAAE,UAAU,YAAY,SAAS,IAAI,OAAO;AAGlD,YAAM,SAAS,MAAM,WAAW,SAAS,QAAQ;AACjD,UAAI,QAAQ;AACV,YAAI,OAAO,GAAG,EAAE,KAAK;AAAA,UACnB,SAAS;AAAA,UACT,OAAO;AAAA,UACP,SAAS;AAAA,QACX,CAAC;AACD;AAAA,MACF;AAGA,YAAM,eAAe,MAAM,SAAS,QAAQ,EAAE,KAAK,SAAS,CAAQ;AACpE,UAAI,YAAY;AAChB,UAAI;AAEJ,UAAI,CAAC,cAAc;AAEjB,mBAAW;AAAA,UACT,KAAK;AAAA,UACL,GAAG,OAAO,WAAW,UAAU,EAAE,YAAY,SAAS,CAAC;AAAA,QACzD;AACA,cAAM,SAAS,UAAU,QAAe;AACxC,oBAAY;AAAA,MACd,OAAO;AACL,mBAAW;AAGX,YAAI,OAAO,kBAAkB,OAAO;AAClC,gBAAM,UAAU,aAAa;AAG7B,cAAI,SAAS;AACX,gBACE,QAAQ,UAAU,WAAW,SAC7B,QAAQ,UAAU,WAAW,OAC7B;AACA,kBAAI,OAAO,GAAG,EAAE,KAAK;AAAA,gBACnB,SAAS;AAAA,gBACT,OAAO;AAAA,gBACP,SAAS;AAAA,cACX,CAAC;AACD;AAAA,YACF;AAAA,UACF,OAAO;AACL,kBAAM,SAAS;AAAA,cACb,EAAE,KAAK,SAAS;AAAA,cAChB,EAAE,MAAM,EAAE,eAAe,WAAW,EAAE;AAAA,YACxC;AAAA,UACF;AAAA,QACF;AAGA,YAAI,UAAU;AACZ,gBAAM,SAAS;AAAA,YACb,EAAE,KAAK,SAAS;AAAA,YAChB;AAAA,cACE,MAAM;AAAA,gBACJ,UAAU,EAAE,GAAG,UAAU,aAAa,KAAK,IAAI,EAAE;AAAA,cACnD;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAGA,YAAM,SAAS,MAAM,IAAI,KAAK,QAAQ;AAGtC,YAAM,YAAY,WAAgB,UAAU,OAAO,YAAY;AAC/D,YAAM,iBAAiB,UAAU;AAAA,QAC/B;AAAA,QACA;AAAA,QACA,WAAW,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,KAAK,KAAK,GAAI;AAAA;AAAA,QACzD,WAAW,oBAAI,KAAK;AAAA,MACtB,CAAC;AAGD,YAAM,EAAE,KAAK,GAAG,aAAa,IAAI;AAEjC,UAAI,KAAK;AAAA,QACP,SAAS;AAAA,QACT,aAAa,OAAO;AAAA,QACpB,cAAc,OAAO;AAAA,QACrB,MAAM,EAAE,GAAG,cAAc,SAAS;AAAA,QAClC;AAAA,MACF,CAAC;AAAA,IACH,SAAS,OAAO;AACd,cAAQ,MAAM,qBAAqB,KAAK;AACxC,UAAI,OAAO,GAAG,EAAE,KAAK;AAAA,QACnB,SAAS;AAAA,QACT,OAAO;AAAA,MACT,CAAC;AAAA,IACH;AAAA,EACF,CAAC;AAED,SAAO;AAAA,IACL;AAAA,IACA,OAAO,KAAc,QAAiC;AACpD,UAAI;AACF,cAAM,SAAS,yCAA0B,UAAU,IAAI,IAAI;AAC3D,YAAI,CAAC,OAAO,SAAS;AACnB,cACG,OAAO,GAAG,EACV,KAAK,EAAE,SAAS,OAAO,OAAO,2BAA2B,CAAC;AAC7D;AAAA,QACF;AAEA,cAAM,EAAE,aAAa,IAAI,OAAO;AAGhC,cAAM,UAAU,MAAM,IAAI,cAAc,YAAY;AACpD,cAAM,WAAW,QAAQ;AAGzB,cAAM,SAAS,MAAM,WAAW,SAAS,QAAQ;AACjD,YAAI,QAAQ;AACV,cAAI,OAAO,GAAG,EAAE,KAAK;AAAA,YACnB,SAAS;AAAA,YACT,OAAO;AAAA,UACT,CAAC;AACD;AAAA,QACF;AAGA,cAAM,YAAY,WAAgB,UAAU,YAAY;AACxD,cAAM,cAAc,MAAM,iBAAiB;AAAA,UACzC,EAAE,WAAW,WAAW,EAAE,SAAS,MAAM,EAAE;AAAA,UAC3C,EAAE,MAAM,EAAE,WAAW,oBAAI,KAAK,EAAE,EAAE;AAAA,QACpC;AAEA,YAAI,CAAC,aAAa;AAChB,cAAI,OAAO,GAAG,EAAE,KAAK;AAAA,YACnB,SAAS;AAAA,YACT,OAAO;AAAA,UACT,CAAC;AACD;AAAA,QACF;AAGA,cAAM,SAAS,MAAM,IAAI,KAAK,QAAQ;AACtC,cAAM,eAAe,WAAgB,UAAU,OAAO,YAAY;AAClE,cAAM,iBAAiB,UAAU;AAAA,UAC/B;AAAA,UACA,WAAW;AAAA,UACX,WAAW,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,KAAK,KAAK,GAAI;AAAA,UACzD,WAAW,oBAAI,KAAK;AAAA,QACtB,CAAC;AAED,YAAI,KAAK;AAAA,UACP,SAAS;AAAA,UACT,aAAa,OAAO;AAAA,UACpB,cAAc,OAAO;AAAA,QACvB,CAAC;AAAA,MACH,SAAS,OAAO;AACd,YAAI,iBAAiB,6BAAc;AACjC,cACG,OAAO,MAAM,UAAU,EACvB,KAAK,EAAE,SAAS,OAAO,OAAO,MAAM,KAAK,CAAC;AAC7C;AAAA,QACF;AACA,gBAAQ,MAAM,uBAAuB,KAAK;AAC1C,YACG,OAAO,GAAG,EACV,KAAK,EAAE,SAAS,OAAO,OAAO,0BAA0B,CAAC;AAAA,MAC9D;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA,OAAO,KAAc,QAAiC;AACpD,UAAI;AACF,cAAM,EAAE,aAAa,IAAI,IAAI,QAAQ,CAAC;AACtC,YAAI,cAAc;AAChB,gBAAM,YAAY,WAAgB,UAAU,YAAY;AACxD,gBAAM,iBAAiB;AAAA,YACrB,EAAE,UAAU;AAAA,YACZ,EAAE,MAAM,EAAE,WAAW,oBAAI,KAAK,EAAE,EAAE;AAAA,UACpC;AAAA,QACF;AACA,YAAI,KAAK,EAAE,SAAS,KAAK,CAAC;AAAA,MAC5B,QAAQ;AACN,YAAI,KAAK,EAAE,SAAS,KAAK,CAAC;AAAA,MAC5B;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;;;ACnOO,IAAM,QAAN,MAAgC;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAER,YAAY,YAA2B,SAAoB,CAAC,GAAG;AAC7D,SAAK,aAAa;AAClB,SAAK,UAAU;AAAA,EACjB;AAAA,EAEA,KAAK,MAAkB;AACrB,SAAK,QAAQ;AACb,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,GAAiB;AACrB,SAAK,SAAS;AACd,WAAO;AAAA,EACT;AAAA,EAEA,KAAK,GAAiB;AACpB,SAAK,QAAQ;AACb,WAAO;AAAA,EACT;AAAA,EAEA,OAAO,YAA4B;AACjC,SAAK,cAAc;AACnB,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,WAAW,KAAoC;AAC7C,QAAI,CAAC,KAAK,OAAO;AACf,YAAM,IAAI,MAAM,iDAAiD;AAAA,IACnE;AAEA,UAAM,cAAc,OAAO,QAAQ,KAAK,KAA+B;AACvE,QAAI,YAAY,WAAW,GAAG;AAC5B,YAAM,IAAI,MAAM,+CAA+C;AAAA,IACjE;AAKA,UAAM,aAAwC,CAAC;AAC/C,eAAW,CAAC,OAAO,SAAS,KAAK,aAAa;AAC5C,YAAM,QAAQ,IAAI,KAAK;AACvB,UAAI,UAAU,OAAW;AACzB,YAAM,KAAK,cAAc,KAAK,QAAQ;AACtC,iBAAW,KAAK,EAAE,CAAC,KAAK,GAAG,EAAE,CAAC,EAAE,GAAG,MAAM,EAAE,CAAC;AAAA,IAC9C;AAEA,QAAI,WAAW,WAAW,GAAG;AAC3B,WAAK,oBAAoB,WAAW,CAAC;AAAA,IACvC,WAAW,WAAW,SAAS,GAAG;AAChC,WAAK,oBAAoB,EAAE,KAAK,WAAW;AAAA,IAC7C;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,OAAqB;AACzB,QAAI,SAAS,KAAK;AAGlB,QAAI,KAAK,mBAAmB;AAC1B,eAAS,EAAE,MAAM,CAAC,QAAQ,KAAK,iBAAiB,EAAE;AAAA,IACpD;AAEA,UAAM,UAAuB,CAAC;AAC9B,QAAI,KAAK,MAAO,SAAQ,OAAO,KAAK;AACpC,QAAI,KAAK,OAAQ,SAAQ,QAAQ,KAAK;AACtC,QAAI,KAAK,MAAO,SAAQ,OAAO,KAAK;AACpC,QAAI,KAAK,YAAa,SAAQ,aAAa,KAAK;AAEhD,WAAO,KAAK,WAAW,KAAK,QAAQ,OAAO,EAAE,QAAQ;AAAA,EACvD;AAAA;AAAA,EAGA,KACE,aACA,YAC8B;AAC9B,WAAO,KAAK,KAAK,EAAE,KAAK,aAAa,UAAU;AAAA,EACjD;AACF;;;AC5FA,IAAAC,sBAAmB;AAkBZ,IAAM,QAAN,MAAiC;AAAA,EAC9B;AAAA,EACA;AAAA,EACA,MAAiB;AAAA,EACjB,WAA0B;AAAA,EAClB;AAAA,EAEhB,YAAY,gBAAwB,YAAgC;AAClE,SAAK,iBAAiB;AACtB,SAAK,aAAa;AAAA,EACpB;AAAA;AAAA,EAGA,MAAM,IAAQ,YAA0B;AAEtC,QAAI,KAAK,aAAa,WAAY;AAClC,SAAK,MAAM;AACX,SAAK,aAAa,GAAG,WAAW,KAAK,cAAc;AACnD,SAAK,WAAW;AAAA,EAClB;AAAA;AAAA,EAGA,MAAM,iBAAgC;AACpC,QAAI,CAAC,KAAK,WAAW,SAAS,OAAQ;AACtC,UAAM,aAAiC,KAAK,WAAW,QAAQ;AAAA,MAC7D,CAAC,YAAY,EAAE,KAAK,OAAO;AAAA,IAC7B;AACA,UAAM,KAAK,WAAW,cAAc,UAAU;AAAA,EAChD;AAAA,EAEQ,SAAqB;AAC3B,QAAI,CAAC,KAAK,YAAY;AACpB,YAAM,IAAI;AAAA,QACR,UAAU,KAAK,cAAc;AAAA,MAC/B;AAAA,IACF;AACA,WAAO,KAAK;AAAA,EACd;AAAA,EAEQ,SAAS,MAA2B;AAC1C,WAAO,KAAK,WAAW,OAAO,MAAM,IAAI;AAAA,EAC1C;AAAA,EAEA,MAAM,OACJ,MACA,SACuB;AACvB,UAAM,YAAY,KAAK,SAAS,IAAI;AACpC,UAAM,KAAK,KAAK,OAAO,oBAAAC,QAAO,WAAW;AACzC,UAAM,MAAM,EAAE,GAAG,WAAW,KAAK,GAAG;AACpC,QAAI,KAAK,WAAW,YAAY;AAC9B,UAAI,YAAY,oBAAI,KAAK;AACzB,UAAI,YAAY,oBAAI,KAAK;AAAA,IAC3B;AACA,UAAM,KAAK,OAAO,EAAE,UAAU,KAAK,EAAE,SAAS,SAAS,QAAQ,CAAC;AAChE,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,SACJ,IACA,SAC8B;AAC9B,UAAM,MAAM,MAAM,KAAK,OAAO,EAAE;AAAA,MAC9B,EAAE,KAAK,GAAU;AAAA,MACjB,EAAE,SAAS,SAAS,QAAQ;AAAA,IAC9B;AACA,WAAQ,OAAwB;AAAA,EAClC;AAAA,EAEA,MAAM,QACJ,QACA,SAC8B;AAC9B,UAAM,MAAM,MAAM,KAAK,OAAO,EAAE,QAAQ,QAAQ;AAAA,MAC9C,SAAS,SAAS;AAAA,IACpB,CAAC;AACD,WAAQ,OAAwB;AAAA,EAClC;AAAA,EAEA,KAAK,SAA2B,CAAC,GAAwB;AACvD,WAAO,IAAI,MAAoB,KAAK,OAAO,GAAU,MAAa;AAAA,EACpE;AAAA,EAEA,MAAM,WACJ,IACA,QACA,SACkB;AAClB,UAAM,kBAAkB,KAAK,WAAW,aACpC,EAAE,MAAM,EAAE,WAAW,oBAAI,KAAK,EAAE,GAAG,GAAG,OAAO,IAC7C;AACJ,UAAM,SAAS,MAAM,KAAK,OAAO,EAAE;AAAA,MACjC,EAAE,KAAK,GAAU;AAAA,MACjB;AAAA,MACA,EAAE,SAAS,SAAS,QAAQ;AAAA,IAC9B;AACA,WAAO,OAAO,eAAe;AAAA,EAC/B;AAAA,EAEA,MAAM,kBACJ,IACA,QACA,SAC8B;AAC9B,UAAM,kBAAkB,KAAK,WAAW,aACpC,EAAE,MAAM,EAAE,WAAW,oBAAI,KAAK,EAAE,GAAG,GAAG,OAAO,IAC7C;AACJ,UAAM,SAAS,MAAM,KAAK,OAAO,EAAE;AAAA,MACjC,EAAE,KAAK,GAAU;AAAA,MACjB;AAAA,MACA;AAAA,QACE,gBAAgB,SAAS,YAAY,UAAU;AAAA,QAC/C,SAAS,SAAS;AAAA,MACpB;AAAA,IACF;AACA,WAAQ,UAA2B;AAAA,EACrC;AAAA,EAEA,MAAM,WACJ,QACA,QACA,SACiB;AACjB,UAAM,SAAS,MAAM,KAAK,OAAO,EAAE,WAAW,QAAQ,QAAe;AAAA,MACnE,SAAS,SAAS;AAAA,IACpB,CAAC;AACD,WAAO,OAAO;AAAA,EAChB;AAAA,EAEA,MAAM,WAAW,IAAY,SAA0C;AACrE,UAAM,SAAS,MAAM,KAAK,OAAO,EAAE;AAAA,MACjC,EAAE,KAAK,GAAU;AAAA,MACjB,EAAE,SAAS,SAAS,QAAQ;AAAA,IAC9B;AACA,WAAO,OAAO,eAAe;AAAA,EAC/B;AAAA,EAEA,MAAM,WACJ,QACA,SACiB;AACjB,UAAM,SAAS,MAAM,KAAK,OAAO,EAAE,WAAW,QAAQ;AAAA,MACpD,SAAS,SAAS;AAAA,IACpB,CAAC;AACD,WAAO,OAAO;AAAA,EAChB;AAAA,EAEA,MAAM,MACJ,SAA2B,CAAC,GAC5B,SACiB;AACjB,WAAO,KAAK,OAAO,EAAE,eAAe,QAAQ;AAAA,MAC1C,SAAS,SAAS;AAAA,IACpB,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,OACJ,QACA,SACkB;AAClB,UAAM,MAAM,MAAM,KAAK,OAAO,EAAE,QAAQ,QAAQ;AAAA,MAC9C,YAAY,EAAE,KAAK,EAAE;AAAA,MACrB,SAAS,SAAS;AAAA,IACpB,CAAC;AACD,WAAO,QAAQ;AAAA,EACjB;AAAA,EAEA,MAAM,KACJ,YACA,SACA;AACA,WAAO,KAAK,OAAO,EAAE,UAAU,YAAY,OAAO;AAAA,EACpD;AAAA,EAEA,MAAM,UAAU,UAA2C;AACzD,WAAO,KAAK,OAAO,EAAE,UAAU,QAAQ,EAAE,QAAQ;AAAA,EACnD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,IACE,UACA,SACA,YACqB;AACrB,UAAM,aAAa,GAAG,KAAK,cAAc,KAAK,OAAO;AACrD,WAAO,IAAI;AAAA,MACT,KAAK,OAAO,EAAE,SAAS,KAAK,MAAO,KAAK;AAAA,MACxC;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AACF;AAOO,IAAM,gBAAN,MAAyC;AAAA,EACtC;AAAA,EACA;AAAA,EACA;AAAA,EAER,YACE,IACA,gBACA,UACA,YACA;AACA,SAAK,aAAa,GAAG,WAAW,cAAc;AAC9C,SAAK,WAAW;AAChB,SAAK,aAAa;AAAA,EACpB;AAAA,EAEA,MAAM,OACJ,MACA,SACc;AACd,QAAI;AACJ,QAAI,KAAK,YAAY;AACnB,kBAAY,KAAK,WAAW,OAAO,MAAM,IAAI;AAAA,IAC/C,OAAO;AACL,kBAAY;AAAA,IACd;AACA,UAAM,KAAK,KAAK,OAAO,oBAAAA,QAAO,WAAW;AACzC,UAAM,MAAM,EAAE,GAAG,WAAW,KAAK,IAAI,WAAW,KAAK,SAAS;AAC9D,UAAM,KAAK,WAAW,UAAU,KAAK,EAAE,SAAS,SAAS,QAAQ,CAAC;AAClE,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,SAAS,IAAY,SAAsC;AAC/D,WAAO,KAAK,WAAW;AAAA,MACrB,EAAE,KAAK,IAAW,WAAW,KAAK,SAAS;AAAA,MAC3C,EAAE,SAAS,SAAS,QAAQ;AAAA,IAC9B;AAAA,EACF;AAAA,EAEA,MAAM,QAAQ,SAA2B,CAAC,GAAG,SAAsC;AACjF,WAAO,KAAK,WAAW;AAAA,MACrB,EAAE,GAAG,QAAQ,WAAW,KAAK,SAAS;AAAA,MACtC,EAAE,SAAS,SAAS,QAAQ;AAAA,IAC9B;AAAA,EACF;AAAA,EAEA,KAAK,SAA2B,CAAC,GAAe;AAC9C,WAAO,IAAI,MAAM,KAAK,YAAmB;AAAA,MACvC,GAAG;AAAA,MACH,WAAW,KAAK;AAAA,IAClB,CAAQ;AAAA,EACV;AAAA,EAEA,MAAM,WACJ,IACA,QACA,SACkB;AAClB,UAAM,SAAS,MAAM,KAAK,WAAW;AAAA,MACnC,EAAE,KAAK,IAAW,WAAW,KAAK,SAAS;AAAA,MAC3C;AAAA,MACA,EAAE,SAAS,SAAS,QAAQ;AAAA,IAC9B;AACA,WAAO,OAAO,eAAe;AAAA,EAC/B;AAAA,EAEA,MAAM,WAAW,IAAY,SAA0C;AACrE,UAAM,SAAS,MAAM,KAAK,WAAW;AAAA,MACnC,EAAE,KAAK,IAAW,WAAW,KAAK,SAAS;AAAA,MAC3C,EAAE,SAAS,SAAS,QAAQ;AAAA,IAC9B;AACA,WAAO,OAAO,eAAe;AAAA,EAC/B;AAAA,EAEA,MAAM,MAAM,SAA2B,CAAC,GAAG,SAAyC;AAClF,WAAO,KAAK,WAAW;AAAA,MACrB,EAAE,GAAG,QAAQ,WAAW,KAAK,SAAS;AAAA,MACtC,EAAE,SAAS,SAAS,QAAQ;AAAA,IAC9B;AAAA,EACF;AACF;AAGA,IAAM,gBAA8B,CAAC;AAE9B,SAAS,MACd,gBACA,YACU;AACV,QAAM,IAAI,IAAI,MAAS,gBAAgB,UAAU;AACjD,gBAAc,KAAK,CAAC;AACpB,SAAO;AACT;AAEO,SAAS,mBAAiC;AAC/C,SAAO;AACT;;;ACzUA,eAAsB,eACpB,QACA,IACY;AACZ,QAAM,UAAU,OAAO,aAAa;AACpC,MAAI;AACF,QAAI;AACJ,UAAM,QAAQ,gBAAgB,YAAY;AACxC,eAAS,MAAM,GAAG,OAAO;AAAA,IAC3B,CAAC;AACD,WAAO;AAAA,EACT,UAAE;AACA,UAAM,QAAQ,WAAW;AAAA,EAC3B;AACF;;;ACfA,IAAAC,sBAAmB;AAOnB,IAAM,oBAAoB,IAAI,KAAK;AACnC,IAAM,yBAAyB,KAAK;AAGpC,IAAM,aAAa,oBAAI,IAAoB;AAE3C,YAAY,MAAM;AAChB,QAAM,SAAS,KAAK,IAAI,IAAI,oBAAoB;AAChD,aAAW,CAAC,OAAO,SAAS,KAAK,YAAY;AAC3C,QAAI,YAAY,QAAQ;AACtB,iBAAW,OAAO,KAAK;AAAA,IACzB;AAAA,EACF;AACF,GAAG,sBAAsB,EAAE,MAAM;AAEjC,SAAS,iBACP,QACA,QACA,MACA,WACA,OACA,MACQ;AACR,QAAM,WAAW,OACb,oBAAAC,QAAO,WAAW,QAAQ,EAAE,OAAO,IAAI,EAAE,OAAO,KAAK,IACrD;AACJ,QAAM,UAAU,CAAC,OAAO,YAAY,GAAG,MAAM,WAAW,OAAO,QAAQ,EAAE;AAAA,IACvE;AAAA,EACF;AACA,SAAO,oBAAAA,QAAO,WAAW,UAAU,MAAM,EAAE,OAAO,OAAO,EAAE,OAAO,KAAK;AACzE;AAEO,SAAS,wBAAwB,QAAuB;AAC7D,QAAM,EAAE,WAAW,oBAAoB,kBAAkB,IAAI;AAE7D,SAAO,CAAC,KAAc,KAAe,SAA6B;AAChE,UAAM,YAAY,IAAI,QAAQ,qBAAqB;AACnD,UAAM,QAAQ,IAAI,QAAQ,iBAAiB;AAC3C,UAAM,YAAY,IAAI,QAAQ,qBAAqB;AAGnD,QAAI,CAAC,aAAa,CAAC,SAAS,CAAC,WAAW;AACtC,UAAI,OAAO,GAAG,EAAE,KAAK;AAAA,QACnB,SAAS;AAAA,QACT,OAAO;AAAA,MACT,CAAC;AACD;AAAA,IACF;AAGA,UAAM,KAAK,OAAO,SAAS;AAC3B,QAAI,OAAO,MAAM,EAAE,GAAG;AACpB,UAAI,OAAO,GAAG,EAAE,KAAK;AAAA,QACnB,SAAS;AAAA,QACT,OAAO;AAAA,MACT,CAAC;AACD;AAAA,IACF;AACA,UAAM,MAAM,KAAK,IAAI;AACrB,QAAI,KAAK,IAAI,MAAM,EAAE,IAAI,mBAAmB;AAC1C,UAAI,OAAO,GAAG,EAAE,KAAK;AAAA,QACnB,SAAS;AAAA,QACT,OAAO;AAAA,MACT,CAAC;AACD;AAAA,IACF;AAGA,QAAI,WAAW,IAAI,KAAK,GAAG;AACzB,UAAI,OAAO,GAAG,EAAE,KAAK;AAAA,QACnB,SAAS;AAAA,QACT,OAAO;AAAA,MACT,CAAC;AACD;AAAA,IACF;AAGA,UAAM,UACJ,IAAI,QAAQ,OAAO,KAAK,IAAI,IAAI,EAAE,SAAS,IACvC,KAAK,UAAU,IAAI,IAAI,IACvB;AAEN,UAAM,oBAAoB;AAAA,MACxB;AAAA,MACA,IAAI;AAAA,MACJ,IAAI,eAAe,IAAI;AAAA,MACvB;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAEA,UAAM,YAAY,OAAO,KAAK,WAAW,KAAK;AAC9C,UAAM,iBAAiB,OAAO,KAAK,mBAAmB,KAAK;AAE3D,QACE,UAAU,WAAW,eAAe,UACpC,CAAC,oBAAAA,QAAO,gBAAgB,WAAW,cAAc,GACjD;AACA,UAAI,OAAO,GAAG,EAAE,KAAK;AAAA,QACnB,SAAS;AAAA,QACT,OAAO;AAAA,MACT,CAAC;AACD;AAAA,IACF;AAGA,eAAW,IAAI,OAAO,EAAE;AAExB,SAAK;AAAA,EACP;AACF;;;ACxGA,IAAM,mBAAmB,KAAK;AAEvB,SAAS,gBAAgB,SAA0B,CAAC,GAAG;AAC5D,QAAM;AAAA,IACJ,WAAW;AAAA,IACX,cAAc;AAAA,IACd,eAAe;AAAA,IACf,UAAU;AAAA,EACZ,IAAI;AAEJ,QAAM,QAAQ,oBAAI,IAAyB;AAG3C,QAAM,UAAU,YAAY,MAAM;AAChC,UAAM,MAAM,KAAK,IAAI;AACrB,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO;AAChC,UAAI,MAAM,WAAW,KAAK;AACxB,cAAM,OAAO,GAAG;AAAA,MAClB;AAAA,IACF;AAAA,EACF,GAAG,gBAAgB;AACnB,UAAQ,MAAM;AAEd,SAAO,CAAC,KAAc,KAAe,SAA6B;AAChE,UAAM,MAAM,aAAa,GAAG;AAC5B,UAAM,MAAM,KAAK,IAAI;AACrB,QAAI,QAAQ,MAAM,IAAI,GAAG;AAEzB,QAAI,CAAC,SAAS,MAAM,WAAW,KAAK;AAClC,cAAQ,EAAE,OAAO,GAAG,SAAS,MAAM,SAAS;AAC5C,YAAM,IAAI,KAAK,KAAK;AAAA,IACtB;AAEA,UAAM;AAGN,UAAM,YAAY,KAAK,IAAI,GAAG,cAAc,MAAM,KAAK;AACvD,QAAI,UAAU,qBAAqB,WAAW;AAC9C,QAAI,UAAU,yBAAyB,SAAS;AAChD,QAAI,UAAU,qBAAqB,KAAK,KAAK,MAAM,UAAU,GAAI,CAAC;AAElE,QAAI,MAAM,QAAQ,aAAa;AAC7B,YAAM,aAAa,KAAK,MAAM,MAAM,UAAU,OAAO,GAAI;AACzD,UAAI,UAAU,eAAe,UAAU;AACvC,UAAI,OAAO,GAAG,EAAE,KAAK;AAAA,QACnB,SAAS;AAAA,QACT,OAAO;AAAA,QACP;AAAA,MACF,CAAC;AACD;AAAA,IACF;AAEA,SAAK;AAAA,EACP;AACF;AAEA,SAAS,oBAAoB,KAAsB;AACjD,QAAM,KACH,IAAI,QAAQ,iBAAiB,GAAc,MAAM,GAAG,EAAE,CAAC,GAAG,KAAK,KAChE,IAAI,QAAQ,iBACZ;AACF,QAAM,WAAY,IAAY,MAAM,YAAY;AAChD,SAAO,GAAG,EAAE,IAAI,QAAQ;AAC1B;;;AC7EA,IAAAC,kBAAoD;AAGpD,IAAAC,sBAAmB;AAYnB,IAAM,kBAAkB,oBAAI,IAAI;AAAA,EAC9B;AAAA,EAAQ;AAAA,EAAU;AAAA,EAAQ;AAAA,EAAS;AAAA,EACnC;AAAA,EAAa;AAAA,EAAQ;AAAA,EAAQ;AAAA,EAAQ;AAAA,EACrC;AAAA,EAAgB;AAClB,CAAC;AAED,IAAM,cAAc,oBAAI,IAAI;AAAA,EAC1B;AAAA,EAAU;AAAA,EAAa;AAAA,EAAgB;AAAA,EACvC;AAAA,EAAe;AACjB,CAAC;AAED,SAAS,eAAe,KAAc,QAAQ,GAA4B;AACxE,MAAI,QAAQ,GAAI,OAAM,IAAI,MAAM,0BAA0B;AAC1D,MAAI,QAAQ,QAAQ,QAAQ,OAAW,QAAO,CAAC;AAC/C,MAAI,OAAO,QAAQ,YAAY,MAAM,QAAQ,GAAG,EAAG,OAAM,IAAI,MAAM,iBAAiB;AAEpF,QAAM,SAAkC,CAAC;AACzC,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,GAA8B,GAAG;AACzE,QAAI,YAAY,IAAI,GAAG,EAAG,OAAM,IAAI,MAAM,aAAa,GAAG,kBAAkB;AAC5E,QAAI,UAAU,QAAQ,OAAO,UAAU,YAAY,CAAC,MAAM,QAAQ,KAAK,KAAK,EAAE,iBAAiB,OAAO;AACpG,aAAO,GAAG,IAAI,eAAe,OAAO,QAAQ,CAAC;AAAA,IAC/C,OAAO;AACL,aAAO,GAAG,IAAI;AAAA,IAChB;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,eAAe,KAAuC;AAC7D,MAAI,CAAC,OAAO,OAAO,QAAQ,SAAU,OAAM,IAAI,MAAM,0BAA0B;AAC/E,aAAW,OAAO,OAAO,KAAK,GAA8B,GAAG;AAC7D,QAAI,IAAI,WAAW,GAAG,KAAK,CAAC,gBAAgB,IAAI,GAAG,GAAG;AACpD,YAAM,IAAI,MAAM,oBAAoB,GAAG,kBAAkB;AAAA,IAC3D;AAAA,EACF;AACA,SAAO,eAAe,GAAG;AAC3B;AAEA,SAAS,MAAM,KAAc,MAAsB;AACjD,QAAM,MAAM,IAAI,OAAO,IAAI;AAC3B,SAAO,MAAM,QAAQ,GAAG,IAAI,IAAI,CAAC,IAAM,OAAO;AAChD;AAEO,SAAS,iBACdC,QACA,UAAuB,CAAC,GAChB;AACR,QAAM;AAAA,IACJ,cAAc;AAAA,IACd,cAAc;AAAA,IACd,cAAc;AAAA,IACd,WAAW;AAAA,IACX,eAAe;AAAA,IACf;AAAA,EACF,IAAI;AAEJ,QAAM,aAAS,wBAAO;AAGtB,SAAO,IAAI,KAAK,OAAO,KAAc,QAAiC;AACpE,QAAI;AACF,YAAM,YAAY,IAAI,MAAM;AAC5B,YAAM,UAAU,IAAI,MAAM;AAC1B,YAAM,WAAW,IAAI,MAAM;AAC3B,YAAM,UAAU,IAAI,MAAM;AAC1B,YAAM,SAAS,IAAI,MAAM;AAEzB,UAAI,SAAS,CAAC;AACd,UAAI,WAAW;AACb,iBAAS,eAAe,KAAK,MAAM,SAAS,CAAC;AAAA,MAC/C;AAEA,YAAM,OAAO,UAAU,KAAK,MAAM,OAAO,IAAI;AAC7C,YAAM,QAAQ,KAAK,IAAI,OAAO,QAAQ,KAAK,cAAc,QAAQ;AACjE,YAAM,OAAO,OAAO,OAAO,KAAK;AAEhC,UAAI,QAAQA,OAAM,KAAK,MAAM;AAC7B,UAAI,KAAM,SAAQ,MAAM,KAAK,IAAI;AACjC,UAAI,UAAU,MAAM;AAElB,cAAM,YAAY,OAAO,KAAK,IAAI,EAAE,CAAC;AACrC,cAAM,cAAc,OAAO,MAAM,OAAO,MAAM,CAAC,IAAI,SAAS,OAAO,MAAM;AACzE,gBAAQ,MAAM,WAAW,EAAE,CAAC,SAAS,GAAG,YAAY,CAAC;AAAA,MACvD;AACA,UAAI,KAAM,SAAQ,MAAM,KAAK,IAAI;AACjC,cAAQ,MAAM,MAAM,KAAK;AAEzB,YAAM,OAAO,MAAM,MAAM,KAAK;AAC9B,UAAI,aAAsB;AAC1B,UAAI,KAAK,WAAW,SAAS,MAAM;AACjC,cAAM,YAAY,OAAO,KAAK,IAAI,EAAE,CAAC;AACrC,qBAAc,KAAK,KAAK,SAAS,CAAC,IAAY,SAAS,KAAK;AAAA,MAC9D;AAEA,UAAI,KAAK,EAAE,SAAS,MAAM,MAAM,MAAM,WAAW,CAAC;AAAA,IACpD,SAAS,OAAY;AACnB,UAAI,OAAO,GAAG,EAAE,KAAK,EAAE,SAAS,OAAO,OAAO,MAAM,QAAQ,CAAC;AAAA,IAC/D;AAAA,EACF,CAAC;AAGD,SAAO,IAAI,QAAQ,OAAO,KAAc,QAAiC;AACvE,UAAM,KAAK,MAAM,KAAK,IAAI;AAC1B,UAAM,MAAM,MAAMA,OAAM,SAAS,EAAE;AACnC,QAAI,CAAC,KAAK;AACR,UAAI,OAAO,GAAG,EAAE,KAAK,EAAE,SAAS,OAAO,OAAO,YAAY,CAAC;AAC3D;AAAA,IACF;AACA,QAAI,KAAK,EAAE,SAAS,MAAM,MAAM,IAAI,CAAC;AAAA,EACvC,CAAC;AAGD,SAAO,KAAK,KAAK,OAAO,KAAc,QAAiC;AACrE,QAAI,CAAC,aAAa;AAChB,UAAI,OAAO,GAAG,EAAE,KAAK,EAAE,SAAS,OAAO,OAAO,qBAAqB,CAAC;AACpE;AAAA,IACF;AACA,QAAI;AACF,YAAM,OAAO,IAAI;AACjB,UAAI,CAAC,KAAK,IAAK,MAAK,MAAM,oBAAAC,QAAO,WAAW;AAC5C,YAAM,MAAM,MAAMD,OAAM,OAAO,IAAI;AACnC,UAAI,OAAO,GAAG,EAAE,KAAK,EAAE,SAAS,MAAM,MAAM,IAAI,CAAC;AAAA,IACnD,SAAS,OAAY;AACnB,UAAI,OAAO,GAAG,EAAE,KAAK,EAAE,SAAS,OAAO,OAAO,MAAM,QAAQ,CAAC;AAAA,IAC/D;AAAA,EACF,CAAC;AAGD,SAAO,KAAK,UAAU,OAAO,KAAc,QAAiC;AAC1E,QAAI;AACF,YAAM,SAAS,IAAI,KAAK,SAAS,eAAe,IAAI,KAAK,MAAM,IAAI,CAAC;AACpE,YAAM,QAAQ,MAAMA,OAAM,MAAM,MAAM;AACtC,UAAI,KAAK,EAAE,SAAS,MAAM,MAAM,CAAC;AAAA,IACnC,SAAS,OAAY;AACnB,UAAI,OAAO,GAAG,EAAE,KAAK,EAAE,SAAS,OAAO,OAAO,MAAM,QAAQ,CAAC;AAAA,IAC/D;AAAA,EACF,CAAC;AAGD,SAAO,MAAM,QAAQ,OAAO,KAAc,QAAiC;AACzE,QAAI,CAAC,aAAa;AAChB,UAAI,OAAO,GAAG,EAAE,KAAK,EAAE,SAAS,OAAO,OAAO,qBAAqB,CAAC;AACpE;AAAA,IACF;AACA,UAAM,KAAK,MAAM,KAAK,IAAI;AAC1B,QAAI;AACF,YAAM,SAAS,eAAe,IAAI,KAAK,UAAU,IAAI,IAAI;AACzD,YAAM,UAAU,MAAMA,OAAM,WAAW,IAAI,MAAM;AACjD,UAAI,CAAC,SAAS;AACZ,YAAI,OAAO,GAAG,EAAE,KAAK,EAAE,SAAS,OAAO,OAAO,YAAY,CAAC;AAC3D;AAAA,MACF;AACA,YAAM,MAAM,MAAMA,OAAM,SAAS,EAAE;AACnC,UAAI,KAAK,EAAE,SAAS,MAAM,MAAM,IAAI,CAAC;AAAA,IACvC,SAAS,OAAY;AACnB,UAAI,OAAO,GAAG,EAAE,KAAK,EAAE,SAAS,OAAO,OAAO,MAAM,QAAQ,CAAC;AAAA,IAC/D;AAAA,EACF,CAAC;AAGD,SAAO,OAAO,QAAQ,OAAO,KAAc,QAAiC;AAC1E,UAAM,KAAK,MAAM,KAAK,IAAI;AAE1B,QAAI,OAAO,gBAAgB,YAAY;AACrC,YAAM,MAAM,MAAMA,OAAM,SAAS,EAAE;AACnC,UAAI,CAAC,KAAK;AACR,YAAI,OAAO,GAAG,EAAE,KAAK,EAAE,SAAS,OAAO,OAAO,YAAY,CAAC;AAC3D;AAAA,MACF;AACA,UAAI,CAAC,YAAY,KAAK,GAA8B,GAAG;AACrD,YAAI,OAAO,GAAG,EAAE,KAAK,EAAE,SAAS,OAAO,OAAO,qBAAqB,CAAC;AACpE;AAAA,MACF;AAAA,IACF,WAAW,CAAC,aAAa;AACvB,UAAI,OAAO,GAAG,EAAE,KAAK,EAAE,SAAS,OAAO,OAAO,qBAAqB,CAAC;AACpE;AAAA,IACF;AAEA,UAAM,UAAU,MAAMA,OAAM,WAAW,EAAE;AACzC,QAAI,CAAC,SAAS;AACZ,UAAI,OAAO,GAAG,EAAE,KAAK,EAAE,SAAS,OAAO,OAAO,YAAY,CAAC;AAC3D;AAAA,IACF;AACA,QAAI,KAAK,EAAE,SAAS,KAAK,CAAC;AAAA,EAC5B,CAAC;AAED,SAAO;AACT;;;AC5KO,IAAM,gBAAN,MAAoB;AAAA,EA0CzB,YAAoB,QAA6B;AAA7B;AAClB,SAAK,aAAa,IAAI,kBAAkB,OAAO,UAAU,OAAO,MAAM;AACtE,SAAK,aAAa,OAAO;AACzB,SAAK,MAAM,IAAI,WAAW;AAAA,MACxB,QAAQ,OAAO;AAAA,MACf,eAAe,OAAO;AAAA,MACtB,gBAAgB,OAAO,kBAAkB;AAAA,MACzC,iBAAiB,OAAO,mBAAmB;AAAA,IAC7C,CAAC;AAAA,EACH;AAAA,EAlDQ;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACS,aAAa,uBAAO,gBAAgB;AAAA,EAC7C;AAAA,EAER;AAAA,EA0BA;AAAA,EAkBA,MAAM,UAAyB;AAC7B,SAAK,MAAM,MAAM,KAAK,WAAW,QAAQ;AACzC,SAAK,aAAa,IAAI,WAAW,KAAK,GAAG;AACzC,SAAK,UAAU,YAAY,KAAK,GAAG;AAGnC,eAAW,KAAK,iBAAiB,GAAG;AAClC,QAAE,MAAM,KAAK,KAAK,KAAK,UAAU;AACjC,YAAM,EAAE,eAAe;AAAA,IACzB;AAGA,UAAM,mBAAmB,KAAK,IAAI,WAAW,gBAAgB;AAC7D,UAAM,iBAAiB,YAAY,EAAE,WAAW,EAAE,GAAG,EAAE,QAAQ,KAAK,CAAC;AACrE,UAAM,iBAAiB,YAAY,EAAE,UAAU,EAAE,CAAC;AAClD,UAAM,iBAAiB;AAAA,MACrB,EAAE,WAAW,EAAE;AAAA,MACf,EAAE,oBAAoB,EAAE;AAAA,IAC1B;AAGA,SAAK,OAAO;AAAA,MACV,MAAM,CAAC,SAAS,WAAW,KAAK,IAAI,KAAK,SAAS,MAAM;AAAA,MACxD,QAAQ,CAAC,UAAU,KAAK,IAAI,OAAO,KAAK;AAAA,MACxC,SAAS,OAAO,iBAAiB;AAC/B,cAAM,UAAU,MAAM,KAAK,IAAI,cAAc,YAAY;AACzD,cAAM,WAAW,QAAQ;AACzB,cAAM,SAAS,MAAM,KAAK,IAAI,KAAK,QAAQ;AAC3C,eAAO;AAAA,MACT;AAAA,MACA,OAAO,CAAC,YAAY,KAAK,QAAQ,OAAO;AAAA,MACxC,QAAQ,CAAC,WACP,iBAAiB,KAAK,KAAK,KAAK,YAAY,KAAK,KAAK,MAAM;AAAA,MAC9D,KAAK,CAAC,UAAU,WAAW,KAAK,WAAW,IAAI,UAAU,MAAM;AAAA,MAC/D,OAAO,CAAC,aAAa,KAAK,WAAW,MAAM,QAAQ;AAAA,MACnD,UAAU,CAAC,aAAa,KAAK,WAAW,SAAS,QAAQ;AAAA,IAC3D;AAGA,SAAK,KAAK;AAAA,MACR,aAAa,CAAI,OACf,eAAe,KAAK,WAAW,UAAU,GAAG,EAAE;AAAA,MAChD,OAAO,MAAM,KAAK;AAAA,IACpB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,QACE,WAC2D;AAC3D,UAAM,SAAS,WAAW,aAAa,KAAK;AAC5C,QAAI,CAAC,QAAQ;AACX,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AACA,WAAO,wBAAwB;AAAA,MAC7B,WAAW;AAAA,MACX,mBAAmB,WAAW;AAAA,IAChC,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,UAAU,QAA0B;AAClC,WAAO,gBAAgB,MAAM;AAAA,EAC/B;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,KAA0B,GAAa,SAAuB;AAC5D,WAAO,iBAAiB,GAAG,OAAO;AAAA,EACpC;AAAA,EAEA,MAAM,aAA4B;AAChC,UAAM,KAAK,WAAW,WAAW;AAAA,EACnC;AACF;;;ACnKO,SAAS,SAA8B,QAAW;AACvD,SAAO,CAAC,KAAc,KAAe,SAA6B;AAChE,UAAM,SAAS,OAAO,UAAU,IAAI,IAAI;AACxC,QAAI,CAAC,OAAO,SAAS;AACnB,UAAI,OAAO,GAAG,EAAE,KAAK;AAAA,QACnB,SAAS;AAAA,QACT,OAAO;AAAA,QACP,SAAS,OAAO,MAAM;AAAA,MACxB,CAAC;AACD;AAAA,IACF;AACA,QAAI,OAAO,OAAO;AAClB,SAAK;AAAA,EACP;AACF;;;AbNA,IAAAE,iBAWO;","names":["crypto","import_shared","import_node_crypto","crypto","import_node_crypto","crypto","import_express","import_node_crypto","model","crypto","import_shared"]}
|
package/dist/index.js
CHANGED
|
@@ -702,10 +702,9 @@ function createSigningMiddleware(config) {
|
|
|
702
702
|
nonce,
|
|
703
703
|
rawBody
|
|
704
704
|
);
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
)) {
|
|
705
|
+
const sigBuffer = Buffer.from(signature, "hex");
|
|
706
|
+
const expectedBuffer = Buffer.from(expectedSignature, "hex");
|
|
707
|
+
if (sigBuffer.length !== expectedBuffer.length || !crypto3.timingSafeEqual(sigBuffer, expectedBuffer)) {
|
|
709
708
|
res.status(401).json({
|
|
710
709
|
success: false,
|
|
711
710
|
error: "Invalid signature"
|
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 const expectedSignature = computeSignature(\n appSecret,\n req.method,\n req.originalUrl || req.url,\n timestamp,\n nonce,\n rawBody,\n );\n\n if (\n !crypto.timingSafeEqual(\n Buffer.from(signature, \"hex\"),\n Buffer.from(expectedSignature, \"hex\"),\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\";\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 const expectedSignature = computeSignature(\n appSecret,\n req.method,\n req.originalUrl || 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 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"]}
|