@gaballahtech/seba 0.0.0-stage → 0.2.1

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 (86) hide show
  1. package/ARCHITECTURE.md +242 -0
  2. package/BUILD_REPORT.md +195 -0
  3. package/CHANGELOG.md +86 -0
  4. package/LICENSE +21 -0
  5. package/README.md +282 -2
  6. package/RESEARCH.md +180 -0
  7. package/SECURITY.md +224 -0
  8. package/VALIDATION_REPORT.md +187 -0
  9. package/dist/browser/index.d.ts +9 -0
  10. package/dist/browser/index.d.ts.map +1 -0
  11. package/dist/browser/index.js +9 -0
  12. package/dist/browser/index.js.map +1 -0
  13. package/dist/browser/platform.d.ts +14 -0
  14. package/dist/browser/platform.d.ts.map +1 -0
  15. package/dist/browser/platform.js +60 -0
  16. package/dist/browser/platform.js.map +1 -0
  17. package/dist/browser/provider-modal.d.ts +15 -0
  18. package/dist/browser/provider-modal.d.ts.map +1 -0
  19. package/dist/browser/provider-modal.js +126 -0
  20. package/dist/browser/provider-modal.js.map +1 -0
  21. package/dist/browser/storage.d.ts +32 -0
  22. package/dist/browser/storage.d.ts.map +1 -0
  23. package/dist/browser/storage.js +121 -0
  24. package/dist/browser/storage.js.map +1 -0
  25. package/dist/core/client.d.ts +49 -0
  26. package/dist/core/client.d.ts.map +1 -0
  27. package/dist/core/client.js +371 -0
  28. package/dist/core/client.js.map +1 -0
  29. package/dist/core/discovery.d.ts +82 -0
  30. package/dist/core/discovery.d.ts.map +1 -0
  31. package/dist/core/discovery.js +243 -0
  32. package/dist/core/discovery.js.map +1 -0
  33. package/dist/core/dpop.d.ts +67 -0
  34. package/dist/core/dpop.d.ts.map +1 -0
  35. package/dist/core/dpop.js +176 -0
  36. package/dist/core/dpop.js.map +1 -0
  37. package/dist/core/errors.d.ts +86 -0
  38. package/dist/core/errors.d.ts.map +1 -0
  39. package/dist/core/errors.js +104 -0
  40. package/dist/core/errors.js.map +1 -0
  41. package/dist/core/http.d.ts +68 -0
  42. package/dist/core/http.d.ts.map +1 -0
  43. package/dist/core/http.js +128 -0
  44. package/dist/core/http.js.map +1 -0
  45. package/dist/core/identity.d.ts +145 -0
  46. package/dist/core/identity.d.ts.map +1 -0
  47. package/dist/core/identity.js +735 -0
  48. package/dist/core/identity.js.map +1 -0
  49. package/dist/core/oidc.d.ts +175 -0
  50. package/dist/core/oidc.d.ts.map +1 -0
  51. package/dist/core/oidc.js +413 -0
  52. package/dist/core/oidc.js.map +1 -0
  53. package/dist/core/session.d.ts +116 -0
  54. package/dist/core/session.d.ts.map +1 -0
  55. package/dist/core/session.js +350 -0
  56. package/dist/core/session.js.map +1 -0
  57. package/dist/core/storage.d.ts +22 -0
  58. package/dist/core/storage.d.ts.map +1 -0
  59. package/dist/core/storage.js +48 -0
  60. package/dist/core/storage.js.map +1 -0
  61. package/dist/index.d.ts +18 -0
  62. package/dist/index.d.ts.map +1 -0
  63. package/dist/index.js +3 -0
  64. package/dist/index.js.map +1 -0
  65. package/dist/node/index.d.ts +9 -0
  66. package/dist/node/index.d.ts.map +1 -0
  67. package/dist/node/index.js +9 -0
  68. package/dist/node/index.js.map +1 -0
  69. package/dist/node/platform.d.ts +25 -0
  70. package/dist/node/platform.d.ts.map +1 -0
  71. package/dist/node/platform.js +161 -0
  72. package/dist/node/platform.js.map +1 -0
  73. package/dist/seba.d.ts +39 -0
  74. package/dist/seba.d.ts.map +1 -0
  75. package/dist/seba.js +58 -0
  76. package/dist/seba.js.map +1 -0
  77. package/dist/types.d.ts +279 -0
  78. package/dist/types.d.ts.map +1 -0
  79. package/dist/types.js +8 -0
  80. package/dist/types.js.map +1 -0
  81. package/examples/node/index.ts +61 -0
  82. package/examples/react/App.tsx +127 -0
  83. package/examples/react/index.html +12 -0
  84. package/examples/react/main.tsx +14 -0
  85. package/examples/react/vite.config.ts +27 -0
  86. package/package.json +83 -4
@@ -0,0 +1,126 @@
1
+ /**
2
+ * Minimal, dependency-free identity prompt for browsers.
3
+ *
4
+ * The dialog asks for a WebID by default and offers an identity-provider URL instead.
5
+ * It is only a hint: whatever the user enters is validated and discovered by the core.
6
+ */
7
+ import { SebaAuthError } from "../core/errors.js";
8
+ /**
9
+ * Ask the user which WebID or identity provider to use.
10
+ *
11
+ * @returns Login options collected from the dialog.
12
+ * @throws {@link SebaAuthError} when the user cancels or the dialog cannot be shown.
13
+ */
14
+ export function askForIdentity() {
15
+ return new Promise((resolve, reject) => {
16
+ if (typeof document === "undefined" || document.body === null) {
17
+ reject(new SebaAuthError("Cannot ask for a WebID outside a browser document."));
18
+ return;
19
+ }
20
+ const overlay = document.createElement("div");
21
+ overlay.setAttribute("role", "dialog");
22
+ overlay.setAttribute("aria-modal", "true");
23
+ overlay.setAttribute("aria-labelledby", "seba-dialog-title");
24
+ overlay.style.cssText = [
25
+ "position:fixed",
26
+ "inset:0",
27
+ "z-index:2147483647",
28
+ "display:flex",
29
+ "align-items:center",
30
+ "justify-content:center",
31
+ "background:rgba(15,23,42,0.55)",
32
+ "font-family:system-ui,sans-serif",
33
+ "padding:16px",
34
+ ].join(";");
35
+ const card = document.createElement("div");
36
+ card.style.cssText = [
37
+ "background:#fff",
38
+ "color:#0f172a",
39
+ "border-radius:12px",
40
+ "box-shadow:0 20px 50px rgba(0,0,0,0.25)",
41
+ "max-width:440px",
42
+ "width:100%",
43
+ "padding:24px",
44
+ "display:flex",
45
+ "flex-direction:column",
46
+ "gap:12px",
47
+ ].join(";");
48
+ const title = document.createElement("h2");
49
+ title.id = "seba-dialog-title";
50
+ title.textContent = "Sign in to Solid";
51
+ title.style.cssText = "margin:0;font-size:18px;";
52
+ const description = document.createElement("p");
53
+ description.textContent = "Enter your WebID, or the URL of the identity provider that issues your WebID.";
54
+ description.style.cssText = "margin:0;font-size:14px;line-height:1.5;color:#334155;";
55
+ const input = document.createElement("input");
56
+ input.type = "url";
57
+ input.required = true;
58
+ input.placeholder = "https://alice.example/profile/card#me";
59
+ input.setAttribute("aria-label", "WebID or identity provider URL");
60
+ input.style.cssText = "padding:10px 12px;border:1px solid #cbd5e1;border-radius:8px;font-size:14px;";
61
+ const error = document.createElement("p");
62
+ error.setAttribute("role", "alert");
63
+ error.style.cssText = "margin:0;font-size:13px;color:#b91c1c;display:none;";
64
+ const buttons = document.createElement("div");
65
+ buttons.style.cssText = "display:flex;justify-content:flex-end;gap:8px;margin-top:4px;";
66
+ const cancel = document.createElement("button");
67
+ cancel.type = "button";
68
+ cancel.textContent = "Cancel";
69
+ cancel.style.cssText = "padding:8px 14px;border:1px solid #cbd5e1;background:#fff;border-radius:8px;cursor:pointer;";
70
+ const submit = document.createElement("button");
71
+ submit.type = "submit";
72
+ submit.textContent = "Continue";
73
+ submit.style.cssText =
74
+ "padding:8px 14px;border:0;background:#0f172a;color:#fff;border-radius:8px;cursor:pointer;font-weight:600;";
75
+ const form = document.createElement("form");
76
+ form.style.cssText = "display:flex;flex-direction:column;gap:12px;";
77
+ form.append(input, error, buttons);
78
+ buttons.append(cancel, submit);
79
+ card.append(title, description, form);
80
+ overlay.append(card);
81
+ document.body.append(overlay);
82
+ input.focus();
83
+ const close = () => {
84
+ overlay.remove();
85
+ };
86
+ cancel.addEventListener("click", () => {
87
+ close();
88
+ reject(new SebaAuthError("The sign-in prompt was cancelled."));
89
+ });
90
+ overlay.addEventListener("keydown", (event) => {
91
+ if (event.key === "Escape") {
92
+ event.preventDefault();
93
+ close();
94
+ reject(new SebaAuthError("The sign-in prompt was cancelled."));
95
+ }
96
+ });
97
+ form.addEventListener("submit", (event) => {
98
+ event.preventDefault();
99
+ const value = input.value.trim();
100
+ if (value === "") {
101
+ error.textContent = "Enter a WebID or identity provider URL.";
102
+ error.style.display = "block";
103
+ return;
104
+ }
105
+ let parsed;
106
+ try {
107
+ parsed = new URL(value);
108
+ }
109
+ catch {
110
+ error.textContent = "That is not an absolute URL. It must start with https://";
111
+ error.style.display = "block";
112
+ return;
113
+ }
114
+ if (parsed.protocol !== "https:" && parsed.protocol !== "http:") {
115
+ error.textContent = "Only https URLs are accepted (http for localhost).";
116
+ error.style.display = "block";
117
+ return;
118
+ }
119
+ close();
120
+ // A WebID usually has a path or fragment; a bare origin is an issuer.
121
+ const looksLikeIssuer = parsed.pathname === "/" && parsed.search === "" && parsed.hash === "";
122
+ resolve(looksLikeIssuer ? { issuer: value } : { webId: value });
123
+ });
124
+ });
125
+ }
126
+ //# sourceMappingURL=provider-modal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider-modal.js","sourceRoot":"","sources":["../../src/browser/provider-modal.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAGlD;;;;;GAKG;AACH,MAAM,UAAU,cAAc;IAC5B,OAAO,IAAI,OAAO,CAAe,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACnD,IAAI,OAAO,QAAQ,KAAK,WAAW,IAAI,QAAQ,CAAC,IAAI,KAAK,IAAI,EAAE,CAAC;YAC9D,MAAM,CAAC,IAAI,aAAa,CAAC,oDAAoD,CAAC,CAAC,CAAC;YAChF,OAAO;QACT,CAAC;QAED,MAAM,OAAO,GAAG,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;QAC9C,OAAO,CAAC,YAAY,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QACvC,OAAO,CAAC,YAAY,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;QAC3C,OAAO,CAAC,YAAY,CAAC,iBAAiB,EAAE,mBAAmB,CAAC,CAAC;QAC7D,OAAO,CAAC,KAAK,CAAC,OAAO,GAAG;YACtB,gBAAgB;YAChB,SAAS;YACT,oBAAoB;YACpB,cAAc;YACd,oBAAoB;YACpB,wBAAwB;YACxB,gCAAgC;YAChC,kCAAkC;YAClC,cAAc;SACf,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAEZ,MAAM,IAAI,GAAG,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;QAC3C,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG;YACnB,iBAAiB;YACjB,eAAe;YACf,oBAAoB;YACpB,yCAAyC;YACzC,iBAAiB;YACjB,YAAY;YACZ,cAAc;YACd,cAAc;YACd,uBAAuB;YACvB,UAAU;SACX,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAEZ,MAAM,KAAK,GAAG,QAAQ,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;QAC3C,KAAK,CAAC,EAAE,GAAG,mBAAmB,CAAC;QAC/B,KAAK,CAAC,WAAW,GAAG,kBAAkB,CAAC;QACvC,KAAK,CAAC,KAAK,CAAC,OAAO,GAAG,0BAA0B,CAAC;QAEjD,MAAM,WAAW,GAAG,QAAQ,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC;QAChD,WAAW,CAAC,WAAW,GAAG,+EAA+E,CAAC;QAC1G,WAAW,CAAC,KAAK,CAAC,OAAO,GAAG,wDAAwD,CAAC;QAErF,MAAM,KAAK,GAAG,QAAQ,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;QAC9C,KAAK,CAAC,IAAI,GAAG,KAAK,CAAC;QACnB,KAAK,CAAC,QAAQ,GAAG,IAAI,CAAC;QACtB,KAAK,CAAC,WAAW,GAAG,uCAAuC,CAAC;QAC5D,KAAK,CAAC,YAAY,CAAC,YAAY,EAAE,gCAAgC,CAAC,CAAC;QACnE,KAAK,CAAC,KAAK,CAAC,OAAO,GAAG,8EAA8E,CAAC;QAErG,MAAM,KAAK,GAAG,QAAQ,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC;QAC1C,KAAK,CAAC,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QACpC,KAAK,CAAC,KAAK,CAAC,OAAO,GAAG,qDAAqD,CAAC;QAE5E,MAAM,OAAO,GAAG,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;QAC9C,OAAO,CAAC,KAAK,CAAC,OAAO,GAAG,+DAA+D,CAAC;QAExF,MAAM,MAAM,GAAG,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;QAChD,MAAM,CAAC,IAAI,GAAG,QAAQ,CAAC;QACvB,MAAM,CAAC,WAAW,GAAG,QAAQ,CAAC;QAC9B,MAAM,CAAC,KAAK,CAAC,OAAO,GAAG,6FAA6F,CAAC;QAErH,MAAM,MAAM,GAAG,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;QAChD,MAAM,CAAC,IAAI,GAAG,QAAQ,CAAC;QACvB,MAAM,CAAC,WAAW,GAAG,UAAU,CAAC;QAChC,MAAM,CAAC,KAAK,CAAC,OAAO;YAClB,2GAA2G,CAAC;QAE9G,MAAM,IAAI,GAAG,QAAQ,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;QAC5C,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,8CAA8C,CAAC;QACpE,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;QACnC,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAC/B,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,WAAW,EAAE,IAAI,CAAC,CAAC;QACtC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QACrB,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAC9B,KAAK,CAAC,KAAK,EAAE,CAAC;QAEd,MAAM,KAAK,GAAG,GAAS,EAAE;YACvB,OAAO,CAAC,MAAM,EAAE,CAAC;QACnB,CAAC,CAAC;QAEF,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE;YACpC,KAAK,EAAE,CAAC;YACR,MAAM,CAAC,IAAI,aAAa,CAAC,mCAAmC,CAAC,CAAC,CAAC;QACjE,CAAC,CAAC,CAAC;QAEH,OAAO,CAAC,gBAAgB,CAAC,SAAS,EAAE,CAAC,KAAK,EAAE,EAAE;YAC5C,IAAI,KAAK,CAAC,GAAG,KAAK,QAAQ,EAAE,CAAC;gBAC3B,KAAK,CAAC,cAAc,EAAE,CAAC;gBACvB,KAAK,EAAE,CAAC;gBACR,MAAM,CAAC,IAAI,aAAa,CAAC,mCAAmC,CAAC,CAAC,CAAC;YACjE,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,gBAAgB,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE;YACxC,KAAK,CAAC,cAAc,EAAE,CAAC;YACvB,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;YACjC,IAAI,KAAK,KAAK,EAAE,EAAE,CAAC;gBACjB,KAAK,CAAC,WAAW,GAAG,yCAAyC,CAAC;gBAC9D,KAAK,CAAC,KAAK,CAAC,OAAO,GAAG,OAAO,CAAC;gBAC9B,OAAO;YACT,CAAC;YACD,IAAI,MAAW,CAAC;YAChB,IAAI,CAAC;gBACH,MAAM,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC;YAC1B,CAAC;YAAC,MAAM,CAAC;gBACP,KAAK,CAAC,WAAW,GAAG,0DAA0D,CAAC;gBAC/E,KAAK,CAAC,KAAK,CAAC,OAAO,GAAG,OAAO,CAAC;gBAC9B,OAAO;YACT,CAAC;YACD,IAAI,MAAM,CAAC,QAAQ,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;gBAChE,KAAK,CAAC,WAAW,GAAG,oDAAoD,CAAC;gBACzE,KAAK,CAAC,KAAK,CAAC,OAAO,GAAG,OAAO,CAAC;gBAC9B,OAAO;YACT,CAAC;YACD,KAAK,EAAE,CAAC;YACR,sEAAsE;YACtE,MAAM,eAAe,GAAG,MAAM,CAAC,QAAQ,KAAK,GAAG,IAAI,MAAM,CAAC,MAAM,KAAK,EAAE,IAAI,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;YAC9F,OAAO,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;QAClE,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Browser storage: IndexedDB for the session, `sessionStorage` for the short-lived
3
+ * authorization transaction.
4
+ *
5
+ * IndexedDB is used for the session because it can store a non-extractable `CryptoKey`
6
+ * through structured clone; `sessionStorage` is used for the PKCE verifier so it dies
7
+ * with the tab and is never shared between tabs.
8
+ */
9
+ import type { PendingAuthorizationStore, SessionStorageAdapter } from "../types.js";
10
+ /** IndexedDB database name. */
11
+ export declare const DB_NAME = "seba";
12
+ /** Object store holding exactly one session record. */
13
+ export declare const STORE_NAME = "session";
14
+ /** Key of the single session record. */
15
+ export declare const SESSION_KEY = "current";
16
+ /** `sessionStorage` key for the pending authorization transaction. */
17
+ export declare const PENDING_AUTH_KEY = "seba.pending-authorization";
18
+ /** Maximum age of an authorization transaction (10 minutes). */
19
+ export declare const PENDING_AUTH_TTL_MS: number;
20
+ /**
21
+ * Create the IndexedDB-backed session store.
22
+ *
23
+ * Only {@link PersistedSession} is written; access tokens never reach this code.
24
+ */
25
+ export declare function createIndexedDbStorage(): SessionStorageAdapter;
26
+ /**
27
+ * Create the `sessionStorage`-backed authorization transaction store.
28
+ *
29
+ * Expired transactions are discarded on read instead of being resumed.
30
+ */
31
+ export declare function createSessionStoragePendingAuthStore(): PendingAuthorizationStore;
32
+ //# sourceMappingURL=storage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../src/browser/storage.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,KAAK,EAEV,yBAAyB,EAEzB,qBAAqB,EACtB,MAAM,aAAa,CAAC;AAErB,+BAA+B;AAC/B,eAAO,MAAM,OAAO,SAAS,CAAC;AAE9B,uDAAuD;AACvD,eAAO,MAAM,UAAU,YAAY,CAAC;AAEpC,wCAAwC;AACxC,eAAO,MAAM,WAAW,YAAY,CAAC;AAErC,sEAAsE;AACtE,eAAO,MAAM,gBAAgB,+BAA+B,CAAC;AAE7D,gEAAgE;AAChE,eAAO,MAAM,mBAAmB,QAAiB,CAAC;AAwBlD;;;;GAIG;AACH,wBAAgB,sBAAsB,IAAI,qBAAqB,CAgB9D;AAED;;;;GAIG;AACH,wBAAgB,oCAAoC,IAAI,yBAAyB,CAmChF"}
@@ -0,0 +1,121 @@
1
+ /**
2
+ * Browser storage: IndexedDB for the session, `sessionStorage` for the short-lived
3
+ * authorization transaction.
4
+ *
5
+ * IndexedDB is used for the session because it can store a non-extractable `CryptoKey`
6
+ * through structured clone; `sessionStorage` is used for the PKCE verifier so it dies
7
+ * with the tab and is never shared between tabs.
8
+ */
9
+ import { openDB } from "idb";
10
+ import { SebaAuthError, SebaConfigError } from "../core/errors.js";
11
+ /** IndexedDB database name. */
12
+ export const DB_NAME = "seba";
13
+ /** Object store holding exactly one session record. */
14
+ export const STORE_NAME = "session";
15
+ /** Key of the single session record. */
16
+ export const SESSION_KEY = "current";
17
+ /** `sessionStorage` key for the pending authorization transaction. */
18
+ export const PENDING_AUTH_KEY = "seba.pending-authorization";
19
+ /** Maximum age of an authorization transaction (10 minutes). */
20
+ export const PENDING_AUTH_TTL_MS = 10 * 60 * 1000;
21
+ let database = null;
22
+ function open() {
23
+ if (typeof indexedDB === "undefined") {
24
+ throw new SebaConfigError("IndexedDB is not available in this environment. Use storage: \"memory\" or run in a browser.");
25
+ }
26
+ database ??= openDB(DB_NAME, 1, {
27
+ upgrade(db) {
28
+ if (!db.objectStoreNames.contains(STORE_NAME)) {
29
+ db.createObjectStore(STORE_NAME);
30
+ }
31
+ },
32
+ });
33
+ return database;
34
+ }
35
+ /**
36
+ * Create the IndexedDB-backed session store.
37
+ *
38
+ * Only {@link PersistedSession} is written; access tokens never reach this code.
39
+ */
40
+ export function createIndexedDbStorage() {
41
+ return {
42
+ async save(session) {
43
+ const db = await open();
44
+ await db.put(STORE_NAME, structuredClone(session), SESSION_KEY);
45
+ },
46
+ async load() {
47
+ const db = await open();
48
+ const value = await db.get(STORE_NAME, SESSION_KEY);
49
+ return value ?? null;
50
+ },
51
+ async clear() {
52
+ const db = await open();
53
+ await db.delete(STORE_NAME, SESSION_KEY);
54
+ },
55
+ };
56
+ }
57
+ /**
58
+ * Create the `sessionStorage`-backed authorization transaction store.
59
+ *
60
+ * Expired transactions are discarded on read instead of being resumed.
61
+ */
62
+ export function createSessionStoragePendingAuthStore() {
63
+ return {
64
+ async save(pending) {
65
+ const storage = sessionStorageOrThrow();
66
+ storage.setItem(PENDING_AUTH_KEY, JSON.stringify(pending));
67
+ },
68
+ async load() {
69
+ const storage = sessionStorageOrThrow();
70
+ const raw = storage.getItem(PENDING_AUTH_KEY);
71
+ if (raw === null) {
72
+ return null;
73
+ }
74
+ let parsed;
75
+ try {
76
+ parsed = JSON.parse(raw);
77
+ }
78
+ catch {
79
+ storage.removeItem(PENDING_AUTH_KEY);
80
+ return null;
81
+ }
82
+ if (!isPendingAuthorization(parsed)) {
83
+ storage.removeItem(PENDING_AUTH_KEY);
84
+ return null;
85
+ }
86
+ if (Date.now() - parsed.createdAt > PENDING_AUTH_TTL_MS) {
87
+ storage.removeItem(PENDING_AUTH_KEY);
88
+ throw new SebaAuthError("The pending login expired after 10 minutes. Start the login again from the application.");
89
+ }
90
+ return parsed;
91
+ },
92
+ async clear() {
93
+ sessionStorageOrThrow().removeItem(PENDING_AUTH_KEY);
94
+ },
95
+ };
96
+ }
97
+ function sessionStorageOrThrow() {
98
+ try {
99
+ if (typeof sessionStorage === "undefined") {
100
+ throw new Error("sessionStorage is undefined");
101
+ }
102
+ return sessionStorage;
103
+ }
104
+ catch (error) {
105
+ throw new SebaConfigError("sessionStorage is unavailable, so an interactive login cannot be started safely.", { cause: error });
106
+ }
107
+ }
108
+ function isPendingAuthorization(value) {
109
+ if (typeof value !== "object" || value === null) {
110
+ return false;
111
+ }
112
+ const record = value;
113
+ return (typeof record["state"] === "string" &&
114
+ typeof record["codeVerifier"] === "string" &&
115
+ typeof record["nonce"] === "string" &&
116
+ typeof record["issuer"] === "string" &&
117
+ typeof record["clientId"] === "string" &&
118
+ typeof record["redirectUri"] === "string" &&
119
+ typeof record["createdAt"] === "number");
120
+ }
121
+ //# sourceMappingURL=storage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage.js","sourceRoot":"","sources":["../../src/browser/storage.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,MAAM,EAAoC,MAAM,KAAK,CAAC;AAC/D,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAQnE,+BAA+B;AAC/B,MAAM,CAAC,MAAM,OAAO,GAAG,MAAM,CAAC;AAE9B,uDAAuD;AACvD,MAAM,CAAC,MAAM,UAAU,GAAG,SAAS,CAAC;AAEpC,wCAAwC;AACxC,MAAM,CAAC,MAAM,WAAW,GAAG,SAAS,CAAC;AAErC,sEAAsE;AACtE,MAAM,CAAC,MAAM,gBAAgB,GAAG,4BAA4B,CAAC;AAE7D,gEAAgE;AAChE,MAAM,CAAC,MAAM,mBAAmB,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AAMlD,IAAI,QAAQ,GAAyC,IAAI,CAAC;AAE1D,SAAS,IAAI;IACX,IAAI,OAAO,SAAS,KAAK,WAAW,EAAE,CAAC;QACrC,MAAM,IAAI,eAAe,CACvB,8FAA8F,CAC/F,CAAC;IACJ,CAAC;IACD,QAAQ,KAAK,MAAM,CAAS,OAAO,EAAE,CAAC,EAAE;QACtC,OAAO,CAAC,EAAE;YACR,IAAI,CAAC,EAAE,CAAC,gBAAgB,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;gBAC9C,EAAE,CAAC,iBAAiB,CAAC,UAAU,CAAC,CAAC;YACnC,CAAC;QACH,CAAC;KACF,CAAC,CAAC;IACH,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,sBAAsB;IACpC,OAAO;QACL,KAAK,CAAC,IAAI,CAAC,OAAO;YAChB,MAAM,EAAE,GAAG,MAAM,IAAI,EAAE,CAAC;YACxB,MAAM,EAAE,CAAC,GAAG,CAAC,UAAU,EAAE,eAAe,CAAC,OAAO,CAAC,EAAE,WAAW,CAAC,CAAC;QAClE,CAAC;QACD,KAAK,CAAC,IAAI;YACR,MAAM,EAAE,GAAG,MAAM,IAAI,EAAE,CAAC;YACxB,MAAM,KAAK,GAAG,MAAM,EAAE,CAAC,GAAG,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC;YACpD,OAAO,KAAK,IAAI,IAAI,CAAC;QACvB,CAAC;QACD,KAAK,CAAC,KAAK;YACT,MAAM,EAAE,GAAG,MAAM,IAAI,EAAE,CAAC;YACxB,MAAM,EAAE,CAAC,MAAM,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC;QAC3C,CAAC;KACF,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,oCAAoC;IAClD,OAAO;QACL,KAAK,CAAC,IAAI,CAAC,OAAO;YAChB,MAAM,OAAO,GAAG,qBAAqB,EAAE,CAAC;YACxC,OAAO,CAAC,OAAO,CAAC,gBAAgB,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC;QAC7D,CAAC;QACD,KAAK,CAAC,IAAI;YACR,MAAM,OAAO,GAAG,qBAAqB,EAAE,CAAC;YACxC,MAAM,GAAG,GAAG,OAAO,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC;YAC9C,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;gBACjB,OAAO,IAAI,CAAC;YACd,CAAC;YACD,IAAI,MAAe,CAAC;YACpB,IAAI,CAAC;gBACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YAC3B,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,CAAC,UAAU,CAAC,gBAAgB,CAAC,CAAC;gBACrC,OAAO,IAAI,CAAC;YACd,CAAC;YACD,IAAI,CAAC,sBAAsB,CAAC,MAAM,CAAC,EAAE,CAAC;gBACpC,OAAO,CAAC,UAAU,CAAC,gBAAgB,CAAC,CAAC;gBACrC,OAAO,IAAI,CAAC;YACd,CAAC;YACD,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,MAAM,CAAC,SAAS,GAAG,mBAAmB,EAAE,CAAC;gBACxD,OAAO,CAAC,UAAU,CAAC,gBAAgB,CAAC,CAAC;gBACrC,MAAM,IAAI,aAAa,CACrB,yFAAyF,CAC1F,CAAC;YACJ,CAAC;YACD,OAAO,MAAM,CAAC;QAChB,CAAC;QACD,KAAK,CAAC,KAAK;YACT,qBAAqB,EAAE,CAAC,UAAU,CAAC,gBAAgB,CAAC,CAAC;QACvD,CAAC;KACF,CAAC;AACJ,CAAC;AAED,SAAS,qBAAqB;IAC5B,IAAI,CAAC;QACH,IAAI,OAAO,cAAc,KAAK,WAAW,EAAE,CAAC;YAC1C,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAC;QACjD,CAAC;QACD,OAAO,cAAc,CAAC;IACxB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,eAAe,CACvB,kFAAkF,EAClF,EAAE,KAAK,EAAE,KAAK,EAAE,CACjB,CAAC;IACJ,CAAC;AACH,CAAC;AAED,SAAS,sBAAsB,CAAC,KAAc;IAC5C,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QAChD,OAAO,KAAK,CAAC;IACf,CAAC;IACD,MAAM,MAAM,GAAG,KAAgC,CAAC;IAChD,OAAO,CACL,OAAO,MAAM,CAAC,OAAO,CAAC,KAAK,QAAQ;QACnC,OAAO,MAAM,CAAC,cAAc,CAAC,KAAK,QAAQ;QAC1C,OAAO,MAAM,CAAC,OAAO,CAAC,KAAK,QAAQ;QACnC,OAAO,MAAM,CAAC,QAAQ,CAAC,KAAK,QAAQ;QACpC,OAAO,MAAM,CAAC,UAAU,CAAC,KAAK,QAAQ;QACtC,OAAO,MAAM,CAAC,aAAa,CAAC,KAAK,QAAQ;QACzC,OAAO,MAAM,CAAC,WAAW,CAAC,KAAK,QAAQ,CACxC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Runtime-independent implementation of the four public operations.
3
+ *
4
+ * The platform object supplies storage, navigation, callback capture and `fetch`; this
5
+ * class owns the protocol flow and the security decisions that must be identical in
6
+ * every runtime.
7
+ */
8
+ import type { LoginOptions, Platform, SebaConfig, Session } from "../types.js";
9
+ /**
10
+ * The protocol engine behind {@link Seba}.
11
+ *
12
+ * Obtained through `Seba`, which resolves the platform first. Not exported from the
13
+ * package entry point.
14
+ */
15
+ export declare class SebaClient {
16
+ #private;
17
+ constructor(config: SebaConfig, platform: Platform);
18
+ /** Current session, if any (token-free). */
19
+ get session(): Session | null;
20
+ /**
21
+ * Sign in, or finish a sign-in that the provider redirected back to this application.
22
+ *
23
+ * When the current URL carries an authorization response, the stored transaction is
24
+ * validated and the code is exchanged. Otherwise a new authorization request is
25
+ * started: the returned promise resolves after the redirect in Node.js and never
26
+ * settles in the browser (the page navigates away).
27
+ */
28
+ login(options?: LoginOptions): Promise<Session>;
29
+ /**
30
+ * Restore a previous session from storage.
31
+ *
32
+ * @returns The session, or `null` when nothing is stored.
33
+ * @throws SebaSessionExpiredError when the stored grant was revoked (state cleared).
34
+ */
35
+ restoreSession(): Promise<Session | null>;
36
+ /**
37
+ * Perform a DPoP-authenticated request.
38
+ *
39
+ * A fresh proof is created for every attempt. Same-origin redirects are followed with a
40
+ * new proof per hop; cross-origin redirects are returned to the caller unchanged, so
41
+ * credentials are never forwarded to another origin. One retry is allowed for a DPoP
42
+ * nonce challenge and one for an expired access token; non-replayable bodies are never
43
+ * resent.
44
+ */
45
+ fetch(input: RequestInfo | URL, init?: RequestInit): Promise<Response>;
46
+ /** Sign out, revoking the refresh token when the provider supports revocation. */
47
+ logout(): Promise<void>;
48
+ }
49
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/core/client.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAsBH,OAAO,KAAK,EAAE,YAAY,EAAE,QAAQ,EAAE,UAAU,EAAE,OAAO,EAAe,MAAM,aAAa,CAAC;AAyB5F;;;;;GAKG;AACH,qBAAa,UAAU;;gBAMT,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,QAAQ;IAclD,4CAA4C;IAC5C,IAAI,OAAO,IAAI,OAAO,GAAG,IAAI,CAE5B;IAED;;;;;;;OAOG;IACG,KAAK,CAAC,OAAO,GAAE,YAAiB,GAAG,OAAO,CAAC,OAAO,CAAC;IAYzD;;;;;OAKG;IACG,cAAc,IAAI,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC;IAI/C;;;;;;;;OAQG;IACG,KAAK,CAAC,KAAK,EAAE,WAAW,GAAG,GAAG,EAAE,IAAI,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,QAAQ,CAAC;IA6E5E,kFAAkF;IAC5E,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;CAmK9B"}