@bravely-studios/account-web 0.3.4

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.
Files changed (59) hide show
  1. package/LICENSE +10 -0
  2. package/README.md +262 -0
  3. package/dist/ActivationStateMachine.d.ts +50 -0
  4. package/dist/ActivationStateMachine.d.ts.map +1 -0
  5. package/dist/ActivationStateMachine.js +141 -0
  6. package/dist/ActivationStateMachine.js.map +1 -0
  7. package/dist/BravelyAccountManager.d.ts +156 -0
  8. package/dist/BravelyAccountManager.d.ts.map +1 -0
  9. package/dist/BravelyAccountManager.js +621 -0
  10. package/dist/BravelyAccountManager.js.map +1 -0
  11. package/dist/EntitlementCache.d.ts +50 -0
  12. package/dist/EntitlementCache.d.ts.map +1 -0
  13. package/dist/EntitlementCache.js +116 -0
  14. package/dist/EntitlementCache.js.map +1 -0
  15. package/dist/components/ActivationLadder.d.ts +78 -0
  16. package/dist/components/ActivationLadder.d.ts.map +1 -0
  17. package/dist/components/ActivationLadder.js +145 -0
  18. package/dist/components/ActivationLadder.js.map +1 -0
  19. package/dist/components/CrossAppCard.d.ts +48 -0
  20. package/dist/components/CrossAppCard.d.ts.map +1 -0
  21. package/dist/components/CrossAppCard.js +45 -0
  22. package/dist/components/CrossAppCard.js.map +1 -0
  23. package/dist/deprecation.d.ts +19 -0
  24. package/dist/deprecation.d.ts.map +1 -0
  25. package/dist/deprecation.js +83 -0
  26. package/dist/deprecation.js.map +1 -0
  27. package/dist/displayName.d.ts +15 -0
  28. package/dist/displayName.d.ts.map +1 -0
  29. package/dist/displayName.js +41 -0
  30. package/dist/displayName.js.map +1 -0
  31. package/dist/dpop.d.ts +30 -0
  32. package/dist/dpop.d.ts.map +1 -0
  33. package/dist/dpop.js +87 -0
  34. package/dist/dpop.js.map +1 -0
  35. package/dist/hooks/useActivationLaneFromUrl.d.ts +54 -0
  36. package/dist/hooks/useActivationLaneFromUrl.d.ts.map +1 -0
  37. package/dist/hooks/useActivationLaneFromUrl.js +105 -0
  38. package/dist/hooks/useActivationLaneFromUrl.js.map +1 -0
  39. package/dist/hooks/useFreshLaunchRestoration.d.ts +62 -0
  40. package/dist/hooks/useFreshLaunchRestoration.d.ts.map +1 -0
  41. package/dist/hooks/useFreshLaunchRestoration.js +135 -0
  42. package/dist/hooks/useFreshLaunchRestoration.js.map +1 -0
  43. package/dist/index.d.ts +16 -0
  44. package/dist/index.d.ts.map +1 -0
  45. package/dist/index.js +15 -0
  46. package/dist/index.js.map +1 -0
  47. package/dist/oauth.d.ts +50 -0
  48. package/dist/oauth.d.ts.map +1 -0
  49. package/dist/oauth.js +107 -0
  50. package/dist/oauth.js.map +1 -0
  51. package/dist/storage.d.ts +48 -0
  52. package/dist/storage.d.ts.map +1 -0
  53. package/dist/storage.js +153 -0
  54. package/dist/storage.js.map +1 -0
  55. package/dist/types.d.ts +172 -0
  56. package/dist/types.d.ts.map +1 -0
  57. package/dist/types.js +7 -0
  58. package/dist/types.js.map +1 -0
  59. package/package.json +61 -0
