@nibgate/sdk 0.2.5 → 0.2.7
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/SKILL.md +14 -19
- package/dist/nibgate.js +64 -11
- package/dist/nibgate.js.map +2 -2
- package/dist/nibgate.min.js +2 -2
- package/dist/nibgate.min.js.map +3 -3
- package/package.json +1 -1
- package/src/browser/evm-gateway.js +3 -1
- package/src/browser/gateway.js +30 -4
- package/src/core/resource.js +43 -8
package/src/browser/gateway.js
CHANGED
|
@@ -1,6 +1,34 @@
|
|
|
1
1
|
import { stringifyJson } from './json.js';
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
let cachedCircleModule = null;
|
|
4
|
+
|
|
5
|
+
async function getCircleClient(options = {}) {
|
|
6
|
+
if (cachedCircleModule) return cachedCircleModule;
|
|
7
|
+
|
|
8
|
+
if (options.clientModule) {
|
|
9
|
+
cachedCircleModule = options.clientModule;
|
|
10
|
+
return cachedCircleModule;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const moduleUrl = options.clientModuleUrl || '@circle-fin/x402-batching/client';
|
|
14
|
+
|
|
15
|
+
try {
|
|
16
|
+
cachedCircleModule = await import(moduleUrl);
|
|
17
|
+
return cachedCircleModule;
|
|
18
|
+
} catch (error) {
|
|
19
|
+
if (!options.clientModuleUrl) {
|
|
20
|
+
throw new Error(
|
|
21
|
+
`Could not load @circle-fin/x402-batching/client from node_modules. ` +
|
|
22
|
+
`Provide a clientModuleUrl option (e.g. "https://esm.sh/@circle-fin/x402-batching@3.2.0/client?bundle") ` +
|
|
23
|
+
`to load from CDN. Original error: ${error.message}`
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
throw new Error(
|
|
27
|
+
`Could not load Circle Gateway client from CDN: ${error.message}. ` +
|
|
28
|
+
`Check that ${options.clientModuleUrl} is reachable.`
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
4
32
|
|
|
5
33
|
function encodeBase64(value) {
|
|
6
34
|
const text = typeof value === 'string' ? value : stringifyJson(value);
|
|
@@ -19,9 +47,7 @@ export async function createCircleGatewayBrowserAdapter(options = {}) {
|
|
|
19
47
|
throw new Error('Circle Gateway browser adapter requires an EVM signer with address and signTypedData.');
|
|
20
48
|
}
|
|
21
49
|
|
|
22
|
-
const circleClientModule =
|
|
23
|
-
? await runtimeImport(options.clientModuleUrl)
|
|
24
|
-
: await runtimeImport('@circle-fin/x402-batching/client'));
|
|
50
|
+
const circleClientModule = await getCircleClient(options);
|
|
25
51
|
const { BatchEvmScheme } = circleClientModule;
|
|
26
52
|
const scheme = new BatchEvmScheme(signer);
|
|
27
53
|
const network = options.network || options.chainId && `eip155:${options.chainId}` || 'eip155:5042002';
|
package/src/core/resource.js
CHANGED
|
@@ -70,6 +70,38 @@ function autoDeriveImage() {
|
|
|
70
70
|
return metaContent('og:image') || undefined;
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
+
function autoDeriveDescription() {
|
|
74
|
+
return metaContent('og:description') || metaContent('description') || undefined;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function autoDeriveTitle() {
|
|
78
|
+
const win = browserEnv();
|
|
79
|
+
return metaContent('og:title') || metaContent('twitter:title') || (win ? win.document.title : '') || undefined;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function autoDeriveType() {
|
|
83
|
+
const ogType = metaContent('og:type').toLowerCase();
|
|
84
|
+
if (ogType.includes('music') || ogType.includes('audio') || ogType.includes('song')) return 'music';
|
|
85
|
+
if (ogType.includes('video') || ogType.includes('movie')) return 'video';
|
|
86
|
+
if (ogType.includes('image') || ogType.includes('photo')) return 'image';
|
|
87
|
+
return 'article';
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function autoDeriveTags() {
|
|
91
|
+
const kw = metaContent('keywords');
|
|
92
|
+
if (!kw) return undefined;
|
|
93
|
+
return kw.split(',').map((t) => t.trim().toLowerCase()).filter(Boolean).slice(0, 8);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function accessForPrice(price, explicitAccess) {
|
|
97
|
+
if (explicitAccess && typeof explicitAccess === 'object' && Object.keys(explicitAccess).length > 0) {
|
|
98
|
+
return normalizeAccessPolicy(explicitAccess);
|
|
99
|
+
}
|
|
100
|
+
const hasPrice = price !== undefined && price !== null && price !== '' && Number.parseFloat(price) > 0;
|
|
101
|
+
if (hasPrice) return { humans: 'paid', agents: 'paid' };
|
|
102
|
+
return { humans: 'free', agents: 'free' };
|
|
103
|
+
}
|
|
104
|
+
|
|
73
105
|
export function normalizeResource(resource = {}) {
|
|
74
106
|
const input = typeof resource === 'string' ? { id: resource } : (resource || {});
|
|
75
107
|
const {
|
|
@@ -87,21 +119,25 @@ export function normalizeResource(resource = {}) {
|
|
|
87
119
|
|
|
88
120
|
const path = input.path || input.route || undefined;
|
|
89
121
|
const url = input.url || autoDeriveUrl(path) || undefined;
|
|
122
|
+
const explicitAccess = input.access;
|
|
123
|
+
const price = input.price ?? input.amount ?? '';
|
|
90
124
|
|
|
91
125
|
return {
|
|
92
126
|
...v1Input,
|
|
93
127
|
id: String(input.id || input.contentId || input.slug || '').trim(),
|
|
94
|
-
title: String(input.title || input.name || '').trim(),
|
|
95
|
-
type: normalizeContentType(input.type || input.contentType),
|
|
96
|
-
price
|
|
128
|
+
title: String(input.title || input.name || autoDeriveTitle() || 'Untitled').trim(),
|
|
129
|
+
type: normalizeContentType(input.type || input.contentType || autoDeriveType()),
|
|
130
|
+
price,
|
|
131
|
+
currency: input.currency || 'USDC',
|
|
97
132
|
paymentRail: normalizePaymentRail(input.paymentRail || input.paymentMode || input.rail),
|
|
98
133
|
recipient: input.recipient || input.receiver || input.receiverAddress || input.payTo || input.creatorWallet || undefined,
|
|
99
134
|
payTo: input.payTo || input.recipient || input.receiver || input.receiverAddress || input.creatorWallet || undefined,
|
|
100
135
|
path,
|
|
101
136
|
url,
|
|
102
137
|
imageUrl: input.imageUrl || input.image || autoDeriveImage() || undefined,
|
|
103
|
-
|
|
104
|
-
|
|
138
|
+
description: input.description || input.summary || autoDeriveDescription() || undefined,
|
|
139
|
+
tags: input.tags || autoDeriveTags() || undefined,
|
|
140
|
+
access: accessForPrice(price, explicitAccess),
|
|
105
141
|
unlock: normalizeUnlockPolicy(input.unlock),
|
|
106
142
|
ratingsEnabled: input.ratingsEnabled ?? input.enableRatings ?? input.reputation?.ratingsEnabled ?? true,
|
|
107
143
|
reputation: {
|
|
@@ -125,8 +161,8 @@ export function validateResourceMetadata(resource = {}, options = {}) {
|
|
|
125
161
|
const normalized = normalizeResource(resource);
|
|
126
162
|
const warnings = [];
|
|
127
163
|
const errors = [];
|
|
128
|
-
const required = options.required || ['id', '
|
|
129
|
-
const recommended = options.recommended || ['description', 'imageUrl', 'tags'];
|
|
164
|
+
const required = options.required || ['id', 'type'];
|
|
165
|
+
const recommended = options.recommended || ['title', 'url', 'description', 'imageUrl', 'tags'];
|
|
130
166
|
|
|
131
167
|
for (const field of required) {
|
|
132
168
|
if (!hasValue(normalized[field])) errors.push(`Missing required content metadata: ${field}`);
|
|
@@ -168,6 +204,5 @@ export function normalizeServerResource(resource = {}) {
|
|
|
168
204
|
title: normalized.title || String((typeof resource === 'object' && (resource.name || resource.id)) || 'Untitled content').trim(),
|
|
169
205
|
price: normalized.price || '0',
|
|
170
206
|
path: normalized.path || '/',
|
|
171
|
-
currency: normalized.currency || 'USDC'
|
|
172
207
|
};
|
|
173
208
|
}
|