working version of appRouter
This commit is contained in:
parent
90317d71d3
commit
f4edab87af
21 changed files with 249 additions and 93 deletions
48
packages/nextjs/package.json
Normal file
48
packages/nextjs/package.json
Normal file
|
@ -0,0 +1,48 @@
|
|||
{
|
||||
"name": "@aptabase/nextjs",
|
||||
"version": "0.0.1",
|
||||
"type": "module",
|
||||
"description": "Next.js SDK for Aptabase: Open Source, Privacy-First and Simple Analytics for Mobile, Desktop and Web Apps",
|
||||
"types": "./dist/index.d.ts",
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./dist/index.d.ts",
|
||||
"default": "./dist/index.js"
|
||||
},
|
||||
"./server": {
|
||||
"types": "./dist/server.d.ts",
|
||||
"default": "./dist/server.js"
|
||||
}
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/aptabase/aptabase-js.git",
|
||||
"directory": "packages/nextjs"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/aptabase/aptabase-js/issues"
|
||||
},
|
||||
"homepage": "https://github.com/aptabase/aptabase-js",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"build": "tsc"
|
||||
},
|
||||
"files": [
|
||||
"README.md",
|
||||
"LICENSE",
|
||||
"dist",
|
||||
"package.json"
|
||||
],
|
||||
"devDependencies": {
|
||||
"@rollup/plugin-replace": "5.0.2",
|
||||
"@rollup/plugin-typescript": "11.1.3",
|
||||
"rollup": "3.28.1",
|
||||
"@rollup/plugin-terser": "0.4.3",
|
||||
"tslib": "2.6.2",
|
||||
"typescript": "5.2.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^18.0.0",
|
||||
"next": "^13.0.0"
|
||||
}
|
||||
}
|
82
packages/nextjs/src/client.tsx
Normal file
82
packages/nextjs/src/client.tsx
Normal file
|
@ -0,0 +1,82 @@
|
|||
'use client';
|
||||
|
||||
import { createContext, useContext } from 'react';
|
||||
import { AptabaseOptions } from './types';
|
||||
|
||||
type TrackEventFn = (eventName: string, props?: Record<string, string | number | boolean>) => Promise<void>;
|
||||
|
||||
type ContextProps = {
|
||||
appKey?: string;
|
||||
client?: AptabaseClient;
|
||||
} & AptabaseOptions;
|
||||
|
||||
export type AptabaseClient = {
|
||||
trackEvent: TrackEventFn;
|
||||
};
|
||||
|
||||
const AptabaseContext = createContext<ContextProps>({});
|
||||
|
||||
type Props = {
|
||||
appKey: string;
|
||||
options?: AptabaseOptions;
|
||||
children: React.ReactNode;
|
||||
};
|
||||
|
||||
export function AptabaseProvider({ appKey, options, children }: Props) {
|
||||
const client: AptabaseClient = {
|
||||
trackEvent: (eventName, props) => sendEvent(appKey, eventName, props),
|
||||
};
|
||||
|
||||
return <AptabaseContext.Provider value={{ appKey, ...options, client }}>{children}</AptabaseContext.Provider>;
|
||||
}
|
||||
|
||||
export function useAptabase(): AptabaseClient {
|
||||
const ctx = useContext(AptabaseContext);
|
||||
if (!ctx.client) {
|
||||
throw new Error(
|
||||
'useAptabase must be used within AptabaseProvider. Did you forget to wrap your app in <AptabaseProvider>?',
|
||||
);
|
||||
}
|
||||
|
||||
return ctx.client;
|
||||
}
|
||||
|
||||
async function sendEvent(
|
||||
appKey: string | undefined,
|
||||
eventName: string,
|
||||
props?: Record<string, string | number | boolean>,
|
||||
): Promise<void> {
|
||||
if (!appKey) return Promise.resolve();
|
||||
|
||||
const body = JSON.stringify({
|
||||
timestamp: new Date().toISOString(),
|
||||
sessionId: 'CHANGE-THIS',
|
||||
eventName: eventName,
|
||||
systemProps: {
|
||||
isDebug: true,
|
||||
locale: 'en',
|
||||
appVersion: '',
|
||||
sdkVersion: 'aptabase-nextjs@0.0.1',
|
||||
},
|
||||
props: props,
|
||||
});
|
||||
|
||||
try {
|
||||
const response = await fetch('http://localhost:3000/api/v0/event', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'App-Key': appKey,
|
||||
},
|
||||
credentials: 'omit',
|
||||
body,
|
||||
});
|
||||
|
||||
if (response.status >= 300) {
|
||||
const responseBody = await response.text();
|
||||
console.warn(`Failed to send event "${eventName}": ${response.status} ${responseBody}`);
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn(`Failed to send event "${eventName}": ${e}`);
|
||||
}
|
||||
}
|
5
packages/nextjs/src/global.d.ts
vendored
Normal file
5
packages/nextjs/src/global.d.ts
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
type AptabaseState = {
|
||||
appKey?: string;
|
||||
};
|
||||
|
||||
declare var __APTABASE__: AptabaseState;
|
5
packages/nextjs/src/index.ts
Normal file
5
packages/nextjs/src/index.ts
Normal file
|
@ -0,0 +1,5 @@
|
|||
export * from './client';
|
||||
|
||||
export function init(appKey: string) {
|
||||
globalThis.__APTABASE__ = { appKey };
|
||||
}
|
39
packages/nextjs/src/server.ts
Normal file
39
packages/nextjs/src/server.ts
Normal file
|
@ -0,0 +1,39 @@
|
|||
import { headers } from 'next/headers';
|
||||
|
||||
export async function trackEvent(eventName: string, props?: Record<string, string | number | boolean>): Promise<void> {
|
||||
const appKey = globalThis.__APTABASE__.appKey;
|
||||
if (!appKey) return Promise.resolve();
|
||||
|
||||
const body = JSON.stringify({
|
||||
timestamp: new Date().toISOString(),
|
||||
sessionId: 'CHANGE-THIS',
|
||||
eventName: eventName,
|
||||
systemProps: {
|
||||
isDebug: true,
|
||||
locale: 'en',
|
||||
appVersion: '',
|
||||
sdkVersion: 'aptabase-nextjs@0.0.1',
|
||||
},
|
||||
props: props,
|
||||
});
|
||||
|
||||
try {
|
||||
const response = await fetch('http://localhost:3000/api/v0/event', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'User-Agent': headers().get('User-Agent') ?? '',
|
||||
'Content-Type': 'application/json',
|
||||
'App-Key': appKey,
|
||||
},
|
||||
credentials: 'omit',
|
||||
body,
|
||||
});
|
||||
|
||||
if (response.status >= 300) {
|
||||
const responseBody = await response.text();
|
||||
console.warn(`Failed to send event "${eventName}": ${response.status} ${responseBody}`);
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn(`Failed to send event "${eventName}": ${e}`);
|
||||
}
|
||||
}
|
4
packages/nextjs/src/types.ts
Normal file
4
packages/nextjs/src/types.ts
Normal file
|
@ -0,0 +1,4 @@
|
|||
export type AptabaseOptions = {
|
||||
host?: string;
|
||||
appVersion?: string;
|
||||
};
|
22
packages/nextjs/tsconfig.json
Normal file
22
packages/nextjs/tsconfig.json
Normal file
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"declaration": true,
|
||||
"esModuleInterop": true,
|
||||
"lib": ["esnext", "dom"],
|
||||
"module": "esnext",
|
||||
"jsx": "react-jsx",
|
||||
"moduleResolution": "node",
|
||||
"noEmitOnError": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noImplicitReturns": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"outDir": "dist",
|
||||
"sourceMap": true,
|
||||
"strict": true,
|
||||
"target": "es2020",
|
||||
"types": ["node"],
|
||||
},
|
||||
"include": ["src/*", "src/global.d.ts"],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue