@nibgate/sdk 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/README.md +605 -0
- package/package.json +58 -0
- package/src/browser/env.js +3 -0
- package/src/browser/events.js +57 -0
- package/src/browser/gateway.js +89 -0
- package/src/browser/index.js +710 -0
- package/src/browser/json.js +8 -0
- package/src/browser/reputation.js +161 -0
- package/src/browser/storage.js +68 -0
- package/src/browser/tracking.js +42 -0
- package/src/browser/transfer.js +53 -0
- package/src/core/payment.js +8 -0
- package/src/core/rating.js +28 -0
- package/src/core/resource.js +143 -0
- package/src/core/settings.js +47 -0
- package/src/index.d.ts +423 -0
- package/src/index.js +1 -0
- package/src/server/access.js +217 -0
- package/src/server/actor.js +23 -0
- package/src/server/challenge.js +51 -0
- package/src/server/env.js +3 -0
- package/src/server/gateway.js +186 -0
- package/src/server/hub.js +36 -0
- package/src/server/index.js +15 -0
- package/src/server/manifest.js +19 -0
- package/src/server/presets.js +14 -0
- package/src/server/proof.js +73 -0
- package/src/server/response.js +9 -0
- package/src/server/runtime.js +39 -0
- package/src/server.d.ts +212 -0
- package/src/server.js +1 -0
- package/src/testing.d.ts +23 -0
- package/src/testing.js +56 -0
- package/src/tracking.d.ts +18 -0
- package/src/tracking.js +1 -0
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { normalizePaymentRail } from '../core/payment.js';
|
|
2
|
+
import { normalizeServerResource as normalizeResource } from '../core/resource.js';
|
|
3
|
+
import { serverEnv } from './env.js';
|
|
4
|
+
|
|
5
|
+
export function createPaymentChallenge(resourceInput, options = {}) {
|
|
6
|
+
const resource = normalizeResource(resourceInput);
|
|
7
|
+
const origin = options.origin || serverEnv('NIBGATE_SITE_ORIGIN') || '';
|
|
8
|
+
const actor = options.actor || 'human';
|
|
9
|
+
const recipient = resource.recipient || resource.payTo || options.recipient || serverEnv('NIBGATE_SELLER_ADDRESS') || '';
|
|
10
|
+
const paymentRail = normalizePaymentRail(resource.paymentRail || options.paymentRail || options.paymentMode);
|
|
11
|
+
return {
|
|
12
|
+
x402Version: options.x402Version || 2,
|
|
13
|
+
status: 402,
|
|
14
|
+
scheme: 'exact',
|
|
15
|
+
paymentMode: paymentRail === 'gateway' ? (options.paymentMode || serverEnv('NIBGATE_PAYMENT_MODE') || 'unconfigured') : 'transfer',
|
|
16
|
+
paymentRail,
|
|
17
|
+
accepts: [
|
|
18
|
+
{
|
|
19
|
+
asset: resource.currency,
|
|
20
|
+
network: options.network || serverEnv('NIBGATE_PAYMENT_NETWORK') || 'eip155:5042002',
|
|
21
|
+
amount: String(resource.price),
|
|
22
|
+
recipient,
|
|
23
|
+
description: `Unlock ${resource.title}`,
|
|
24
|
+
resource: resource.url || `${origin}${resource.path}`,
|
|
25
|
+
mimeType: resource.type === 'article' ? 'text/html' : 'application/octet-stream',
|
|
26
|
+
payTo: recipient,
|
|
27
|
+
maxTimeoutSeconds: options.maxTimeoutSeconds || 120,
|
|
28
|
+
rail: paymentRail,
|
|
29
|
+
transfer: paymentRail === 'transfer' ? {
|
|
30
|
+
token: resource.currency || 'USDC',
|
|
31
|
+
chainId: options.chainId || options.network || serverEnv('NIBGATE_PAYMENT_NETWORK') || 'eip155:5042002',
|
|
32
|
+
recipient,
|
|
33
|
+
amount: String(resource.price),
|
|
34
|
+
verifier: 'creator-server'
|
|
35
|
+
} : undefined
|
|
36
|
+
}
|
|
37
|
+
],
|
|
38
|
+
nibgate: {
|
|
39
|
+
contentId: resource.id,
|
|
40
|
+
title: resource.title,
|
|
41
|
+
contentType: resource.type,
|
|
42
|
+
price: String(resource.price),
|
|
43
|
+
currency: resource.currency,
|
|
44
|
+
path: resource.path,
|
|
45
|
+
actor,
|
|
46
|
+
access: resource.access,
|
|
47
|
+
unlock: resource.unlock,
|
|
48
|
+
paymentRail
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
}
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import { normalizeServerResource as normalizeResource } from '../core/resource.js';
|
|
2
|
+
import { serverEnv } from './env.js';
|
|
3
|
+
import { jsonResponse } from './response.js';
|
|
4
|
+
|
|
5
|
+
async function importGatewayPackage(specifier) {
|
|
6
|
+
return import(specifier);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export async function payWithGateway(resourceInput, options = {}) {
|
|
10
|
+
const resource = normalizeResource(resourceInput);
|
|
11
|
+
const gatewayBuyerResult = await createGatewayBuyer(options);
|
|
12
|
+
if (!gatewayBuyerResult.ok) return gatewayBuyerResult;
|
|
13
|
+
const gatewayBuyer = gatewayBuyerResult.client;
|
|
14
|
+
|
|
15
|
+
const origin = options.origin || serverEnv('NIBGATE_SITE_ORIGIN') || '';
|
|
16
|
+
const accessUrl = options.accessUrl || `${origin.replace(/\/$/, '')}${resource.path || '/'}`;
|
|
17
|
+
const paymentResult = await gatewayBuyer.pay(accessUrl);
|
|
18
|
+
const data = paymentResult?.data || {};
|
|
19
|
+
const returnedPayment = data.payment || {};
|
|
20
|
+
return {
|
|
21
|
+
ok: true,
|
|
22
|
+
payment: {
|
|
23
|
+
paymentId: returnedPayment.paymentId || data.paymentId || data.id || paymentResult?.id || '',
|
|
24
|
+
paymentProvider: 'circle-gateway',
|
|
25
|
+
memo: returnedPayment.memo || data.memo || paymentResult?.memo || '',
|
|
26
|
+
txHash: returnedPayment.txHash || data.txHash || data.transaction || paymentResult?.transaction || '',
|
|
27
|
+
receiptUrl: returnedPayment.receiptUrl || data.receiptUrl || '',
|
|
28
|
+
chainExplorerUrl: returnedPayment.chainExplorerUrl || ((returnedPayment.txHash || data.txHash || data.transaction || paymentResult?.transaction)
|
|
29
|
+
? `https://testnet.arcscan.app/tx/${returnedPayment.txHash || data.txHash || data.transaction || paymentResult?.transaction}`
|
|
30
|
+
: ''),
|
|
31
|
+
amount: Number(returnedPayment.amount || resource.price || 0),
|
|
32
|
+
revenue: Number(returnedPayment.revenue || returnedPayment.amount || resource.price || 0),
|
|
33
|
+
currency: returnedPayment.currency || resource.currency || 'USDC',
|
|
34
|
+
payer: returnedPayment.payer || data.payer || gatewayBuyerResult.address || '',
|
|
35
|
+
recipient: resource.recipient || resource.payTo || options.recipient || serverEnv('NIBGATE_SELLER_ADDRESS') || '',
|
|
36
|
+
network: returnedPayment.network || options.network || serverEnv('NIBGATE_PAYMENT_NETWORK') || 'eip155:5042002',
|
|
37
|
+
verified: true,
|
|
38
|
+
raw: data
|
|
39
|
+
},
|
|
40
|
+
raw: paymentResult
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export async function createGatewayBuyer(options = {}) {
|
|
45
|
+
const buyerPrivateKey = options.buyerPrivateKey || serverEnv('NIBGATE_BUYER_PRIVATE_KEY') || '';
|
|
46
|
+
if (!buyerPrivateKey) {
|
|
47
|
+
return {
|
|
48
|
+
ok: false,
|
|
49
|
+
status: 503,
|
|
50
|
+
error: 'Gateway buyer is not configured',
|
|
51
|
+
detail: 'Set NIBGATE_BUYER_PRIVATE_KEY so this local example can execute a real Gateway payment.'
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
let GatewayClient;
|
|
56
|
+
try {
|
|
57
|
+
({ GatewayClient } = await importGatewayPackage('@circle-fin/x402-batching/client'));
|
|
58
|
+
} catch (error) {
|
|
59
|
+
return {
|
|
60
|
+
ok: false,
|
|
61
|
+
status: 500,
|
|
62
|
+
error: 'Gateway client package is not available',
|
|
63
|
+
detail: error.message
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const gatewayBuyer = new GatewayClient({
|
|
68
|
+
chain: options.buyerChain || serverEnv('NIBGATE_BUYER_CHAIN') || 'arcTestnet',
|
|
69
|
+
privateKey: buyerPrivateKey,
|
|
70
|
+
rpcUrl: options.buyerRpcUrl || serverEnv('NIBGATE_BUYER_RPC_URL') || undefined
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
return {
|
|
74
|
+
ok: true,
|
|
75
|
+
client: gatewayBuyer,
|
|
76
|
+
address: gatewayBuyer.address,
|
|
77
|
+
chain: options.buyerChain || serverEnv('NIBGATE_BUYER_CHAIN') || 'arcTestnet'
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export async function getGatewayBalances(options = {}) {
|
|
82
|
+
const buyer = await createGatewayBuyer(options);
|
|
83
|
+
if (!buyer.ok) return buyer;
|
|
84
|
+
const balances = await buyer.client.getBalances(options.address);
|
|
85
|
+
return { ok: true, address: options.address || buyer.address, ...balances };
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export async function depositToGateway(amount, options = {}) {
|
|
89
|
+
const buyer = await createGatewayBuyer(options);
|
|
90
|
+
if (!buyer.ok) return buyer;
|
|
91
|
+
const result = await buyer.client.deposit(String(amount), options.depositOptions || {});
|
|
92
|
+
return { ok: true, ...result };
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export async function withdrawFromGateway(amount, options = {}) {
|
|
96
|
+
const buyer = await createGatewayBuyer(options);
|
|
97
|
+
if (!buyer.ok) return buyer;
|
|
98
|
+
const result = await buyer.client.withdraw(String(amount), {
|
|
99
|
+
chain: options.chain,
|
|
100
|
+
recipient: options.recipient,
|
|
101
|
+
maxFee: options.maxFee,
|
|
102
|
+
...(options.withdrawOptions || {})
|
|
103
|
+
});
|
|
104
|
+
return { ok: true, ...result };
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export async function runCircleGatewayRequirement(request, resourceInput, options = {}) {
|
|
108
|
+
let createGatewayMiddleware;
|
|
109
|
+
try {
|
|
110
|
+
({ createGatewayMiddleware } = await importGatewayPackage('@circle-fin/x402-batching/server'));
|
|
111
|
+
} catch (error) {
|
|
112
|
+
return {
|
|
113
|
+
handled: true,
|
|
114
|
+
response: jsonResponse({
|
|
115
|
+
error: 'Gateway server package is not available',
|
|
116
|
+
detail: error.message
|
|
117
|
+
}, { status: 500 })
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const resource = normalizeResource(resourceInput);
|
|
122
|
+
const recipient = resource.recipient || resource.payTo || options.recipient || serverEnv('NIBGATE_SELLER_ADDRESS') || '';
|
|
123
|
+
const middleware = createGatewayMiddleware({
|
|
124
|
+
sellerAddress: recipient,
|
|
125
|
+
facilitatorUrl: options.facilitatorUrl || serverEnv('NIBGATE_FACILITATOR_URL') || serverEnv('CIRCLE_GATEWAY_FACILITATOR_URL') || 'https://gateway-api-testnet.circle.com',
|
|
126
|
+
networks: [options.network || serverEnv('NIBGATE_PAYMENT_NETWORK') || 'eip155:5042002'],
|
|
127
|
+
description: `Unlock ${resource.title}`
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
let body = '';
|
|
131
|
+
const headers = {};
|
|
132
|
+
let statusCode = 200;
|
|
133
|
+
let nextCalled = false;
|
|
134
|
+
const requestHeaders = {};
|
|
135
|
+
request.headers?.forEach?.((value, key) => {
|
|
136
|
+
requestHeaders[key.toLowerCase()] = value;
|
|
137
|
+
});
|
|
138
|
+
const req = {
|
|
139
|
+
method: request.method || 'GET',
|
|
140
|
+
url: resource.url || resource.path || '/',
|
|
141
|
+
headers: requestHeaders
|
|
142
|
+
};
|
|
143
|
+
const res = {
|
|
144
|
+
get statusCode() {
|
|
145
|
+
return statusCode;
|
|
146
|
+
},
|
|
147
|
+
set statusCode(value) {
|
|
148
|
+
statusCode = value;
|
|
149
|
+
},
|
|
150
|
+
setHeader(name, value) {
|
|
151
|
+
headers[name] = value;
|
|
152
|
+
},
|
|
153
|
+
end(value = '') {
|
|
154
|
+
body = value;
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
await middleware.require(`$${resource.price}`)(req, res, () => {
|
|
159
|
+
nextCalled = true;
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
if (!nextCalled) {
|
|
163
|
+
return {
|
|
164
|
+
handled: true,
|
|
165
|
+
response: new Response(body, {
|
|
166
|
+
status: statusCode,
|
|
167
|
+
headers
|
|
168
|
+
})
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return {
|
|
173
|
+
handled: false,
|
|
174
|
+
payment: {
|
|
175
|
+
paymentProvider: 'circle-gateway',
|
|
176
|
+
paymentId: request.headers.get('payment-signature') || '',
|
|
177
|
+
memo: request.headers.get('payment-memo') || '',
|
|
178
|
+
amount: Number(resource.price || 0),
|
|
179
|
+
revenue: Number(resource.price || 0),
|
|
180
|
+
currency: resource.currency || 'USDC',
|
|
181
|
+
recipient,
|
|
182
|
+
network: options.network || serverEnv('NIBGATE_PAYMENT_NETWORK') || 'eip155:5042002',
|
|
183
|
+
verified: true
|
|
184
|
+
}
|
|
185
|
+
};
|
|
186
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { normalizeServerResource as normalizeResource } from '../core/resource.js';
|
|
2
|
+
import { serverEnv } from './env.js';
|
|
3
|
+
|
|
4
|
+
export async function emitHubEvent(event, resourceInput, options = {}) {
|
|
5
|
+
const resource = normalizeResource(resourceInput);
|
|
6
|
+
const siteId = options.siteId || serverEnv('NIBGATE_SITE_ID') || '';
|
|
7
|
+
const token = options.token || serverEnv('NIBGATE_SITE_TOKEN') || '';
|
|
8
|
+
const apiBaseUrl = (options.apiBaseUrl || serverEnv('NIBGATE_API_BASE') || 'http://localhost:3000').replace(/\/$/, '');
|
|
9
|
+
const origin = options.origin || serverEnv('NIBGATE_SITE_ORIGIN') || '';
|
|
10
|
+
|
|
11
|
+
if (!siteId || !token) {
|
|
12
|
+
return { skipped: true, reason: 'Missing NIBGATE_SITE_ID or NIBGATE_SITE_TOKEN' };
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const response = await fetch(`${apiBaseUrl}/api/hub/track`, {
|
|
16
|
+
method: 'POST',
|
|
17
|
+
headers: {
|
|
18
|
+
'content-type': 'application/json',
|
|
19
|
+
...(origin ? { origin } : {}),
|
|
20
|
+
...(options.headers || {})
|
|
21
|
+
},
|
|
22
|
+
body: JSON.stringify({
|
|
23
|
+
siteId,
|
|
24
|
+
token,
|
|
25
|
+
event,
|
|
26
|
+
resource,
|
|
27
|
+
url: resource.url,
|
|
28
|
+
path: resource.path,
|
|
29
|
+
visitorId: options.visitorId || 'nibgate-visitor',
|
|
30
|
+
sessionId: options.sessionId || 'nibgate-session',
|
|
31
|
+
...(options.payload || {})
|
|
32
|
+
})
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
return { ok: response.ok, status: response.status, body: await response.text() };
|
|
36
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { createNibgateServer } from './access.js';
|
|
2
|
+
|
|
3
|
+
export { actorFromRequest, accessModeFor } from './actor.js';
|
|
4
|
+
export { createPaymentChallenge } from './challenge.js';
|
|
5
|
+
export { createManifest, manifestResponse } from './manifest.js';
|
|
6
|
+
export { createUnlockToken, verifyUnlockToken } from './proof.js';
|
|
7
|
+
export { emitHubEvent } from './hub.js';
|
|
8
|
+
export { payWithGateway, createGatewayBuyer, getGatewayBalances, depositToGateway, withdrawFromGateway } from './gateway.js';
|
|
9
|
+
export { createNibgateServer, protect } from './access.js';
|
|
10
|
+
export { circleGatewayOptions, createCircleGatewayServer } from './presets.js';
|
|
11
|
+
export { normalizeServerResource as normalizeResource, normalizeAccessPolicy, normalizeUnlockPolicy, validateResourceMetadata, UNLOCK_MODES } from '../core/resource.js';
|
|
12
|
+
|
|
13
|
+
export const server = createNibgateServer();
|
|
14
|
+
export { NIBGATE_CONTENT_SETTING_FIELDS, createNibgateContentSettings, settingsToAccessPolicy, settingsToUnlockPolicy } from '../core/settings.js';
|
|
15
|
+
export { PAYMENT_RAILS, normalizePaymentRail } from '../core/payment.js';
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { normalizeServerResource as normalizeResource } from '../core/resource.js';
|
|
2
|
+
import { serverEnv } from './env.js';
|
|
3
|
+
import { jsonResponse } from './response.js';
|
|
4
|
+
|
|
5
|
+
export function createManifest(input = {}) {
|
|
6
|
+
const origin = input.origin || serverEnv('NIBGATE_SITE_ORIGIN') || '';
|
|
7
|
+
const content = (input.content || input.resources || []).map((resource) => normalizeResource(resource));
|
|
8
|
+
return {
|
|
9
|
+
name: input.name || 'Nibgate creator site',
|
|
10
|
+
origin,
|
|
11
|
+
nibgate: {
|
|
12
|
+
content
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function manifestResponse(input = {}) {
|
|
18
|
+
return jsonResponse(createManifest(input));
|
|
19
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { createNibgateServer } from './access.js';
|
|
2
|
+
import { serverEnv } from './env.js';
|
|
3
|
+
|
|
4
|
+
export function circleGatewayOptions(options = {}) {
|
|
5
|
+
return {
|
|
6
|
+
...options,
|
|
7
|
+
paymentMode: options.paymentMode || serverEnv('NIBGATE_PAYMENT_MODE') || 'circle-gateway',
|
|
8
|
+
network: options.network || serverEnv('NIBGATE_PAYMENT_NETWORK') || 'eip155:5042002'
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function createCircleGatewayServer(options = {}) {
|
|
13
|
+
return createNibgateServer(circleGatewayOptions(options));
|
|
14
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import crypto from 'node:crypto';
|
|
2
|
+
import { normalizeServerResource as normalizeResource } from '../core/resource.js';
|
|
3
|
+
import { serverEnv } from './env.js';
|
|
4
|
+
|
|
5
|
+
export const DEFAULT_UNLOCK_SECONDS = 60 * 60 * 12;
|
|
6
|
+
|
|
7
|
+
function stableJson(value) {
|
|
8
|
+
if (Array.isArray(value)) return `[${value.map((entry) => stableJson(entry)).join(',')}]`;
|
|
9
|
+
if (value && typeof value === 'object') {
|
|
10
|
+
return `{${Object.keys(value).sort().map((key) => `${JSON.stringify(key)}:${stableJson(value[key])}`).join(',')}}`;
|
|
11
|
+
}
|
|
12
|
+
return JSON.stringify(value);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function base64url(value) {
|
|
16
|
+
return Buffer.from(value).toString('base64url');
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function fromBase64url(value) {
|
|
20
|
+
return Buffer.from(value, 'base64url').toString('utf8');
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function sign(payload, secret) {
|
|
24
|
+
return crypto.createHmac('sha256', secret).update(payload).digest('base64url');
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function createUnlockToken(resourceInput, options = {}) {
|
|
28
|
+
const resource = normalizeResource(resourceInput);
|
|
29
|
+
const secret = options.secret || serverEnv('NIBGATE_SECRET') || serverEnv('NIBGATE_UNLOCK_SECRET') || 'nibgate-dev-secret';
|
|
30
|
+
const now = Math.floor(Date.now() / 1000);
|
|
31
|
+
const payment = options.payment || {};
|
|
32
|
+
const payload = {
|
|
33
|
+
contentId: resource.id,
|
|
34
|
+
paymentId: options.paymentId || '',
|
|
35
|
+
payment: {
|
|
36
|
+
paymentId: payment.paymentId || options.paymentId || '',
|
|
37
|
+
txHash: payment.txHash || '',
|
|
38
|
+
memo: payment.memo || '',
|
|
39
|
+
payer: payment.payer || '',
|
|
40
|
+
recipient: payment.recipient || resource.recipient || resource.payTo || '',
|
|
41
|
+
amount: Number(payment.amount || resource.price || 0),
|
|
42
|
+
currency: payment.currency || resource.currency || 'USDC',
|
|
43
|
+
network: payment.network || '',
|
|
44
|
+
verified: Boolean(payment.verified)
|
|
45
|
+
},
|
|
46
|
+
actor: options.actor || 'human',
|
|
47
|
+
iat: now,
|
|
48
|
+
exp: now + (options.expiresInSeconds || DEFAULT_UNLOCK_SECONDS)
|
|
49
|
+
};
|
|
50
|
+
const encoded = base64url(stableJson(payload));
|
|
51
|
+
return `${encoded}.${sign(encoded, secret)}`;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function verifyUnlockToken(token, resourceInput, options = {}) {
|
|
55
|
+
if (!token || !token.includes('.')) return null;
|
|
56
|
+
const resource = normalizeResource(resourceInput);
|
|
57
|
+
const secret = options.secret || serverEnv('NIBGATE_SECRET') || serverEnv('NIBGATE_UNLOCK_SECRET') || 'nibgate-dev-secret';
|
|
58
|
+
const [encoded, signature] = token.split('.');
|
|
59
|
+
const expected = sign(encoded, secret);
|
|
60
|
+
const signatureBuffer = Buffer.from(signature || '');
|
|
61
|
+
const expectedBuffer = Buffer.from(expected);
|
|
62
|
+
if (signatureBuffer.length !== expectedBuffer.length) return null;
|
|
63
|
+
if (!crypto.timingSafeEqual(signatureBuffer, expectedBuffer)) return null;
|
|
64
|
+
|
|
65
|
+
try {
|
|
66
|
+
const payload = JSON.parse(fromBase64url(encoded));
|
|
67
|
+
if (payload.contentId !== resource.id) return null;
|
|
68
|
+
if (payload.exp && payload.exp < Math.floor(Date.now() / 1000)) return null;
|
|
69
|
+
return payload;
|
|
70
|
+
} catch (_error) {
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { createRequire } from 'node:module';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
4
|
+
|
|
5
|
+
const requireFromPackage = createRequire(import.meta.url);
|
|
6
|
+
const requireFromCwd = createRequire(`${process.cwd()}/package.json`);
|
|
7
|
+
const packageSourceDir = path.dirname(fileURLToPath(import.meta.url));
|
|
8
|
+
const workspaceNodeModulesDir = path.resolve(packageSourceDir, '../../../node_modules/.pnpm/node_modules');
|
|
9
|
+
const nativeImport = new Function('specifier', 'return import(specifier)');
|
|
10
|
+
|
|
11
|
+
export async function runtimeImportPackage(specifier) {
|
|
12
|
+
try {
|
|
13
|
+
return await nativeImport(specifier);
|
|
14
|
+
} catch (_error) {
|
|
15
|
+
try {
|
|
16
|
+
return await nativeImport(requireFromPackage.resolve(specifier));
|
|
17
|
+
} catch (_packageError) {
|
|
18
|
+
try {
|
|
19
|
+
return await nativeImport(requireFromCwd.resolve(specifier));
|
|
20
|
+
} catch (_cwdError) {
|
|
21
|
+
if (specifier === '@circle-fin/x402-batching/client') {
|
|
22
|
+
try {
|
|
23
|
+
return await nativeImport(`${process.cwd()}/node_modules/.pnpm/node_modules/@circle-fin/x402-batching/dist/client/index.mjs`);
|
|
24
|
+
} catch {
|
|
25
|
+
return nativeImport(pathToFileURL(path.join(workspaceNodeModulesDir, '@circle-fin/x402-batching/dist/client/index.mjs')).href);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
if (specifier === '@circle-fin/x402-batching/server') {
|
|
29
|
+
try {
|
|
30
|
+
return await nativeImport(`${process.cwd()}/node_modules/.pnpm/node_modules/@circle-fin/x402-batching/dist/server/index.mjs`);
|
|
31
|
+
} catch {
|
|
32
|
+
return nativeImport(pathToFileURL(path.join(workspaceNodeModulesDir, '@circle-fin/x402-batching/dist/server/index.mjs')).href);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return nativeImport(`${process.cwd()}/node_modules/.pnpm/node_modules/${specifier}`);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
package/src/server.d.ts
ADDED
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
export type NibgateServerResource = {
|
|
2
|
+
id: string;
|
|
3
|
+
title?: string;
|
|
4
|
+
type?: 'music' | 'video' | 'article' | 'image' | string;
|
|
5
|
+
contentType?: 'music' | 'video' | 'article' | 'image' | string;
|
|
6
|
+
price?: string | number;
|
|
7
|
+
paymentRail?: NibgatePaymentRail | string;
|
|
8
|
+
amount?: string | number;
|
|
9
|
+
recipient?: string;
|
|
10
|
+
receiver?: string;
|
|
11
|
+
receiverAddress?: string;
|
|
12
|
+
payTo?: string;
|
|
13
|
+
creatorWallet?: string;
|
|
14
|
+
path?: string;
|
|
15
|
+
route?: string;
|
|
16
|
+
url?: string;
|
|
17
|
+
imageUrl?: string;
|
|
18
|
+
image?: string;
|
|
19
|
+
description?: string;
|
|
20
|
+
summary?: string;
|
|
21
|
+
tags?: string[] | string;
|
|
22
|
+
currency?: string;
|
|
23
|
+
access?: NibgateAccessMode | NibgateAccessPolicy;
|
|
24
|
+
unlock?: NibgateUnlockMode | NibgateUnlockPolicy;
|
|
25
|
+
[key: string]: unknown;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export type NibgateMetadataValidation = {
|
|
29
|
+
ok: boolean;
|
|
30
|
+
score: number;
|
|
31
|
+
errors: string[];
|
|
32
|
+
warnings: string[];
|
|
33
|
+
resource: NibgateServerResource;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export type NibgateActor = 'human' | 'agent';
|
|
37
|
+
export type NibgateAccessMode = 'free' | 'paid' | 'blocked';
|
|
38
|
+
export type NibgateUnlockMode = 'one_time' | 'metered_stream' | 'metered_read' | 'time_pass' | 'agent_quota';
|
|
39
|
+
export type NibgatePaymentRail = 'gateway' | 'transfer';
|
|
40
|
+
export type NibgateAccessPolicy = {
|
|
41
|
+
humans?: NibgateAccessMode;
|
|
42
|
+
human?: NibgateAccessMode;
|
|
43
|
+
agents?: NibgateAccessMode;
|
|
44
|
+
agent?: NibgateAccessMode;
|
|
45
|
+
default?: NibgateAccessMode;
|
|
46
|
+
};
|
|
47
|
+
export type NibgateUnlockPolicy = {
|
|
48
|
+
mode?: NibgateUnlockMode | string;
|
|
49
|
+
type?: NibgateUnlockMode | string;
|
|
50
|
+
unit?: string;
|
|
51
|
+
pricePerUnit?: string | number;
|
|
52
|
+
duration?: string | number;
|
|
53
|
+
maxReads?: number;
|
|
54
|
+
[key: string]: unknown;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
export type NibgateContentSettingField = {
|
|
59
|
+
name: string;
|
|
60
|
+
label: string;
|
|
61
|
+
type: 'boolean' | 'select' | 'text' | 'wallet' | 'textarea' | string;
|
|
62
|
+
options?: readonly string[];
|
|
63
|
+
defaultValue?: string | boolean;
|
|
64
|
+
};
|
|
65
|
+
export type NibgateContentSettings = {
|
|
66
|
+
publishToNibgate: boolean;
|
|
67
|
+
type: 'music' | 'video' | 'article' | 'image';
|
|
68
|
+
humanAccess: NibgateAccessMode;
|
|
69
|
+
agentAccess: NibgateAccessMode;
|
|
70
|
+
unlockMode: NibgateUnlockMode | string;
|
|
71
|
+
price: string;
|
|
72
|
+
currency: string;
|
|
73
|
+
recipient: string;
|
|
74
|
+
license: string;
|
|
75
|
+
};
|
|
76
|
+
export declare const NIBGATE_CONTENT_SETTING_FIELDS: readonly NibgateContentSettingField[];
|
|
77
|
+
export declare function createNibgateContentSettings(input?: Record<string, unknown>): NibgateContentSettings;
|
|
78
|
+
export declare function settingsToAccessPolicy(settings?: Partial<NibgateContentSettings>): Required<Pick<NibgateAccessPolicy, 'humans' | 'agents'>>;
|
|
79
|
+
export declare function settingsToUnlockPolicy(settings?: Partial<NibgateContentSettings>): Required<Pick<NibgateUnlockPolicy, 'mode'>> & NibgateUnlockPolicy;
|
|
80
|
+
|
|
81
|
+
export declare const PAYMENT_RAILS: readonly ['gateway', 'transfer'];
|
|
82
|
+
export declare function normalizePaymentRail(value?: string, fallback?: NibgatePaymentRail): NibgatePaymentRail;
|
|
83
|
+
export declare const UNLOCK_MODES: readonly ['one_time', 'metered_stream', 'metered_read', 'time_pass', 'agent_quota'];
|
|
84
|
+
|
|
85
|
+
export type NibgatePaymentInput = {
|
|
86
|
+
id?: string;
|
|
87
|
+
paymentId?: string;
|
|
88
|
+
paymentProvider?: 'circle-gateway' | 'arc-testnet' | 'x402' | string;
|
|
89
|
+
receiptUrl?: string;
|
|
90
|
+
txHash?: string;
|
|
91
|
+
chainId?: string | number;
|
|
92
|
+
chainExplorerUrl?: string;
|
|
93
|
+
payer?: string;
|
|
94
|
+
recipient?: string;
|
|
95
|
+
actor?: string;
|
|
96
|
+
expiresInSeconds?: number;
|
|
97
|
+
[key: string]: unknown;
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
export type NibgateServerOptions = {
|
|
101
|
+
secret?: string;
|
|
102
|
+
origin?: string;
|
|
103
|
+
paymentMode?: string;
|
|
104
|
+
network?: string;
|
|
105
|
+
recipient?: string;
|
|
106
|
+
expiresInSeconds?: number;
|
|
107
|
+
actor?: NibgateActor;
|
|
108
|
+
defaultActor?: NibgateActor;
|
|
109
|
+
paymentRail?: NibgatePaymentRail | string;
|
|
110
|
+
verifyPayment?: (input: { resource: NibgateServerResource; payment: NibgatePaymentInput }) => boolean | Promise<boolean>;
|
|
111
|
+
verifyTransfer?: (input: { resource: NibgateServerResource; txHash: string; payment: NibgatePaymentInput; request: Request }) => boolean | Promise<boolean>;
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
export type NibgateUnlockResult =
|
|
115
|
+
| {
|
|
116
|
+
ok: true;
|
|
117
|
+
unlockProof: string;
|
|
118
|
+
expiresInSeconds: number;
|
|
119
|
+
resource: NibgateServerResource;
|
|
120
|
+
payment: NibgatePaymentInput;
|
|
121
|
+
}
|
|
122
|
+
| {
|
|
123
|
+
ok: false;
|
|
124
|
+
status: 402;
|
|
125
|
+
error: string;
|
|
126
|
+
challenge: Record<string, unknown>;
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
export declare function createUnlockToken(resource: NibgateServerResource | string, options?: NibgateServerOptions & NibgatePaymentInput): string;
|
|
130
|
+
export declare function verifyUnlockToken(token: string, resource: NibgateServerResource | string, options?: NibgateServerOptions): Record<string, unknown> | null;
|
|
131
|
+
export declare function createPaymentChallenge(resource: NibgateServerResource | string, options?: NibgateServerOptions): Record<string, unknown>;
|
|
132
|
+
export declare function createManifest(input?: { name?: string; origin?: string; content?: Array<NibgateServerResource | string>; resources?: Array<NibgateServerResource | string> }): Record<string, unknown>;
|
|
133
|
+
export declare function manifestResponse(input?: { name?: string; origin?: string; content?: Array<NibgateServerResource | string>; resources?: Array<NibgateServerResource | string> }): Response;
|
|
134
|
+
export declare function emitHubEvent(event: string, resource: NibgateServerResource | string, options?: NibgateServerOptions & {
|
|
135
|
+
siteId?: string;
|
|
136
|
+
token?: string;
|
|
137
|
+
apiBaseUrl?: string;
|
|
138
|
+
headers?: Record<string, string>;
|
|
139
|
+
visitorId?: string;
|
|
140
|
+
sessionId?: string;
|
|
141
|
+
payload?: Record<string, unknown>;
|
|
142
|
+
}): Promise<Record<string, unknown>>;
|
|
143
|
+
export declare function payWithGateway(resource: NibgateServerResource | string, options?: NibgateServerOptions & {
|
|
144
|
+
accessUrl?: string;
|
|
145
|
+
accessPath?: string;
|
|
146
|
+
buyerPrivateKey?: string;
|
|
147
|
+
buyerChain?: string;
|
|
148
|
+
buyerRpcUrl?: string;
|
|
149
|
+
}): Promise<Record<string, unknown>>;
|
|
150
|
+
export declare function createGatewayBuyer(options?: NibgateServerOptions & {
|
|
151
|
+
buyerPrivateKey?: string;
|
|
152
|
+
buyerChain?: string;
|
|
153
|
+
buyerRpcUrl?: string;
|
|
154
|
+
}): Promise<Record<string, unknown>>;
|
|
155
|
+
export declare function getGatewayBalances(options?: NibgateServerOptions & {
|
|
156
|
+
buyerPrivateKey?: string;
|
|
157
|
+
buyerChain?: string;
|
|
158
|
+
buyerRpcUrl?: string;
|
|
159
|
+
address?: string;
|
|
160
|
+
}): Promise<Record<string, unknown>>;
|
|
161
|
+
export declare function depositToGateway(amount: string | number, options?: NibgateServerOptions & {
|
|
162
|
+
buyerPrivateKey?: string;
|
|
163
|
+
buyerChain?: string;
|
|
164
|
+
buyerRpcUrl?: string;
|
|
165
|
+
depositOptions?: Record<string, unknown>;
|
|
166
|
+
}): Promise<Record<string, unknown>>;
|
|
167
|
+
export declare function withdrawFromGateway(amount: string | number, options?: NibgateServerOptions & {
|
|
168
|
+
buyerPrivateKey?: string;
|
|
169
|
+
buyerChain?: string;
|
|
170
|
+
buyerRpcUrl?: string;
|
|
171
|
+
chain?: string;
|
|
172
|
+
recipient?: string;
|
|
173
|
+
maxFee?: string;
|
|
174
|
+
withdrawOptions?: Record<string, unknown>;
|
|
175
|
+
}): Promise<Record<string, unknown>>;
|
|
176
|
+
export declare function circleGatewayOptions(options?: NibgateServerOptions): NibgateServerOptions & { paymentMode: string; network: string };
|
|
177
|
+
export declare function createCircleGatewayServer(options?: NibgateServerOptions): ReturnType<typeof createNibgateServer>;
|
|
178
|
+
export declare function createNibgateServer(options?: NibgateServerOptions): {
|
|
179
|
+
unlock(resource: NibgateServerResource | string, payment?: NibgatePaymentInput): Promise<NibgateUnlockResult>;
|
|
180
|
+
isUnlocked(request: Request, resource: NibgateServerResource | string, options?: { actor?: NibgateActor }): boolean;
|
|
181
|
+
accessFor(request: Request, resource: NibgateServerResource | string, options?: { actor?: NibgateActor; defaultActor?: NibgateActor }): {
|
|
182
|
+
actor: NibgateActor;
|
|
183
|
+
mode: NibgateAccessMode;
|
|
184
|
+
unlocked: boolean;
|
|
185
|
+
allowed: boolean;
|
|
186
|
+
blocked: boolean;
|
|
187
|
+
paid: boolean;
|
|
188
|
+
resource: NibgateServerResource;
|
|
189
|
+
};
|
|
190
|
+
protect(resource: NibgateServerResource | string, handler: (request: Request, context?: unknown) => Response | Promise<Response>, routeOptions?: NibgateServerOptions): (request: Request, context?: unknown) => Promise<Response>;
|
|
191
|
+
accessResponse(request: Request, resource: NibgateServerResource | string, allowedBody?: Record<string, unknown> | ((input: { access: Record<string, unknown>; resource: NibgateServerResource }) => Record<string, unknown> | Response) | null, routeOptions?: NibgateServerOptions): Promise<Response>;
|
|
192
|
+
payAndUnlockResponse(request: Request, resource: NibgateServerResource | string, routeOptions?: NibgateServerOptions & { accessUrl?: string; accessPath?: string }): Promise<Response>;
|
|
193
|
+
manifest(input?: { name?: string; origin?: string; content?: Array<NibgateServerResource | string>; resources?: Array<NibgateServerResource | string> }): Record<string, unknown>;
|
|
194
|
+
manifestResponse(input?: { name?: string; origin?: string; content?: Array<NibgateServerResource | string>; resources?: Array<NibgateServerResource | string> }): Response;
|
|
195
|
+
emitHubEvent(event: string, resource: NibgateServerResource | string, options?: Record<string, unknown>): Promise<Record<string, unknown>>;
|
|
196
|
+
getGatewayBalances(options?: Record<string, unknown>): Promise<Record<string, unknown>>;
|
|
197
|
+
depositToGateway(amount: string | number, options?: Record<string, unknown>): Promise<Record<string, unknown>>;
|
|
198
|
+
withdrawFromGateway(amount: string | number, options?: Record<string, unknown>): Promise<Record<string, unknown>>;
|
|
199
|
+
createPaymentChallenge(resource: NibgateServerResource | string, options?: NibgateServerOptions): Record<string, unknown>;
|
|
200
|
+
createUnlockToken(resource: NibgateServerResource | string, options?: NibgateServerOptions & NibgatePaymentInput): string;
|
|
201
|
+
verifyUnlockToken(token: string, resource: NibgateServerResource | string): Record<string, unknown> | null;
|
|
202
|
+
actorFromRequest(request: Request, fallback?: NibgateActor): NibgateActor;
|
|
203
|
+
accessModeFor(resource: NibgateServerResource | string, actor?: NibgateActor): NibgateAccessMode;
|
|
204
|
+
};
|
|
205
|
+
export declare function protect(resource: NibgateServerResource | string, handler: (request: Request, context?: unknown) => Response | Promise<Response>, options?: NibgateServerOptions): (request: Request, context?: unknown) => Promise<Response>;
|
|
206
|
+
export declare const server: ReturnType<typeof createNibgateServer>;
|
|
207
|
+
export declare function actorFromRequest(request: Request, fallback?: NibgateActor): NibgateActor;
|
|
208
|
+
export declare function accessModeFor(resource: NibgateServerResource | string, actor?: NibgateActor): NibgateAccessMode;
|
|
209
|
+
export declare function normalizeResource(resource?: NibgateServerResource | string): NibgateServerResource;
|
|
210
|
+
export declare function validateResourceMetadata(resource?: NibgateServerResource | string, options?: Record<string, unknown>): NibgateMetadataValidation;
|
|
211
|
+
export declare function normalizeAccessPolicy(access?: NibgateAccessMode | NibgateAccessPolicy): Required<Pick<NibgateAccessPolicy, 'humans' | 'agents'>>;
|
|
212
|
+
export declare function normalizeUnlockPolicy(unlock?: NibgateUnlockMode | NibgateUnlockPolicy): Required<Pick<NibgateUnlockPolicy, 'mode'>> & NibgateUnlockPolicy;
|
package/src/server.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './server/index.js';
|