@reactll/connect 1.0.1 → 1.1.0
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 +19 -2
- package/dist/server.d.ts +25 -0
- package/dist/server.js +39 -1
- package/package.json +15 -2
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
# Reactll Connect for Next.js
|
|
1
|
+
# Reactll Connect for Next.js and Node.js
|
|
2
2
|
|
|
3
|
-
Connects a Next.js site to its [Reactll](https://reactll.com) dashboard: visits, calls, WhatsApp and
|
|
3
|
+
Connects a Next.js or any Node.js site (Express, Fastify, Nuxt, Remix, Astro, Hono…) to its [Reactll](https://reactll.com) dashboard: visits, calls, WhatsApp and
|
|
4
4
|
directions clicks, form leads and site health. Built and maintained by **Reactor Technology**.
|
|
5
5
|
|
|
6
6
|
## Install
|
|
@@ -54,6 +54,23 @@ export async function contact(formData: FormData) {
|
|
|
54
54
|
The script stamps every form with the page view id (`_rc_pv`), so Reactll ties the lead to the visit it
|
|
55
55
|
came from. `submitLead(form, fields, options)` takes a plain object instead. Neither ever throws.
|
|
56
56
|
|
|
57
|
+
## Any other Node.js app
|
|
58
|
+
|
|
59
|
+
The same package, without Next.js or React (they are optional):
|
|
60
|
+
|
|
61
|
+
```js
|
|
62
|
+
import { scriptTag, expressHealth, submitLead } from '@reactll/connect/server';
|
|
63
|
+
|
|
64
|
+
app.use(expressHealth()); // Express / Connect / node:http — GET /api/reactll/health
|
|
65
|
+
res.render('page', { reactll: scriptTag() }); // put {{{ reactll }}} / <%- reactll %> in the <head>
|
|
66
|
+
|
|
67
|
+
// after your form was validated and saved:
|
|
68
|
+
await submitLead('Contact', { name, email, message }, { pv: req.body._rc_pv, page: req.get('referer') });
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Frameworks on web `Request`/`Response` (Hono, Remix, Nuxt/h3, Astro, Bun, Deno): route
|
|
72
|
+
`GET /api/reactll/health` to `health(request)` from `@reactll/connect/server`.
|
|
73
|
+
|
|
57
74
|
## License
|
|
58
75
|
|
|
59
76
|
MIT © Reactor Technology
|
package/dist/server.d.ts
CHANGED
|
@@ -21,6 +21,11 @@ export declare function submitLead(form: string, fields: Fields, options?: LeadO
|
|
|
21
21
|
export declare function submitLeadFromFormData(form: string, data: FormData, options?: LeadOptions & {
|
|
22
22
|
headers?: Headers;
|
|
23
23
|
}): Promise<boolean>;
|
|
24
|
+
/**
|
|
25
|
+
* The script tag for any server-rendered page (Express/EJS, Handlebars, Fastify, Nuxt, Astro…), or ''
|
|
26
|
+
* when not connected. Put it in the <head>. Only the public site key is in it.
|
|
27
|
+
*/
|
|
28
|
+
export declare function scriptTag(token?: string): string;
|
|
24
29
|
/**
|
|
25
30
|
* Hourly health check, asked by Reactll (Next.js has no scheduler of its own). Export it from
|
|
26
31
|
* app/api/reactll/health/route.ts:
|
|
@@ -31,3 +36,23 @@ export declare function submitLeadFromFormData(form: string, data: FormData, opt
|
|
|
31
36
|
*/
|
|
32
37
|
export declare function GET(request: Request): Promise<Response>;
|
|
33
38
|
export declare const dynamic = "force-dynamic";
|
|
39
|
+
/** The health answer as plain data (platform and versions), for any framework. */
|
|
40
|
+
export declare function health(request: Request): Promise<Response>;
|
|
41
|
+
type NodeReq = {
|
|
42
|
+
method?: string;
|
|
43
|
+
url?: string;
|
|
44
|
+
originalUrl?: string;
|
|
45
|
+
headers: Record<string, string | string[] | undefined>;
|
|
46
|
+
};
|
|
47
|
+
type NodeRes = {
|
|
48
|
+
statusCode: number;
|
|
49
|
+
setHeader(name: string, value: string): unknown;
|
|
50
|
+
end(body?: string): unknown;
|
|
51
|
+
};
|
|
52
|
+
/**
|
|
53
|
+
* Express / Connect (and plain node:http) middleware answering Reactll's hourly health question at
|
|
54
|
+
* GET /api/reactll/health. Other requests pass through.
|
|
55
|
+
*
|
|
56
|
+
* app.use(expressHealth());
|
|
57
|
+
*/
|
|
58
|
+
export declare function expressHealth(path?: string): (req: NodeReq, res: NodeRes, next?: () => void) => Promise<void>;
|
package/dist/server.js
CHANGED
|
@@ -65,6 +65,14 @@ export async function submitLeadFromFormData(form, data, options = {}) {
|
|
|
65
65
|
const pv = typeof data.get('_rc_pv') === 'string' ? data.get('_rc_pv') : null;
|
|
66
66
|
return submitLead(form, fields, { ...options, pv: options.pv ?? pv, page: options.page ?? options.headers?.get('referer') ?? null });
|
|
67
67
|
}
|
|
68
|
+
/**
|
|
69
|
+
* The script tag for any server-rendered page (Express/EJS, Handlebars, Fastify, Nuxt, Astro…), or ''
|
|
70
|
+
* when not connected. Put it in the <head>. Only the public site key is in it.
|
|
71
|
+
*/
|
|
72
|
+
export function scriptTag(token) {
|
|
73
|
+
const c = credentials(token);
|
|
74
|
+
return c ? `<script src="${c.u}/c.js" data-site="${c.k}" defer></script>` : '';
|
|
75
|
+
}
|
|
68
76
|
function versionOf(pkg) {
|
|
69
77
|
try {
|
|
70
78
|
return createRequire(import.meta.url)(`${pkg}/package.json`).version;
|
|
@@ -93,7 +101,7 @@ export async function GET(request) {
|
|
|
93
101
|
return Response.json({ error: 'unauthorized' }, { status: 401 });
|
|
94
102
|
}
|
|
95
103
|
return Response.json({
|
|
96
|
-
platform: 'next',
|
|
104
|
+
platform: versionOf('next') ? 'next' : 'node',
|
|
97
105
|
version: VERSION,
|
|
98
106
|
runtime: Object.fromEntries(Object.entries({
|
|
99
107
|
next: versionOf('next'),
|
|
@@ -105,3 +113,33 @@ export async function GET(request) {
|
|
|
105
113
|
}, { headers: { 'Cache-Control': 'no-store' } });
|
|
106
114
|
}
|
|
107
115
|
export const dynamic = 'force-dynamic';
|
|
116
|
+
/** The health answer as plain data (platform and versions), for any framework. */
|
|
117
|
+
export async function health(request) {
|
|
118
|
+
return GET(request);
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Express / Connect (and plain node:http) middleware answering Reactll's hourly health question at
|
|
122
|
+
* GET /api/reactll/health. Other requests pass through.
|
|
123
|
+
*
|
|
124
|
+
* app.use(expressHealth());
|
|
125
|
+
*/
|
|
126
|
+
export function expressHealth(path = '/api/reactll/health') {
|
|
127
|
+
return async (req, res, next) => {
|
|
128
|
+
const url = (req.originalUrl ?? req.url ?? '').split('?')[0];
|
|
129
|
+
if ((req.method ?? 'GET') !== 'GET' || url !== path) {
|
|
130
|
+
next?.();
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
const header = (name) => {
|
|
134
|
+
const v = req.headers[name];
|
|
135
|
+
return Array.isArray(v) ? v[0] : (v ?? '');
|
|
136
|
+
};
|
|
137
|
+
const answer = await GET(new Request('http://localhost' + path, {
|
|
138
|
+
headers: { 'x-reactll-timestamp': header('x-reactll-timestamp'), 'x-reactll-signature': header('x-reactll-signature') },
|
|
139
|
+
}));
|
|
140
|
+
res.statusCode = answer.status;
|
|
141
|
+
res.setHeader('Content-Type', 'application/json');
|
|
142
|
+
res.setHeader('Cache-Control', 'no-store');
|
|
143
|
+
res.end(await answer.text());
|
|
144
|
+
};
|
|
145
|
+
}
|
package/package.json
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@reactll/connect",
|
|
3
|
-
"version": "1.0
|
|
4
|
-
"description": "Reactll Connect for Next.js: visits, clicks, form leads and site health for your Reactll dashboard.",
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"description": "Reactll Connect for Next.js and any Node.js app: visits, clicks, form leads and site health for your Reactll dashboard.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"nextjs",
|
|
7
|
+
"nodejs",
|
|
8
|
+
"express",
|
|
7
9
|
"analytics",
|
|
8
10
|
"leads",
|
|
9
11
|
"reactll"
|
|
@@ -47,5 +49,16 @@
|
|
|
47
49
|
"next": "^15.5.0",
|
|
48
50
|
"react": "^19.0.0",
|
|
49
51
|
"typescript": "^5.6.0"
|
|
52
|
+
},
|
|
53
|
+
"peerDependenciesMeta": {
|
|
54
|
+
"next": {
|
|
55
|
+
"optional": true
|
|
56
|
+
},
|
|
57
|
+
"react": {
|
|
58
|
+
"optional": true
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
"engines": {
|
|
62
|
+
"node": ">=18"
|
|
50
63
|
}
|
|
51
64
|
}
|