coonlink-openpanel-dev 26.1.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/README.md +69 -0
- package/dist/OpenPanelAnalytics.d.ts +6 -0
- package/dist/OpenPanelAnalytics.js +5 -0
- package/dist/client.d.ts +1 -0
- package/dist/client.js +2 -0
- package/dist/config.d.ts +23 -0
- package/dist/config.js +53 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +3 -0
- package/dist/server.d.ts +15 -0
- package/dist/server.js +30 -0
- package/package.json +38 -0
package/README.md
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# `coonlink-openpanel`
|
|
2
|
+
|
|
3
|
+
Reusable OpenPanel proxy setup for Next.js projects.
|
|
4
|
+
|
|
5
|
+
## What it gives you
|
|
6
|
+
|
|
7
|
+
- Loads the SDK through your own domain
|
|
8
|
+
- Sends browser requests to `/api/op`
|
|
9
|
+
- Proxies tracking requests from your app to your configured upstream API
|
|
10
|
+
- Keeps the env shape consistent across projects
|
|
11
|
+
|
|
12
|
+
## Expected environment variables
|
|
13
|
+
|
|
14
|
+
```env
|
|
15
|
+
OPENPANEL_CLIENT_ID=your-client-id
|
|
16
|
+
OPENPANEL_EVENTS_ENDPOINT=https://analysisapi.example.com
|
|
17
|
+
NEXT_PUBLIC_URL_CANONICAL=https://your-app.example.com
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
`OPENPANEL_EVENTS_ENDPOINT` must be the upstream API base URL, not `/track`.
|
|
21
|
+
|
|
22
|
+
## Usage in a Next.js app
|
|
23
|
+
|
|
24
|
+
### `app/layout.tsx`
|
|
25
|
+
|
|
26
|
+
```tsx
|
|
27
|
+
import { OpenPanelAnalytics, getOpenPanelConfigFromEnv } from 'coonlink-openpanel'
|
|
28
|
+
|
|
29
|
+
const openPanelConfig = getOpenPanelConfigFromEnv()
|
|
30
|
+
|
|
31
|
+
export default function RootLayout({
|
|
32
|
+
children,
|
|
33
|
+
}: Readonly<{ children: React.ReactNode }>) {
|
|
34
|
+
return (
|
|
35
|
+
<html lang="en">
|
|
36
|
+
<body>
|
|
37
|
+
{openPanelConfig ? <OpenPanelAnalytics config={openPanelConfig} /> : null}
|
|
38
|
+
{children}
|
|
39
|
+
</body>
|
|
40
|
+
</html>
|
|
41
|
+
)
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### `app/api/[...op]/route.ts`
|
|
46
|
+
|
|
47
|
+
```ts
|
|
48
|
+
import { createOpenPanelProxyRouteHandlersFromEnv } from 'coonlink-openpanel/server'
|
|
49
|
+
|
|
50
|
+
export const { GET, POST } = createOpenPanelProxyRouteHandlersFromEnv()
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Client components
|
|
54
|
+
|
|
55
|
+
```tsx
|
|
56
|
+
'use client'
|
|
57
|
+
|
|
58
|
+
import { useOpenPanel } from 'coonlink-openpanel/client'
|
|
59
|
+
|
|
60
|
+
export function ExampleButton() {
|
|
61
|
+
const op = useOpenPanel()
|
|
62
|
+
|
|
63
|
+
return (
|
|
64
|
+
<button type="button" onClick={() => op.track('example_click')}>
|
|
65
|
+
Track event
|
|
66
|
+
</button>
|
|
67
|
+
)
|
|
68
|
+
}
|
|
69
|
+
```
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { OpenPanelComponent } from '@openpanel/nextjs';
|
|
3
|
+
export function OpenPanelAnalytics({ config }) {
|
|
4
|
+
return (_jsx(OpenPanelComponent, { apiUrl: config.proxyPath, clientId: config.clientId, scriptUrl: config.scriptUrl, trackAttributes: true, trackOutgoingLinks: true, trackScreenViews: true }));
|
|
5
|
+
}
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { useOpenPanel } from '@openpanel/nextjs';
|
package/dist/client.js
ADDED
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export type OpenPanelEnvSource = {
|
|
2
|
+
[key: string]: string | undefined;
|
|
3
|
+
NEXT_PUBLIC_URL_CANONICAL?: string;
|
|
4
|
+
OPENPANEL_CLIENT_ID?: string;
|
|
5
|
+
OPENPANEL_EVENTS_ENDPOINT?: string;
|
|
6
|
+
};
|
|
7
|
+
export type CoonlinkOpenPanelConfig = {
|
|
8
|
+
clientId: string;
|
|
9
|
+
proxyPath: string;
|
|
10
|
+
scriptUrl: string;
|
|
11
|
+
upstreamApiUrl: string;
|
|
12
|
+
};
|
|
13
|
+
export declare const defaultOpenPanelProxyPath = "/api/op";
|
|
14
|
+
export declare function createOpenPanelConfig(input: {
|
|
15
|
+
canonicalUrl?: string;
|
|
16
|
+
clientId?: string;
|
|
17
|
+
eventsEndpoint?: string;
|
|
18
|
+
proxyPath?: string;
|
|
19
|
+
}): CoonlinkOpenPanelConfig | null;
|
|
20
|
+
export declare function getOpenPanelConfigFromEnv(env?: OpenPanelEnvSource, options?: {
|
|
21
|
+
proxyPath?: string;
|
|
22
|
+
}): CoonlinkOpenPanelConfig | null;
|
|
23
|
+
export declare function isOpenPanelEnabled(config: CoonlinkOpenPanelConfig | null): config is CoonlinkOpenPanelConfig;
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
export const defaultOpenPanelProxyPath = '/api/op';
|
|
2
|
+
function normalize(value) {
|
|
3
|
+
return (value ?? '').trim();
|
|
4
|
+
}
|
|
5
|
+
function stripTrailingSlash(value) {
|
|
6
|
+
return value.replace(/\/+$/, '');
|
|
7
|
+
}
|
|
8
|
+
function withLeadingSlash(value) {
|
|
9
|
+
return value.startsWith('/') ? value : `/${value}`;
|
|
10
|
+
}
|
|
11
|
+
function joinPath(basePath, suffix) {
|
|
12
|
+
return `${stripTrailingSlash(basePath)}${suffix}`;
|
|
13
|
+
}
|
|
14
|
+
export function createOpenPanelConfig(input) {
|
|
15
|
+
const clientId = normalize(input.clientId);
|
|
16
|
+
const eventsEndpoint = normalize(input.eventsEndpoint);
|
|
17
|
+
const canonicalUrl = normalize(input.canonicalUrl);
|
|
18
|
+
const proxyPath = withLeadingSlash(stripTrailingSlash(normalize(input.proxyPath) || defaultOpenPanelProxyPath));
|
|
19
|
+
if (!clientId || !eventsEndpoint)
|
|
20
|
+
return null;
|
|
21
|
+
let upstreamApiUrl;
|
|
22
|
+
if (eventsEndpoint.startsWith('http://') ||
|
|
23
|
+
eventsEndpoint.startsWith('https://')) {
|
|
24
|
+
upstreamApiUrl = stripTrailingSlash(eventsEndpoint);
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
if (!canonicalUrl)
|
|
28
|
+
return null;
|
|
29
|
+
try {
|
|
30
|
+
upstreamApiUrl = stripTrailingSlash(new URL(eventsEndpoint, canonicalUrl).toString());
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return {
|
|
37
|
+
clientId,
|
|
38
|
+
proxyPath,
|
|
39
|
+
scriptUrl: joinPath(proxyPath, '/op1.js'),
|
|
40
|
+
upstreamApiUrl,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
export function getOpenPanelConfigFromEnv(env = process.env, options) {
|
|
44
|
+
return createOpenPanelConfig({
|
|
45
|
+
canonicalUrl: env.NEXT_PUBLIC_URL_CANONICAL,
|
|
46
|
+
clientId: env.OPENPANEL_CLIENT_ID,
|
|
47
|
+
eventsEndpoint: env.OPENPANEL_EVENTS_ENDPOINT,
|
|
48
|
+
proxyPath: options?.proxyPath,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
export function isOpenPanelEnabled(config) {
|
|
52
|
+
return config !== null;
|
|
53
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import 'server-only';
|
|
2
|
+
export { OpenPanelAnalytics } from './OpenPanelAnalytics';
|
|
3
|
+
export { createOpenPanelConfig, defaultOpenPanelProxyPath, getOpenPanelConfigFromEnv, isOpenPanelEnabled, } from './config';
|
|
4
|
+
export type { CoonlinkOpenPanelConfig, OpenPanelEnvSource } from './config';
|
package/dist/index.js
ADDED
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import 'server-only';
|
|
2
|
+
import { createOpenPanelConfig, getOpenPanelConfigFromEnv } from './config';
|
|
3
|
+
import type { CoonlinkOpenPanelConfig, OpenPanelEnvSource } from './config';
|
|
4
|
+
export declare function createOpenPanelProxyRouteHandlers(config: CoonlinkOpenPanelConfig | null): {
|
|
5
|
+
GET: any;
|
|
6
|
+
POST: any;
|
|
7
|
+
};
|
|
8
|
+
export declare function createOpenPanelProxyRouteHandlersFromEnv(env?: OpenPanelEnvSource, options?: {
|
|
9
|
+
proxyPath?: string;
|
|
10
|
+
}): {
|
|
11
|
+
GET: any;
|
|
12
|
+
POST: any;
|
|
13
|
+
};
|
|
14
|
+
export { createOpenPanelConfig, getOpenPanelConfigFromEnv };
|
|
15
|
+
export type { CoonlinkOpenPanelConfig, OpenPanelEnvSource };
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import 'server-only';
|
|
2
|
+
import { createRouteHandler } from '@openpanel/nextjs/server';
|
|
3
|
+
import { NextResponse } from 'next/server';
|
|
4
|
+
import { createOpenPanelConfig, getOpenPanelConfigFromEnv, } from './config';
|
|
5
|
+
function notConfigured() {
|
|
6
|
+
return NextResponse.json({
|
|
7
|
+
error: 'OpenPanel is not configured',
|
|
8
|
+
}, {
|
|
9
|
+
status: 503,
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
export function createOpenPanelProxyRouteHandlers(config) {
|
|
13
|
+
if (!config) {
|
|
14
|
+
return {
|
|
15
|
+
GET: notConfigured,
|
|
16
|
+
POST: notConfigured,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
const routeHandler = createRouteHandler({
|
|
20
|
+
apiUrl: config.upstreamApiUrl,
|
|
21
|
+
});
|
|
22
|
+
return {
|
|
23
|
+
GET: routeHandler.GET,
|
|
24
|
+
POST: routeHandler.POST,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
export function createOpenPanelProxyRouteHandlersFromEnv(env = process.env, options) {
|
|
28
|
+
return createOpenPanelProxyRouteHandlers(getOpenPanelConfigFromEnv(env, options));
|
|
29
|
+
}
|
|
30
|
+
export { createOpenPanelConfig, getOpenPanelConfigFromEnv };
|
package/package.json
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "coonlink-openpanel-dev",
|
|
3
|
+
"version": "26.1.1",
|
|
4
|
+
"description": "Reusable OpenPanel proxy integration for Next.js projects",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"homepage": "https://dev.coonlink.com",
|
|
7
|
+
"main": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"files": [
|
|
10
|
+
"dist",
|
|
11
|
+
"README.md"
|
|
12
|
+
],
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build": "tsc -p tsconfig.build.json",
|
|
15
|
+
"typecheck": "tsc -p tsconfig.build.json --noEmit"
|
|
16
|
+
},
|
|
17
|
+
"exports": {
|
|
18
|
+
".": {
|
|
19
|
+
"types": "./dist/index.d.ts",
|
|
20
|
+
"default": "./dist/index.js"
|
|
21
|
+
},
|
|
22
|
+
"./client": {
|
|
23
|
+
"types": "./dist/client.d.ts",
|
|
24
|
+
"default": "./dist/client.js"
|
|
25
|
+
},
|
|
26
|
+
"./server": {
|
|
27
|
+
"types": "./dist/server.d.ts",
|
|
28
|
+
"default": "./dist/server.js"
|
|
29
|
+
},
|
|
30
|
+
"./package.json": "./package.json"
|
|
31
|
+
},
|
|
32
|
+
"peerDependencies": {
|
|
33
|
+
"@openpanel/nextjs": "^1.4.0",
|
|
34
|
+
"next": ">=16.0.0",
|
|
35
|
+
"react": ">=19.0.0",
|
|
36
|
+
"react-dom": ">=19.0.0"
|
|
37
|
+
}
|
|
38
|
+
}
|