@nevermined-io/ui-widgets 0.4.6 → 0.5.2

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,11 @@
1
+ type EventHandler<T> = (payload: T) => void;
2
+ export declare class TypedEventEmitter<Events extends object> {
3
+ private listeners;
4
+ on<K extends keyof Events>(event: K, handler: EventHandler<Events[K]>): this;
5
+ off<K extends keyof Events>(event: K, handler: EventHandler<Events[K]>): this;
6
+ once<K extends keyof Events>(event: K, handler: EventHandler<Events[K]>): this;
7
+ removeAllListeners(event?: keyof Events): this;
8
+ emit<K extends keyof Events>(event: K, payload: Events[K]): void;
9
+ }
10
+ export {};
11
+ //# sourceMappingURL=event-emitter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-emitter.d.ts","sourceRoot":"","sources":["../src/event-emitter.ts"],"names":[],"mappings":"AAAA,KAAK,YAAY,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,KAAK,IAAI,CAAA;AAE3C,qBAAa,iBAAiB,CAAC,MAAM,SAAS,MAAM;IAClD,OAAO,CAAC,SAAS,CAAsD;IAEvE,EAAE,CAAC,CAAC,SAAS,MAAM,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI;IAO5E,GAAG,CAAC,CAAC,SAAS,MAAM,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI;IAS7E,IAAI,CAAC,CAAC,SAAS,MAAM,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI;IAS9E,kBAAkB,CAAC,KAAK,CAAC,EAAE,MAAM,MAAM,GAAG,IAAI;IAS9C,IAAI,CAAC,CAAC,SAAS,MAAM,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,GAAG,IAAI;CAWjE"}
@@ -0,0 +1,21 @@
1
+ import { type WidgetMessage } from './messages.js';
2
+ export interface IframeOptions {
3
+ container?: HTMLElement;
4
+ style?: Partial<CSSStyleDeclaration>;
5
+ }
6
+ export declare class IframeManager {
7
+ private expectedOrigin;
8
+ private iframe;
9
+ private messageHandlers;
10
+ private protocolErrorHandlers;
11
+ private messageListener;
12
+ private destroyed;
13
+ constructor(expectedOrigin: string);
14
+ create(url: string, options?: IframeOptions): HTMLIFrameElement;
15
+ destroy(): void;
16
+ postMessage(msg: WidgetMessage): void;
17
+ onMessage(handler: (msg: WidgetMessage) => void): () => void;
18
+ onProtocolError(handler: (reason: string) => void): () => void;
19
+ private ensureListener;
20
+ }
21
+ //# sourceMappingURL=iframe-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"iframe-manager.d.ts","sourceRoot":"","sources":["../src/iframe-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,aAAa,EAAE,MAAM,eAAe,CAAA;AAEhE,MAAM,WAAW,aAAa;IAC5B,SAAS,CAAC,EAAE,WAAW,CAAA;IACvB,KAAK,CAAC,EAAE,OAAO,CAAC,mBAAmB,CAAC,CAAA;CACrC;AAED,qBAAa,aAAa;IAOZ,OAAO,CAAC,cAAc;IANlC,OAAO,CAAC,MAAM,CAAiC;IAC/C,OAAO,CAAC,eAAe,CAA0C;IACjE,OAAO,CAAC,qBAAqB,CAAsC;IACnE,OAAO,CAAC,eAAe,CAA+C;IACtE,OAAO,CAAC,SAAS,CAAQ;gBAEL,cAAc,EAAE,MAAM;IAQ1C,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,iBAAiB;IA6B/D,OAAO,IAAI,IAAI;IAYf,WAAW,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI;IAKrC,SAAS,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,aAAa,KAAK,IAAI,GAAG,MAAM,IAAI;IAO5D,eAAe,CAAC,OAAO,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,GAAG,MAAM,IAAI;IAO9D,OAAO,CAAC,cAAc;CAiCvB"}
package/dist/index.d.ts CHANGED
@@ -1,345 +1,14 @@
1
- export declare interface CardAction {
2
- /** Currently the only emitted action; reserved as a discriminator for future ones. */
3
- action: 'delegate';
4
- paymentMethodId: string;
5
- }
6
-
7
- export declare interface CheckoutOptions {
8
- did: string;
9
- planId?: string;
10
- container?: HTMLElement;
11
- onBooted?: () => void;
12
- onReady?: () => void;
13
- onSuccess?: (result: CheckoutResult) => void;
14
- onError?: (error: EmbedError) => void;
15
- onClose?: () => void;
16
- }
17
-
18
- export declare interface CheckoutResult {
19
- did: string;
20
- planId?: string;
21
- txHash?: string;
22
- }
23
-
24
- /**
25
- * Checkout widget.
26
- *
27
- * Lifecycle note for SDK consumers: when the iframe sends `nvm:close` the
28
- * widget instance auto-calls `destroy()` and becomes terminal — any
29
- * subsequent `start()` call throws. If the host page needs to re-show the
30
- * checkout after a close, construct a new `CheckoutWidget` (typically via
31
- * `nvm.checkout`) and call `start()` on the fresh instance.
32
- */
33
- export declare class CheckoutWidget {
34
- private readonly session;
35
- private readonly webappBase;
36
- private manager;
37
- private destroyed;
38
- constructor(session: SessionManager, webappBase: string);
39
- /**
40
- * Mounts the checkout iframe into `options.container`.
41
- * Throws if called after `destroy()` (including the implicit destroy on
42
- * `nvm:close` — see class JSDoc).
43
- */
44
- start(options: CheckoutOptions): void;
45
- destroy(): void;
46
- private handleMessage;
47
- }
48
-
49
- export declare interface CreateDelegationOptions {
50
- paymentMethodId: string;
51
- container?: HTMLElement;
52
- onBooted?: () => void;
53
- onReady?: () => void;
54
- onSuccess?: (result: CreateDelegationResult) => void;
55
- onError?: (error: EmbedError) => void;
56
- onClose?: () => void;
57
- }
58
-
59
- export declare interface CreateDelegationResult {
60
- delegationId: string;
61
- paymentMethodId: string;
62
- }
63
-
64
- export declare function createMessage<T>(type: WidgetMessageType, payload?: T): WidgetMessage<T>;
65
-
66
- /**
67
- * Card and delegation management widget.
68
- *
69
- * Surfaces three iframe-based flows (enrollment, listing, delegation creation)
70
- * and two SDK-direct revocations. The three iframe flows share the single
71
- * `manager` slot — calling any of them destroys the previously-mounted iframe
72
- * (same semantics as calling `enrollCard()` twice). Once any iframe is closed
73
- * by the user (`nvm:close`), the instance is implicitly destroyed and any
74
- * subsequent iframe call throws. Construct a fresh widget (via
75
- * `nvm.delegations`) to mount another flow after a close.
76
- *
77
- * The two `revoke*` methods do NOT use an iframe — they hit the
78
- * `/api/v1/widgets/...` endpoints directly with the widget session token.
79
- * They exist because the SDK consumer on the host page only holds the widget
80
- * session token; the apiKeyHash that gates the standard delegation/payment
81
- * endpoints never leaves the embedded iframe.
82
- */
83
- export declare class DelegationsWidget {
84
- private readonly session;
85
- private readonly webappBase;
86
- private readonly apiBase;
87
- private manager;
88
- private destroyed;
89
- constructor(session: SessionManager, webappBase: string, apiBase: string);
90
- /**
91
- * Mounts the enrollment iframe at `/embed/cards/enroll`.
92
- * Throws if called after `destroy()` (including the implicit destroy on
93
- * `nvm:close` — see class JSDoc).
94
- */
95
- enrollCard(options: EnrollCardOptions): void;
96
- /**
97
- * Mounts the cards-list iframe at `/embed/cards/list`. Per-row actions
98
- * (currently only "Create Delegation") are forwarded via `onCardAction` so
99
- * the host can mount the appropriate follow-up widget.
100
- */
101
- listCards(options: ListCardsOptions): void;
102
- /**
103
- * Mounts the delegation creation iframe at `/embed/cards/delegate` for a
104
- * specific payment method. The `paymentMethodId` is required and is passed
105
- * as a search param so the embed route can scope the form to that card.
106
- */
107
- createDelegation(options: CreateDelegationOptions): void;
108
- /**
109
- * Revoke (detach) a payment method via the widget-prefixed API endpoint.
110
- * Resolves on 2xx; throws `WidgetApiError` on any other response or
111
- * network failure.
112
- */
113
- revokeCard(paymentMethodId: string): Promise<void>;
114
- /**
115
- * Revoke a delegation via the widget-prefixed API endpoint.
116
- * Resolves on 2xx; throws `WidgetApiError` on any other response or
117
- * network failure.
118
- */
119
- revokeDelegation(delegationId: string): Promise<void>;
120
- destroy(): void;
121
- private assertAlive;
122
- private mountIframe;
123
- private postInitOnBooted;
124
- private handleEnrollMessage;
125
- private handleListMessage;
126
- private handleCreateDelegationMessage;
127
- private deleteWithSession;
128
- }
129
-
130
- export declare interface EmbedError {
131
- code: 'UNAUTHORIZED' | 'NETWORK' | 'PAYMENT_NOT_CONFIRMED' | 'UNKNOWN';
132
- message: string;
133
- status?: number;
134
- apiCode?: string;
135
- }
136
-
137
- export declare interface EnrollCardOptions {
138
- container?: HTMLElement;
139
- onBooted?: () => void;
140
- onReady?: () => void;
141
- onSuccess?: (result: EnrollCardResult) => void;
142
- onError?: (error: EmbedError) => void;
143
- onClose?: () => void;
144
- }
145
-
146
- export declare interface EnrollCardResult {
147
- paymentMethodId: string;
148
- }
149
-
150
- export declare type Environment = (typeof ENVIRONMENTS)[number];
151
-
152
- declare const ENVIRONMENTS: readonly ["local", "sandbox", "live", "staging_sandbox", "staging_live"];
153
-
154
- declare type EventHandler<T> = (payload: T) => void;
155
-
156
- export declare class IframeManager {
157
- private expectedOrigin;
158
- private iframe;
159
- private messageHandlers;
160
- private protocolErrorHandlers;
161
- private messageListener;
162
- private destroyed;
163
- constructor(expectedOrigin: string);
164
- create(url: string, options?: IframeOptions): HTMLIFrameElement;
165
- destroy(): void;
166
- postMessage(msg: WidgetMessage): void;
167
- onMessage(handler: (msg: WidgetMessage) => void): () => void;
168
- onProtocolError(handler: (reason: string) => void): () => void;
169
- private ensureListener;
170
- }
171
-
172
- export declare interface IframeOptions {
173
- container?: HTMLElement;
174
- style?: Partial<CSSStyleDeclaration>;
175
- }
176
-
177
- export declare interface ListCardsOptions {
178
- container?: HTMLElement;
179
- onBooted?: () => void;
180
- onReady?: () => void;
181
- onCardAction?: (action: CardAction) => void;
182
- onError?: (error: EmbedError) => void;
183
- onClose?: () => void;
184
- }
185
-
186
- export declare class NeverminedWidgets {
187
- private readonly sessionManager;
188
- private readonly _account;
189
- private readonly environment;
190
- private _checkout;
191
- private _delegations;
192
- private readonly events;
193
- private constructor();
194
- static initialize(config: WidgetConfig): Promise<NeverminedWidgets>;
195
- private refreshSession;
196
- on<K extends keyof NeverminedWidgetsEvents>(event: K, handler: (payload: NeverminedWidgetsEvents[K]) => void): this;
197
- off<K extends keyof NeverminedWidgetsEvents>(event: K, handler: (payload: NeverminedWidgetsEvents[K]) => void): this;
198
- get account(): WidgetAccount;
199
- get hasValidSession(): boolean;
200
- getSessionToken(): string;
201
- get checkout(): CheckoutWidget;
202
- get delegations(): DelegationsWidget;
203
- /**
204
- * Resets the parent widget container: tears down any live child widget (e.g.
205
- * the checkout widget) and clears the internal cache. This is a reset, not a
206
- * terminal state — accessing `widget.checkout` after `destroy()` lazily
207
- * creates a fresh `CheckoutWidget` instance. If you need a terminal "this
208
- * widget can no longer be used" semantics, call `destroy()` on the child
209
- * widget directly (e.g. `widget.checkout.destroy()`), which flips its
210
- * internal `destroyed` flag and makes subsequent `start()` calls throw.
211
- */
212
- destroy(): void;
213
- }
214
-
215
- declare interface NeverminedWidgetsEvents {
216
- 'session-expired': void;
217
- }
218
-
219
- export declare function parseMessage(data: unknown): ParseResult;
220
-
221
- export declare type ParseResult<T = unknown> = {
222
- ok: true;
223
- message: WidgetMessage<T>;
224
- } | {
225
- ok: false;
226
- reason: string;
227
- };
228
-
229
- export declare class SessionManager {
230
- private session;
231
- private expiresMs;
232
- private timer;
233
- constructor(session: WidgetSession);
234
- isValid(): boolean;
235
- getToken(): string;
236
- getSession(): WidgetSession;
237
- startAutoRefresh(refreshFn: () => Promise<WidgetSession>, onExpired: () => void): void;
238
- stopAutoRefresh(): void;
239
- }
240
-
241
- export declare class TypedEventEmitter<Events extends object> {
242
- private listeners;
243
- on<K extends keyof Events>(event: K, handler: EventHandler<Events[K]>): this;
244
- off<K extends keyof Events>(event: K, handler: EventHandler<Events[K]>): this;
245
- once<K extends keyof Events>(event: K, handler: EventHandler<Events[K]>): this;
246
- removeAllListeners(event?: keyof Events): this;
247
- emit<K extends keyof Events>(event: K, payload: Events[K]): void;
248
- }
249
-
250
- declare const WIDGET_ERRORS: {
251
- readonly MISSING_INIT_TOKEN: {
252
- readonly numericCode: "WDG.0001";
253
- readonly message: "initToken is required and must be a non-empty string";
254
- };
255
- readonly INVALID_ENVIRONMENT: {
256
- readonly numericCode: "WDG.0002";
257
- readonly message: "environment must be one of: sandbox, live, staging_sandbox, staging_live, local";
258
- };
259
- readonly INVALID_INIT_TOKEN: {
260
- readonly numericCode: "WDG.0003";
261
- readonly message: "Init token is invalid or expired";
262
- };
263
- readonly INVALID_RESPONSE: {
264
- readonly numericCode: "WDG.0004";
265
- readonly message: "Server response is missing required fields";
266
- };
267
- readonly NETWORK_ERROR: {
268
- readonly numericCode: "WDG.0005";
269
- readonly message: "Network request failed";
270
- };
271
- readonly SESSION_EXPIRED: {
272
- readonly numericCode: "WDG.0006";
273
- readonly message: "Widget session has expired";
274
- };
275
- };
276
-
277
- export declare const WIDGET_MESSAGE_VERSION: "1";
278
-
279
- export declare interface WidgetAccount {
280
- userId: string;
281
- userWallet: `0x${string}`;
282
- }
283
-
284
- /**
285
- * Thrown by SDK methods that hit the API directly (no iframe), e.g.
286
- * `delegations.revokeCard()` / `delegations.revokeDelegation()`. Carries the
287
- * HTTP status and the optional BCK error code so consumers can branch on
288
- * 401/403/etc. without parsing the message.
289
- */
290
- export declare class WidgetApiError extends Error {
291
- readonly status?: number | undefined;
292
- readonly apiCode?: string | undefined;
293
- constructor(message: string, status?: number | undefined, apiCode?: string | undefined);
294
- }
295
-
296
- export declare interface WidgetConfig {
297
- initToken: string;
298
- environment: Environment;
299
- }
300
-
301
- declare type WidgetErrorCode = keyof typeof WIDGET_ERRORS;
302
-
303
- export declare class WidgetInitError extends Error {
304
- readonly code: WidgetErrorCode;
305
- constructor(code: WidgetErrorCode, message?: string, cause?: unknown);
306
- }
307
-
308
- export declare interface WidgetMessage<T = unknown> {
309
- type: WidgetMessageType;
310
- version: '1';
311
- payload?: T;
312
- }
313
-
314
- export declare enum WidgetMessageType {
315
- INIT = "nvm:init",
316
- CLOSE = "nvm:close",
317
- BOOTED = "nvm:booted",
318
- READY = "nvm:ready",
319
- RESIZE = "nvm:resize",
320
- SUCCESS = "nvm:success",
321
- ERROR = "nvm:error",
322
- CARD_ACTION = "nvm:card-action"
323
- }
324
-
325
- export declare interface WidgetSession {
326
- sessionToken: string;
327
- userId: string;
328
- userWallet: `0x${string}`;
329
- /**
330
- * Hash of the NVM API key bound to this widget session user. Returned by
331
- * `POST /api/v1/widgets/session` so host pages that want to call user-scoped
332
- * endpoints directly (outside the iframe) have the bearer token to do so.
333
- * The embedded iframe flow consumes it via the session JWT claims rather
334
- * than this field.
335
- */
336
- apiKeyHash: string;
337
- expiresAt: string;
338
- }
339
-
340
- export declare class WidgetSessionExpiredError extends Error {
341
- readonly code: "SESSION_EXPIRED";
342
- constructor();
343
- }
344
-
345
- export { }
1
+ export { NeverminedWidgets } from './nevermined-widgets.js';
2
+ export { SessionManager } from './session.js';
3
+ export { IframeManager } from './iframe-manager.js';
4
+ export { CheckoutWidget } from './widgets/checkout.js';
5
+ export { DelegationsWidget } from './widgets/delegations.js';
6
+ export { TypedEventEmitter } from './event-emitter.js';
7
+ export { WidgetMessageType, WIDGET_MESSAGE_VERSION, createMessage, parseMessage, } from './messages.js';
8
+ export { WidgetApiError, WidgetInitError, WidgetSessionExpiredError } from './utils/errors.js';
9
+ export type { WidgetConfig, WidgetSession, WidgetAccount, Environment, EmbedError, AuthMismatchDetail, } from './types.js';
10
+ export type { IframeOptions } from './iframe-manager.js';
11
+ export type { CheckoutOptions, CheckoutResult } from './widgets/checkout.js';
12
+ export type { CardAction, CreateDelegationOptions, CreateDelegationResult, EnrollCardOptions, EnrollCardResult, ListCardsOptions, } from './widgets/delegations.js';
13
+ export type { WidgetMessage, ParseResult } from './messages.js';
14
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAA;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAA;AAC5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAA;AACtD,OAAO,EACL,iBAAiB,EACjB,sBAAsB,EACtB,aAAa,EACb,YAAY,GACb,MAAM,eAAe,CAAA;AACtB,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,yBAAyB,EAAE,MAAM,mBAAmB,CAAA;AAC9F,YAAY,EACV,YAAY,EACZ,aAAa,EACb,aAAa,EACb,WAAW,EACX,UAAU,EACV,kBAAkB,GACnB,MAAM,YAAY,CAAA;AACnB,YAAY,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AACxD,YAAY,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AAC5E,YAAY,EACV,UAAU,EACV,uBAAuB,EACvB,sBAAsB,EACtB,iBAAiB,EACjB,gBAAgB,EAChB,gBAAgB,GACjB,MAAM,0BAA0B,CAAA;AACjC,YAAY,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA"}
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- (function(e,t){typeof exports==`object`&&typeof module<`u`?t(exports):typeof define==`function`&&define.amd?define([`exports`],t):(e=typeof globalThis<`u`?globalThis:e||self,t(e.NeverminedWidgets={}))})(this,function(e){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});var t=[`local`,`sandbox`,`live`,`staging_sandbox`,`staging_live`],n={local:`http://localhost:3001`,sandbox:`https://api.sandbox.nevermined.app`,live:`https://api.live.nevermined.app`,staging_sandbox:`https://api.sandbox.nevermined.dev`,staging_live:`https://api.live.nevermined.dev`},r={local:`http://localhost:4200`,sandbox:`https://nevermined.app`,live:`https://nevermined.app`,staging_sandbox:`https://nevermined.dev`,staging_live:`https://nevermined.dev`};function i(e){return n[e]}function a(e){return r[e]}var o={MISSING_INIT_TOKEN:{numericCode:`WDG.0001`,message:`initToken is required and must be a non-empty string`},INVALID_ENVIRONMENT:{numericCode:`WDG.0002`,message:`environment must be one of: sandbox, live, staging_sandbox, staging_live, local`},INVALID_INIT_TOKEN:{numericCode:`WDG.0003`,message:`Init token is invalid or expired`},INVALID_RESPONSE:{numericCode:`WDG.0004`,message:`Server response is missing required fields`},NETWORK_ERROR:{numericCode:`WDG.0005`,message:`Network request failed`},SESSION_EXPIRED:{numericCode:`WDG.0006`,message:`Widget session has expired`}},s=class extends Error{constructor(e,t,n){super(t??o[e].message,{cause:n}),this.code=e,this.name=`WidgetInitError`}},c=class extends Error{code=`SESSION_EXPIRED`;constructor(){super(o.SESSION_EXPIRED.message),this.name=`WidgetSessionExpiredError`}},l=class extends Error{constructor(e,t,n){super(e),this.status=t,this.apiCode=n,this.name=`WidgetApiError`}},u=.8,d=class{session;expiresMs;timer=null;constructor(e){this.session=e,this.expiresMs=new Date(e.expiresAt).getTime(),Number.isNaN(this.expiresMs)&&console.warn(`[SessionManager] malformed expiresAt, session will be treated as expired:`,e.expiresAt)}isValid(){return!Number.isNaN(this.expiresMs)&&this.expiresMs>Date.now()}getToken(){return this.session.sessionToken}getSession(){return this.session}startAutoRefresh(e,t){if(this.stopAutoRefresh(),!this.isValid()){t();return}let n=Math.max(0,Math.floor((this.expiresMs-Date.now())*u));this.timer=setTimeout(()=>{this.timer=null,e().then(n=>{if(this.session=n,this.expiresMs=new Date(n.expiresAt).getTime(),!this.isValid()){t();return}this.startAutoRefresh(e,t)},e=>{console.error(`[SessionManager] session refresh failed:`,e),t()})},n)}stopAutoRefresh(){this.timer!==null&&(clearTimeout(this.timer),this.timer=null)}},f=class{listeners=new Map;on(e,t){let n=this.listeners.get(e)??new Set;return n.add(t),this.listeners.set(e,n),this}off(e,t){let n=this.listeners.get(e);return n?(n.delete(t),n.size===0&&this.listeners.delete(e),this):this}once(e,t){let n=r=>{this.off(e,n),t(r)};return this.on(e,n)}removeAllListeners(e){return e===void 0?this.listeners.clear():this.listeners.delete(e),this}emit(e,t){let n=this.listeners.get(e);n&&[...n].forEach(e=>{try{e(t)}catch(e){console.error(`[TypedEventEmitter] Handler threw:`,e)}})}},p=function(e){return e.INIT=`nvm:init`,e.CLOSE=`nvm:close`,e.BOOTED=`nvm:booted`,e.READY=`nvm:ready`,e.RESIZE=`nvm:resize`,e.SUCCESS=`nvm:success`,e.ERROR=`nvm:error`,e.CARD_ACTION=`nvm:card-action`,e}({}),m=`1`,h=`1`;function g(e){return typeof e==`string`&&Object.values(p).includes(e)}function _(e,t){return{type:e,version:h,payload:t}}function v(e){if(typeof e!=`object`||!e)return{ok:!1,reason:`not an object`};let t=e;return g(t.type)?t.version===h?{ok:!0,message:{type:t.type,version:t.version,payload:t.payload}}:{ok:!1,reason:`version mismatch: received "${t.version}", expected "${h}"`}:{ok:!1,reason:typeof t.type==`string`&&t.type.startsWith(`nvm:`)?`unknown nvm: type "${t.type}"`:`missing or unknown type`}}var y=class{iframe=null;messageHandlers=new Set;protocolErrorHandlers=new Set;messageListener=null;destroyed=!1;constructor(e){if(this.expectedOrigin=e,e===`*`)throw Error(`[IframeManager] Wildcard origin "*" is not allowed — pass an explicit origin`)}create(e,t){this.iframe?.remove();let n=document.createElement(`iframe`);return n.src=e,n.style.width=`100%`,n.style.height=`100%`,n.style.border=`none`,n.style.display=`block`,n.setAttribute(`sandbox`,`allow-scripts allow-same-origin allow-forms`),t?.container||(n.style.position=`fixed`,n.style.top=`0`,n.style.left=`0`,n.style.right=`0`,n.style.bottom=`0`,n.style.zIndex=`9999`),t?.style&&Object.assign(n.style,t.style),(t?.container??document.body).appendChild(n),this.iframe=n,n}destroy(){this.destroyed=!0,this.messageListener&&=(window.removeEventListener(`message`,this.messageListener),null),this.messageHandlers.clear(),this.protocolErrorHandlers.clear(),this.iframe?.remove(),this.iframe=null}postMessage(e){this.destroyed||this.iframe?.contentWindow?.postMessage(e,this.expectedOrigin)}onMessage(e){return this.destroyed?()=>void 0:(this.messageHandlers.add(e),this.ensureListener(),()=>this.messageHandlers.delete(e))}onProtocolError(e){return this.destroyed?()=>void 0:(this.protocolErrorHandlers.add(e),this.ensureListener(),()=>this.protocolErrorHandlers.delete(e))}ensureListener(){this.messageListener||(this.messageListener=e=>{if(e.origin!==this.expectedOrigin)return;let t=v(e.data);if(!t.ok){console.warn(`[IframeManager] Discarding message from ${this.expectedOrigin}: ${t.reason}`),this.protocolErrorHandlers.forEach(e=>{try{e(t.reason)}catch(e){console.error(`[IframeManager] Protocol error handler threw:`,e)}});return}this.messageHandlers.forEach(e=>{try{e(t.message)}catch(e){console.error(`[IframeManager] Message handler threw:`,e)}})},window.addEventListener(`message`,this.messageListener))}},b={code:`UNKNOWN`,message:`Unknown widget error`},x=class{manager=null;destroyed=!1;constructor(e,t){this.session=e,this.webappBase=t}start(e){if(this.destroyed)throw Error(`[CheckoutWidget] cannot start: instance has been destroyed`);if(!e.did||typeof e.did!=`string`)throw Error(`[CheckoutWidget] did is required`);this.manager?.destroy();let t=new URL(this.webappBase).origin,n=window.location.origin,r=new URL(`/embed/checkout/${encodeURIComponent(e.did)}`,this.webappBase);r.searchParams.set(`parentOrigin`,n),e.planId&&r.searchParams.set(`planId`,e.planId);let i=new y(t);this.manager=i,i.create(r.toString(),{container:e.container}),i.onMessage(t=>this.handleMessage(t,e))}destroy(){this.destroyed=!0,this.manager?.destroy(),this.manager=null}handleMessage(e,t){switch(e.type){case p.BOOTED:this.manager?.postMessage(_(p.INIT,{sessionToken:this.session.getToken()})),t.onBooted?.();return;case p.READY:t.onReady?.();return;case p.SUCCESS:{let n=e.payload??{};t.onSuccess?.({did:n.did??t.did,planId:n.planId??t.planId,txHash:n.txHash});return}case p.ERROR:{let n=e.payload;t.onError?.(n?.error??b);return}case p.CLOSE:t.onClose?.(),this.destroy();return;default:return}}},S={code:`UNKNOWN`,message:`Unknown widget error`},C={code:`UNKNOWN`,message:`Malformed nvm:success payload — paymentMethodId missing or invalid`},w={code:`UNKNOWN`,message:`Malformed nvm:success payload — delegationId missing or invalid`},T=class{manager=null;destroyed=!1;constructor(e,t,n){this.session=e,this.webappBase=t,this.apiBase=n}enrollCard(e){this.assertAlive(`enrollCard`),this.mountIframe(`/embed/cards/enroll`,e.container).onMessage(t=>this.handleEnrollMessage(t,e))}listCards(e){this.assertAlive(`listCards`),this.mountIframe(`/embed/cards/list`,e.container).onMessage(t=>this.handleListMessage(t,e))}createDelegation(e){if(this.assertAlive(`createDelegation`),typeof e.paymentMethodId!=`string`||e.paymentMethodId.length===0)throw Error(`[DelegationsWidget] createDelegation: paymentMethodId is required`);this.mountIframe(`/embed/cards/delegate`,e.container,{paymentMethodId:e.paymentMethodId}).onMessage(t=>this.handleCreateDelegationMessage(t,e))}async revokeCard(e){if(typeof e!=`string`||e.length===0)throw Error(`[DelegationsWidget] revokeCard: paymentMethodId is required`);await this.deleteWithSession(`${this.apiBase}/api/v1/widgets/payment-methods/${encodeURIComponent(e)}`,`Failed to revoke payment method`)}async revokeDelegation(e){if(typeof e!=`string`||e.length===0)throw Error(`[DelegationsWidget] revokeDelegation: delegationId is required`);await this.deleteWithSession(`${this.apiBase}/api/v1/widgets/delegation/${encodeURIComponent(e)}`,`Failed to revoke delegation`)}destroy(){this.destroyed=!0,this.manager?.destroy(),this.manager=null}assertAlive(e){if(this.destroyed)throw Error(`[DelegationsWidget] cannot ${e}: instance has been destroyed`)}mountIframe(e,t,n={}){this.manager?.destroy();let r=new URL(this.webappBase).origin,i=window.location.origin,a=new URL(e,this.webappBase);a.searchParams.set(`parentOrigin`,i);for(let[e,t]of Object.entries(n))a.searchParams.set(e,t);let o=new y(r);return this.manager=o,o.create(a.toString(),{container:t}),o}postInitOnBooted(){this.manager?.postMessage(_(p.INIT,{sessionToken:this.session.getToken()}))}handleEnrollMessage(e,t){switch(e.type){case p.BOOTED:this.postInitOnBooted(),t.onBooted?.();return;case p.READY:t.onReady?.();return;case p.SUCCESS:{let n=(e.payload??{}).paymentMethodId;if(typeof n!=`string`||n.length===0){t.onError?.(C);return}t.onSuccess?.({paymentMethodId:n});return}case p.ERROR:{let n=e.payload;t.onError?.(n?.error??S);return}case p.CLOSE:t.onClose?.(),this.destroy();return;default:return}}handleListMessage(e,t){switch(e.type){case p.BOOTED:this.postInitOnBooted(),t.onBooted?.();return;case p.READY:t.onReady?.();return;case p.CARD_ACTION:{let n=e.payload??{};if(n.action!==`delegate`||typeof n.paymentMethodId!=`string`||n.paymentMethodId.length===0)return;t.onCardAction?.({action:n.action,paymentMethodId:n.paymentMethodId});return}case p.ERROR:{let n=e.payload;t.onError?.(n?.error??S);return}case p.CLOSE:t.onClose?.(),this.destroy();return;default:return}}handleCreateDelegationMessage(e,t){switch(e.type){case p.BOOTED:this.postInitOnBooted(),t.onBooted?.();return;case p.READY:t.onReady?.();return;case p.SUCCESS:{let n=(e.payload??{}).delegationId;if(typeof n!=`string`||n.length===0){t.onError?.(w);return}t.onSuccess?.({delegationId:n,paymentMethodId:t.paymentMethodId});return}case p.ERROR:{let n=e.payload;t.onError?.(n?.error??S);return}case p.CLOSE:t.onClose?.(),this.destroy();return;default:return}}async deleteWithSession(e,t){let n;try{n=await fetch(e,{method:`DELETE`,headers:{Authorization:`Bearer ${this.session.getToken()}`,Accept:`application/json`}})}catch(e){throw new l(e instanceof Error&&e.message?e.message:t)}if(n.ok)return;let r,i=t;try{let e=await n.json();typeof e?.message==`string`&&e.message.length>0&&(i=e.message),typeof e?.code==`string`&&(r=e.code)}catch{}throw new l(i,n.status,r)}};function E(e){if(typeof e!=`object`||!e)return!1;let t=e;return[`sessionToken`,`userId`,`expiresAt`,`apiKeyHash`].every(e=>typeof t[e]==`string`)&&typeof t.userWallet==`string`&&t.userWallet.startsWith(`0x`)}var D=class e{_checkout=null;_delegations=null;events=new f;constructor(e,t,n){this.sessionManager=e,this._account=t,this.environment=n}static async initialize(n){let{initToken:r,environment:a}=n;if(!r||typeof r!=`string`)throw new s(`MISSING_INIT_TOKEN`);if(!a||!t.includes(a))throw new s(`INVALID_ENVIRONMENT`);let o=i(a),c;try{c=await fetch(`${o}/api/v1/widgets/session`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({initToken:r})})}catch(e){throw console.error(`[NeverminedWidgets] fetch failed:`,e),new s(`NETWORK_ERROR`,void 0,e)}if(!c.ok)throw c.status===401?new s(`INVALID_INIT_TOKEN`):new s(`NETWORK_ERROR`,`Request failed with status ${c.status}`);let l;try{l=await c.json()}catch(e){throw new s(`INVALID_RESPONSE`,void 0,e)}if(!E(l))throw new s(`INVALID_RESPONSE`);let u=new d(l),f=new e(u,{userId:l.userId,userWallet:l.userWallet},a);return u.startAutoRefresh(()=>f.refreshSession(),()=>f.events.emit(`session-expired`,void 0)),f}async refreshSession(){let e=await fetch(`${i(this.environment)}/api/v1/widgets/session/refresh`,{method:`POST`,headers:{Authorization:`Bearer ${this.sessionManager.getToken()}`}});if(!e.ok)throw Error(`Session refresh failed with status ${e.status}`);let t=await e.json();if(!E(t))throw Error(`Session refresh returned an invalid response`);return t}on(e,t){return this.events.on(e,t),this}off(e,t){return this.events.off(e,t),this}get account(){return this._account}get hasValidSession(){return this.sessionManager.isValid()}getSessionToken(){if(!this.sessionManager.isValid())throw new c;return this.sessionManager.getToken()}get checkout(){return this._checkout||=new x(this.sessionManager,a(this.environment)),this._checkout}get delegations(){return this._delegations||=new T(this.sessionManager,a(this.environment),i(this.environment)),this._delegations}destroy(){this.sessionManager.stopAutoRefresh(),this._checkout?.destroy(),this._checkout=null,this._delegations?.destroy(),this._delegations=null,this.events.removeAllListeners()}};e.CheckoutWidget=x,e.DelegationsWidget=T,e.IframeManager=y,e.NeverminedWidgets=D,e.SessionManager=d,e.TypedEventEmitter=f,e.WIDGET_MESSAGE_VERSION=m,e.WidgetApiError=l,e.WidgetInitError=s,e.WidgetMessageType=p,e.WidgetSessionExpiredError=c,e.createMessage=_,e.parseMessage=v});
1
+ (function(e,t){typeof exports==`object`&&typeof module<`u`?t(exports):typeof define==`function`&&define.amd?define([`exports`],t):(e=typeof globalThis<`u`?globalThis:e||self,t(e.NeverminedWidgets={}))})(this,function(e){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});var t=[`local`,`sandbox`,`live`,`staging_sandbox`,`staging_live`],n={local:`http://localhost:3001`,sandbox:`https://api.sandbox.nevermined.app`,live:`https://api.live.nevermined.app`,staging_sandbox:`https://api.sandbox.nevermined.dev`,staging_live:`https://api.live.nevermined.dev`},r={local:`http://localhost:4200`,sandbox:`https://nevermined.app`,live:`https://nevermined.app`,staging_sandbox:`https://nevermined.dev`,staging_live:`https://nevermined.dev`};function i(e){return n[e]}function a(e){return r[e]}var o={MISSING_INIT_TOKEN:{numericCode:`WDG.0001`,message:`initToken is required and must be a non-empty string`},INVALID_ENVIRONMENT:{numericCode:`WDG.0002`,message:`environment must be one of: sandbox, live, staging_sandbox, staging_live, local`},INVALID_INIT_TOKEN:{numericCode:`WDG.0003`,message:`Init token is invalid or expired`},INVALID_RESPONSE:{numericCode:`WDG.0004`,message:`Server response is missing required fields`},NETWORK_ERROR:{numericCode:`WDG.0005`,message:`Network request failed`},SESSION_EXPIRED:{numericCode:`WDG.0006`,message:`Widget session has expired`}},s=class extends Error{constructor(e,t,n){super(t??o[e].message,{cause:n}),this.code=e,this.name=`WidgetInitError`}},c=class extends Error{code=`SESSION_EXPIRED`;constructor(){super(o.SESSION_EXPIRED.message),this.name=`WidgetSessionExpiredError`}},l=class extends Error{constructor(e,t,n){super(e),this.status=t,this.apiCode=n,this.name=`WidgetApiError`}},u=.8,d=class{session;expiresMs;timer=null;constructor(e){this.session=e,this.expiresMs=new Date(e.expiresAt).getTime(),Number.isNaN(this.expiresMs)&&console.warn(`[SessionManager] malformed expiresAt, session will be treated as expired:`,e.expiresAt)}isValid(){return!Number.isNaN(this.expiresMs)&&this.expiresMs>Date.now()}getToken(){return this.session.sessionToken}getSession(){return this.session}startAutoRefresh(e,t){if(this.stopAutoRefresh(),!this.isValid()){t();return}let n=Math.max(0,Math.floor((this.expiresMs-Date.now())*u));this.timer=setTimeout(()=>{this.timer=null,e().then(n=>{if(this.session=n,this.expiresMs=new Date(n.expiresAt).getTime(),!this.isValid()){t();return}this.startAutoRefresh(e,t)},e=>{console.error(`[SessionManager] session refresh failed:`,e),t()})},n)}stopAutoRefresh(){this.timer!==null&&(clearTimeout(this.timer),this.timer=null)}},f=class{listeners=new Map;on(e,t){let n=this.listeners.get(e)??new Set;return n.add(t),this.listeners.set(e,n),this}off(e,t){let n=this.listeners.get(e);return n?(n.delete(t),n.size===0&&this.listeners.delete(e),this):this}once(e,t){let n=r=>{this.off(e,n),t(r)};return this.on(e,n)}removeAllListeners(e){return e===void 0?this.listeners.clear():this.listeners.delete(e),this}emit(e,t){let n=this.listeners.get(e);n&&[...n].forEach(e=>{try{e(t)}catch(e){console.error(`[TypedEventEmitter] Handler threw:`,e)}})}},p=function(e){return e.INIT=`nvm:init`,e.CLOSE=`nvm:close`,e.BOOTED=`nvm:booted`,e.READY=`nvm:ready`,e.RESIZE=`nvm:resize`,e.SUCCESS=`nvm:success`,e.ERROR=`nvm:error`,e.CARD_ACTION=`nvm:card-action`,e.AUTH_MISMATCH=`nvm:auth-mismatch`,e}({}),m=`1`,h=`1`;function g(e){return typeof e==`string`&&Object.values(p).includes(e)}function _(e,t){return{type:e,version:h,payload:t}}function v(e){if(typeof e!=`object`||!e)return{ok:!1,reason:`not an object`};let t=e;return g(t.type)?t.version===h?{ok:!0,message:{type:t.type,version:t.version,payload:t.payload}}:{ok:!1,reason:`version mismatch: received "${t.version}", expected "${h}"`}:{ok:!1,reason:typeof t.type==`string`&&t.type.startsWith(`nvm:`)?`unknown nvm: type "${t.type}"`:`missing or unknown type`}}var y=class{iframe=null;messageHandlers=new Set;protocolErrorHandlers=new Set;messageListener=null;destroyed=!1;constructor(e){if(this.expectedOrigin=e,e===`*`)throw Error(`[IframeManager] Wildcard origin "*" is not allowed — pass an explicit origin`)}create(e,t){this.iframe?.remove();let n=document.createElement(`iframe`);return n.src=e,n.style.width=`100%`,n.style.height=`100%`,n.style.border=`none`,n.style.display=`block`,n.setAttribute(`sandbox`,`allow-scripts allow-same-origin allow-forms`),t?.container||(n.style.position=`fixed`,n.style.top=`0`,n.style.left=`0`,n.style.right=`0`,n.style.bottom=`0`,n.style.zIndex=`9999`),t?.style&&Object.assign(n.style,t.style),(t?.container??document.body).appendChild(n),this.iframe=n,n}destroy(){this.destroyed=!0,this.messageListener&&=(window.removeEventListener(`message`,this.messageListener),null),this.messageHandlers.clear(),this.protocolErrorHandlers.clear(),this.iframe?.remove(),this.iframe=null}postMessage(e){this.destroyed||this.iframe?.contentWindow?.postMessage(e,this.expectedOrigin)}onMessage(e){return this.destroyed?()=>void 0:(this.messageHandlers.add(e),this.ensureListener(),()=>this.messageHandlers.delete(e))}onProtocolError(e){return this.destroyed?()=>void 0:(this.protocolErrorHandlers.add(e),this.ensureListener(),()=>this.protocolErrorHandlers.delete(e))}ensureListener(){this.messageListener||(this.messageListener=e=>{if(e.origin!==this.expectedOrigin)return;let t=v(e.data);if(!t.ok){console.warn(`[IframeManager] Discarding message from ${this.expectedOrigin}: ${t.reason}`),this.protocolErrorHandlers.forEach(e=>{try{e(t.reason)}catch(e){console.error(`[IframeManager] Protocol error handler threw:`,e)}});return}this.messageHandlers.forEach(e=>{try{e(t.message)}catch(e){console.error(`[IframeManager] Message handler threw:`,e)}})},window.addEventListener(`message`,this.messageListener))}},b={code:`UNKNOWN`,message:`Unknown widget error`},x=class{manager=null;destroyed=!1;constructor(e,t){this.session=e,this.webappBase=t}start(e){if(this.destroyed)throw Error(`[CheckoutWidget] cannot start: instance has been destroyed`);if(!e.did||typeof e.did!=`string`)throw Error(`[CheckoutWidget] did is required`);this.manager?.destroy();let t=new URL(this.webappBase).origin,n=window.location.origin,r=new URL(`/embed/checkout/${encodeURIComponent(e.did)}`,this.webappBase);r.searchParams.set(`parentOrigin`,n),e.planId&&r.searchParams.set(`planId`,e.planId);let i=new y(t);this.manager=i,i.create(r.toString(),{container:e.container}),i.onMessage(t=>this.handleMessage(t,e))}destroy(){this.destroyed=!0,this.manager?.destroy(),this.manager=null}handleMessage(e,t){switch(e.type){case p.BOOTED:this.manager?.postMessage(_(p.INIT,{sessionToken:this.session.getToken()})),t.onBooted?.();return;case p.READY:t.onReady?.();return;case p.SUCCESS:{let n=e.payload??{};t.onSuccess?.({did:n.did??t.did,planId:n.planId??t.planId,txHash:n.txHash});return}case p.ERROR:{let n=e.payload;t.onError?.(n?.error??b);return}case p.AUTH_MISMATCH:{let n=S(e.payload);n&&t.onAuthMismatch?.(n);return}case p.CLOSE:t.onClose?.(),this.destroy();return;default:return}}};function S(e){if(typeof e!=`object`||!e)return null;let t=e.expectedEmail;return typeof t!=`string`||t.length===0?null:{expectedEmail:t}}var C={code:`UNKNOWN`,message:`Unknown widget error`},w={code:`UNKNOWN`,message:`Malformed nvm:success payload — paymentMethodId missing or invalid`},T={code:`UNKNOWN`,message:`Malformed nvm:success payload — delegationId missing or invalid`},E=class{manager=null;destroyed=!1;constructor(e,t,n){this.session=e,this.webappBase=t,this.apiBase=n}enrollCard(e){this.assertAlive(`enrollCard`),this.mountIframe(`/embed/cards/enroll`,e.container).onMessage(t=>this.handleEnrollMessage(t,e))}listCards(e){this.assertAlive(`listCards`),this.mountIframe(`/embed/cards/list`,e.container).onMessage(t=>this.handleListMessage(t,e))}createDelegation(e){if(this.assertAlive(`createDelegation`),typeof e.paymentMethodId!=`string`||e.paymentMethodId.length===0)throw Error(`[DelegationsWidget] createDelegation: paymentMethodId is required`);this.mountIframe(`/embed/cards/delegate`,e.container,{paymentMethodId:e.paymentMethodId}).onMessage(t=>this.handleCreateDelegationMessage(t,e))}async revokeCard(e){if(typeof e!=`string`||e.length===0)throw Error(`[DelegationsWidget] revokeCard: paymentMethodId is required`);await this.deleteWithSession(`${this.apiBase}/api/v1/widgets/payment-methods/${encodeURIComponent(e)}`,`Failed to revoke payment method`)}async revokeDelegation(e){if(typeof e!=`string`||e.length===0)throw Error(`[DelegationsWidget] revokeDelegation: delegationId is required`);await this.deleteWithSession(`${this.apiBase}/api/v1/widgets/delegation/${encodeURIComponent(e)}`,`Failed to revoke delegation`)}destroy(){this.destroyed=!0,this.manager?.destroy(),this.manager=null}assertAlive(e){if(this.destroyed)throw Error(`[DelegationsWidget] cannot ${e}: instance has been destroyed`)}mountIframe(e,t,n={}){this.manager?.destroy();let r=new URL(this.webappBase).origin,i=window.location.origin,a=new URL(e,this.webappBase);a.searchParams.set(`parentOrigin`,i);for(let[e,t]of Object.entries(n))a.searchParams.set(e,t);let o=new y(r);return this.manager=o,o.create(a.toString(),{container:t}),o}postInitOnBooted(){this.manager?.postMessage(_(p.INIT,{sessionToken:this.session.getToken()}))}handleEnrollMessage(e,t){switch(e.type){case p.BOOTED:this.postInitOnBooted(),t.onBooted?.();return;case p.READY:t.onReady?.();return;case p.SUCCESS:{let n=(e.payload??{}).paymentMethodId;if(typeof n!=`string`||n.length===0){t.onError?.(w);return}t.onSuccess?.({paymentMethodId:n});return}case p.ERROR:{let n=e.payload;t.onError?.(n?.error??C);return}case p.AUTH_MISMATCH:{let n=S(e.payload);n&&t.onAuthMismatch?.(n);return}case p.CLOSE:t.onClose?.(),this.destroy();return;default:return}}handleListMessage(e,t){switch(e.type){case p.BOOTED:this.postInitOnBooted(),t.onBooted?.();return;case p.READY:t.onReady?.();return;case p.CARD_ACTION:{let n=e.payload??{};if(n.action!==`delegate`||typeof n.paymentMethodId!=`string`||n.paymentMethodId.length===0)return;t.onCardAction?.({action:n.action,paymentMethodId:n.paymentMethodId});return}case p.ERROR:{let n=e.payload;t.onError?.(n?.error??C);return}case p.AUTH_MISMATCH:{let n=S(e.payload);n&&t.onAuthMismatch?.(n);return}case p.CLOSE:t.onClose?.(),this.destroy();return;default:return}}handleCreateDelegationMessage(e,t){switch(e.type){case p.BOOTED:this.postInitOnBooted(),t.onBooted?.();return;case p.READY:t.onReady?.();return;case p.SUCCESS:{let n=(e.payload??{}).delegationId;if(typeof n!=`string`||n.length===0){t.onError?.(T);return}t.onSuccess?.({delegationId:n,paymentMethodId:t.paymentMethodId});return}case p.ERROR:{let n=e.payload;t.onError?.(n?.error??C);return}case p.AUTH_MISMATCH:{let n=S(e.payload);n&&t.onAuthMismatch?.(n);return}case p.CLOSE:t.onClose?.(),this.destroy();return;default:return}}async deleteWithSession(e,t){let n;try{n=await fetch(e,{method:`DELETE`,headers:{Authorization:`Bearer ${this.session.getToken()}`,Accept:`application/json`}})}catch(e){throw new l(e instanceof Error&&e.message?e.message:t)}if(n.ok)return;let r,i=t;try{let e=await n.json();typeof e?.message==`string`&&e.message.length>0&&(i=e.message),typeof e?.code==`string`&&(r=e.code)}catch{}throw new l(i,n.status,r)}};function D(e){if(typeof e!=`object`||!e)return!1;let t=e;return[`sessionToken`,`userId`,`expiresAt`,`apiKeyHash`].every(e=>typeof t[e]==`string`)&&typeof t.userWallet==`string`&&t.userWallet.startsWith(`0x`)}var O=class e{_checkout=null;_delegations=null;events=new f;constructor(e,t,n){this.sessionManager=e,this._account=t,this.environment=n}static async initialize(n){let{initToken:r,environment:a}=n;if(!r||typeof r!=`string`)throw new s(`MISSING_INIT_TOKEN`);if(!a||!t.includes(a))throw new s(`INVALID_ENVIRONMENT`);let o=i(a),c;try{c=await fetch(`${o}/api/v1/widgets/session`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({initToken:r})})}catch(e){throw console.error(`[NeverminedWidgets] fetch failed:`,e),new s(`NETWORK_ERROR`,void 0,e)}if(!c.ok)throw c.status===401?new s(`INVALID_INIT_TOKEN`):new s(`NETWORK_ERROR`,`Request failed with status ${c.status}`);let l;try{l=await c.json()}catch(e){throw new s(`INVALID_RESPONSE`,void 0,e)}if(!D(l))throw new s(`INVALID_RESPONSE`);let u=new d(l),f=new e(u,{userId:l.userId,userWallet:l.userWallet},a);return u.startAutoRefresh(()=>f.refreshSession(),()=>f.events.emit(`session-expired`,void 0)),f}async refreshSession(){let e=await fetch(`${i(this.environment)}/api/v1/widgets/session/refresh`,{method:`POST`,headers:{Authorization:`Bearer ${this.sessionManager.getToken()}`}});if(!e.ok)throw Error(`Session refresh failed with status ${e.status}`);let t=await e.json();if(!D(t))throw Error(`Session refresh returned an invalid response`);return t}on(e,t){return this.events.on(e,t),this}off(e,t){return this.events.off(e,t),this}get account(){return this._account}get hasValidSession(){return this.sessionManager.isValid()}getSessionToken(){if(!this.sessionManager.isValid())throw new c;return this.sessionManager.getToken()}get checkout(){return this._checkout||=new x(this.sessionManager,a(this.environment)),this._checkout}get delegations(){return this._delegations||=new E(this.sessionManager,a(this.environment),i(this.environment)),this._delegations}destroy(){this.sessionManager.stopAutoRefresh(),this._checkout?.destroy(),this._checkout=null,this._delegations?.destroy(),this._delegations=null,this.events.removeAllListeners()}};e.CheckoutWidget=x,e.DelegationsWidget=E,e.IframeManager=y,e.NeverminedWidgets=O,e.SessionManager=d,e.TypedEventEmitter=f,e.WIDGET_MESSAGE_VERSION=m,e.WidgetApiError=l,e.WidgetInitError=s,e.WidgetMessageType=p,e.WidgetSessionExpiredError=c,e.createMessage=_,e.parseMessage=v});
package/dist/index.mjs CHANGED
@@ -131,7 +131,7 @@ var a = {
131
131
  });
