@foldset/nextjs 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/dist/adapter.d.ts +18 -0
- package/dist/adapter.d.ts.map +1 -0
- package/dist/adapter.js +49 -0
- package/dist/core.d.ts +3 -0
- package/dist/core.d.ts.map +1 -0
- package/dist/core.js +17 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1 -0
- package/dist/proxy.d.ts +4 -0
- package/dist/proxy.d.ts.map +1 -0
- package/dist/proxy.js +60 -0
- package/dist/store.d.ts +9 -0
- package/dist/store.d.ts.map +1 -0
- package/dist/store.js +31 -0
- package/dist/types.d.ts +4 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +1 -0
- package/package.json +50 -0
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { RequestAdapter } from "@foldset/core";
|
|
2
|
+
import type { NextRequest } from "next/server";
|
|
3
|
+
export declare class NextjsAdapter implements RequestAdapter {
|
|
4
|
+
private readonly request;
|
|
5
|
+
constructor(request: NextRequest);
|
|
6
|
+
getIpAddress(): string | null;
|
|
7
|
+
getHeader(name: string): string | undefined;
|
|
8
|
+
getMethod(): string;
|
|
9
|
+
getPath(): string;
|
|
10
|
+
getUrl(): string;
|
|
11
|
+
getHost(): string;
|
|
12
|
+
getAcceptHeader(): string;
|
|
13
|
+
getUserAgent(): string;
|
|
14
|
+
getQueryParams(): Record<string, string | string[]>;
|
|
15
|
+
getQueryParam(name: string): string | string[] | undefined;
|
|
16
|
+
getBody(): Promise<unknown>;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C,qBAAa,aAAc,YAAW,cAAc;IACtC,OAAO,CAAC,QAAQ,CAAC,OAAO;gBAAP,OAAO,EAAE,WAAW;IAEjD,YAAY,IAAI,MAAM,GAAG,IAAI;IAI7B,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAI3C,SAAS,IAAI,MAAM;IAInB,OAAO,IAAI,MAAM;IAIjB,MAAM,IAAI,MAAM;IAIhB,OAAO,IAAI,MAAM;IAIjB,eAAe,IAAI,MAAM;IAIzB,YAAY,IAAI,MAAM;IAItB,cAAc,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAYnD,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS;IAQ1D,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC;CAG5B"}
|
package/dist/adapter.js
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
export class NextjsAdapter {
|
|
2
|
+
request;
|
|
3
|
+
constructor(request) {
|
|
4
|
+
this.request = request;
|
|
5
|
+
}
|
|
6
|
+
getIpAddress() {
|
|
7
|
+
return this.request.headers.get("x-forwarded-for")?.split(",")[0]?.trim() ?? null;
|
|
8
|
+
}
|
|
9
|
+
getHeader(name) {
|
|
10
|
+
return this.request.headers.get(name) ?? undefined;
|
|
11
|
+
}
|
|
12
|
+
getMethod() {
|
|
13
|
+
return this.request.method;
|
|
14
|
+
}
|
|
15
|
+
getPath() {
|
|
16
|
+
return this.request.nextUrl.pathname;
|
|
17
|
+
}
|
|
18
|
+
getUrl() {
|
|
19
|
+
return this.request.url;
|
|
20
|
+
}
|
|
21
|
+
getHost() {
|
|
22
|
+
return this.request.nextUrl.hostname;
|
|
23
|
+
}
|
|
24
|
+
getAcceptHeader() {
|
|
25
|
+
return this.request.headers.get("Accept") ?? "";
|
|
26
|
+
}
|
|
27
|
+
getUserAgent() {
|
|
28
|
+
return this.request.headers.get("User-Agent") ?? "";
|
|
29
|
+
}
|
|
30
|
+
getQueryParams() {
|
|
31
|
+
const params = this.request.nextUrl.searchParams;
|
|
32
|
+
const result = {};
|
|
33
|
+
for (const key of new Set(params.keys())) {
|
|
34
|
+
const values = params.getAll(key);
|
|
35
|
+
result[key] = values.length === 1 ? values[0] : values;
|
|
36
|
+
}
|
|
37
|
+
return result;
|
|
38
|
+
}
|
|
39
|
+
getQueryParam(name) {
|
|
40
|
+
const params = this.request.nextUrl.searchParams;
|
|
41
|
+
if (!params.has(name))
|
|
42
|
+
return undefined;
|
|
43
|
+
const values = params.getAll(name);
|
|
44
|
+
return values.length === 1 ? values[0] : values;
|
|
45
|
+
}
|
|
46
|
+
getBody() {
|
|
47
|
+
return this.request.json().catch(() => undefined);
|
|
48
|
+
}
|
|
49
|
+
}
|
package/dist/core.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../src/core.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAM3C,wBAAsB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAevE"}
|
package/dist/core.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { WorkerCore } from "@foldset/core";
|
|
2
|
+
import { fetchRedisCredentials, createRedisStore } from "./store";
|
|
3
|
+
let cachedCore = null;
|
|
4
|
+
export async function getWorkerCore(apiKey) {
|
|
5
|
+
if (cachedCore) {
|
|
6
|
+
console.log("[foldset] Using cached WorkerCore");
|
|
7
|
+
return cachedCore;
|
|
8
|
+
}
|
|
9
|
+
console.log("[foldset] Initializing WorkerCore, apiKey:", apiKey.slice(0, 12) + "...");
|
|
10
|
+
const credentials = await fetchRedisCredentials(apiKey);
|
|
11
|
+
const store = createRedisStore(credentials);
|
|
12
|
+
cachedCore = new WorkerCore(store, {
|
|
13
|
+
apiKey,
|
|
14
|
+
});
|
|
15
|
+
console.log("[foldset] WorkerCore initialized");
|
|
16
|
+
return cachedCore;
|
|
17
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { createFoldsetProxy } from "./proxy";
|
package/dist/proxy.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { FoldsetOptions } from "@foldset/core";
|
|
2
|
+
import { NextResponse, type NextRequest } from "next/server";
|
|
3
|
+
export declare function createFoldsetProxy(options: FoldsetOptions): (request: NextRequest) => Promise<NextResponse>;
|
|
4
|
+
//# sourceMappingURL=proxy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proxy.d.ts","sourceRoot":"","sources":["../src/proxy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAEpD,OAAO,EAAE,YAAY,EAAE,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AAW7D,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,cAAc,GAAG,CAAC,OAAO,EAAE,WAAW,KAAK,OAAO,CAAC,YAAY,CAAC,CAkE3G"}
|
package/dist/proxy.js
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { WorkerCore, reportError } from "@foldset/core";
|
|
2
|
+
import { NextResponse } from "next/server";
|
|
3
|
+
import packageJson from "../package.json" with { type: "json" };
|
|
4
|
+
import { NextjsAdapter } from "./adapter";
|
|
5
|
+
function setHeaders(response, headers) {
|
|
6
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
7
|
+
response.headers.set(key, value);
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
export function createFoldsetProxy(options) {
|
|
11
|
+
if (!options.apiKey) {
|
|
12
|
+
console.warn("[foldset] No API key provided, proxy disabled");
|
|
13
|
+
return async function proxy(_request) {
|
|
14
|
+
return NextResponse.next();
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
const opts = { ...options, platform: "nextjs", sdkVersion: packageJson.version };
|
|
18
|
+
return async function proxy(request) {
|
|
19
|
+
try {
|
|
20
|
+
const core = await WorkerCore.fromOptions(opts);
|
|
21
|
+
const adapter = new NextjsAdapter(request);
|
|
22
|
+
const result = await core.processRequest(adapter);
|
|
23
|
+
switch (result.type) {
|
|
24
|
+
case "health-check":
|
|
25
|
+
return new NextResponse(result.response.body, {
|
|
26
|
+
status: result.response.status,
|
|
27
|
+
headers: result.response.headers,
|
|
28
|
+
});
|
|
29
|
+
case "no-payment-required": {
|
|
30
|
+
const response = NextResponse.next();
|
|
31
|
+
if (result.headers) {
|
|
32
|
+
setHeaders(response, result.headers);
|
|
33
|
+
}
|
|
34
|
+
return response;
|
|
35
|
+
}
|
|
36
|
+
case "payment-error":
|
|
37
|
+
return new NextResponse(result.response.body, {
|
|
38
|
+
status: result.response.status,
|
|
39
|
+
headers: result.response.headers,
|
|
40
|
+
});
|
|
41
|
+
case "payment-verified": {
|
|
42
|
+
// TODO rfradkin: Optimistically assumes 200, Next.js middleware
|
|
43
|
+
// can't see the downstream response status code.
|
|
44
|
+
const settlement = await core.processSettlement(adapter, result.paymentPayload, result.paymentRequirements, 200, result.metadata.request_id);
|
|
45
|
+
if (!settlement.success) {
|
|
46
|
+
return new NextResponse(JSON.stringify({ error: "Settlement failed", details: settlement.errorReason }), { status: 402, headers: { "Content-Type": "application/json" } });
|
|
47
|
+
}
|
|
48
|
+
const response = NextResponse.next();
|
|
49
|
+
setHeaders(response, settlement.headers);
|
|
50
|
+
return response;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
catch (error) {
|
|
55
|
+
// On any error, allow the request through rather than blocking the user.
|
|
56
|
+
reportError(opts.apiKey, error, new NextjsAdapter(request));
|
|
57
|
+
return NextResponse.next();
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
}
|
package/dist/store.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ConfigStore } from "@foldset/core";
|
|
2
|
+
export interface RedisCredentials {
|
|
3
|
+
url: string;
|
|
4
|
+
token: string;
|
|
5
|
+
tenantId: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function fetchRedisCredentials(apiKey: string): Promise<RedisCredentials>;
|
|
8
|
+
export declare function createRedisStore(credentials: RedisCredentials): ConfigStore;
|
|
9
|
+
//# sourceMappingURL=store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAIjD,MAAM,WAAW,gBAAgB;IAC/B,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,wBAAsB,qBAAqB,CACzC,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,gBAAgB,CAAC,CAgB3B;AAED,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,gBAAgB,GAAG,WAAW,CAgB3E"}
|
package/dist/store.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { Redis } from "@upstash/redis";
|
|
2
|
+
const API_BASE_URL = "https://api.foldset.com";
|
|
3
|
+
export async function fetchRedisCredentials(apiKey) {
|
|
4
|
+
console.log("[foldset] Fetching Redis credentials from", API_BASE_URL);
|
|
5
|
+
const response = await fetch(`${API_BASE_URL}/v1/config/redis`, {
|
|
6
|
+
headers: { Authorization: `Bearer ${apiKey}` },
|
|
7
|
+
});
|
|
8
|
+
if (!response.ok) {
|
|
9
|
+
console.error("[foldset] Failed to fetch Redis credentials:", response.status, response.statusText);
|
|
10
|
+
throw new Error(`Failed to fetch Redis credentials: ${response.status} ${response.statusText}`);
|
|
11
|
+
}
|
|
12
|
+
const { data } = (await response.json());
|
|
13
|
+
console.log("[foldset] Redis credentials fetched, tenantId:", data.tenantId);
|
|
14
|
+
return data;
|
|
15
|
+
}
|
|
16
|
+
export function createRedisStore(credentials) {
|
|
17
|
+
const redis = new Redis({
|
|
18
|
+
url: credentials.url,
|
|
19
|
+
token: credentials.token,
|
|
20
|
+
automaticDeserialization: false,
|
|
21
|
+
});
|
|
22
|
+
const prefix = credentials.tenantId;
|
|
23
|
+
return {
|
|
24
|
+
async get(key) {
|
|
25
|
+
const fullKey = `${prefix}:${key}`;
|
|
26
|
+
const value = await redis.get(fullKey);
|
|
27
|
+
console.log("[foldset] Redis GET", fullKey, value ? `(${typeof value === "string" ? value.length : 0} chars)` : "(null)");
|
|
28
|
+
return value;
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAC;CAChB"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@foldset/nextjs",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Next.js middleware for Foldset payment protection",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"default": "./dist/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist"
|
|
17
|
+
],
|
|
18
|
+
"publishConfig": {
|
|
19
|
+
"access": "public"
|
|
20
|
+
},
|
|
21
|
+
"repository": {
|
|
22
|
+
"type": "git",
|
|
23
|
+
"url": "https://github.com/foldset/sdks.git",
|
|
24
|
+
"directory": "typescript/nextjs"
|
|
25
|
+
},
|
|
26
|
+
"homepage": "https://docs.foldset.com",
|
|
27
|
+
"keywords": [
|
|
28
|
+
"foldset",
|
|
29
|
+
"nextjs",
|
|
30
|
+
"middleware",
|
|
31
|
+
"micropayments",
|
|
32
|
+
"ai",
|
|
33
|
+
"agents"
|
|
34
|
+
],
|
|
35
|
+
"dependencies": {
|
|
36
|
+
"@foldset/core": "0.1.0"
|
|
37
|
+
},
|
|
38
|
+
"peerDependencies": {
|
|
39
|
+
"next": ">=14"
|
|
40
|
+
},
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"next": "^15.3.3",
|
|
43
|
+
"typescript": "^5.9.3",
|
|
44
|
+
"typescript-eslint": "^8.25.0"
|
|
45
|
+
},
|
|
46
|
+
"scripts": {
|
|
47
|
+
"build": "tsc",
|
|
48
|
+
"typecheck": "tsc --noEmit"
|
|
49
|
+
}
|
|
50
|
+
}
|