better-auth-studio 1.1.3-beta.8 → 1.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +145 -16
- package/dist/adapters/astro.d.ts +0 -1
- package/dist/adapters/astro.js +5 -2
- package/dist/adapters/cloudflare-workers.d.ts +101 -0
- package/dist/adapters/cloudflare-workers.js +494 -0
- package/dist/adapters/elysia.d.ts +0 -1
- package/dist/adapters/elysia.js +7 -33
- package/dist/adapters/express.d.ts +0 -1
- package/dist/adapters/express.js +4 -1
- package/dist/adapters/hono.d.ts +0 -1
- package/dist/adapters/hono.js +7 -27
- package/dist/adapters/nextjs.d.ts +0 -1
- package/dist/adapters/nextjs.js +5 -2
- package/dist/adapters/nuxt.d.ts +0 -1
- package/dist/adapters/nuxt.js +5 -2
- package/dist/adapters/remix.d.ts +0 -1
- package/dist/adapters/remix.js +5 -2
- package/dist/adapters/solid-start.d.ts +0 -1
- package/dist/adapters/solid-start.js +5 -2
- package/dist/adapters/svelte-kit.d.ts +0 -1
- package/dist/adapters/svelte-kit.js +5 -2
- package/dist/adapters/tanstack-start.d.ts +0 -1
- package/dist/adapters/tanstack-start.js +36 -8
- package/dist/add-svelte-kit-env-modules.d.ts +0 -1
- package/dist/add-svelte-kit-env-modules.js +0 -1
- package/dist/auth-adapter.d.ts +5 -2
- package/dist/auth-adapter.js +39 -4
- package/dist/cli/commands/init.d.ts +0 -1
- package/dist/cli/commands/init.js +0 -1
- package/dist/cli.d.ts +0 -1
- package/dist/cli.js +6 -1
- package/dist/config.d.ts +0 -1
- package/dist/config.js +0 -1
- package/dist/core/handler.d.ts +0 -1
- package/dist/core/handler.js +36 -5
- package/dist/data.d.ts +10 -4
- package/dist/data.js +109 -19
- package/dist/geo-service.d.ts +0 -1
- package/dist/geo-service.js +0 -1
- package/dist/get-tsconfig-info.d.ts +0 -1
- package/dist/get-tsconfig-info.js +0 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.js +0 -1
- package/dist/providers/events/helpers.d.ts +3 -2
- package/dist/providers/events/helpers.js +303 -93
- package/dist/public/assets/main-C-R_HO98.css +1 -0
- package/dist/public/assets/main-DDypFItU.js +1302 -0
- package/dist/public/index.html +2 -2
- package/dist/public/shaders.png +0 -0
- package/dist/routes/api-router.d.ts +2 -3
- package/dist/routes/api-router.js +0 -1
- package/dist/routes.d.ts +2 -3
- package/dist/routes.js +813 -172
- package/dist/studio.d.ts +0 -1
- package/dist/studio.js +6 -4
- package/dist/types/events.d.ts +0 -1
- package/dist/types/events.js +0 -1
- package/dist/types/handler.d.ts +13 -3
- package/dist/types/handler.js +0 -1
- package/dist/types/index.d.ts +0 -1
- package/dist/types/index.js +0 -1
- package/dist/utils/access-rules.d.ts +19 -0
- package/dist/utils/access-rules.js +126 -0
- package/dist/utils/auth-callbacks-injector.d.ts +0 -1
- package/dist/utils/auth-callbacks-injector.js +0 -1
- package/dist/utils/database-detection.d.ts +0 -1
- package/dist/utils/database-detection.js +33 -4
- package/dist/utils/event-ingestion.d.ts +0 -1
- package/dist/utils/event-ingestion.js +1 -1
- package/dist/utils/hook-injector.d.ts +0 -1
- package/dist/utils/hook-injector.js +2 -2
- package/dist/utils/html-injector.d.ts +1 -7
- package/dist/utils/html-injector.js +15 -1
- package/dist/utils/org-hooks-injector.d.ts +0 -1
- package/dist/utils/org-hooks-injector.js +0 -1
- package/dist/utils/package-json.d.ts +1 -1
- package/dist/utils/package-json.js +21 -1
- package/dist/utils/paths.d.ts +0 -1
- package/dist/utils/paths.js +0 -1
- package/dist/utils/reason-messages.d.ts +0 -1
- package/dist/utils/reason-messages.js +0 -1
- package/dist/utils/session.d.ts +0 -1
- package/dist/utils/session.js +0 -1
- package/dist/utils.d.ts +0 -1
- package/dist/utils.js +0 -1
- package/package.json +4 -4
- package/dist/adapters/astro.d.ts.map +0 -1
- package/dist/adapters/astro.js.map +0 -1
- package/dist/adapters/elysia.d.ts.map +0 -1
- package/dist/adapters/elysia.js.map +0 -1
- package/dist/adapters/express.d.ts.map +0 -1
- package/dist/adapters/express.js.map +0 -1
- package/dist/adapters/hono.d.ts.map +0 -1
- package/dist/adapters/hono.js.map +0 -1
- package/dist/adapters/nextjs.d.ts.map +0 -1
- package/dist/adapters/nextjs.js.map +0 -1
- package/dist/adapters/nuxt.d.ts.map +0 -1
- package/dist/adapters/nuxt.js.map +0 -1
- package/dist/adapters/remix.d.ts.map +0 -1
- package/dist/adapters/remix.js.map +0 -1
- package/dist/adapters/solid-start.d.ts.map +0 -1
- package/dist/adapters/solid-start.js.map +0 -1
- package/dist/adapters/svelte-kit.d.ts.map +0 -1
- package/dist/adapters/svelte-kit.js.map +0 -1
- package/dist/adapters/tanstack-start.d.ts.map +0 -1
- package/dist/adapters/tanstack-start.js.map +0 -1
- package/dist/add-svelte-kit-env-modules.d.ts.map +0 -1
- package/dist/add-svelte-kit-env-modules.js.map +0 -1
- package/dist/auth-adapter.d.ts.map +0 -1
- package/dist/auth-adapter.js.map +0 -1
- package/dist/cli/commands/init.d.ts.map +0 -1
- package/dist/cli/commands/init.js.map +0 -1
- package/dist/cli.d.ts.map +0 -1
- package/dist/cli.js.map +0 -1
- package/dist/config.d.ts.map +0 -1
- package/dist/config.js.map +0 -1
- package/dist/core/handler.d.ts.map +0 -1
- package/dist/core/handler.js.map +0 -1
- package/dist/data.d.ts.map +0 -1
- package/dist/data.js.map +0 -1
- package/dist/geo-service.d.ts.map +0 -1
- package/dist/geo-service.js.map +0 -1
- package/dist/get-tsconfig-info.d.ts.map +0 -1
- package/dist/get-tsconfig-info.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/providers/events/helpers.d.ts.map +0 -1
- package/dist/providers/events/helpers.js.map +0 -1
- package/dist/public/assets/main-Bi83bOQp.js +0 -1216
- package/dist/public/assets/main-Dx_SZlEy.css +0 -1
- package/dist/routes/api-router.d.ts.map +0 -1
- package/dist/routes/api-router.js.map +0 -1
- package/dist/routes.d.ts.map +0 -1
- package/dist/routes.js.map +0 -1
- package/dist/studio.d.ts.map +0 -1
- package/dist/studio.js.map +0 -1
- package/dist/types/events.d.ts.map +0 -1
- package/dist/types/events.js.map +0 -1
- package/dist/types/handler.d.ts.map +0 -1
- package/dist/types/handler.js.map +0 -1
- package/dist/types/index.d.ts.map +0 -1
- package/dist/types/index.js.map +0 -1
- package/dist/utils/auth-callbacks-injector.d.ts.map +0 -1
- package/dist/utils/auth-callbacks-injector.js.map +0 -1
- package/dist/utils/auth-callbacks-wrapper.d.ts +0 -7
- package/dist/utils/auth-callbacks-wrapper.d.ts.map +0 -1
- package/dist/utils/auth-callbacks-wrapper.js +0 -133
- package/dist/utils/auth-callbacks-wrapper.js.map +0 -1
- package/dist/utils/database-detection.d.ts.map +0 -1
- package/dist/utils/database-detection.js.map +0 -1
- package/dist/utils/database-hook-injector.d.ts +0 -3
- package/dist/utils/database-hook-injector.d.ts.map +0 -1
- package/dist/utils/database-hook-injector.js +0 -145
- package/dist/utils/database-hook-injector.js.map +0 -1
- package/dist/utils/email-otp-hooks-injector.d.ts +0 -45
- package/dist/utils/email-otp-hooks-injector.d.ts.map +0 -1
- package/dist/utils/email-otp-hooks-injector.js +0 -141
- package/dist/utils/email-otp-hooks-injector.js.map +0 -1
- package/dist/utils/event-ingestion.d.ts.map +0 -1
- package/dist/utils/event-ingestion.js.map +0 -1
- package/dist/utils/hook-injector.d.ts.map +0 -1
- package/dist/utils/hook-injector.js.map +0 -1
- package/dist/utils/html-injector.d.ts.map +0 -1
- package/dist/utils/html-injector.js.map +0 -1
- package/dist/utils/org-hooks-injector.d.ts.map +0 -1
- package/dist/utils/org-hooks-injector.js.map +0 -1
- package/dist/utils/org-hooks-wrapper.d.ts +0 -80
- package/dist/utils/org-hooks-wrapper.d.ts.map +0 -1
- package/dist/utils/org-hooks-wrapper.js +0 -807
- package/dist/utils/org-hooks-wrapper.js.map +0 -1
- package/dist/utils/organization-hooks-wrapper.d.ts +0 -44
- package/dist/utils/organization-hooks-wrapper.d.ts.map +0 -1
- package/dist/utils/organization-hooks-wrapper.js +0 -345
- package/dist/utils/organization-hooks-wrapper.js.map +0 -1
- package/dist/utils/package-json.d.ts.map +0 -1
- package/dist/utils/package-json.js.map +0 -1
- package/dist/utils/paths.d.ts.map +0 -1
- package/dist/utils/paths.js.map +0 -1
- package/dist/utils/reason-messages.d.ts.map +0 -1
- package/dist/utils/reason-messages.js.map +0 -1
- package/dist/utils/server-init.d.ts +0 -10
- package/dist/utils/server-init.d.ts.map +0 -1
- package/dist/utils/server-init.js +0 -40
- package/dist/utils/server-init.js.map +0 -1
- package/dist/utils/session.d.ts.map +0 -1
- package/dist/utils/session.js.map +0 -1
- package/dist/utils.d.ts.map +0 -1
- package/dist/utils.js.map +0 -1
- package/public/assets/main-Bi83bOQp.js +0 -1216
- package/public/assets/main-Dx_SZlEy.css +0 -1
- package/public/favicon.svg +0 -6
- package/public/index.html +0 -14
- package/public/logo.png +0 -0
- package/public/vite.svg +0 -5
- package/scripts/download-geolite2.js +0 -42
- package/scripts/generate-default-db.js +0 -462
package/dist/index.js
CHANGED
|
@@ -5,4 +5,3 @@ export { defineStudioConfig, STUDIO_TOOL_IDS } from "./types/handler.js";
|
|
|
5
5
|
export { injectLastSeenAtHooks } from "./utils/hook-injector.js";
|
|
6
6
|
export { checkEventIngestionHealth, emitEvent, getEventIngestionProvider, getEventQueueSize, initializeEventIngestion, isEventIngestionInitialized, shutdownEventIngestion, } from "./utils/event-ingestion.js";
|
|
7
7
|
import "./utils/server-init.js";
|
|
8
|
-
//# sourceMappingURL=index.js.map
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import type { AuthEvent, EventIngestionProvider } from "../../types/events.js";
|
|
2
|
+
type PostgresProviderClientType = "postgres" | "prisma" | "drizzle" | "kysely";
|
|
2
3
|
export declare function createPostgresProvider(options: {
|
|
3
4
|
client: any;
|
|
4
5
|
tableName?: string;
|
|
5
6
|
schema?: string;
|
|
6
|
-
clientType?:
|
|
7
|
+
clientType?: PostgresProviderClientType;
|
|
7
8
|
}): EventIngestionProvider;
|
|
8
9
|
export declare function createSqliteProvider(options: {
|
|
9
10
|
client: any;
|
|
@@ -33,4 +34,4 @@ export declare function createStorageProvider(options: {
|
|
|
33
34
|
adapter: any;
|
|
34
35
|
tableName?: string;
|
|
35
36
|
}): EventIngestionProvider;
|
|
36
|
-
|
|
37
|
+
export {};
|
|
@@ -1,3 +1,37 @@
|
|
|
1
|
+
function isKyselyClient(client, clientType) {
|
|
2
|
+
const hasExecuteQuery = typeof client?.executeQuery === "function";
|
|
3
|
+
if (clientType === "kysely") {
|
|
4
|
+
return hasExecuteQuery;
|
|
5
|
+
}
|
|
6
|
+
return hasExecuteQuery && typeof client?.selectFrom === "function";
|
|
7
|
+
}
|
|
8
|
+
function createKyselyCompiledQuery(sql, parameters = []) {
|
|
9
|
+
return {
|
|
10
|
+
sql,
|
|
11
|
+
parameters,
|
|
12
|
+
queryId: { queryId: `bas_${Date.now()}_${Math.random().toString(36).slice(2)}` },
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
async function executeKyselyQuery(client, query, params = []) {
|
|
16
|
+
return await client.executeQuery(createKyselyCompiledQuery(query, params));
|
|
17
|
+
}
|
|
18
|
+
function getEventInsertParams(event) {
|
|
19
|
+
return [
|
|
20
|
+
event.id,
|
|
21
|
+
event.type,
|
|
22
|
+
event.timestamp,
|
|
23
|
+
event.status || "success",
|
|
24
|
+
event.userId || null,
|
|
25
|
+
event.sessionId || null,
|
|
26
|
+
event.organizationId || null,
|
|
27
|
+
JSON.stringify(event.metadata || {}),
|
|
28
|
+
event.ipAddress || null,
|
|
29
|
+
event.userAgent || null,
|
|
30
|
+
event.source,
|
|
31
|
+
event.display?.message || null,
|
|
32
|
+
event.display?.severity || null,
|
|
33
|
+
];
|
|
34
|
+
}
|
|
1
35
|
export function createPostgresProvider(options) {
|
|
2
36
|
const { client, tableName = "auth_events", schema = "public", clientType } = options;
|
|
3
37
|
// Validate client is provided
|
|
@@ -18,12 +52,15 @@ export function createPostgresProvider(options) {
|
|
|
18
52
|
const hasExecuteRaw = client?.$executeRaw;
|
|
19
53
|
const hasExecute = client?.execute;
|
|
20
54
|
const hasUnsafe = actualClient?.unsafe || client?.$client?.unsafe || client?.unsafe;
|
|
21
|
-
|
|
55
|
+
const hasKysely = isKyselyClient(client, clientType);
|
|
56
|
+
if (!hasQuery && !hasExecuteRaw && !hasExecute && !hasUnsafe && !hasKysely) {
|
|
22
57
|
const errorMessage = clientType === "prisma"
|
|
23
58
|
? "Invalid Prisma client. Client must have a `$executeRaw` method."
|
|
24
59
|
: clientType === "drizzle"
|
|
25
60
|
? "Invalid Drizzle client. Drizzle instance must wrap a postgres-js (with `unsafe` method) or pg (with `query` method) client."
|
|
26
|
-
:
|
|
61
|
+
: clientType === "kysely"
|
|
62
|
+
? "Invalid Kysely client. Client must have an `executeQuery` method."
|
|
63
|
+
: "Invalid Postgres client. Client must have either a `query` method (pg Pool/Client), `$executeRaw` method (Prisma client), or `executeQuery` method (Kysely client).";
|
|
27
64
|
throw new Error(errorMessage);
|
|
28
65
|
}
|
|
29
66
|
// Ensure table exists
|
|
@@ -39,6 +76,11 @@ export function createPostgresProvider(options) {
|
|
|
39
76
|
return await client.$executeRawUnsafe(query);
|
|
40
77
|
};
|
|
41
78
|
}
|
|
79
|
+
else if (hasKysely) {
|
|
80
|
+
executeQuery = async (query) => {
|
|
81
|
+
return await executeKyselyQuery(client, query);
|
|
82
|
+
};
|
|
83
|
+
}
|
|
42
84
|
else if (clientType === "drizzle") {
|
|
43
85
|
// Drizzle client - use $client which exposes the underlying client
|
|
44
86
|
if (actualClient?.unsafe) {
|
|
@@ -69,7 +111,7 @@ export function createPostgresProvider(options) {
|
|
|
69
111
|
};
|
|
70
112
|
}
|
|
71
113
|
else {
|
|
72
|
-
throw new Error(`Postgres client doesn't support $executeRaw or query method. Available properties: ${Object.keys(client).join(", ")}`);
|
|
114
|
+
throw new Error(`Postgres client doesn't support $executeRaw, executeQuery, or query method. Available properties: ${Object.keys(client).join(", ")}`);
|
|
73
115
|
}
|
|
74
116
|
// Use CREATE TABLE IF NOT EXISTS (simpler and more reliable)
|
|
75
117
|
const createTableQuery = `
|
|
@@ -141,7 +183,32 @@ export function createPostgresProvider(options) {
|
|
|
141
183
|
return {
|
|
142
184
|
async ingest(event) {
|
|
143
185
|
await ensureTableSync();
|
|
144
|
-
if (
|
|
186
|
+
if (hasKysely) {
|
|
187
|
+
try {
|
|
188
|
+
await executeKyselyQuery(client, `INSERT INTO ${schema}.${tableName}
|
|
189
|
+
(id, type, timestamp, status, user_id, session_id, organization_id, metadata, ip_address, user_agent, source, display_message, display_severity)
|
|
190
|
+
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)`, getEventInsertParams(event));
|
|
191
|
+
}
|
|
192
|
+
catch (error) {
|
|
193
|
+
console.error(`Failed to insert event (${event.type}) into ${schema}.${tableName}:`, error);
|
|
194
|
+
if (error.code === "42P01") {
|
|
195
|
+
tableEnsured = false;
|
|
196
|
+
await ensureTableSync();
|
|
197
|
+
try {
|
|
198
|
+
await executeKyselyQuery(client, `INSERT INTO ${schema}.${tableName}
|
|
199
|
+
(id, type, timestamp, status, user_id, session_id, organization_id, metadata, ip_address, user_agent, source, display_message, display_severity)
|
|
200
|
+
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)`, getEventInsertParams(event));
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
catch (retryError) {
|
|
204
|
+
console.error(`Retry after table creation also failed:`, retryError);
|
|
205
|
+
throw retryError;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
throw error;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
else if (clientType === "prisma" || client.$executeRaw) {
|
|
145
212
|
const query = `
|
|
146
213
|
INSERT INTO ${schema}.${tableName}
|
|
147
214
|
(id, type, timestamp, status, user_id, session_id, organization_id, metadata, ip_address, user_agent, source, display_message, display_severity)
|
|
@@ -176,7 +243,7 @@ export function createPostgresProvider(options) {
|
|
|
176
243
|
if (useUnsafe) {
|
|
177
244
|
// postgres-js client - use unsafe() for raw SQL
|
|
178
245
|
const query = `
|
|
179
|
-
INSERT INTO ${schema}.${tableName}
|
|
246
|
+
INSERT INTO ${schema}.${tableName}
|
|
180
247
|
(id, type, timestamp, status, user_id, session_id, organization_id, metadata, ip_address, user_agent, source, display_message, display_severity)
|
|
181
248
|
VALUES ('${event.id}'::uuid, '${event.type}', '${event.timestamp.toISOString()}', '${event.status || "success"}', ${event.userId ? `'${event.userId.replace(/'/g, "''")}'` : "NULL"}, ${event.sessionId ? `'${event.sessionId.replace(/'/g, "''")}'` : "NULL"}, ${event.organizationId ? `'${event.organizationId.replace(/'/g, "''")}'` : "NULL"}, '${JSON.stringify(event.metadata || {}).replace(/'/g, "''")}'::jsonb, ${event.ipAddress ? `'${event.ipAddress.replace(/'/g, "''")}'` : "NULL"}, ${event.userAgent ? `'${event.userAgent.replace(/'/g, "''")}'` : "NULL"}, '${event.source}', ${event.display?.message ? `'${event.display.message.replace(/'/g, "''")}'` : "NULL"}, ${event.display?.severity ? `'${event.display.severity}'` : "NULL"})
|
|
182
249
|
`;
|
|
@@ -205,21 +272,7 @@ export function createPostgresProvider(options) {
|
|
|
205
272
|
try {
|
|
206
273
|
await queryClient.query(`INSERT INTO ${schema}.${tableName}
|
|
207
274
|
(id, type, timestamp, status, user_id, session_id, organization_id, metadata, ip_address, user_agent, source, display_message, display_severity)
|
|
208
|
-
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)`, [
|
|
209
|
-
event.id,
|
|
210
|
-
event.type,
|
|
211
|
-
event.timestamp,
|
|
212
|
-
event.status || "success",
|
|
213
|
-
event.userId || null,
|
|
214
|
-
event.sessionId || null,
|
|
215
|
-
event.organizationId || null,
|
|
216
|
-
JSON.stringify(event.metadata || {}),
|
|
217
|
-
event.ipAddress || null,
|
|
218
|
-
event.userAgent || null,
|
|
219
|
-
event.source,
|
|
220
|
-
event.display?.message || null,
|
|
221
|
-
event.display?.severity || null,
|
|
222
|
-
]);
|
|
275
|
+
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)`, [...getEventInsertParams(event)]);
|
|
223
276
|
}
|
|
224
277
|
catch (error) {
|
|
225
278
|
console.error(`Failed to insert event (${event.type}) into ${schema}.${tableName}:`, error);
|
|
@@ -229,21 +282,7 @@ export function createPostgresProvider(options) {
|
|
|
229
282
|
try {
|
|
230
283
|
await queryClient.query(`INSERT INTO ${schema}.${tableName}
|
|
231
284
|
(id, type, timestamp, status, user_id, session_id, organization_id, metadata, ip_address, user_agent, source, display_message, display_severity)
|
|
232
|
-
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)`, [
|
|
233
|
-
event.id,
|
|
234
|
-
event.type,
|
|
235
|
-
event.timestamp,
|
|
236
|
-
event.status || "success",
|
|
237
|
-
event.userId || null,
|
|
238
|
-
event.sessionId || null,
|
|
239
|
-
event.organizationId || null,
|
|
240
|
-
JSON.stringify(event.metadata || {}),
|
|
241
|
-
event.ipAddress || null,
|
|
242
|
-
event.userAgent || null,
|
|
243
|
-
event.source,
|
|
244
|
-
event.display?.message || null,
|
|
245
|
-
event.display?.severity || null,
|
|
246
|
-
]);
|
|
285
|
+
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)`, [...getEventInsertParams(event)]);
|
|
247
286
|
return;
|
|
248
287
|
}
|
|
249
288
|
catch (retryError) {
|
|
@@ -271,7 +310,34 @@ export function createPostgresProvider(options) {
|
|
|
271
310
|
return;
|
|
272
311
|
await ensureTableSync();
|
|
273
312
|
// Support Prisma client ($executeRaw), Drizzle instance, or standard pg client (query)
|
|
274
|
-
if (
|
|
313
|
+
if (hasKysely) {
|
|
314
|
+
const PARAMS_PER_EVENT = 13;
|
|
315
|
+
const MAX_PARAMS = 65535;
|
|
316
|
+
const CHUNK_SIZE = Math.floor(MAX_PARAMS / PARAMS_PER_EVENT) - 1;
|
|
317
|
+
for (let chunkStart = 0; chunkStart < events.length; chunkStart += CHUNK_SIZE) {
|
|
318
|
+
const chunk = events.slice(chunkStart, chunkStart + CHUNK_SIZE);
|
|
319
|
+
const values = chunk
|
|
320
|
+
.map((_, i) => {
|
|
321
|
+
const base = i * PARAMS_PER_EVENT;
|
|
322
|
+
return `($${base + 1}, $${base + 2}, $${base + 3}, $${base + 4}, $${base + 5}, $${base + 6}, $${base + 7}, $${base + 8}, $${base + 9}, $${base + 10}, $${base + 11}, $${base + 12}, $${base + 13})`;
|
|
323
|
+
})
|
|
324
|
+
.join(", ");
|
|
325
|
+
const query = `
|
|
326
|
+
INSERT INTO ${schema}.${tableName}
|
|
327
|
+
(id, type, timestamp, status, user_id, session_id, organization_id, metadata, ip_address, user_agent, source, display_message, display_severity)
|
|
328
|
+
VALUES ${values}
|
|
329
|
+
`;
|
|
330
|
+
const params = chunk.flatMap((event) => getEventInsertParams(event));
|
|
331
|
+
try {
|
|
332
|
+
await executeKyselyQuery(client, query, params);
|
|
333
|
+
}
|
|
334
|
+
catch (error) {
|
|
335
|
+
console.error(`Failed to insert batch chunk (${chunk.length} events) into ${schema}.${tableName}:`, error);
|
|
336
|
+
throw error;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
else if (clientType === "prisma" || client.$executeRaw) {
|
|
275
341
|
// Prisma client - use $executeRawUnsafe for batch inserts
|
|
276
342
|
const CHUNK_SIZE = 500; // Reasonable chunk size for string-based queries
|
|
277
343
|
for (let i = 0; i < events.length; i += CHUNK_SIZE) {
|
|
@@ -339,21 +405,7 @@ export function createPostgresProvider(options) {
|
|
|
339
405
|
(id, type, timestamp, status, user_id, session_id, organization_id, metadata, ip_address, user_agent, source, display_message, display_severity)
|
|
340
406
|
VALUES ${values}
|
|
341
407
|
`;
|
|
342
|
-
const params = chunk.flatMap((event) =>
|
|
343
|
-
event.id,
|
|
344
|
-
event.type,
|
|
345
|
-
event.timestamp,
|
|
346
|
-
event.status || "success",
|
|
347
|
-
event.userId || null,
|
|
348
|
-
event.sessionId || null,
|
|
349
|
-
event.organizationId || null,
|
|
350
|
-
JSON.stringify(event.metadata || {}),
|
|
351
|
-
event.ipAddress || null,
|
|
352
|
-
event.userAgent || null,
|
|
353
|
-
event.source,
|
|
354
|
-
event.display?.message || null,
|
|
355
|
-
event.display?.severity || null,
|
|
356
|
-
]);
|
|
408
|
+
const params = chunk.flatMap((event) => getEventInsertParams(event));
|
|
357
409
|
try {
|
|
358
410
|
await batchQueryClient.query(query, params);
|
|
359
411
|
}
|
|
@@ -376,7 +428,7 @@ export function createPostgresProvider(options) {
|
|
|
376
428
|
}
|
|
377
429
|
},
|
|
378
430
|
async query(options) {
|
|
379
|
-
const { limit = 20, after, sort = "desc", type, userId, since } = options;
|
|
431
|
+
const { limit = 20, offset, after, sort = "desc", type, userId, since } = options;
|
|
380
432
|
let queryFn;
|
|
381
433
|
if (client.$executeRaw) {
|
|
382
434
|
// Prisma client
|
|
@@ -401,6 +453,11 @@ export function createPostgresProvider(options) {
|
|
|
401
453
|
}
|
|
402
454
|
};
|
|
403
455
|
}
|
|
456
|
+
else if (hasKysely) {
|
|
457
|
+
queryFn = async (query, params) => {
|
|
458
|
+
return await executeKyselyQuery(client, query, params || []);
|
|
459
|
+
};
|
|
460
|
+
}
|
|
404
461
|
else if (client.query) {
|
|
405
462
|
// Standard pg client (Pool or Client)
|
|
406
463
|
queryFn = async (query, params) => {
|
|
@@ -427,6 +484,9 @@ export function createPostgresProvider(options) {
|
|
|
427
484
|
.replace("$2", `'${tableName}'`);
|
|
428
485
|
checkResult = await client.$queryRawUnsafe(prismaQuery);
|
|
429
486
|
}
|
|
487
|
+
else if (hasKysely) {
|
|
488
|
+
checkResult = await queryFn(checkTableQuery, [schema, tableName]);
|
|
489
|
+
}
|
|
430
490
|
else {
|
|
431
491
|
// Standard pg client
|
|
432
492
|
checkResult = await queryFn(checkTableQuery, [schema, tableName]);
|
|
@@ -448,8 +508,8 @@ export function createPostgresProvider(options) {
|
|
|
448
508
|
const whereClauses = [];
|
|
449
509
|
const params = [];
|
|
450
510
|
let paramIndex = 1;
|
|
451
|
-
//
|
|
452
|
-
if (after) {
|
|
511
|
+
// Use cursor-based pagination only when offset is not provided
|
|
512
|
+
if (offset == null && after) {
|
|
453
513
|
if (sort === "desc") {
|
|
454
514
|
whereClauses.push(`id < $${paramIndex++}`);
|
|
455
515
|
params.push(after);
|
|
@@ -473,15 +533,29 @@ export function createPostgresProvider(options) {
|
|
|
473
533
|
}
|
|
474
534
|
const whereClause = whereClauses.length > 0 ? `WHERE ${whereClauses.join(" AND ")}` : "";
|
|
475
535
|
const orderDirection = sort === "desc" ? "DESC" : "ASC";
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
536
|
+
let query;
|
|
537
|
+
if (offset != null && offset > 0) {
|
|
538
|
+
query = `
|
|
539
|
+
SELECT id, type, timestamp, status, user_id, session_id, organization_id,
|
|
540
|
+
metadata, ip_address, user_agent, source, display_message, display_severity
|
|
541
|
+
FROM ${schema}.${tableName}
|
|
542
|
+
${whereClause}
|
|
543
|
+
ORDER BY timestamp ${orderDirection}, id ${orderDirection}
|
|
544
|
+
LIMIT $${paramIndex++} OFFSET $${paramIndex++}
|
|
545
|
+
`;
|
|
546
|
+
params.push(limit + 1, offset);
|
|
547
|
+
}
|
|
548
|
+
else {
|
|
549
|
+
query = `
|
|
550
|
+
SELECT id, type, timestamp, status, user_id, session_id, organization_id,
|
|
551
|
+
metadata, ip_address, user_agent, source, display_message, display_severity
|
|
552
|
+
FROM ${schema}.${tableName}
|
|
553
|
+
${whereClause}
|
|
554
|
+
ORDER BY timestamp ${orderDirection}, id ${orderDirection}
|
|
555
|
+
LIMIT $${paramIndex++}
|
|
556
|
+
`;
|
|
557
|
+
params.push(limit + 1);
|
|
558
|
+
}
|
|
485
559
|
try {
|
|
486
560
|
const result = await queryFn(query, params);
|
|
487
561
|
const rows = result.rows || result || [];
|
|
@@ -698,7 +772,7 @@ export function createSqliteProvider(options) {
|
|
|
698
772
|
}
|
|
699
773
|
},
|
|
700
774
|
async query(options) {
|
|
701
|
-
const { limit = 20, after, sort = "desc", type, userId, since } = options;
|
|
775
|
+
const { limit = 20, offset, after, sort = "desc", type, userId, since } = options;
|
|
702
776
|
await ensureTableSync();
|
|
703
777
|
try {
|
|
704
778
|
let query = `SELECT * FROM ${tableName} WHERE 1=1`;
|
|
@@ -715,13 +789,20 @@ export function createSqliteProvider(options) {
|
|
|
715
789
|
query += ` AND timestamp >= ?`;
|
|
716
790
|
params.push(since instanceof Date ? since.toISOString() : since);
|
|
717
791
|
}
|
|
718
|
-
if (
|
|
719
|
-
query += sort === "desc" ?
|
|
720
|
-
|
|
792
|
+
if (offset != null && offset > 0) {
|
|
793
|
+
query += ` ORDER BY timestamp ${sort === "desc" ? "DESC" : "ASC"}`;
|
|
794
|
+
query += ` LIMIT ? OFFSET ?`;
|
|
795
|
+
params.push(limit + 1, offset);
|
|
796
|
+
}
|
|
797
|
+
else {
|
|
798
|
+
if (after) {
|
|
799
|
+
query += sort === "desc" ? ` AND id < ?` : ` AND id > ?`;
|
|
800
|
+
params.push(after);
|
|
801
|
+
}
|
|
802
|
+
query += ` ORDER BY timestamp ${sort === "desc" ? "DESC" : "ASC"}`;
|
|
803
|
+
query += ` LIMIT ?`;
|
|
804
|
+
params.push(limit + 1);
|
|
721
805
|
}
|
|
722
|
-
query += ` ORDER BY timestamp ${sort === "desc" ? "DESC" : "ASC"}`;
|
|
723
|
-
query += ` LIMIT ?`;
|
|
724
|
-
params.push(limit + 1); // Fetch one extra to check if there are more
|
|
725
806
|
const stmt = actualClient.prepare(query);
|
|
726
807
|
const rows = stmt.all(...params);
|
|
727
808
|
const hasMore = rows.length > limit;
|
|
@@ -1154,7 +1235,7 @@ export function createClickHouseProvider(options) {
|
|
|
1154
1235
|
await ingestBatchFn(events);
|
|
1155
1236
|
},
|
|
1156
1237
|
async query(options) {
|
|
1157
|
-
const { limit = 20, after, sort = "desc", type, userId, since } = options;
|
|
1238
|
+
const { limit = 20, offset, after, sort = "desc", type, userId, since } = options;
|
|
1158
1239
|
const tableFullName = database ? `${database}.${table}` : table;
|
|
1159
1240
|
try {
|
|
1160
1241
|
const checkTableQuery = `EXISTS TABLE ${tableFullName}`;
|
|
@@ -1269,7 +1350,7 @@ export function createClickHouseProvider(options) {
|
|
|
1269
1350
|
}
|
|
1270
1351
|
}
|
|
1271
1352
|
const whereClauses = [];
|
|
1272
|
-
if (after) {
|
|
1353
|
+
if (offset == null && after) {
|
|
1273
1354
|
if (sort === "desc") {
|
|
1274
1355
|
whereClauses.push(`id < '${String(after).replace(/'/g, "''")}'`);
|
|
1275
1356
|
}
|
|
@@ -1285,13 +1366,12 @@ export function createClickHouseProvider(options) {
|
|
|
1285
1366
|
}
|
|
1286
1367
|
if (since) {
|
|
1287
1368
|
const sinceDate = since instanceof Date ? since : new Date(since);
|
|
1288
|
-
// ClickHouse requires DateTime type, so we need to cast the string to DateTime
|
|
1289
|
-
// Format: 'YYYY-MM-DD HH:MM:SS' or use toDateTime() function
|
|
1290
1369
|
const isoString = sinceDate.toISOString().replace("T", " ").slice(0, 19);
|
|
1291
1370
|
whereClauses.push(`timestamp >= toDateTime('${isoString.replace(/'/g, "''")}')`);
|
|
1292
1371
|
}
|
|
1293
1372
|
const whereClause = whereClauses.length > 0 ? `WHERE ${whereClauses.join(" AND ")}` : "";
|
|
1294
1373
|
const orderDirection = sort === "desc" ? "DESC" : "ASC";
|
|
1374
|
+
const offsetClause = offset != null && offset > 0 ? `OFFSET ${offset}` : "";
|
|
1295
1375
|
let query = `
|
|
1296
1376
|
SELECT id, type, timestamp, status, user_id, session_id, organization_id,
|
|
1297
1377
|
metadata, ip_address, user_agent, source, display_message, display_severity
|
|
@@ -1299,6 +1379,7 @@ export function createClickHouseProvider(options) {
|
|
|
1299
1379
|
${whereClause}
|
|
1300
1380
|
ORDER BY timestamp ${orderDirection}, id ${orderDirection}
|
|
1301
1381
|
LIMIT ${limit + 1}
|
|
1382
|
+
${offsetClause}
|
|
1302
1383
|
`;
|
|
1303
1384
|
let result;
|
|
1304
1385
|
let hasStatusColumn = true;
|
|
@@ -1412,6 +1493,132 @@ export function createStorageProvider(options) {
|
|
|
1412
1493
|
const { adapter, tableName = "auth_events" } = options;
|
|
1413
1494
|
let tableEnsured = false;
|
|
1414
1495
|
let tableEnsuringPromise = null;
|
|
1496
|
+
let resolvedModelName = null;
|
|
1497
|
+
const isMissingModelError = (error) => error?.message?.includes("not found in schema") ||
|
|
1498
|
+
error?.message?.includes("not found in model") ||
|
|
1499
|
+
error?.message?.includes("Model") ||
|
|
1500
|
+
error?.code === "P2025" ||
|
|
1501
|
+
error?.code === "42P01";
|
|
1502
|
+
const toCamelCase = (value) => value.replace(/[_-]([a-z])/g, (_match, char) => char.toUpperCase());
|
|
1503
|
+
const getModelCandidates = () => {
|
|
1504
|
+
const candidates = new Set();
|
|
1505
|
+
const addForms = (value) => {
|
|
1506
|
+
const normalized = value?.trim();
|
|
1507
|
+
if (!normalized)
|
|
1508
|
+
return;
|
|
1509
|
+
const snake = normalized.replace(/-/g, "_");
|
|
1510
|
+
const singularSnake = snake.endsWith("s") ? snake.slice(0, -1) : snake;
|
|
1511
|
+
const pluralSnake = snake.endsWith("s") ? snake : `${snake}s`;
|
|
1512
|
+
const singularCamel = toCamelCase(singularSnake);
|
|
1513
|
+
const pluralCamel = toCamelCase(pluralSnake);
|
|
1514
|
+
[
|
|
1515
|
+
normalized,
|
|
1516
|
+
snake,
|
|
1517
|
+
singularSnake,
|
|
1518
|
+
pluralSnake,
|
|
1519
|
+
singularCamel,
|
|
1520
|
+
pluralCamel,
|
|
1521
|
+
singularCamel.charAt(0).toUpperCase() + singularCamel.slice(1),
|
|
1522
|
+
pluralCamel.charAt(0).toUpperCase() + pluralCamel.slice(1),
|
|
1523
|
+
].forEach((candidate) => {
|
|
1524
|
+
if (candidate) {
|
|
1525
|
+
candidates.add(candidate);
|
|
1526
|
+
}
|
|
1527
|
+
});
|
|
1528
|
+
};
|
|
1529
|
+
addForms(tableName);
|
|
1530
|
+
addForms(tableName === "auth_events" ? "auth_event" : "auth_events");
|
|
1531
|
+
return Array.from(candidates);
|
|
1532
|
+
};
|
|
1533
|
+
const withResolvedModel = async (callback) => {
|
|
1534
|
+
const candidates = Array.from(new Set([resolvedModelName, ...getModelCandidates()].filter(Boolean)));
|
|
1535
|
+
let lastLookupError = null;
|
|
1536
|
+
for (const modelName of candidates) {
|
|
1537
|
+
try {
|
|
1538
|
+
const result = await callback(modelName);
|
|
1539
|
+
resolvedModelName = modelName;
|
|
1540
|
+
return result;
|
|
1541
|
+
}
|
|
1542
|
+
catch (error) {
|
|
1543
|
+
if (isMissingModelError(error)) {
|
|
1544
|
+
lastLookupError = error;
|
|
1545
|
+
continue;
|
|
1546
|
+
}
|
|
1547
|
+
throw error;
|
|
1548
|
+
}
|
|
1549
|
+
}
|
|
1550
|
+
if (lastLookupError) {
|
|
1551
|
+
throw lastLookupError;
|
|
1552
|
+
}
|
|
1553
|
+
throw new Error(`No event model candidates available for "${tableName}"`);
|
|
1554
|
+
};
|
|
1555
|
+
const getFieldCandidates = (field) => {
|
|
1556
|
+
switch (field) {
|
|
1557
|
+
case "userId":
|
|
1558
|
+
return ["userId", "user_id"];
|
|
1559
|
+
case "sessionId":
|
|
1560
|
+
return ["sessionId", "session_id"];
|
|
1561
|
+
case "organizationId":
|
|
1562
|
+
return ["organizationId", "organization_id"];
|
|
1563
|
+
case "ipAddress":
|
|
1564
|
+
return ["ipAddress", "ip_address"];
|
|
1565
|
+
case "userAgent":
|
|
1566
|
+
return ["userAgent", "user_agent"];
|
|
1567
|
+
case "displayMessage":
|
|
1568
|
+
return ["displayMessage", "display_message"];
|
|
1569
|
+
case "displaySeverity":
|
|
1570
|
+
return ["displaySeverity", "display_severity"];
|
|
1571
|
+
case "createdAt":
|
|
1572
|
+
return ["createdAt", "created_at"];
|
|
1573
|
+
default:
|
|
1574
|
+
return field ? [field] : [];
|
|
1575
|
+
}
|
|
1576
|
+
};
|
|
1577
|
+
const getWhereCandidates = (where) => {
|
|
1578
|
+
if (!Array.isArray(where) || where.length === 0) {
|
|
1579
|
+
return {
|
|
1580
|
+
whereCandidates: [undefined],
|
|
1581
|
+
hasAliasedFields: false,
|
|
1582
|
+
};
|
|
1583
|
+
}
|
|
1584
|
+
let hasAliasedFields = false;
|
|
1585
|
+
let combinations = [[]];
|
|
1586
|
+
for (const clause of where) {
|
|
1587
|
+
const fieldCandidates = getFieldCandidates(clause?.field);
|
|
1588
|
+
if (fieldCandidates.length > 1) {
|
|
1589
|
+
hasAliasedFields = true;
|
|
1590
|
+
}
|
|
1591
|
+
const nextCombinations = fieldCandidates.flatMap((fieldName) => combinations.map((existing) => [...existing, { ...clause, field: fieldName }]));
|
|
1592
|
+
if (nextCombinations.length > 0) {
|
|
1593
|
+
combinations = nextCombinations;
|
|
1594
|
+
}
|
|
1595
|
+
}
|
|
1596
|
+
return {
|
|
1597
|
+
whereCandidates: combinations.length > 0 ? combinations : [where],
|
|
1598
|
+
hasAliasedFields,
|
|
1599
|
+
};
|
|
1600
|
+
};
|
|
1601
|
+
const findManyWithResolvedModel = async (options) => {
|
|
1602
|
+
const { where, ...restOptions } = options;
|
|
1603
|
+
const { whereCandidates, hasAliasedFields } = getWhereCandidates(where);
|
|
1604
|
+
let lastSuccessfulEmptyResult = null;
|
|
1605
|
+
for (let index = 0; index < whereCandidates.length; index += 1) {
|
|
1606
|
+
const result = (await withResolvedModel((modelName) => adapter.findMany({
|
|
1607
|
+
...restOptions,
|
|
1608
|
+
...(whereCandidates[index] ? { where: whereCandidates[index] } : {}),
|
|
1609
|
+
model: modelName,
|
|
1610
|
+
})));
|
|
1611
|
+
if (Array.isArray(result) &&
|
|
1612
|
+
result.length === 0 &&
|
|
1613
|
+
hasAliasedFields &&
|
|
1614
|
+
index < whereCandidates.length - 1) {
|
|
1615
|
+
lastSuccessfulEmptyResult = result;
|
|
1616
|
+
continue;
|
|
1617
|
+
}
|
|
1618
|
+
return Array.isArray(result) ? result : [];
|
|
1619
|
+
}
|
|
1620
|
+
return lastSuccessfulEmptyResult ?? [];
|
|
1621
|
+
};
|
|
1415
1622
|
const ensureTable = async () => {
|
|
1416
1623
|
if (!adapter)
|
|
1417
1624
|
return;
|
|
@@ -1423,10 +1630,10 @@ export function createStorageProvider(options) {
|
|
|
1423
1630
|
try {
|
|
1424
1631
|
if (adapter.findMany) {
|
|
1425
1632
|
// Try to query the table to see if it exists
|
|
1426
|
-
await adapter.findMany({
|
|
1427
|
-
model:
|
|
1633
|
+
await withResolvedModel((modelName) => adapter.findMany({
|
|
1634
|
+
model: modelName,
|
|
1428
1635
|
limit: 1,
|
|
1429
|
-
});
|
|
1636
|
+
}));
|
|
1430
1637
|
tableEnsured = true;
|
|
1431
1638
|
return;
|
|
1432
1639
|
}
|
|
@@ -1496,8 +1703,8 @@ export function createStorageProvider(options) {
|
|
|
1496
1703
|
return {
|
|
1497
1704
|
async ingest(event) {
|
|
1498
1705
|
if (adapter.create) {
|
|
1499
|
-
await adapter.create({
|
|
1500
|
-
model:
|
|
1706
|
+
await withResolvedModel((modelName) => adapter.create({
|
|
1707
|
+
model: modelName,
|
|
1501
1708
|
data: {
|
|
1502
1709
|
id: event.id,
|
|
1503
1710
|
type: event.type,
|
|
@@ -1513,7 +1720,7 @@ export function createStorageProvider(options) {
|
|
|
1513
1720
|
displayMessage: event.display?.message,
|
|
1514
1721
|
displaySeverity: event.display?.severity,
|
|
1515
1722
|
},
|
|
1516
|
-
});
|
|
1723
|
+
}));
|
|
1517
1724
|
}
|
|
1518
1725
|
else if (adapter.insert) {
|
|
1519
1726
|
await adapter.insert({
|
|
@@ -1540,8 +1747,8 @@ export function createStorageProvider(options) {
|
|
|
1540
1747
|
// Ensure table exists before ingesting
|
|
1541
1748
|
await ensureTable();
|
|
1542
1749
|
if (adapter.createMany) {
|
|
1543
|
-
await adapter.createMany({
|
|
1544
|
-
model:
|
|
1750
|
+
await withResolvedModel((modelName) => adapter.createMany({
|
|
1751
|
+
model: modelName,
|
|
1545
1752
|
data: events.map((event) => ({
|
|
1546
1753
|
id: event.id,
|
|
1547
1754
|
type: event.type,
|
|
@@ -1557,21 +1764,21 @@ export function createStorageProvider(options) {
|
|
|
1557
1764
|
displayMessage: event.display?.message,
|
|
1558
1765
|
displaySeverity: event.display?.severity,
|
|
1559
1766
|
})),
|
|
1560
|
-
});
|
|
1767
|
+
}));
|
|
1561
1768
|
}
|
|
1562
1769
|
else {
|
|
1563
1770
|
await Promise.all(events.map((event) => this.ingest(event)));
|
|
1564
1771
|
}
|
|
1565
1772
|
},
|
|
1566
1773
|
async query(options) {
|
|
1567
|
-
const { limit = 20, after, sort = "desc", type, userId, since } = options;
|
|
1774
|
+
const { limit = 20, offset, after, sort = "desc", type, userId, since } = options;
|
|
1568
1775
|
// Ensure table exists before querying
|
|
1569
1776
|
await ensureTable();
|
|
1570
1777
|
// First, try findMany (normal path)
|
|
1571
1778
|
if (adapter && adapter.findMany) {
|
|
1572
1779
|
try {
|
|
1573
1780
|
const where = [];
|
|
1574
|
-
if (after) {
|
|
1781
|
+
if (offset == null && after) {
|
|
1575
1782
|
if (sort === "desc") {
|
|
1576
1783
|
where.push({ field: "id", operator: "<", value: after });
|
|
1577
1784
|
}
|
|
@@ -1589,12 +1796,15 @@ export function createStorageProvider(options) {
|
|
|
1589
1796
|
const sinceDate = since instanceof Date ? since : new Date(since);
|
|
1590
1797
|
where.push({ field: "timestamp", operator: ">=", value: sinceDate });
|
|
1591
1798
|
}
|
|
1592
|
-
const
|
|
1593
|
-
model: tableName,
|
|
1799
|
+
const findManyOptions = {
|
|
1594
1800
|
where,
|
|
1595
1801
|
orderBy: [{ field: "timestamp", direction: sort === "desc" ? "desc" : "asc" }],
|
|
1596
|
-
limit: limit + 1,
|
|
1597
|
-
}
|
|
1802
|
+
limit: limit + 1,
|
|
1803
|
+
};
|
|
1804
|
+
if (offset != null && offset > 0) {
|
|
1805
|
+
findManyOptions.offset = offset;
|
|
1806
|
+
}
|
|
1807
|
+
const events = await findManyWithResolvedModel(findManyOptions);
|
|
1598
1808
|
const hasMore = events.length > limit;
|
|
1599
1809
|
const paginatedEvents = events.slice(0, limit).map((event) => ({
|
|
1600
1810
|
id: event.id,
|
|
@@ -1657,7 +1867,7 @@ export function createStorageProvider(options) {
|
|
|
1657
1867
|
const whereConditions = [];
|
|
1658
1868
|
const params = [];
|
|
1659
1869
|
let paramIndex = 1;
|
|
1660
|
-
if (after) {
|
|
1870
|
+
if (offset == null && after) {
|
|
1661
1871
|
if (sort === "desc") {
|
|
1662
1872
|
whereConditions.push(`id < $${paramIndex}`);
|
|
1663
1873
|
}
|
|
@@ -1683,12 +1893,13 @@ export function createStorageProvider(options) {
|
|
|
1683
1893
|
paramIndex++;
|
|
1684
1894
|
}
|
|
1685
1895
|
const whereClause = whereConditions.length > 0 ? `WHERE ${whereConditions.join(" AND ")}` : "";
|
|
1896
|
+
const offsetSql = offset != null && offset > 0 ? ` OFFSET ${offset}` : "";
|
|
1686
1897
|
const orderDirection = sort === "desc" ? "DESC" : "ASC";
|
|
1687
1898
|
// Use appropriate raw SQL method
|
|
1688
1899
|
let queryFn;
|
|
1689
1900
|
if (sqlAdapter.$queryRawUnsafe || adapter.$queryRawUnsafe) {
|
|
1690
1901
|
// Prisma - build query with parameters embedded
|
|
1691
|
-
let query = `SELECT * FROM ${tableName} ${whereClause} ORDER BY timestamp ${orderDirection}, id ${orderDirection} LIMIT ${limit + 1}`;
|
|
1902
|
+
let query = `SELECT * FROM ${tableName} ${whereClause} ORDER BY timestamp ${orderDirection}, id ${orderDirection} LIMIT ${limit + 1}${offsetSql}`;
|
|
1692
1903
|
// Replace $1, $2, etc. with actual values for Prisma
|
|
1693
1904
|
params.forEach((param, index) => {
|
|
1694
1905
|
const placeholder = `$${index + 1}`;
|
|
@@ -1732,7 +1943,7 @@ export function createStorageProvider(options) {
|
|
|
1732
1943
|
}
|
|
1733
1944
|
else {
|
|
1734
1945
|
// Other adapters - use parameterized query
|
|
1735
|
-
const query = `SELECT * FROM ${tableName} ${whereClause} ORDER BY timestamp ${orderDirection}, id ${orderDirection} LIMIT $${paramIndex}`;
|
|
1946
|
+
const query = `SELECT * FROM ${tableName} ${whereClause} ORDER BY timestamp ${orderDirection}, id ${orderDirection} LIMIT $${paramIndex}${offsetSql}`;
|
|
1736
1947
|
params.push(limit + 1);
|
|
1737
1948
|
if (sqlAdapter.$queryRaw || adapter.$queryRaw) {
|
|
1738
1949
|
const queryMethod = sqlAdapter.$queryRaw || adapter.$queryRaw;
|
|
@@ -1788,4 +1999,3 @@ export function createStorageProvider(options) {
|
|
|
1788
1999
|
},
|
|
1789
2000
|
};
|
|
1790
2001
|
}
|
|
1791
|
-
//# sourceMappingURL=helpers.js.map
|