132
132
  }
133
133
  }, f = /* @__PURE__ */ function(e) {
134
- return e.INIT = "nvm:init", e.CLOSE = "nvm:close", e.BOOTED = "nvm:booted", e.READY = "nvm:ready", e.RESIZE = "nvm:resize", e.SUCCESS = "nvm:success", e.ERROR = "nvm:error", e.CARD_ACTION = "nvm:card-action", e;
134
+ return e.INIT = "nvm:init", e.CLOSE = "nvm:close", e.BOOTED = "nvm:booted", e.READY = "nvm:ready", e.RESIZE = "nvm:resize", e.SUCCESS = "nvm:success", e.ERROR = "nvm:error", e.CARD_ACTION = "nvm:card-action", e.AUTH_MISMATCH = "nvm:auth-mismatch", e;
135
135
  }({}), p = "1", m = "1";
136
136
  function h(e) {
137
137
  return typeof e == "string" && Object.values(f).includes(e);
@@ -258,22 +258,35 @@ var v = class {
258
258
  t.onError?.(n?.error ?? y);
259
259
  return;
260
260
  }
261
+ case f.AUTH_MISMATCH: {
262
+ let n = x(e.payload);
263
+ n && t.onAuthMismatch?.(n);
264
+ return;
265
+ }
261
266
  case f.CLOSE:
262
267
  t.onClose?.(), this.destroy();
263
268
  return;
264
269
  default: return;
265
270
  }
