Repository: prisma/prisma
File: packages/cli/src/Studio.ts (TypeScript)

Code before:
      }

      const apiKey = connectionURL.searchParams.get(ACCELERATE_API_KEY_QUERY_PARAMETER)

      if (!apiKey) {
        throw new Error(
          `\`${ACCELERATE_API_KEY_QUERY_PARAMETER}\` query parameter is missing in the provided "prisma+postgres" connection string.`,
        )
      }

      const [, payload] = apiKey.split('.')

      try {
        const decodedPayload = JSON.parse(Buffer.from(payload, 'base64').toString('utf-8'))

        if (
          typeof decodedPayload !== 'object' ||
          decodedPayload === null ||
          Array.isArray(decodedPayload) ||
          !('secure_key' in decodedPayload) ||
          typeof decodedPayload.secure_key !== 'string' ||
          !('tenant_id' in decodedPayload) ||
          typeof decodedPayload.tenant_id !== 'string'
        ) {
          throw new Error('structure mismatch')
        }

        connectionURL.password = decodedPayload.secure_key
        connectionURL.username = decodedPayload.tenant_id
      } catch {
        throw new Error(
          `Invalid/outdated \`${ACCELERATE_API_KEY_QUERY_PARAMETER}\` query parameter in the provided "prisma+postgres" connection string. Please create a new API key and use the new connection string OR use a direct TCP connection string instead.`,
        )
      }

      connectionURL.host = 'db.prisma.io:5432'
      connectionURL.pathname = '/postgres'
      connectionURL.protocol = 'postgres:'
      connectionURL.searchParams.delete(ACCELERATE_API_KEY_QUERY_PARAMETER)
      connectionURL.searchParams.set('sslmode', 'require')

      return await POSTGRES_STUDIO_STUFF.createExecutor(connectionURL.toString(), relativeTo)
    },
    reExportAdapterScript: POSTGRES_STUDIO_STUFF.reExportAdapterScript,
  },
  mysql: {
    async createExecutor(connectionString) {
      const { createPool } = await import('mysql2/promise')

      const pool = createPool(connectionString)


Review comment (suggestion):
suggestion (optional, non-blocking): maybe use zod or effect schema instead (we have both already available in `cli`, for reasons 😬)

Code after:
      const connectionURL = new URL(connectionString)

      if (['localhost', '127.0.0.1', '[::1]'].includes(connectionURL.hostname)) {
        // TODO: support `prisma dev` accelerate URLs.

        throw new Error('The "prisma+postgres" protocol with localhost is not supported in Prisma Studio yet.')
      }

      const apiKey = connectionURL.searchParams.get(ACCELERATE_API_KEY_QUERY_PARAMETER)

      if (!apiKey) {
        throw new Error(
          `\`${ACCELERATE_API_KEY_QUERY_PARAMETER}\` query parameter is missing in the provided "prisma+postgres" connection string.`,
        )
      }

      const [, payload] = apiKey.split('.')

      try {
        const decodedPayload = AccelerateAPIKeyPayloadSchema.parse(
          JSON.parse(Buffer.from(payload, 'base64').toString('utf-8')),
        )

        connectionURL.password = decodedPayload.secure_key
        connectionURL.username = decodedPayload.tenant_id
      } catch {
        throw new Error(
          `Invalid/outdated \`${ACCELERATE_API_KEY_QUERY_PARAMETER}\` query parameter in the provided "prisma+postgres" connection string. Please create a new API key and use the new connection string OR use a direct TCP connection string instead.`,
        )
      }

      connectionURL.host = 'db.prisma.io:5432'
      connectionURL.pathname = '/postgres'
      connectionURL.protocol = 'postgres:'
      connectionURL.searchParams.delete(ACCELERATE_API_KEY_QUERY_PARAMETER)
      connectionURL.searchParams.set('sslmode', 'require')

      return await POSTGRES_STUDIO_STUFF.createExecutor(connectionURL.toString(), relativeTo)
    },
    reExportAdapterScript: POSTGRES_STUDIO_STUFF.reExportAdapterScript,
  },
  mysql: {
    async createExecutor(connectionString) {
      const { createPool } = await import('mysql2/promise')

      const pool = createPool(connectionString)

      process.once('SIGINT', () => pool.end())
      process.once('SIGTERM', () => pool.end())

      return createMySQL2Executor(pool)