@ownichat/next 0.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/CHANGELOG.md ADDED
@@ -0,0 +1,17 @@
1
+ # Changelog
2
+
3
+ All notable changes to `@ownichat/next` are documented here. This project follows
4
+ [Semantic Versioning](https://semver.org/).
5
+
6
+ ## 0.1.0
7
+
8
+ First public release.
9
+
10
+ - `<OwniChat>` — server component that renders the widget through `next/script`, adding
11
+ no client JavaScript of its own
12
+ - `@ownichat/next/client` — re-exports the hooks and components from `@ownichat/react`
13
+ - `@ownichat/next/server`:
14
+ - `createWebhookHandler()` — App Router route handler that verifies the signature over
15
+ the raw request body before invoking your callback
16
+ - `createOwniClientFromEnv()` — API client built from `OWNI_API_KEY`, throwing on a
17
+ missing key rather than failing mid-sync
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 owni.chat
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,160 @@
1
+ <div align="center">
2
+
3
+ # @ownichat/next
4
+
5
+ **Next.js integration for the [owni.chat](https://owni.chat) AI chat widget.**
6
+
7
+ [![npm](https://img.shields.io/npm/v/@ownichat/next?color=306cf1)](https://www.npmjs.com/package/@ownichat/next)
8
+ [![bundle](https://img.shields.io/bundlephobia/minzip/@ownichat/next?color=306cf1)](https://bundlephobia.com/package/@ownichat/next)
9
+ [![types](https://img.shields.io/npm/types/@ownichat/next?color=306cf1)](https://www.npmjs.com/package/@ownichat/next)
10
+ [![license](https://img.shields.io/npm/l/@ownichat/next?color=306cf1)](./LICENSE)
11
+
12
+ </div>
13
+
14
+ ```sh
15
+ npm install @ownichat/next
16
+ ```
17
+
18
+ | | |
19
+ | --- | --- |
20
+ | ⚡ **Server component** | `<OwniChat>` adds the widget with no client JS of its own |
21
+ | 🎛️ **Client hooks** | `@ownichat/next/client` — open the chat from your own button |
22
+ | 📥 **Webhook route** | Signature-verified route handler in three lines |
23
+ | 🛍️ **Catalog sync** | Typed API client for Server Actions and cron routes |
24
+
25
+ App Router and Pages Router. Next.js 13.4+, React 18 and 19.
26
+
27
+ ## Add the widget
28
+
29
+ ```tsx
30
+ // app/layout.tsx
31
+ import { OwniChat } from '@ownichat/next';
32
+
33
+ export default function RootLayout({ children }: { children: React.ReactNode }) {
34
+ return (
35
+ <html lang="en">
36
+ <body>
37
+ {children}
38
+ <OwniChat projectKey={process.env.NEXT_PUBLIC_OWNI_PROJECT_KEY!} />
39
+ </body>
40
+ </html>
41
+ );
42
+ }
43
+ ```
44
+
45
+ `<OwniChat>` is a **server component** — no `'use client'`, no client bundle cost
46
+ beyond the widget itself. It renders `next/script` with `strategy="afterInteractive"`,
47
+ so the widget never competes with your content for bandwidth.
48
+
49
+ Set `<html lang>`: the widget uses it to pick its language.
50
+
51
+ Pages Router works the same way from `pages/_app.tsx`.
52
+
53
+ ## Control it from a client component
54
+
55
+ ```tsx
56
+ 'use client';
57
+ import { OwniChatProvider, useOwniChat } from '@ownichat/next/client';
58
+
59
+ export function ChatButton() {
60
+ const chat = useOwniChat();
61
+ return <button onClick={chat.open}>Chat with us</button>;
62
+ }
63
+ ```
64
+
65
+ The hooks need a provider in the tree. Since `<OwniChat>` already loads the script,
66
+ render it with `autoLoad={false}`:
67
+
68
+ ```tsx
69
+ 'use client';
70
+ import { OwniChatProvider } from '@ownichat/next/client';
71
+
72
+ export function Providers({ children }: { children: React.ReactNode }) {
73
+ return (
74
+ <OwniChatProvider projectKey={process.env.NEXT_PUBLIC_OWNI_PROJECT_KEY!} autoLoad={false}>
75
+ {children}
76
+ </OwniChatProvider>
77
+ );
78
+ }
79
+ ```
80
+
81
+ Everything from [`@ownichat/react`](https://www.npmjs.com/package/@ownichat/react) —
82
+ `useOwniChat`, `useOwniEvent`, `OwniChatInline` — is re-exported from
83
+ `@ownichat/next/client`.
84
+
85
+ ## Receive leads
86
+
87
+ owni.chat signs every webhook. `createWebhookHandler` verifies the signature and the
88
+ timestamp for you:
89
+
90
+ ```ts
91
+ // app/api/owni/webhook/route.ts
92
+ import { createWebhookHandler } from '@ownichat/next/server';
93
+
94
+ export const POST = createWebhookHandler({
95
+ onLead: async (fields) => {
96
+ await db.lead.create({ data: fields });
97
+ },
98
+ });
99
+ ```
100
+
101
+ Set `OWNI_WEBHOOK_SECRET` to the signing secret shown when you connect the webhook in
102
+ **Integrations → Webhooks**, then paste your route URL there.
103
+
104
+ It reads the raw body with `request.text()` — the signature covers the exact bytes
105
+ sent, so `request.json()` would not verify. Invalid deliveries get 401 and never reach
106
+ your callback; a missing secret gets 503 rather than accepting anything.
107
+
108
+ ## Sync a product catalog
109
+
110
+ ```ts
111
+ // app/actions/sync-catalog.ts
112
+ 'use server';
113
+ import { createOwniClientFromEnv } from '@ownichat/next/server';
114
+
115
+ export async function syncCatalog() {
116
+ const owni = createOwniClientFromEnv();
117
+
118
+ const products = await db.product.findMany();
119
+ await owni.products.bulkUpsert(
120
+ products.map((product) => ({
121
+ external_id: String(product.id),
122
+ title: product.name,
123
+ url: `https://shop.example.com/p/${product.slug}`,
124
+ price: product.price.toFixed(2),
125
+ currency: 'EUR',
126
+ availability: product.stock > 0 ? 'in_stock' : 'out_of_stock',
127
+ })),
128
+ );
129
+ }
130
+ ```
131
+
132
+ Batching to the API's 100-item limit is handled for you. Full client documentation
133
+ lives in [`@ownichat/sdk`](https://www.npmjs.com/package/@ownichat/sdk).
134
+
135
+ ## Environment variables
136
+
137
+ | Variable | Where | Purpose |
138
+ | --- | --- | --- |
139
+ | `NEXT_PUBLIC_OWNI_PROJECT_KEY` | client | Public `pk_…` key for the widget |
140
+ | `OWNI_API_KEY` | **server only** | `ak_live_…` — catalog and knowledge writes |
141
+ | `OWNI_WEBHOOK_SECRET` | server only | `whsec_…` — webhook verification |
142
+ | `OWNI_API_BASE_URL` | server only | Self-hosted instances |
143
+
144
+ Never prefix `OWNI_API_KEY` with `NEXT_PUBLIC_` — that would ship a write-capable
145
+ credential to every visitor. `createOwniClientFromEnv()` throws when the key is
146
+ missing, so a misconfigured deployment fails immediately instead of mid-sync.
147
+
148
+ ## Related packages
149
+
150
+ | Package | For |
151
+ | --- | --- |
152
+ | [`@ownichat/sdk`](https://www.npmjs.com/package/@ownichat/sdk) | The API client re-exported by `/server`, documented in full |
153
+ | [`@ownichat/react`](https://www.npmjs.com/package/@ownichat/react) | The hooks re-exported by `/client`, documented in full |
154
+
155
+ Not on Next.js? owni.chat also ships official plugins for WordPress/WooCommerce, Shopify and
156
+ OpenCart — see [owni.chat/integrations](https://owni.chat/integrations).
157
+
158
+ ## License
159
+
160
+ MIT © [owni.chat](https://owni.chat)
@@ -0,0 +1,39 @@
1
+ "use client";
2
+ 'use strict';
3
+
4
+ var react = require('@ownichat/react');
5
+
6
+
7
+
8
+ Object.defineProperty(exports, "DEFAULT_SCRIPT_URL", {
9
+ enumerable: true,
10
+ get: function () { return react.DEFAULT_SCRIPT_URL; }
11
+ });
12
+ Object.defineProperty(exports, "OwniChatInline", {
13
+ enumerable: true,
14
+ get: function () { return react.OwniChatInline; }
15
+ });
16
+ Object.defineProperty(exports, "OwniChatProvider", {
17
+ enumerable: true,
18
+ get: function () { return react.OwniChatProvider; }
19
+ });
20
+ Object.defineProperty(exports, "OwniChatWidget", {
21
+ enumerable: true,
22
+ get: function () { return react.OwniChatWidget; }
23
+ });
24
+ Object.defineProperty(exports, "inlineTarget", {
25
+ enumerable: true,
26
+ get: function () { return react.inlineTarget; }
27
+ });
28
+ Object.defineProperty(exports, "useOwniChat", {
29
+ enumerable: true,
30
+ get: function () { return react.useOwniChat; }
31
+ });
32
+ Object.defineProperty(exports, "useOwniChatContext", {
33
+ enumerable: true,
34
+ get: function () { return react.useOwniChatContext; }
35
+ });
36
+ Object.defineProperty(exports, "useOwniEvent", {
37
+ enumerable: true,
38
+ get: function () { return react.useOwniEvent; }
39
+ });
@@ -0,0 +1 @@
1
+ export { DEFAULT_SCRIPT_URL, OwniChatContextValue, OwniChatInline, OwniChatInlineProps, OwniChatProvider, OwniChatProviderProps, OwniChatWidget, OwniChatWidgetProps, OwniEventName, OwniEventPayload, OwniGlobalApi, OwniInstanceApi, OwniMessageEvent, OwniVisitorContact, UseOwniChat, inlineTarget, useOwniChat, useOwniChatContext, useOwniEvent } from '@ownichat/react';
@@ -0,0 +1 @@
1
+ export { DEFAULT_SCRIPT_URL, OwniChatContextValue, OwniChatInline, OwniChatInlineProps, OwniChatProvider, OwniChatProviderProps, OwniChatWidget, OwniChatWidgetProps, OwniEventName, OwniEventPayload, OwniGlobalApi, OwniInstanceApi, OwniMessageEvent, OwniVisitorContact, UseOwniChat, inlineTarget, useOwniChat, useOwniChatContext, useOwniEvent } from '@ownichat/react';
package/dist/client.js ADDED
@@ -0,0 +1,2 @@
1
+ "use client";
2
+ export { DEFAULT_SCRIPT_URL, OwniChatInline, OwniChatProvider, OwniChatWidget, inlineTarget, useOwniChat, useOwniChatContext, useOwniEvent } from '@ownichat/react';
package/dist/index.cjs ADDED
@@ -0,0 +1,27 @@
1
+ 'use strict';
2
+
3
+ var Script = require('next/script');
4
+ var jsxRuntime = require('react/jsx-runtime');
5
+
6
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
7
+
8
+ var Script__default = /*#__PURE__*/_interopDefault(Script);
9
+
10
+ // src/index.tsx
11
+ var DEFAULT_SCRIPT_URL = "https://app.owni.chat/widget/embed.js";
12
+ var OwniChat = ({
13
+ projectKey,
14
+ scriptUrl = DEFAULT_SCRIPT_URL,
15
+ strategy = "afterInteractive"
16
+ }) => /* @__PURE__ */ jsxRuntime.jsx(
17
+ Script__default.default,
18
+ {
19
+ id: "owni-chat-widget",
20
+ src: scriptUrl,
21
+ strategy,
22
+ "data-project-key": projectKey
23
+ }
24
+ );
25
+
26
+ exports.DEFAULT_SCRIPT_URL = DEFAULT_SCRIPT_URL;
27
+ exports.OwniChat = OwniChat;
@@ -0,0 +1,41 @@
1
+ import * as react from 'react';
2
+
3
+ declare const DEFAULT_SCRIPT_URL = "https://app.owni.chat/widget/embed.js";
4
+ type OwniChatProps = {
5
+ /** Public project key (`pk_…`). Safe to expose — it identifies, it does not authorize. */
6
+ projectKey: string;
7
+ /** Override for self-hosted instances. */
8
+ scriptUrl?: string;
9
+ /**
10
+ * Next.js loading strategy. The default defers the widget until the page is
11
+ * interactive, so it never competes with your content for bandwidth.
12
+ */
13
+ strategy?: 'afterInteractive' | 'lazyOnload' | 'beforeInteractive';
14
+ };
15
+ /**
16
+ * Drops the owni.chat widget onto every page it renders.
17
+ *
18
+ * A server component by design — no `'use client'` — so adding chat to an App Router
19
+ * layout costs nothing in client JavaScript beyond the widget itself:
20
+ *
21
+ * ```tsx
22
+ * // app/layout.tsx
23
+ * import { OwniChat } from '@ownichat/next';
24
+ *
25
+ * export default function RootLayout({ children }) {
26
+ * return (
27
+ * <html lang="en">
28
+ * <body>
29
+ * {children}
30
+ * <OwniChat projectKey={process.env.NEXT_PUBLIC_OWNI_PROJECT_KEY!} />
31
+ * </body>
32
+ * </html>
33
+ * );
34
+ * }
35
+ * ```
36
+ *
37
+ * The widget reads the page's `<html lang>` to pick its language, so set it.
38
+ */
39
+ declare const OwniChat: ({ projectKey, scriptUrl, strategy, }: OwniChatProps) => react.JSX.Element;
40
+
41
+ export { DEFAULT_SCRIPT_URL, OwniChat, type OwniChatProps, type OwniChatProps as OwniChatWidgetProps };
@@ -0,0 +1,41 @@
1
+ import * as react from 'react';
2
+
3
+ declare const DEFAULT_SCRIPT_URL = "https://app.owni.chat/widget/embed.js";
4
+ type OwniChatProps = {
5
+ /** Public project key (`pk_…`). Safe to expose — it identifies, it does not authorize. */
6
+ projectKey: string;
7
+ /** Override for self-hosted instances. */
8
+ scriptUrl?: string;
9
+ /**
10
+ * Next.js loading strategy. The default defers the widget until the page is
11
+ * interactive, so it never competes with your content for bandwidth.
12
+ */
13
+ strategy?: 'afterInteractive' | 'lazyOnload' | 'beforeInteractive';
14
+ };
15
+ /**
16
+ * Drops the owni.chat widget onto every page it renders.
17
+ *
18
+ * A server component by design — no `'use client'` — so adding chat to an App Router
19
+ * layout costs nothing in client JavaScript beyond the widget itself:
20
+ *
21
+ * ```tsx
22
+ * // app/layout.tsx
23
+ * import { OwniChat } from '@ownichat/next';
24
+ *
25
+ * export default function RootLayout({ children }) {
26
+ * return (
27
+ * <html lang="en">
28
+ * <body>
29
+ * {children}
30
+ * <OwniChat projectKey={process.env.NEXT_PUBLIC_OWNI_PROJECT_KEY!} />
31
+ * </body>
32
+ * </html>
33
+ * );
34
+ * }
35
+ * ```
36
+ *
37
+ * The widget reads the page's `<html lang>` to pick its language, so set it.
38
+ */
39
+ declare const OwniChat: ({ projectKey, scriptUrl, strategy, }: OwniChatProps) => react.JSX.Element;
40
+
41
+ export { DEFAULT_SCRIPT_URL, OwniChat, type OwniChatProps, type OwniChatProps as OwniChatWidgetProps };
package/dist/index.js ADDED
@@ -0,0 +1,20 @@
1
+ import Script from 'next/script';
2
+ import { jsx } from 'react/jsx-runtime';
3
+
4
+ // src/index.tsx
5
+ var DEFAULT_SCRIPT_URL = "https://app.owni.chat/widget/embed.js";
6
+ var OwniChat = ({
7
+ projectKey,
8
+ scriptUrl = DEFAULT_SCRIPT_URL,
9
+ strategy = "afterInteractive"
10
+ }) => /* @__PURE__ */ jsx(
11
+ Script,
12
+ {
13
+ id: "owni-chat-widget",
14
+ src: scriptUrl,
15
+ strategy,
16
+ "data-project-key": projectKey
17
+ }
18
+ );
19
+
20
+ export { DEFAULT_SCRIPT_URL, OwniChat };
@@ -0,0 +1,61 @@
1
+ 'use strict';
2
+
3
+ var sdk = require('@ownichat/sdk');
4
+ var webhooks = require('@ownichat/sdk/webhooks');
5
+
6
+ // src/server.ts
7
+ var createOwniClientFromEnv = (options = {}) => {
8
+ const apiKey = options.apiKey ?? process.env.OWNI_API_KEY;
9
+ if (!apiKey) {
10
+ throw new Error(
11
+ "OWNI_API_KEY is not set. Add it to your server environment \u2014 never as NEXT_PUBLIC_."
12
+ );
13
+ }
14
+ const baseUrl = options.baseUrl ?? process.env.OWNI_API_BASE_URL;
15
+ return sdk.createOwniClient({ ...options, apiKey, ...baseUrl ? { baseUrl } : {} });
16
+ };
17
+ var createWebhookHandler = (options = {}) => {
18
+ return async (request) => {
19
+ const secret = options.secret ?? process.env.OWNI_WEBHOOK_SECRET;
20
+ if (!secret) {
21
+ return Response.json({ message: "Webhook secret is not configured" }, { status: 503 });
22
+ }
23
+ const body = await request.text();
24
+ const result = webhooks.parseWebhookRequest({
25
+ body,
26
+ headers: request.headers,
27
+ secret,
28
+ ...options.toleranceSeconds !== void 0 ? { toleranceSeconds: options.toleranceSeconds } : {}
29
+ });
30
+ if (!result.valid) {
31
+ return Response.json({ message: result.reason }, { status: 401 });
32
+ }
33
+ const event = result.event;
34
+ if (event.event === "lead_captured" && options.onLead) {
35
+ const data = event.data;
36
+ const fields = data && typeof data === "object" && "fields" in data && data.fields && typeof data.fields === "object" ? data.fields : data;
37
+ await options.onLead(fields, event);
38
+ }
39
+ await options.onEvent?.(event);
40
+ return Response.json({ ok: true });
41
+ };
42
+ };
43
+
44
+ Object.defineProperty(exports, "OwniApiError", {
45
+ enumerable: true,
46
+ get: function () { return sdk.OwniApiError; }
47
+ });
48
+ Object.defineProperty(exports, "OwniConnectionError", {
49
+ enumerable: true,
50
+ get: function () { return sdk.OwniConnectionError; }
51
+ });
52
+ Object.defineProperty(exports, "parseWebhookRequest", {
53
+ enumerable: true,
54
+ get: function () { return webhooks.parseWebhookRequest; }
55
+ });
56
+ Object.defineProperty(exports, "verifyWebhookSignature", {
57
+ enumerable: true,
58
+ get: function () { return webhooks.verifyWebhookSignature; }
59
+ });
60
+ exports.createOwniClientFromEnv = createOwniClientFromEnv;
61
+ exports.createWebhookHandler = createWebhookHandler;
@@ -0,0 +1,47 @@
1
+ import { OwniClientOptions, OwniClient } from '@ownichat/sdk';
2
+ export { OwniApiError, OwniClient, OwniConnectionError, OwniProductInput } from '@ownichat/sdk';
3
+ import { OwniWebhookEvent } from '@ownichat/sdk/webhooks';
4
+ export { OwniWebhookEvent, parseWebhookRequest, verifyWebhookSignature } from '@ownichat/sdk/webhooks';
5
+
6
+ /**
7
+ * Server-only helpers: an API client built from the environment, and a ready-made
8
+ * route handler for owni.chat's signed webhooks.
9
+ *
10
+ * Nothing here may be imported into a client component — `OWNI_API_KEY` is a secret.
11
+ */
12
+
13
+ type CreateOwniClientOptions = Partial<OwniClientOptions>;
14
+ /**
15
+ * Builds a client from `OWNI_API_KEY` (and optionally `OWNI_API_BASE_URL`).
16
+ *
17
+ * Throws when the key is missing rather than failing on the first request, so a
18
+ * misconfigured deployment surfaces at startup instead of during a customer's sync.
19
+ */
20
+ declare const createOwniClientFromEnv: (options?: CreateOwniClientOptions) => OwniClient;
21
+ type WebhookHandlerOptions = {
22
+ /** Defaults to `OWNI_WEBHOOK_SECRET`. */
23
+ secret?: string;
24
+ /** Called for a captured lead. Throwing returns 500, which owni.chat surfaces to the merchant. */
25
+ onLead?: (data: Record<string, unknown>, event: OwniWebhookEvent) => void | Promise<void>;
26
+ /** Called for every verified event, including `test`. */
27
+ onEvent?: (event: OwniWebhookEvent) => void | Promise<void>;
28
+ toleranceSeconds?: number;
29
+ };
30
+ /**
31
+ * App Router route handler for owni.chat webhooks.
32
+ *
33
+ * ```ts
34
+ * // app/api/owni/webhook/route.ts
35
+ * import { createWebhookHandler } from '@ownichat/next/server';
36
+ *
37
+ * export const POST = createWebhookHandler({
38
+ * onLead: async (fields) => { await db.leads.create({ data: fields }); },
39
+ * });
40
+ * ```
41
+ *
42
+ * The body is read with `request.text()`, not `request.json()`: the signature covers
43
+ * the exact bytes sent, and re-serialized JSON will not verify.
44
+ */
45
+ declare const createWebhookHandler: (options?: WebhookHandlerOptions) => (request: Request) => Promise<Response>;
46
+
47
+ export { type CreateOwniClientOptions, type WebhookHandlerOptions, createOwniClientFromEnv, createWebhookHandler };
@@ -0,0 +1,47 @@
1
+ import { OwniClientOptions, OwniClient } from '@ownichat/sdk';
2
+ export { OwniApiError, OwniClient, OwniConnectionError, OwniProductInput } from '@ownichat/sdk';
3
+ import { OwniWebhookEvent } from '@ownichat/sdk/webhooks';
4
+ export { OwniWebhookEvent, parseWebhookRequest, verifyWebhookSignature } from '@ownichat/sdk/webhooks';
5
+
6
+ /**
7
+ * Server-only helpers: an API client built from the environment, and a ready-made
8
+ * route handler for owni.chat's signed webhooks.
9
+ *
10
+ * Nothing here may be imported into a client component — `OWNI_API_KEY` is a secret.
11
+ */
12
+
13
+ type CreateOwniClientOptions = Partial<OwniClientOptions>;
14
+ /**
15
+ * Builds a client from `OWNI_API_KEY` (and optionally `OWNI_API_BASE_URL`).
16
+ *
17
+ * Throws when the key is missing rather than failing on the first request, so a
18
+ * misconfigured deployment surfaces at startup instead of during a customer's sync.
19
+ */
20
+ declare const createOwniClientFromEnv: (options?: CreateOwniClientOptions) => OwniClient;
21
+ type WebhookHandlerOptions = {
22
+ /** Defaults to `OWNI_WEBHOOK_SECRET`. */
23
+ secret?: string;
24
+ /** Called for a captured lead. Throwing returns 500, which owni.chat surfaces to the merchant. */
25
+ onLead?: (data: Record<string, unknown>, event: OwniWebhookEvent) => void | Promise<void>;
26
+ /** Called for every verified event, including `test`. */
27
+ onEvent?: (event: OwniWebhookEvent) => void | Promise<void>;
28
+ toleranceSeconds?: number;
29
+ };
30
+ /**
31
+ * App Router route handler for owni.chat webhooks.
32
+ *
33
+ * ```ts
34
+ * // app/api/owni/webhook/route.ts
35
+ * import { createWebhookHandler } from '@ownichat/next/server';
36
+ *
37
+ * export const POST = createWebhookHandler({
38
+ * onLead: async (fields) => { await db.leads.create({ data: fields }); },
39
+ * });
40
+ * ```
41
+ *
42
+ * The body is read with `request.text()`, not `request.json()`: the signature covers
43
+ * the exact bytes sent, and re-serialized JSON will not verify.
44
+ */
45
+ declare const createWebhookHandler: (options?: WebhookHandlerOptions) => (request: Request) => Promise<Response>;
46
+
47
+ export { type CreateOwniClientOptions, type WebhookHandlerOptions, createOwniClientFromEnv, createWebhookHandler };
package/dist/server.js ADDED
@@ -0,0 +1,44 @@
1
+ import { createOwniClient } from '@ownichat/sdk';
2
+ export { OwniApiError, OwniConnectionError } from '@ownichat/sdk';
3
+ import { parseWebhookRequest } from '@ownichat/sdk/webhooks';
4
+ export { parseWebhookRequest, verifyWebhookSignature } from '@ownichat/sdk/webhooks';
5
+
6
+ // src/server.ts
7
+ var createOwniClientFromEnv = (options = {}) => {
8
+ const apiKey = options.apiKey ?? process.env.OWNI_API_KEY;
9
+ if (!apiKey) {
10
+ throw new Error(
11
+ "OWNI_API_KEY is not set. Add it to your server environment \u2014 never as NEXT_PUBLIC_."
12
+ );
13
+ }
14
+ const baseUrl = options.baseUrl ?? process.env.OWNI_API_BASE_URL;
15
+ return createOwniClient({ ...options, apiKey, ...baseUrl ? { baseUrl } : {} });
16
+ };
17
+ var createWebhookHandler = (options = {}) => {
18
+ return async (request) => {
19
+ const secret = options.secret ?? process.env.OWNI_WEBHOOK_SECRET;
20
+ if (!secret) {
21
+ return Response.json({ message: "Webhook secret is not configured" }, { status: 503 });
22
+ }
23
+ const body = await request.text();
24
+ const result = parseWebhookRequest({
25
+ body,
26
+ headers: request.headers,
27
+ secret,
28
+ ...options.toleranceSeconds !== void 0 ? { toleranceSeconds: options.toleranceSeconds } : {}
29
+ });
30
+ if (!result.valid) {
31
+ return Response.json({ message: result.reason }, { status: 401 });
32
+ }
33
+ const event = result.event;
34
+ if (event.event === "lead_captured" && options.onLead) {
35
+ const data = event.data;
36
+ const fields = data && typeof data === "object" && "fields" in data && data.fields && typeof data.fields === "object" ? data.fields : data;
37
+ await options.onLead(fields, event);
38
+ }
39
+ await options.onEvent?.(event);
40
+ return Response.json({ ok: true });
41
+ };
42
+ };
43
+
44
+ export { createOwniClientFromEnv, createWebhookHandler };
package/package.json ADDED
@@ -0,0 +1,102 @@
1
+ {
2
+ "name": "@ownichat/next",
3
+ "version": "0.1.0",
4
+ "description": "Next.js integration for the owni.chat AI chat widget: App Router component, client hooks and server helpers.",
5
+ "license": "MIT",
6
+ "homepage": "https://owni.chat",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/UpMon-app/chats.git",
10
+ "directory": "integrations/javascript/packages/next"
11
+ },
12
+ "keywords": [
13
+ "owni",
14
+ "ownichat",
15
+ "next",
16
+ "nextjs",
17
+ "chat widget",
18
+ "ai chat"
19
+ ],
20
+ "type": "module",
21
+ "sideEffects": false,
22
+ "exports": {
23
+ ".": {
24
+ "import": {
25
+ "types": "./dist/index.d.ts",
26
+ "default": "./dist/index.js"
27
+ },
28
+ "require": {
29
+ "types": "./dist/index.d.cts",
30
+ "default": "./dist/index.cjs"
31
+ }
32
+ },
33
+ "./client": {
34
+ "import": {
35
+ "types": "./dist/client.d.ts",
36
+ "default": "./dist/client.js"
37
+ },
38
+ "require": {
39
+ "types": "./dist/client.d.cts",
40
+ "default": "./dist/client.cjs"
41
+ }
42
+ },
43
+ "./server": {
44
+ "import": {
45
+ "types": "./dist/server.d.ts",
46
+ "default": "./dist/server.js"
47
+ },
48
+ "require": {
49
+ "types": "./dist/server.d.cts",
50
+ "default": "./dist/server.cjs"
51
+ }
52
+ },
53
+ "./package.json": "./package.json"
54
+ },
55
+ "main": "./dist/index.cjs",
56
+ "module": "./dist/index.js",
57
+ "types": "./dist/index.d.ts",
58
+ "typesVersions": {
59
+ "*": {
60
+ "client": [
61
+ "./dist/client.d.ts"
62
+ ],
63
+ "server": [
64
+ "./dist/server.d.ts"
65
+ ]
66
+ }
67
+ },
68
+ "files": [
69
+ "dist",
70
+ "README.md",
71
+ "CHANGELOG.md",
72
+ "LICENSE"
73
+ ],
74
+ "scripts": {
75
+ "build": "tsup",
76
+ "test": "vitest run",
77
+ "typecheck": "tsc --noEmit"
78
+ },
79
+ "dependencies": {
80
+ "@ownichat/react": "0.1.0",
81
+ "@ownichat/sdk": "0.1.0"
82
+ },
83
+ "peerDependencies": {
84
+ "next": ">=13.4",
85
+ "react": ">=18"
86
+ },
87
+ "devDependencies": {
88
+ "@types/react": "^19.0.0",
89
+ "next": "^15.3.0",
90
+ "react": "^19.0.0"
91
+ },
92
+ "publishConfig": {
93
+ "access": "public"
94
+ },
95
+ "engines": {
96
+ "node": ">=18"
97
+ },
98
+ "bugs": {
99
+ "url": "https://github.com/UpMon-app/chats/issues"
100
+ },
101
+ "author": "owni.chat"
102
+ }