@nxisai/nxis 2.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.
@@ -0,0 +1,110 @@
1
+ name: Deploy nxis.js to S3 and GitHub Packages
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - main
7
+ workflow_dispatch:
8
+
9
+ jobs:
10
+ build-and-deploy:
11
+ runs-on: ubuntu-latest
12
+
13
+ steps:
14
+ - name: Checkout code
15
+ uses: actions/checkout@v4
16
+
17
+ - name: Setup Node.js
18
+ uses: actions/setup-node@v4
19
+ with:
20
+ node-version: '20'
21
+ cache: 'npm'
22
+
23
+ - name: Install dependencies
24
+ run: npm ci
25
+
26
+ - name: Build project
27
+ env:
28
+ NXIS_API_HOST: ${{ vars.NXIS_API_HOST || secrets.NXIS_API_HOST }}
29
+ run: npx rollup --config rollup.config.js
30
+
31
+ - name: Configure AWS credentials
32
+ uses: aws-actions/configure-aws-credentials@v4
33
+ with:
34
+ aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
35
+ aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
36
+ aws-region: ${{ vars.AWS_REGION || secrets.AWS_REGION }}
37
+
38
+ - name: Deploy to S3
39
+ run: aws s3 cp build/nxis.js s3://nxis-ai-static/nxis.js
40
+
41
+ publish-npm:
42
+ needs: build-and-deploy
43
+ runs-on: ubuntu-latest
44
+ permissions:
45
+ contents: read
46
+ packages: write
47
+
48
+ steps:
49
+ - name: Checkout code
50
+ uses: actions/checkout@v4
51
+
52
+ - name: Setup Node.js for GitHub Packages
53
+ uses: actions/setup-node@v4
54
+ with:
55
+ node-version: '20'
56
+ cache: 'npm'
57
+ registry-url: 'https://npm.pkg.github.com'
58
+ scope: '@nxisai'
59
+
60
+ - name: Install dependencies
61
+ run: npm ci
62
+
63
+ - name: Build SSR package
64
+ env:
65
+ NXIS_API_HOST: ${{ vars.NXIS_API_HOST || secrets.NXIS_API_HOST }}
66
+ run: |
67
+ npx rollup --config rollup.config.js --environment NXIS_API_HOST:$NXIS_API_HOST
68
+ npm run build:types
69
+
70
+ - name: Scope package for GitHub Packages
71
+ run: npm pkg set name='@nxisai/nxis'
72
+
73
+ - name: Publish to GitHub Packages
74
+ run: npm publish
75
+ env:
76
+ NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
77
+
78
+ publish-npmjs:
79
+ needs: publish-npm
80
+ runs-on: ubuntu-latest
81
+
82
+ steps:
83
+ - name: Checkout code
84
+ uses: actions/checkout@v4
85
+
86
+ - name: Setup Node.js for npm
87
+ uses: actions/setup-node@v4
88
+ with:
89
+ node-version: '20'
90
+ cache: 'npm'
91
+ registry-url: 'https://registry.npmjs.org'
92
+ scope: '@nxisai'
93
+
94
+ - name: Install dependencies
95
+ run: npm ci
96
+
97
+ - name: Build package
98
+ env:
99
+ NXIS_API_HOST: ${{ vars.NXIS_API_HOST || secrets.NXIS_API_HOST }}
100
+ run: |
101
+ npx rollup --config rollup.config.js --environment NXIS_API_HOST:$NXIS_API_HOST
102
+ npm run build:types
103
+
104
+ - name: Scope package for npm
105
+ run: npm pkg set name='@nxisai/nxis'
106
+
107
+ - name: Publish to npm
108
+ run: npm publish --access public
109
+ env:
110
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
package/README.md ADDED
@@ -0,0 +1,401 @@
1
+ # Nxis.js
2
+
3
+ ## Overview
4
+ Nxis.js is a lightweight JavaScript client designed to integrate with the Nxis AI platform. It dynamically injects JSON-LD structured data into web pages to enhance visibility for search engines, AI agents, and large language models (LLMs). By embedding this structured data, Nxis.js helps transform standard web content into semantic data that is easily discoverable and consumable across the modern search and AI ecosystem.
5
+
6
+ Nxis.js supports **both client-side (browser)** and **server-side rendering (SSR)** environments, making it compatible with modern web frameworks.
7
+
8
+ ## Supported Frameworks
9
+
10
+ | Framework | Rendering | Method |
11
+ |-----------|-----------|--------|
12
+ | **Static HTML / WordPress / Shopify** | Client-side | `<script>` tag |
13
+ | **Next.js** (App Router & Pages Router) | SSR / SSG | `NxisClient` |
14
+ | **Nuxt 3** | SSR / SSG | `NxisClient` |
15
+ | **Remix** | SSR | `NxisClient` |
16
+ | **Astro** | SSR / SSG | `NxisClient` |
17
+ | **SvelteKit** | SSR / SSG | `NxisClient` |
18
+ | **Express / Node.js** | Server | `NxisClient` |
19
+
20
+ ## How It Works
21
+
22
+ Nxis.js supports two integration paths — **client-side (browser)** and **server-side rendering (SSR)**.
23
+
24
+ ### Client-Side (Browser)
25
+
26
+ 1. **Script Loading**: Your page loads `nxis.js` via a `<script>` tag from the Nxis CDN with a signed Nxis JWT token as a query parameter.
27
+ 2. **Request**: On execution, the script sends a request to the Nxis AI Proxy (`/v1/nxis:inject`) with the current page URI, referrer, and session context.
28
+ 3. **Validation & Retrieval**: The Proxy validates the JWT token, and retrieves JSON-LD structured data from the Structured Data Service.
29
+ 4. **Injection**: On success, `nxis.js` creates a `<script type="application/ld+json">` element and appends it to the document `<head>`.
30
+
31
+ ### Server-Side Rendering (SSR)
32
+
33
+ 1. **Initialize**: Your application creates a `NxisClient` with OAuth client credentials. Tokens are managed automatically.
34
+ 2. **Request**: At render time, the client calls the Nxis AI Proxy (`/v1/nxis:ssr`) with the page URI and a Bearer access token.
35
+ 3. **Validation & Retrieval**: The Proxy validates the token, authorizes the requesting domain, and retrieves the structured data.
36
+ 4. **Embedding**: The returned JSON-LD object is serialized directly into a `<script type="application/ld+json">` tag in the initial HTML response — visible to search engines, LLMs, and AI agents without requiring JavaScript execution.
37
+
38
+ ---
39
+
40
+ ## Client-Side Installation (Browser)
41
+
42
+ Add the script tag to the head of your HTML document. Replace `${TOKEN}` with your Nxis JWT token.
43
+
44
+ ```html
45
+ <script
46
+ type="text/javascript"
47
+ async
48
+ src="https://cdn.nxis.ai/nxis.js?token=${TOKEN}"
49
+ crossorigin="anonymous">
50
+ </script>
51
+ ```
52
+
53
+ The JWT token contains your organization and site configuration. No additional data attributes are needed — the CDN extracts everything from the token claims and injects it into the script automatically.
54
+
55
+ This works with any static HTML page, CMS (WordPress, Shopify, Squarespace), or client-rendered SPA.
56
+
57
+ ---
58
+
59
+ ## Server-Side Rendering (SSR)
60
+
61
+ For SSR frameworks, Nxis.js provides a `NxisClient` class that fetches JSON-LD at render time so structured data is present in the initial HTML response — no client-side JavaScript required.
62
+
63
+ **Why SSR matters:** While search engines like Google can render JavaScript, large language models and LLM-based agents do not consistently execute JavaScript when crawling web pages. If structured data is only injected client-side (via the browser `<script>` tag), LLMs and AI agents may never see it. SSR ensures that JSON-LD is embedded directly in the initial HTML response, making your structured data immediately visible to every consumer — from traditional search engine crawlers to LLM training pipelines and AI agents browsing on behalf of users.
64
+
65
+ The SSR client uses **OAuth 2.0 client credentials** for authentication. Access tokens are managed automatically — cached in memory and refreshed before expiration.
66
+
67
+ ### Installation
68
+
69
+ ```bash
70
+ npm install @nxisai/nxis
71
+ ```
72
+
73
+ ### Environment Setup
74
+
75
+ Set these environment variables on your server:
76
+
77
+ ```bash
78
+ NXIS_API_HOST=https://api.nxis.ai
79
+ NXIS_CLIENT_ID=nxis_cid_... # Your OAuth client ID
80
+ NXIS_CLIENT_SECRET=nxis_sec_... # Your OAuth client secret
81
+ NXIS_SITE_ID=... # Your site identifier
82
+ ```
83
+
84
+ ### API Reference
85
+
86
+ ```typescript
87
+ import { NxisClient } from '@nxisai/nxis/ssr';
88
+
89
+ const nxis = new NxisClient({
90
+ clientId: string, // OAuth client ID
91
+ clientSecret: string, // OAuth client secret
92
+ tokenUrl?: string, // Optional token endpoint URL (defaults to NXIS_TOKEN_URL env var)
93
+ scope?: string, // Optional OAuth scope (defaults to "jsonld:read")
94
+ apiHost?: string, // Optional API host override (defaults to NXIS_API_HOST env var)
95
+ });
96
+
97
+ const jsonLd: Record<string, unknown> = await nxis.getStructuredData({
98
+ uri: string, // The full URI of the page being rendered
99
+ siteId: string, // The site identifier
100
+ userAgent?: string, // Optional User-Agent for bot detection
101
+ });
102
+ ```
103
+
104
+ Returns a `Promise<Record<string, unknown>>` — a JSON-LD object ready to be serialized into a `<script type="application/ld+json">` tag.
105
+
106
+ ### Token Lifecycle
107
+
108
+ Access tokens are managed automatically by `NxisClient`:
109
+
110
+ - **Lazy initialization**: No token is fetched until the first `getStructuredData` call.
111
+ - **In-memory cache**: Tokens are cached and reused for subsequent requests.
112
+ - **Auto-refresh**: Tokens are refreshed 60 seconds before expiration.
113
+ - **Concurrency-safe**: Multiple concurrent requests during a refresh all await the same token fetch.
114
+
115
+ ---
116
+
117
+ ### Next.js (App Router)
118
+
119
+ ```tsx
120
+ // app/page.tsx
121
+ import { NxisClient } from '@nxisai/nxis/ssr';
122
+ import { headers } from 'next/headers';
123
+
124
+ const nxis = new NxisClient({
125
+ clientId: process.env.NXIS_CLIENT_ID!,
126
+ clientSecret: process.env.NXIS_CLIENT_SECRET!,
127
+ });
128
+
129
+ export default async function Page() {
130
+ const headersList = await headers();
131
+ const host = headersList.get('host') ?? 'localhost:3000';
132
+ const proto = headersList.get('x-forwarded-proto') ?? 'http';
133
+ const pageUri = `${proto}://${host}/`;
134
+
135
+ const jsonLd = await nxis.getStructuredData({
136
+ uri: pageUri,
137
+ siteId: process.env.NXIS_SITE_ID!,
138
+ userAgent: headersList.get('user-agent') ?? undefined,
139
+ });
140
+
141
+ return (
142
+ <>
143
+ <script
144
+ type="application/ld+json"
145
+ dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
146
+ />
147
+ <main>{/* page content */}</main>
148
+ </>
149
+ );
150
+ }
151
+ ```
152
+
153
+ ### Next.js (Pages Router)
154
+
155
+ ```tsx
156
+ // pages/index.tsx
157
+ import { NxisClient } from '@nxisai/nxis/ssr';
158
+ import Head from 'next/head';
159
+ import { GetServerSideProps } from 'next';
160
+
161
+ const nxis = new NxisClient({
162
+ clientId: process.env.NXIS_CLIENT_ID!,
163
+ clientSecret: process.env.NXIS_CLIENT_SECRET!,
164
+ });
165
+
166
+ export const getServerSideProps: GetServerSideProps = async (context) => {
167
+ const jsonLd = await nxis.getStructuredData({
168
+ uri: `https://yoursite.com${context.resolvedUrl}`,
169
+ siteId: process.env.NXIS_SITE_ID!,
170
+ });
171
+
172
+ return { props: { jsonLd } };
173
+ };
174
+
175
+ export default function Page({ jsonLd }: { jsonLd: Record<string, unknown> }) {
176
+ return (
177
+ <>
178
+ <Head>
179
+ <script
180
+ type="application/ld+json"
181
+ dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
182
+ />
183
+ </Head>
184
+ <main>{/* page content */}</main>
185
+ </>
186
+ );
187
+ }
188
+ ```
189
+
190
+ ### Nuxt 3
191
+
192
+ ```html
193
+ <!-- pages/index.vue -->
194
+ <script setup lang="ts">
195
+ import { NxisClient } from '@nxisai/nxis/ssr';
196
+
197
+ const config = useRuntimeConfig();
198
+ const nxis = new NxisClient({
199
+ clientId: config.nxisClientId,
200
+ clientSecret: config.nxisClientSecret,
201
+ });
202
+
203
+ const { data: jsonLd } = await useAsyncData('nxis-jsonld', () =>
204
+ nxis.getStructuredData({
205
+ uri: `https://yoursite.com${useRoute().fullPath}`,
206
+ siteId: config.nxisSiteId,
207
+ })
208
+ );
209
+
210
+ useHead({
211
+ script: [
212
+ {
213
+ type: 'application/ld+json',
214
+ innerHTML: JSON.stringify(jsonLd.value),
215
+ },
216
+ ],
217
+ });
218
+ </script>
219
+
220
+ <template>
221
+ <main><!-- page content --></main>
222
+ </template>
223
+ ```
224
+
225
+ ### Remix
226
+
227
+ ```tsx
228
+ // app/routes/_index.tsx
229
+ import { json, type LoaderFunctionArgs } from '@remix-run/node';
230
+ import { useLoaderData } from '@remix-run/react';
231
+ import { NxisClient } from '@nxisai/nxis/ssr';
232
+
233
+ const nxis = new NxisClient({
234
+ clientId: process.env.NXIS_CLIENT_ID!,
235
+ clientSecret: process.env.NXIS_CLIENT_SECRET!,
236
+ });
237
+
238
+ export async function loader({ request }: LoaderFunctionArgs) {
239
+ const jsonLd = await nxis.getStructuredData({
240
+ uri: request.url,
241
+ siteId: process.env.NXIS_SITE_ID!,
242
+ });
243
+
244
+ return json({ jsonLd });
245
+ }
246
+
247
+ export default function Index() {
248
+ const { jsonLd } = useLoaderData<typeof loader>();
249
+
250
+ return (
251
+ <>
252
+ <script
253
+ type="application/ld+json"
254
+ dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
255
+ />
256
+ <main>{/* page content */}</main>
257
+ </>
258
+ );
259
+ }
260
+ ```
261
+
262
+ ### Astro
263
+
264
+ ```astro
265
+ ---
266
+ // src/pages/index.astro
267
+ import { NxisClient } from '@nxisai/nxis/ssr';
268
+
269
+ const nxis = new NxisClient({
270
+ clientId: import.meta.env.NXIS_CLIENT_ID,
271
+ clientSecret: import.meta.env.NXIS_CLIENT_SECRET,
272
+ });
273
+
274
+ const jsonLd = await nxis.getStructuredData({
275
+ uri: Astro.url.href,
276
+ siteId: import.meta.env.NXIS_SITE_ID,
277
+ });
278
+ ---
279
+
280
+ <html>
281
+ <head>
282
+ <script type="application/ld+json" set:html={JSON.stringify(jsonLd)} />
283
+ </head>
284
+ <body>
285
+ <!-- page content -->
286
+ </body>
287
+ </html>
288
+ ```
289
+
290
+ ### SvelteKit
291
+
292
+ ```typescript
293
+ // src/routes/+page.server.ts
294
+ import { NxisClient } from '@nxisai/nxis/ssr';
295
+ import { env } from '$env/static/private';
296
+ import type { PageServerLoad } from './$types';
297
+
298
+ const nxis = new NxisClient({
299
+ clientId: env.NXIS_CLIENT_ID,
300
+ clientSecret: env.NXIS_CLIENT_SECRET,
301
+ });
302
+
303
+ export const load: PageServerLoad = async ({ url }) => {
304
+ const jsonLd = await nxis.getStructuredData({
305
+ uri: url.href,
306
+ siteId: env.NXIS_SITE_ID,
307
+ });
308
+
309
+ return { jsonLd };
310
+ };
311
+ ```
312
+
313
+ ```html
314
+ <!-- src/routes/+page.svelte -->
315
+ <script lang="ts">
316
+ export let data;
317
+ </script>
318
+
319
+ <svelte:head>
320
+ {@html `<script type="application/ld+json">${JSON.stringify(data.jsonLd)}</script>`}
321
+ </svelte:head>
322
+
323
+ <main><!-- page content --></main>
324
+ ```
325
+
326
+ ### Express / Node.js
327
+
328
+ ```javascript
329
+ const express = require('express');
330
+ const { NxisClient } = require('@nxisai/nxis');
331
+
332
+ const nxis = new NxisClient({
333
+ clientId: process.env.NXIS_CLIENT_ID,
334
+ clientSecret: process.env.NXIS_CLIENT_SECRET,
335
+ });
336
+
337
+ const app = express();
338
+
339
+ app.get('*', async (req, res) => {
340
+ const jsonLd = await nxis.getStructuredData({
341
+ uri: `https://yoursite.com${req.originalUrl}`,
342
+ siteId: process.env.NXIS_SITE_ID,
343
+ });
344
+
345
+ res.send(`
346
+ <!DOCTYPE html>
347
+ <html>
348
+ <head>
349
+ <script type="application/ld+json">${JSON.stringify(jsonLd)}</script>
350
+ </head>
351
+ <body><!-- page content --></body>
352
+ </html>
353
+ `);
354
+ });
355
+
356
+ app.listen(3000);
357
+ ```
358
+
359
+ ---
360
+
361
+ ## Adding Nxis SSR with Claude Code
362
+
363
+ You can use [Claude Code](https://docs.anthropic.com/en/docs/claude-code) to automatically add Nxis SSR to an existing Next.js project. Paste the following prompt into Claude Code from your project's root directory:
364
+
365
+ ```
366
+ Install the @nxisai/nxis package and add server-side structured data injection to my
367
+ Next.js App Router project. Here's what I need:
368
+
369
+ 1. Install the @nxisai/nxis npm package
370
+ 2. Add NXIS_API_HOST, NXIS_CLIENT_ID, and NXIS_CLIENT_SECRET to my .env.local
371
+ 3. Create a shared NxisClient instance using `NxisClient` from `@nxisai/nxis/ssr`
372
+ initialized with the OAuth client credentials from environment variables
373
+ 4. Update my root layout (or individual pages) to:
374
+ - Import `headers` from `next/headers`
375
+ - Derive the page URI from the incoming request's `host` and
376
+ `x-forwarded-proto` headers
377
+ - Pass the `user-agent` header for bot detection
378
+ - Inject the returned JSON-LD as a <script type="application/ld+json"> tag
379
+
380
+ Here's the API reference:
381
+
382
+ import { NxisClient } from '@nxisai/nxis/ssr';
383
+
384
+ const nxis = new NxisClient({
385
+ clientId: process.env.NXIS_CLIENT_ID!,
386
+ clientSecret: process.env.NXIS_CLIENT_SECRET!,
387
+ });
388
+
389
+ const jsonLd: Record<string, unknown> = await nxis.getStructuredData({
390
+ uri: pageUri,
391
+ siteId: process.env.NXIS_SITE_ID!,
392
+ userAgent: headersList.get('user-agent') ?? undefined,
393
+ });
394
+
395
+ Tokens are managed automatically — no manual token handling needed.
396
+ Make sure JSON-LD is present in the initial HTML response so it's visible
397
+ to search engines, LLMs, and AI agents that don't render JavaScript.
398
+ ```
399
+
400
+ This will guide Claude Code to install the package, configure environment variables, and wire up SSR structured data injection across your pages.
401
+
package/bin/deploy.sh ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env bash
2
+ aws s3 cp build/nxis.js s3://nxis-ai-static/nxis.js