Press n or j to go to the next uncovered block, b, p or k for the previous block.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 | 24x 24x 24x 24x 24x 24x 24x 24x 24x 24x 24x 24x 24x 24x 24x 24x | import * as mongodb from 'mongodb'; import {SessionInterface} from '../types'; import {SessionStorage} from '../session_storage'; import {sessionFromEntries, sessionEntries} from '../session-utils'; import {sanitizeShop} from '../../../utils/shop-validator'; export interface MongoDBSessionStorageOptions { sessionCollectionName: string; } const defaultMongoDBSessionStorageOptions: MongoDBSessionStorageOptions = { sessionCollectionName: 'shopify_sessions', }; export class MongoDBSessionStorage implements SessionStorage { static withCredentials( host: string, dbName: string, username: string, password: string, opts: Partial<MongoDBSessionStorageOptions>, ) { return new MongoDBSessionStorage( new URL( `mongodb://${encodeURIComponent(username)}:${encodeURIComponent( password, )}@${host}/`, ), dbName, opts, ); } public readonly ready: Promise<void>; private options: MongoDBSessionStorageOptions; // `mongodb` has no types for `MongoClient`???! private client: any; constructor( private dbUrl: URL, private dbName: string, opts: Partial<MongoDBSessionStorageOptions> = {}, ) { if (typeof this.dbUrl === 'string') { this.dbUrl = new URL(this.dbUrl); } this.options = {...defaultMongoDBSessionStorageOptions, ...opts}; this.ready = this.init(); } public async storeSession(session: SessionInterface): Promise<boolean> { await this.ready; await this.collection.findOneAndReplace( {id: session.id}, Object.fromEntries(sessionEntries(session)), { upsert: true, }, ); return true; } public async loadSession(id: string): Promise<SessionInterface | undefined> { await this.ready; const result = await this.collection.findOne({id}); return result ? sessionFromEntries(Object.entries(result)) : undefined; } public async deleteSession(id: string): Promise<boolean> { await this.ready; await this.collection.deleteOne({id}); return true; } public async deleteSessions(ids: string[]): Promise<boolean> { await this.ready; await this.collection.deleteMany({id: {$in: ids}}); return true; } public async findSessionsByShop(shop: string): Promise<SessionInterface[]> { await this.ready; const cleanShop = sanitizeShop(shop, true)!; const rawResults = await this.collection.find({shop: cleanShop}).toArray(); if (!rawResults || rawResults?.length === 0) return []; return rawResults.map((rawResult: any) => sessionFromEntries(Object.entries(rawResult)), ); } public async disconnect(): Promise<void> { await this.client.close(); } private get collection() { return this.client .db(this.dbName) .collection(this.options.sessionCollectionName); } private async init() { this.client = new (mongodb as any).MongoClient(this.dbUrl.toString()); await this.client.connect(); await this.client.db().command({ping: 1}); await this.createCollection(); } private async hasSessionCollection(): Promise<boolean> { const collections = await this.client.db().collections(); return collections .map((collection: any) => collection.collectionName) .includes(this.options.sessionCollectionName); } private async createCollection() { const hasSessionCollection = await this.hasSessionCollection(); if (!hasSessionCollection) { await this.client.db().collection(this.options.sessionCollectionName); } } } |