@onabl/next 0.0.0-stage → 1.0.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/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2026 Onabl (Pty) Ltd. All rights reserved.
2
+
3
+ This package is proprietary software owned by Onabl (Pty) Ltd ("Onabl").
4
+
5
+ You may install and use this package only to connect your own websites and
6
+ applications to the Onabl service, while you hold an Onabl account or have
7
+ Onabl's written permission, and subject to Onabl's terms of service.
8
+
9
+ Without Onabl's prior written permission, you may not:
10
+
11
+ 1. copy, modify, publish, distribute, sublicense or sell this package or any
12
+ part of it, except as part of an application that uses the Onabl service;
13
+ 2. decompile, reverse engineer or otherwise try to derive the source code,
14
+ algorithms or pricing logic of the Onabl service from it; or
15
+ 3. use this package, or any part of it, to build or support a product or
16
+ service that competes with Onabl.
17
+
18
+ THIS PACKAGE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
+ FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL ONABL
21
+ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY ARISING FROM, OUT OF OR IN
22
+ CONNECTION WITH THIS PACKAGE OR ITS USE.
package/README.md CHANGED
@@ -1,3 +1,63 @@
1
- # Temporary Holding Version
1
+ # `@onabl/next`
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Next.js integration for the onabl SDK. Provides the server-side route
4
+ handlers and helpers that keep your onabl secret key out of the browser, so
5
+ `@onabl/react`'s hooks have a same-origin proxy to call.
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ npm install @onabl/next @onabl/react
11
+ ```
12
+
13
+ ## Usage
14
+
15
+ Mount the route handlers at a catch-all API route:
16
+
17
+ ```ts
18
+ // app/api/onabl/[...onabl]/route.ts
19
+ import {createOnablRouteHandlers} from "@onabl/next";
20
+
21
+ export const {GET, POST, PATCH} = createOnablRouteHandlers({
22
+ handle: "acme",
23
+ secretKey: process.env.ONABL_SECRET_KEY!,
24
+ });
25
+ ```
26
+
27
+ Then use `@onabl/react`'s hooks anywhere in your app — `OnablProvider`
28
+ defaults to this route already:
29
+
30
+ ```tsx
31
+ import {OnablProvider} from "@onabl/react";
32
+
33
+ export default function RootLayout({children}: {children: React.ReactNode}) {
34
+ return <OnablProvider>{children}</OnablProvider>;
35
+ }
36
+ ```
37
+
38
+ For a Server Component quote or invoice page (e.g. an emailed link opened
39
+ with `?token=`), use `createOnablServerClient` to fetch data directly, and
40
+ `setAccessCookieOn` to persist the token so subsequent client-side actions
41
+ (accept/decline, POP upload) are authenticated:
42
+
43
+ ```ts
44
+ import {createOnablServerClient, setAccessCookieOn} from "@onabl/next";
45
+
46
+ const onabl = createOnablServerClient({
47
+ handle: "acme",
48
+ secretKey: process.env.ONABL_SECRET_KEY!,
49
+ });
50
+
51
+ const quote = await onabl.quotes.get(uuid, {token});
52
+ ```
53
+
54
+ ## What's included
55
+
56
+ - `createOnablRouteHandlers(config)` — the `{GET, POST, PATCH}` route
57
+ handler factory for your proxy route
58
+ - `createOnablServerClient(config)` — a server-side client for Server
59
+ Components/Server Actions
60
+ - `setAccessCookieOn(res, uuid, token)` — persists a customer access token
61
+ as an httpOnly cookie
62
+ - `accessCookieName`, `ACCESS_COOKIE_MAX_AGE_SECONDS` — cookie naming/expiry
63
+ constants, if you need to read the cookie yourself (e.g. in middleware)
@@ -0,0 +1,51 @@
1
+ import { NextRequest, NextResponse } from 'next/server';
2
+ import { OnablClientConfig, OnablClient } from '@onabl/js';
3
+
4
+ type OnablNextConfig = OnablClientConfig;
5
+
6
+ interface OnablRouteHandlers {
7
+ GET: (req: NextRequest) => Promise<Response>;
8
+ POST: (req: NextRequest) => Promise<Response>;
9
+ PATCH: (req: NextRequest) => Promise<Response>;
10
+ }
11
+ /**
12
+ * Route-handler factory for the same-origin proxy every @onabl/react hook
13
+ * calls (see packages/react/src/context.tsx) — the reference implementation
14
+ * of onabl.routes() described in docs/SDK-DESIGN.md §14.5.4. Mount the
15
+ * returned {GET, POST, PATCH} at a single catch-all route matching
16
+ * `basePath`, e.g. `app/api/onabl/[...onabl]/route.ts`:
17
+ *
18
+ * export const {GET, POST, PATCH} = createOnablRouteHandlers({
19
+ * handle: "acme",
20
+ * secretKey: process.env.ONABL_SECRET_KEY!,
21
+ * basePath: "/api/onabl",
22
+ * });
23
+ *
24
+ * Holds config.secretKey server-side only — it never reaches the browser.
25
+ * Customer access tokens (quote/invoice-scoped, not secrets in the same
26
+ * sense) are read from/written to an httpOnly cookie per resource UUID (see
27
+ * cookies.ts) so browser-side hooks never need to carry or send one.
28
+ */
29
+ declare function createOnablRouteHandlers(config: OnablNextConfig & {
30
+ basePath?: string;
31
+ }): OnablRouteHandlers;
32
+
33
+ /**
34
+ * For Server Component pages (the quote/invoice view pages) to fetch data
35
+ * with a token read straight off the URL (or props) — not the cookie, since
36
+ * a Server Component can't set cookies itself. Use together with
37
+ * `setAccessCookieOn` in a Route Handler the page's first client-side
38
+ * interaction goes through, or call `setAccessCookieOn` on a redirect
39
+ * response if the page needs the cookie persisted from a bare `?token=`
40
+ * link (e.g. an emailed invoice link opened on a device that never went
41
+ * through the submission flow, so no cookie exists yet).
42
+ */
43
+ declare function createOnablServerClient(config: OnablNextConfig): OnablClient;
44
+ /** Persists a customer access token as the same httpOnly cookie createOnablRouteHandlers() reads — call this from a Route Handler or Server Action, never from render. */
45
+ declare function setAccessCookieOn(res: NextResponse, uuid: string, token: string): void;
46
+
47
+ declare function accessCookieName(uuid: string): string;
48
+ /** 30 days — matches the quote/invoice UUID's own practical lifetime; the API is the real source of truth on expiry, this is just how long the browser bothers to keep offering the token. */
49
+ declare const ACCESS_COOKIE_MAX_AGE_SECONDS: number;
50
+
51
+ export { ACCESS_COOKIE_MAX_AGE_SECONDS, type OnablNextConfig, type OnablRouteHandlers, accessCookieName, createOnablRouteHandlers, createOnablServerClient, setAccessCookieOn };
@@ -0,0 +1,51 @@
1
+ import { NextRequest, NextResponse } from 'next/server';
2
+ import { OnablClientConfig, OnablClient } from '@onabl/js';
3
+
4
+ type OnablNextConfig = OnablClientConfig;
5
+
6
+ interface OnablRouteHandlers {
7
+ GET: (req: NextRequest) => Promise<Response>;
8
+ POST: (req: NextRequest) => Promise<Response>;
9
+ PATCH: (req: NextRequest) => Promise<Response>;
10
+ }
11
+ /**
12
+ * Route-handler factory for the same-origin proxy every @onabl/react hook
13
+ * calls (see packages/react/src/context.tsx) — the reference implementation
14
+ * of onabl.routes() described in docs/SDK-DESIGN.md §14.5.4. Mount the
15
+ * returned {GET, POST, PATCH} at a single catch-all route matching
16
+ * `basePath`, e.g. `app/api/onabl/[...onabl]/route.ts`:
17
+ *
18
+ * export const {GET, POST, PATCH} = createOnablRouteHandlers({
19
+ * handle: "acme",
20
+ * secretKey: process.env.ONABL_SECRET_KEY!,
21
+ * basePath: "/api/onabl",
22
+ * });
23
+ *
24
+ * Holds config.secretKey server-side only — it never reaches the browser.
25
+ * Customer access tokens (quote/invoice-scoped, not secrets in the same
26
+ * sense) are read from/written to an httpOnly cookie per resource UUID (see
27
+ * cookies.ts) so browser-side hooks never need to carry or send one.
28
+ */
29
+ declare function createOnablRouteHandlers(config: OnablNextConfig & {
30
+ basePath?: string;
31
+ }): OnablRouteHandlers;
32
+
33
+ /**
34
+ * For Server Component pages (the quote/invoice view pages) to fetch data
35
+ * with a token read straight off the URL (or props) — not the cookie, since
36
+ * a Server Component can't set cookies itself. Use together with
37
+ * `setAccessCookieOn` in a Route Handler the page's first client-side
38
+ * interaction goes through, or call `setAccessCookieOn` on a redirect
39
+ * response if the page needs the cookie persisted from a bare `?token=`
40
+ * link (e.g. an emailed invoice link opened on a device that never went
41
+ * through the submission flow, so no cookie exists yet).
42
+ */
43
+ declare function createOnablServerClient(config: OnablNextConfig): OnablClient;
44
+ /** Persists a customer access token as the same httpOnly cookie createOnablRouteHandlers() reads — call this from a Route Handler or Server Action, never from render. */
45
+ declare function setAccessCookieOn(res: NextResponse, uuid: string, token: string): void;
46
+
47
+ declare function accessCookieName(uuid: string): string;
48
+ /** 30 days — matches the quote/invoice UUID's own practical lifetime; the API is the real source of truth on expiry, this is just how long the browser bothers to keep offering the token. */
49
+ declare const ACCESS_COOKIE_MAX_AGE_SECONDS: number;
50
+
51
+ export { ACCESS_COOKIE_MAX_AGE_SECONDS, type OnablNextConfig, type OnablRouteHandlers, accessCookieName, createOnablRouteHandlers, createOnablServerClient, setAccessCookieOn };
package/dist/index.js ADDED
@@ -0,0 +1,156 @@
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
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ ACCESS_COOKIE_MAX_AGE_SECONDS: () => ACCESS_COOKIE_MAX_AGE_SECONDS,
24
+ accessCookieName: () => accessCookieName,
25
+ createOnablRouteHandlers: () => createOnablRouteHandlers,
26
+ createOnablServerClient: () => createOnablServerClient,
27
+ setAccessCookieOn: () => setAccessCookieOn
28
+ });
29
+ module.exports = __toCommonJS(index_exports);
30
+
31
+ // src/route-handlers.ts
32
+ var import_js2 = require("@onabl/js");
33
+ var import_server = require("next/server");
34
+
35
+ // src/config.ts
36
+ var import_js = require("@onabl/js");
37
+ function buildClient(config) {
38
+ return (0, import_js.createOnablClient)(config);
39
+ }
40
+
41
+ // src/cookies.ts
42
+ var COOKIE_PREFIX = "onabl_access_";
43
+ function accessCookieName(uuid) {
44
+ return `${COOKIE_PREFIX}${uuid}`;
45
+ }
46
+ var ACCESS_COOKIE_MAX_AGE_SECONDS = 60 * 60 * 24 * 30;
47
+
48
+ // src/route-handlers.ts
49
+ function errorResponse(err) {
50
+ if (err instanceof import_js2.OnablError) {
51
+ return import_server.NextResponse.json({ message: err.message }, { status: err.status ?? 400 });
52
+ }
53
+ return import_server.NextResponse.json({ message: "Unexpected error" }, { status: 500 });
54
+ }
55
+ function subpath(req, basePath) {
56
+ const { pathname } = req.nextUrl;
57
+ return pathname.startsWith(basePath) ? pathname.slice(basePath.length) : pathname;
58
+ }
59
+ function createOnablRouteHandlers(config) {
60
+ const basePath = config.basePath ?? "/api/onabl";
61
+ const client = buildClient(config);
62
+ async function handleGet(req) {
63
+ const path = subpath(req, basePath);
64
+ if (path === "/forms/validate-code") {
65
+ const code = req.nextUrl.searchParams.get("code") ?? "";
66
+ const result = await client.forms.validateDiscountCode(code);
67
+ return import_server.NextResponse.json(result);
68
+ }
69
+ return import_server.NextResponse.json({ message: "Not found" }, { status: 404 });
70
+ }
71
+ async function handlePost(req) {
72
+ const path = subpath(req, basePath);
73
+ if (path === "/submissions") {
74
+ const body = await req.json();
75
+ const created = await client.submissions.create(body.answers, {
76
+ consentGiven: body.consentGiven,
77
+ discountCode: body.discountCode
78
+ });
79
+ const res = import_server.NextResponse.json({ quoteId: created.quoteId, quoteUrl: created.quoteUrl });
80
+ res.cookies.set(accessCookieName(created.quoteId), created.token, {
81
+ httpOnly: true,
82
+ sameSite: "lax",
83
+ secure: true,
84
+ maxAge: ACCESS_COOKIE_MAX_AGE_SECONDS,
85
+ path: "/"
86
+ });
87
+ return res;
88
+ }
89
+ if (path === "/storage/presign") {
90
+ const body = await req.json();
91
+ const token = req.cookies.get(accessCookieName(body.resourceId))?.value;
92
+ if (!token) return import_server.NextResponse.json({ message: "No access token for this resource" }, { status: 401 });
93
+ const result = await client.storage.presignPop(body.resourceId, body.filename, body.contentType, body.fileSize, { token });
94
+ return import_server.NextResponse.json(result);
95
+ }
96
+ const acceptMatch = /^\/quotes\/([^/]+)\/accept$/.exec(path);
97
+ if (acceptMatch) {
98
+ const uuid = acceptMatch[1];
99
+ const token = req.cookies.get(accessCookieName(uuid))?.value;
100
+ if (!token) return import_server.NextResponse.json({ message: "No access token for this quote" }, { status: 401 });
101
+ await client.quotes.accept(uuid, { token }, await req.json().catch(() => ({})));
102
+ return import_server.NextResponse.json({ accepted: true });
103
+ }
104
+ const declineMatch = /^\/quotes\/([^/]+)\/decline$/.exec(path);
105
+ if (declineMatch) {
106
+ const uuid = declineMatch[1];
107
+ const token = req.cookies.get(accessCookieName(uuid))?.value;
108
+ if (!token) return import_server.NextResponse.json({ message: "No access token for this quote" }, { status: 401 });
109
+ const body = await req.json();
110
+ await client.quotes.decline(uuid, body.declineReason, body.declineNote, { token });
111
+ return import_server.NextResponse.json({ declined: true });
112
+ }
113
+ return import_server.NextResponse.json({ message: "Not found" }, { status: 404 });
114
+ }
115
+ async function handlePatch(req) {
116
+ const path = subpath(req, basePath);
117
+ const popMatch = /^\/invoices\/([^/]+)\/pop$/.exec(path);
118
+ if (popMatch) {
119
+ const uuid = popMatch[1];
120
+ const token = req.cookies.get(accessCookieName(uuid))?.value;
121
+ if (!token) return import_server.NextResponse.json({ message: "No access token for this invoice" }, { status: 401 });
122
+ const body = await req.json();
123
+ await client.invoices.savePopUrl(uuid, body.key, body.milestone, { token });
124
+ return import_server.NextResponse.json({ saved: true });
125
+ }
126
+ return import_server.NextResponse.json({ message: "Not found" }, { status: 404 });
127
+ }
128
+ return {
129
+ GET: (req) => handleGet(req).catch(errorResponse),
130
+ POST: (req) => handlePost(req).catch(errorResponse),
131
+ PATCH: (req) => handlePatch(req).catch(errorResponse)
132
+ };
133
+ }
134
+
135
+ // src/server.ts
136
+ var import_js3 = require("@onabl/js");
137
+ function createOnablServerClient(config) {
138
+ return (0, import_js3.createOnablClient)(config);
139
+ }
140
+ function setAccessCookieOn(res, uuid, token) {
141
+ res.cookies.set(accessCookieName(uuid), token, {
142
+ httpOnly: true,
143
+ sameSite: "lax",
144
+ secure: true,
145
+ maxAge: ACCESS_COOKIE_MAX_AGE_SECONDS,
146
+ path: "/"
147
+ });
148
+ }
149
+ // Annotate the CommonJS export names for ESM import in node:
150
+ 0 && (module.exports = {
151
+ ACCESS_COOKIE_MAX_AGE_SECONDS,
152
+ accessCookieName,
153
+ createOnablRouteHandlers,
154
+ createOnablServerClient,
155
+ setAccessCookieOn
156
+ });
package/dist/index.mjs ADDED
@@ -0,0 +1,125 @@
1
+ // src/route-handlers.ts
2
+ import { OnablError } from "@onabl/js";
3
+ import { NextResponse } from "next/server";
4
+
5
+ // src/config.ts
6
+ import { createOnablClient } from "@onabl/js";
7
+ function buildClient(config) {
8
+ return createOnablClient(config);
9
+ }
10
+
11
+ // src/cookies.ts
12
+ var COOKIE_PREFIX = "onabl_access_";
13
+ function accessCookieName(uuid) {
14
+ return `${COOKIE_PREFIX}${uuid}`;
15
+ }
16
+ var ACCESS_COOKIE_MAX_AGE_SECONDS = 60 * 60 * 24 * 30;
17
+
18
+ // src/route-handlers.ts
19
+ function errorResponse(err) {
20
+ if (err instanceof OnablError) {
21
+ return NextResponse.json({ message: err.message }, { status: err.status ?? 400 });
22
+ }
23
+ return NextResponse.json({ message: "Unexpected error" }, { status: 500 });
24
+ }
25
+ function subpath(req, basePath) {
26
+ const { pathname } = req.nextUrl;
27
+ return pathname.startsWith(basePath) ? pathname.slice(basePath.length) : pathname;
28
+ }
29
+ function createOnablRouteHandlers(config) {
30
+ const basePath = config.basePath ?? "/api/onabl";
31
+ const client = buildClient(config);
32
+ async function handleGet(req) {
33
+ const path = subpath(req, basePath);
34
+ if (path === "/forms/validate-code") {
35
+ const code = req.nextUrl.searchParams.get("code") ?? "";
36
+ const result = await client.forms.validateDiscountCode(code);
37
+ return NextResponse.json(result);
38
+ }
39
+ return NextResponse.json({ message: "Not found" }, { status: 404 });
40
+ }
41
+ async function handlePost(req) {
42
+ const path = subpath(req, basePath);
43
+ if (path === "/submissions") {
44
+ const body = await req.json();
45
+ const created = await client.submissions.create(body.answers, {
46
+ consentGiven: body.consentGiven,
47
+ discountCode: body.discountCode
48
+ });
49
+ const res = NextResponse.json({ quoteId: created.quoteId, quoteUrl: created.quoteUrl });
50
+ res.cookies.set(accessCookieName(created.quoteId), created.token, {
51
+ httpOnly: true,
52
+ sameSite: "lax",
53
+ secure: true,
54
+ maxAge: ACCESS_COOKIE_MAX_AGE_SECONDS,
55
+ path: "/"
56
+ });
57
+ return res;
58
+ }
59
+ if (path === "/storage/presign") {
60
+ const body = await req.json();
61
+ const token = req.cookies.get(accessCookieName(body.resourceId))?.value;
62
+ if (!token) return NextResponse.json({ message: "No access token for this resource" }, { status: 401 });
63
+ const result = await client.storage.presignPop(body.resourceId, body.filename, body.contentType, body.fileSize, { token });
64
+ return NextResponse.json(result);
65
+ }
66
+ const acceptMatch = /^\/quotes\/([^/]+)\/accept$/.exec(path);
67
+ if (acceptMatch) {
68
+ const uuid = acceptMatch[1];
69
+ const token = req.cookies.get(accessCookieName(uuid))?.value;
70
+ if (!token) return NextResponse.json({ message: "No access token for this quote" }, { status: 401 });
71
+ await client.quotes.accept(uuid, { token }, await req.json().catch(() => ({})));
72
+ return NextResponse.json({ accepted: true });
73
+ }
74
+ const declineMatch = /^\/quotes\/([^/]+)\/decline$/.exec(path);
75
+ if (declineMatch) {
76
+ const uuid = declineMatch[1];
77
+ const token = req.cookies.get(accessCookieName(uuid))?.value;
78
+ if (!token) return NextResponse.json({ message: "No access token for this quote" }, { status: 401 });
79
+ const body = await req.json();
80
+ await client.quotes.decline(uuid, body.declineReason, body.declineNote, { token });
81
+ return NextResponse.json({ declined: true });
82
+ }
83
+ return NextResponse.json({ message: "Not found" }, { status: 404 });
84
+ }
85
+ async function handlePatch(req) {
86
+ const path = subpath(req, basePath);
87
+ const popMatch = /^\/invoices\/([^/]+)\/pop$/.exec(path);
88
+ if (popMatch) {
89
+ const uuid = popMatch[1];
90
+ const token = req.cookies.get(accessCookieName(uuid))?.value;
91
+ if (!token) return NextResponse.json({ message: "No access token for this invoice" }, { status: 401 });
92
+ const body = await req.json();
93
+ await client.invoices.savePopUrl(uuid, body.key, body.milestone, { token });
94
+ return NextResponse.json({ saved: true });
95
+ }
96
+ return NextResponse.json({ message: "Not found" }, { status: 404 });
97
+ }
98
+ return {
99
+ GET: (req) => handleGet(req).catch(errorResponse),
100
+ POST: (req) => handlePost(req).catch(errorResponse),
101
+ PATCH: (req) => handlePatch(req).catch(errorResponse)
102
+ };
103
+ }
104
+
105
+ // src/server.ts
106
+ import { createOnablClient as createOnablClient2 } from "@onabl/js";
107
+ function createOnablServerClient(config) {
108
+ return createOnablClient2(config);
109
+ }
110
+ function setAccessCookieOn(res, uuid, token) {
111
+ res.cookies.set(accessCookieName(uuid), token, {
112
+ httpOnly: true,
113
+ sameSite: "lax",
114
+ secure: true,
115
+ maxAge: ACCESS_COOKIE_MAX_AGE_SECONDS,
116
+ path: "/"
117
+ });
118
+ }
119
+ export {
120
+ ACCESS_COOKIE_MAX_AGE_SECONDS,
121
+ accessCookieName,
122
+ createOnablRouteHandlers,
123
+ createOnablServerClient,
124
+ setAccessCookieOn
125
+ };
package/package.json CHANGED
@@ -1,6 +1,47 @@
1
1
  {
2
2
  "name": "@onabl/next",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "1.0.0",
4
+ "description": "Next.js integration for the Onabl SDK — server-action-free route-handler factory, cookie-aware client, RSC-safe boundary.",
5
+ "license": "SEE LICENSE IN LICENSE",
6
+ "homepage": "https://onabl.com",
7
+ "publishConfig": {
8
+ "access": "public"
9
+ },
10
+ "files": [
11
+ "dist"
12
+ ],
13
+ "main": "./dist/index.js",
14
+ "module": "./dist/index.mjs",
15
+ "types": "./dist/index.d.ts",
16
+ "exports": {
17
+ ".": {
18
+ "types": "./dist/index.d.ts",
19
+ "import": "./dist/index.mjs",
20
+ "require": "./dist/index.js"
21
+ }
22
+ },
23
+ "devDependencies": {
24
+ "@types/react": "^19",
25
+ "eslint": "latest",
26
+ "next": "latest",
27
+ "tsup": "^8.0.0",
28
+ "vitest": "^1.6.0",
29
+ "typescript": "^5.4.0",
30
+ "@onabl/typescript-config": "0.0.1",
31
+ "@onabl/eslint-config": "0.0.1"
32
+ },
33
+ "dependencies": {
34
+ "@onabl/js": "1.0.0",
35
+ "@onabl/react": "1.0.0"
36
+ },
37
+ "peerDependencies": {
38
+ "next": "^16",
39
+ "react": "^19"
40
+ },
41
+ "scripts": {
42
+ "build": "tsup && node ../js/check-bundle.mjs",
43
+ "dev": "tsup --watch",
44
+ "lint": "eslint src",
45
+ "test": "vitest run"
46
+ }
6
47
  }