@shopify/shopify-app-session-storage-prisma
Version:
Shopify App Session Storage for Prisma
1 lines • 14 kB
Source Map (JSON)
{"version":3,"file":"prisma.mjs","sources":["../../../src/prisma.ts"],"sourcesContent":["import {Session} from '@shopify/shopify-api';\nimport {SessionStorage} from '@shopify/shopify-app-session-storage';\nimport type {PrismaClient, Session as Row} from '@prisma/client';\nimport {Prisma} from '@prisma/client';\n\ninterface PrismaSessionStorageOptions {\n tableName?: string;\n connectionRetries?: number;\n connectionRetryIntervalMs?: number;\n}\n\nconst UNIQUE_KEY_CONSTRAINT_ERROR_CODE = 'P2002';\n\n// eslint-disable-next-line no-warning-comments\n// TODO: Remove this when all session storages have implemented the isReady method\nexport interface PrismaSessionStorageInterface extends SessionStorage {\n isReady(): Promise<boolean>;\n}\n\nexport class PrismaSessionStorage<\n T extends PrismaClient,\n> implements PrismaSessionStorageInterface {\n private ready: Promise<boolean>;\n private readonly tableName: string = 'session';\n private connectionRetries = 2;\n private connectionRetryIntervalMs = 5000;\n\n constructor(\n private prisma: T,\n {\n tableName,\n connectionRetries,\n connectionRetryIntervalMs,\n }: PrismaSessionStorageOptions = {},\n ) {\n if (tableName) {\n this.tableName = tableName;\n }\n\n if (connectionRetries !== undefined) {\n this.connectionRetries = connectionRetries;\n }\n\n if (connectionRetryIntervalMs !== undefined) {\n this.connectionRetryIntervalMs = connectionRetryIntervalMs;\n }\n\n if (this.getSessionTable() === undefined) {\n throw new Error(`PrismaClient does not have a ${this.tableName} table`);\n }\n\n this.ready = this.pollForTable()\n .then(() => true)\n .catch((cause) => {\n throw new MissingSessionTableError(\n `Prisma ${this.tableName} table does not exist. This could happen for a few reasons, see https://github.com/Shopify/shopify-app-js/tree/main/packages/apps/session-storage/shopify-app-session-storage-prisma#troubleshooting for more information`,\n cause,\n );\n });\n }\n\n public async storeSession(session: Session): Promise<boolean> {\n await this.ensureReady();\n const data = this.sessionToRow(session);\n\n try {\n await this.getSessionTable().upsert({\n where: {id: session.id},\n update: data,\n create: data,\n });\n } catch (error) {\n if (\n error instanceof Prisma.PrismaClientKnownRequestError &&\n error.code === UNIQUE_KEY_CONSTRAINT_ERROR_CODE\n ) {\n console.log(\n 'Caught PrismaClientKnownRequestError P2002 - Unique Key Key Constraint, retrying upsert.',\n );\n await this.getSessionTable().upsert({\n where: {id: session.id},\n update: data,\n create: data,\n });\n return true;\n }\n throw error;\n }\n\n return true;\n }\n\n public async loadSession(id: string): Promise<Session | undefined> {\n await this.ensureReady();\n const row = await this.getSessionTable().findUnique({\n where: {id},\n });\n\n if (!row) {\n return undefined;\n }\n\n return this.rowToSession(row);\n }\n\n public async deleteSession(id: string): Promise<boolean> {\n await this.ensureReady();\n try {\n await this.getSessionTable().delete({where: {id}});\n } catch {\n return true;\n }\n\n return true;\n }\n\n public async deleteSessions(ids: string[]): Promise<boolean> {\n await this.ensureReady();\n await this.getSessionTable().deleteMany({where: {id: {in: ids}}});\n\n return true;\n }\n\n public async findSessionsByShop(shop: string): Promise<Session[]> {\n await this.ensureReady();\n const sessions = await this.getSessionTable().findMany({\n where: {shop},\n take: 25,\n orderBy: [{expires: 'desc'}],\n });\n\n return sessions.map((session) => this.rowToSession(session));\n }\n\n public async isReady(): Promise<boolean> {\n try {\n await this.pollForTable();\n this.ready = Promise.resolve(true);\n } catch (_error) {\n this.ready = Promise.resolve(false);\n }\n return this.ready;\n }\n\n private async ensureReady(): Promise<void> {\n if (!(await this.ready))\n throw new MissingSessionStorageError(\n 'Prisma session storage is not ready. Use the `isReady` method to poll for the table.',\n );\n }\n\n private async pollForTable(): Promise<void> {\n for (let i = 0; i < this.connectionRetries; i++) {\n try {\n await this.getSessionTable().count();\n return;\n } catch (error) {\n console.log(`Error obtaining session table: ${error}`);\n }\n await sleep(this.connectionRetryIntervalMs);\n }\n throw Error(\n `The table \\`${this.tableName}\\` does not exist in the current database.`,\n );\n }\n\n private sessionToRow(session: Session): Row {\n const sessionParams = session.toObject();\n\n return {\n id: session.id,\n shop: session.shop,\n state: session.state,\n isOnline: session.isOnline,\n scope: session.scope || null,\n expires: session.expires || null,\n accessToken: session.accessToken || '',\n userId:\n (sessionParams.onlineAccessInfo?.associated_user\n .id as unknown as bigint) || null,\n firstName:\n sessionParams.onlineAccessInfo?.associated_user.first_name || null,\n lastName:\n sessionParams.onlineAccessInfo?.associated_user.last_name || null,\n email: sessionParams.onlineAccessInfo?.associated_user.email || null,\n accountOwner:\n sessionParams.onlineAccessInfo?.associated_user.account_owner || false,\n locale: sessionParams.onlineAccessInfo?.associated_user.locale || null,\n collaborator:\n sessionParams.onlineAccessInfo?.associated_user.collaborator || false,\n emailVerified:\n sessionParams.onlineAccessInfo?.associated_user.email_verified || false,\n refreshToken: sessionParams.refreshToken || null,\n refreshTokenExpires: sessionParams.refreshTokenExpires || null,\n };\n }\n\n private rowToSession(row: Row): Session {\n const sessionParams: Record<string, boolean | string | number> = {\n id: row.id,\n shop: row.shop,\n state: row.state,\n isOnline: row.isOnline,\n userId: String(row.userId),\n firstName: String(row.firstName),\n lastName: String(row.lastName),\n email: String(row.email),\n locale: String(row.locale),\n };\n\n if (row.accountOwner !== null) {\n sessionParams.accountOwner = row.accountOwner;\n }\n\n if (row.collaborator !== null) {\n sessionParams.collaborator = row.collaborator;\n }\n\n if (row.emailVerified !== null) {\n sessionParams.emailVerified = row.emailVerified;\n }\n\n if (row.expires) {\n sessionParams.expires = row.expires.getTime();\n }\n\n if (row.scope) {\n sessionParams.scope = row.scope;\n }\n\n if (row.accessToken) {\n sessionParams.accessToken = row.accessToken;\n }\n\n if (row.refreshToken) {\n sessionParams.refreshToken = row.refreshToken;\n }\n\n if (row.refreshTokenExpires) {\n sessionParams.refreshTokenExpires = row.refreshTokenExpires.getTime();\n }\n\n return Session.fromPropertyArray(Object.entries(sessionParams), true);\n }\n\n private getSessionTable(): T['session'] {\n return (this.prisma as any)[this.tableName];\n }\n}\n\nexport class MissingSessionTableError extends Error {\n constructor(\n message: string,\n public readonly cause: Error,\n ) {\n super(message);\n }\n}\n\nexport class MissingSessionStorageError extends Error {\n constructor(message: string) {\n super(message);\n }\n}\n\nasync function sleep(ms: number) {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n"],"names":[],"mappings":"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"}