@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 CHANGED
@@ -44,35 +44,30 @@ If the widget loads after app code, the SDK queues events and flushes them when
44
44
 
45
45
  ---
46
46
 
47
- ## 2. Resource Shape
47
+ ## 2. Resource Shape (Minimal)
48
48
 
49
- Define one stable resource per paid route, CMS row, media item, file, or API product:
49
+ The SDK auto-derives most fields from meta tags and defaults. You only need:
50
50
 
51
51
  ```ts
52
52
  const resource = {
53
53
  id: post.id,
54
- title: post.title,
55
- description: post.excerpt,
56
- type: 'article',
57
- price: '0.01',
58
- currency: 'USDC',
59
- recipient: post.creatorWallet,
54
+ title: post.title, // auto-fallsback to og:title → document.title
60
55
  path: `/posts/${post.slug}`,
61
- url: `https://creator.example/posts/${post.slug}`,
62
- tags: ['essay', 'research'],
63
- access: { humans: 'paid', agents: 'paid' },
64
- unlock: { mode: 'one_time' }
56
+ price: '0.01' // sets access: { humans: 'paid', agents: 'paid' } automatically
65
57
  }
66
58
  ```
67
59
 
68
- Allowed types: `article`, `image`, `music`, `video` (aliases like `audio→music`, `photo→image` are normalized). Use stable IDs — changing IDs breaks continuity for Explore, receipts, and reputation.
69
-
70
- **Auto-derived fields:** When running in a browser, the SDK auto-fills:
71
- - `url` from `window.location.origin + path` if `path` is provided but `url` is not
72
- - `imageUrl` from `<meta property="og:image">` if not explicitly set
73
- - `recipient` is **not required client-side** — the server's 402 payment challenge provides the canonical wallet address. Missing it generates a warning, not an error.
60
+ The rest fills in automatically from your page's HTML:
61
+ - `url` from `window.location.origin + path`
62
+ - `type` from `<meta property="og:type">` (defaults to `article`)
63
+ - `imageUrl` from `<meta property="og:image">`
64
+ - `description` from `<meta property="og:description">` `<meta name="description">`
65
+ - `tags` from `<meta name="keywords">`
66
+ - `currency` defaults to `USDC`
67
+ - `access` defaults to `paid` when `price > 0`, otherwise `free`
68
+ - `recipient` is optional (server's 402 challenge provides the real wallet)
74
69
 
75
- So a minimal client-side resource only needs `id`, `title`, `path`, and `price` — the rest is filled in automatically.
70
+ Allowed types: `article`, `image`, `music`, `video` (aliases like `audio→music`, `photo→image` are normalized). Use stable IDs changing IDs breaks continuity for Explore, receipts, and reputation.
76
71
 
77
72
  **Important:** The `image`, `description`, and `title` fields become the public thumbnail and card copy on the Explore page. Use a teaser preview, not the actual paid file.
78
73
 
package/dist/nibgate.js CHANGED
@@ -38,6 +38,27 @@ var Nibgate = (() => {
38
38
  __export(gateway_exports, {
39
39
  createCircleGatewayBrowserAdapter: () => createCircleGatewayBrowserAdapter
40
40
  });
41
+ async function getCircleClient(options = {}) {
42
+ if (cachedCircleModule) return cachedCircleModule;
43
+ if (options.clientModule) {
44
+ cachedCircleModule = options.clientModule;
45
+ return cachedCircleModule;
46
+ }
47
+ const moduleUrl = options.clientModuleUrl || "@circle-fin/x402-batching/client";
48
+ try {
49
+ cachedCircleModule = await import(moduleUrl);
50
+ return cachedCircleModule;
51
+ } catch (error) {
52
+ if (!options.clientModuleUrl) {
53
+ throw new Error(
54
+ `Could not load @circle-fin/x402-batching/client from node_modules. Provide a clientModuleUrl option (e.g. "https://esm.sh/@circle-fin/x402-batching@3.2.0/client?bundle") to load from CDN. Original error: ${error.message}`
55
+ );
56
+ }
57
+ throw new Error(
58
+ `Could not load Circle Gateway client from CDN: ${error.message}. Check that ${options.clientModuleUrl} is reachable.`
59
+ );
60
+ }
61
+ }
41
62
  function encodeBase64(value) {
42
63
  const text = typeof value === "string" ? value : stringifyJson(value);
43
64
  if (typeof Buffer !== "undefined") return Buffer.from(text).toString("base64");
@@ -52,7 +73,7 @@ var Nibgate = (() => {
52
73
  if (!signer?.address || typeof signer.signTypedData !== "function") {
53
74
  throw new Error("Circle Gateway browser adapter requires an EVM signer with address and signTypedData.");
54
75
  }
55
- const circleClientModule = options.clientModule || (options.clientModuleUrl ? await runtimeImport(options.clientModuleUrl) : await runtimeImport("@circle-fin/x402-batching/client"));
76
+ const circleClientModule = await getCircleClient(options);
56
77
  const { BatchEvmScheme } = circleClientModule;
57
78
  const scheme = new BatchEvmScheme(signer);
58
79
  const network = options.network || options.chainId && `eip155:${options.chainId}` || "eip155:5042002";
@@ -110,11 +131,11 @@ var Nibgate = (() => {
110
131
  }
111
132
  };
112
133
  }
113
- var runtimeImport;
134
+ var cachedCircleModule;
114
135
  var init_gateway = __esm({
115
136
  "src/browser/gateway.js"() {
116
137
  init_json();
117
- runtimeImport = new Function("specifier", "return import(specifier)");
138
+ cachedCircleModule = null;
118
139
  }
119
140
  });
120
141
 
@@ -233,6 +254,33 @@ var Nibgate = (() => {
233
254
  function autoDeriveImage() {
234
255
  return metaContent("og:image") || void 0;
235
256
  }
257
+ function autoDeriveDescription() {
258
+ return metaContent("og:description") || metaContent("description") || void 0;
259
+ }
260
+ function autoDeriveTitle() {
261
+ const win = browserEnv();
262
+ return metaContent("og:title") || metaContent("twitter:title") || (win ? win.document.title : "") || void 0;
263
+ }
264
+ function autoDeriveType() {
265
+ const ogType = metaContent("og:type").toLowerCase();
266
+ if (ogType.includes("music") || ogType.includes("audio") || ogType.includes("song")) return "music";
267
+ if (ogType.includes("video") || ogType.includes("movie")) return "video";
268
+ if (ogType.includes("image") || ogType.includes("photo")) return "image";
269
+ return "article";
270
+ }
271
+ function autoDeriveTags() {
272
+ const kw = metaContent("keywords");
273
+ if (!kw) return void 0;
274
+ return kw.split(",").map((t) => t.trim().toLowerCase()).filter(Boolean).slice(0, 8);
275
+ }
276
+ function accessForPrice(price, explicitAccess) {
277
+ if (explicitAccess && typeof explicitAccess === "object" && Object.keys(explicitAccess).length > 0) {
278
+ return normalizeAccessPolicy(explicitAccess);
279
+ }
280
+ const hasPrice = price !== void 0 && price !== null && price !== "" && Number.parseFloat(price) > 0;
281
+ if (hasPrice) return { humans: "paid", agents: "paid" };
282
+ return { humans: "free", agents: "free" };
283
+ }
236
284
  function normalizeResource(resource = {}) {
237
285
  const input = typeof resource === "string" ? { id: resource } : resource || {};
238
286
  const {
@@ -249,20 +297,24 @@ var Nibgate = (() => {
249
297
  } = input;
250
298
  const path = input.path || input.route || void 0;
251
299
  const url = input.url || autoDeriveUrl(path) || void 0;
300
+ const explicitAccess = input.access;
301
+ const price = input.price ?? input.amount ?? "";
252
302
  return {
253
303
  ...v1Input,
254
304
  id: String(input.id || input.contentId || input.slug || "").trim(),
255
- title: String(input.title || input.name || "").trim(),
256
- type: normalizeContentType(input.type || input.contentType),
257
- price: input.price ?? input.amount ?? "",
305
+ title: String(input.title || input.name || autoDeriveTitle() || "Untitled").trim(),
306
+ type: normalizeContentType(input.type || input.contentType || autoDeriveType()),
307
+ price,
308
+ currency: input.currency || "USDC",
258
309
  paymentRail: normalizePaymentRail(input.paymentRail || input.paymentMode || input.rail),
259
310
  recipient: input.recipient || input.receiver || input.receiverAddress || input.payTo || input.creatorWallet || void 0,
260
311
  payTo: input.payTo || input.recipient || input.receiver || input.receiverAddress || input.creatorWallet || void 0,
261
312
  path,
262
313
  url,
263
314
  imageUrl: input.imageUrl || input.image || autoDeriveImage() || void 0,
264
- tags: input.tags || void 0,
265
- access: normalizeAccessPolicy(input.access),
315
+ description: input.description || input.summary || autoDeriveDescription() || void 0,
316
+ tags: input.tags || autoDeriveTags() || void 0,
317
+ access: accessForPrice(price, explicitAccess),
266
318
  unlock: normalizeUnlockPolicy(input.unlock),
267
319
  ratingsEnabled: input.ratingsEnabled ?? input.enableRatings ?? input.reputation?.ratingsEnabled ?? true,
268
320
  reputation: {
@@ -283,8 +335,8 @@ var Nibgate = (() => {
283
335
  const normalized = normalizeResource(resource);
284
336
  const warnings = [];
285
337
  const errors = [];
286
- const required = options.required || ["id", "title", "url", "type"];
287
- const recommended = options.recommended || ["description", "imageUrl", "tags"];
338
+ const required = options.required || ["id", "type"];
339
+ const recommended = options.recommended || ["title", "url", "description", "imageUrl", "tags"];
288
340
  for (const field of required) {
289
341
  if (!hasValue(normalized[field])) errors.push(`Missing required content metadata: ${field}`);
290
342
  }
@@ -751,6 +803,7 @@ var Nibgate = (() => {
751
803
  const gateway = await Promise.resolve().then(() => (init_gateway(), gateway_exports));
752
804
  return gateway.createCircleGatewayBrowserAdapter(options);
753
805
  }
806
+ var DEFAULT_CIRCLE_CDN = "https://esm.sh/@circle-fin/x402-batching@3.2.0/client?bundle";
754
807
  function createEvmGatewayUnlock(resource, options = {}) {
755
808
  const item = createGate(resource, options.gateOptions || {});
756
809
  const win = browserWindow();
@@ -845,7 +898,7 @@ var Nibgate = (() => {
845
898
  signTypedData: (typedData) => evm.request({ method: "eth_signTypedData_v4", params: [walletAddress, stringifyJson(typedData)] })
846
899
  },
847
900
  clientModule: options.circleClientModule,
848
- clientModuleUrl: options.circleClientModuleUrl
901
+ clientModuleUrl: options.circleClientModuleUrl || DEFAULT_CIRCLE_CDN
849
902
  });
850
903
  return gatewayWallet.pay(input);
851
904
  }