From 8e7e38e02df6dd9385301016057a4fb9c2087a1e Mon Sep 17 00:00:00 2001 From: daniel starns Date: Mon, 12 Dec 2022 11:40:59 +0000 Subject: [PATCH] feat: DataProxy query logs --- packages/client/package.json | 2 +- .../_utils/stopMiniProxyQueryEngine.ts | 4 +- .../client/tests/functional/logging/tests.ts | 284 +++-- .../client/tests/functional/tracing/tests.ts | 1025 ++++++++--------- .../src/data-proxy/DataProxyEngine.ts | 194 +++- .../src/data-proxy/utils/request.ts | 6 +- pnpm-lock.yaml | 417 +++++-- 7 files changed, 1136 insertions(+), 796 deletions(-) diff --git a/packages/client/package.json b/packages/client/package.json index 2d713f524d55..d0637381dc90 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -80,7 +80,7 @@ "@prisma/instrumentation": "workspace:*", "@prisma/internals": "workspace:*", "@prisma/migrate": "workspace:*", - "@prisma/mini-proxy": "0.3.0", + "@prisma/mini-proxy": "0.6.4", "@swc-node/register": "1.5.4", "@swc/core": "1.3.14", "@swc/jest": "0.2.24", diff --git a/packages/client/tests/functional/_utils/stopMiniProxyQueryEngine.ts b/packages/client/tests/functional/_utils/stopMiniProxyQueryEngine.ts index 20a9d01e64d3..955534c83ba9 100644 --- a/packages/client/tests/functional/_utils/stopMiniProxyQueryEngine.ts +++ b/packages/client/tests/functional/_utils/stopMiniProxyQueryEngine.ts @@ -15,7 +15,9 @@ export async function stopMiniProxyQueryEngine(client: any): Promise { const response = await nodeFetch(`https://${host}/_mini-proxy/${clientVersion}/${schemaHash}/stop-engine`, { method: 'POST', - headers: engine.headers, + headers: { + Authorization: `Bearer ${engine.apiKey()}`, + }, }) debug('response status', response.status) diff --git a/packages/client/tests/functional/logging/tests.ts b/packages/client/tests/functional/logging/tests.ts index 58ee68673703..46d08b6d2730 100644 --- a/packages/client/tests/functional/logging/tests.ts +++ b/packages/client/tests/functional/logging/tests.ts @@ -7,176 +7,168 @@ import type { Prisma, PrismaClient } from './node_modules/@prisma/client' declare let newPrismaClient: NewPrismaClient -testMatrix.setupTestSuite( - (suiteConfig, _suiteMeta, clientMeta) => { - let client: PrismaClient - - test('should log queries on a method call', async () => { - client = newPrismaClient({ - log: [ - { - emit: 'event', - level: 'query', - }, - ], - }) +testMatrix.setupTestSuite((suiteConfig, _suiteMeta, clientMeta) => { + let client: PrismaClient + + test('should log queries on a method call', async () => { + client = newPrismaClient({ + log: [ + { + emit: 'event', + level: 'query', + }, + ], + }) - const queryLogPromise = new Promise((resolve) => { - client.$on('query', (data) => { - if ('query' in data) { - resolve(data) - } - }) + const queryLogPromise = new Promise((resolve) => { + client.$on('query', (data) => { + if ('query' in data) { + resolve(data) + } }) - - await client.user.findMany() - - const queryLogEvents = await queryLogPromise - expect(queryLogEvents).toHaveProperty('query') - expect(queryLogEvents).toHaveProperty('duration') - expect(queryLogEvents).toHaveProperty('timestamp') - - if (suiteConfig.provider === 'mongodb') { - expect(queryLogEvents.query).toContain('db.User.aggregate') - } else { - expect(queryLogEvents.query).toContain('SELECT') - } - - if (!clientMeta.dataProxy) { - expect(queryLogEvents).toHaveProperty('params') - expect(queryLogEvents).toHaveProperty('target') - } }) - test('should log queries inside a ITX', async () => { - client = newPrismaClient({ - log: [ - { - emit: 'event', - level: 'query', - }, - ], - }) + await client.user.findMany() + + const queryLogEvents = await queryLogPromise + expect(queryLogEvents).toHaveProperty('query') + expect(queryLogEvents).toHaveProperty('duration') + expect(queryLogEvents).toHaveProperty('timestamp') + + if (suiteConfig.provider === 'mongodb') { + expect(queryLogEvents.query).toContain('db.User.aggregate') + } else { + expect(queryLogEvents.query).toContain('SELECT') + } + + if (!clientMeta.dataProxy) { + expect(queryLogEvents).toHaveProperty('params') + expect(queryLogEvents).toHaveProperty('target') + } + }) + + test('should log queries inside a ITX', async () => { + client = newPrismaClient({ + log: [ + { + emit: 'event', + level: 'query', + }, + ], + }) - const queryLogs = new Promise((resolve) => { - const logs: Prisma.QueryEvent[] = [] + const queryLogs = new Promise((resolve) => { + const logs: Prisma.QueryEvent[] = [] - client.$on('query', (data) => { - if ('query' in data) { - logs.push(data) + client.$on('query', (data) => { + if ('query' in data) { + logs.push(data) - if (suiteConfig.provider === 'mongodb' && logs.length === 3) { - resolve(logs) - } + if (suiteConfig.provider === 'mongodb' && logs.length === 3) { + resolve(logs) + } - if (logs.length === 5) { - resolve(logs) - } + if ((data.query as string).includes('COMMIT')) { + resolve(logs) } - }) + } }) + }) - await client.$transaction(async (tx) => { - const id = suiteConfig.provider === 'mongodb' ? faker.database.mongodbObjectId() : faker.random.numeric() + await client.$transaction(async (tx) => { + const id = suiteConfig.provider === 'mongodb' ? faker.database.mongodbObjectId() : faker.random.numeric() - await tx.user.create({ - data: { - id, - }, - }) - - return tx.user.findMany({ - where: { - id, - }, - }) + await tx.user.create({ + data: { + id, + }, }) - const logs = await queryLogs - - if (suiteConfig.provider === 'mongodb') { - expect(logs).toHaveLength(3) - - expect(logs[0].query).toContain('User.insertOne') - expect(logs[1].query).toContain('User.aggregate') - expect(logs[2].query).toContain('User.aggregate') - } else { - expect(logs).toHaveLength(5) - - expect(logs[0].query).toContain('BEGIN') - expect(logs[1].query).toContain('INSERT') - expect(logs[2].query).toContain('SELECT') - expect(logs[3].query).toContain('SELECT') - expect(logs[4].query).toContain('COMMIT') - } + return tx.user.findMany({ + where: { + id, + }, + }) }) - test('should log parallel queries inside a ITX', async () => { - client = newPrismaClient({ - log: [ - { - emit: 'event', - level: 'query', - }, - ], - }) + const logs = await queryLogs + + if (suiteConfig.provider === 'mongodb') { + expect(logs).toHaveLength(3) + + expect(logs[0].query).toContain('User.insertOne') + expect(logs[1].query).toContain('User.aggregate') + expect(logs[2].query).toContain('User.aggregate') + } else { + expect(logs).toHaveLength(5) + + expect(logs[0].query).toContain('BEGIN') + expect(logs[1].query).toContain('INSERT') + expect(logs[2].query).toContain('SELECT') + expect(logs[3].query).toContain('SELECT') + expect(logs[4].query).toContain('COMMIT') + } + }) + + test('should log parallel queries inside a ITX', async () => { + client = newPrismaClient({ + log: [ + { + emit: 'event', + level: 'query', + }, + ], + }) - const queryLogs = new Promise((resolve) => { - const logs: Prisma.QueryEvent[] = [] + const queryLogs = new Promise((resolve) => { + const logs: Prisma.QueryEvent[] = [] - client.$on('query', (data) => { - if ('query' in data) { - logs.push(data) + client.$on('query', (data) => { + if ('query' in data) { + logs.push(data) - if (suiteConfig.provider === 'mongodb' && logs.length === 2) { - resolve(logs) - } + if (suiteConfig.provider === 'mongodb' && logs.length === 2) { + resolve(logs) + } - if (logs.length === 4) { - resolve(logs) - } + if ((data.query as string).includes('COMMIT')) { + resolve(logs) } - }) + } }) + }) - await client.$transaction(async (tx) => { - const id = suiteConfig.provider === 'mongodb' ? faker.database.mongodbObjectId() : faker.random.numeric() - - await Promise.all([ - tx.user.findMany({ - where: { - id, - }, - }), - tx.user.findMany({ - where: { - id, - }, - }), - ]) - }) + await client.$transaction(async (tx) => { + const id = suiteConfig.provider === 'mongodb' ? faker.database.mongodbObjectId() : faker.random.numeric() - const logs = await queryLogs + await Promise.all([ + tx.user.findMany({ + where: { + id, + }, + }), + tx.user.findMany({ + where: { + id, + }, + }), + ]) + }) - if (suiteConfig.provider === 'mongodb') { - expect(logs).toHaveLength(2) + const logs = await queryLogs - expect(logs[0].query).toContain('User.aggregate') - expect(logs[0].query).toContain('User.aggregate') - } else { - expect(logs).toHaveLength(4) + if (suiteConfig.provider === 'mongodb') { + expect(logs).toHaveLength(2) - expect(logs[0].query).toContain('BEGIN') - expect(logs[1].query).toContain('SELECT') - expect(logs[2].query).toContain('SELECT') - expect(logs[3].query).toContain('COMMIT') - } - }) - }, - { - skipDataProxy: { - reason: 'Not implemented yet', - runtimes: ['edge', 'node'], - }, - }, -) + expect(logs[0].query).toContain('User.aggregate') + expect(logs[0].query).toContain('User.aggregate') + } else { + expect(logs).toHaveLength(4) + + expect(logs[0].query).toContain('BEGIN') + expect(logs[1].query).toContain('SELECT') + expect(logs[2].query).toContain('SELECT') + expect(logs[3].query).toContain('COMMIT') + } + }) +}) diff --git a/packages/client/tests/functional/tracing/tests.ts b/packages/client/tests/functional/tracing/tests.ts index 59472ba599f6..1a81ba5d10e0 100644 --- a/packages/client/tests/functional/tracing/tests.ts +++ b/packages/client/tests/functional/tracing/tests.ts @@ -104,752 +104,741 @@ afterAll(() => { context.disable() }) -testMatrix.setupTestSuite( - ({ provider }) => { - jest.retryTimes(3) +testMatrix.setupTestSuite(({ provider }, suiteMeta, clientMeta) => { + jest.retryTimes(3) - beforeEach(async () => { - await prisma.$connect() - }) - - beforeEach(() => { - inMemorySpanExporter.reset() - }) + beforeEach(async () => { + await prisma.$connect() + }) - function cleanSpanTreeForSnapshot(tree: Tree) { - return JSON.parse(JSON.stringify(tree), (key, value) => { - if (key[0] === '_') return undefined - if (key === 'parentSpanId') return '' - if (key === 'itx_id') return '' - if (key === 'endTime') return '' - if (key === 'startTime') return '' - if (key === 'db.type') return '' - if (key === 'db.statement') return '' - if (key === 'resource') return undefined - if (key === 'spanId') return '' - if (key === 'traceId') return '' + beforeEach(() => { + inMemorySpanExporter.reset() + }) - return value - }) - } + function cleanSpanTreeForSnapshot(tree: Tree) { + return JSON.parse(JSON.stringify(tree), (key, value) => { + if (key[0] === '_') return undefined + if (key === 'parentSpanId') return '' + if (key === 'itx_id') return '' + if (key === 'endTime') return '' + if (key === 'startTime') return '' + if (key === 'db.type') return '' + if (key === 'db.statement') return '' + if (key === 'resource') return undefined + if (key === 'spanId') return '' + if (key === 'traceId') return '' + + return value + }) + } - async function waitForSpanTree(): Promise { - /* + async function waitForSpanTree(): Promise { + /* Spans come through logs and sometimes these tests can be flaky without giving some buffer */ - await new Promise((resolve) => setTimeout(resolve, 500)) + await new Promise((resolve) => setTimeout(resolve, 500)) - const spans = inMemorySpanExporter.getFinishedSpans() - const rootSpan = spans.find((span) => !span.parentSpanId) as ReadableSpan - const tree = buildTree({ span: rootSpan }, spans) + const spans = inMemorySpanExporter.getFinishedSpans() + const rootSpan = spans.find((span) => !span.parentSpanId) as ReadableSpan + const tree = buildTree({ span: rootSpan }, spans) - return tree - } - - describe('tracing on crud methods', () => { - let email = faker.internet.email() - - test('create', async () => { - await prisma.user.create({ - data: { - email: email, - }, - }) - - const tree = await waitForSpanTree() - - expect(cleanSpanTreeForSnapshot(tree)).toMatchSnapshot() - - expect(tree.span.name).toEqual('prisma:client:operation') - expect(tree.span.attributes['method']).toEqual('create') - expect(tree.span.attributes['model']).toEqual('User') + return tree + } - expect(tree.children).toHaveLength(2) + describe('tracing on crud methods', () => { + let email = faker.internet.email() - const serialize = (tree?.children || [])[0] as unknown as Tree - expect(serialize.span.name).toEqual('prisma:client:serialize') + test('create', async () => { + await prisma.user.create({ + data: { + email: email, + }, + }) - const engine = (tree?.children || [])[1] as unknown as Tree - expect(engine.span.name).toEqual('prisma:engine') + const tree = await waitForSpanTree() - const getConnection = (engine.children || [])[0] - expect(getConnection.span.name).toEqual('prisma:engine:connection') + expect(cleanSpanTreeForSnapshot(tree)).toMatchSnapshot() - if (provider === 'mongodb') { - expect(engine.children).toHaveLength(4) + expect(tree.span.name).toEqual('prisma:client:operation') + expect(tree.span.attributes['method']).toEqual('create') + expect(tree.span.attributes['model']).toEqual('User') - const dbQuery1 = (engine.children || [])[1] - expect(dbQuery1.span.name).toEqual('prisma:engine:db_query') - expect(dbQuery1.span.attributes['db.statement']).toContain('db.User.insertOne(*)') + expect(tree.children).toHaveLength(2) - const dbQuery2 = (engine.children || [])[2] - expect(dbQuery2.span.name).toEqual('prisma:engine:db_query') - expect(dbQuery2.span.attributes['db.statement']).toContain('db.User.findOne(*)') + const serialize = (tree?.children || [])[0] as unknown as Tree + expect(serialize.span.name).toEqual('prisma:client:serialize') - const engineSerialize = (engine.children || [])[3] - expect(engineSerialize.span.name).toEqual('prisma:engine:serialize') + const engine = (tree?.children || [])[1] as unknown as Tree + expect(engine.span.name).toEqual('prisma:engine') - return - } + const getConnection = (engine.children || [])[0] + expect(getConnection.span.name).toEqual('prisma:engine:connection') - expect(engine.children).toHaveLength(6) + if (provider === 'mongodb') { + expect(engine.children).toHaveLength(4) const dbQuery1 = (engine.children || [])[1] expect(dbQuery1.span.name).toEqual('prisma:engine:db_query') - expect(dbQuery1.span.attributes['db.statement']).toContain('BEGIN') + expect(dbQuery1.span.attributes['db.statement']).toContain('db.User.insertOne(*)') const dbQuery2 = (engine.children || [])[2] expect(dbQuery2.span.name).toEqual('prisma:engine:db_query') - expect(dbQuery2.span.attributes['db.statement']).toContain('INSERT') - - const dbQuery3 = (engine.children || [])[3] - expect(dbQuery3.span.name).toEqual('prisma:engine:db_query') - expect(dbQuery3.span.attributes['db.statement']).toContain('SELECT') + expect(dbQuery2.span.attributes['db.statement']).toContain('db.User.findOne(*)') - const engineSerialize = (engine.children || [])[4] + const engineSerialize = (engine.children || [])[3] expect(engineSerialize.span.name).toEqual('prisma:engine:serialize') - const dbQuery4 = (engine.children || [])[5] - expect(dbQuery4.span.name).toEqual('prisma:engine:db_query') - expect(dbQuery4.span.attributes['db.statement']).toContain('COMMIT') - }) + return + } - test('read', async () => { - await prisma.user.findMany({ - where: { - email: email, - }, - }) + expect(engine.children).toHaveLength(6) - const tree = await waitForSpanTree() + const dbQuery1 = (engine.children || [])[1] + expect(dbQuery1.span.name).toEqual('prisma:engine:db_query') + expect(dbQuery1.span.attributes['db.statement']).toContain('BEGIN') - expect(cleanSpanTreeForSnapshot(tree)).toMatchSnapshot() + const dbQuery2 = (engine.children || [])[2] + expect(dbQuery2.span.name).toEqual('prisma:engine:db_query') + expect(dbQuery2.span.attributes['db.statement']).toContain('INSERT') - expect(tree.span.name).toEqual('prisma:client:operation') - expect(tree.span.attributes['method']).toEqual('findMany') - expect(tree.span.attributes['model']).toEqual('User') + const dbQuery3 = (engine.children || [])[3] + expect(dbQuery3.span.name).toEqual('prisma:engine:db_query') + expect(dbQuery3.span.attributes['db.statement']).toContain('SELECT') + + const engineSerialize = (engine.children || [])[4] + expect(engineSerialize.span.name).toEqual('prisma:engine:serialize') + + const dbQuery4 = (engine.children || [])[5] + expect(dbQuery4.span.name).toEqual('prisma:engine:db_query') + expect(dbQuery4.span.attributes['db.statement']).toContain('COMMIT') + }) - expect(tree.children).toHaveLength(2) + test('read', async () => { + await prisma.user.findMany({ + where: { + email: email, + }, + }) - const serialize = (tree?.children || [])[0] as unknown as Tree - expect(serialize.span.name).toEqual('prisma:client:serialize') + const tree = await waitForSpanTree() - const engine = (tree?.children || [])[1] as unknown as Tree - expect(engine.span.name).toEqual('prisma:engine') + expect(cleanSpanTreeForSnapshot(tree)).toMatchSnapshot() - const getConnection = (engine.children || [])[0] - expect(getConnection.span.name).toEqual('prisma:engine:connection') + expect(tree.span.name).toEqual('prisma:client:operation') + expect(tree.span.attributes['method']).toEqual('findMany') + expect(tree.span.attributes['model']).toEqual('User') - if (provider === 'mongodb') { - expect(engine.children).toHaveLength(3) + expect(tree.children).toHaveLength(2) - const dbQuery1 = (engine.children || [])[1] - expect(dbQuery1.span.name).toEqual('prisma:engine:db_query') - expect(dbQuery1.span.attributes['db.statement']).toContain('db.User.findMany(*)') + const serialize = (tree?.children || [])[0] as unknown as Tree + expect(serialize.span.name).toEqual('prisma:client:serialize') - const engineSerialize = (engine.children || [])[2] - expect(engineSerialize.span.name).toEqual('prisma:engine:serialize') + const engine = (tree?.children || [])[1] as unknown as Tree + expect(engine.span.name).toEqual('prisma:engine') - return - } + const getConnection = (engine.children || [])[0] + expect(getConnection.span.name).toEqual('prisma:engine:connection') + if (provider === 'mongodb') { expect(engine.children).toHaveLength(3) - const select = (engine.children || [])[1] - expect(select.span.name).toEqual('prisma:engine:db_query') - expect(select.span.attributes['db.statement']).toContain('SELECT') + const dbQuery1 = (engine.children || [])[1] + expect(dbQuery1.span.name).toEqual('prisma:engine:db_query') + expect(dbQuery1.span.attributes['db.statement']).toContain('db.User.findMany(*)') const engineSerialize = (engine.children || [])[2] expect(engineSerialize.span.name).toEqual('prisma:engine:serialize') - }) - - test('update', async () => { - const newEmail = faker.internet.email() - - await prisma.user.update({ - data: { - email: newEmail, - }, - where: { - email: email, - }, - }) - email = newEmail + return + } - const tree = await waitForSpanTree() + expect(engine.children).toHaveLength(3) - expect(cleanSpanTreeForSnapshot(tree)).toMatchSnapshot() + const select = (engine.children || [])[1] + expect(select.span.name).toEqual('prisma:engine:db_query') + expect(select.span.attributes['db.statement']).toContain('SELECT') - expect(tree.span.name).toEqual('prisma:client:operation') - expect(tree.span.attributes['method']).toEqual('update') - expect(tree.span.attributes['model']).toEqual('User') + const engineSerialize = (engine.children || [])[2] + expect(engineSerialize.span.name).toEqual('prisma:engine:serialize') + }) - expect(tree.children).toHaveLength(2) + test('update', async () => { + const newEmail = faker.internet.email() - const serialize = (tree?.children || [])[0] as unknown as Tree - expect(serialize.span.name).toEqual('prisma:client:serialize') + await prisma.user.update({ + data: { + email: newEmail, + }, + where: { + email: email, + }, + }) - const engine = (tree?.children || [])[1] as unknown as Tree - expect(engine.span.name).toEqual('prisma:engine') + email = newEmail - const getConnection = (engine.children || [])[0] - expect(getConnection.span.name).toEqual('prisma:engine:connection') + const tree = await waitForSpanTree() - if (provider === 'mongodb') { - expect(engine.children).toHaveLength(5) + expect(cleanSpanTreeForSnapshot(tree)).toMatchSnapshot() - const dbQuery1 = (engine.children || [])[1] - expect(dbQuery1.span.name).toEqual('prisma:engine:db_query') - expect(dbQuery1.span.attributes['db.statement']).toContain('db.User.findMany(*)') + expect(tree.span.name).toEqual('prisma:client:operation') + expect(tree.span.attributes['method']).toEqual('update') + expect(tree.span.attributes['model']).toEqual('User') - const dbQuery2 = (engine.children || [])[2] - expect(dbQuery2.span.name).toEqual('prisma:engine:db_query') - expect(dbQuery2.span.attributes['db.statement']).toContain('db.User.updateMany(*)') + expect(tree.children).toHaveLength(2) - const dbQuery3 = (engine.children || [])[3] - expect(dbQuery3.span.name).toEqual('prisma:engine:db_query') - expect(dbQuery3.span.attributes['db.statement']).toContain('db.User.findOne(*)') + const serialize = (tree?.children || [])[0] as unknown as Tree + expect(serialize.span.name).toEqual('prisma:client:serialize') - const engineSerialize = (engine.children || [])[4] - expect(engineSerialize.span.name).toEqual('prisma:engine:serialize') + const engine = (tree?.children || [])[1] as unknown as Tree + expect(engine.span.name).toEqual('prisma:engine') - return - } + const getConnection = (engine.children || [])[0] + expect(getConnection.span.name).toEqual('prisma:engine:connection') - expect(engine.children).toHaveLength(7) + if (provider === 'mongodb') { + expect(engine.children).toHaveLength(5) const dbQuery1 = (engine.children || [])[1] expect(dbQuery1.span.name).toEqual('prisma:engine:db_query') - expect(dbQuery1.span.attributes['db.statement']).toContain('BEGIN') + expect(dbQuery1.span.attributes['db.statement']).toContain('db.User.findMany(*)') const dbQuery2 = (engine.children || [])[2] expect(dbQuery2.span.name).toEqual('prisma:engine:db_query') - expect(dbQuery2.span.attributes['db.statement']).toContain('SELECT') + expect(dbQuery2.span.attributes['db.statement']).toContain('db.User.updateMany(*)') const dbQuery3 = (engine.children || [])[3] expect(dbQuery3.span.name).toEqual('prisma:engine:db_query') - expect(dbQuery3.span.attributes['db.statement']).toContain('UPDATE') - - const dbQuery4 = (engine.children || [])[4] - expect(dbQuery4.span.name).toEqual('prisma:engine:db_query') - expect(dbQuery4.span.attributes['db.statement']).toContain('SELECT') + expect(dbQuery3.span.attributes['db.statement']).toContain('db.User.findOne(*)') - const engineSerialize = (engine.children || [])[5] + const engineSerialize = (engine.children || [])[4] expect(engineSerialize.span.name).toEqual('prisma:engine:serialize') - const dbQuery5 = (engine.children || [])[6] - expect(dbQuery5.span.name).toEqual('prisma:engine:db_query') - expect(dbQuery5.span.attributes['db.statement']).toContain('COMMIT') - }) + return + } - test('delete', async () => { - await prisma.user.delete({ - where: { - email: email, - }, - }) + expect(engine.children).toHaveLength(7) - const tree = await waitForSpanTree() + const dbQuery1 = (engine.children || [])[1] + expect(dbQuery1.span.name).toEqual('prisma:engine:db_query') + expect(dbQuery1.span.attributes['db.statement']).toContain('BEGIN') - expect(cleanSpanTreeForSnapshot(tree)).toMatchSnapshot() + const dbQuery2 = (engine.children || [])[2] + expect(dbQuery2.span.name).toEqual('prisma:engine:db_query') + expect(dbQuery2.span.attributes['db.statement']).toContain('SELECT') - expect(tree.span.name).toEqual('prisma:client:operation') - expect(tree.span.attributes['method']).toEqual('delete') - expect(tree.span.attributes['model']).toEqual('User') + const dbQuery3 = (engine.children || [])[3] + expect(dbQuery3.span.name).toEqual('prisma:engine:db_query') + expect(dbQuery3.span.attributes['db.statement']).toContain('UPDATE') - expect(tree.children).toHaveLength(2) + const dbQuery4 = (engine.children || [])[4] + expect(dbQuery4.span.name).toEqual('prisma:engine:db_query') + expect(dbQuery4.span.attributes['db.statement']).toContain('SELECT') - const serialize = (tree?.children || [])[0] as unknown as Tree - expect(serialize.span.name).toEqual('prisma:client:serialize') + const engineSerialize = (engine.children || [])[5] + expect(engineSerialize.span.name).toEqual('prisma:engine:serialize') - const engine = (tree?.children || [])[1] as unknown as Tree - expect(engine.span.name).toEqual('prisma:engine') + const dbQuery5 = (engine.children || [])[6] + expect(dbQuery5.span.name).toEqual('prisma:engine:db_query') + expect(dbQuery5.span.attributes['db.statement']).toContain('COMMIT') + }) - const getConnection = (engine.children || [])[0] - expect(getConnection.span.name).toEqual('prisma:engine:connection') + test('delete', async () => { + await prisma.user.delete({ + where: { + email: email, + }, + }) - if (provider === 'mongodb') { - expect(engine.children).toHaveLength(5) + const tree = await waitForSpanTree() - const dbQuery1 = (engine.children || [])[1] - expect(dbQuery1.span.name).toEqual('prisma:engine:db_query') - expect(dbQuery1.span.attributes['db.statement']).toContain('db.User.findOne(*)') + expect(cleanSpanTreeForSnapshot(tree)).toMatchSnapshot() - const dbQuery2 = (engine.children || [])[2] - expect(dbQuery2.span.name).toEqual('prisma:engine:db_query') - expect(dbQuery2.span.attributes['db.statement']).toContain('db.User.findMany(*)') + expect(tree.span.name).toEqual('prisma:client:operation') + expect(tree.span.attributes['method']).toEqual('delete') + expect(tree.span.attributes['model']).toEqual('User') - const dbQuery3 = (engine.children || [])[3] - expect(dbQuery3.span.name).toEqual('prisma:engine:db_query') - expect(dbQuery3.span.attributes['db.statement']).toContain('db.User.deleteMany(*)') + expect(tree.children).toHaveLength(2) - const engineSerialize = (engine.children || [])[4] - expect(engineSerialize.span.name).toEqual('prisma:engine:serialize') + const serialize = (tree?.children || [])[0] as unknown as Tree + expect(serialize.span.name).toEqual('prisma:client:serialize') - return - } + const engine = (tree?.children || [])[1] as unknown as Tree + expect(engine.span.name).toEqual('prisma:engine') - expect(engine.children).toHaveLength(7) + const getConnection = (engine.children || [])[0] + expect(getConnection.span.name).toEqual('prisma:engine:connection') + + if (provider === 'mongodb') { + expect(engine.children).toHaveLength(5) const dbQuery1 = (engine.children || [])[1] expect(dbQuery1.span.name).toEqual('prisma:engine:db_query') - expect(dbQuery1.span.attributes['db.statement']).toContain('BEGIN') + expect(dbQuery1.span.attributes['db.statement']).toContain('db.User.findOne(*)') const dbQuery2 = (engine.children || [])[2] expect(dbQuery2.span.name).toEqual('prisma:engine:db_query') - expect(dbQuery2.span.attributes['db.statement']).toContain('SELECT') + expect(dbQuery2.span.attributes['db.statement']).toContain('db.User.findMany(*)') const dbQuery3 = (engine.children || [])[3] expect(dbQuery3.span.name).toEqual('prisma:engine:db_query') - expect(dbQuery3.span.attributes['db.statement']).toContain('SELECT') + expect(dbQuery3.span.attributes['db.statement']).toContain('db.User.deleteMany(*)') - const dbQuery4 = (engine.children || [])[4] - expect(dbQuery4.span.name).toEqual('prisma:engine:db_query') - expect(dbQuery4.span.attributes['db.statement']).toContain('DELETE') - - const engineSerialize = (engine.children || [])[5] + const engineSerialize = (engine.children || [])[4] expect(engineSerialize.span.name).toEqual('prisma:engine:serialize') - const dbQuery5 = (engine.children || [])[6] - expect(dbQuery5.span.name).toEqual('prisma:engine:db_query') - expect(dbQuery5.span.attributes['db.statement']).toContain('COMMIT') - }) - }) - - describe('tracing on transactions', () => { - test('$transaction', async () => { - const email = faker.internet.email() - - await prisma.$transaction([ - prisma.user.create({ - data: { - email, - }, - }), - prisma.user.findMany({ - where: { - email, - }, - }), - ]) - - const tree = await waitForSpanTree() + return + } - expect(cleanSpanTreeForSnapshot(tree)).toMatchSnapshot() + expect(engine.children).toHaveLength(7) - expect(tree.span.name).toEqual('prisma:client:transaction') - expect(tree.span.attributes['method']).toEqual('$transaction') - expect(tree.children).toHaveLength(3) + const dbQuery1 = (engine.children || [])[1] + expect(dbQuery1.span.name).toEqual('prisma:engine:db_query') + expect(dbQuery1.span.attributes['db.statement']).toContain('BEGIN') - const create = (tree?.children || [])[0] as unknown as Tree - expect(create.span.name).toEqual('prisma:client:operation') - expect(create.span.attributes.model).toEqual('User') - expect(create.span.attributes.method).toEqual('create') + const dbQuery2 = (engine.children || [])[2] + expect(dbQuery2.span.name).toEqual('prisma:engine:db_query') + expect(dbQuery2.span.attributes['db.statement']).toContain('SELECT') - const findMany = (tree?.children || [])[1] as unknown as Tree - expect(findMany.span.name).toEqual('prisma:client:operation') - expect(findMany.span.attributes.model).toEqual('User') - expect(findMany.span.attributes.method).toEqual('findMany') + const dbQuery3 = (engine.children || [])[3] + expect(dbQuery3.span.name).toEqual('prisma:engine:db_query') + expect(dbQuery3.span.attributes['db.statement']).toContain('SELECT') - const queryBuilder = (tree?.children || [])[2] as unknown as Tree - expect(queryBuilder.span.name).toEqual('prisma:engine') + const dbQuery4 = (engine.children || [])[4] + expect(dbQuery4.span.name).toEqual('prisma:engine:db_query') + expect(dbQuery4.span.attributes['db.statement']).toContain('DELETE') - if (provider === 'mongodb') { - expect(queryBuilder.children).toHaveLength(6) + const engineSerialize = (engine.children || [])[5] + expect(engineSerialize.span.name).toEqual('prisma:engine:serialize') - return - } + const dbQuery5 = (engine.children || [])[6] + expect(dbQuery5.span.name).toEqual('prisma:engine:db_query') + expect(dbQuery5.span.attributes['db.statement']).toContain('COMMIT') + }) + }) - expect(queryBuilder.children).toHaveLength(8) - }) + describeIf(!clientMeta.dataProxy)('tracing on transactions', () => { + test('$transaction', async () => { + const email = faker.internet.email() - test('interactive-transactions', async () => { - const email = faker.internet.email() - - await prisma.$transaction(async (client) => { - await client.user.create({ - data: { - email, - }, - }) - await client.user.findMany({ - where: { - email, - }, - }) - }) + await prisma.$transaction([ + prisma.user.create({ + data: { + email, + }, + }), + prisma.user.findMany({ + where: { + email, + }, + }), + ]) - const tree = await waitForSpanTree() + const tree = await waitForSpanTree() - expect(cleanSpanTreeForSnapshot(tree)).toMatchSnapshot() + expect(cleanSpanTreeForSnapshot(tree)).toMatchSnapshot() - expect(tree.span.name).toEqual('prisma:client:transaction') - expect(tree.span.attributes['method']).toEqual('$transaction') - expect(tree.children).toHaveLength(3) + expect(tree.span.name).toEqual('prisma:client:transaction') + expect(tree.span.attributes['method']).toEqual('$transaction') + expect(tree.children).toHaveLength(3) - const create = (tree?.children || [])[0] as unknown as Tree - expect(create.span.name).toEqual('prisma:client:operation') - expect(create.span.attributes.model).toEqual('User') - expect(create.span.attributes.method).toEqual('create') + const create = (tree?.children || [])[0] as unknown as Tree + expect(create.span.name).toEqual('prisma:client:operation') + expect(create.span.attributes.model).toEqual('User') + expect(create.span.attributes.method).toEqual('create') - const findMany = (tree?.children || [])[1] as unknown as Tree - expect(findMany.span.name).toEqual('prisma:client:operation') - expect(findMany.span.attributes.model).toEqual('User') - expect(findMany.span.attributes.method).toEqual('findMany') + const findMany = (tree?.children || [])[1] as unknown as Tree + expect(findMany.span.name).toEqual('prisma:client:operation') + expect(findMany.span.attributes.model).toEqual('User') + expect(findMany.span.attributes.method).toEqual('findMany') - const itxRunner = (tree?.children || [])[2] as unknown as Tree - expect(itxRunner.span.name).toEqual('prisma:engine:itx_runner') + const queryBuilder = (tree?.children || [])[2] as unknown as Tree + expect(queryBuilder.span.name).toEqual('prisma:engine') - if (provider === 'mongodb') { - expect(itxRunner.children).toHaveLength(3) + if (provider === 'mongodb') { + expect(queryBuilder.children).toHaveLength(6) - return - } + return + } - expect(itxRunner.children).toHaveLength(5) - }) + expect(queryBuilder.children).toHaveLength(8) }) - describe('tracing on $raw methods', () => { - test('$queryRaw', async () => { - if (provider === 'mongodb') { - return - } - - // @ts-test-if: provider !== 'mongodb' - await prisma.$queryRaw`SELECT 1 + 1;` + test('interactive-transactions', async () => { + const email = faker.internet.email() - const tree = await waitForSpanTree() + await prisma.$transaction(async (client) => { + await client.user.create({ + data: { + email, + }, + }) + await client.user.findMany({ + where: { + email, + }, + }) + }) - expect(cleanSpanTreeForSnapshot(tree)).toMatchSnapshot() + const tree = await waitForSpanTree() - expect(tree.span.name).toEqual('prisma:client:operation') - expect(tree.span.attributes['method']).toEqual('queryRaw') + expect(cleanSpanTreeForSnapshot(tree)).toMatchSnapshot() - expect(tree.children).toHaveLength(2) + expect(tree.span.name).toEqual('prisma:client:transaction') + expect(tree.span.attributes['method']).toEqual('$transaction') + expect(tree.children).toHaveLength(3) - const serialize = (tree?.children || [])[0] as unknown as Tree - expect(serialize.span.name).toEqual('prisma:client:serialize') + const create = (tree?.children || [])[0] as unknown as Tree + expect(create.span.name).toEqual('prisma:client:operation') + expect(create.span.attributes.model).toEqual('User') + expect(create.span.attributes.method).toEqual('create') - const engine = (tree?.children || [])[1] as unknown as Tree - expect(engine.span.name).toEqual('prisma:engine') + const findMany = (tree?.children || [])[1] as unknown as Tree + expect(findMany.span.name).toEqual('prisma:client:operation') + expect(findMany.span.attributes.model).toEqual('User') + expect(findMany.span.attributes.method).toEqual('findMany') - expect(engine.children).toHaveLength(3) + const itxRunner = (tree?.children || [])[2] as unknown as Tree + expect(itxRunner.span.name).toEqual('prisma:engine:itx_runner') - const getConnection = (engine.children || [])[0] - expect(getConnection.span.name).toEqual('prisma:engine:connection') + if (provider === 'mongodb') { + expect(itxRunner.children).toHaveLength(3) - const dbQuery1 = (engine.children || [])[1] - expect(dbQuery1.span.name).toEqual('prisma:engine:db_query') - expect(dbQuery1.span.attributes['db.statement']).toEqual('SELECT 1 + 1;') + return + } - const engineSerialize = (engine.children || [])[2] - expect(engineSerialize.span.name).toEqual('prisma:engine:serialize') - }) + expect(itxRunner.children).toHaveLength(5) + }) + }) - test('$executeRaw', async () => { - // Raw query failed. Code: `N/A`. Message: `Execute returned results, which is not allowed in SQLite.` - if (provider === 'sqlite' || provider === 'mongodb') { - return - } + describe('tracing on $raw methods', () => { + test('$queryRaw', async () => { + if (provider === 'mongodb') { + return + } - // @ts-test-if: provider !== 'mongodb' - await prisma.$executeRaw`SELECT 1 + 1;` + // @ts-test-if: provider !== 'mongodb' + await prisma.$queryRaw`SELECT 1 + 1;` - const tree = await waitForSpanTree() + const tree = await waitForSpanTree() - expect(cleanSpanTreeForSnapshot(tree)).toMatchSnapshot() + expect(cleanSpanTreeForSnapshot(tree)).toMatchSnapshot() - expect(tree.span.name).toEqual('prisma:client:operation') - expect(tree.span.attributes['method']).toEqual('executeRaw') + expect(tree.span.name).toEqual('prisma:client:operation') + expect(tree.span.attributes['method']).toEqual('queryRaw') - expect(tree.children).toHaveLength(2) + expect(tree.children).toHaveLength(2) - const serialize = (tree?.children || [])[0] as unknown as Tree - expect(serialize.span.name).toEqual('prisma:client:serialize') + const serialize = (tree?.children || [])[0] as unknown as Tree + expect(serialize.span.name).toEqual('prisma:client:serialize') - const engine = (tree?.children || [])[1] as unknown as Tree - expect(engine.span.name).toEqual('prisma:engine') + const engine = (tree?.children || [])[1] as unknown as Tree + expect(engine.span.name).toEqual('prisma:engine') - expect(engine.children).toHaveLength(3) + expect(engine.children).toHaveLength(3) - const getConnection = (engine.children || [])[0] - expect(getConnection.span.name).toEqual('prisma:engine:connection') + const getConnection = (engine.children || [])[0] + expect(getConnection.span.name).toEqual('prisma:engine:connection') - const dbQuery1 = (engine.children || [])[1] - expect(dbQuery1.span.name).toEqual('prisma:engine:db_query') - expect(dbQuery1.span.attributes['db.statement']).toEqual('SELECT 1 + 1;') + const dbQuery1 = (engine.children || [])[1] + expect(dbQuery1.span.name).toEqual('prisma:engine:db_query') + expect(dbQuery1.span.attributes['db.statement']).toEqual('SELECT 1 + 1;') - const engineSerialize = (engine.children || [])[2] - expect(engineSerialize.span.name).toEqual('prisma:engine:serialize') - }) + const engineSerialize = (engine.children || [])[2] + expect(engineSerialize.span.name).toEqual('prisma:engine:serialize') }) - test('tracing with custom span', async () => { - const tracer = trace.getTracer('MyApp') - const email = faker.internet.email() + test('$executeRaw', async () => { + // Raw query failed. Code: `N/A`. Message: `Execute returned results, which is not allowed in SQLite.` + if (provider === 'sqlite' || provider === 'mongodb') { + return + } - await tracer.startActiveSpan('create-user', async (span) => { - try { - return await prisma.user.create({ - data: { - email: email, - }, - }) - } finally { - span.end() - } - }) + // @ts-test-if: provider !== 'mongodb' + await prisma.$executeRaw`SELECT 1 + 1;` const tree = await waitForSpanTree() expect(cleanSpanTreeForSnapshot(tree)).toMatchSnapshot() - expect(tree.span.name).toEqual('create-user') + expect(tree.span.name).toEqual('prisma:client:operation') + expect(tree.span.attributes['method']).toEqual('executeRaw') - const prismaSpan = (tree.children || [])[0] - expect(prismaSpan.span.name).toEqual('prisma:client:operation') - expect(prismaSpan.span.attributes['method']).toEqual('create') - expect(prismaSpan.span.attributes['model']).toEqual('User') - expect(prismaSpan.children).toHaveLength(2) + expect(tree.children).toHaveLength(2) - const serialize = (prismaSpan?.children || [])[0] as unknown as Tree + const serialize = (tree?.children || [])[0] as unknown as Tree expect(serialize.span.name).toEqual('prisma:client:serialize') - const engine = (prismaSpan?.children || [])[1] as unknown as Tree + const engine = (tree?.children || [])[1] as unknown as Tree expect(engine.span.name).toEqual('prisma:engine') + expect(engine.children).toHaveLength(3) + const getConnection = (engine.children || [])[0] expect(getConnection.span.name).toEqual('prisma:engine:connection') - if (provider === 'mongodb') { - expect(engine.children).toHaveLength(4) - - const dbQuery1 = (engine.children || [])[1] - expect(dbQuery1.span.name).toEqual('prisma:engine:db_query') - expect(dbQuery1.span.attributes['db.statement']).toContain('db.User.insertOne(*)') + const dbQuery1 = (engine.children || [])[1] + expect(dbQuery1.span.name).toEqual('prisma:engine:db_query') + expect(dbQuery1.span.attributes['db.statement']).toEqual('SELECT 1 + 1;') - const dbQuery2 = (engine.children || [])[2] - expect(dbQuery2.span.name).toEqual('prisma:engine:db_query') - expect(dbQuery2.span.attributes['db.statement']).toContain('db.User.findOne(*)') + const engineSerialize = (engine.children || [])[2] + expect(engineSerialize.span.name).toEqual('prisma:engine:serialize') + }) + }) - const engineSerialize = (engine.children || [])[3] - expect(engineSerialize.span.name).toEqual('prisma:engine:serialize') + test('tracing with custom span', async () => { + const tracer = trace.getTracer('MyApp') + const email = faker.internet.email() - return + await tracer.startActiveSpan('create-user', async (span) => { + try { + return await prisma.user.create({ + data: { + email: email, + }, + }) + } finally { + span.end() } + }) - expect(engine.children).toHaveLength(6) + const tree = await waitForSpanTree() + + expect(cleanSpanTreeForSnapshot(tree)).toMatchSnapshot() + + expect(tree.span.name).toEqual('create-user') + + const prismaSpan = (tree.children || [])[0] + expect(prismaSpan.span.name).toEqual('prisma:client:operation') + expect(prismaSpan.span.attributes['method']).toEqual('create') + expect(prismaSpan.span.attributes['model']).toEqual('User') + expect(prismaSpan.children).toHaveLength(2) + + const serialize = (prismaSpan?.children || [])[0] as unknown as Tree + expect(serialize.span.name).toEqual('prisma:client:serialize') + + const engine = (prismaSpan?.children || [])[1] as unknown as Tree + expect(engine.span.name).toEqual('prisma:engine') + + const getConnection = (engine.children || [])[0] + expect(getConnection.span.name).toEqual('prisma:engine:connection') + + if (provider === 'mongodb') { + expect(engine.children).toHaveLength(4) const dbQuery1 = (engine.children || [])[1] expect(dbQuery1.span.name).toEqual('prisma:engine:db_query') - expect(dbQuery1.span.attributes['db.statement']).toContain('BEGIN') + expect(dbQuery1.span.attributes['db.statement']).toContain('db.User.insertOne(*)') const dbQuery2 = (engine.children || [])[2] expect(dbQuery2.span.name).toEqual('prisma:engine:db_query') - expect(dbQuery2.span.attributes['db.statement']).toContain('INSERT') - - const dbQuery3 = (engine.children || [])[3] - expect(dbQuery3.span.name).toEqual('prisma:engine:db_query') - expect(dbQuery3.span.attributes['db.statement']).toContain('SELECT') + expect(dbQuery2.span.attributes['db.statement']).toContain('db.User.findOne(*)') - const engineSerialize = (engine.children || [])[4] + const engineSerialize = (engine.children || [])[3] expect(engineSerialize.span.name).toEqual('prisma:engine:serialize') - const dbQuery4 = (engine.children || [])[5] - expect(dbQuery4.span.name).toEqual('prisma:engine:db_query') - expect(dbQuery4.span.attributes['db.statement']).toContain('COMMIT') - }) + return + } - describe('tracing with middleware', () => { - let _prisma: PrismaClient + expect(engine.children).toHaveLength(6) - beforeAll(async () => { - _prisma = newPrismaClient() + const dbQuery1 = (engine.children || [])[1] + expect(dbQuery1.span.name).toEqual('prisma:engine:db_query') + expect(dbQuery1.span.attributes['db.statement']).toContain('BEGIN') - await _prisma.$connect() - }) + const dbQuery2 = (engine.children || [])[2] + expect(dbQuery2.span.name).toEqual('prisma:engine:db_query') + expect(dbQuery2.span.attributes['db.statement']).toContain('INSERT') - test('tracing with middleware', async () => { - const email = faker.internet.email() + const dbQuery3 = (engine.children || [])[3] + expect(dbQuery3.span.name).toEqual('prisma:engine:db_query') + expect(dbQuery3.span.attributes['db.statement']).toContain('SELECT') - _prisma.$use(async (params, next) => { - // Manipulate params here - const result = await next(params) - // See results here - return result - }) - _prisma.$use(async (params, next) => { - // Manipulate params here - const result = await next(params) - // See results here - return result - }) + const engineSerialize = (engine.children || [])[4] + expect(engineSerialize.span.name).toEqual('prisma:engine:serialize') - await _prisma.user.create({ - data: { - email: email, - }, - }) + const dbQuery4 = (engine.children || [])[5] + expect(dbQuery4.span.name).toEqual('prisma:engine:db_query') + expect(dbQuery4.span.attributes['db.statement']).toContain('COMMIT') + }) - const tree = await waitForSpanTree() + describe('tracing with middleware', () => { + let _prisma: PrismaClient - expect(cleanSpanTreeForSnapshot(tree)).toMatchSnapshot() + beforeAll(async () => { + _prisma = newPrismaClient() - expect(tree.span.name).toEqual('prisma:client:operation') - expect(tree.span.attributes['method']).toEqual('create') - expect(tree.span.attributes['model']).toEqual('User') + await _prisma.$connect() + }) - expect(tree.children).toHaveLength(10) + test('tracing with middleware', async () => { + const email = faker.internet.email() - const middleware1 = (tree.children || [])[0] as unknown as Tree - expect(middleware1.span.name).toEqual('prisma:client:middleware') - expect(middleware1.children).toHaveLength(0) + _prisma.$use(async (params, next) => { + // Manipulate params here + const result = await next(params) + // See results here + return result + }) + _prisma.$use(async (params, next) => { + // Manipulate params here + const result = await next(params) + // See results here + return result + }) + + await _prisma.user.create({ + data: { + email: email, + }, + }) - const middleware2 = (tree.children || [])[1] as unknown as Tree - expect(middleware2.span.name).toEqual('prisma:client:middleware') - expect(middleware2.children).toHaveLength(0) + const tree = await waitForSpanTree() - const engine = (tree.children || []).find(({ span }) => span.name === 'prisma:engine') as Tree + expect(cleanSpanTreeForSnapshot(tree)).toMatchSnapshot() - const getConnection = (engine.children || [])[0] - expect(getConnection.span.name).toEqual('prisma:engine:connection') + expect(tree.span.name).toEqual('prisma:client:operation') + expect(tree.span.attributes['method']).toEqual('create') + expect(tree.span.attributes['model']).toEqual('User') - if (provider === 'mongodb') { - expect(engine.children).toHaveLength(4) + expect(tree.children).toHaveLength(10) - const dbQuery1 = (engine.children || [])[1] - expect(dbQuery1.span.name).toEqual('prisma:engine:db_query') - expect(dbQuery1.span.attributes['db.statement']).toContain('db.User.insertOne(*)') + const middleware1 = (tree.children || [])[0] as unknown as Tree + expect(middleware1.span.name).toEqual('prisma:client:middleware') + expect(middleware1.children).toHaveLength(0) - const dbQuery2 = (engine.children || [])[2] - expect(dbQuery2.span.name).toEqual('prisma:engine:db_query') - expect(dbQuery2.span.attributes['db.statement']).toContain('db.User.findOne(*)') + const middleware2 = (tree.children || [])[1] as unknown as Tree + expect(middleware2.span.name).toEqual('prisma:client:middleware') + expect(middleware2.children).toHaveLength(0) - const serialize = (engine.children || [])[3] - expect(serialize.span.name).toEqual('prisma:engine:serialize') + const engine = (tree.children || []).find(({ span }) => span.name === 'prisma:engine') as Tree - return - } + const getConnection = (engine.children || [])[0] + expect(getConnection.span.name).toEqual('prisma:engine:connection') - expect(engine.children).toHaveLength(6) + if (provider === 'mongodb') { + expect(engine.children).toHaveLength(4) const dbQuery1 = (engine.children || [])[1] expect(dbQuery1.span.name).toEqual('prisma:engine:db_query') - expect(dbQuery1.span.attributes['db.statement']).toContain('BEGIN') + expect(dbQuery1.span.attributes['db.statement']).toContain('db.User.insertOne(*)') const dbQuery2 = (engine.children || [])[2] expect(dbQuery2.span.name).toEqual('prisma:engine:db_query') - expect(dbQuery2.span.attributes['db.statement']).toContain('INSERT') - - const dbQuery3 = (engine.children || [])[3] - expect(dbQuery3.span.name).toEqual('prisma:engine:db_query') - expect(dbQuery3.span.attributes['db.statement']).toContain('SELECT') + expect(dbQuery2.span.attributes['db.statement']).toContain('db.User.findOne(*)') - const serialize = (engine.children || [])[4] + const serialize = (engine.children || [])[3] expect(serialize.span.name).toEqual('prisma:engine:serialize') - const dbQuery4 = (engine.children || [])[5] - expect(dbQuery4.span.name).toEqual('prisma:engine:db_query') - expect(dbQuery4.span.attributes['db.statement']).toContain('COMMIT') - }) + return + } + + expect(engine.children).toHaveLength(6) + + const dbQuery1 = (engine.children || [])[1] + expect(dbQuery1.span.name).toEqual('prisma:engine:db_query') + expect(dbQuery1.span.attributes['db.statement']).toContain('BEGIN') + + const dbQuery2 = (engine.children || [])[2] + expect(dbQuery2.span.name).toEqual('prisma:engine:db_query') + expect(dbQuery2.span.attributes['db.statement']).toContain('INSERT') + + const dbQuery3 = (engine.children || [])[3] + expect(dbQuery3.span.name).toEqual('prisma:engine:db_query') + expect(dbQuery3.span.attributes['db.statement']).toContain('SELECT') + + const serialize = (engine.children || [])[4] + expect(serialize.span.name).toEqual('prisma:engine:serialize') + + const dbQuery4 = (engine.children || [])[5] + expect(dbQuery4.span.name).toEqual('prisma:engine:db_query') + expect(dbQuery4.span.attributes['db.statement']).toContain('COMMIT') }) + }) - describe('tracing connect', () => { - let _prisma: PrismaClient + describeIf(!clientMeta.dataProxy)('tracing connect', () => { + let _prisma: PrismaClient - beforeEach(() => { - _prisma = newPrismaClient() - }) + beforeEach(() => { + _prisma = newPrismaClient() + }) - afterEach(async () => { - await _prisma.$disconnect() - }) + afterEach(async () => { + await _prisma.$disconnect() + }) - // Different order of traces between binary and library - testIf(getClientEngineType() === ClientEngineType.Library)( - 'should trace the implicit $connect call', - async () => { - const email = faker.internet.email() + // Different order of traces between binary and library + testIf(getClientEngineType() === ClientEngineType.Library)('should trace the implicit $connect call', async () => { + const email = faker.internet.email() - await _prisma.user.findMany({ - where: { - email: email, - }, - }) + await _prisma.user.findMany({ + where: { + email: email, + }, + }) - const tree = await waitForSpanTree() + const tree = await waitForSpanTree() - expect(cleanSpanTreeForSnapshot(tree)).toMatchSnapshot() + expect(cleanSpanTreeForSnapshot(tree)).toMatchSnapshot() - expect(tree.span.name).toEqual('prisma:client:operation') - expect(tree.span.attributes['method']).toEqual('findMany') - expect(tree.span.attributes['model']).toEqual('User') + expect(tree.span.name).toEqual('prisma:client:operation') + expect(tree.span.attributes['method']).toEqual('findMany') + expect(tree.span.attributes['model']).toEqual('User') - expect(tree.children).toHaveLength(3) + expect(tree.children).toHaveLength(3) - const connect = (tree?.children || [])[0] as unknown as Tree - expect(connect.span.name).toEqual('prisma:client:connect') + const connect = (tree?.children || [])[0] as unknown as Tree + expect(connect.span.name).toEqual('prisma:client:connect') - const serialize = (tree?.children || [])[1] as unknown as Tree - expect(serialize.span.name).toEqual('prisma:client:serialize') + const serialize = (tree?.children || [])[1] as unknown as Tree + expect(serialize.span.name).toEqual('prisma:client:serialize') - expect(connect.children).toHaveLength(0) + expect(connect.children).toHaveLength(0) - const engine = (tree?.children || [])[2] as unknown as Tree - expect(engine.span.name).toEqual('prisma:engine') + const engine = (tree?.children || [])[2] as unknown as Tree + expect(engine.span.name).toEqual('prisma:engine') - const getConnection = (engine.children || [])[0] - expect(getConnection.span.name).toEqual('prisma:engine:connection') + const getConnection = (engine.children || [])[0] + expect(getConnection.span.name).toEqual('prisma:engine:connection') - if (provider === 'mongodb') { - expect(engine.children).toHaveLength(3) + if (provider === 'mongodb') { + expect(engine.children).toHaveLength(3) - const dbQuery1 = (engine.children || [])[1] - expect(dbQuery1.span.name).toEqual('prisma:engine:db_query') - expect(dbQuery1.span.attributes['db.statement']).toContain('db.User.findMany(*)') + const dbQuery1 = (engine.children || [])[1] + expect(dbQuery1.span.name).toEqual('prisma:engine:db_query') + expect(dbQuery1.span.attributes['db.statement']).toContain('db.User.findMany(*)') - const engineSerialize = (engine.children || [])[2] - expect(engineSerialize.span.name).toEqual('prisma:engine:serialize') + const engineSerialize = (engine.children || [])[2] + expect(engineSerialize.span.name).toEqual('prisma:engine:serialize') - return - } + return + } - expect(engine.children).toHaveLength(3) + expect(engine.children).toHaveLength(3) - const select = (engine.children || [])[1] - expect(select.span.name).toEqual('prisma:engine:db_query') - expect(select.span.attributes['db.statement']).toContain('SELECT') + const select = (engine.children || [])[1] + expect(select.span.name).toEqual('prisma:engine:db_query') + expect(select.span.attributes['db.statement']).toContain('SELECT') - const engineSerialize = (engine.children || [])[2] - expect(engineSerialize.span.name).toEqual('prisma:engine:serialize') - }, - ) + const engineSerialize = (engine.children || [])[2] + expect(engineSerialize.span.name).toEqual('prisma:engine:serialize') }) + }) - describe('tracing disconnect', () => { - let _prisma: PrismaClient + describeIf(!clientMeta.dataProxy)('tracing disconnect', () => { + let _prisma: PrismaClient - beforeAll(async () => { - _prisma = newPrismaClient() - await _prisma.$connect() - }) + beforeAll(async () => { + _prisma = newPrismaClient() + await _prisma.$connect() + }) - test('should trace $disconnect', async () => { - await _prisma.$disconnect() + test('should trace $disconnect', async () => { + await _prisma.$disconnect() - const tree = await waitForSpanTree() + const tree = await waitForSpanTree() - expect(tree.span.name).toEqual('prisma:client:disconnect') - }) + expect(tree.span.name).toEqual('prisma:client:disconnect') }) - }, - { - skipDataProxy: { - runtimes: ['node', 'edge'], - reason: 'Tracing is not supported with Data Proxy yet', - }, - }, -) + }) +}) diff --git a/packages/engine-core/src/data-proxy/DataProxyEngine.ts b/packages/engine-core/src/data-proxy/DataProxyEngine.ts index 2f7654f4c2b1..08f35a3da47f 100644 --- a/packages/engine-core/src/data-proxy/DataProxyEngine.ts +++ b/packages/engine-core/src/data-proxy/DataProxyEngine.ts @@ -14,13 +14,14 @@ import type { } from '../common/Engine' import { Engine } from '../common/Engine' import { PrismaClientUnknownRequestError } from '../common/errors/PrismaClientUnknownRequestError' +import { LogLevel } from '../common/errors/utils/log' import { prismaGraphQLToJSError } from '../common/errors/utils/prismaGraphQLToJSError' import { EventEmitter } from '../common/types/Events' import { EngineMetricsOptions, Metrics, MetricsOptionsJson, MetricsOptionsPrometheus } from '../common/types/Metrics' -import { QueryEngineResult, QueryEngineResultBatchQueryResult } from '../common/types/QueryEngine' +import { EngineSpan, QueryEngineResult, QueryEngineResultBatchQueryResult } from '../common/types/QueryEngine' import type * as Tx from '../common/types/Transaction' import { getBatchRequestPayload } from '../common/utils/getBatchRequestPayload' -import { getInteractiveTransactionId } from '../common/utils/getInteractiveTransactionId' +import { createSpan, getTraceParent, getTracingConfig, TracingConfig } from '../tracing' import { DataProxyError } from './errors/DataProxyError' import { ForcedRetryError } from './errors/ForcedRetryError' import { InvalidDatasourceError } from './errors/InvalidDatasourceError' @@ -51,6 +52,94 @@ type RequestInternalOptions = { interactiveTransaction?: InteractiveTransactionOptions } +type DataProxyLog = { + span_id: string + name: string + level: LogLevel + timestamp: [number, number] + attributes: Record & { duration_ms: number } +} + +type DataProxyExtensions = { + logs?: DataProxyLog[] + traces?: EngineSpan[] +} + +type DataProxyHeaders = { + Authorization: string + 'X-capture-telemetry'?: string + traceparent?: string +} + +type HeaderBuilderOptions = { + traceparent?: string + interactiveTransaction?: InteractiveTransactionOptions +} + +class DataProxyHeaderBuilder { + readonly apiKey: string + readonly tracingConfig: TracingConfig + readonly logLevel: EngineConfig['logLevel'] + readonly logQueries: boolean | undefined + + constructor({ + apiKey, + tracingConfig, + logLevel, + logQueries, + }: { + apiKey: string + tracingConfig: TracingConfig + logLevel: EngineConfig['logLevel'] + logQueries: boolean | undefined + engine: DataProxyEngine + }) { + this.apiKey = apiKey + this.tracingConfig = tracingConfig + this.logLevel = logLevel + this.logQueries = logQueries + } + + build({ traceparent, interactiveTransaction }: HeaderBuilderOptions = {}): DataProxyHeaders { + const headers: DataProxyHeaders = { + Authorization: `Bearer ${this.apiKey}`, + } + + if (this.tracingConfig.enabled) { + headers.traceparent = traceparent ?? getTraceParent({}) + } + + if (interactiveTransaction) { + headers['X-transaction-id'] = interactiveTransaction.id + } + + const captureTelemetry: string[] = this.buildCaptureSettings() + + if (captureTelemetry.length > 0) { + headers['X-capture-telemetry'] = captureTelemetry.join(', ') + } + + return headers + } + + private buildCaptureSettings() { + const captureTelemetry: string[] = [] + + if (this.tracingConfig.enabled) { + captureTelemetry.push('tracing') + } + + if (this.logLevel) { + captureTelemetry.push(this.logLevel) + } + + if (this.logQueries) { + captureTelemetry.push('query') + } + return captureTelemetry + } +} + export class DataProxyEngine extends Engine { private inlineSchema: string readonly inlineSchemaHash: string @@ -61,8 +150,8 @@ export class DataProxyEngine extends Engine { private clientVersion: string readonly remoteClientVersion: Promise - readonly headers: { Authorization: string } readonly host: string + readonly headerBuilder: DataProxyHeaderBuilder constructor(config: EngineConfig) { super() @@ -76,13 +165,25 @@ export class DataProxyEngine extends Engine { this.logEmitter = config.logEmitter const [host, apiKey] = this.extractHostAndApiKey() - this.remoteClientVersion = P.then(() => getClientVersion(this.config)) - this.headers = { Authorization: `Bearer ${apiKey}` } this.host = host + this.headerBuilder = new DataProxyHeaderBuilder({ + apiKey, + tracingConfig: getTracingConfig(this.config.previewFeatures || []), + logLevel: config.logLevel, + logQueries: config.logQueries, + engine: this, + }) + + this.remoteClientVersion = P.then(() => getClientVersion(this.config)) + debug('host', this.host) } + apiKey(): string { + return this.headerBuilder.apiKey + } + version() { // QE is remote, we don't need to know the exact commit SHA return 'unknown' @@ -91,6 +192,48 @@ export class DataProxyEngine extends Engine { async start() {} async stop() {} + private propagateResponseExtensions(extensions: DataProxyExtensions): void { + const tracingConfig = getTracingConfig(this.config.previewFeatures || []) + + if (extensions?.logs?.length) { + extensions.logs.forEach((log) => { + switch (log.level) { + case 'debug': + case 'error': + case 'trace': + case 'warn': + case 'info': + // TODO these are propgated into the response.errors key + break + case 'query': { + let dbQuery = + typeof log.attributes?.query === 'string' && log.attributes?.query ? log.attributes.query : log.name + if (!tracingConfig.enabled) { + // The engine uses tracing to consolidate logs + // - and so we should strip the generated traceparent + // - if tracing is disabled. + // Example query: 'SELECT /* traceparent=00-123-0-01 */' + const [query] = dbQuery.split('/* traceparent') + dbQuery = query + } + + this.logEmitter.emit('query', { + query: dbQuery, + timestamp: log.timestamp, + duration: log.attributes.duration_ms, + // params: log.params - Missing + // target: log.target - Missing + }) + } + } + }) + } + + if (extensions?.traces?.length && tracingConfig.enabled) { + void createSpan({ span: true, spans: extensions.traces }) + } + } + on(event: EngineEventType, listener: (args?: any) => any): void { if (event === 'beforeExit') { // TODO: hook into the process @@ -116,7 +259,7 @@ export class DataProxyEngine extends Engine { private async uploadSchema() { const response = await request(await this.url('schema'), { method: 'PUT', - headers: this.headers, + headers: this.headerBuilder.build(), body: this.inlineSchema, clientVersion: this.clientVersion, }) @@ -141,7 +284,6 @@ export class DataProxyEngine extends Engine { { query }: EngineQuery, { traceparent, interactiveTransaction, customDataProxyFetch }: RequestOptions, ) { - this.logEmitter.emit('query', { query }) // TODO: `elapsed`? return this.requestInternal({ body: { query, variables: {} }, @@ -155,13 +297,6 @@ export class DataProxyEngine extends Engine { queries: EngineQuery[], { traceparent, transaction, customDataProxyFetch }: RequestBatchOptions, ): Promise[]> { - const isTransaction = Boolean(transaction) - this.logEmitter.emit('query', { - query: `Batch${isTransaction ? ' in transaction' : ''} (${queries.length}):\n${queries - .map((q) => q.query) - .join('\n')}`, - }) - const interactiveTransaction = transaction?.kind === 'itx' ? transaction.options : undefined const body = getBatchRequestPayload(queries, transaction) @@ -201,20 +336,11 @@ export class DataProxyEngine extends Engine { logHttpCall(url) - const headers: Record = {} - if (traceparent) { - headers.traceparent = traceparent - } - - if (interactiveTransaction) { - headers['X-transaction-id'] = interactiveTransaction.id - } - const response = await request( url, { method: 'POST', - headers: { ...headers, ...this.headers }, + headers: this.headerBuilder.build({ traceparent, interactiveTransaction }), body: JSON.stringify(body), clientVersion: this.clientVersion, }, @@ -229,6 +355,10 @@ export class DataProxyEngine extends Engine { await this.handleError(e) const data = await response.json() + const extensions = data.extensions as DataProxyExtensions | undefined + if (extensions) { + this.propagateResponseExtensions(extensions) + } // TODO: headers contain `x-elapsed` and it needs to be returned @@ -278,7 +408,7 @@ export class DataProxyEngine extends Engine { const response = await request(url, { method: 'POST', - headers: { ...headers, ...this.headers }, + headers: this.headerBuilder.build({ traceparent: headers.traceparent }), body, clientVersion: this.clientVersion, }) @@ -287,6 +417,12 @@ export class DataProxyEngine extends Engine { await this.handleError(err) const json = await response.json() + + const extensions = json.extensions as DataProxyExtensions | undefined + if (extensions) { + this.propagateResponseExtensions(extensions) + } + const id = json.id as string const endpoint = json['data-proxy'].endpoint as string @@ -298,10 +434,16 @@ export class DataProxyEngine extends Engine { const response = await request(url, { method: 'POST', - headers: { ...headers, ...this.headers }, + headers: this.headerBuilder.build({ traceparent: headers.traceparent }), clientVersion: this.clientVersion, }) + const json = await response.json() + const extensions = json.extensions as DataProxyExtensions | undefined + if (extensions) { + this.propagateResponseExtensions(extensions) + } + const err = await responseToError(response, this.clientVersion) await this.handleError(err) diff --git a/packages/engine-core/src/data-proxy/utils/request.ts b/packages/engine-core/src/data-proxy/utils/request.ts index 1aa4070aee61..6ea2ad064aa9 100644 --- a/packages/engine-core/src/data-proxy/utils/request.ts +++ b/packages/engine-core/src/data-proxy/utils/request.ts @@ -104,8 +104,10 @@ async function nodeFetch(url: string, options: RequestOptions = {}): Promise { // we execute the https request and build a fetch response out of it const request = https.request(url, httpsOptions, (response) => { - // eslint-disable-next-line prettier/prettier - const { statusCode, headers: { location } } = response + const { + statusCode, + headers: { location }, + } = response if (statusCode! >= 301 && statusCode! <= 399 && location) { if (location.startsWith('http') === false) { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d8972ba4cbf5..10569fb9919d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -236,7 +236,7 @@ importers: '@prisma/instrumentation': workspace:* '@prisma/internals': workspace:* '@prisma/migrate': workspace:* - '@prisma/mini-proxy': 0.3.0 + '@prisma/mini-proxy': 0.6.4 '@swc-node/register': 1.5.4 '@swc/core': 1.3.14 '@swc/jest': 0.2.24 @@ -316,7 +316,7 @@ importers: '@prisma/instrumentation': link:../instrumentation '@prisma/internals': link:../internals '@prisma/migrate': link:../migrate - '@prisma/mini-proxy': 0.3.0 + '@prisma/mini-proxy': 0.6.4 '@swc-node/register': 1.5.4_ldaqumno46ke76prz5kcgkjhhy '@swc/core': 1.3.14 '@swc/jest': 0.2.24_@swc+core@1.3.14 @@ -2410,15 +2410,15 @@ packages: dev: true optional: true - /@eslint/eslintrc/1.3.3: - resolution: {integrity: sha512-uj3pT6Mg+3t39fvLrj8iuCIJ38zKO9FpGtJ4BBJebJhEwjoT+KLVNCcHT5QC9NGRIEi7fZ0ZR8YRb884auB4Lg==} + /@eslint/eslintrc/1.4.1: + resolution: {integrity: sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: ajv: 6.12.6 debug: 4.3.4 - espree: 9.4.0 - globals: 13.17.0 - ignore: 5.2.0 + espree: 9.4.1 + globals: 13.19.0 + ignore: 5.2.4 import-fresh: 3.3.0 js-yaml: 4.1.0 minimatch: 3.1.2 @@ -2452,8 +2452,8 @@ packages: resolution: {integrity: sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==} dev: true - /@humanwhocodes/config-array/0.11.6: - resolution: {integrity: sha512-jJr+hPTJYKyDILJfhNSHsjiwXYf26Flsz8DvNndOsHs5pwSnpGUEy8yzF0JYhCEvTDdV2vuOK5tt8BVhwO5/hg==} + /@humanwhocodes/config-array/0.11.8: + resolution: {integrity: sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==} engines: {node: '>=10.10.0'} dependencies: '@humanwhocodes/object-schema': 1.2.1 @@ -3071,7 +3071,7 @@ packages: engines: {node: '>= 8'} dependencies: '@nodelib/fs.scandir': 2.1.5 - fastq: 1.13.0 + fastq: 1.15.0 /@npmcli/arborist/4.3.1: resolution: {integrity: sha512-yMRgZVDpwWjplorzt9SFSaakWx6QIK248Nw4ZFgkrAy/GvJaFRaSZzE6nD7JBK5r8g/+PTxFq5Wj/sfciE7x+A==} @@ -3412,8 +3412,8 @@ packages: /@prisma/engines-version/4.10.0-57.2160401104b9937426e26638f1fb54cf6b52d7b0: resolution: {integrity: sha512-QfDsAe4/BCF8kZ5+FFTweX4KDV6J3ZrR+b0S64zvL610FS0gYJWW6RBqG9N6a+pyC/T9Y8IHDBJujfY7ZsLlIA==} - /@prisma/mini-proxy/0.3.0: - resolution: {integrity: sha512-Vcp8L5S66qM9aUdolqzwF7FBZUSWSb+PzzOE8ikgCB58Sw8DVS1TZG2KbWNbmMre1e/naxwOIFdovJpO/Jg+Ww==} + /@prisma/mini-proxy/0.6.4: + resolution: {integrity: sha512-soUbebrPZfNg9zJCALHQAZd0E5tvcgi1zmyonHUe3Inqa6nMOGvdDWAcDUl1OHkZ22WDFpWkj5qOZTULfdNH2w==} engines: {node: '>=14.17'} hasBin: true dev: true @@ -3478,7 +3478,7 @@ packages: jju: 1.4.0 resolve: 1.17.0 semver: 7.3.8 - z-schema: 5.0.4 + z-schema: 5.0.5 dev: true /@rushstack/rig-package/0.3.17: @@ -3556,7 +3556,7 @@ packages: engines: {node: '>= 12.13.0', npm: '>= 6.12.0'} dependencies: '@slack/types': 1.10.0 - '@types/node': 18.11.18 + '@types/node': 14.18.36 axios: 0.21.4 transitivePeerDependencies: - debug @@ -4130,7 +4130,7 @@ packages: /@types/fs-extra/9.0.13: resolution: {integrity: sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==} dependencies: - '@types/node': 14.18.32 + '@types/node': 14.18.36 dev: true /@types/geojson/7946.0.10: @@ -4140,14 +4140,14 @@ packages: resolution: {integrity: sha512-l6NQsDDyQUVeoTynNpC9uRvCUint/gSUXQA2euwmTuWGvPY5LSDUu6tkCtJB2SvGQlJQzLaKqcGZP4//7EDveA==} dependencies: '@types/minimatch': 5.1.2 - '@types/node': 18.11.18 + '@types/node': 14.18.36 dev: true /@types/glob/8.0.1: resolution: {integrity: sha512-8bVUjXZvJacUFkJXHdyZ9iH1Eaj5V7I8c4NdH5sQJsdXkqT4CA5Dhb4yb4VE/3asyx4L9ayZr1NIhTsWHczmMw==} dependencies: '@types/minimatch': 5.1.2 - '@types/node': 18.11.18 + '@types/node': 14.18.36 dev: true /@types/graceful-fs/4.1.5: @@ -4159,7 +4159,7 @@ packages: /@types/graphviz/0.0.35: resolution: {integrity: sha512-AqGaB/5M0nMPOPVuOd3PQGS0glhJ4Fzg4CcZ4IZ1M0ezuz7OJEuz3D0xwr3qn8sdf3Xo7ZJl9qR1c5XkzrdY+w==} dependencies: - '@types/node': 18.11.18 + '@types/node': 14.18.36 dev: true /@types/http-cache-semantics/4.0.1: @@ -4264,7 +4264,7 @@ packages: /@types/node-fetch/2.6.2: resolution: {integrity: sha512-DHqhlq5jeESLy19TYhLakJ07kNumXWjcDdxXsLUMJZ6ue8VZJj4kLPQVE/2mdHh3xZziNF1xppu5lwmS53HR+A==} dependencies: - '@types/node': 18.11.18 + '@types/node': 14.18.36 form-data: 3.0.1 dev: true @@ -4276,10 +4276,6 @@ packages: resolution: {integrity: sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==} dev: true - /@types/node/14.18.32: - resolution: {integrity: sha512-Y6S38pFr04yb13qqHf8uk1nHE3lXgQ30WZbv1mLliV9pt0NjvqdWttLcrOYLnXbOafknVYRHZGoMSpR9UwfYow==} - dev: true - /@types/node/14.18.36: resolution: {integrity: sha512-FXKWbsJ6a1hIrRxv+FoukuHnGTgEzKYGi7kilfMae96AL9UNkPFNWJEEYWzdRI9ooIkbr4AKldyuSTLql06vLQ==} dev: true @@ -4341,7 +4337,7 @@ packages: /@types/redis/2.8.32: resolution: {integrity: sha512-7jkMKxcGq9p242exlbsVzuJb57KqHRhNl4dHoQu2Y5v9bCAbtIXXH0R3HleSQW4CTOqpHIYUW3t6tpUj4BVQ+w==} dependencies: - '@types/node': 18.11.18 + '@types/node': 14.18.36 dev: true /@types/resolve/1.20.2: @@ -4364,8 +4360,8 @@ packages: '@types/node': 18.11.5 dev: true - /@types/semver/7.3.12: - resolution: {integrity: sha512-WwA1MW0++RfXmCr12xeYOOC5baSC9mSb0ZqCquFzKhcoF4TvHu5MKOuXsncgZcpVFhB1pXd5hZmM0ryAoCp12A==} + /@types/semver/7.3.13: + resolution: {integrity: sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==} dev: true /@types/sqlite3/3.1.8: @@ -4475,7 +4471,7 @@ packages: '@typescript-eslint/utils': 5.42.1_rmayb2veg2btbq6mbmnyivgasy debug: 4.3.4 eslint: 8.27.0 - ignore: 5.2.0 + ignore: 5.2.4 natural-compare-lite: 1.4.0 regexpp: 3.2.0 semver: 7.3.8 @@ -4513,6 +4509,14 @@ packages: '@typescript-eslint/visitor-keys': 5.42.1 dev: true + /@typescript-eslint/scope-manager/5.49.0: + resolution: {integrity: sha512-clpROBOiMIzpbWNxCe1xDK14uPZh35u4QaZO1GddilEzoCLAEz4szb51rBpdgurs5k2YzPtJeTEN3qVbG+LRUQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + '@typescript-eslint/types': 5.49.0 + '@typescript-eslint/visitor-keys': 5.49.0 + dev: true + /@typescript-eslint/type-utils/5.42.1_rmayb2veg2btbq6mbmnyivgasy: resolution: {integrity: sha512-WWiMChneex5w4xPIX56SSnQQo0tEOy5ZV2dqmj8Z371LJ0E+aymWD25JQ/l4FOuuX+Q49A7pzh/CGIQflxMVXg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -4538,6 +4542,11 @@ packages: engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true + /@typescript-eslint/types/5.49.0: + resolution: {integrity: sha512-7If46kusG+sSnEpu0yOz2xFv5nRz158nzEXnJFCGVEHWnuzolXKwrH5Bsf9zsNlOQkyZuk0BZKKoJQI+1JPBBg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dev: true + /@typescript-eslint/typescript-estree/5.42.1_typescript@4.8.4: resolution: {integrity: sha512-qElc0bDOuO0B8wDhhW4mYVgi/LZL+igPwXtV87n69/kYC/7NG3MES0jHxJNCr4EP7kY1XVsRy8C/u3DYeTKQmw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -4559,6 +4568,27 @@ packages: - supports-color dev: true + /@typescript-eslint/typescript-estree/5.49.0_typescript@4.8.4: + resolution: {integrity: sha512-PBdx+V7deZT/3GjNYPVQv1Nc0U46dAHbIuOG8AZ3on3vuEKiPDwFE/lG1snN2eUB9IhF7EyF7K1hmTcLztNIsA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/types': 5.49.0 + '@typescript-eslint/visitor-keys': 5.49.0 + debug: 4.3.4 + globby: 11.1.0 + is-glob: 4.0.3 + semver: 7.3.8 + tsutils: 3.21.0_typescript@4.8.4 + typescript: 4.8.4 + transitivePeerDependencies: + - supports-color + dev: true + /@typescript-eslint/utils/5.42.1_rmayb2veg2btbq6mbmnyivgasy: resolution: {integrity: sha512-Gxvf12xSp3iYZd/fLqiQRD4uKZjDNR01bQ+j8zvhPjpsZ4HmvEFL/tC4amGNyxN9Rq+iqvpHLhlqx6KTxz9ZyQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -4566,7 +4596,7 @@ packages: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 dependencies: '@types/json-schema': 7.0.11 - '@types/semver': 7.3.12 + '@types/semver': 7.3.13 '@typescript-eslint/scope-manager': 5.42.1 '@typescript-eslint/types': 5.42.1 '@typescript-eslint/typescript-estree': 5.42.1_typescript@4.8.4 @@ -4579,6 +4609,26 @@ packages: - typescript dev: true + /@typescript-eslint/utils/5.49.0_rmayb2veg2btbq6mbmnyivgasy: + resolution: {integrity: sha512-cPJue/4Si25FViIb74sHCLtM4nTSBXtLx1d3/QT6mirQ/c65bV8arBEebBJJizfq8W2YyMoPI/WWPFWitmNqnQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + dependencies: + '@types/json-schema': 7.0.11 + '@types/semver': 7.3.13 + '@typescript-eslint/scope-manager': 5.49.0 + '@typescript-eslint/types': 5.49.0 + '@typescript-eslint/typescript-estree': 5.49.0_typescript@4.8.4 + eslint: 8.27.0 + eslint-scope: 5.1.1 + eslint-utils: 3.0.0_eslint@8.27.0 + semver: 7.3.8 + transitivePeerDependencies: + - supports-color + - typescript + dev: true + /@typescript-eslint/visitor-keys/5.42.1: resolution: {integrity: sha512-LOQtSF4z+hejmpUvitPlc4hA7ERGoj2BVkesOcG91HCn8edLGUXbTrErmutmPbl8Bo9HjAvOO/zBKQHExXNA2A==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -4587,6 +4637,14 @@ packages: eslint-visitor-keys: 3.3.0 dev: true + /@typescript-eslint/visitor-keys/5.49.0: + resolution: {integrity: sha512-v9jBMjpNWyn8B6k/Mjt6VbUS4J1GvUlR4x3Y+ibnP1z7y7V4n0WRz+50DY6+Myj0UaXVSuUlHohO+eZ8IJEnkg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + '@typescript-eslint/types': 5.49.0 + eslint-visitor-keys: 3.3.0 + dev: true + /abbrev/1.1.1: resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==} dev: true @@ -4599,12 +4657,12 @@ packages: negotiator: 0.6.3 dev: true - /acorn-jsx/5.3.2_acorn@8.8.1: + /acorn-jsx/5.3.2_acorn@8.8.2: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 dependencies: - acorn: 8.8.1 + acorn: 8.8.2 dev: true /acorn-walk/8.2.0: @@ -4618,6 +4676,12 @@ packages: hasBin: true dev: true + /acorn/8.8.2: + resolution: {integrity: sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==} + engines: {node: '>=0.4.0'} + hasBin: true + dev: true + /agent-base/6.0.2: resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} engines: {node: '>= 6.0.0'} @@ -4728,6 +4792,14 @@ packages: picomatch: 2.3.1 dev: true + /anymatch/3.1.3: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} + engines: {node: '>= 8'} + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.1 + dev: true + /aproba/2.0.0: resolution: {integrity: sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==} dev: true @@ -4815,14 +4887,14 @@ packages: resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==} dev: true - /array-includes/3.1.5: - resolution: {integrity: sha512-iSDYZMMyTPkiFasVqfuAQnWAYcvO/SeBSCGKePoEthjp4LEMTe4uLc7b025o4jAZpHhihh8xPo99TNWUWWkGDQ==} + /array-includes/3.1.6: + resolution: {integrity: sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==} engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.2 define-properties: 1.1.4 - es-abstract: 1.20.4 - get-intrinsic: 1.1.3 + es-abstract: 1.21.1 + get-intrinsic: 1.2.0 is-string: 1.0.7 dev: true @@ -4830,13 +4902,13 @@ packages: resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} engines: {node: '>=8'} - /array.prototype.flat/1.3.0: - resolution: {integrity: sha512-12IUEkHsAhA4DY5s0FPgNXIdc8VRSqD9Zp78a5au9abH/SOBrsp082JOWFNTjkMozh8mqcdiKuaLGhPeYztxSw==} + /array.prototype.flat/1.3.1: + resolution: {integrity: sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==} engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.2 define-properties: 1.1.4 - es-abstract: 1.20.4 + es-abstract: 1.21.1 es-shim-unscopables: 1.0.0 dev: true @@ -5378,7 +5450,7 @@ packages: resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==} engines: {node: '>= 8.10.0'} dependencies: - anymatch: 3.1.2 + anymatch: 3.1.3 braces: 3.0.2 glob-parent: 5.1.2 is-binary-path: 2.1.0 @@ -5409,6 +5481,11 @@ packages: resolution: {integrity: sha512-yH4RezKOGlOhxkmhbeNuC4eYZKAUsEaGtBuBzDDP1eFUKiccDWzBABxBfOx31IDwDIXMTxWuwAxUGModvkbuVw==} dev: true + /ci-info/3.7.1: + resolution: {integrity: sha512-4jYS4MOAaCIStSRwiuxc4B8MYhIe676yO1sYGzARnjXkWpmzZMMYxY6zu8WYWDhSuth5zhrQ1rhNSibyyvv4/w==} + engines: {node: '>=8'} + dev: true + /cjs-module-lexer/1.2.2: resolution: {integrity: sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==} dev: true @@ -5604,6 +5681,11 @@ packages: resolution: {integrity: sha512-5EEkTNyHNGFPD2H+c/dXXfQZYa/scCKasxWcXJaWnNJ99pnQN9Vnmqow+p+PlFPE63Q6mThaZws1T+HxfpgtPw==} engines: {node: ^12.20.0 || >=14} + /commander/9.5.0: + resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==} + engines: {node: ^12.20.0 || >=14} + dev: true + /common-ancestor-path/1.0.1: resolution: {integrity: sha512-L3sHRo1pXXEqX8VU28kfgUY+YGsk09hPqZiZmLacNib6XNTCM8ubYeT7ryXQw8asB1sKgcU5lkB7ONug08aB8w==} dev: true @@ -5766,8 +5848,8 @@ packages: engines: {node: '>=8'} dev: true - /data-uri-to-buffer/4.0.0: - resolution: {integrity: sha512-Vr3mLBA8qWmcuschSLAOogKgQ/Jwxulv3RNE4FXnYWRGujzrRWQI4m12fQqRkwX06C0KanhLr4hK+GydchZsaA==} + /data-uri-to-buffer/4.0.1: + resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==} engines: {node: '>= 12'} dev: true @@ -6142,6 +6224,45 @@ packages: string.prototype.trimstart: 1.0.5 unbox-primitive: 1.0.2 + /es-abstract/1.21.1: + resolution: {integrity: sha512-QudMsPOz86xYz/1dG1OuGBKOELjCh99IIWHLzy5znUB6j8xG2yMA7bfTV86VSqKF+Y/H08vQPR+9jyXpuC6hfg==} + engines: {node: '>= 0.4'} + dependencies: + available-typed-arrays: 1.0.5 + call-bind: 1.0.2 + es-set-tostringtag: 2.0.1 + es-to-primitive: 1.2.1 + function-bind: 1.1.1 + function.prototype.name: 1.1.5 + get-intrinsic: 1.2.0 + get-symbol-description: 1.0.0 + globalthis: 1.0.3 + gopd: 1.0.1 + has: 1.0.3 + has-property-descriptors: 1.0.0 + has-proto: 1.0.1 + has-symbols: 1.0.3 + internal-slot: 1.0.4 + is-array-buffer: 3.0.1 + is-callable: 1.2.7 + is-negative-zero: 2.0.2 + is-regex: 1.1.4 + is-shared-array-buffer: 1.0.2 + is-string: 1.0.7 + is-typed-array: 1.1.10 + is-weakref: 1.0.2 + object-inspect: 1.12.3 + object-keys: 1.1.1 + object.assign: 4.1.4 + regexp.prototype.flags: 1.4.3 + safe-regex-test: 1.0.0 + string.prototype.trimend: 1.0.6 + string.prototype.trimstart: 1.0.6 + typed-array-length: 1.0.4 + unbox-primitive: 1.0.2 + which-typed-array: 1.1.9 + dev: true + /es-aggregate-error/1.0.8: resolution: {integrity: sha512-AKUb5MKLWMozPlFRHOKqWD7yta5uaEhH21qwtnf6FlKjNjTJOoqFi0/G14+FfSkIQhhu6X68Af4xgRC6y8qG4A==} engines: {node: '>= 0.4'} @@ -6154,6 +6275,15 @@ packages: globalthis: 1.0.3 has-property-descriptors: 1.0.0 + /es-set-tostringtag/2.0.1: + resolution: {integrity: sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==} + engines: {node: '>= 0.4'} + dependencies: + get-intrinsic: 1.2.0 + has: 1.0.3 + has-tostringtag: 1.0.0 + dev: true + /es-shim-unscopables/1.0.0: resolution: {integrity: sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==} dependencies: @@ -6469,16 +6599,17 @@ packages: supports-hyperlinks: 2.3.0 dev: true - /eslint-import-resolver-node/0.3.6: - resolution: {integrity: sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==} + /eslint-import-resolver-node/0.3.7: + resolution: {integrity: sha512-gozW2blMLJCeFpBwugLTGyvVjNoeo1knonXAcatC6bjPBZitotxdWf7Gimr25N4c0AAOo4eOUfaG82IJPDpqCA==} dependencies: debug: 3.2.7 + is-core-module: 2.11.0 resolve: 1.22.1 transitivePeerDependencies: - supports-color dev: true - /eslint-module-utils/2.7.4_l3rkqmr6ujglf4zsfjyz5e7jai: + /eslint-module-utils/2.7.4_4mu4zcmlslje6odeqmnmef5pn4: resolution: {integrity: sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==} engines: {node: '>=4'} peerDependencies: @@ -6502,7 +6633,7 @@ packages: '@typescript-eslint/parser': 5.42.1_rmayb2veg2btbq6mbmnyivgasy debug: 3.2.7 eslint: 8.27.0 - eslint-import-resolver-node: 0.3.6 + eslint-import-resolver-node: 0.3.7 transitivePeerDependencies: - supports-color dev: true @@ -6515,7 +6646,7 @@ packages: dependencies: escape-string-regexp: 1.0.5 eslint: 8.27.0 - ignore: 5.2.0 + ignore: 5.2.4 dev: true /eslint-plugin-import/2.26.0_jnohwm7eexgw7uduhweedcbnpe: @@ -6529,18 +6660,18 @@ packages: optional: true dependencies: '@typescript-eslint/parser': 5.42.1_rmayb2veg2btbq6mbmnyivgasy - array-includes: 3.1.5 - array.prototype.flat: 1.3.0 + array-includes: 3.1.6 + array.prototype.flat: 1.3.1 debug: 2.6.9 doctrine: 2.1.0 eslint: 8.27.0 - eslint-import-resolver-node: 0.3.6 - eslint-module-utils: 2.7.4_l3rkqmr6ujglf4zsfjyz5e7jai + eslint-import-resolver-node: 0.3.7 + eslint-module-utils: 2.7.4_4mu4zcmlslje6odeqmnmef5pn4 has: 1.0.3 is-core-module: 2.11.0 is-glob: 4.0.3 minimatch: 3.1.2 - object.values: 1.1.5 + object.values: 1.1.6 resolve: 1.22.1 tsconfig-paths: 3.14.1 transitivePeerDependencies: @@ -6563,7 +6694,7 @@ packages: optional: true dependencies: '@typescript-eslint/eslint-plugin': 5.42.1_2udltptbznfmezdozpdoa2aemq - '@typescript-eslint/utils': 5.42.1_rmayb2veg2btbq6mbmnyivgasy + '@typescript-eslint/utils': 5.49.0_rmayb2veg2btbq6mbmnyivgasy eslint: 8.27.0 transitivePeerDependencies: - supports-color @@ -6640,8 +6771,8 @@ packages: engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} hasBin: true dependencies: - '@eslint/eslintrc': 1.3.3 - '@humanwhocodes/config-array': 0.11.6 + '@eslint/eslintrc': 1.4.1 + '@humanwhocodes/config-array': 0.11.8 '@humanwhocodes/module-importer': 1.0.1 '@nodelib/fs.walk': 1.2.8 ajv: 6.12.6 @@ -6653,21 +6784,21 @@ packages: eslint-scope: 7.1.1 eslint-utils: 3.0.0_eslint@8.27.0 eslint-visitor-keys: 3.3.0 - espree: 9.4.0 + espree: 9.4.1 esquery: 1.4.0 esutils: 2.0.3 fast-deep-equal: 3.1.3 file-entry-cache: 6.0.1 find-up: 5.0.0 glob-parent: 6.0.2 - globals: 13.17.0 + globals: 13.19.0 grapheme-splitter: 1.0.4 - ignore: 5.2.0 + ignore: 5.2.4 import-fresh: 3.3.0 imurmurhash: 0.1.4 is-glob: 4.0.3 is-path-inside: 3.0.3 - js-sdsl: 4.1.5 + js-sdsl: 4.3.0 js-yaml: 4.1.0 json-stable-stringify-without-jsonify: 1.0.1 levn: 0.4.1 @@ -6683,12 +6814,12 @@ packages: - supports-color dev: true - /espree/9.4.0: - resolution: {integrity: sha512-DQmnRpLj7f6TgN/NYb0MTzJXL+vJF9h3pHy4JhCIs3zwcgez8xmGg3sXHcEO97BrmO2OSvCwMdfdlyl+E9KjOw==} + /espree/9.4.1: + resolution: {integrity: sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: - acorn: 8.8.1 - acorn-jsx: 5.3.2_acorn@8.8.1 + acorn: 8.8.2 + acorn-jsx: 5.3.2_acorn@8.8.2 eslint-visitor-keys: 3.3.0 dev: true @@ -6945,8 +7076,8 @@ packages: dev: false optional: true - /fastq/1.13.0: - resolution: {integrity: sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==} + /fastq/1.15.0: + resolution: {integrity: sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==} dependencies: reusify: 1.0.4 @@ -7300,6 +7431,14 @@ packages: has: 1.0.3 has-symbols: 1.0.3 + /get-intrinsic/1.2.0: + resolution: {integrity: sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==} + dependencies: + function-bind: 1.1.1 + has: 1.0.3 + has-symbols: 1.0.3 + dev: true + /get-own-enumerable-property-symbols/3.0.2: resolution: {integrity: sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==} dev: true @@ -7393,7 +7532,7 @@ packages: fs.realpath: 1.0.0 inflight: 1.0.6 inherits: 2.0.4 - minimatch: 5.1.0 + minimatch: 5.1.6 once: 1.4.0 dev: true @@ -7451,8 +7590,8 @@ packages: engines: {node: '>=4'} dev: true - /globals/13.17.0: - resolution: {integrity: sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==} + /globals/13.19.0: + resolution: {integrity: sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ==} engines: {node: '>=8'} dependencies: type-fest: 0.20.2 @@ -7471,7 +7610,7 @@ packages: array-union: 2.1.0 dir-glob: 3.0.1 fast-glob: 3.2.12 - ignore: 5.2.0 + ignore: 5.2.4 merge2: 1.4.1 slash: 3.0.0 @@ -7481,11 +7620,17 @@ packages: dependencies: dir-glob: 3.0.1 fast-glob: 3.2.12 - ignore: 5.2.0 + ignore: 5.2.4 merge2: 1.4.1 slash: 4.0.0 dev: true + /gopd/1.0.1: + resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} + dependencies: + get-intrinsic: 1.2.0 + dev: true + /got/11.8.5: resolution: {integrity: sha512-o0Je4NvQObAuZPHLFoRSkdG2lTgtcynqymzg2Vupdx6PorhaT5MCbIyXG6d4D94kk8ZG57QeosgdiqfJWhEhlQ==} engines: {node: '>=10.19.0'} @@ -7619,6 +7764,11 @@ packages: dependencies: get-intrinsic: 1.1.3 + /has-proto/1.0.1: + resolution: {integrity: sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==} + engines: {node: '>= 0.4'} + dev: true + /has-symbol-support-x/1.4.2: resolution: {integrity: sha512-3ToOva++HaW+eCpgqZrCfN51IPB+7bJNVT6CUATzueB5Heb8o6Nam0V3HG5dlDvZU1Gn5QLcbahiKw/XVk5JJw==} dev: true @@ -7783,8 +7933,8 @@ packages: minimatch: 3.1.2 dev: true - /ignore/5.2.0: - resolution: {integrity: sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==} + /ignore/5.2.4: + resolution: {integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==} engines: {node: '>= 4'} /import-fresh/3.3.0: @@ -7897,6 +8047,15 @@ packages: has: 1.0.3 side-channel: 1.0.4 + /internal-slot/1.0.4: + resolution: {integrity: sha512-tA8URYccNzMo94s5MQZgH8NB/XTa6HsOo0MLfXTKKEnHVVdegzaQoFZ7Jp44bdvLvY2waT5dc+j5ICEswhi7UQ==} + engines: {node: '>= 0.4'} + dependencies: + get-intrinsic: 1.2.0 + has: 1.0.3 + side-channel: 1.0.4 + dev: true + /interpret/1.4.0: resolution: {integrity: sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==} engines: {node: '>= 0.10'} @@ -7931,6 +8090,14 @@ packages: has-tostringtag: 1.0.0 dev: true + /is-array-buffer/3.0.1: + resolution: {integrity: sha512-ASfLknmY8Xa2XtB4wmbz13Wu202baeA18cJBCeCy0wXUHZF0IPyVEXqKEcd+t2fNSLLL1vC6k7lxZEojNbISXQ==} + dependencies: + call-bind: 1.0.2 + get-intrinsic: 1.2.0 + is-typed-array: 1.1.10 + dev: true + /is-arrayish/0.2.1: resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} @@ -7968,7 +8135,7 @@ packages: resolution: {integrity: sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==} hasBin: true dependencies: - ci-info: 3.5.0 + ci-info: 3.7.1 dev: true /is-core-module/2.11.0: @@ -8177,14 +8344,14 @@ packages: dependencies: has-symbols: 1.0.3 - /is-typed-array/1.1.9: - resolution: {integrity: sha512-kfrlnTTn8pZkfpJMUgYD7YZ3qzeJgWUn8XfVYBARc4wnmNOmLbmuuaAs3q5fvB0UJOn6yHAKaGTPM7d6ezoD/A==} + /is-typed-array/1.1.10: + resolution: {integrity: sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==} engines: {node: '>= 0.4'} dependencies: available-typed-arrays: 1.0.5 call-bind: 1.0.2 - es-abstract: 1.20.4 for-each: 0.3.3 + gopd: 1.0.1 has-tostringtag: 1.0.0 dev: true @@ -9311,8 +9478,8 @@ packages: /js-md4/0.3.2: resolution: {integrity: sha512-/GDnfQYsltsjRswQhN9fhv3EMw2sCpUdrdxyWDOUK7eyD++r3gRhzgiQgc/x4MAv2i1iuQ4lxO5mvqM3vj4bwA==} - /js-sdsl/4.1.5: - resolution: {integrity: sha512-08bOAKweV2NUC1wqTtf3qZlnpOX/R2DU9ikpjOHs0H+ibQv3zpncVQg6um4uYtRtrwIX8M4Nh3ytK4HGlYAq7Q==} + /js-sdsl/4.3.0: + resolution: {integrity: sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ==} dev: true /js-tokens/4.0.0: @@ -9373,8 +9540,8 @@ packages: resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==} dev: true - /json5/1.0.1: - resolution: {integrity: sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==} + /json5/1.0.2: + resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==} hasBin: true dependencies: minimist: 1.2.7 @@ -9541,17 +9708,17 @@ packages: dependencies: cli-truncate: 3.1.0 colorette: 2.0.19 - commander: 9.4.1 + commander: 9.5.0 debug: 4.3.4 execa: 6.1.0 lilconfig: 2.0.5 listr2: 4.0.5 micromatch: 4.0.5 normalize-path: 3.0.0 - object-inspect: 1.12.2 + object-inspect: 1.12.3 pidtree: 0.6.0 string-argv: 0.3.1 - yaml: 2.1.3 + yaml: 2.2.1 transitivePeerDependencies: - enquirer - supports-color @@ -9571,7 +9738,7 @@ packages: log-update: 4.0.0 p-map: 4.0.0 rfdc: 1.3.0 - rxjs: 7.5.7 + rxjs: 7.8.0 through: 2.3.8 wrap-ansi: 7.0.0 dev: true @@ -10069,6 +10236,13 @@ packages: dependencies: brace-expansion: 2.0.1 + /minimatch/5.1.6: + resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} + engines: {node: '>=10'} + dependencies: + brace-expansion: 2.0.1 + dev: true + /minimist-options/3.0.2: resolution: {integrity: sha512-FyBrT/d0d4+uiZRbqznPXqw3IpZZG3gl3wKWiX784FycUKVwBt0uLBFkQrtE4tZOrgo78nZp2jnKz3L65T5LdQ==} engines: {node: '>= 4'} @@ -10379,7 +10553,7 @@ packages: resolution: {integrity: sha512-MhuzNwdURnZ1Cp4XTazr69K0BTizsBroX7Zx3UgDSVcZYKF/6p0CBe4EUb/hLqmzVhl0UpYfgRljQ4yxE+iCxA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} dependencies: - data-uri-to-buffer: 4.0.0 + data-uri-to-buffer: 4.0.1 fetch-blob: 3.2.0 formdata-polyfill: 4.0.10 dev: true @@ -10603,6 +10777,10 @@ packages: /object-inspect/1.12.2: resolution: {integrity: sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==} + /object-inspect/1.12.3: + resolution: {integrity: sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==} + dev: true + /object-keys/1.1.1: resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} engines: {node: '>= 0.4'} @@ -10616,13 +10794,13 @@ packages: has-symbols: 1.0.3 object-keys: 1.1.1 - /object.values/1.1.5: - resolution: {integrity: sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg==} + /object.values/1.1.6: + resolution: {integrity: sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==} engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.2 define-properties: 1.1.4 - es-abstract: 1.20.4 + es-abstract: 1.21.1 dev: true /on-finished/2.3.0: @@ -11331,6 +11509,11 @@ packages: resolution: {integrity: sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==} engines: {node: '>=6'} + /punycode/2.3.0: + resolution: {integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==} + engines: {node: '>=6'} + dev: true + /pupa/2.1.1: resolution: {integrity: sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A==} engines: {node: '>=8'} @@ -11777,6 +11960,12 @@ packages: tslib: 2.4.1 dev: true + /rxjs/7.8.0: + resolution: {integrity: sha512-F2+gxDshqmIub1KdvZkaEfGDwLNpPvk9Fs6LD/MyQxNgMds/WH9OdDDXOmxUZpME+iSK3rQCctkL0DYyytUqMg==} + dependencies: + tslib: 2.4.1 + dev: true + /safe-buffer/5.1.2: resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} @@ -12255,6 +12444,14 @@ packages: define-properties: 1.1.4 es-abstract: 1.20.4 + /string.prototype.trimend/1.0.6: + resolution: {integrity: sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==} + dependencies: + call-bind: 1.0.2 + define-properties: 1.1.4 + es-abstract: 1.21.1 + dev: true + /string.prototype.trimstart/1.0.5: resolution: {integrity: sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg==} dependencies: @@ -12262,6 +12459,14 @@ packages: define-properties: 1.1.4 es-abstract: 1.20.4 + /string.prototype.trimstart/1.0.6: + resolution: {integrity: sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==} + dependencies: + call-bind: 1.0.2 + define-properties: 1.1.4 + es-abstract: 1.21.1 + dev: true + /string_decoder/1.1.1: resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} dependencies: @@ -12753,7 +12958,7 @@ packages: '@tsconfig/node14': 1.0.3 '@tsconfig/node16': 1.0.3 '@types/node': 14.18.36 - acorn: 8.8.1 + acorn: 8.8.2 acorn-walk: 8.2.0 arg: 4.1.3 create-require: 1.1.1 @@ -12785,7 +12990,7 @@ packages: '@tsconfig/node14': 1.0.3 '@tsconfig/node16': 1.0.3 '@types/node': 14.18.36 - acorn: 8.8.1 + acorn: 8.8.2 acorn-walk: 8.2.0 arg: 4.1.3 create-require: 1.1.1 @@ -12811,7 +13016,7 @@ packages: resolution: {integrity: sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==} dependencies: '@types/json5': 0.0.29 - json5: 1.0.1 + json5: 1.0.2 minimist: 1.2.7 strip-bom: 3.0.0 dev: true @@ -12930,6 +13135,14 @@ packages: mime-types: 2.1.35 dev: true + /typed-array-length/1.0.4: + resolution: {integrity: sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==} + dependencies: + call-bind: 1.0.2 + for-each: 0.3.3 + is-typed-array: 1.1.10 + dev: true + /typedarray-to-buffer/3.1.5: resolution: {integrity: sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==} dependencies: @@ -13061,7 +13274,7 @@ packages: /uri-js/4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} dependencies: - punycode: 2.1.1 + punycode: 2.3.0 dev: true /url-parse-lax/1.0.0: @@ -13099,8 +13312,8 @@ packages: inherits: 2.0.4 is-arguments: 1.1.1 is-generator-function: 1.0.10 - is-typed-array: 1.1.9 - which-typed-array: 1.1.8 + is-typed-array: 1.1.10 + which-typed-array: 1.1.9 dev: true /utils-merge/1.0.1: @@ -13250,16 +13463,16 @@ packages: path-exists: 4.0.0 dev: true - /which-typed-array/1.1.8: - resolution: {integrity: sha512-Jn4e5PItbcAHyLoRDwvPj1ypu27DJbtdYXUa5zsinrUx77Uvfb0cXwwnGMTn7cjUfhhqgVQnVJCwF+7cgU7tpw==} + /which-typed-array/1.1.9: + resolution: {integrity: sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==} engines: {node: '>= 0.4'} dependencies: available-typed-arrays: 1.0.5 call-bind: 1.0.2 - es-abstract: 1.20.4 for-each: 0.3.3 + gopd: 1.0.1 has-tostringtag: 1.0.0 - is-typed-array: 1.1.9 + is-typed-array: 1.1.10 dev: true /which/1.3.1: @@ -13372,8 +13585,8 @@ packages: /yallist/4.0.0: resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} - /yaml/2.1.3: - resolution: {integrity: sha512-AacA8nRULjKMX2DvWvOAdBZMOfQlypSFkjcOcu9FalllIDJ1kvlREzcdIZmidQUqqeMv7jorHjq2HlLv/+c2lg==} + /yaml/2.2.1: + resolution: {integrity: sha512-e0WHiYql7+9wr4cWMx3TVQrNwejKaEe7/rHNmQmqRjazfOP5W8PB6Jpebb5o6fIapbz9o9+2ipcaTM2ZwDI6lw==} engines: {node: '>= 14'} dev: true @@ -13578,8 +13791,8 @@ packages: wrap-ansi: 2.1.0 dev: true - /z-schema/5.0.4: - resolution: {integrity: sha512-gm/lx3hDzJNcLwseIeQVm1UcwhWIKpSB4NqH89pTBtFns4k/HDHudsICtvG05Bvw/Mv3jMyk700y5dadueLHdA==} + /z-schema/5.0.5: + resolution: {integrity: sha512-D7eujBWkLa3p2sIpJA0d1pr7es+a7m0vFAnZLlCEKq/Ij2k0MLi9Br2UPxoxdYystm5K1yeBGzub0FlYUEWj2Q==} engines: {node: '>=8.0.0'} hasBin: true dependencies: @@ -13587,7 +13800,7 @@ packages: lodash.isequal: 4.5.0 validator: 13.7.0 optionalDependencies: - commander: 2.20.3 + commander: 9.5.0 dev: true /zip-stream/4.1.0: @@ -13616,5 +13829,5 @@ packages: node-fetch: 3.2.10 ps-tree: 1.2.0 which: 2.0.2 - yaml: 2.1.3 + yaml: 2.2.1 dev: true