266
271
  }
267
- }, x = {
272
+ };
273
+ function x(e) {
274
+ if (typeof e != "object" || !e) return null;
275
+ let t = e.expectedEmail;
276
+ return typeof t != "string" || t.length === 0 ? null : { expectedEmail: t };
277
+ }
278
+ //#endregion
279
+ //#region src/widgets/delegations.ts
280
+ var S = {
268
281
  code: "UNKNOWN",
269
282
  message: "Unknown widget error"
270
- }, S = {
283
+ }, C = {
271
284
  code: "UNKNOWN",
272
285
  message: "Malformed nvm:success payload — paymentMethodId missing or invalid"
273
- }, C = {
286
+ }, w = {
274
287
  code: "UNKNOWN",
275
288
  message: "Malformed nvm:success payload — delegationId missing or invalid"
276
- }, w = class {
289
+ }, T = class {
277
290
  manager = null;
278
291
  destroyed = !1;
279
292
  constructor(e, t, n) {
@@ -325,7 +338,7 @@ var v = class {
325
338
  case f.SUCCESS: {
326
339
  let n = (e.payload ?? {}).paymentMethodId;
327
340
  if (typeof n != "string" || n.length === 0) {
328
- t.onError?.(S);
341
+ t.onError?.(C);
329
342
  return;
330
343
  }
331
344
  t.onSuccess?.({ paymentMethodId: n });
@@ -333,7 +346,12 @@ var v = class {
333
346
  }
334
347
  case f.ERROR: {
335
348
  let n = e.payload;
336
- t.onError?.(n?.error ?? x);
349
+ t.onError?.(n?.error ?? S);
350
+ return;
351
+ }
352
+ case f.AUTH_MISMATCH: {
353
+ let n = x(e.payload);
354
+ n && t.onAuthMismatch?.(n);
337
355
  return;
338
356
  }
339
357
  case f.CLOSE:
@@ -361,7 +379,12 @@ var v = class {
361
379
  }
362
380
  case f.ERROR: {
363
381
  let n = e.payload;
364
- t.onError?.(n?.error ?? x);
382
+ t.onError?.(n?.error ?? S);
383
+ return;
384
+ }
385
+ case f.AUTH_MISMATCH: {
386
+ let n = x(e.payload);
387
+ n && t.onAuthMismatch?.(n);
365
388
  return;
366
389
  }
367
390
  case f.CLOSE:
@@ -381,7 +404,7 @@ var v = class {
381
404
  case f.SUCCESS: {
382
405
  let n = (e.payload ?? {}).delegationId;
383
406
  if (typeof n != "string" || n.length === 0) {
384
- t.onError?.(C);
407
+ t.onError?.(w);
385
408
  return;
386
409
  }
387
410
  t.onSuccess?.({
@@ -392,7 +415,12 @@ var v = class {
392
415
  }
393
416
  case f.ERROR: {
394
417
  let n = e.payload;
395
- t.onError?.(n?.error ?? x);
418
+ t.onError?.(n?.error ?? S);
419
+ return;
420
+ }
421
+ case f.AUTH_MISMATCH: {
422
+ let n = x(e.payload);
423
+ n && t.onAuthMismatch?.(n);
396
424
  return;
397
425
  }
398
426
  case f.CLOSE:
@@ -425,7 +453,7 @@ var v = class {
425
453
  };
426
454
  //#endregion
427
455
  //#region src/nevermined-widgets.ts
428
- function T(e) {
456
+ function E(e) {
429
457
  if (typeof e != "object" || !e) return !1;
430
458
  let t = e;
431
459
  return [
@@ -435,7 +463,7 @@ function T(e) {
435
463
  "apiKeyHash"
436
464
  ].every((e) => typeof t[e] == "string") && typeof t.userWallet == "string" && t.userWallet.startsWith("0x");
437
465
  }
438
- var E = class t {
466
+ var D = class t {
439
467
  _checkout = null;
440
468
  _delegations = null;
441
469
  events = new d();
@@ -463,7 +491,7 @@ var E = class t {
463
491
  } catch (e) {
464
492
  throw new o("INVALID_RESPONSE", void 0, e);
465
493
  }
466
- if (!T(l)) throw new o("INVALID_RESPONSE");
494
+ if (!E(l)) throw new o("INVALID_RESPONSE");
467
495
  let d = new u(l), f = new t(d, {
468
496
  userId: l.userId,
469
497
  userWallet: l.userWallet
@@ -477,7 +505,7 @@ var E = class t {
477
505
  });
478
506
  if (!e.ok) throw Error(`Session refresh failed with status ${e.status}`);
479
507
  let t = await e.json();
480
- if (!T(t)) throw Error("Session refresh returned an invalid response");
508
+ if (!E(t)) throw Error("Session refresh returned an invalid response");
481
509
  return t;
482
510
  }
483
511
  on(e, t) {
@@ -500,11 +528,11 @@ var E = class t {
500
528
  return this._checkout ||= new b(this.sessionManager, i(this.environment)), this._checkout;
501
529
  }
502
530
  get delegations() {
503
- return this._delegations ||= new w(this.sessionManager, i(this.environment), r(this.environment)), this._delegations;
531
+ return this._delegations ||= new T(this.sessionManager, i(this.environment), r(this.environment)), this._delegations;
504
532
  }
505
533
  destroy() {
506
534
  this.sessionManager.stopAutoRefresh(), this._checkout?.destroy(), this._checkout = null, this._delegations?.destroy(), this._delegations = null, this.events.removeAllListeners();
507
535
  }
508
536
  };
509
537
  //#endregion
510
- export { b as CheckoutWidget, w as DelegationsWidget, v as IframeManager, E as NeverminedWidgets, u as SessionManager, d as TypedEventEmitter, p as WIDGET_MESSAGE_VERSION, c as WidgetApiError, o as WidgetInitError, f as WidgetMessageType, s as WidgetSessionExpiredError, g as createMessage, _ as parseMessage };
538
+ export { b as CheckoutWidget, T as DelegationsWidget, v as IframeManager, D as NeverminedWidgets, u as SessionManager, d as TypedEventEmitter, p as WIDGET_MESSAGE_VERSION, c as WidgetApiError, o as WidgetInitError, f as WidgetMessageType, s as WidgetSessionExpiredError, g as createMessage, _ as parseMessage };
@@ -0,0 +1,27 @@
1
+ export declare enum WidgetMessageType {
2
+ INIT = "nvm:init",
3
+ CLOSE = "nvm:close",
4
+ BOOTED = "nvm:booted",
5
+ READY = "nvm:ready",
6
+ RESIZE = "nvm:resize",
7
+ SUCCESS = "nvm:success",
8
+ ERROR = "nvm:error",
9
+ CARD_ACTION = "nvm:card-action",
10
+ AUTH_MISMATCH = "nvm:auth-mismatch"
11
+ }
12
+ export interface WidgetMessage<T = unknown> {
13
+ type: WidgetMessageType;
14
+ version: '1';
15
+ payload?: T;
16
+ }
17
+ export declare const WIDGET_MESSAGE_VERSION: "1";
18
+ export declare function createMessage<T>(type: WidgetMessageType, payload?: T): WidgetMessage<T>;
19
+ export type ParseResult<T = unknown> = {
20
+ ok: true;
21
+ message: WidgetMessage<T>;
22
+ } | {
23
+ ok: false;
24
+ reason: string;
25
+ };
26
+ export declare function parseMessage(data: unknown): ParseResult;
27
+ //# sourceMappingURL=messages.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../src/messages.ts"],"names":[],"mappings":"AAAA,oBAAY,iBAAiB;IAE3B,IAAI,aAAa;IACjB,KAAK,cAAc;IAEnB,MAAM,eAAe;IACrB,KAAK,cAAc;IACnB,MAAM,eAAe;IACrB,OAAO,gBAAgB;IACvB,KAAK,cAAc;IAInB,WAAW,oBAAoB;IAI/B,aAAa,sBAAsB;CACpC;AAED,MAAM,WAAW,aAAa,CAAC,CAAC,GAAG,OAAO;IACxC,IAAI,EAAE,iBAAiB,CAAA;IACvB,OAAO,EAAE,GAAG,CAAA;IACZ,OAAO,CAAC,EAAE,CAAC,CAAA;CACZ;AAED,eAAO,MAAM,sBAAsB,EAAG,GAAY,CAAA;AAWlD,wBAAgB,aAAa,CAAC,CAAC,EAAE,IAAI,EAAE,iBAAiB,EAAE,OAAO,CAAC,EAAE,CAAC,GAAG,aAAa,CAAC,CAAC,CAAC,CAMvF;AAED,MAAM,MAAM,WAAW,CAAC,CAAC,GAAG,OAAO,IAC/B;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,OAAO,EAAE,aAAa,CAAC,CAAC,CAAC,CAAA;CAAE,GACvC;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAA;AAEjC,wBAAgB,YAAY,CAAC,IAAI,EAAE,OAAO,GAAG,WAAW,CA8BvD"}
@@ -0,0 +1,36 @@
1
+ import type { WidgetConfig, WidgetAccount } from './types.js';
2
+ import { CheckoutWidget } from './widgets/checkout.js';
3
+ import { DelegationsWidget } from './widgets/delegations.js';
4
+ interface NeverminedWidgetsEvents {
5
+ 'session-expired': void;
6
+ }
7
+ export declare class NeverminedWidgets {
8
+ private readonly sessionManager;
9
+ private readonly _account;
10
+ private readonly environment;
11
+ private _checkout;
12
+ private _delegations;
13
+ private readonly events;
14
+ private constructor();
15
+ static initialize(config: WidgetConfig): Promise<NeverminedWidgets>;
16
+ private refreshSession;
17
+ on<K extends keyof NeverminedWidgetsEvents>(event: K, handler: (payload: NeverminedWidgetsEvents[K]) => void): this;
18
+ off<K extends keyof NeverminedWidgetsEvents>(event: K, handler: (payload: NeverminedWidgetsEvents[K]) => void): this;
19
+ get account(): WidgetAccount;
20
+ get hasValidSession(): boolean;
21
+ getSessionToken(): string;
22
+ get checkout(): CheckoutWidget;
23
+ get delegations(): DelegationsWidget;
24
+ /**
25
+ * Resets the parent widget container: tears down any live child widget (e.g.
26
+ * the checkout widget) and clears the internal cache. This is a reset, not a
27
+ * terminal state — accessing `widget.checkout` after `destroy()` lazily
28
+ * creates a fresh `CheckoutWidget` instance. If you need a terminal "this
29
+ * widget can no longer be used" semantics, call `destroy()` on the child
30
+ * widget directly (e.g. `widget.checkout.destroy()`), which flips its
31
+ * internal `destroyed` flag and makes subsequent `start()` calls throw.
32
+ */
33
+ destroy(): void;
34
+ }
35
+ export {};
36
+ //# sourceMappingURL=nevermined-widgets.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nevermined-widgets.d.ts","sourceRoot":"","sources":["../src/nevermined-widgets.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAA8B,MAAM,YAAY,CAAA;AAMzF,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAA;AAE5D,UAAU,uBAAuB;IAC/B,iBAAiB,EAAE,IAAI,CAAA;CACxB;AAYD,qBAAa,iBAAiB;IAM1B,OAAO,CAAC,QAAQ,CAAC,cAAc;IAC/B,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,WAAW;IAP9B,OAAO,CAAC,SAAS,CAA8B;IAC/C,OAAO,CAAC,YAAY,CAAiC;IACrD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAmD;IAE1E,OAAO;WAMM,UAAU,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,iBAAiB,CAAC;YA+C3D,cAAc;IAwB5B,EAAE,CAAC,CAAC,SAAS,MAAM,uBAAuB,EACxC,KAAK,EAAE,CAAC,EACR,OAAO,EAAE,CAAC,OAAO,EAAE,uBAAuB,CAAC,CAAC,CAAC,KAAK,IAAI,GACrD,IAAI;IAKP,GAAG,CAAC,CAAC,SAAS,MAAM,uBAAuB,EACzC,KAAK,EAAE,CAAC,EACR,OAAO,EAAE,CAAC,OAAO,EAAE,uBAAuB,CAAC,CAAC,CAAC,KAAK,IAAI,GACrD,IAAI;IAKP,IAAI,OAAO,IAAI,aAAa,CAE3B;IAED,IAAI,eAAe,IAAI,OAAO,CAE7B;IAED,eAAe,IAAI,MAAM;IAKzB,IAAI,QAAQ,IAAI,cAAc,CAK7B;IAED,IAAI,WAAW,IAAI,iBAAiB,CASnC;IAED;;;;;;;;OAQG;IACH,OAAO,IAAI,IAAI;CAQhB"}
@@ -0,0 +1,13 @@
1
+ import type { WidgetSession } from './types.js';
2
+ export declare class SessionManager {
3
+ private session;
4
+ private expiresMs;
5
+ private timer;
6
+ constructor(session: WidgetSession);
7
+ isValid(): boolean;
8
+ getToken(): string;
9
+ getSession(): WidgetSession;
10
+ startAutoRefresh(refreshFn: () => Promise<WidgetSession>, onExpired: () => void): void;
11
+ stopAutoRefresh(): void;
12
+ }
13
+ //# sourceMappingURL=session.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAI/C,qBAAa,cAAc;IACzB,OAAO,CAAC,OAAO,CAAe;IAC9B,OAAO,CAAC,SAAS,CAAQ;IACzB,OAAO,CAAC,KAAK,CAA6C;gBAE9C,OAAO,EAAE,aAAa;IAWlC,OAAO,IAAI,OAAO;IAIlB,QAAQ,IAAI,MAAM;IAIlB,UAAU,IAAI,aAAa;IAI3B,gBAAgB,CAAC,SAAS,EAAE,MAAM,OAAO,CAAC,aAAa,CAAC,EAAE,SAAS,EAAE,MAAM,IAAI,GAAG,IAAI;IA8BtF,eAAe,IAAI,IAAI;CAMxB"}
@@ -0,0 +1,44 @@
1
+ export declare const ENVIRONMENTS: readonly ["local", "sandbox", "live", "staging_sandbox", "staging_live"];
2
+ export type Environment = (typeof ENVIRONMENTS)[number];
3
+ export interface WidgetConfig {
4
+ initToken: string;
5
+ environment: Environment;
6
+ }
7
+ export interface WidgetSession {
8
+ sessionToken: string;
9
+ userId: string;
10
+ userWallet: `0x${string}`;
11
+ /**
12
+ * Hash of the NVM API key bound to this widget session user. Returned by
13
+ * `POST /api/v1/widgets/session` so host pages that want to call user-scoped
14
+ * endpoints directly (outside the iframe) have the bearer token to do so.
15
+ * The embedded iframe flow consumes it via the session JWT claims rather
16
+ * than this field.
17
+ */
18
+ apiKeyHash: string;
19
+ expiresAt: string;
20
+ }
21
+ export interface WidgetAccount {
22
+ userId: string;
23
+ userWallet: `0x${string}`;
24
+ }
25
+ export interface EmbedError {
26
+ code: 'UNAUTHORIZED' | 'NETWORK' | 'PAYMENT_NOT_CONFIRMED' | 'UNKNOWN';
27
+ message: string;
28
+ status?: number;
29
+ apiCode?: string;
30
+ }
31
+ /**
32
+ * Emitted (via the per-widget `onAuthMismatch` callback) when the iframe
33
+ * detects a live host Privy session whose email does not match the email
34
+ * baked into the widget init token. The iframe renders a blocking panel and
35
+ * the host page is informed so it can surface its own "switch account"
36
+ * affordance. After this fires the widget is effectively halted — the user
37
+ * has to log out of the host site as the expected identity for the flow to
38
+ * become usable again.
39
+ */
40
+ export interface AuthMismatchDetail {
41
+ /** Email expected by the widget init token (normalized — trimmed, lower-cased). */
42
+ expectedEmail: string;
43
+ }
44
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,YAAY,0EAA2E,CAAA;AACpG,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,CAAC,CAAA;AAEvD,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,MAAM,CAAA;IACjB,WAAW,EAAE,WAAW,CAAA;CACzB;AAED,MAAM,WAAW,aAAa;IAC5B,YAAY,EAAE,MAAM,CAAA;IACpB,MAAM,EAAE,MAAM,CAAA;IACd,UAAU,EAAE,KAAK,MAAM,EAAE,CAAA;IACzB;;;;;;OAMG;IACH,UAAU,EAAE,MAAM,CAAA;IAClB,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAA;IACd,UAAU,EAAE,KAAK,MAAM,EAAE,CAAA;CAC1B;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,cAAc,GAAG,SAAS,GAAG,uBAAuB,GAAG,SAAS,CAAA;IACtE,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,kBAAkB;IACjC,mFAAmF;IACnF,aAAa,EAAE,MAAM,CAAA;CACtB"}
@@ -0,0 +1,4 @@
1
+ import type { Environment } from '../types.js';
2
+ export declare function getApiBaseUrl(environment: Environment): string;
3
+ export declare function getWebappBaseUrl(environment: Environment): string;
4
+ //# sourceMappingURL=environment.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"environment.d.ts","sourceRoot":"","sources":["../../src/utils/environment.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAkB9C,wBAAgB,aAAa,CAAC,WAAW,EAAE,WAAW,GAAG,MAAM,CAE9D;AAED,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,WAAW,GAAG,MAAM,CAEjE"}
@@ -0,0 +1,47 @@
1
+ export declare const WIDGET_ERRORS: {
2
+ readonly MISSING_INIT_TOKEN: {
3
+ readonly numericCode: "WDG.0001";
4
+ readonly message: "initToken is required and must be a non-empty string";
5
+ };
6
+ readonly INVALID_ENVIRONMENT: {
7
+ readonly numericCode: "WDG.0002";
8
+ readonly message: "environment must be one of: sandbox, live, staging_sandbox, staging_live, local";
9
+ };
10
+ readonly INVALID_INIT_TOKEN: {
11
+ readonly numericCode: "WDG.0003";
12
+ readonly message: "Init token is invalid or expired";
13
+ };
14
+ readonly INVALID_RESPONSE: {
15
+ readonly numericCode: "WDG.0004";
16
+ readonly message: "Server response is missing required fields";
17
+ };
18
+ readonly NETWORK_ERROR: {
19
+ readonly numericCode: "WDG.0005";
20
+ readonly message: "Network request failed";
21
+ };
22
+ readonly SESSION_EXPIRED: {
23
+ readonly numericCode: "WDG.0006";
24
+ readonly message: "Widget session has expired";
25
+ };
26
+ };
27
+ export type WidgetErrorCode = keyof typeof WIDGET_ERRORS;
28
+ export declare class WidgetInitError extends Error {
29
+ readonly code: WidgetErrorCode;
30
+ constructor(code: WidgetErrorCode, message?: string, cause?: unknown);
31
+ }
32
+ export declare class WidgetSessionExpiredError extends Error {
33
+ readonly code: "SESSION_EXPIRED";
34
+ constructor();
35
+ }
36
+ /**
37
+ * Thrown by SDK methods that hit the API directly (no iframe), e.g.
38
+ * `delegations.revokeCard()` / `delegations.revokeDelegation()`. Carries the
39
+ * HTTP status and the optional BCK error code so consumers can branch on
40
+ * 401/403/etc. without parsing the message.
41
+ */
42
+ export declare class WidgetApiError extends Error {
43
+ readonly status?: number | undefined;
44
+ readonly apiCode?: string | undefined;
45
+ constructor(message: string, status?: number | undefined, apiCode?: string | undefined);
46
+ }
47
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/utils/errors.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;CAgBmD,CAAA;AAE7E,MAAM,MAAM,eAAe,GAAG,MAAM,OAAO,aAAa,CAAA;AAExD,qBAAa,eAAgB,SAAQ,KAAK;aAEtB,IAAI,EAAE,eAAe;gBAArB,IAAI,EAAE,eAAe,EACrC,OAAO,CAAC,EAAE,MAAM,EAChB,KAAK,CAAC,EAAE,OAAO;CAKlB;AAED,qBAAa,yBAA0B,SAAQ,KAAK;IAClD,QAAQ,CAAC,IAAI,EAAG,iBAAiB,CAAS;;CAM3C;AAED;;;;;GAKG;AACH,qBAAa,cAAe,SAAQ,KAAK;aAGrB,MAAM,CAAC,EAAE,MAAM;aACf,OAAO,CAAC,EAAE,MAAM;gBAFhC,OAAO,EAAE,MAAM,EACC,MAAM,CAAC,EAAE,MAAM,YAAA,EACf,OAAO,CAAC,EAAE,MAAM,YAAA;CAKnC"}
@@ -0,0 +1,54 @@
1
+ import { SessionManager } from '../session.js';
2
+ import type { AuthMismatchDetail, EmbedError } from '../types.js';
3
+ export interface CheckoutResult {
4
+ did: string;
5
+ planId?: string;
6
+ txHash?: string;
7
+ }
8
+ export interface CheckoutOptions {
9
+ did: string;
10
+ planId?: string;
11
+ container?: HTMLElement;
12
+ onBooted?: () => void;
13
+ onReady?: () => void;
14
+ onSuccess?: (result: CheckoutResult) => void;
15
+ onError?: (error: EmbedError) => void;
16
+ /**
17
+ * Fires when the iframe detects that the live host Privy session belongs
18
+ * to a different account than the email baked into the widget init token.
19
+ * The iframe stays mounted on a blocking panel; the host should react by
20
+ * surfacing its own "switch account" UI. See `AuthMismatchDetail`.
21
+ */
22
+ onAuthMismatch?: (detail: AuthMismatchDetail) => void;
23
+ onClose?: () => void;
24
+ }
25
+ /**
26
+ * Checkout widget.
27
+ *
28
+ * Lifecycle note for SDK consumers: when the iframe sends `nvm:close` the
29
+ * widget instance auto-calls `destroy()` and becomes terminal — any
30
+ * subsequent `start()` call throws. If the host page needs to re-show the
31
+ * checkout after a close, construct a new `CheckoutWidget` (typically via
32
+ * `nvm.checkout`) and call `start()` on the fresh instance.
33
+ */
34
+ export declare class CheckoutWidget {
35
+ private readonly session;
36
+ private readonly webappBase;
37
+ private manager;
38
+ private destroyed;
39
+ constructor(session: SessionManager, webappBase: string);
40
+ /**
41
+ * Mounts the checkout iframe into `options.container`.
42
+ * Throws if called after `destroy()` (including the implicit destroy on
43
+ * `nvm:close` — see class JSDoc).
44
+ */
45
+ start(options: CheckoutOptions): void;
46
+ destroy(): void;
47
+ private handleMessage;
48
+ }
49
+ /**
50
+ * Drop the message if the payload doesn't match the contract — keeps stray
51
+ * protocol updates from crashing host pages.
52
+ */
53
+ export declare function parseAuthMismatch(payload: unknown): AuthMismatchDetail | null;
54
+ //# sourceMappingURL=checkout.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"checkout.d.ts","sourceRoot":"","sources":["../../src/widgets/checkout.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AAE9C,OAAO,KAAK,EAAE,kBAAkB,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAEjE,MAAM,WAAW,cAAc;IAC7B,GAAG,EAAE,MAAM,CAAA;IACX,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,eAAe;IAC9B,GAAG,EAAE,MAAM,CAAA;IACX,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,SAAS,CAAC,EAAE,WAAW,CAAA;IACvB,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAA;IACrB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;IACpB,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,cAAc,KAAK,IAAI,CAAA;IAC5C,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAA;IACrC;;;;;OAKG;IACH,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,kBAAkB,KAAK,IAAI,CAAA;IACrD,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;CACrB;AAID;;;;;;;;GAQG;AACH,qBAAa,cAAc;IAKvB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,UAAU;IAL7B,OAAO,CAAC,OAAO,CAA6B;IAC5C,OAAO,CAAC,SAAS,CAAQ;gBAGN,OAAO,EAAE,cAAc,EACvB,UAAU,EAAE,MAAM;IAGrC;;;;OAIG;IACH,KAAK,CAAC,OAAO,EAAE,eAAe,GAAG,IAAI;IAwBrC,OAAO,IAAI,IAAI;IAMf,OAAO,CAAC,aAAa;CA4CtB;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,OAAO,GAAG,kBAAkB,GAAG,IAAI,CAK7E"}
@@ -0,0 +1,109 @@
1
+ import { SessionManager } from '../session.js';
2
+ import type { AuthMismatchDetail, EmbedError } from '../types.js';
3
+ export interface EnrollCardResult {
4
+ paymentMethodId: string;
5
+ }
6
+ export interface EnrollCardOptions {
7
+ container?: HTMLElement;
8
+ onBooted?: () => void;
9
+ onReady?: () => void;
10
+ onSuccess?: (result: EnrollCardResult) => void;
11
+ onError?: (error: EmbedError) => void;
12
+ /** See `CheckoutOptions.onAuthMismatch`. */
13
+ onAuthMismatch?: (detail: AuthMismatchDetail) => void;
14
+ onClose?: () => void;
15
+ }
16
+ export interface CardAction {
17
+ /** Currently the only emitted action; reserved as a discriminator for future ones. */
18
+ action: 'delegate';
19
+ paymentMethodId: string;
20
+ }
21
+ export interface ListCardsOptions {
22
+ container?: HTMLElement;
23
+ onBooted?: () => void;
24
+ onReady?: () => void;
25
+ onCardAction?: (action: CardAction) => void;
26
+ onError?: (error: EmbedError) => void;
27
+ /** See `CheckoutOptions.onAuthMismatch`. */
28
+ onAuthMismatch?: (detail: AuthMismatchDetail) => void;
29
+ onClose?: () => void;
30
+ }
31
+ export interface CreateDelegationResult {
32
+ delegationId: string;
33
+ paymentMethodId: string;
34
+ }
35
+ export interface CreateDelegationOptions {
36
+ paymentMethodId: string;
37
+ container?: HTMLElement;
38
+ onBooted?: () => void;
39
+ onReady?: () => void;
40
+ onSuccess?: (result: CreateDelegationResult) => void;
41
+ onError?: (error: EmbedError) => void;
42
+ /** See `CheckoutOptions.onAuthMismatch`. */
43
+ onAuthMismatch?: (detail: AuthMismatchDetail) => void;
44
+ onClose?: () => void;
45
+ }
46
+ /**
47
+ * Card and delegation management widget.
48
+ *
49
+ * Surfaces three iframe-based flows (enrollment, listing, delegation creation)
50
+ * and two SDK-direct revocations. The three iframe flows share the single
51
+ * `manager` slot — calling any of them destroys the previously-mounted iframe
52
+ * (same semantics as calling `enrollCard()` twice). Once any iframe is closed
53
+ * by the user (`nvm:close`), the instance is implicitly destroyed and any
54
+ * subsequent iframe call throws. Construct a fresh widget (via
55
+ * `nvm.delegations`) to mount another flow after a close.
56
+ *
57
+ * The two `revoke*` methods do NOT use an iframe — they hit the
58
+ * `/api/v1/widgets/...` endpoints directly with the widget session token.
59
+ * They exist because the SDK consumer on the host page only holds the widget
60
+ * session token; the apiKeyHash that gates the standard delegation/payment
61
+ * endpoints never leaves the embedded iframe.
62
+ */
63
+ export declare class DelegationsWidget {
64
+ private readonly session;
65
+ private readonly webappBase;
66
+ private readonly apiBase;
67
+ private manager;
68
+ private destroyed;
69
+ constructor(session: SessionManager, webappBase: string, apiBase: string);
70
+ /**
71
+ * Mounts the enrollment iframe at `/embed/cards/enroll`.
72
+ * Throws if called after `destroy()` (including the implicit destroy on
73
+ * `nvm:close` — see class JSDoc).
74
+ */
75
+ enrollCard(options: EnrollCardOptions): void;
76
+ /**
77
+ * Mounts the cards-list iframe at `/embed/cards/list`. Per-row actions
78
+ * (currently only "Create Delegation") are forwarded via `onCardAction` so
79
+ * the host can mount the appropriate follow-up widget.
80
+ */
81
+ listCards(options: ListCardsOptions): void;
82
+ /**
83
+ * Mounts the delegation creation iframe at `/embed/cards/delegate` for a
84
+ * specific payment method. The `paymentMethodId` is required and is passed
85
+ * as a search param so the embed route can scope the form to that card.
86
+ */
87
+ createDelegation(options: CreateDelegationOptions): void;
88
+ /**
89
+ * Revoke (detach) a payment method via the widget-prefixed API endpoint.
90
+ * Resolves on 2xx; throws `WidgetApiError` on any other response or
91
+ * network failure.
92
+ */
93
+ revokeCard(paymentMethodId: string): Promise<void>;
94
+ /**
95
+ * Revoke a delegation via the widget-prefixed API endpoint.
96
+ * Resolves on 2xx; throws `WidgetApiError` on any other response or
97
+ * network failure.
98
+ */
99
+ revokeDelegation(delegationId: string): Promise<void>;
100
+ destroy(): void;
101
+ private assertAlive;
102
+ private mountIframe;
103
+ private postInitOnBooted;
104
+ private handleEnrollMessage;
105
+ private handleListMessage;
106
+ private handleCreateDelegationMessage;
107
+ private deleteWithSession;
108
+ }
109
+ //# sourceMappingURL=delegations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delegations.d.ts","sourceRoot":"","sources":["../../src/widgets/delegations.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AAE9C,OAAO,KAAK,EAAE,kBAAkB,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAIjE,MAAM,WAAW,gBAAgB;IAC/B,eAAe,EAAE,MAAM,CAAA;CACxB;AAED,MAAM,WAAW,iBAAiB;IAChC,SAAS,CAAC,EAAE,WAAW,CAAA;IACvB,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAA;IACrB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;IACpB,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,gBAAgB,KAAK,IAAI,CAAA;IAC9C,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAA;IACrC,4CAA4C;IAC5C,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,kBAAkB,KAAK,IAAI,CAAA;IACrD,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;CACrB;AAED,MAAM,WAAW,UAAU;IACzB,sFAAsF;IACtF,MAAM,EAAE,UAAU,CAAA;IAClB,eAAe,EAAE,MAAM,CAAA;CACxB;AAED,MAAM,WAAW,gBAAgB;IAC/B,SAAS,CAAC,EAAE,WAAW,CAAA;IACvB,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAA;IACrB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;IACpB,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,IAAI,CAAA;IAC3C,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAA;IACrC,4CAA4C;IAC5C,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,kBAAkB,KAAK,IAAI,CAAA;IACrD,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;CACrB;AAED,MAAM,WAAW,sBAAsB;IACrC,YAAY,EAAE,MAAM,CAAA;IACpB,eAAe,EAAE,MAAM,CAAA;CACxB;AAED,MAAM,WAAW,uBAAuB;IACtC,eAAe,EAAE,MAAM,CAAA;IACvB,SAAS,CAAC,EAAE,WAAW,CAAA;IACvB,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAA;IACrB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;IACpB,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,sBAAsB,KAAK,IAAI,CAAA;IACpD,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAA;IACrC,4CAA4C;IAC5C,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,kBAAkB,KAAK,IAAI,CAAA;IACrD,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;CACrB;AAYD;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,iBAAiB;IAK1B,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,OAAO;IAN1B,OAAO,CAAC,OAAO,CAA6B;IAC5C,OAAO,CAAC,SAAS,CAAQ;gBAGN,OAAO,EAAE,cAAc,EACvB,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,MAAM;IAGlC;;;;OAIG;IACH,UAAU,CAAC,OAAO,EAAE,iBAAiB,GAAG,IAAI;IAM5C;;;;OAIG;IACH,SAAS,CAAC,OAAO,EAAE,gBAAgB,GAAG,IAAI;IAM1C;;;;OAIG;IACH,gBAAgB,CAAC,OAAO,EAAE,uBAAuB,GAAG,IAAI;IAWxD;;;;OAIG;IACG,UAAU,CAAC,eAAe,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAUxD;;;;OAIG;IACG,gBAAgB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAU3D,OAAO,IAAI,IAAI;IAMf,OAAO,CAAC,WAAW;IAMnB,OAAO,CAAC,WAAW;IAsBnB,OAAO,CAAC,gBAAgB;IAMxB,OAAO,CAAC,mBAAmB;IA4C3B,OAAO,CAAC,iBAAiB;IAmDzB,OAAO,CAAC,6BAA6B;YA+CvB,iBAAiB;CAgChC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nevermined-io/ui-widgets",
3
- "version": "0.4.6",
3
+ "version": "0.5.2",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",