@nextlytics/core 0.1.0-canary-1
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/dist/anonymous-user.cjs +118 -0
- package/dist/anonymous-user.d.mts +22 -0
- package/dist/anonymous-user.d.ts +22 -0
- package/dist/anonymous-user.js +94 -0
- package/dist/backends/clickhouse.cjs +110 -0
- package/dist/backends/clickhouse.d.mts +58 -0
- package/dist/backends/clickhouse.d.ts +58 -0
- package/dist/backends/clickhouse.js +92 -0
- package/dist/backends/ga.cjs +207 -0
- package/dist/backends/ga.d.mts +21 -0
- package/dist/backends/ga.d.ts +21 -0
- package/dist/backends/ga.js +183 -0
- package/dist/backends/gtm.cjs +155 -0
- package/dist/backends/gtm.d.mts +11 -0
- package/dist/backends/gtm.d.ts +11 -0
- package/dist/backends/gtm.js +131 -0
- package/dist/backends/lib/db.cjs +150 -0
- package/dist/backends/lib/db.d.mts +121 -0
- package/dist/backends/lib/db.d.ts +121 -0
- package/dist/backends/lib/db.js +119 -0
- package/dist/backends/logging.cjs +45 -0
- package/dist/backends/logging.d.mts +7 -0
- package/dist/backends/logging.d.ts +7 -0
- package/dist/backends/logging.js +21 -0
- package/dist/backends/neon.cjs +84 -0
- package/dist/backends/neon.d.mts +11 -0
- package/dist/backends/neon.d.ts +11 -0
- package/dist/backends/neon.js +66 -0
- package/dist/backends/postgrest.cjs +98 -0
- package/dist/backends/postgrest.d.mts +46 -0
- package/dist/backends/postgrest.d.ts +46 -0
- package/dist/backends/postgrest.js +73 -0
- package/dist/backends/posthog.cjs +120 -0
- package/dist/backends/posthog.d.mts +13 -0
- package/dist/backends/posthog.d.ts +13 -0
- package/dist/backends/posthog.js +96 -0
- package/dist/backends/segment.cjs +112 -0
- package/dist/backends/segment.d.mts +43 -0
- package/dist/backends/segment.d.ts +43 -0
- package/dist/backends/segment.js +88 -0
- package/dist/client.cjs +171 -0
- package/dist/client.d.mts +29 -0
- package/dist/client.d.ts +29 -0
- package/dist/client.js +146 -0
- package/dist/config-helpers.cjs +71 -0
- package/dist/config-helpers.d.mts +16 -0
- package/dist/config-helpers.d.ts +16 -0
- package/dist/config-helpers.js +45 -0
- package/dist/handlers.cjs +123 -0
- package/dist/handlers.d.mts +9 -0
- package/dist/handlers.d.ts +9 -0
- package/dist/handlers.js +99 -0
- package/dist/headers.cjs +41 -0
- package/dist/headers.d.mts +3 -0
- package/dist/headers.d.ts +3 -0
- package/dist/headers.js +17 -0
- package/dist/index.cjs +41 -0
- package/dist/index.d.mts +9 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +12 -0
- package/dist/middleware.cjs +204 -0
- package/dist/middleware.d.mts +10 -0
- package/dist/middleware.d.ts +10 -0
- package/dist/middleware.js +183 -0
- package/dist/pages-router.cjs +45 -0
- package/dist/pages-router.d.mts +45 -0
- package/dist/pages-router.d.ts +45 -0
- package/dist/pages-router.js +21 -0
- package/dist/plugins/vercel-geo.cjs +60 -0
- package/dist/plugins/vercel-geo.d.mts +25 -0
- package/dist/plugins/vercel-geo.d.ts +25 -0
- package/dist/plugins/vercel-geo.js +36 -0
- package/dist/server-component-context.cjs +95 -0
- package/dist/server-component-context.d.mts +30 -0
- package/dist/server-component-context.d.ts +30 -0
- package/dist/server-component-context.js +69 -0
- package/dist/server.cjs +236 -0
- package/dist/server.d.mts +13 -0
- package/dist/server.d.ts +13 -0
- package/dist/server.js +213 -0
- package/dist/template.cjs +108 -0
- package/dist/template.d.mts +27 -0
- package/dist/template.d.ts +27 -0
- package/dist/template.js +83 -0
- package/dist/types.cjs +16 -0
- package/dist/types.d.mts +216 -0
- package/dist/types.d.ts +216 -0
- package/dist/types.js +0 -0
- package/dist/uitils.cjs +94 -0
- package/dist/uitils.d.mts +22 -0
- package/dist/uitils.d.ts +22 -0
- package/dist/uitils.js +68 -0
- package/package.json +162 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
function loggingBackend() {
|
|
2
|
+
return {
|
|
3
|
+
name: "logging",
|
|
4
|
+
supportsUpdates: true,
|
|
5
|
+
async onEvent(event) {
|
|
6
|
+
const { type, eventId, serverContext, ...rest } = event;
|
|
7
|
+
const method = serverContext?.method || "";
|
|
8
|
+
const path = serverContext?.path || "";
|
|
9
|
+
const route = method && path ? `${method} ${path}` : "";
|
|
10
|
+
console.log(`[Nextlytics Log] ${type}${route ? ` ${route}` : ""} (${eventId})`);
|
|
11
|
+
console.log(JSON.stringify({ serverContext, ...rest }, null, 2));
|
|
12
|
+
},
|
|
13
|
+
updateEvent(eventId, patch) {
|
|
14
|
+
console.log(`[Nextlytics Log] Update ${eventId}`);
|
|
15
|
+
console.log(JSON.stringify(patch, null, 2));
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
export {
|
|
20
|
+
loggingBackend
|
|
21
|
+
};
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var neon_exports = {};
|
|
20
|
+
__export(neon_exports, {
|
|
21
|
+
neonBackend: () => neonBackend
|
|
22
|
+
});
|
|
23
|
+
module.exports = __toCommonJS(neon_exports);
|
|
24
|
+
var import_serverless = require("@neondatabase/serverless");
|
|
25
|
+
var import_db = require("./lib/db");
|
|
26
|
+
function neonBackend(config) {
|
|
27
|
+
const sql = (0, import_serverless.neon)(config.databaseUrl);
|
|
28
|
+
const table = config.tableName ?? "analytics";
|
|
29
|
+
function printCreateTableStatement() {
|
|
30
|
+
console.error(`[Nextlytics Neon] Table "${table}" does not exist. Run this SQL:
|
|
31
|
+
`);
|
|
32
|
+
console.error((0, import_db.generatePgCreateTableSQL)(table));
|
|
33
|
+
}
|
|
34
|
+
return {
|
|
35
|
+
name: "neon",
|
|
36
|
+
supportsUpdates: true,
|
|
37
|
+
async onEvent(event) {
|
|
38
|
+
const values = (0, import_db.eventToRow)(event);
|
|
39
|
+
const cols = import_db.tableColumns.map((c) => c.name).join(", ");
|
|
40
|
+
const placeholders = import_db.tableColumns.map((_, i) => `$${i + 1}`).join(", ");
|
|
41
|
+
try {
|
|
42
|
+
await sql(`INSERT INTO ${table} (${cols}) VALUES (${placeholders})`, [
|
|
43
|
+
...import_db.tableColumns.map((c) => values[c.name])
|
|
44
|
+
]);
|
|
45
|
+
} catch (err) {
|
|
46
|
+
if ((0, import_db.isPgTableNotFoundError)(err)) {
|
|
47
|
+
printCreateTableStatement();
|
|
48
|
+
}
|
|
49
|
+
throw err;
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
async updateEvent(eventId, patch) {
|
|
53
|
+
const sets = [];
|
|
54
|
+
const params = [];
|
|
55
|
+
let paramIndex = 1;
|
|
56
|
+
if (patch.clientContext) {
|
|
57
|
+
const clientCtx = (0, import_db.extractClientContext)(patch.clientContext);
|
|
58
|
+
const columns = {
|
|
59
|
+
referer: clientCtx.referer,
|
|
60
|
+
user_agent: clientCtx.user_agent,
|
|
61
|
+
locale: clientCtx.locale
|
|
62
|
+
};
|
|
63
|
+
for (const [col, val] of Object.entries(columns)) {
|
|
64
|
+
if (val !== void 0) {
|
|
65
|
+
sets.push(`${col} = $${paramIndex++}`);
|
|
66
|
+
params.push(val);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
if (clientCtx.rest) {
|
|
70
|
+
sets.push(`client_context = $${paramIndex++}::jsonb`);
|
|
71
|
+
params.push(JSON.stringify(clientCtx.rest));
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
if (sets.length > 0) {
|
|
75
|
+
params.push(eventId);
|
|
76
|
+
await sql(`UPDATE ${table} SET ${sets.join(", ")} WHERE event_id = $${paramIndex}`, params);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
82
|
+
0 && (module.exports = {
|
|
83
|
+
neonBackend
|
|
84
|
+
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { NextlyticsBackend } from '../types.mjs';
|
|
2
|
+
import 'next/dist/server/web/spec-extension/cookies';
|
|
3
|
+
import 'next/server';
|
|
4
|
+
|
|
5
|
+
type NeonBackendConfig = {
|
|
6
|
+
databaseUrl: string;
|
|
7
|
+
tableName?: string;
|
|
8
|
+
};
|
|
9
|
+
declare function neonBackend(config: NeonBackendConfig): NextlyticsBackend;
|
|
10
|
+
|
|
11
|
+
export { type NeonBackendConfig, neonBackend };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { NextlyticsBackend } from '../types.js';
|
|
2
|
+
import 'next/dist/server/web/spec-extension/cookies';
|
|
3
|
+
import 'next/server';
|
|
4
|
+
|
|
5
|
+
type NeonBackendConfig = {
|
|
6
|
+
databaseUrl: string;
|
|
7
|
+
tableName?: string;
|
|
8
|
+
};
|
|
9
|
+
declare function neonBackend(config: NeonBackendConfig): NextlyticsBackend;
|
|
10
|
+
|
|
11
|
+
export { type NeonBackendConfig, neonBackend };
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { neon } from "@neondatabase/serverless";
|
|
2
|
+
import {
|
|
3
|
+
tableColumns,
|
|
4
|
+
eventToRow,
|
|
5
|
+
extractClientContext,
|
|
6
|
+
generatePgCreateTableSQL,
|
|
7
|
+
isPgTableNotFoundError
|
|
8
|
+
} from "./lib/db";
|
|
9
|
+
function neonBackend(config) {
|
|
10
|
+
const sql = neon(config.databaseUrl);
|
|
11
|
+
const table = config.tableName ?? "analytics";
|
|
12
|
+
function printCreateTableStatement() {
|
|
13
|
+
console.error(`[Nextlytics Neon] Table "${table}" does not exist. Run this SQL:
|
|
14
|
+
`);
|
|
15
|
+
console.error(generatePgCreateTableSQL(table));
|
|
16
|
+
}
|
|
17
|
+
return {
|
|
18
|
+
name: "neon",
|
|
19
|
+
supportsUpdates: true,
|
|
20
|
+
async onEvent(event) {
|
|
21
|
+
const values = eventToRow(event);
|
|
22
|
+
const cols = tableColumns.map((c) => c.name).join(", ");
|
|
23
|
+
const placeholders = tableColumns.map((_, i) => `$${i + 1}`).join(", ");
|
|
24
|
+
try {
|
|
25
|
+
await sql(`INSERT INTO ${table} (${cols}) VALUES (${placeholders})`, [
|
|
26
|
+
...tableColumns.map((c) => values[c.name])
|
|
27
|
+
]);
|
|
28
|
+
} catch (err) {
|
|
29
|
+
if (isPgTableNotFoundError(err)) {
|
|
30
|
+
printCreateTableStatement();
|
|
31
|
+
}
|
|
32
|
+
throw err;
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
async updateEvent(eventId, patch) {
|
|
36
|
+
const sets = [];
|
|
37
|
+
const params = [];
|
|
38
|
+
let paramIndex = 1;
|
|
39
|
+
if (patch.clientContext) {
|
|
40
|
+
const clientCtx = extractClientContext(patch.clientContext);
|
|
41
|
+
const columns = {
|
|
42
|
+
referer: clientCtx.referer,
|
|
43
|
+
user_agent: clientCtx.user_agent,
|
|
44
|
+
locale: clientCtx.locale
|
|
45
|
+
};
|
|
46
|
+
for (const [col, val] of Object.entries(columns)) {
|
|
47
|
+
if (val !== void 0) {
|
|
48
|
+
sets.push(`${col} = $${paramIndex++}`);
|
|
49
|
+
params.push(val);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
if (clientCtx.rest) {
|
|
53
|
+
sets.push(`client_context = $${paramIndex++}::jsonb`);
|
|
54
|
+
params.push(JSON.stringify(clientCtx.rest));
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
if (sets.length > 0) {
|
|
58
|
+
params.push(eventId);
|
|
59
|
+
await sql(`UPDATE ${table} SET ${sets.join(", ")} WHERE event_id = $${paramIndex}`, params);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
export {
|
|
65
|
+
neonBackend
|
|
66
|
+
};
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var postgrest_exports = {};
|
|
20
|
+
__export(postgrest_exports, {
|
|
21
|
+
generatePgCreateTableSQL: () => import_db2.generatePgCreateTableSQL,
|
|
22
|
+
postgrestBackend: () => postgrestBackend
|
|
23
|
+
});
|
|
24
|
+
module.exports = __toCommonJS(postgrest_exports);
|
|
25
|
+
var import_db = require("./lib/db");
|
|
26
|
+
var import_db2 = require("./lib/db");
|
|
27
|
+
function postgrestBackend(config) {
|
|
28
|
+
const table = config.tableName ?? "analytics";
|
|
29
|
+
const baseUrl = config.url.replace(/\/$/, "");
|
|
30
|
+
function headers() {
|
|
31
|
+
const h = {
|
|
32
|
+
"Content-Type": "application/json",
|
|
33
|
+
Prefer: "return=minimal"
|
|
34
|
+
};
|
|
35
|
+
if (config.apiKey) {
|
|
36
|
+
h["apikey"] = config.apiKey;
|
|
37
|
+
h["Authorization"] = `Bearer ${config.apiKey}`;
|
|
38
|
+
}
|
|
39
|
+
return h;
|
|
40
|
+
}
|
|
41
|
+
function printCreateTableStatement() {
|
|
42
|
+
console.error(`[Nextlytics PostgREST] Table "${table}" does not exist. Run this SQL:
|
|
43
|
+
`);
|
|
44
|
+
console.error((0, import_db.generatePgCreateTableSQL)(table));
|
|
45
|
+
}
|
|
46
|
+
async function handleResponse(res) {
|
|
47
|
+
if (!res.ok) {
|
|
48
|
+
const text = await res.text();
|
|
49
|
+
if (text.includes("does not exist") || res.status === 404) {
|
|
50
|
+
printCreateTableStatement();
|
|
51
|
+
}
|
|
52
|
+
throw new Error(`PostgREST error ${res.status}: ${text}`);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return {
|
|
56
|
+
name: "postgrest",
|
|
57
|
+
supportsUpdates: true,
|
|
58
|
+
async onEvent(event) {
|
|
59
|
+
const row = (0, import_db.eventToJsonRow)(event);
|
|
60
|
+
const res = await fetch(`${baseUrl}/${table}`, {
|
|
61
|
+
method: "POST",
|
|
62
|
+
headers: headers(),
|
|
63
|
+
body: JSON.stringify(row)
|
|
64
|
+
});
|
|
65
|
+
await handleResponse(res);
|
|
66
|
+
},
|
|
67
|
+
async updateEvent(eventId, patch) {
|
|
68
|
+
const updates = {};
|
|
69
|
+
if (patch.clientContext) {
|
|
70
|
+
const clientCtx = (0, import_db.extractClientContext)(patch.clientContext);
|
|
71
|
+
if (clientCtx.referer !== void 0) updates.referer = clientCtx.referer;
|
|
72
|
+
if (clientCtx.user_agent !== void 0) updates.user_agent = clientCtx.user_agent;
|
|
73
|
+
if (clientCtx.locale !== void 0) updates.locale = clientCtx.locale;
|
|
74
|
+
if (clientCtx.rest) updates.client_context = clientCtx.rest;
|
|
75
|
+
}
|
|
76
|
+
if (patch.userContext) {
|
|
77
|
+
updates.user_id = patch.userContext.userId;
|
|
78
|
+
if (patch.userContext.traits?.email) updates.user_email = patch.userContext.traits.email;
|
|
79
|
+
if (patch.userContext.traits?.name) updates.user_name = patch.userContext.traits.name;
|
|
80
|
+
}
|
|
81
|
+
if (patch.anonymousUserId) {
|
|
82
|
+
updates.anonymous_user_id = patch.anonymousUserId;
|
|
83
|
+
}
|
|
84
|
+
if (Object.keys(updates).length === 0) return;
|
|
85
|
+
const res = await fetch(`${baseUrl}/${table}?event_id=eq.${encodeURIComponent(eventId)}`, {
|
|
86
|
+
method: "PATCH",
|
|
87
|
+
headers: headers(),
|
|
88
|
+
body: JSON.stringify(updates)
|
|
89
|
+
});
|
|
90
|
+
await handleResponse(res);
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
95
|
+
0 && (module.exports = {
|
|
96
|
+
generatePgCreateTableSQL,
|
|
97
|
+
postgrestBackend
|
|
98
|
+
});
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { NextlyticsBackend } from '../types.mjs';
|
|
2
|
+
export { AnalyticsEventRow, generatePgCreateTableSQL } from './lib/db.mjs';
|
|
3
|
+
import 'next/dist/server/web/spec-extension/cookies';
|
|
4
|
+
import 'next/server';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* PostgREST backend for Nextlytics
|
|
8
|
+
*
|
|
9
|
+
* Works with any PostgREST-compatible API including Supabase.
|
|
10
|
+
*
|
|
11
|
+
* ## Supabase Usage
|
|
12
|
+
*
|
|
13
|
+
* ```typescript
|
|
14
|
+
* import { postgrestBackend } from "@nextlytics/core/backends/postgrest"
|
|
15
|
+
*
|
|
16
|
+
* const analytics = Nextlytics({
|
|
17
|
+
* backends: [
|
|
18
|
+
* postgrestBackend({
|
|
19
|
+
* url: process.env.SUPABASE_URL! + "/rest/v1",
|
|
20
|
+
* apiKey: process.env.SUPABASE_SERVICE_ROLE_KEY!,
|
|
21
|
+
* })
|
|
22
|
+
* ]
|
|
23
|
+
* })
|
|
24
|
+
* ```
|
|
25
|
+
*
|
|
26
|
+
* ## Generic PostgREST Usage
|
|
27
|
+
*
|
|
28
|
+
* ```typescript
|
|
29
|
+
* postgrestBackend({
|
|
30
|
+
* url: "https://your-postgrest-server.com",
|
|
31
|
+
* // apiKey is optional for non-Supabase PostgREST
|
|
32
|
+
* })
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
type PostgrestBackendConfig = {
|
|
37
|
+
/** PostgREST API URL (e.g., "https://xxx.supabase.co/rest/v1") */
|
|
38
|
+
url: string;
|
|
39
|
+
/** API key for authentication (required for Supabase) */
|
|
40
|
+
apiKey?: string;
|
|
41
|
+
/** Table name (default: "analytics") */
|
|
42
|
+
tableName?: string;
|
|
43
|
+
};
|
|
44
|
+
declare function postgrestBackend(config: PostgrestBackendConfig): NextlyticsBackend;
|
|
45
|
+
|
|
46
|
+
export { type PostgrestBackendConfig, postgrestBackend };
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { NextlyticsBackend } from '../types.js';
|
|
2
|
+
export { AnalyticsEventRow, generatePgCreateTableSQL } from './lib/db.js';
|
|
3
|
+
import 'next/dist/server/web/spec-extension/cookies';
|
|
4
|
+
import 'next/server';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* PostgREST backend for Nextlytics
|
|
8
|
+
*
|
|
9
|
+
* Works with any PostgREST-compatible API including Supabase.
|
|
10
|
+
*
|
|
11
|
+
* ## Supabase Usage
|
|
12
|
+
*
|
|
13
|
+
* ```typescript
|
|
14
|
+
* import { postgrestBackend } from "@nextlytics/core/backends/postgrest"
|
|
15
|
+
*
|
|
16
|
+
* const analytics = Nextlytics({
|
|
17
|
+
* backends: [
|
|
18
|
+
* postgrestBackend({
|
|
19
|
+
* url: process.env.SUPABASE_URL! + "/rest/v1",
|
|
20
|
+
* apiKey: process.env.SUPABASE_SERVICE_ROLE_KEY!,
|
|
21
|
+
* })
|
|
22
|
+
* ]
|
|
23
|
+
* })
|
|
24
|
+
* ```
|
|
25
|
+
*
|
|
26
|
+
* ## Generic PostgREST Usage
|
|
27
|
+
*
|
|
28
|
+
* ```typescript
|
|
29
|
+
* postgrestBackend({
|
|
30
|
+
* url: "https://your-postgrest-server.com",
|
|
31
|
+
* // apiKey is optional for non-Supabase PostgREST
|
|
32
|
+
* })
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
type PostgrestBackendConfig = {
|
|
37
|
+
/** PostgREST API URL (e.g., "https://xxx.supabase.co/rest/v1") */
|
|
38
|
+
url: string;
|
|
39
|
+
/** API key for authentication (required for Supabase) */
|
|
40
|
+
apiKey?: string;
|
|
41
|
+
/** Table name (default: "analytics") */
|
|
42
|
+
tableName?: string;
|
|
43
|
+
};
|
|
44
|
+
declare function postgrestBackend(config: PostgrestBackendConfig): NextlyticsBackend;
|
|
45
|
+
|
|
46
|
+
export { type PostgrestBackendConfig, postgrestBackend };
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { eventToJsonRow, extractClientContext, generatePgCreateTableSQL } from "./lib/db";
|
|
2
|
+
import { generatePgCreateTableSQL as generatePgCreateTableSQL2 } from "./lib/db";
|
|
3
|
+
function postgrestBackend(config) {
|
|
4
|
+
const table = config.tableName ?? "analytics";
|
|
5
|
+
const baseUrl = config.url.replace(/\/$/, "");
|
|
6
|
+
function headers() {
|
|
7
|
+
const h = {
|
|
8
|
+
"Content-Type": "application/json",
|
|
9
|
+
Prefer: "return=minimal"
|
|
10
|
+
};
|
|
11
|
+
if (config.apiKey) {
|
|
12
|
+
h["apikey"] = config.apiKey;
|
|
13
|
+
h["Authorization"] = `Bearer ${config.apiKey}`;
|
|
14
|
+
}
|
|
15
|
+
return h;
|
|
16
|
+
}
|
|
17
|
+
function printCreateTableStatement() {
|
|
18
|
+
console.error(`[Nextlytics PostgREST] Table "${table}" does not exist. Run this SQL:
|
|
19
|
+
`);
|
|
20
|
+
console.error(generatePgCreateTableSQL(table));
|
|
21
|
+
}
|
|
22
|
+
async function handleResponse(res) {
|
|
23
|
+
if (!res.ok) {
|
|
24
|
+
const text = await res.text();
|
|
25
|
+
if (text.includes("does not exist") || res.status === 404) {
|
|
26
|
+
printCreateTableStatement();
|
|
27
|
+
}
|
|
28
|
+
throw new Error(`PostgREST error ${res.status}: ${text}`);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return {
|
|
32
|
+
name: "postgrest",
|
|
33
|
+
supportsUpdates: true,
|
|
34
|
+
async onEvent(event) {
|
|
35
|
+
const row = eventToJsonRow(event);
|
|
36
|
+
const res = await fetch(`${baseUrl}/${table}`, {
|
|
37
|
+
method: "POST",
|
|
38
|
+
headers: headers(),
|
|
39
|
+
body: JSON.stringify(row)
|
|
40
|
+
});
|
|
41
|
+
await handleResponse(res);
|
|
42
|
+
},
|
|
43
|
+
async updateEvent(eventId, patch) {
|
|
44
|
+
const updates = {};
|
|
45
|
+
if (patch.clientContext) {
|
|
46
|
+
const clientCtx = extractClientContext(patch.clientContext);
|
|
47
|
+
if (clientCtx.referer !== void 0) updates.referer = clientCtx.referer;
|
|
48
|
+
if (clientCtx.user_agent !== void 0) updates.user_agent = clientCtx.user_agent;
|
|
49
|
+
if (clientCtx.locale !== void 0) updates.locale = clientCtx.locale;
|
|
50
|
+
if (clientCtx.rest) updates.client_context = clientCtx.rest;
|
|
51
|
+
}
|
|
52
|
+
if (patch.userContext) {
|
|
53
|
+
updates.user_id = patch.userContext.userId;
|
|
54
|
+
if (patch.userContext.traits?.email) updates.user_email = patch.userContext.traits.email;
|
|
55
|
+
if (patch.userContext.traits?.name) updates.user_name = patch.userContext.traits.name;
|
|
56
|
+
}
|
|
57
|
+
if (patch.anonymousUserId) {
|
|
58
|
+
updates.anonymous_user_id = patch.anonymousUserId;
|
|
59
|
+
}
|
|
60
|
+
if (Object.keys(updates).length === 0) return;
|
|
61
|
+
const res = await fetch(`${baseUrl}/${table}?event_id=eq.${encodeURIComponent(eventId)}`, {
|
|
62
|
+
method: "PATCH",
|
|
63
|
+
headers: headers(),
|
|
64
|
+
body: JSON.stringify(updates)
|
|
65
|
+
});
|
|
66
|
+
await handleResponse(res);
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
export {
|
|
71
|
+
generatePgCreateTableSQL2 as generatePgCreateTableSQL,
|
|
72
|
+
postgrestBackend
|
|
73
|
+
};
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var posthog_exports = {};
|
|
20
|
+
__export(posthog_exports, {
|
|
21
|
+
posthogBackend: () => posthogBackend
|
|
22
|
+
});
|
|
23
|
+
module.exports = __toCommonJS(posthog_exports);
|
|
24
|
+
function posthogBackend(opts) {
|
|
25
|
+
const host = (opts.host ?? "https://app.posthog.com").replace(/\/$/, "");
|
|
26
|
+
const apiKey = opts.apiKey;
|
|
27
|
+
return {
|
|
28
|
+
name: "posthog",
|
|
29
|
+
supportsUpdates: false,
|
|
30
|
+
async onEvent(event) {
|
|
31
|
+
const {
|
|
32
|
+
type,
|
|
33
|
+
eventId,
|
|
34
|
+
parentEventId,
|
|
35
|
+
collectedAt,
|
|
36
|
+
userContext,
|
|
37
|
+
clientContext,
|
|
38
|
+
serverContext,
|
|
39
|
+
properties,
|
|
40
|
+
anonymousUserId
|
|
41
|
+
} = event;
|
|
42
|
+
const posthogProps = {
|
|
43
|
+
...properties,
|
|
44
|
+
nextlytics_event_id: eventId
|
|
45
|
+
};
|
|
46
|
+
if (parentEventId) {
|
|
47
|
+
posthogProps.nextlytics_parent_event_id = parentEventId;
|
|
48
|
+
}
|
|
49
|
+
posthogProps.nextlytics_collected_at = collectedAt;
|
|
50
|
+
posthogProps.$current_url = `${serverContext.host}${serverContext.path}`;
|
|
51
|
+
posthogProps.$pathname = serverContext.path;
|
|
52
|
+
posthogProps.$host = serverContext.host;
|
|
53
|
+
posthogProps.$ip = serverContext.ip;
|
|
54
|
+
posthogProps.http_method = serverContext.method;
|
|
55
|
+
posthogProps.server_collected_at = serverContext.collectedAt;
|
|
56
|
+
if (serverContext.search && Object.keys(serverContext.search).length > 0) {
|
|
57
|
+
posthogProps.query_params = serverContext.search;
|
|
58
|
+
}
|
|
59
|
+
if (serverContext.requestHeaders && Object.keys(serverContext.requestHeaders).length > 0) {
|
|
60
|
+
posthogProps.request_headers = serverContext.requestHeaders;
|
|
61
|
+
}
|
|
62
|
+
if (serverContext.responseHeaders && Object.keys(serverContext.responseHeaders).length > 0) {
|
|
63
|
+
posthogProps.response_headers = serverContext.responseHeaders;
|
|
64
|
+
}
|
|
65
|
+
const referer = clientContext?.referer ?? serverContext.requestHeaders?.["referer"];
|
|
66
|
+
if (referer) {
|
|
67
|
+
posthogProps.$referrer = referer;
|
|
68
|
+
}
|
|
69
|
+
const userAgent = clientContext?.userAgent ?? serverContext.requestHeaders?.["user-agent"];
|
|
70
|
+
if (userAgent) {
|
|
71
|
+
posthogProps.$user_agent = userAgent;
|
|
72
|
+
}
|
|
73
|
+
if (clientContext) {
|
|
74
|
+
posthogProps.client_collected_at = clientContext.collectedAt;
|
|
75
|
+
if (clientContext.path) {
|
|
76
|
+
posthogProps.client_path = clientContext.path;
|
|
77
|
+
}
|
|
78
|
+
if (clientContext.locale) {
|
|
79
|
+
posthogProps.$locale = clientContext.locale;
|
|
80
|
+
}
|
|
81
|
+
if (clientContext.screen) {
|
|
82
|
+
const { screen } = clientContext;
|
|
83
|
+
if (screen.width) posthogProps.$screen_width = screen.width;
|
|
84
|
+
if (screen.height) posthogProps.$screen_height = screen.height;
|
|
85
|
+
if (screen.innerWidth) posthogProps.$viewport_width = screen.innerWidth;
|
|
86
|
+
if (screen.innerHeight) posthogProps.$viewport_height = screen.innerHeight;
|
|
87
|
+
if (screen.density) posthogProps.$device_pixel_ratio = screen.density;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
const distinctId = userContext?.userId ?? anonymousUserId ?? "anonymous";
|
|
91
|
+
const payload = {
|
|
92
|
+
api_key: apiKey,
|
|
93
|
+
event: type,
|
|
94
|
+
distinct_id: distinctId,
|
|
95
|
+
properties: posthogProps,
|
|
96
|
+
timestamp: collectedAt
|
|
97
|
+
};
|
|
98
|
+
if (userContext?.userId && userContext.traits) {
|
|
99
|
+
payload.$set = userContext.traits;
|
|
100
|
+
}
|
|
101
|
+
const res = await fetch(`${host}/capture/`, {
|
|
102
|
+
method: "POST",
|
|
103
|
+
headers: {
|
|
104
|
+
"Content-Type": "application/json"
|
|
105
|
+
},
|
|
106
|
+
body: JSON.stringify(payload)
|
|
107
|
+
});
|
|
108
|
+
if (!res.ok) {
|
|
109
|
+
const text = await res.text();
|
|
110
|
+
throw new Error(`PostHog error ${res.status}: ${text}`);
|
|
111
|
+
}
|
|
112
|
+
},
|
|
113
|
+
updateEvent() {
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
118
|
+
0 && (module.exports = {
|
|
119
|
+
posthogBackend
|
|
120
|
+
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { NextlyticsBackend } from '../types.mjs';
|
|
2
|
+
import 'next/dist/server/web/spec-extension/cookies';
|
|
3
|
+
import 'next/server';
|
|
4
|
+
|
|
5
|
+
type PosthogBackendOptions = {
|
|
6
|
+
/** PostHog project API key */
|
|
7
|
+
apiKey: string;
|
|
8
|
+
/** PostHog host (default: "https://app.posthog.com") */
|
|
9
|
+
host?: string;
|
|
10
|
+
};
|
|
11
|
+
declare function posthogBackend(opts: PosthogBackendOptions): NextlyticsBackend;
|
|
12
|
+
|
|
13
|
+
export { type PosthogBackendOptions, posthogBackend };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { NextlyticsBackend } from '../types.js';
|
|
2
|
+
import 'next/dist/server/web/spec-extension/cookies';
|
|
3
|
+
import 'next/server';
|
|
4
|
+
|
|
5
|
+
type PosthogBackendOptions = {
|
|
6
|
+
/** PostHog project API key */
|
|
7
|
+
apiKey: string;
|
|
8
|
+
/** PostHog host (default: "https://app.posthog.com") */
|
|
9
|
+
host?: string;
|
|
10
|
+
};
|
|
11
|
+
declare function posthogBackend(opts: PosthogBackendOptions): NextlyticsBackend;
|
|
12
|
+
|
|
13
|
+
export { type PosthogBackendOptions, posthogBackend };
|