@nibgate/sdk 0.1.8 → 0.2.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.
@@ -0,0 +1,1339 @@
1
+ var Nibgate = (() => {
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __esm = (fn, res) => function __init() {
7
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
8
+ };
9
+ var __export = (target, all) => {
10
+ for (var name in all)
11
+ __defProp(target, name, { get: all[name], enumerable: true });
12
+ };
13
+ var __copyProps = (to, from, except, desc) => {
14
+ if (from && typeof from === "object" || typeof from === "function") {
15
+ for (let key of __getOwnPropNames(from))
16
+ if (!__hasOwnProp.call(to, key) && key !== except)
17
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
18
+ }
19
+ return to;
20
+ };
21
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
22
+
23
+ // src/browser/json.js
24
+ function jsonReplacer(_key, value) {
25
+ if (typeof value === "bigint") return value.toString();
26
+ return value;
27
+ }
28
+ function stringifyJson(value) {
29
+ return JSON.stringify(value, jsonReplacer);
30
+ }
31
+ var init_json = __esm({
32
+ "src/browser/json.js"() {
33
+ }
34
+ });
35
+
36
+ // src/browser/gateway.js
37
+ var gateway_exports = {};
38
+ __export(gateway_exports, {
39
+ createCircleGatewayBrowserAdapter: () => createCircleGatewayBrowserAdapter
40
+ });
41
+ function encodeBase64(value) {
42
+ const text = typeof value === "string" ? value : stringifyJson(value);
43
+ if (typeof Buffer !== "undefined") return Buffer.from(text).toString("base64");
44
+ return btoa(unescape(encodeURIComponent(text)));
45
+ }
46
+ function decodeBase64(value) {
47
+ if (typeof Buffer !== "undefined") return Buffer.from(value, "base64").toString("utf8");
48
+ return decodeURIComponent(escape(atob(value)));
49
+ }
50
+ async function createCircleGatewayBrowserAdapter(options = {}) {
51
+ const signer = options.signer || await options.getSigner?.();
52
+ if (!signer?.address || typeof signer.signTypedData !== "function") {
53
+ throw new Error("Circle Gateway browser adapter requires an EVM signer with address and signTypedData.");
54
+ }
55
+ const circleClientModule = options.clientModule || (options.clientModuleUrl ? await runtimeImport(options.clientModuleUrl) : await runtimeImport("@circle-fin/x402-batching/client"));
56
+ const { BatchEvmScheme } = circleClientModule;
57
+ const scheme = new BatchEvmScheme(signer);
58
+ const network = options.network || options.chainId && `eip155:${options.chainId}` || "eip155:5042002";
59
+ function parsePaymentRequired(input) {
60
+ if (input && typeof input === "object") return input;
61
+ if (!input || typeof input !== "string") throw new Error("Missing PAYMENT-REQUIRED header.");
62
+ return JSON.parse(decodeBase64(input));
63
+ }
64
+ function selectGatewayRequirement(paymentRequired) {
65
+ const accepts = Array.isArray(paymentRequired?.accepts) ? paymentRequired.accepts : [];
66
+ const selected = accepts.find((option) => {
67
+ const extra = option.extra || {};
68
+ return option.network === network && extra.name === "GatewayWalletBatched" && extra.version === "1" && typeof extra.verifyingContract === "string";
69
+ }) || accepts.find((option) => {
70
+ const extra = option.extra || {};
71
+ return extra.name === "GatewayWalletBatched" && extra.version === "1" && typeof extra.verifyingContract === "string";
72
+ });
73
+ if (!selected) {
74
+ const networks = accepts.map((option) => option.network).filter(Boolean).join(", ") || "none";
75
+ const hasGatewayExtra = accepts.some((option) => {
76
+ const extra = option.extra || {};
77
+ return extra.name === "GatewayWalletBatched" && extra.version === "1" && typeof extra.verifyingContract === "string";
78
+ });
79
+ throw new Error(
80
+ hasGatewayExtra ? `No Circle Gateway batching payment option found for ${network}. Server returned networks: ${networks}.` : `The payment challenge is not a Circle Gateway batching challenge. Configure the creator access route with createCircleGatewayServer(...) or createNibgateServer({ paymentMode: 'circle-gateway', network: '${network}' }).`
81
+ );
82
+ }
83
+ return selected;
84
+ }
85
+ return {
86
+ signer,
87
+ network,
88
+ async pay({ paymentRequiredHeader, challenge }) {
89
+ const paymentRequired = parsePaymentRequired(paymentRequiredHeader || challenge);
90
+ const accepted = selectGatewayRequirement(paymentRequired);
91
+ const x402Version = paymentRequired.x402Version ?? 2;
92
+ const paymentPayload = await scheme.createPaymentPayload(x402Version, accepted);
93
+ const paymentSignature = encodeBase64({
94
+ ...paymentPayload,
95
+ resource: paymentRequired.resource,
96
+ accepted
97
+ });
98
+ return {
99
+ paymentSignature,
100
+ signature: paymentSignature,
101
+ metadata: {
102
+ paymentProvider: "circle-gateway",
103
+ network: accepted.network,
104
+ payer: signer.address,
105
+ recipient: accepted.payTo || accepted.recipient,
106
+ amount: accepted.amount,
107
+ currency: accepted.asset
108
+ }
109
+ };
110
+ }
111
+ };
112
+ }
113
+ var runtimeImport;
114
+ var init_gateway = __esm({
115
+ "src/browser/gateway.js"() {
116
+ init_json();
117
+ runtimeImport = new Function("specifier", "return import(specifier)");
118
+ }
119
+ });
120
+
121
+ // src/browser/index.js
122
+ var index_exports = {};
123
+ __export(index_exports, {
124
+ ACCESS_MODES: () => ACCESS_MODES,
125
+ CONTENT_TYPES: () => CONTENT_TYPES,
126
+ NIBGATE_CONTENT_HASH_NAMESPACE: () => NIBGATE_CONTENT_HASH_NAMESPACE,
127
+ NIBGATE_CONTENT_SETTING_FIELDS: () => NIBGATE_CONTENT_SETTING_FIELDS,
128
+ NIBGATE_REPUTATION_ABI: () => NIBGATE_REPUTATION_ABI,
129
+ NIBGATE_REPUTATION_CHAIN_ID: () => NIBGATE_REPUTATION_CHAIN_ID,
130
+ NIBGATE_REPUTATION_CHAIN_NAME: () => NIBGATE_REPUTATION_CHAIN_NAME,
131
+ NIBGATE_REPUTATION_CONTRACT: () => NIBGATE_REPUTATION_CONTRACT,
132
+ NIBGATE_REPUTATION_RPC_URL: () => NIBGATE_REPUTATION_RPC_URL,
133
+ PAYMENT_RAILS: () => PAYMENT_RAILS,
134
+ UNLOCK_MODES: () => UNLOCK_MODES,
135
+ checkResourceAccess: () => checkResourceAccess,
136
+ contentRatingHash: () => contentRatingHash,
137
+ createCircleGatewayBrowserAdapter: () => createCircleGatewayBrowserAdapter2,
138
+ createEvmGatewayUnlock: () => createEvmGatewayUnlock,
139
+ createGate: () => createGate,
140
+ createNibgate: () => createNibgate,
141
+ createNibgateContentSettings: () => createNibgateContentSettings,
142
+ createOnchainRating: () => createOnchainRating,
143
+ createTransferCheckout: () => createTransferCheckout,
144
+ createWalletCheckout: () => createWalletCheckout,
145
+ gate: () => gate,
146
+ mountRatingUI: () => mountRatingUI,
147
+ nibgate: () => nibgate,
148
+ normalizeAccessPolicy: () => normalizeAccessPolicy,
149
+ normalizeContentType: () => normalizeContentType,
150
+ normalizePaymentRail: () => normalizePaymentRail,
151
+ normalizeResource: () => normalizeResource,
152
+ normalizeUnlockPolicy: () => normalizeUnlockPolicy,
153
+ payAndUnlockResource: () => payAndUnlockResource,
154
+ payWithPaymentSignature: () => payWithPaymentSignature,
155
+ payWithTransfer: () => payWithTransfer,
156
+ rateContentOnchain: () => rateContentOnchain,
157
+ rateResource: () => rateResource,
158
+ reviewTextHash: () => reviewTextHash,
159
+ settingsToAccessPolicy: () => settingsToAccessPolicy,
160
+ settingsToUnlockPolicy: () => settingsToUnlockPolicy,
161
+ setupResourcePage: () => setupResourcePage,
162
+ trackResourcePage: () => trackResourcePage,
163
+ validateResourceMetadata: () => validateResourceMetadata
164
+ });
165
+
166
+ // src/core/payment.js
167
+ var PAYMENT_RAILS = ["gateway", "transfer"];
168
+ function normalizePaymentRail(value, fallback = "gateway") {
169
+ const rail = String(value || "").trim().toLowerCase().replace(/[-\s]+/g, "_");
170
+ if (rail === "circle_gateway" || rail === "x402") return "gateway";
171
+ if (rail === "direct_transfer" || rail === "wallet_transfer") return "transfer";
172
+ return PAYMENT_RAILS.includes(rail) ? rail : fallback;
173
+ }
174
+
175
+ // src/core/resource.js
176
+ var CONTENT_TYPES = ["music", "video", "article", "image"];
177
+ var TYPE_ALIASES = {
178
+ audio: "music",
179
+ song: "music",
180
+ track: "music",
181
+ album: "music",
182
+ playlist: "music",
183
+ photo: "image",
184
+ picture: "image",
185
+ illustration: "image",
186
+ art: "image",
187
+ movie: "video",
188
+ clip: "video"
189
+ };
190
+ var ACCESS_MODES = ["free", "paid", "blocked"];
191
+ var UNLOCK_MODES = ["one_time", "metered_stream", "metered_read", "time_pass", "agent_quota"];
192
+ function normalizeContentType(value) {
193
+ const type = String(value || "").trim().toLowerCase();
194
+ if (CONTENT_TYPES.includes(type)) return type;
195
+ return TYPE_ALIASES[type] || "article";
196
+ }
197
+ function normalizeAccessMode(value, fallback = "paid") {
198
+ const mode = String(value || "").trim().toLowerCase();
199
+ return ACCESS_MODES.includes(mode) ? mode : fallback;
200
+ }
201
+ function normalizeAccessPolicy(value = {}) {
202
+ if (typeof value === "string") {
203
+ const mode = normalizeAccessMode(value);
204
+ return { humans: mode, agents: mode };
205
+ }
206
+ return {
207
+ humans: normalizeAccessMode(value.humans || value.human || value.default, "paid"),
208
+ agents: normalizeAccessMode(value.agents || value.agent || value.default, "paid")
209
+ };
210
+ }
211
+ function normalizeUnlockPolicy(value = {}) {
212
+ const input = typeof value === "string" ? { mode: value } : value || {};
213
+ const mode = String(input.mode || input.type || "one_time").trim().toLowerCase().replace(/[-\s]+/g, "_");
214
+ return {
215
+ ...input,
216
+ mode: UNLOCK_MODES.includes(mode) ? mode : "one_time"
217
+ };
218
+ }
219
+ function normalizeResource(resource = {}) {
220
+ const input = typeof resource === "string" ? { id: resource } : resource || {};
221
+ const {
222
+ publisher,
223
+ publisherId,
224
+ publisherWallet,
225
+ publisherHandle,
226
+ publisherName,
227
+ publisherProfileUrl,
228
+ publisherOrigin,
229
+ publisherVerification,
230
+ authorHandle,
231
+ ...v1Input
232
+ } = input;
233
+ return {
234
+ ...v1Input,
235
+ id: String(input.id || input.contentId || input.slug || "").trim(),
236
+ title: String(input.title || input.name || "").trim(),
237
+ type: normalizeContentType(input.type || input.contentType),
238
+ price: input.price ?? input.amount ?? "",
239
+ paymentRail: normalizePaymentRail(input.paymentRail || input.paymentMode || input.rail),
240
+ recipient: input.recipient || input.receiver || input.receiverAddress || input.payTo || input.creatorWallet || void 0,
241
+ payTo: input.payTo || input.recipient || input.receiver || input.receiverAddress || input.creatorWallet || void 0,
242
+ path: input.path || input.route || void 0,
243
+ url: input.url || void 0,
244
+ imageUrl: input.imageUrl || input.image || void 0,
245
+ tags: input.tags || void 0,
246
+ access: normalizeAccessPolicy(input.access),
247
+ unlock: normalizeUnlockPolicy(input.unlock),
248
+ ratingsEnabled: input.ratingsEnabled ?? input.enableRatings ?? input.reputation?.ratingsEnabled ?? true,
249
+ reputation: {
250
+ ...typeof input.reputation === "object" && input.reputation ? input.reputation : {},
251
+ ratingsEnabled: input.ratingsEnabled ?? input.enableRatings ?? input.reputation?.ratingsEnabled ?? true
252
+ }
253
+ };
254
+ }
255
+ function hasValue(value) {
256
+ if (Array.isArray(value)) return value.length > 0;
257
+ return value !== void 0 && value !== null && String(value).trim() !== "";
258
+ }
259
+ function isPaidResource(resource = {}) {
260
+ const access = normalizeAccessPolicy(resource.access);
261
+ return access.humans === "paid" || access.agents === "paid" || Number.parseFloat(resource.price || resource.amount || "0") > 0;
262
+ }
263
+ function validateResourceMetadata(resource = {}, options = {}) {
264
+ const normalized = normalizeResource(resource);
265
+ const warnings = [];
266
+ const errors = [];
267
+ const required = options.required || ["id", "title", "url", "type"];
268
+ const recommended = options.recommended || ["description", "imageUrl", "tags"];
269
+ for (const field of required) {
270
+ if (!hasValue(normalized[field])) errors.push(`Missing required content metadata: ${field}`);
271
+ }
272
+ for (const field of recommended) {
273
+ if (!hasValue(normalized[field])) warnings.push(`Missing recommended discovery metadata: ${field}`);
274
+ }
275
+ if (!CONTENT_TYPES.includes(normalized.type)) errors.push("Content type must be one of music, video, article, or image.");
276
+ if (normalized.url && !/^https?:\/\//i.test(String(normalized.url))) {
277
+ warnings.push("Use an absolute canonical url for stronger discovery identity.");
278
+ }
279
+ if (normalized.imageUrl && !/^https?:\/\//i.test(String(normalized.imageUrl))) {
280
+ warnings.push("Use an absolute imageUrl for thumbnails in Explore and agent discovery.");
281
+ }
282
+ if (isPaidResource(normalized)) {
283
+ if (!hasValue(normalized.price)) errors.push("Paid content requires price.");
284
+ if (!hasValue(normalized.recipient || normalized.payTo)) errors.push("Paid content requires recipient/payTo wallet.");
285
+ }
286
+ const score = Math.max(0, 100 - errors.length * 20 - warnings.length * 8);
287
+ return {
288
+ ok: errors.length === 0,
289
+ score,
290
+ errors,
291
+ warnings,
292
+ resource: normalized
293
+ };
294
+ }
295
+
296
+ // src/core/rating.js
297
+ function normalizeRating(input = {}) {
298
+ const value = typeof input === "number" ? input : input.rating ?? input.stars ?? input.ratingValue ?? input.score;
299
+ const numeric = Number.parseFloat(value);
300
+ const ratingValue = Number.isFinite(numeric) ? Math.max(1, Math.min(50, numeric <= 5 ? Math.round(numeric * 10) : Math.round(numeric))) : null;
301
+ return {
302
+ ...input,
303
+ rating: ratingValue ? ratingValue / 10 : void 0,
304
+ ratingValue: ratingValue || void 0
305
+ };
306
+ }
307
+ function ratingMessage(resource, rating = {}, options = {}) {
308
+ const normalized = normalizeResource(resource);
309
+ const normalizedRating = normalizeRating(rating);
310
+ const value = normalizedRating.ratingValue || 0;
311
+ return [
312
+ "Nibgate content rating",
313
+ `site:${options.siteDomain || options.domain || normalized.siteDomain || normalized.domain || ""}`,
314
+ `content:${normalized.externalId || normalized.id}`,
315
+ `url:${normalized.url || options.url || ""}`,
316
+ `rating:${value}`,
317
+ "I confirm this rating is tied to my unlock/payment proof."
318
+ ].join("\n");
319
+ }
320
+
321
+ // src/browser/env.js
322
+ function browserWindow() {
323
+ return typeof window === "undefined" ? null : window;
324
+ }
325
+
326
+ // src/browser/events.js
327
+ function queueEvent(eventName, payload) {
328
+ const win = browserWindow();
329
+ if (!win) return false;
330
+ win.__nibgateClientQueue = win.__nibgateClientQueue || [];
331
+ win.__nibgateClientQueue.push({ eventName, payload });
332
+ return true;
333
+ }
334
+ function flushQueue() {
335
+ const win = browserWindow();
336
+ if (!win?.nibgateHub?.track || !Array.isArray(win.__nibgateClientQueue)) return false;
337
+ const queue = win.__nibgateClientQueue.splice(0);
338
+ queue.forEach((entry) => {
339
+ win.nibgateHub.track(entry.eventName, entry.payload);
340
+ });
341
+ return queue.length > 0;
342
+ }
343
+ function startQueueFlush() {
344
+ const win = browserWindow();
345
+ if (!win || win.__nibgateClientFlushStarted) return;
346
+ win.__nibgateClientFlushStarted = true;
347
+ let attempts = 0;
348
+ const timer = win.setInterval(() => {
349
+ attempts += 1;
350
+ flushQueue();
351
+ if (win.nibgateHub?.track || attempts >= 80) {
352
+ win.clearInterval(timer);
353
+ win.__nibgateClientFlushStarted = false;
354
+ }
355
+ }, 250);
356
+ }
357
+ function emit(eventName, payload = {}) {
358
+ const win = browserWindow();
359
+ if (!win) return false;
360
+ if (win.nibgateHub?.track) {
361
+ win.nibgateHub.track(eventName, payload);
362
+ flushQueue();
363
+ return true;
364
+ }
365
+ queueEvent(eventName, payload);
366
+ startQueueFlush();
367
+ return false;
368
+ }
369
+ function payloadWithResource(resource, extra = {}) {
370
+ return {
371
+ ...extra,
372
+ resource: normalizeResource(resource)
373
+ };
374
+ }
375
+
376
+ // src/browser/storage.js
377
+ function unlockStorageKey(resource) {
378
+ return `nibgate:unlock:${resource.id || resource.path || resource.url || "content"}`;
379
+ }
380
+ function proofStorageKey(resource) {
381
+ return `nibgate:payment-proof:${resource.id || resource.path || resource.url || "content"}`;
382
+ }
383
+ function markUnlocked(resource, payment = {}) {
384
+ const win = browserWindow();
385
+ if (!win) return false;
386
+ try {
387
+ win.localStorage.setItem(unlockStorageKey(resource), JSON.stringify({
388
+ unlockedAt: (/* @__PURE__ */ new Date()).toISOString(),
389
+ payment
390
+ }));
391
+ return true;
392
+ } catch (_error) {
393
+ return false;
394
+ }
395
+ }
396
+ function storePaymentProof(resource, proof) {
397
+ const win = browserWindow();
398
+ if (!win || !proof) return false;
399
+ try {
400
+ const value = typeof proof === "string" ? proof : JSON.stringify(proof);
401
+ win.localStorage.setItem(proofStorageKey(resource), value);
402
+ return true;
403
+ } catch (_error) {
404
+ return false;
405
+ }
406
+ }
407
+ function getPaymentProof(resource) {
408
+ const win = browserWindow();
409
+ if (!win) return "";
410
+ try {
411
+ return win.localStorage.getItem(proofStorageKey(resource)) || "";
412
+ } catch (_error) {
413
+ return "";
414
+ }
415
+ }
416
+ function clearPaymentProof(resource) {
417
+ const normalized = normalizeResource(resource);
418
+ const win = browserWindow();
419
+ if (!win) return false;
420
+ try {
421
+ win.localStorage.removeItem(proofStorageKey(normalized));
422
+ win.localStorage.removeItem(unlockStorageKey(normalized));
423
+ return true;
424
+ } catch (_error) {
425
+ return false;
426
+ }
427
+ }
428
+ function hasUnlock(resource) {
429
+ const win = browserWindow();
430
+ if (!win) return false;
431
+ try {
432
+ return Boolean(win.localStorage.getItem(unlockStorageKey(resource)));
433
+ } catch (_error) {
434
+ return false;
435
+ }
436
+ }
437
+
438
+ // src/browser/index.js
439
+ init_json();
440
+
441
+ // src/browser/reputation.js
442
+ var RATE_CONTENT_SELECTOR = "0xc62fad09";
443
+ var ZERO_HASH = `0x${"0".repeat(64)}`;
444
+ var NIBGATE_CONTENT_HASH_NAMESPACE = "nibgate:content:v1";
445
+ var NIBGATE_REPUTATION_CHAIN_ID = 5042002;
446
+ var NIBGATE_REPUTATION_CHAIN_NAME = "Arc Testnet";
447
+ var NIBGATE_REPUTATION_RPC_URL = "https://rpc.testnet.arc.network";
448
+ var NIBGATE_REPUTATION_CONTRACT = "0x9f27fd62e75f86a3c7addfdba443aab1f930e281";
449
+ var NIBGATE_REPUTATION_ABI = [
450
+ {
451
+ type: "function",
452
+ name: "rateContent",
453
+ stateMutability: "nonpayable",
454
+ inputs: [
455
+ { name: "contentId", type: "bytes32" },
456
+ { name: "rating", type: "uint8" },
457
+ { name: "reviewHash", type: "bytes32" },
458
+ { name: "unlockRef", type: "string" }
459
+ ],
460
+ outputs: []
461
+ }
462
+ ];
463
+ function stripHex(value = "") {
464
+ return String(value || "").replace(/^0x/i, "").toLowerCase();
465
+ }
466
+ function wordRight(hex = "") {
467
+ const clean = stripHex(hex);
468
+ if (clean.length > 64) throw new Error("ABI word is too long.");
469
+ return clean.padEnd(64, "0");
470
+ }
471
+ function numberWord(value = 0) {
472
+ return Number(value || 0).toString(16).padStart(64, "0");
473
+ }
474
+ function utf8Hex(value = "") {
475
+ return Array.from(new TextEncoder().encode(String(value || ""))).map((byte) => byte.toString(16).padStart(2, "0")).join("");
476
+ }
477
+ function encodeString(value = "") {
478
+ const hex = utf8Hex(value);
479
+ const byteLength = hex.length / 2;
480
+ const paddedLength = Math.ceil(byteLength / 32) * 64;
481
+ return numberWord(byteLength) + hex.padEnd(paddedLength, "0");
482
+ }
483
+ function encodeRateContent({ contentId, ratingValue, reviewHash, unlockRef }) {
484
+ return RATE_CONTENT_SELECTOR + wordRight(contentId) + numberWord(ratingValue) + wordRight(reviewHash || ZERO_HASH) + numberWord(128) + encodeString(unlockRef || "");
485
+ }
486
+ function contentRatingHash(_resource, options = {}) {
487
+ const contentId = options.contentId || options.contentHash;
488
+ if (!contentId) {
489
+ throw new Error("contentId/contentHash is required. Use the Nibgate backend prepare endpoint or pass a known content hash.");
490
+ }
491
+ return contentId;
492
+ }
493
+ function reviewTextHash(review = "") {
494
+ if (!review) return ZERO_HASH;
495
+ throw new Error("Text review hashing is not available in direct-browser mode. Pass reviewHash from your app/backend.");
496
+ }
497
+ async function prepareOnchainRating(resource, options = {}) {
498
+ if (options.contentId || options.contentHash) return { contentId: options.contentId || options.contentHash };
499
+ const prepareUrl = options.prepareUrl || options.indexUrl?.replace(/\/index$/, "/prepare");
500
+ if (!prepareUrl) throw new Error("contentId/contentHash or prepareUrl is required for onchain rating.");
501
+ const response = await fetch(prepareUrl, {
502
+ method: "POST",
503
+ headers: { "content-type": "application/json", ...options.indexHeaders || {} },
504
+ body: JSON.stringify({
505
+ siteId: options.siteId,
506
+ token: options.token,
507
+ resource,
508
+ url: resource.url,
509
+ path: resource.path
510
+ })
511
+ });
512
+ const payload = await response.json().catch(() => ({}));
513
+ if (!response.ok || !payload.contentHash) throw new Error(payload.error || "Could not prepare Nibgate onchain rating.");
514
+ return payload;
515
+ }
516
+ async function rateContentOnchain(resource, options = {}) {
517
+ const normalized = normalizeResource(resource);
518
+ const rating = normalizeRating(options.rating ?? options.stars ?? options);
519
+ if (!rating.ratingValue) throw new Error("Rating must be between 0.1 and 5 stars.");
520
+ const provider = options.provider || globalThis?.ethereum;
521
+ if (!provider?.request) throw new Error("Connect an EVM wallet to rate this content onchain.");
522
+ const contractAddress = options.contractAddress || options.reputationContract || NIBGATE_REPUTATION_CONTRACT;
523
+ if (!contractAddress) throw new Error("Nibgate reputation contract address is not configured.");
524
+ const accounts = await provider.request({ method: "eth_requestAccounts" });
525
+ const walletAddress = Array.isArray(accounts) ? accounts[0] || "" : "";
526
+ if (!walletAddress) throw new Error("No wallet account selected.");
527
+ const prepared = await prepareOnchainRating(normalized, options);
528
+ const contentId = prepared.contentHash || prepared.contentId || contentRatingHash(normalized, options);
529
+ const reviewHash = options.reviewHash || ZERO_HASH;
530
+ const unlockRef = String(options.unlockRef || options.paymentId || options.txHash || "");
531
+ const data = encodeRateContent({ contentId, ratingValue: rating.ratingValue, reviewHash, unlockRef });
532
+ const txHash = await provider.request({
533
+ method: "eth_sendTransaction",
534
+ params: [{
535
+ from: walletAddress,
536
+ to: contractAddress,
537
+ data
538
+ }]
539
+ });
540
+ const payload = payloadWithResource(normalized, {
541
+ rating: rating.rating,
542
+ ratingValue: rating.ratingValue,
543
+ walletAddress,
544
+ txHash,
545
+ contentHash: contentId,
546
+ reviewHash,
547
+ proofType: "onchain_pending",
548
+ proof: unlockRef,
549
+ paymentId: options.paymentId,
550
+ actor: options.actor || "human"
551
+ });
552
+ emit("content_rating", payload);
553
+ if (options.indexUrl) {
554
+ await fetch(options.indexUrl, {
555
+ method: "POST",
556
+ headers: { "content-type": "application/json", ...options.indexHeaders || {} },
557
+ body: JSON.stringify({
558
+ siteId: options.siteId,
559
+ token: options.token,
560
+ txHash,
561
+ resource: normalized,
562
+ url: normalized.url,
563
+ path: normalized.path,
564
+ actor: options.actor || "human"
565
+ })
566
+ }).catch(() => null);
567
+ }
568
+ return { txHash, walletAddress, contentId, ratingValue: rating.ratingValue, reviewHash };
569
+ }
570
+
571
+ // src/browser/transfer.js
572
+ function createTransferCheckout(resource, options = {}) {
573
+ const normalized = normalizeResource({ ...resource, paymentRail: "transfer" });
574
+ const sendTransfer = options.sendTransfer || options.transfer;
575
+ if (typeof sendTransfer !== "function") {
576
+ throw new Error("createTransferCheckout requires sendTransfer({ resource, recipient, amount, currency, network }) and a server verifyTransfer hook.");
577
+ }
578
+ return {
579
+ resource: normalized,
580
+ async pay(input = {}) {
581
+ const recipient = normalized.recipient || normalized.payTo;
582
+ const amount = String(normalized.price || normalized.amount || "0");
583
+ const currency = normalized.currency || "USDC";
584
+ const network = options.network || input.challenge?.accepts?.[0]?.network || "eip155:5042002";
585
+ const result = await sendTransfer({ resource: normalized, recipient, amount, currency, network, challenge: input.challenge });
586
+ const txHash = result?.txHash || result?.hash || result?.transactionHash || result?.paymentId || "";
587
+ if (!txHash) throw new Error("Transfer checkout did not return a txHash.");
588
+ return {
589
+ paymentSignature: txHash,
590
+ signature: txHash,
591
+ memo: result.memo || "",
592
+ metadata: {
593
+ paymentProvider: "direct-transfer",
594
+ paymentId: txHash,
595
+ txHash,
596
+ recipient,
597
+ amount: Number(amount),
598
+ currency,
599
+ network,
600
+ ...result.metadata || result
601
+ }
602
+ };
603
+ }
604
+ };
605
+ }
606
+ async function payWithTransfer(resource, options = {}) {
607
+ const checkout = options.checkout || createTransferCheckout(resource, options).pay;
608
+ const result = await checkout({ resource: normalizeResource(resource), challenge: options.challenge || null });
609
+ const txHash = result?.metadata?.txHash || result?.txHash || result?.paymentSignature || result?.signature || "";
610
+ if (!txHash) throw new Error("Transfer checkout did not return a txHash.");
611
+ return checkResourceAccess(resource, {
612
+ ...options,
613
+ headers: {
614
+ ...options.headers || {},
615
+ "x-nibgate-transfer-tx": txHash
616
+ },
617
+ payment: result.metadata || { paymentProvider: "direct-transfer", txHash, paymentId: txHash }
618
+ });
619
+ }
620
+
621
+ // src/core/settings.js
622
+ var NIBGATE_CONTENT_SETTING_FIELDS = [
623
+ { name: "publishToNibgate", label: "Publish to Nibgate discovery", type: "boolean", defaultValue: true },
624
+ { name: "type", label: "Content type", type: "select", options: CONTENT_TYPES, defaultValue: "article" },
625
+ { name: "humanAccess", label: "Human access", type: "select", options: ACCESS_MODES, defaultValue: "paid" },
626
+ { name: "agentAccess", label: "Agent access", type: "select", options: ACCESS_MODES, defaultValue: "paid" },
627
+ { name: "unlockMode", label: "Unlock mode", type: "select", options: UNLOCK_MODES, defaultValue: "one_time" },
628
+ { name: "paymentRail", label: "Payment rail", type: "select", options: PAYMENT_RAILS, defaultValue: "gateway" },
629
+ { name: "price", label: "Price", type: "text", defaultValue: "0.005" },
630
+ { name: "currency", label: "Currency", type: "text", defaultValue: "USDC" },
631
+ { name: "recipient", label: "Recipient wallet", type: "wallet", defaultValue: "" },
632
+ { name: "ratingsEnabled", label: "Enable ratings", type: "boolean", defaultValue: true },
633
+ { name: "license", label: "License / terms", type: "textarea", defaultValue: "" }
634
+ ];
635
+ function createNibgateContentSettings(input = {}) {
636
+ const access = normalizeAccessPolicy(input.access || {
637
+ humans: input.humanAccess,
638
+ agents: input.agentAccess
639
+ });
640
+ const unlock = normalizeUnlockPolicy(input.unlock || input.unlockMode || "one_time");
641
+ return {
642
+ publishToNibgate: input.publishToNibgate ?? input.publishedToNibgate ?? true,
643
+ type: normalizeContentType(input.type || input.contentType || "article"),
644
+ humanAccess: access.humans,
645
+ agentAccess: access.agents,
646
+ unlockMode: unlock.mode,
647
+ paymentRail: normalizePaymentRail(input.paymentRail || input.paymentMode || input.rail),
648
+ price: String(input.price ?? input.amount ?? "0.005"),
649
+ currency: input.currency || "USDC",
650
+ recipient: input.recipient || input.payTo || input.receiverAddress || input.creatorWallet || "",
651
+ ratingsEnabled: input.ratingsEnabled ?? input.enableRatings ?? input.reputation?.ratingsEnabled ?? true,
652
+ license: input.license || input.terms || ""
653
+ };
654
+ }
655
+ function settingsToAccessPolicy(settings = {}) {
656
+ return normalizeAccessPolicy({
657
+ humans: settings.humanAccess,
658
+ agents: settings.agentAccess
659
+ });
660
+ }
661
+ function settingsToUnlockPolicy(settings = {}) {
662
+ return normalizeUnlockPolicy(settings.unlockMode || settings.unlock || "one_time");
663
+ }
664
+
665
+ // src/browser/index.js
666
+ async function createCircleGatewayBrowserAdapter2(options = {}) {
667
+ const gateway = await Promise.resolve().then(() => (init_gateway(), gateway_exports));
668
+ return gateway.createCircleGatewayBrowserAdapter(options);
669
+ }
670
+ function createGate(resource, options = {}) {
671
+ const normalized = normalizeResource(resource);
672
+ const client = options.client || nibgate;
673
+ return {
674
+ resource: normalized,
675
+ content(extra = {}) {
676
+ return client.content(normalized, extra);
677
+ },
678
+ view(extra = {}) {
679
+ return client.view(normalized, extra);
680
+ },
681
+ track(eventName, payload = {}) {
682
+ return client.track(eventName, payloadWithResource(normalized, payload));
683
+ },
684
+ unlockStarted(extra = {}) {
685
+ return client.unlockStarted(normalized, extra);
686
+ },
687
+ unlockCompleted(payment = {}) {
688
+ markUnlocked(normalized, payment);
689
+ return client.unlockCompleted(normalized, payment);
690
+ },
691
+ paymentCompleted(payment = {}) {
692
+ return client.paymentCompleted(normalized, payment);
693
+ },
694
+ isUnlocked() {
695
+ return hasUnlock(normalized);
696
+ },
697
+ markUnlocked(payment = {}) {
698
+ markUnlocked(normalized, payment);
699
+ client.unlockCompleted(normalized, payment);
700
+ client.paymentCompleted(normalized, payment);
701
+ return true;
702
+ },
703
+ async unlock(handlerOrPayment = {}) {
704
+ client.unlockStarted(normalized);
705
+ const payment = typeof handlerOrPayment === "function" ? await handlerOrPayment(normalized) : handlerOrPayment;
706
+ markUnlocked(normalized, payment || {});
707
+ client.unlockCompleted(normalized, payment || {});
708
+ client.paymentCompleted(normalized, payment || {});
709
+ return { unlocked: true, resource: normalized, payment: payment || {} };
710
+ },
711
+ rate(rating = {}, extra = {}) {
712
+ return client.rateResource(normalized, rating, extra);
713
+ }
714
+ };
715
+ }
716
+ function rateResource(resource, rating = {}, extra = {}) {
717
+ const normalized = normalizeResource(resource);
718
+ const normalizedRating = normalizeRating(rating);
719
+ const payload = {
720
+ ...extra,
721
+ ...normalizedRating,
722
+ ratingMessage: extra.ratingMessage || rating.message || rating.ratingMessage || ratingMessage(normalized, normalizedRating, extra),
723
+ ratingSignature: extra.ratingSignature || rating.signature || rating.ratingSignature || void 0,
724
+ resource: normalized
725
+ };
726
+ return emit("content_rating", payload);
727
+ }
728
+ function trackResourcePage(resource, options = {}) {
729
+ const item = createGate(resource, options.gateOptions || {});
730
+ const validation = validateResourceMetadata(item.resource, options.validation || {});
731
+ if ((validation.warnings.length || validation.errors.length) && options.warn !== false && browserWindow()?.console?.warn) {
732
+ browserWindow().console.warn("Nibgate content metadata needs attention", validation);
733
+ }
734
+ item.content({ source: options.source, metadataQuality: { score: validation.score, warnings: validation.warnings, errors: validation.errors }, ...options.content || {} });
735
+ item.view({
736
+ source: options.source,
737
+ path: options.path || browserWindow()?.location?.pathname || item.resource.path,
738
+ referrer: options.referrer ?? browserWindow()?.document?.referrer ?? "",
739
+ ...options.view || {}
740
+ });
741
+ return item;
742
+ }
743
+ async function checkResourceAccess(resource, options = {}) {
744
+ const item = createGate(resource, options.gateOptions || {});
745
+ const accessPath = options.accessPath || item.resource.accessPath || "/api/nibgate/access";
746
+ const status = typeof options.onStatus === "function" ? options.onStatus : () => {
747
+ };
748
+ status(options.checkingMessage || "Checking access route...");
749
+ item.unlockStarted({ source: options.source, paymentProvider: options.paymentProvider || "nibgate-access-route" });
750
+ const response = await fetch(accessPath, {
751
+ method: options.method || "GET",
752
+ headers: {
753
+ accept: "application/json",
754
+ ...getPaymentProof(item.resource) ? { "x-nibgate-payment-proof": getPaymentProof(item.resource) } : {},
755
+ ...options.headers || {}
756
+ },
757
+ body: options.body
758
+ });
759
+ const payload = await response.json().catch(() => ({}));
760
+ if (response.status === 402) {
761
+ item.track("payment_challenge_returned", { source: options.source, challenge: payload, resource: item.resource });
762
+ status(options.challengeMessage || "Payment challenge returned. Continue with checkout.");
763
+ if (typeof options.createPaymentSignature === "function" || typeof options.checkout === "function") {
764
+ const paymentResult = await payWithPaymentSignature(resource, {
765
+ ...options,
766
+ challenge: payload,
767
+ paymentRequiredHeader: response.headers.get("PAYMENT-REQUIRED") || response.headers.get("payment-required") || ""
768
+ });
769
+ return paymentResult;
770
+ }
771
+ if (options.autoPay && options.payPath) {
772
+ const paymentResult = await payAndUnlockResource(resource, options);
773
+ if (paymentResult.ok && options.retryAfterPay !== false) {
774
+ return checkResourceAccess(resource, { ...options, autoPay: false });
775
+ }
776
+ return paymentResult;
777
+ }
778
+ return { ok: false, status: response.status, challenge: payload, resource: item.resource, response };
779
+ }
780
+ if (!response.ok) {
781
+ status(payload.error || options.errorMessage || "Access check failed");
782
+ return { ok: false, status: response.status, error: payload.error || "Access check failed", payload, resource: item.resource, response };
783
+ }
784
+ const payment = options.payment || payload.payment || null;
785
+ if (payment) {
786
+ item.unlockCompleted(payment);
787
+ item.paymentCompleted(payment);
788
+ }
789
+ status(options.successMessage || "Access allowed and Nibgate events emitted.");
790
+ return { ok: true, status: response.status, payload, payment, resource: item.resource, response };
791
+ }
792
+ async function payWithPaymentSignature(resource, options = {}) {
793
+ const item = createGate(resource, options.gateOptions || {});
794
+ const accessPath = options.accessPath || item.resource.accessPath || "/api/nibgate/access";
795
+ const status = typeof options.onStatus === "function" ? options.onStatus : () => {
796
+ };
797
+ status(options.paymentMessage || "Waiting for wallet payment approval...");
798
+ item.unlockStarted({ source: options.source, paymentProvider: options.paymentProvider || "wallet-gateway" });
799
+ let paymentSignature = options.paymentSignature || "";
800
+ let paymentMemo = options.memo || "";
801
+ let paymentMetadata = options.payment || {};
802
+ if (!paymentSignature) {
803
+ const paymentRequiredHeader = options.paymentRequiredHeader || "";
804
+ const challenge = options.challenge || null;
805
+ const checkout = options.createPaymentSignature || options.checkout;
806
+ const result = await checkout({
807
+ resource: item.resource,
808
+ challenge,
809
+ paymentRequiredHeader,
810
+ accessPath
811
+ });
812
+ paymentSignature = result?.paymentSignature || result?.signature || result?.payment || "";
813
+ paymentMemo = result?.memo || result?.paymentMemo || "";
814
+ paymentMetadata = result?.metadata || result?.paymentMetadata || result || {};
815
+ }
816
+ if (!paymentSignature) {
817
+ const error = "Wallet did not return a payment signature.";
818
+ item.track("payment_failed", { source: options.source, error });
819
+ status(error);
820
+ return { ok: false, status: 400, error, resource: item.resource };
821
+ }
822
+ const response = await fetch(accessPath, {
823
+ method: options.method || "GET",
824
+ headers: {
825
+ accept: "application/json",
826
+ "payment-signature": paymentSignature,
827
+ ...paymentMemo ? { "payment-memo": paymentMemo } : {},
828
+ ...options.headers || {}
829
+ }
830
+ });
831
+ const responseText = await response.text();
832
+ let payload = {};
833
+ try {
834
+ payload = responseText ? JSON.parse(responseText) : {};
835
+ } catch (_error) {
836
+ payload = { error: responseText || "Payment verification failed" };
837
+ }
838
+ if (!response.ok) {
839
+ const detail = payload.detail || payload.reason || payload.invalidReason || payload.error || responseText || "Payment verification failed";
840
+ const error = typeof detail === "string" ? detail : stringifyJson(detail);
841
+ item.track("payment_failed", { source: options.source, status: response.status, error, ...paymentMetadata });
842
+ status(options.paymentErrorMessage || error);
843
+ return { ok: false, status: response.status, error, payload, resource: item.resource, response };
844
+ }
845
+ const payment = payload.payment || {
846
+ paymentProvider: options.paymentProvider || "wallet-gateway",
847
+ paymentId: paymentSignature,
848
+ memo: paymentMemo,
849
+ amount: Number(item.resource.price || 0),
850
+ revenue: Number(item.resource.price || 0),
851
+ currency: item.resource.currency || "USDC",
852
+ ...paymentMetadata
853
+ };
854
+ storePaymentProof(item.resource, payload.unlockProof);
855
+ item.markUnlocked(payment);
856
+ status(options.paymentSuccessMessage || "Payment verified. Content unlocked.");
857
+ return { ok: true, status: response.status, payload, payment, resource: item.resource, response };
858
+ }
859
+ function setElementText(target, message) {
860
+ const win = browserWindow();
861
+ if (!target || !win) return;
862
+ const element = typeof target === "string" ? win.document.querySelector(target) : target;
863
+ if (element) element.textContent = message || "";
864
+ }
865
+ function setElementDisabled(target, disabled) {
866
+ const win = browserWindow();
867
+ if (!target || !win) return;
868
+ const element = typeof target === "string" ? win.document.querySelector(target) : target;
869
+ if (element && "disabled" in element) element.disabled = Boolean(disabled);
870
+ }
871
+ function createWalletCheckout(resource, options = {}) {
872
+ const normalized = normalizeResource(resource);
873
+ const accessPath = options.accessPath || normalized.accessPath || "/api/nibgate/access";
874
+ const button = options.button || null;
875
+ const statusTarget = options.status || null;
876
+ const status = typeof options.onStatus === "function" ? options.onStatus : (message) => setElementText(statusTarget, message);
877
+ const checkout = options.checkout || options.createPaymentSignature || options.pay;
878
+ if (typeof checkout !== "function") {
879
+ throw new Error("createWalletCheckout requires checkout/createPaymentSignature/pay callback for the active wallet or Gateway adapter.");
880
+ }
881
+ async function unlock(extra = {}) {
882
+ setElementDisabled(button, true);
883
+ try {
884
+ return await checkResourceAccess(normalized, {
885
+ ...options,
886
+ ...extra,
887
+ accessPath,
888
+ createPaymentSignature: checkout,
889
+ onStatus: status
890
+ });
891
+ } finally {
892
+ setElementDisabled(button, false);
893
+ }
894
+ }
895
+ function mount() {
896
+ const win = browserWindow();
897
+ if (!win || !button) return { unlock };
898
+ const element = typeof button === "string" ? win.document.querySelector(button) : button;
899
+ if (element) element.addEventListener("click", () => unlock().catch((error) => status(error.message || "Checkout failed.")));
900
+ return { unlock };
901
+ }
902
+ return {
903
+ resource: normalized,
904
+ unlock,
905
+ mount
906
+ };
907
+ }
908
+ function createEvmGatewayUnlock(resource, options = {}) {
909
+ const item = createGate(resource, options.gateOptions || {});
910
+ const win = browserWindow();
911
+ const accessPath = options.accessPath || item.resource.accessPath || "/api/nibgate/access";
912
+ const source = options.source || "nibgate-evm-gateway";
913
+ const network = options.network || "eip155:5042002";
914
+ const statusTarget = typeof options.status === "string" ? win?.document.querySelector(options.status) : options.status;
915
+ const connectButton = typeof options.connectButton === "string" ? win?.document.querySelector(options.connectButton) : options.connectButton;
916
+ const disconnectButton = typeof options.disconnectButton === "string" ? win?.document.querySelector(options.disconnectButton) : options.disconnectButton;
917
+ const unlockButton = typeof options.unlockButton === "string" ? win?.document.querySelector(options.unlockButton) : options.unlockButton;
918
+ const clearButton = typeof options.clearButton === "string" ? win?.document.querySelector(options.clearButton) : options.clearButton;
919
+ const walletLabel = typeof options.walletLabel === "string" ? win?.document.querySelector(options.walletLabel) : options.walletLabel;
920
+ const unlockedTarget = typeof options.unlockedTarget === "string" ? win?.document.querySelector(options.unlockedTarget) : options.unlockedTarget;
921
+ let walletAddress = "";
922
+ let busy = false;
923
+ function setStatus(message) {
924
+ if (typeof options.onStatus === "function") options.onStatus(message);
925
+ if (statusTarget) statusTarget.textContent = message || "";
926
+ }
927
+ function shortAddress(address) {
928
+ return address ? `${address.slice(0, 6)}...${address.slice(-4)}` : "";
929
+ }
930
+ function provider() {
931
+ return win?.ethereum || options.provider || null;
932
+ }
933
+ function setBusy(value) {
934
+ busy = Boolean(value);
935
+ [connectButton, disconnectButton, unlockButton, clearButton].forEach((button) => {
936
+ if (button && "disabled" in button) {
937
+ button.disabled = busy || button === connectButton && !provider() || button === disconnectButton && !walletAddress;
938
+ }
939
+ });
940
+ }
941
+ function renderWallet() {
942
+ const hasProvider = Boolean(provider());
943
+ if (walletLabel) walletLabel.textContent = walletAddress ? shortAddress(walletAddress) : hasProvider ? "Ready to connect" : "No wallet detected";
944
+ if (connectButton) connectButton.textContent = walletAddress ? "Connected" : "Connect wallet";
945
+ if (disconnectButton) disconnectButton.textContent = "Disconnect";
946
+ if (connectButton && "disabled" in connectButton) connectButton.disabled = busy || !hasProvider;
947
+ if (disconnectButton && "disabled" in disconnectButton) disconnectButton.disabled = busy || !walletAddress;
948
+ }
949
+ function setUnlocked(isUnlocked, payment = {}) {
950
+ if (unlockButton) unlockButton.textContent = isUnlocked ? "Unlocked" : `Unlock for ${item.resource.price} ${item.resource.currency || "USDC"}`;
951
+ if (unlockedTarget) {
952
+ if ("hidden" in unlockedTarget) unlockedTarget.hidden = !isUnlocked;
953
+ unlockedTarget.setAttribute("aria-hidden", isUnlocked ? "false" : "true");
954
+ }
955
+ if (isUnlocked) item.markUnlocked(payment);
956
+ }
957
+ async function connect() {
958
+ setBusy(true);
959
+ setStatus("Opening wallet connection...");
960
+ try {
961
+ const evm = provider();
962
+ if (!evm) throw new Error(options.noWalletMessage || "Install or open an EVM wallet to continue.");
963
+ const accounts = await evm.request({ method: "eth_requestAccounts" });
964
+ walletAddress = Array.isArray(accounts) ? accounts[0] || "" : "";
965
+ if (!walletAddress) throw new Error("No wallet account selected.");
966
+ renderWallet();
967
+ setStatus("Wallet connected. You can unlock now.");
968
+ return walletAddress;
969
+ } finally {
970
+ setBusy(false);
971
+ }
972
+ }
973
+ async function disconnect() {
974
+ setBusy(true);
975
+ try {
976
+ const evm = provider();
977
+ if (evm?.request && walletAddress) {
978
+ try {
979
+ await evm.request({
980
+ method: "wallet_revokePermissions",
981
+ params: [{ eth_accounts: {} }]
982
+ });
983
+ } catch (_error) {
984
+ }
985
+ }
986
+ walletAddress = "";
987
+ renderWallet();
988
+ setStatus(options.disconnectMessage || "Wallet disconnected for this page.");
989
+ return true;
990
+ } finally {
991
+ setBusy(false);
992
+ }
993
+ }
994
+ async function checkout(input) {
995
+ const evm = provider();
996
+ if (!evm) throw new Error(options.noWalletMessage || "Install or open an EVM wallet to continue.");
997
+ if (!walletAddress) await connect();
998
+ const gatewayWallet = await createCircleGatewayBrowserAdapter2({
999
+ network,
1000
+ signer: {
1001
+ address: walletAddress,
1002
+ signTypedData: (typedData) => evm.request({
1003
+ method: "eth_signTypedData_v4",
1004
+ params: [walletAddress, stringifyJson(typedData)]
1005
+ })
1006
+ },
1007
+ clientModule: options.circleClientModule,
1008
+ clientModuleUrl: options.circleClientModuleUrl
1009
+ });
1010
+ return gatewayWallet.pay(input);
1011
+ }
1012
+ async function unlock() {
1013
+ setBusy(true);
1014
+ try {
1015
+ if (!walletAddress) await connect();
1016
+ setBusy(true);
1017
+ setStatus("Requesting Gateway unlock...");
1018
+ const result = await checkResourceAccess(item.resource, {
1019
+ accessPath,
1020
+ source,
1021
+ paymentProvider: options.paymentProvider || "circle-gateway-browser",
1022
+ challengeMessage: options.challengeMessage || "Gateway payment required. Connect your wallet to continue...",
1023
+ paymentMessage: options.paymentMessage || "Approve the Gateway payment proof in your wallet...",
1024
+ successMessage: options.successMessage || `Unlocked ${item.resource.title || "content"}.`,
1025
+ checkout,
1026
+ onStatus: setStatus
1027
+ });
1028
+ if (result.ok) {
1029
+ setUnlocked(true, result.payment || {});
1030
+ if (typeof options.onUnlock === "function") options.onUnlock(result);
1031
+ }
1032
+ return result;
1033
+ } catch (error) {
1034
+ const message = error?.message || "Unlock failed. Please try again.";
1035
+ setStatus(message);
1036
+ return { ok: false, status: 0, error: message, resource: item.resource };
1037
+ } finally {
1038
+ setBusy(false);
1039
+ renderWallet();
1040
+ }
1041
+ }
1042
+ function clear() {
1043
+ clearPaymentProof(item.resource);
1044
+ setUnlocked(false);
1045
+ setStatus("Local payment proof cleared. The next unlock will require Gateway payment again.");
1046
+ }
1047
+ async function hydrate() {
1048
+ const evm = provider();
1049
+ try {
1050
+ const accounts = evm ? await evm.request({ method: "eth_accounts" }) : [];
1051
+ walletAddress = Array.isArray(accounts) ? accounts[0] || "" : "";
1052
+ } catch {
1053
+ }
1054
+ renderWallet();
1055
+ setUnlocked(false);
1056
+ }
1057
+ function mount() {
1058
+ connectButton?.addEventListener?.("click", () => connect().catch((error) => setStatus(error?.message || "Could not connect wallet.")));
1059
+ disconnectButton?.addEventListener?.("click", () => disconnect().catch((error) => setStatus(error?.message || "Could not disconnect wallet.")));
1060
+ unlockButton?.addEventListener?.("click", () => unlock());
1061
+ clearButton?.addEventListener?.("click", clear);
1062
+ hydrate();
1063
+ trackResourcePage(item.resource, { source });
1064
+ return controller;
1065
+ }
1066
+ const controller = { resource: item.resource, connect, disconnect, unlock, clear, hydrate, mount, getWalletAddress: () => walletAddress };
1067
+ if (options.autoMount !== false) mount();
1068
+ return controller;
1069
+ }
1070
+ function createOnchainRating(resource, options = {}) {
1071
+ const item = createGate(resource, options.gateOptions || {});
1072
+ const win = browserWindow();
1073
+ const statusTarget = typeof options.status === "string" ? win?.document.querySelector(options.status) : options.status;
1074
+ const ratingTarget = typeof options.ratingTarget === "string" ? win?.document.querySelector(options.ratingTarget) : options.ratingTarget;
1075
+ const buttonSelector = options.ratingButtons || options.buttons || "[data-nibgate-rating-value], [data-rating]";
1076
+ const explicitButtons = Array.isArray(options.buttons) ? options.buttons : typeof options.buttons === "string" ? Array.from(win?.document.querySelectorAll(options.buttons) || []) : options.buttons ? [options.buttons] : null;
1077
+ const buttons = explicitButtons || Array.from(win?.document.querySelectorAll(buttonSelector) || []);
1078
+ const source = options.source || "nibgate-onchain-rating";
1079
+ let busy = false;
1080
+ let payment = options.payment || null;
1081
+ function setStatus(message) {
1082
+ if (typeof options.onStatus === "function") options.onStatus(message);
1083
+ if (statusTarget) statusTarget.textContent = message || "";
1084
+ }
1085
+ function setBusy(value) {
1086
+ busy = Boolean(value);
1087
+ buttons.forEach((button) => {
1088
+ if (button && "disabled" in button) button.disabled = busy;
1089
+ });
1090
+ }
1091
+ function setPayment(nextPayment = null) {
1092
+ payment = nextPayment || null;
1093
+ return payment;
1094
+ }
1095
+ function setVisible(isVisible) {
1096
+ if (!ratingTarget) return Boolean(isVisible);
1097
+ if ("hidden" in ratingTarget) ratingTarget.hidden = !isVisible;
1098
+ ratingTarget.setAttribute("aria-hidden", isVisible ? "false" : "true");
1099
+ return Boolean(isVisible);
1100
+ }
1101
+ function valueFromButton(button) {
1102
+ const raw = button?.dataset?.nibgateRatingValue || button?.dataset?.rating || button?.value || button?.textContent;
1103
+ const numeric = Number.parseFloat(String(raw || "").replace(/[^\d.]/g, ""));
1104
+ return Number.isFinite(numeric) ? numeric : Number(options.rating || options.stars || 0);
1105
+ }
1106
+ async function rate(input = {}) {
1107
+ setBusy(true);
1108
+ try {
1109
+ const rating = Number.parseFloat(input.rating ?? input.stars ?? input.value ?? options.rating ?? options.stars);
1110
+ if (!Number.isFinite(rating)) throw new Error("Choose a rating before sending.");
1111
+ const paymentId = input.paymentId || options.paymentId || (typeof options.getPaymentId === "function" ? options.getPaymentId() : payment?.paymentId);
1112
+ const unlockRef = input.unlockRef || options.unlockRef || (typeof options.getUnlockRef === "function" ? options.getUnlockRef() : null) || paymentId || payment?.txHash || payment?.transactionHash || "";
1113
+ setStatus(options.pendingMessage || "Send the onchain rating transaction...");
1114
+ const result = await rateContentOnchain(item.resource, {
1115
+ ...options,
1116
+ ...input,
1117
+ rating,
1118
+ paymentId,
1119
+ unlockRef,
1120
+ source
1121
+ });
1122
+ setStatus(options.successMessage || "Rating sent to Nibgate reputation.");
1123
+ if (typeof options.onRated === "function") options.onRated(result);
1124
+ return result;
1125
+ } catch (error) {
1126
+ const message = error?.message || options.errorMessage || "Rating failed.";
1127
+ setStatus(message);
1128
+ if (typeof options.onError === "function") options.onError(error);
1129
+ throw error;
1130
+ } finally {
1131
+ setBusy(false);
1132
+ }
1133
+ }
1134
+ function mount() {
1135
+ buttons.forEach((button) => {
1136
+ button?.addEventListener?.("click", () => rate({ rating: valueFromButton(button) }).catch(() => null));
1137
+ });
1138
+ if (options.visible !== void 0) setVisible(Boolean(options.visible));
1139
+ return controller;
1140
+ }
1141
+ const controller = { resource: item.resource, rate, mount, setPayment, setVisible };
1142
+ if (options.autoMount !== false) mount();
1143
+ return controller;
1144
+ }
1145
+ function mountRatingUI(resource, options = {}) {
1146
+ const item = createGate(resource, options.gateOptions || {});
1147
+ const win = browserWindow();
1148
+ if (!win) return null;
1149
+ const target = typeof options.target === "string" ? win.document.querySelector(options.target) : options.target;
1150
+ if (!target) return null;
1151
+ const stars = [1, 2, 3, 4, 5];
1152
+ let selectedRating = 0;
1153
+ const container = win.document.createElement("div");
1154
+ container.className = "nibgate-rating-ui";
1155
+ container.style.cssText = "display:flex;align-items:center;gap:4px;padding:8px 0";
1156
+ const starButtons = stars.map((value) => {
1157
+ const btn = win.document.createElement("button");
1158
+ btn.type = "button";
1159
+ btn.dataset.nibgateRatingValue = String(value);
1160
+ btn.setAttribute("aria-label", `${value} star${value > 1 ? "s" : ""}`);
1161
+ btn.innerHTML = "\u2606";
1162
+ btn.style.cssText = "background:none;border:none;font-size:24px;cursor:pointer;color:#ccc;transition:color 0.15s;padding:2px;line-height:1";
1163
+ btn.addEventListener("mouseenter", () => {
1164
+ starButtons.forEach((b, i) => b.style.color = i < value ? "#f5b342" : "#ccc");
1165
+ });
1166
+ btn.addEventListener("mouseleave", () => {
1167
+ starButtons.forEach((b, i) => b.style.color = i < selectedRating ? "#f5b342" : "#ccc");
1168
+ });
1169
+ btn.addEventListener("click", () => {
1170
+ selectedRating = value;
1171
+ starButtons.forEach((b, i) => b.style.color = i < value ? "#f5b342" : "#ccc");
1172
+ rate(item.resource, { rating: value }).catch(() => {
1173
+ });
1174
+ });
1175
+ container.appendChild(btn);
1176
+ return btn;
1177
+ });
1178
+ const statusEl = win.document.createElement("span");
1179
+ statusEl.style.cssText = "font-size:13px;color:#888;margin-left:8px";
1180
+ statusEl.textContent = options.label || "Rate this content";
1181
+ container.appendChild(statusEl);
1182
+ target.appendChild(container);
1183
+ function rate(r, input = {}) {
1184
+ return item.rate({ ...input, rating: r });
1185
+ }
1186
+ function setRating(value) {
1187
+ selectedRating = value;
1188
+ starButtons.forEach((b, i) => b.style.color = i < value ? "#f5b342" : "#ccc");
1189
+ }
1190
+ return {
1191
+ resource: item.resource,
1192
+ container,
1193
+ setRating,
1194
+ rate
1195
+ };
1196
+ }
1197
+ async function payAndUnlockResource(resource, options = {}) {
1198
+ const item = createGate(resource, options.gateOptions || {});
1199
+ const payPath = options.payPath || item.resource.payPath || "/api/nibgate/pay";
1200
+ const status = typeof options.onStatus === "function" ? options.onStatus : () => {
1201
+ };
1202
+ status(options.paymentMessage || "Starting payment...");
1203
+ item.unlockStarted({ source: options.source, paymentProvider: options.paymentProvider || "circle-gateway" });
1204
+ const response = await fetch(payPath, {
1205
+ method: options.payMethod || "POST",
1206
+ headers: {
1207
+ accept: "application/json",
1208
+ "content-type": "application/json",
1209
+ ...options.payHeaders || {}
1210
+ },
1211
+ body: JSON.stringify({
1212
+ resource: item.resource,
1213
+ ...options.payPayload || {}
1214
+ })
1215
+ });
1216
+ const payload = await response.json().catch(() => ({}));
1217
+ if (!response.ok || !payload.success) {
1218
+ item.track("payment_failed", { source: options.source, status: response.status, error: payload.error || "Payment failed", detail: payload.detail || "" });
1219
+ status(payload.detail || payload.error || options.paymentErrorMessage || "Payment failed.");
1220
+ return { ok: false, status: response.status, payload, resource: item.resource, response };
1221
+ }
1222
+ const payment = payload.payment || {
1223
+ paymentProvider: options.paymentProvider || "circle-gateway",
1224
+ paymentId: payload.paymentId || `nibgate_payment_${Date.now()}`,
1225
+ amount: Number(item.resource.price || 0),
1226
+ revenue: Number(item.resource.price || 0),
1227
+ currency: item.resource.currency || "USDC"
1228
+ };
1229
+ storePaymentProof(item.resource, payload.unlockProof);
1230
+ item.markUnlocked(payment);
1231
+ status(options.paymentSuccessMessage || "Payment verified. Content unlocked.");
1232
+ return { ok: true, status: response.status, payload, payment, resource: item.resource, response };
1233
+ }
1234
+ function setupResourcePage(resource, options = {}) {
1235
+ const item = trackResourcePage(resource, options);
1236
+ const win = browserWindow();
1237
+ if (!win) return item;
1238
+ const button = typeof options.button === "string" ? win.document.querySelector(options.button) : options.button;
1239
+ const statusElement = typeof options.status === "string" ? win.document.querySelector(options.status) : options.status;
1240
+ const setStatus = options.onStatus || ((message) => {
1241
+ if (statusElement) statusElement.textContent = message || "";
1242
+ });
1243
+ if (button) {
1244
+ button.addEventListener("click", async () => {
1245
+ button.disabled = true;
1246
+ try {
1247
+ await checkResourceAccess(resource, { ...options, onStatus: setStatus });
1248
+ } finally {
1249
+ button.disabled = false;
1250
+ }
1251
+ });
1252
+ }
1253
+ return item;
1254
+ }
1255
+ function createNibgate(defaults = {}) {
1256
+ const defaultResource = defaults.resource ? normalizeResource(defaults.resource) : null;
1257
+ function resourceWithDefaults(resource = {}) {
1258
+ return normalizeResource({
1259
+ ...defaultResource || {},
1260
+ ...typeof resource === "string" ? { id: resource } : resource
1261
+ });
1262
+ }
1263
+ return {
1264
+ content(resource, extra = {}) {
1265
+ return emit("content_registered", payloadWithResource(resourceWithDefaults(resource), extra));
1266
+ },
1267
+ registerContent(resource, extra = {}) {
1268
+ return emit("content_registered", payloadWithResource(resourceWithDefaults(resource), extra));
1269
+ },
1270
+ view(resource, extra = {}) {
1271
+ return emit("resource_view", payloadWithResource(resourceWithDefaults(resource), extra));
1272
+ },
1273
+ track(eventName, payload = {}) {
1274
+ return emit(eventName || "custom", payload);
1275
+ },
1276
+ unlockStarted(resource, extra = {}) {
1277
+ return emit("unlock_started", payloadWithResource(resourceWithDefaults(resource), extra));
1278
+ },
1279
+ unlockCompleted(resource, payment = {}) {
1280
+ return emit("unlock_completed", payloadWithResource(resourceWithDefaults(resource), payment));
1281
+ },
1282
+ paymentCompleted(resource, payment = {}) {
1283
+ return emit("payment_completed", payloadWithResource(resourceWithDefaults(resource), payment));
1284
+ },
1285
+ rateResource(resource, rating = {}, extra = {}) {
1286
+ return rateResource(resourceWithDefaults(resource), rating, extra);
1287
+ },
1288
+ ratingMessage(resource, rating = {}, messageOptions = {}) {
1289
+ return ratingMessage(resourceWithDefaults(resource), rating, messageOptions);
1290
+ },
1291
+ gate(resource, options = {}) {
1292
+ return createGate(resourceWithDefaults(resource), { ...options, client: this });
1293
+ },
1294
+ trackResourcePage(resource, options = {}) {
1295
+ return trackResourcePage(resourceWithDefaults(resource), options);
1296
+ },
1297
+ checkResourceAccess(resource, options = {}) {
1298
+ return checkResourceAccess(resourceWithDefaults(resource), options);
1299
+ },
1300
+ payWithPaymentSignature(resource, options = {}) {
1301
+ return payWithPaymentSignature(resourceWithDefaults(resource), options);
1302
+ },
1303
+ createWalletCheckout(resource, options = {}) {
1304
+ return createWalletCheckout(resourceWithDefaults(resource), options);
1305
+ },
1306
+ createCircleGatewayBrowserAdapter(options = {}) {
1307
+ return createCircleGatewayBrowserAdapter2(options);
1308
+ },
1309
+ createTransferCheckout(resource, options = {}) {
1310
+ return createTransferCheckout(resourceWithDefaults(resource), options);
1311
+ },
1312
+ payWithTransfer(resource, options = {}) {
1313
+ return payWithTransfer(resourceWithDefaults(resource), options);
1314
+ },
1315
+ createEvmGatewayUnlock(resource, options = {}) {
1316
+ return createEvmGatewayUnlock(resourceWithDefaults(resource), options);
1317
+ },
1318
+ createOnchainRating(resource, options = {}) {
1319
+ return createOnchainRating(resourceWithDefaults(resource), options);
1320
+ },
1321
+ mountRatingUI(resource, options = {}) {
1322
+ return mountRatingUI(resourceWithDefaults(resource), options);
1323
+ },
1324
+ payAndUnlockResource(resource, options = {}) {
1325
+ return payAndUnlockResource(resourceWithDefaults(resource), options);
1326
+ },
1327
+ setupResourcePage(resource, options = {}) {
1328
+ return setupResourcePage(resourceWithDefaults(resource), options);
1329
+ },
1330
+ normalizeResource: resourceWithDefaults,
1331
+ normalizeContentType,
1332
+ flush: flushQueue
1333
+ };
1334
+ }
1335
+ var nibgate = createNibgate();
1336
+ var gate = createGate;
1337
+ return __toCommonJS(index_exports);
1338
+ })();
1339
+ //# sourceMappingURL=nibgate.js.map