@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.
- package/.github/workflows/deploy.yml +110 -0
- package/README.md +401 -0
- package/bin/deploy.sh +2 -0
- package/build/api.d.ts +244 -0
- package/build/auth.d.ts +91 -0
- package/build/core.d.ts +56 -0
- package/build/index.cjs.js +423 -0
- package/build/index.d.ts +33 -0
- package/build/index.esm.js +417 -0
- package/build/nxis.js +1 -0
- package/build/server.d.ts +77 -0
- package/docs/ssr.md +606 -0
- package/nxisbucket.json +16 -0
- package/package.json +53 -0
- package/rollup.config.js +50 -0
- package/src/api.ts +281 -0
- package/src/auth.ts +171 -0
- package/src/client.ts +104 -0
- package/src/core.ts +124 -0
- package/src/index.ts +33 -0
- package/src/server.ts +106 -0
- package/tsconfig.json +66 -0
package/build/api.d.ts
ADDED
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A URL object representing an HTTP or HTTPS URI.
|
|
3
|
+
*
|
|
4
|
+
* @remarks
|
|
5
|
+
* Used as the canonical type for page URIs throughout the client-side request path.
|
|
6
|
+
*/
|
|
7
|
+
export type HttpUri = URL;
|
|
8
|
+
/**
|
|
9
|
+
* A wrapper around an optional string identifier.
|
|
10
|
+
*
|
|
11
|
+
* @remarks
|
|
12
|
+
* Used to represent entity IDs (organization, site, resource, etc.) that may
|
|
13
|
+
* or may not be present in a given context.
|
|
14
|
+
*/
|
|
15
|
+
export type Uid = {
|
|
16
|
+
/** The string identifier value, or `null` if not set. */
|
|
17
|
+
value: string | null;
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Makes a type `T` nullable — allowing `null` or `undefined` in addition to `T`.
|
|
21
|
+
*/
|
|
22
|
+
export type Nullable<T> = T | null | undefined;
|
|
23
|
+
/**
|
|
24
|
+
* Configuration injected by the Nxis CDN into the browser script.
|
|
25
|
+
*
|
|
26
|
+
* @remarks
|
|
27
|
+
* The CDN extracts these values from the JWT token's claims and writes them
|
|
28
|
+
* into `window.__NXIS_CONFIG__` before the client script executes.
|
|
29
|
+
*/
|
|
30
|
+
export type NxisConfig = {
|
|
31
|
+
/** The organization identifier. */
|
|
32
|
+
org_id: string;
|
|
33
|
+
/** The site identifier within the organization. */
|
|
34
|
+
site_id: string;
|
|
35
|
+
/** The subscription identifier used for quota and entitlement checks. */
|
|
36
|
+
sub_id: string;
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* Parameters for a client-side structured data request sent to the
|
|
40
|
+
* `/v1/nxis:inject` endpoint.
|
|
41
|
+
*/
|
|
42
|
+
export type StructuredDataRequest = {
|
|
43
|
+
/** The organization that owns the site. */
|
|
44
|
+
organization_id: Nullable<Uid>;
|
|
45
|
+
/** The site the page belongs to. */
|
|
46
|
+
site_id: Nullable<Uid>;
|
|
47
|
+
/** The full URI of the page being enhanced. */
|
|
48
|
+
uri: HttpUri;
|
|
49
|
+
/** The `document.referrer` value, if available. */
|
|
50
|
+
referrer?: string;
|
|
51
|
+
/** A client-generated session ID for request correlation. */
|
|
52
|
+
session?: string;
|
|
53
|
+
};
|
|
54
|
+
/**
|
|
55
|
+
* The response body returned by both the `/v1/nxis:inject` and `/v1/nxis:ssr`
|
|
56
|
+
* endpoints on success.
|
|
57
|
+
*
|
|
58
|
+
* @remarks
|
|
59
|
+
* The `data` field corresponds to a `google.protobuf.Struct` in the proto
|
|
60
|
+
* definition, which serializes as a flat JSON object over HTTP transcoding.
|
|
61
|
+
*/
|
|
62
|
+
export type StructuredDataResponse = {
|
|
63
|
+
/** A JSON-LD structured data object ready for injection into the page. */
|
|
64
|
+
data: Record<string, unknown>;
|
|
65
|
+
};
|
|
66
|
+
/**
|
|
67
|
+
* A non-fatal warning indicating no structured data was found for a page.
|
|
68
|
+
*
|
|
69
|
+
* @remarks
|
|
70
|
+
* Thrown when the proxy returns a 200 response with an empty `data` object.
|
|
71
|
+
* Callers can catch this specifically to distinguish "no data" from actual errors.
|
|
72
|
+
*/
|
|
73
|
+
export declare class NxisWarning extends Error {
|
|
74
|
+
constructor(msg: string);
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Configuration for initializing a {@link NxisClient} instance.
|
|
78
|
+
*
|
|
79
|
+
* @remarks
|
|
80
|
+
* Used to create a client that automatically manages OAuth tokens and
|
|
81
|
+
* fetches structured data from the Nxis AI Proxy.
|
|
82
|
+
*
|
|
83
|
+
* @example
|
|
84
|
+
* ```typescript
|
|
85
|
+
* const nxis = new NxisClient({
|
|
86
|
+
* clientId: process.env.NXIS_CLIENT_ID!,
|
|
87
|
+
* clientSecret: process.env.NXIS_CLIENT_SECRET!,
|
|
88
|
+
* });
|
|
89
|
+
* ```
|
|
90
|
+
*/
|
|
91
|
+
export type NxisClientConfig = {
|
|
92
|
+
/** OAuth client ID (format: `nxis_cid_[a-zA-Z0-9]{16}`). */
|
|
93
|
+
clientId: string;
|
|
94
|
+
/** OAuth client secret (format: `nxis_sec_[a-zA-Z0-9]{32}`). */
|
|
95
|
+
clientSecret: string;
|
|
96
|
+
/**
|
|
97
|
+
* Override for the OAuth token endpoint URL.
|
|
98
|
+
*
|
|
99
|
+
* @defaultValue Falls back to `NXIS_TOKEN_URL` env var, then `"https://authorization.nxis.ai/v1/oauth/token"`.
|
|
100
|
+
*/
|
|
101
|
+
tokenUrl?: string;
|
|
102
|
+
/**
|
|
103
|
+
* OAuth scope to request.
|
|
104
|
+
*
|
|
105
|
+
* @defaultValue `"jsonld:read"`
|
|
106
|
+
*/
|
|
107
|
+
scope?: string;
|
|
108
|
+
/**
|
|
109
|
+
* Override for the Nxis API host URL.
|
|
110
|
+
*
|
|
111
|
+
* @defaultValue Falls back to the `NXIS_API_HOST` environment variable.
|
|
112
|
+
*/
|
|
113
|
+
apiHost?: string;
|
|
114
|
+
};
|
|
115
|
+
/**
|
|
116
|
+
* Request parameters for fetching structured data for a specific page.
|
|
117
|
+
*
|
|
118
|
+
* @remarks
|
|
119
|
+
* Passed to {@link NxisClient.getStructuredData}. Contains only
|
|
120
|
+
* request-specific parameters — credentials and host config are
|
|
121
|
+
* set once at client initialization.
|
|
122
|
+
*
|
|
123
|
+
* @example
|
|
124
|
+
* ```typescript
|
|
125
|
+
* const jsonLd = await nxis.getStructuredData({
|
|
126
|
+
* uri: 'https://example.com/page',
|
|
127
|
+
* userAgent: req.headers['user-agent'],
|
|
128
|
+
* });
|
|
129
|
+
* ```
|
|
130
|
+
*/
|
|
131
|
+
export type NxisSSRRequest = {
|
|
132
|
+
/** The full URI of the page being rendered (e.g. `"https://example.com/about"`). */
|
|
133
|
+
uri: string;
|
|
134
|
+
/** The site identifier to scope the request to a specific site. */
|
|
135
|
+
siteId: string;
|
|
136
|
+
/**
|
|
137
|
+
* Optional User-Agent string forwarded to the proxy for bot detection.
|
|
138
|
+
*
|
|
139
|
+
* @remarks
|
|
140
|
+
* When provided, the proxy can distinguish search-engine crawlers and LLM
|
|
141
|
+
* agents from regular visitors and adjust response behavior accordingly.
|
|
142
|
+
*/
|
|
143
|
+
userAgent?: string;
|
|
144
|
+
};
|
|
145
|
+
/**
|
|
146
|
+
* gRPC-compatible error codes used by the Nxis AI Proxy.
|
|
147
|
+
*
|
|
148
|
+
* @remarks
|
|
149
|
+
* These codes map directly to gRPC status codes and are included in
|
|
150
|
+
* structured error responses from the proxy. Use {@link errorCodeToHttp}
|
|
151
|
+
* to convert to the corresponding HTTP status code.
|
|
152
|
+
*/
|
|
153
|
+
export declare enum ErrorCode {
|
|
154
|
+
/** The request completed successfully. */
|
|
155
|
+
OK = 0,
|
|
156
|
+
/** The request contained an invalid argument (e.g. malformed URI). */
|
|
157
|
+
INVALID_ARGUMENT = 3,
|
|
158
|
+
/** The requested resource was not found. */
|
|
159
|
+
NOT_FOUND = 5,
|
|
160
|
+
/** The caller does not have permission to access the requested resource. */
|
|
161
|
+
PERMISSION_DENIED = 7,
|
|
162
|
+
/** The caller has exceeded their rate limit or quota. */
|
|
163
|
+
RESOURCE_EXHAUSTED = 8,
|
|
164
|
+
/** An internal server error occurred. */
|
|
165
|
+
INTERNAL = 13,
|
|
166
|
+
/** The request lacks valid authentication credentials. */
|
|
167
|
+
UNAUTHENTICATED = 16
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Maps each {@link ErrorCode} to its conventional HTTP status code.
|
|
171
|
+
*
|
|
172
|
+
* @example
|
|
173
|
+
* ```typescript
|
|
174
|
+
* const httpStatus = errorCodeToHttp[ErrorCode.NOT_FOUND]; // 404
|
|
175
|
+
* ```
|
|
176
|
+
*/
|
|
177
|
+
export declare const errorCodeToHttp: Record<ErrorCode, number>;
|
|
178
|
+
/**
|
|
179
|
+
* The structured JSON body returned by the proxy on error responses.
|
|
180
|
+
*/
|
|
181
|
+
export interface NxisErrorResponse {
|
|
182
|
+
/** The gRPC-style error code. */
|
|
183
|
+
code: ErrorCode;
|
|
184
|
+
/** A human-readable error message. */
|
|
185
|
+
message: string;
|
|
186
|
+
/** Optional array of protobuf `Any`-style detail messages. */
|
|
187
|
+
details?: Array<{
|
|
188
|
+
"@type": string;
|
|
189
|
+
value: string;
|
|
190
|
+
}>;
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* An error thrown when the Nxis AI Proxy returns a non-200 response.
|
|
194
|
+
*
|
|
195
|
+
* @remarks
|
|
196
|
+
* `ProxyError` carries both the gRPC {@link ErrorCode} and the HTTP status
|
|
197
|
+
* code so callers can decide how to surface or retry the failure.
|
|
198
|
+
*
|
|
199
|
+
* @example
|
|
200
|
+
* ```typescript
|
|
201
|
+
* try {
|
|
202
|
+
* const data = await getStructuredData({ token, uri });
|
|
203
|
+
* } catch (err) {
|
|
204
|
+
* if (err instanceof ProxyError && err.isRetryable) {
|
|
205
|
+
* // back off and retry
|
|
206
|
+
* }
|
|
207
|
+
* }
|
|
208
|
+
* ```
|
|
209
|
+
*/
|
|
210
|
+
export declare class ProxyError extends Error {
|
|
211
|
+
readonly code: ErrorCode;
|
|
212
|
+
readonly httpStatus: number;
|
|
213
|
+
/**
|
|
214
|
+
* @param code - The gRPC-style {@link ErrorCode}.
|
|
215
|
+
* @param httpStatus - The HTTP status code from the proxy response.
|
|
216
|
+
* @param message - A human-readable description of the error.
|
|
217
|
+
*/
|
|
218
|
+
constructor(code: ErrorCode, httpStatus: number, message: string);
|
|
219
|
+
/**
|
|
220
|
+
* Whether this error represents a transient failure that may succeed on retry.
|
|
221
|
+
*
|
|
222
|
+
* @remarks
|
|
223
|
+
* Returns `true` for {@link ErrorCode.RESOURCE_EXHAUSTED} (rate limiting)
|
|
224
|
+
* and {@link ErrorCode.INTERNAL} (server errors).
|
|
225
|
+
*/
|
|
226
|
+
get isRetryable(): boolean;
|
|
227
|
+
/**
|
|
228
|
+
* Whether this error indicates an authentication or authorization failure.
|
|
229
|
+
*
|
|
230
|
+
* @remarks
|
|
231
|
+
* Returns `true` for {@link ErrorCode.UNAUTHENTICATED} (missing/invalid token)
|
|
232
|
+
* and {@link ErrorCode.PERMISSION_DENIED} (valid token, insufficient access).
|
|
233
|
+
*/
|
|
234
|
+
get isAuthError(): boolean;
|
|
235
|
+
/**
|
|
236
|
+
* Creates a `ProxyError` from an HTTP status code and a parsed
|
|
237
|
+
* {@link NxisErrorResponse} body.
|
|
238
|
+
*
|
|
239
|
+
* @param status - The HTTP status code of the response.
|
|
240
|
+
* @param body - The parsed error response body from the proxy.
|
|
241
|
+
* @returns A new `ProxyError` instance.
|
|
242
|
+
*/
|
|
243
|
+
static fromResponse(status: number, body: NxisErrorResponse): ProxyError;
|
|
244
|
+
}
|
package/build/auth.d.ts
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration for the OAuth client credentials flow.
|
|
3
|
+
*
|
|
4
|
+
* @internal
|
|
5
|
+
*/
|
|
6
|
+
export interface OAuthConfig {
|
|
7
|
+
/** OAuth client ID (format: `nxis_cid_[a-zA-Z0-9]{16}`). */
|
|
8
|
+
clientId: string;
|
|
9
|
+
/** OAuth client secret (format: `nxis_sec_[a-zA-Z0-9]{32}`). */
|
|
10
|
+
clientSecret: string;
|
|
11
|
+
/**
|
|
12
|
+
* The OAuth token endpoint URL.
|
|
13
|
+
*
|
|
14
|
+
* @defaultValue Falls back to `NXIS_TOKEN_URL` env var, then `"https://authorization.nxis.ai/v1/oauth/token"`.
|
|
15
|
+
*/
|
|
16
|
+
tokenUrl?: string;
|
|
17
|
+
/**
|
|
18
|
+
* OAuth scope to request.
|
|
19
|
+
*
|
|
20
|
+
* @defaultValue `"jsonld:read"`
|
|
21
|
+
*/
|
|
22
|
+
scope?: string;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Response from the OAuth token endpoint (`POST /v1/oauth/token`).
|
|
26
|
+
*
|
|
27
|
+
* @remarks
|
|
28
|
+
* Matches the `IssueTokenResponse` message in the OAuth service proto.
|
|
29
|
+
*/
|
|
30
|
+
export interface IssueTokenResponse {
|
|
31
|
+
/** The issued access token. */
|
|
32
|
+
access_token: string;
|
|
33
|
+
/** Token type — always `"Bearer"`. */
|
|
34
|
+
token_type: string;
|
|
35
|
+
/** Seconds until the token expires. */
|
|
36
|
+
expires_in: number;
|
|
37
|
+
/** The granted scope. */
|
|
38
|
+
scope: string;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Manages OAuth 2.0 access tokens using the client credentials grant.
|
|
42
|
+
*
|
|
43
|
+
* @remarks
|
|
44
|
+
* Tokens are cached in memory and automatically refreshed before expiration.
|
|
45
|
+
* Concurrent calls during a refresh all await the same in-flight request,
|
|
46
|
+
* preventing redundant token fetches.
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* ```typescript
|
|
50
|
+
* const manager = new OAuthTokenManager({
|
|
51
|
+
* clientId: process.env.NXIS_CLIENT_ID!,
|
|
52
|
+
* clientSecret: process.env.NXIS_CLIENT_SECRET!,
|
|
53
|
+
* });
|
|
54
|
+
*
|
|
55
|
+
* const token = await manager.getAccessToken();
|
|
56
|
+
* // Use token in Authorization: Bearer <token> header
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
59
|
+
export declare class OAuthTokenManager {
|
|
60
|
+
private readonly clientId;
|
|
61
|
+
private readonly clientSecret;
|
|
62
|
+
private readonly tokenUrl;
|
|
63
|
+
private readonly scope;
|
|
64
|
+
/** The currently cached access token, or `null` if none. */
|
|
65
|
+
private cachedToken;
|
|
66
|
+
/** Unix timestamp (ms) at which the cached token expires. */
|
|
67
|
+
private expiresAt;
|
|
68
|
+
/** In-flight token request for concurrency deduplication. */
|
|
69
|
+
private pendingRequest;
|
|
70
|
+
constructor(config: OAuthConfig);
|
|
71
|
+
/**
|
|
72
|
+
* Returns a valid access token, fetching or refreshing as needed.
|
|
73
|
+
*
|
|
74
|
+
* @remarks
|
|
75
|
+
* If the cached token has more than {@link REFRESH_BUFFER_SECONDS} seconds
|
|
76
|
+
* remaining, it is returned immediately. Otherwise a new token is requested
|
|
77
|
+
* from the OAuth endpoint.
|
|
78
|
+
*
|
|
79
|
+
* @returns A valid OAuth Bearer access token.
|
|
80
|
+
*
|
|
81
|
+
* @throws {@link ProxyError}
|
|
82
|
+
* Thrown if the token endpoint returns an error response.
|
|
83
|
+
*/
|
|
84
|
+
getAccessToken(): Promise<string>;
|
|
85
|
+
/**
|
|
86
|
+
* Fetches a new access token from the OAuth endpoint.
|
|
87
|
+
*
|
|
88
|
+
* @internal
|
|
89
|
+
*/
|
|
90
|
+
private fetchToken;
|
|
91
|
+
}
|
package/build/core.d.ts
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { StructuredDataRequest, StructuredDataResponse } from './api';
|
|
2
|
+
/**
|
|
3
|
+
* Serializes a {@link StructuredDataRequest} into URL query parameters for
|
|
4
|
+
* the client-side `/v1/nxis:inject` endpoint.
|
|
5
|
+
*
|
|
6
|
+
* @param request - The structured data request containing org, site, URI,
|
|
7
|
+
* referrer, and session info.
|
|
8
|
+
* @returns A `URLSearchParams` instance ready to be appended to the request URL.
|
|
9
|
+
*
|
|
10
|
+
* @internal
|
|
11
|
+
*/
|
|
12
|
+
export declare function buildParams(request: StructuredDataRequest): URLSearchParams;
|
|
13
|
+
/**
|
|
14
|
+
* Processes an HTTP response from the Nxis API and returns the structured
|
|
15
|
+
* data payload, or throws an appropriate error.
|
|
16
|
+
*
|
|
17
|
+
* @remarks
|
|
18
|
+
* - On a `200` response with data, returns the {@link StructuredDataResponse}.
|
|
19
|
+
* - On a `200` response with an empty `data` object, throws {@link NxisWarning}.
|
|
20
|
+
* - On error responses, attempts to parse a structured {@link NxisErrorResponse}
|
|
21
|
+
* and throws a {@link ProxyError}. Falls back to generic status-based errors
|
|
22
|
+
* if the body cannot be parsed.
|
|
23
|
+
*
|
|
24
|
+
* @param response - The raw `fetch` Response from the proxy.
|
|
25
|
+
* @param pageUrl - The page URL for use in error messages. Defaults to `"unknown"`.
|
|
26
|
+
* @returns The parsed structured data response.
|
|
27
|
+
*
|
|
28
|
+
* @throws {@link NxisWarning}
|
|
29
|
+
* Thrown when the proxy returns 200 but the data object is empty.
|
|
30
|
+
*
|
|
31
|
+
* @throws {@link ProxyError}
|
|
32
|
+
* Thrown when the proxy returns a non-200 status code.
|
|
33
|
+
*/
|
|
34
|
+
export declare function responseHandler(response: Response, pageUrl?: string): Promise<StructuredDataResponse>;
|
|
35
|
+
/**
|
|
36
|
+
* Fetches structured data from the Nxis AI Proxy's SSR endpoint (`/v1/nxis:ssr`).
|
|
37
|
+
*
|
|
38
|
+
* @remarks
|
|
39
|
+
* This is the low-level fetch function used by {@link NxisClient}. It sends
|
|
40
|
+
* the request with a `Bearer` access token obtained from the OAuth token manager.
|
|
41
|
+
*
|
|
42
|
+
* @param uri - The full URI of the page being rendered.
|
|
43
|
+
* @param accessToken - A valid OAuth Bearer access token.
|
|
44
|
+
* @param apiHost - The Nxis API host URL.
|
|
45
|
+
* @param userAgent - Optional User-Agent string for bot detection.
|
|
46
|
+
* @returns The full {@link StructuredDataResponse} from the proxy.
|
|
47
|
+
*
|
|
48
|
+
* @throws {@link ProxyError}
|
|
49
|
+
* Thrown if the proxy returns a non-200 response.
|
|
50
|
+
*
|
|
51
|
+
* @throws {@link NxisWarning}
|
|
52
|
+
* Thrown if the proxy returns 200 but no data is available for the page.
|
|
53
|
+
*
|
|
54
|
+
* @internal
|
|
55
|
+
*/
|
|
56
|
+
export declare function fetchStructuredData(uri: string, accessToken: string, apiHost: string, userAgent?: string, siteId?: string): Promise<StructuredDataResponse>;
|