UNPKG

connect-surreal

Version:
1 lines 13.2 kB
{"version":3,"file":"connect-surreal.cjs","sources":["../src/main.ts"],"sourcesContent":["import { type SessionData, Store } from \"express-session\";\nimport { RecordId, Surreal, Table } from \"surrealdb\";\n\n\nexport type SurrealDBStoreOptions = {\n /**\n * URL used to connect to SurrealDB\n * e.g. http://127.0.0.1:8000/rpc\n */\n url: string,\n /**\n * Table to use for storing the sessions\n * @default `user_sessions`\n */\n tableName: string,\n\n /**\n * Options for the initial SurrealDB connection.\n * You should set the namespace and database in this object.\n */\n connectionOpts: Parameters<Surreal['connect']>[1];\n /**\n * Sign-in options\n * @deprecated Use SurrealDBStoreOptions.connectionOpts instead (fixes reconnection issues). This will be removed in a future release.\n */\n signinOpts?: Parameters<Surreal['signin']>[0];\n\n /**\n * Automatically sweep and remove expired sessions periodically.\n * @default false\n */\n autoSweepExpired?: boolean;\n\n /**\n * Interval in milliseconds to sweep for expired sessions.\n * @default 600000 (10 minutes)\n */\n autoSweepIntervalMs?: number;\n\n\n /**\n * Use options (Select namespace, database)\n * @optional\n * @deprecated Use SurrealDBStoreOptions.connectionOpts instead (fixes reconnection issues). This will be removed in a future release.\n */\n useOpts?: Parameters<Surreal['use']>[0];\n /**\n * Optional surreal db instance override.\n */\n surreal?: Surreal,\n\n /**\n * Optional logger\n */\n logger?: {\n error?: (any) => void,\n info?: (any) => void,\n debug?: (any) => void,\n };\n\n /**\n * Custom setter function for storing session data. If provided, this function will be used instead of the default upsert logic.\n */\n customSetter?: (db: Surreal, sessionId: string, session: SessionData) => Promise<any>;\n\n /**\n * Custom getter function for retrieving session data. If provided, this function will be used instead of the default select logic.\n */\n customGetter?: (db: Surreal, sessionId: string) => Promise<SessionData | null>;\n};\n\nexport class SurrealDBStore extends Store {\n\n private db: Surreal;\n private tableName: string;\n private lastConnectionAttempt = 0;\n\n // Has the store ever successfully connected\n private hasConnected = false;\n // Is currently connected\n private isConnected = false;\n\n constructor(private readonly options: SurrealDBStoreOptions) {\n super();\n\n this.db = options.surreal ?? new Surreal();\n\n this.tableName = options.tableName ?? 'user_session';\n\n this._connect()\n .then(async () => {\n this.hasConnected = true;\n options.logger?.info?.(\"SurrealDBStore: Creating schema...\");\n try {\n await this.db.query(`DEFINE TABLE OVERWRITE ${this.tableName} COMMENT 'Automatically created by express-session SurrealDB Store'`);\n options.logger?.info?.(\"SurrealDBStore: Schema created successfully.\");\n }\n catch (err) {\n options.logger?.error?.(\"SurrealDBStore: Failed to create schema: \" + err.message);\n }\n });\n\n\n if (this.options.autoSweepExpired) {\n const intervalMs = this.options.autoSweepIntervalMs ?? 10 * 60 * 1000;\n setInterval(() => {\n this.db.query(\n `DELETE type::table($table) WHERE expires < time::now()`,\n { table: this.tableName }\n ).then(() => {\n options.logger?.info?.(`SurrealDBStore: Swept expired sessions from table ${this.tableName}`);\n }).catch(err => {\n options.logger?.error?.(`SurrealDBStore: Failed to sweep expired sessions: ${err.message}`);\n });\n }, intervalMs);\n }\n }\n\n /**\n * Perform the initial connection to the database. This also sets the scope of our connection.\n */\n private async _connect() {\n this.options.logger?.info?.(\"SurrealDBStore: Connecting to SurrealDB...\");\n const connectionOpts: Parameters<Surreal['connect']>[1] = {\n namespace: this.options.useOpts?.namespace,\n database: this.options.useOpts?.database,\n authentication: this.options.signinOpts as any,\n ...this.options.connectionOpts,\n };\n\n await this.db.connect(this.options.url, connectionOpts)\n .then(() => {\n this.hasConnected = true;\n this.options.logger?.info?.(\"SurrealDBStore: Connected to SurrealDB.\");\n })\n .catch(err => {\n this.options.logger?.error?.(\"SurrealDBStore: Failed to connect to SurrealDB!\\n\" + err.message + '\\n' + err.stack);\n });\n this.isConnected = true;\n this.hasConnected = true;\n }\n\n /**\n * Get session data by session ID\n */\n get(sessionId: string, cb: Function) {\n const getter = this.options.customGetter\n ? this.options.customGetter(this.db, sessionId)\n : this.db.select(new RecordId(this.tableName, sessionId));\n\n this.options.logger?.debug?.(\"SurrealDBStore: Getting session data for session ID: \" + sessionId);\n getter\n .then((res) => {\n this.options.logger?.debug?.(\"SurrealDBStore: Got session data for session ID: \" + sessionId);\n cb(null, res);\n })\n .catch(err => {\n this.options.logger?.error?.(\"SurrealDBStore: Failed to get session data for session ID: \" + sessionId + \"\\n\" + err.message + '\\n' + err.stack);\n cb(err);\n });\n }\n\n /**\n * Set session data for a given session ID\n */\n set(sessionId: string, session: SessionData, cb: Function) {\n const setter = this.options.customSetter\n ? this.options.customSetter(this.db, sessionId, session)\n : this.db.upsert(new RecordId(this.tableName, sessionId)).content(session as any);\n\n this.options.logger?.debug?.(\"SurrealDBStore: Setting session data for session ID: \" + sessionId);\n setter\n .then((res) => {\n this.options.logger?.debug?.(\"SurrealDBStore: Set session data for session ID: \" + sessionId);\n cb(null, res);\n })\n .catch(err => {\n this.options.logger?.error?.(\"SurrealDBStore: Failed to set session data for session ID: \" + sessionId + \"\\n\" + err.message + '\\n' + err.stack);\n cb(err);\n });\n }\n\n touch(sid: string, session, cb: Function) {\n // TODO: The schema of the table should be automatically\n // generated and should have a TTL on sessions\n this.set(sid, session, cb);\n }\n\n destroy(sessionId: string, cb: Function) {\n this.db.delete(new RecordId(this.tableName, sessionId))\n .then(() => {\n this.options.logger?.debug?.(\"SurrealDBStore: Destroyed session data for session ID: \" + sessionId);\n cb(null);\n })\n .catch(err => {\n // This is a bug with the SurrealDB SDK. It sometimes throws this error when \n // the session is deleted. We should ignore this error and return null.\n if (err.message.includes(\"Expected a single result output when using the ONLY keyword\")) {\n this.options.logger?.debug?.(\"SurrealDBStore: SurrealDB returned a known SDK error when destroying session: \" + sessionId);\n cb(null);\n } else {\n this.options.logger?.error?.(\"SurrealDBStore: Failed to destroy session data for session ID: \" + sessionId + \"\\n\" + err.message + '\\n' + err.stack);\n cb(err);\n }\n });\n }\n\n length(cb: Function) {\n this.db.query(`SELECT count() FROM type::table($table) GROUP ALL`, { 'table': this.tableName })\n .collect()\n .then(([result]) => {\n this.options.logger?.debug?.(\"SurrealDBStore: Got session count: \" + result[0].count);\n cb(result[0].count);\n })\n .catch(err => {\n this.options.logger?.error?.(\"SurrealDBStore: Failed to get session count\\n\" + err.message + '\\n' + err.stack);\n cb(err);\n });\n }\n\n all(cb: Function) {\n this.db.select(new Table(this.tableName))\n .then(([result]) => {\n this.options.logger?.debug?.(\"SurrealDBStore: Got all session data\");\n cb(result);\n })\n .catch(err => {\n this.options.logger?.error?.(\"SurrealDBStore: Failed to get all session data\\n\" + err.message + '\\n' + err.stack);\n cb(err);\n });\n }\n\n clear(cb: Function) {\n this.db.query(`DELETE type::table($table)`, { 'table': this.tableName })\n .then(() => {\n this.options.logger?.debug?.(\"SurrealDBStore: Cleared all session data\");\n cb(null);\n })\n .catch(err => {\n this.options.logger?.error?.(\"SurrealDBStore: Failed to clear all session data\\n\" + err.message + '\\n' + err.stack);\n cb(err);\n });\n }\n}\n"],"names":["SurrealDBStore","Store","options","Surreal","err","intervalMs","connectionOpts","sessionId","cb","getter","RecordId","res","session","setter","sid","result","Table"],"mappings":"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"}