@@ -0,0 +1,50 @@
1
+ /** Base64url-encode a Uint8Array (RFC 4648 §5). No padding. */
2
+ export declare function base64urlEncode(bytes: Uint8Array): string;
3
+ /** Base64url-decode to a Uint8Array. */
4
+ export declare function base64urlDecode(s: string): Uint8Array;
5
+ /**
6
+ * Generate a cryptographically random `code_verifier`. RFC 7636 §4.1 requires
7
+ * 43-128 chars of `[A-Z][a-z][0-9]-._~`. We produce 43 chars from 32 random
8
+ * bytes via base64url, which is comfortably inside the range.
9
+ */
10
+ export declare function generateCodeVerifier(): string;
11
+ /**
12
+ * SHA-256 hash a `code_verifier` and base64url-encode the digest.
13
+ * That digest IS the `code_challenge` (RFC 7636 §4.2 — S256 method).
14
+ */
15
+ export declare function generateCodeChallenge(verifier: string): Promise<string>;
16
+ /** Cryptographically random opaque `state` parameter (CSRF defense). */
17
+ export declare function generateState(): string;
18
+ /** Build the `/oauth/authorize` URL with PKCE + state. */
19
+ export declare function buildAuthorizeUrl(args: {
20
+ authority: string;
21
+ clientId: string;
22
+ redirectUri: string;
23
+ codeChallenge: string;
24
+ state: string;
25
+ scope: string;
26
+ loginHint?: string;
27
+ prompt?: "login" | "none" | "consent" | "select_account";
28
+ }): string;
29
+ /** Parse `?code=...&state=...` from a callback URL. */
30
+ export declare function parseCallback(url: string): {
31
+ code: string;
32
+ state: string;
33
+ } | null;
34
+ /**
35
+ * Run the full PKCE-prep dance and return everything the caller needs to
36
+ * (a) redirect to `/oauth/authorize` and (b) finish the exchange when the
37
+ * browser comes back.
38
+ */
39
+ export declare function preparePkce(args: {
40
+ authority: string;
41
+ clientId: string;
42
+ redirectUri: string;
43
+ scope: string;
44
+ loginHint?: string;
45
+ }): Promise<{
46
+ verifier: string;
47
+ state: string;
48
+ authorizeUrl: string;
49
+ }>;
50
+ //# sourceMappingURL=oauth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"oauth.d.ts","sourceRoot":"","sources":["../src/oauth.ts"],"names":[],"mappings":"AAUA,+DAA+D;AAC/D,wBAAgB,eAAe,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAMzD;AAED,wCAAwC;AACxC,wBAAgB,eAAe,CAAC,CAAC,EAAE,MAAM,GAAG,UAAU,CAMrD;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,IAAI,MAAM,CAQ7C;AAED;;;GAGG;AACH,wBAAsB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAI7E;AAED,wEAAwE;AACxE,wBAAgB,aAAa,IAAI,MAAM,CAItC;AAED,0DAA0D;AAC1D,wBAAgB,iBAAiB,CAAC,IAAI,EAAE;IACtC,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,GAAG,gBAAgB,CAAC;CAC1D,GAAG,MAAM,CAYT;AAED,uDAAuD;AACvD,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAUjF;AAED;;;;GAIG;AACH,wBAAsB,WAAW,CAAC,IAAI,EAAE;IACtC,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,GAAG,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,CAAC,CAcrE"}
package/dist/oauth.js ADDED
@@ -0,0 +1,107 @@
1
+ // OAuth 2.1 + PKCE helpers (RFC 7636).
2
+ //
3
+ // PKCE flow:
4
+ // 1. Generate a 64-byte random `code_verifier` (43-128 chars URL-safe).
5
+ // 2. SHA-256 the verifier → base64url-encode → that is the `code_challenge`.
6
+ // 3. Send the challenge with the authorize request.
7
+ // 4. Send the verifier with the token request.
8
+ //
9
+ // Server enforces `code_challenge_method=S256` only (no `plain`).
10
+ /** Base64url-encode a Uint8Array (RFC 4648 §5). No padding. */
11
+ export function base64urlEncode(bytes) {
12
+ let binary = "";
13
+ for (let i = 0; i < bytes.length; i++)
14
+ binary += String.fromCharCode(bytes[i]);
15
+ // btoa lives in browsers + happy-dom + modern Node.
16
+ const b64 = btoa(binary);
17
+ return b64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/g, "");
18
+ }
19
+ /** Base64url-decode to a Uint8Array. */
20
+ export function base64urlDecode(s) {
21
+ const padded = s.replace(/-/g, "+").replace(/_/g, "/") + "=".repeat((4 - (s.length % 4)) % 4);
22
+ const binary = atob(padded);
23
+ const out = new Uint8Array(binary.length);
24
+ for (let i = 0; i < binary.length; i++)
25
+ out[i] = binary.charCodeAt(i);
26
+ return out;
27
+ }
28
+ /**
29
+ * Generate a cryptographically random `code_verifier`. RFC 7636 §4.1 requires
30
+ * 43-128 chars of `[A-Z][a-z][0-9]-._~`. We produce 43 chars from 32 random
31
+ * bytes via base64url, which is comfortably inside the range.
32
+ */
33
+ export function generateCodeVerifier() {
34
+ const bytes = new Uint8Array(32);
35
+ crypto.getRandomValues(bytes);
36
+ const verifier = base64urlEncode(bytes);
37
+ if (verifier.length < 43 || verifier.length > 128) {
38
+ throw new Error(`code_verifier length out of range: ${verifier.length}`);
39
+ }
40
+ return verifier;
41
+ }
42
+ /**
43
+ * SHA-256 hash a `code_verifier` and base64url-encode the digest.
44
+ * That digest IS the `code_challenge` (RFC 7636 §4.2 — S256 method).
45
+ */
46
+ export async function generateCodeChallenge(verifier) {
47
+ const encoded = new TextEncoder().encode(verifier);
48
+ const digest = await crypto.subtle.digest("SHA-256", encoded);
49
+ return base64urlEncode(new Uint8Array(digest));
50
+ }
51
+ /** Cryptographically random opaque `state` parameter (CSRF defense). */
52
+ export function generateState() {
53
+ const bytes = new Uint8Array(16);
54
+ crypto.getRandomValues(bytes);
55
+ return base64urlEncode(bytes);
56
+ }
57
+ /** Build the `/oauth/authorize` URL with PKCE + state. */
58
+ export function buildAuthorizeUrl(args) {
59
+ const u = new URL("/oauth/authorize", args.authority);
60
+ u.searchParams.set("response_type", "code");
61
+ u.searchParams.set("client_id", args.clientId);
62
+ u.searchParams.set("redirect_uri", args.redirectUri);
63
+ u.searchParams.set("code_challenge", args.codeChallenge);
64
+ u.searchParams.set("code_challenge_method", "S256");
65
+ u.searchParams.set("state", args.state);
66
+ u.searchParams.set("scope", args.scope);
67
+ if (args.loginHint)
68
+ u.searchParams.set("login_hint", args.loginHint);
69
+ if (args.prompt)
70
+ u.searchParams.set("prompt", args.prompt);
71
+ return u.toString();
72
+ }
73
+ /** Parse `?code=...&state=...` from a callback URL. */
74
+ export function parseCallback(url) {
75
+ try {
76
+ const u = new URL(url);
77
+ const code = u.searchParams.get("code");
78
+ const state = u.searchParams.get("state");
79
+ if (!code || !state)
80
+ return null;
81
+ return { code, state };
82
+ }
83
+ catch {
84
+ return null;
85
+ }
86
+ }
87
+ /**
88
+ * Run the full PKCE-prep dance and return everything the caller needs to
89
+ * (a) redirect to `/oauth/authorize` and (b) finish the exchange when the
90
+ * browser comes back.
91
+ */
92
+ export async function preparePkce(args) {
93
+ const verifier = generateCodeVerifier();
94
+ const challenge = await generateCodeChallenge(verifier);
95
+ const state = generateState();
96
+ const authorizeUrl = buildAuthorizeUrl({
97
+ authority: args.authority,
98
+ clientId: args.clientId,
99
+ redirectUri: args.redirectUri,
100
+ codeChallenge: challenge,
101
+ state,
102
+ scope: args.scope,
103
+ loginHint: args.loginHint,
104
+ });
105
+ return { verifier, state, authorizeUrl };
106
+ }
107
+ //# sourceMappingURL=oauth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"oauth.js","sourceRoot":"","sources":["../src/oauth.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,48 @@
1
+ export interface Storage {
2
+ /** Write a string value. */
3
+ set(key: string, value: string): Promise<void>;
4
+ /** Read a string value. Returns null if not set. */
5
+ get(key: string): Promise<string | null>;
6
+ /** Remove a key. */
7
+ remove(key: string): Promise<void>;
8
+ /** Clear every key namespaced under `bravely:*`. */
9
+ clear(): Promise<void>;
10
+ }
11
+ /** A no-op storage for SSR or first-render where DOM globals are missing. */
12
+ declare function memoryStorage(): Storage;
13
+ /**
14
+ * sessionStorage-backed adapter. Page-lifetime — best for BAS + PKCE verifier
15
+ * which are not meant to survive a tab close. The refresh_token gets stored
16
+ * separately via IndexedDB.
17
+ */
18
+ declare function sessionStorageBacked(): Storage;
19
+ /**
20
+ * IndexedDB-backed adapter for longer-lived state (refresh_token,
21
+ * entitlement cache). Wraps the verbose IDB API behind the same simple
22
+ * surface. No external dependency — small enough to inline.
23
+ */
24
+ declare function indexedDbBacked(dbName?: string, storeName?: string): Storage;
25
+ /**
26
+ * Composite storage: small/session keys land in sessionStorage; persistent
27
+ * keys (refresh_token, entitlement cache) land in IndexedDB. Falls back to
28
+ * an in-memory map if either subsystem is unavailable (SSR, tests).
29
+ */
30
+ declare class CompositeStorage implements Storage {
31
+ private readonly session;
32
+ private readonly persistent;
33
+ /** Keys routed to persistent storage. Everything else lives in session. */
34
+ static readonly persistentKeys: Set<string>;
35
+ constructor(session: Storage, persistent: Storage);
36
+ private route;
37
+ set(k: string, v: string): Promise<void>;
38
+ get(k: string): Promise<string | null>;
39
+ remove(k: string): Promise<void>;
40
+ clear(): Promise<void>;
41
+ }
42
+ /**
43
+ * Returns the right storage adapter for the current environment. Host pages
44
+ * can override by passing `storage` into the manager config.
45
+ */
46
+ export declare function defaultStorage(): Storage;
47
+ export { CompositeStorage, memoryStorage, sessionStorageBacked, indexedDbBacked };
48
+ //# sourceMappingURL=storage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../src/storage.ts"],"names":[],"mappings":"AAeA,MAAM,WAAW,OAAO;IACtB,4BAA4B;IAC5B,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/C,oDAAoD;IACpD,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACzC,oBAAoB;IACpB,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnC,oDAAoD;IACpD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAID,6EAA6E;AAC7E,iBAAS,aAAa,IAAI,OAAO,CAgBhC;AAED;;;;GAIG;AACH,iBAAS,oBAAoB,IAAI,OAAO,CAoBvC;AAED;;;;GAIG;AACH,iBAAS,eAAe,CAAC,MAAM,SAAoB,EAAE,SAAS,SAAO,GAAG,OAAO,CAsC9E;AAED;;;;GAIG;AACH,cAAM,gBAAiB,YAAW,OAAO;IACvC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAU;IAClC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAU;IACrC,2EAA2E;IAC3E,MAAM,CAAC,QAAQ,CAAC,cAAc,cAI3B;gBAES,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,OAAO;IAKjD,OAAO,CAAC,KAAK;IAIP,GAAG,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAGxC,GAAG,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAGtC,MAAM,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAGhC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAG7B;AAED;;;GAGG;AACH,wBAAgB,cAAc,IAAI,OAAO,CAOxC;AAED,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,oBAAoB,EAAE,eAAe,EAAE,CAAC"}
@@ -0,0 +1,153 @@
1
+ // Storage abstraction. Lets the manager keep BAS, refresh_token, PKCE
2
+ // verifier, and the entitlement cache without baking in any one backing
3
+ // store.
4
+ //
5
+ // Priority order (Gate 1):
6
+ // 1. ServiceWorker-controlled store via postMessage → not implemented yet;
7
+ // host pages will replace `defaultStorage()` with their own SW adapter.
8
+ // 2. sessionStorage for short-lived data (BAS, PKCE verifier) — wipes on
9
+ // tab close (good).
10
+ // 3. IndexedDB for the refresh_token + entitlement cache — survives reload
11
+ // but no cross-origin leak.
12
+ //
13
+ // For Gate 2 the refresh_token will be DPoP-bound and the IndexedDB row will
14
+ // carry the JKT thumbprint of the non-extractable key it is bound to.
15
+ const NAMESPACE = "bravely:";
16
+ /** A no-op storage for SSR or first-render where DOM globals are missing. */
17
+ function memoryStorage() {
18
+ const m = new Map();
19
+ return {
20
+ async set(k, v) {
21
+ m.set(k, v);
22
+ },
23
+ async get(k) {
24
+ return m.get(k) ?? null;
25
+ },
26
+ async remove(k) {
27
+ m.delete(k);
28
+ },
29
+ async clear() {
30
+ m.clear();
31
+ },
32
+ };
33
+ }
34
+ /**
35
+ * sessionStorage-backed adapter. Page-lifetime — best for BAS + PKCE verifier
36
+ * which are not meant to survive a tab close. The refresh_token gets stored
37
+ * separately via IndexedDB.
38
+ */
39
+ function sessionStorageBacked() {
40
+ return {
41
+ async set(k, v) {
42
+ sessionStorage.setItem(NAMESPACE + k, v);
43
+ },
44
+ async get(k) {
45
+ return sessionStorage.getItem(NAMESPACE + k);
46
+ },
47
+ async remove(k) {
48
+ sessionStorage.removeItem(NAMESPACE + k);
49
+ },
50
+ async clear() {
51
+ const keys = [];
52
+ for (let i = 0; i < sessionStorage.length; i++) {
53
+ const key = sessionStorage.key(i);
54
+ if (key && key.startsWith(NAMESPACE))
55
+ keys.push(key);
56
+ }
57
+ for (const key of keys)
58
+ sessionStorage.removeItem(key);
59
+ },
60
+ };
61
+ }
62
+ /**
63
+ * IndexedDB-backed adapter for longer-lived state (refresh_token,
64
+ * entitlement cache). Wraps the verbose IDB API behind the same simple
65
+ * surface. No external dependency — small enough to inline.
66
+ */
67
+ function indexedDbBacked(dbName = "bravely-account", storeName = "kv") {
68
+ const openDb = () => new Promise((resolve, reject) => {
69
+ const req = indexedDB.open(dbName, 1);
70
+ req.onupgradeneeded = () => {
71
+ const db = req.result;
72
+ if (!db.objectStoreNames.contains(storeName))
73
+ db.createObjectStore(storeName);
74
+ };
75
+ req.onsuccess = () => resolve(req.result);
76
+ req.onerror = () => reject(req.error);
77
+ });
78
+ const tx = async (mode, fn) => {
79
+ const db = await openDb();
80
+ return new Promise((resolve, reject) => {
81
+ const t = db.transaction(storeName, mode);
82
+ const store = t.objectStore(storeName);
83
+ const req = fn(store);
84
+ t.oncomplete = () => resolve(req ? req.result : undefined);
85
+ t.onerror = () => reject(t.error);
86
+ });
87
+ };
88
+ return {
89
+ async set(k, v) {
90
+ await tx("readwrite", (s) => s.put(v, NAMESPACE + k));
91
+ },
92
+ async get(k) {
93
+ const value = (await tx("readonly", (s) => s.get(NAMESPACE + k))) ?? null;
94
+ return typeof value === "string" ? value : null;
95
+ },
96
+ async remove(k) {
97
+ await tx("readwrite", (s) => s.delete(NAMESPACE + k));
98
+ },
99
+ async clear() {
100
+ await tx("readwrite", (s) => s.clear());
101
+ },
102
+ };
103
+ }
104
+ /**
105
+ * Composite storage: small/session keys land in sessionStorage; persistent
106
+ * keys (refresh_token, entitlement cache) land in IndexedDB. Falls back to
107
+ * an in-memory map if either subsystem is unavailable (SSR, tests).
108
+ */
109
+ class CompositeStorage {
110
+ session;
111
+ persistent;
112
+ /** Keys routed to persistent storage. Everything else lives in session. */
113
+ static persistentKeys = new Set([
114
+ "refresh_token",
115
+ "entitlement_cache",
116
+ "dpop_jkt_thumbprint",
117
+ ]);
118
+ constructor(session, persistent) {
119
+ this.session = session;
120
+ this.persistent = persistent;
121
+ }
122
+ route(k) {
123
+ return CompositeStorage.persistentKeys.has(k) ? this.persistent : this.session;
124
+ }
125
+ async set(k, v) {
126
+ await this.route(k).set(k, v);
127
+ }
128
+ async get(k) {
129
+ return this.route(k).get(k);
130
+ }
131
+ async remove(k) {
132
+ await this.route(k).remove(k);
133
+ }
134
+ async clear() {
135
+ await Promise.all([this.session.clear(), this.persistent.clear()]);
136
+ }
137
+ }
138
+ /**
139
+ * Returns the right storage adapter for the current environment. Host pages
140
+ * can override by passing `storage` into the manager config.
141
+ */
142
+ export function defaultStorage() {
143
+ // happy-dom / browser path
144
+ const hasSession = typeof globalThis !== "undefined" && typeof globalThis.sessionStorage !== "undefined";
145
+ const hasIdb = typeof globalThis !== "undefined" && typeof globalThis.indexedDB !== "undefined";
146
+ if (hasSession && hasIdb)
147
+ return new CompositeStorage(sessionStorageBacked(), indexedDbBacked());
148
+ if (hasSession)
149
+ return new CompositeStorage(sessionStorageBacked(), memoryStorage());
150
+ return memoryStorage();
151
+ }
152
+ export { CompositeStorage, memoryStorage, sessionStorageBacked, indexedDbBacked };
153
+ //# sourceMappingURL=storage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage.js","sourceRoot":"","sources":["../src/storage.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,172 @@
1
+ /** The 9 utility app identifiers. Hard-coded from the AppSlug enum in the spec. */
2
+ export type AppSlug = "diskaroo" | "markdly" | "printscreenly" | "prodjectly" | "saycopypaste" | "scry" | "stickily" | "terminaltags" | "todoingly";
3
+ /** Per-app entitlement record. Matches `Entitlement` schema. */
4
+ export interface Entitlement {
5
+ /** Public-safe identifier (e.g. `diskaroo_pro`, `bravely_premium`). Never the internal `entlXXX` RC id. */
6
+ lookup_key: string;
7
+ expires_at: string | null;
8
+ will_renew: boolean;
9
+ product_id?: string | null;
10
+ store?: "paddle" | "app_store" | "play_store" | "promotional" | null;
11
+ }
12
+ /** OAuth 2.1 token response from `/oauth/token`. */
13
+ export interface OAuthTokenResponse {
14
+ /** The Bravely App Session (`bas_...`). Treat as opaque. */
15
+ access_token: string;
16
+ token_type: "DPoP" | "Bearer";
17
+ expires_in: number;
18
+ refresh_token: string | null;
19
+ scope: string;
20
+ issued_at: string;
21
+ active_entitlements?: Entitlement[];
22
+ bravely_account_id: string;
23
+ email: string;
24
+ app_slug: AppSlug;
25
+ platform?: string | null;
26
+ expires_at: string;
27
+ /** Server-published lib version policy (Track E10). Read into the deprecation handler. */
28
+ bravely_lib_version?: LibVersionPolicy;
29
+ }
30
+ /** Bravely App Session refresh response from `/api/app-sessions/refresh`. */
31
+ export interface BasResponse {
32
+ ok: true;
33
+ bas: string;
34
+ session_token?: string;
35
+ refresh_token?: string;
36
+ expires_in?: number;
37
+ expires_at: string;
38
+ bravely_account_id: string;
39
+ email: string;
40
+ app_slug: AppSlug;
41
+ platform?: string | null;
42
+ active_entitlements?: Entitlement[];
43
+ app_data_token?: string;
44
+ app_data_token_expires_at?: string;
45
+ }
46
+ /** Entitlement snapshot from `/api/entitlements?app=<slug>`. */
47
+ export interface EntitlementSnapshot {
48
+ bravely_account_id: string;
49
+ app_slug: AppSlug;
50
+ active_entitlements: string[];
51
+ active: boolean;
52
+ override: {
53
+ active: boolean;
54
+ reason: string | null;
55
+ expires_at: string | null;
56
+ };
57
+ trial: {
58
+ active: boolean;
59
+ expires_at: string | null;
60
+ };
61
+ subscription: {
62
+ active: boolean;
63
+ platform: string | null;
64
+ expires_at: string | null;
65
+ };
66
+ fetched_at: string;
67
+ cache_ttl_seconds?: number;
68
+ }
69
+ /** Lib version policy carried on BAS exchange / OAuth token responses. */
70
+ export interface LibVersionPolicy {
71
+ /** Highest known good version. */
72
+ current: string;
73
+ /** Below this version the lib must hard-upgrade. */
74
+ min_version: string;
75
+ /** Reason for any forced upgrade. */
76
+ reason?: string;
77
+ }
78
+ /** Parsed `Bravely-Deprecation: endpoint; ...` directive. */
79
+ export interface DeprecationEndpoint {
80
+ kind: "endpoint";
81
+ endpoint?: string;
82
+ expires?: string;
83
+ replacement?: string;
84
+ reason?: string;
85
+ }
86
+ /** Parsed `Bravely-Deprecation: client; ...` directive. */
87
+ export interface DeprecationClient {
88
+ kind: "client";
89
+ minVersion?: string;
90
+ current?: string;
91
+ reason?: string;
92
+ }
93
+ export type DeprecationDirective = DeprecationEndpoint | DeprecationClient;
94
+ /**
95
+ * Top-level state of the Bravely Account in the host page. Drives UI render
96
+ * via `onStateChange` subscribers.
97
+ */
98
+ export type BravelyAccountState = {
99
+ kind: "signed_out";
100
+ } | {
101
+ kind: "signing_in";
102
+ pending: boolean;
103
+ } | {
104
+ kind: "signed_in";
105
+ ba_id: string;
106
+ email: string;
107
+ bas: string;
108
+ entitlements: Entitlement[];
109
+ } | {
110
+ kind: "failed";
111
+ error: string;
112
+ };
113
+ export type CheckoutPlan = "monthly" | "annual" | "lifetime";
114
+ /** Response from `POST /api/paddle-portal`. */
115
+ export interface PaddlePortalSession {
116
+ ok: true;
117
+ url: string;
118
+ expires_at: string;
119
+ bravely_account_id: string;
120
+ app_slug: AppSlug | null;
121
+ }
122
+ /** Subset of activation state machine state names (full machine in ActivationStateMachine.ts). */
123
+ export type ActivationStateName = "idle" | "restoring_session" | "verifying_entitlement" | "entitlement_cached_valid" | "entitlement_fresh_valid" | "entitlement_none" | "post_checkout_activation" | "fresh_launch_restoration" | "pending_user_action" | "failed";
124
+ export interface ActivationState {
125
+ name: ActivationStateName;
126
+ enteredAt: Date;
127
+ /** True iff the state has a spinner / elapsed-time indicator. */
128
+ busy: boolean;
129
+ }
130
+ /**
131
+ * Configuration for `BravelyAccountManager`. The `authority` and `appSlug`
132
+ * are required; everything else falls back to sane defaults.
133
+ */
134
+ export interface ManagerConfig {
135
+ /** Authorization server origin. Production: `https://auth.bravely.dev`. */
136
+ authority: string;
137
+ /** This app's slug — used as the OAuth `client_id`. */
138
+ appSlug: AppSlug;
139
+ /** Client app version (semver). Sent on every BAS exchange. */
140
+ clientVersion: string;
141
+ /** Lib name. Defaults to `bravely-account-web`. */
142
+ libName?: string;
143
+ /** Lib version. Defaults to this package's version. */
144
+ libVersion?: string;
145
+ /** Identity API origin. Defaults to `https://identity.bravely.dev`. */
146
+ identityOrigin?: string;
147
+ /** Override the OAuth redirect URI. Defaults to `${location.origin}/auth/callback`. */
148
+ redirectUri?: string;
149
+ /** OAuth scope string. Defaults to `bravely.account bravely.entitlements`. */
150
+ scope?: string;
151
+ /** Optional storage adapter override (testing). */
152
+ storage?: import("./storage.js").Storage;
153
+ }
154
+ /** RFC 9449 DPoP proof carrier (Gate 2). For Gate 1 this is null/unused. */
155
+ export interface DPoPProof {
156
+ proof: string | null;
157
+ jktThumbprint: string | null;
158
+ }
159
+ /** Cached entitlement record persisted via the storage abstraction. */
160
+ export interface CachedEntitlements {
161
+ entitlements: Entitlement[];
162
+ cachedAt: string;
163
+ /** RFC 7638 JWK thumbprint of the DPoP key the cache is bound to (Gate 2). Null for Gate 1. */
164
+ dpopJktThumbprint: string | null;
165
+ /** HMAC over the JSON body. Gate 2 server-signed; null for Gate 1. */
166
+ signature: string | null;
167
+ }
168
+ export interface ClientKilledErrorDetails {
169
+ replacement?: string;
170
+ reason?: string;
171
+ }
172
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js ADDED
@@ -0,0 +1,7 @@
1
+ // Bravely Identity API types. Mirrors the OpenAPI 3.1 spec at
2
+ // bravely-commerce-router/openapi.yaml. Keep aligned by hand — the spec is
3
+ // small enough that codegen is more friction than the lib is worth.
4
+ //
5
+ // API version baseline: 1.2.1 (adds Paddle customer-portal session minting).
6
+ export {};
7
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,8DAA8D;AAC9D,2EAA2E;AAC3E,oEAAoE;AACpE,EAAE;AACF,6EAA6E"}
package/package.json ADDED
@@ -0,0 +1,61 @@
1
+ {
2
+ "name": "@bravely-studios/account-web",
3
+ "version": "0.3.4",
4
+ "description": "Bravely Account web facade: OAuth 2.1 + PKCE sign-in, BAS lifecycle, entitlement cache, activation state machine, C-ux M2/M3/M4 components. Used by all 9 utility web variants + bravely.dev.",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ }
13
+ },
14
+ "files": [
15
+ "dist/",
16
+ "README.md",
17
+ "LICENSE"
18
+ ],
19
+ "scripts": {
20
+ "build": "tsc",
21
+ "test": "vitest run",
22
+ "test:watch": "vitest",
23
+ "test:coverage": "vitest run --coverage",
24
+ "lint": "tsc --noEmit",
25
+ "typecheck": "tsc --noEmit",
26
+ "prepublishOnly": "npm run build && npm run test"
27
+ },
28
+ "devDependencies": {
29
+ "@testing-library/react": "^16.3.2",
30
+ "@types/react": "^19.2.14",
31
+ "@types/react-dom": "^19.2.3",
32
+ "@vitest/coverage-v8": "^3.2.4",
33
+ "fast-check": "^4.7.0",
34
+ "happy-dom": "^20.9.0",
35
+ "react": "^19.2.6",
36
+ "react-dom": "^19.2.6",
37
+ "typescript": "^5.6.0",
38
+ "vitest": "^3.2.4"
39
+ },
40
+ "peerDependencies": {
41
+ "react": ">=18.0.0"
42
+ },
43
+ "peerDependenciesMeta": {
44
+ "react": {
45
+ "optional": true
46
+ }
47
+ },
48
+ "publishConfig": {
49
+ "registry": "https://registry.npmjs.org/",
50
+ "access": "public"
51
+ },
52
+ "repository": {
53
+ "type": "git",
54
+ "url": "git+https://github.com/Bravely-Studios/bravely-account-web.git"
55
+ },
56
+ "author": "Jeff Schiesser <jeff@bravely.dev>",
57
+ "license": "LicenseRef-Bravely-Studios-Proprietary",
58
+ "engines": {
59
+ "node": ">=20"
60
+ }
61
+ }