@ledewire/browser 0.5.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -6
- package/dist/index.d.ts +138 -49
- package/dist/index.js +137 -87
- package/dist/index.js.map +1 -1
- package/dist/ledewire.min.js +1 -1
- package/dist/ledewire.min.js.map +1 -1
- package/llms.txt +28 -11
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -83,8 +83,8 @@ switch (checkout_state.next_required_action) {
|
|
|
83
83
|
const { content_type, content_body, content_uri } =
|
|
84
84
|
await lw.content.getWithAccess('article-123')
|
|
85
85
|
if (content_type === 'markdown') {
|
|
86
|
-
//
|
|
87
|
-
renderMarkdown(
|
|
86
|
+
// content_body is plain text — the SDK decodes base64 automatically
|
|
87
|
+
renderMarkdown(content_body)
|
|
88
88
|
} else {
|
|
89
89
|
// redirect to the gated external URI (Vimeo, PDF, etc.)
|
|
90
90
|
window.location.href = content_uri
|
|
@@ -95,14 +95,14 @@ switch (checkout_state.next_required_action) {
|
|
|
95
95
|
|
|
96
96
|
## Example: Seller Content Discovery
|
|
97
97
|
|
|
98
|
-
Use `lw.
|
|
98
|
+
Use `lw.seller.loginWithApiKey` with only the `key` to obtain a read-only token,
|
|
99
99
|
then browse your store's content catalogue directly from the browser:
|
|
100
100
|
|
|
101
101
|
```ts
|
|
102
102
|
const lw = Ledewire.init({ apiKey: 'your_api_key' })
|
|
103
103
|
|
|
104
104
|
// Obtain a view-only seller token (key only — no secret needed)
|
|
105
|
-
await lw.
|
|
105
|
+
await lw.seller.loginWithApiKey({ key: 'your_api_key' })
|
|
106
106
|
|
|
107
107
|
// List all content
|
|
108
108
|
const items = await lw.seller.content.list()
|
|
@@ -118,11 +118,16 @@ const item = await lw.seller.content.get('content-id')
|
|
|
118
118
|
## Token Storage
|
|
119
119
|
|
|
120
120
|
By default tokens are stored **in memory** (most secure — cleared on page unload).
|
|
121
|
-
|
|
121
|
+
Two built-in adapters are available for persistent sessions:
|
|
122
122
|
|
|
123
123
|
```ts
|
|
124
|
-
import { init, localStorageAdapter } from '@ledewire/browser'
|
|
124
|
+
import { init, localStorageAdapter, sessionStorageAdapter } from '@ledewire/browser'
|
|
125
|
+
|
|
126
|
+
// Persists across tabs and browser restarts
|
|
125
127
|
const lw = init({ apiKey: '...', storage: localStorageAdapter() })
|
|
128
|
+
|
|
129
|
+
// Persists within the current tab only (cleared on tab close)
|
|
130
|
+
const lw = init({ apiKey: '...', storage: sessionStorageAdapter() })
|
|
126
131
|
```
|
|
127
132
|
|
|
128
133
|
Token refresh is handled automatically — you never need to call a refresh method manually.
|
package/dist/index.d.ts
CHANGED
|
@@ -92,7 +92,7 @@ export declare interface AuthPasswordResetResponse {
|
|
|
92
92
|
declare type AuthSignupRequest = components['schemas']['AuthSignupRequest'];
|
|
93
93
|
|
|
94
94
|
/**
|
|
95
|
-
* Buyer authentication: signup, email/password login, Google OAuth.
|
|
95
|
+
* Buyer authentication: signup, email/password login, Google OAuth, password reset.
|
|
96
96
|
*
|
|
97
97
|
* Obtain via `lw.auth` — do not construct directly.
|
|
98
98
|
*
|
|
@@ -130,27 +130,6 @@ declare class BrowserAuthNamespace {
|
|
|
130
130
|
* @returns The authentication token response.
|
|
131
131
|
*/
|
|
132
132
|
loginWithGoogle(body: AuthLoginOAuthRequest): Promise<AuthenticationResponse>;
|
|
133
|
-
/**
|
|
134
|
-
* Log in using an API key to obtain a seller token.
|
|
135
|
-
* Provide only `key` for read-only (`view`) access.
|
|
136
|
-
* Provide both `key` and `secret` for read/write (`full`) access.
|
|
137
|
-
* Tokens are stored automatically after successful authentication.
|
|
138
|
-
*
|
|
139
|
-
* Use this before calling `lw.seller.content.*` methods.
|
|
140
|
-
*
|
|
141
|
-
* @param body - API key credentials.
|
|
142
|
-
* @returns The authentication token response.
|
|
143
|
-
*
|
|
144
|
-
* @example
|
|
145
|
-
* ```ts
|
|
146
|
-
* // View access (read-only) — sufficient for seller.content.list/search/get
|
|
147
|
-
* await lw.auth.loginWithApiKey({ key: 'your_api_key' })
|
|
148
|
-
*
|
|
149
|
-
* // Full access (read/write)
|
|
150
|
-
* await lw.auth.loginWithApiKey({ key: 'your_api_key', secret: 'your_secret' })
|
|
151
|
-
* ```
|
|
152
|
-
*/
|
|
153
|
-
loginWithApiKey(body: AuthLoginApiKeyRequest): Promise<AuthenticationResponse>;
|
|
154
133
|
/**
|
|
155
134
|
* Request a password reset code to be sent to the buyer's email address.
|
|
156
135
|
*
|
|
@@ -201,7 +180,7 @@ declare class BrowserClient {
|
|
|
201
180
|
readonly _config: BrowserClientConfig;
|
|
202
181
|
/** Platform-level public configuration (no auth required) */
|
|
203
182
|
readonly config: BrowserConfigNamespace;
|
|
204
|
-
/** Buyer authentication: email/password signup/login, Google, password reset */
|
|
183
|
+
/** Buyer authentication: email/password signup/login, Google OAuth, password reset */
|
|
205
184
|
readonly auth: BrowserAuthNamespace;
|
|
206
185
|
/** Checkout state machine: determines next action for a piece of content */
|
|
207
186
|
readonly checkout: CheckoutNamespace;
|
|
@@ -211,7 +190,7 @@ declare class BrowserClient {
|
|
|
211
190
|
readonly purchases: BrowserPurchasesNamespace;
|
|
212
191
|
/** Public content with per-user access information */
|
|
213
192
|
readonly content: BrowserContentNamespace;
|
|
214
|
-
/** Seller
|
|
193
|
+
/** Seller operations: API key login, content list/search/get */
|
|
215
194
|
readonly seller: BrowserSellerNamespace;
|
|
216
195
|
/* Excluded from this release type: __constructor */
|
|
217
196
|
}
|
|
@@ -286,8 +265,10 @@ declare class BrowserConfigNamespace {
|
|
|
286
265
|
*
|
|
287
266
|
* @example
|
|
288
267
|
* ```ts
|
|
289
|
-
* const
|
|
290
|
-
* if (
|
|
268
|
+
* const result = await lw.content.getWithAccess('content-id')
|
|
269
|
+
* if (result.access_info.next_required_action === 'view_content') {
|
|
270
|
+
* renderMarkdown(result.content_body ?? '')
|
|
271
|
+
* }
|
|
291
272
|
* ```
|
|
292
273
|
*/
|
|
293
274
|
declare class BrowserContentNamespace {
|
|
@@ -298,10 +279,19 @@ declare class BrowserContentNamespace {
|
|
|
298
279
|
* authenticated buyer (or a generic access response when unauthenticated).
|
|
299
280
|
*
|
|
300
281
|
* @param id - The content ID.
|
|
301
|
-
* @
|
|
302
|
-
*
|
|
282
|
+
* @returns The content item with access information. `content_body` and
|
|
283
|
+
* `teaser` are returned as plain UTF-8 text — the SDK decodes base64
|
|
284
|
+
* transparently so you can render them directly.
|
|
285
|
+
*
|
|
286
|
+
* @example
|
|
287
|
+
* ```ts
|
|
288
|
+
* const result = await lw.content.getWithAccess('article-123')
|
|
289
|
+
* if (result.access_info.next_required_action === 'view_content') {
|
|
290
|
+
* renderMarkdown(result.content_body ?? '')
|
|
291
|
+
* }
|
|
292
|
+
* ```
|
|
303
293
|
*/
|
|
304
|
-
getWithAccess(id: string
|
|
294
|
+
getWithAccess(id: string): Promise<ContentWithAccessResponse>;
|
|
305
295
|
}
|
|
306
296
|
|
|
307
297
|
/**
|
|
@@ -348,7 +338,7 @@ declare class BrowserPurchasesNamespace {
|
|
|
348
338
|
* @example
|
|
349
339
|
* ```ts
|
|
350
340
|
* const lw = Ledewire.init({ apiKey: 'your_api_key' })
|
|
351
|
-
* await lw.
|
|
341
|
+
* await lw.seller.loginWithApiKey({ key: 'your_api_key' })
|
|
352
342
|
*
|
|
353
343
|
* const items = await lw.seller.content.list()
|
|
354
344
|
* const results = await lw.seller.content.search({ title: 'intro' })
|
|
@@ -362,7 +352,8 @@ declare class BrowserSellerContentNamespace {
|
|
|
362
352
|
* List all content for the authenticated seller's store.
|
|
363
353
|
* Requires a token with at least `view` permission.
|
|
364
354
|
*
|
|
365
|
-
* @returns Array of content items.
|
|
355
|
+
* @returns Array of content items. `teaser` is returned as plain text —
|
|
356
|
+
* the SDK decodes base64 automatically.
|
|
366
357
|
*
|
|
367
358
|
* @example
|
|
368
359
|
* ```ts
|
|
@@ -376,12 +367,14 @@ declare class BrowserSellerContentNamespace {
|
|
|
376
367
|
* Requires a token with at least `view` permission.
|
|
377
368
|
*
|
|
378
369
|
* @param body - Search criteria (title, uri, and/or metadata).
|
|
379
|
-
* @returns Array of matching content items.
|
|
370
|
+
* @returns Array of matching content items. `teaser` is returned as plain
|
|
371
|
+
* text — the SDK decodes base64 automatically.
|
|
380
372
|
*
|
|
381
373
|
* @example
|
|
382
374
|
* ```ts
|
|
383
375
|
* const results = await lw.seller.content.search({ title: 'intro' })
|
|
384
376
|
* const byUri = await lw.seller.content.search({ uri: 'vimeo.com' })
|
|
377
|
+
* const byId = await lw.seller.content.search({ external_identifier: 'vimeo:123456789' })
|
|
385
378
|
* const byMeta = await lw.seller.content.search({ metadata: { author: 'Alice' } })
|
|
386
379
|
* ```
|
|
387
380
|
*/
|
|
@@ -391,11 +384,14 @@ declare class BrowserSellerContentNamespace {
|
|
|
391
384
|
* Requires a token with at least `view` permission.
|
|
392
385
|
*
|
|
393
386
|
* @param id - The content ID.
|
|
394
|
-
* @returns The content item.
|
|
387
|
+
* @returns The content item. `content_body` and `teaser` are returned as
|
|
388
|
+
* plain UTF-8 text — the SDK decodes base64 automatically so you can render
|
|
389
|
+
* them directly without calling `atob()`.
|
|
395
390
|
*
|
|
396
391
|
* @example
|
|
397
392
|
* ```ts
|
|
398
393
|
* const item = await lw.seller.content.get('content-id')
|
|
394
|
+
* // item.content_body is plain markdown — no atob() needed
|
|
399
395
|
* ```
|
|
400
396
|
*/
|
|
401
397
|
get(id: string): Promise<ContentResponse>;
|
|
@@ -409,14 +405,39 @@ declare class BrowserSellerContentNamespace {
|
|
|
409
405
|
* @example
|
|
410
406
|
* ```ts
|
|
411
407
|
* const lw = Ledewire.init({ apiKey: 'your_api_key' })
|
|
412
|
-
*
|
|
408
|
+
*
|
|
409
|
+
* // Authenticate as a seller (key-only = view; key+secret = full)
|
|
410
|
+
* await lw.seller.loginWithApiKey({ key: 'your_api_key' })
|
|
413
411
|
* const items = await lw.seller.content.list()
|
|
414
412
|
* ```
|
|
415
413
|
*/
|
|
416
414
|
declare class BrowserSellerNamespace {
|
|
415
|
+
private readonly http;
|
|
416
|
+
private readonly tokenManager;
|
|
417
417
|
/** Seller content: list, search, and get by API key. */
|
|
418
418
|
readonly content: BrowserSellerContentNamespace;
|
|
419
419
|
/* Excluded from this release type: __constructor */
|
|
420
|
+
/**
|
|
421
|
+
* Log in using an API key to obtain a seller token.
|
|
422
|
+
* Provide only `key` for read-only (`view`) access.
|
|
423
|
+
* Provide both `key` and `secret` for read/write (`full`) access.
|
|
424
|
+
* Tokens are stored automatically after successful authentication.
|
|
425
|
+
*
|
|
426
|
+
* Use this before calling `lw.seller.content.*` methods.
|
|
427
|
+
*
|
|
428
|
+
* @param body - API key credentials.
|
|
429
|
+
* @returns The authentication token response.
|
|
430
|
+
*
|
|
431
|
+
* @example
|
|
432
|
+
* ```ts
|
|
433
|
+
* // View access (read-only) — sufficient for seller.content.list/search/get
|
|
434
|
+
* await lw.seller.loginWithApiKey({ key: 'your_api_key' })
|
|
435
|
+
*
|
|
436
|
+
* // Full access (read/write)
|
|
437
|
+
* await lw.seller.loginWithApiKey({ key: 'your_api_key', secret: 'your_secret' })
|
|
438
|
+
* ```
|
|
439
|
+
*/
|
|
440
|
+
loginWithApiKey(body: AuthLoginApiKeyRequest): Promise<AuthenticationResponse>;
|
|
420
441
|
}
|
|
421
442
|
|
|
422
443
|
/**
|
|
@@ -497,16 +518,19 @@ declare class CheckoutNamespace {
|
|
|
497
518
|
*/
|
|
498
519
|
export declare type CheckoutNextAction = 'authenticate' | 'fund_wallet' | 'purchase' | 'view_content';
|
|
499
520
|
|
|
500
|
-
/**
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
521
|
+
/**
|
|
522
|
+
* Checkout state machine result for a specific content item, as returned by
|
|
523
|
+
* `lw.checkout.state()`.
|
|
524
|
+
*
|
|
525
|
+
* This is a consumer-facing alias for {@link CheckoutStateResponse} — the two
|
|
526
|
+
* types are identical. Prefer `CheckoutState` in application code; use
|
|
527
|
+
* `CheckoutStateResponse` when you need to explicitly reference the OpenAPI
|
|
528
|
+
* schema name.
|
|
529
|
+
*
|
|
530
|
+
* Note: `checkout_state.has_sufficient_funds` is `boolean | null` because the
|
|
531
|
+
* API omits or nulls the field when the buyer is unauthenticated.
|
|
532
|
+
*/
|
|
533
|
+
export declare type CheckoutState = CheckoutStateResponse;
|
|
510
534
|
|
|
511
535
|
/** Full checkout state for a buyer/content pair, including auth and fund status. */
|
|
512
536
|
export declare type CheckoutStateResponse = components['schemas']['CheckoutStateResponse'];
|
|
@@ -688,7 +712,9 @@ declare interface components {
|
|
|
688
712
|
*/
|
|
689
713
|
currency: string;
|
|
690
714
|
/** @description Additional metadata to include with the payment session */
|
|
691
|
-
metadata?:
|
|
715
|
+
metadata?: {
|
|
716
|
+
[key: string]: unknown;
|
|
717
|
+
};
|
|
692
718
|
};
|
|
693
719
|
WalletPaymentSessionResponse: {
|
|
694
720
|
/** @description The client secret used by the payment widget to confirm the payment */
|
|
@@ -705,7 +731,9 @@ declare interface components {
|
|
|
705
731
|
/** @description Type of event (e.g., payment_intent.succeeded, payment_intent.payment_failed) */
|
|
706
732
|
type?: string;
|
|
707
733
|
/** @description Event data containing the object that triggered the event */
|
|
708
|
-
data?:
|
|
734
|
+
data?: {
|
|
735
|
+
[key: string]: unknown;
|
|
736
|
+
};
|
|
709
737
|
};
|
|
710
738
|
WalletBalanceResponse: {
|
|
711
739
|
balance_cents: number;
|
|
@@ -1313,7 +1341,7 @@ declare interface components {
|
|
|
1313
1341
|
export declare type ContentAccessInfo = components['schemas']['ContentAccessInfo'];
|
|
1314
1342
|
|
|
1315
1343
|
/** Full content item returned by all seller content endpoints. */
|
|
1316
|
-
declare type ContentResponse = components['schemas']['ContentResponse'];
|
|
1344
|
+
export declare type ContentResponse = components['schemas']['ContentResponse'];
|
|
1317
1345
|
|
|
1318
1346
|
/** A piece of content with buyer access information. */
|
|
1319
1347
|
export declare type ContentWithAccessResponse = components['schemas']['ContentWithAccessResponse'];
|
|
@@ -1333,6 +1361,25 @@ export declare type ContentWithAccessResponse = components['schemas']['ContentWi
|
|
|
1333
1361
|
*
|
|
1334
1362
|
* @example
|
|
1335
1363
|
* ```ts
|
|
1364
|
+
* // Browser
|
|
1365
|
+
* import { ForbiddenError, AuthError } from '@ledewire/browser'
|
|
1366
|
+
*
|
|
1367
|
+
* try {
|
|
1368
|
+
* await lw.auth.loginWithGoogle({ id_token })
|
|
1369
|
+
* } catch (err) {
|
|
1370
|
+
* if (err instanceof ForbiddenError) {
|
|
1371
|
+
* // Credentials were valid but account lacks the required role.
|
|
1372
|
+
* console.error('Access denied:', err.message)
|
|
1373
|
+
* } else if (err instanceof AuthError) {
|
|
1374
|
+
* // Bad credentials or expired token — re-authenticate.
|
|
1375
|
+
* console.error('Authentication failed:', err.message)
|
|
1376
|
+
* }
|
|
1377
|
+
* }
|
|
1378
|
+
* ```
|
|
1379
|
+
*
|
|
1380
|
+
* @example
|
|
1381
|
+
* ```ts
|
|
1382
|
+
* // Node
|
|
1336
1383
|
* import { ForbiddenError, AuthError } from '@ledewire/node'
|
|
1337
1384
|
*
|
|
1338
1385
|
* try {
|
|
@@ -1554,10 +1601,45 @@ export declare interface SellerContentSearchRequest {
|
|
|
1554
1601
|
title?: string;
|
|
1555
1602
|
/** Case-insensitive partial match against the content URI (`external_ref` content only). */
|
|
1556
1603
|
uri?: string;
|
|
1604
|
+
/**
|
|
1605
|
+
* Exact match against the content's external identifier.
|
|
1606
|
+
* Use the full formatted value as it appears in `ContentResponse.external_identifier`,
|
|
1607
|
+
* e.g. `'vimeo:123456789'`.
|
|
1608
|
+
*/
|
|
1609
|
+
external_identifier?: string;
|
|
1557
1610
|
/** Exact key/value pairs to AND-match against content metadata. */
|
|
1558
1611
|
metadata?: Record<string, unknown>;
|
|
1559
1612
|
}
|
|
1560
1613
|
|
|
1614
|
+
/**
|
|
1615
|
+
* A {@link TokenStorage} adapter that persists tokens in `sessionStorage`.
|
|
1616
|
+
*
|
|
1617
|
+
* Tokens survive page reloads within the same tab but are cleared when the
|
|
1618
|
+
* tab is closed or the session ends. This prevents token leakage across
|
|
1619
|
+
* tabs and is a good default for sites where users do not expect persistent
|
|
1620
|
+
* sessions (e.g. embedded checkout widgets, kiosk-mode UIs).
|
|
1621
|
+
*
|
|
1622
|
+
* **Security note:** `sessionStorage` is accessible to any JavaScript on the
|
|
1623
|
+
* same origin and tab. It is more isolated than `localStorage` (no
|
|
1624
|
+
* cross-tab sharing), but the default in-memory storage is still safer for
|
|
1625
|
+
* high-security use cases.
|
|
1626
|
+
*
|
|
1627
|
+
* @param key - The `sessionStorage` key used to store tokens.
|
|
1628
|
+
* Defaults to `'lw:tokens'`. Override this if you have multiple
|
|
1629
|
+
* LedeWire integrations on the same origin.
|
|
1630
|
+
*
|
|
1631
|
+
* @example
|
|
1632
|
+
* ```ts
|
|
1633
|
+
* import { init, sessionStorageAdapter } from '@ledewire/browser'
|
|
1634
|
+
*
|
|
1635
|
+
* const lw = init({
|
|
1636
|
+
* apiKey: 'your_api_key',
|
|
1637
|
+
* storage: sessionStorageAdapter(),
|
|
1638
|
+
* })
|
|
1639
|
+
* ```
|
|
1640
|
+
*/
|
|
1641
|
+
export declare function sessionStorageAdapter(key?: string): TokenStorage;
|
|
1642
|
+
|
|
1561
1643
|
/** Internal representation of stored authentication tokens. */
|
|
1562
1644
|
export declare interface StoredTokens {
|
|
1563
1645
|
accessToken: string;
|
|
@@ -1646,9 +1728,16 @@ declare interface TokenManagerOptions {
|
|
|
1646
1728
|
*
|
|
1647
1729
|
* @example
|
|
1648
1730
|
* ```ts
|
|
1649
|
-
* //
|
|
1731
|
+
* // Persist across tabs and browser restarts (browser only)
|
|
1650
1732
|
* import { localStorageAdapter } from '@ledewire/browser'
|
|
1651
|
-
* const
|
|
1733
|
+
* const lw = init({ apiKey, storage: localStorageAdapter() })
|
|
1734
|
+
* ```
|
|
1735
|
+
*
|
|
1736
|
+
* @example
|
|
1737
|
+
* ```ts
|
|
1738
|
+
* // Persist within the current tab only — cleared on tab close (browser only)
|
|
1739
|
+
* import { sessionStorageAdapter } from '@ledewire/browser'
|
|
1740
|
+
* const lw = init({ apiKey, storage: sessionStorageAdapter() })
|
|
1652
1741
|
* ```
|
|
1653
1742
|
*/
|
|
1654
1743
|
export declare interface TokenStorage {
|