@authon/js 0.3.5 → 0.4.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.
- package/dist/index.cjs +145 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +145 -5
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -129,6 +129,7 @@ var ModalRenderer = class {
|
|
|
129
129
|
shadowRoot = null;
|
|
130
130
|
hostElement = null;
|
|
131
131
|
containerElement = null;
|
|
132
|
+
containerId = null;
|
|
132
133
|
mode;
|
|
133
134
|
theme;
|
|
134
135
|
branding;
|
|
@@ -154,11 +155,16 @@ var ModalRenderer = class {
|
|
|
154
155
|
turnstileWidgetId = null;
|
|
155
156
|
turnstileToken = "";
|
|
156
157
|
turnstileWrapper = null;
|
|
158
|
+
// Dev Teleport (test mode)
|
|
159
|
+
isTestMode = false;
|
|
160
|
+
onDevTeleport = null;
|
|
157
161
|
constructor(options) {
|
|
158
162
|
this.mode = options.mode;
|
|
159
163
|
this.theme = options.theme || "auto";
|
|
160
164
|
this.branding = { ...DEFAULT_BRANDING, ...options.branding };
|
|
161
165
|
this.captchaSiteKey = options.captchaSiteKey || "";
|
|
166
|
+
this.isTestMode = options.isTestMode || false;
|
|
167
|
+
this.onDevTeleport = options.onDevTeleport || null;
|
|
162
168
|
this.onProviderClick = options.onProviderClick;
|
|
163
169
|
this.onEmailSubmit = options.onEmailSubmit;
|
|
164
170
|
this.onClose = options.onClose;
|
|
@@ -171,9 +177,20 @@ var ModalRenderer = class {
|
|
|
171
177
|
this.onPasskeyClick = options.onPasskeyClick || (() => {
|
|
172
178
|
});
|
|
173
179
|
if (options.mode === "embedded" && options.containerId) {
|
|
174
|
-
this.
|
|
180
|
+
this.containerId = options.containerId;
|
|
175
181
|
}
|
|
176
182
|
}
|
|
183
|
+
resolveContainerElement() {
|
|
184
|
+
if (this.mode !== "embedded" || !this.containerId) return null;
|
|
185
|
+
const next = document.getElementById(this.containerId);
|
|
186
|
+
if (this.containerElement !== next) {
|
|
187
|
+
this.hostElement?.remove();
|
|
188
|
+
this.hostElement = null;
|
|
189
|
+
this.shadowRoot = null;
|
|
190
|
+
}
|
|
191
|
+
this.containerElement = next;
|
|
192
|
+
return next;
|
|
193
|
+
}
|
|
177
194
|
setProviders(providers) {
|
|
178
195
|
this.enabledProviders = providers;
|
|
179
196
|
}
|
|
@@ -181,6 +198,11 @@ var ModalRenderer = class {
|
|
|
181
198
|
this.branding = { ...DEFAULT_BRANDING, ...branding };
|
|
182
199
|
}
|
|
183
200
|
open(view = "signIn") {
|
|
201
|
+
this.resolveContainerElement();
|
|
202
|
+
if (this.hostElement && !this.hostElement.isConnected) {
|
|
203
|
+
this.hostElement = null;
|
|
204
|
+
this.shadowRoot = null;
|
|
205
|
+
}
|
|
184
206
|
if (this.shadowRoot && this.hostElement) {
|
|
185
207
|
this.hideOverlay();
|
|
186
208
|
this.switchView(view);
|
|
@@ -210,8 +232,9 @@ var ModalRenderer = class {
|
|
|
210
232
|
this.hostElement = null;
|
|
211
233
|
this.shadowRoot = null;
|
|
212
234
|
}
|
|
213
|
-
|
|
214
|
-
|
|
235
|
+
const liveContainer = this.resolveContainerElement();
|
|
236
|
+
if (liveContainer) {
|
|
237
|
+
liveContainer.replaceChildren();
|
|
215
238
|
}
|
|
216
239
|
this.currentOverlay = "none";
|
|
217
240
|
}
|
|
@@ -377,8 +400,14 @@ var ModalRenderer = class {
|
|
|
377
400
|
this.hostElement = host;
|
|
378
401
|
if (this.mode === "popup") {
|
|
379
402
|
document.body.appendChild(host);
|
|
380
|
-
} else
|
|
381
|
-
this.
|
|
403
|
+
} else {
|
|
404
|
+
const container = this.resolveContainerElement();
|
|
405
|
+
if (!container) {
|
|
406
|
+
this.hostElement = null;
|
|
407
|
+
throw new Error(`Authon container "#${this.containerId}" not found`);
|
|
408
|
+
}
|
|
409
|
+
container.replaceChildren();
|
|
410
|
+
container.appendChild(host);
|
|
382
411
|
}
|
|
383
412
|
this.shadowRoot = host.attachShadow({ mode: "open" });
|
|
384
413
|
this.shadowRoot.innerHTML = this.buildShell(view);
|
|
@@ -479,6 +508,16 @@ var ModalRenderer = class {
|
|
|
479
508
|
${authMethods}
|
|
480
509
|
<p class="switch-view">${subtitle} <a href="#" id="switch-link">${subtitleLink}</a></p>
|
|
481
510
|
${footer}
|
|
511
|
+
${this.isTestMode ? `<div class="dev-teleport">
|
|
512
|
+
<div class="dev-teleport-label">
|
|
513
|
+
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M13 2L3 14h9l-1 8 10-12h-9l1-8z"/></svg>
|
|
514
|
+
Dev Teleport
|
|
515
|
+
</div>
|
|
516
|
+
<div class="dev-teleport-row">
|
|
517
|
+
<input type="email" placeholder="test@example.com" id="dev-teleport-email" class="dev-teleport-input" value="dev@test.com" />
|
|
518
|
+
<button type="button" id="dev-teleport-btn" class="dev-teleport-btn">Go</button>
|
|
519
|
+
</div>
|
|
520
|
+
</div>` : ""}
|
|
482
521
|
${b.showSecuredBy !== false ? `<div class="secured-by">Secured by <a href="https://authon.dev" target="_blank" rel="noopener noreferrer" class="secured-link">Authon</a></div>` : ""}
|
|
483
522
|
`;
|
|
484
523
|
}
|
|
@@ -655,6 +694,34 @@ var ModalRenderer = class {
|
|
|
655
694
|
.secured-link { font-weight: 600; color: var(--authon-muted); text-decoration: none; }
|
|
656
695
|
.secured-link:hover { text-decoration: underline; }
|
|
657
696
|
|
|
697
|
+
/* Dev Teleport */
|
|
698
|
+
.dev-teleport {
|
|
699
|
+
margin-top: 12px; padding: 10px;
|
|
700
|
+
border-radius: calc(var(--authon-radius) * 0.5);
|
|
701
|
+
background: rgba(251,191,36,0.06);
|
|
702
|
+
border: 1px dashed rgba(251,191,36,0.25);
|
|
703
|
+
}
|
|
704
|
+
.dev-teleport-label {
|
|
705
|
+
display: flex; align-items: center; gap: 4px;
|
|
706
|
+
font-size: 10px; font-weight: 600; color: #fbbf24;
|
|
707
|
+
margin-bottom: 8px; text-transform: uppercase; letter-spacing: 0.05em;
|
|
708
|
+
}
|
|
709
|
+
.dev-teleport-row { display: flex; gap: 6px; }
|
|
710
|
+
.dev-teleport-input {
|
|
711
|
+
flex: 1; padding: 6px 10px; font-size: 12px;
|
|
712
|
+
border-radius: calc(var(--authon-radius) * 0.4);
|
|
713
|
+
background: rgba(0,0,0,0.2); border: 1px solid rgba(251,191,36,0.2);
|
|
714
|
+
color: #fbbf24; outline: none; font-family: ui-monospace, monospace;
|
|
715
|
+
}
|
|
716
|
+
.dev-teleport-input:focus { border-color: rgba(251,191,36,0.5); }
|
|
717
|
+
.dev-teleport-btn {
|
|
718
|
+
padding: 6px 14px; font-size: 11px; font-weight: 700;
|
|
719
|
+
border-radius: calc(var(--authon-radius) * 0.4);
|
|
720
|
+
background: rgba(251,191,36,0.15); border: 1px solid rgba(251,191,36,0.3);
|
|
721
|
+
color: #fbbf24; cursor: pointer;
|
|
722
|
+
}
|
|
723
|
+
.dev-teleport-btn:hover { background: rgba(251,191,36,0.25); }
|
|
724
|
+
|
|
658
725
|
/* Auth method buttons */
|
|
659
726
|
.auth-methods { display: flex; flex-direction: column; gap: 8px; }
|
|
660
727
|
.auth-method-btn {
|
|
@@ -1100,6 +1167,21 @@ var ModalRenderer = class {
|
|
|
1100
1167
|
});
|
|
1101
1168
|
}
|
|
1102
1169
|
this.renderTurnstile();
|
|
1170
|
+
const devTeleportBtn = this.shadowRoot.getElementById("dev-teleport-btn");
|
|
1171
|
+
const devTeleportEmail = this.shadowRoot.getElementById("dev-teleport-email");
|
|
1172
|
+
if (devTeleportBtn && devTeleportEmail && this.onDevTeleport) {
|
|
1173
|
+
const handler = this.onDevTeleport;
|
|
1174
|
+
devTeleportBtn.addEventListener("click", () => {
|
|
1175
|
+
const email = devTeleportEmail.value.trim();
|
|
1176
|
+
if (email) handler(email);
|
|
1177
|
+
});
|
|
1178
|
+
devTeleportEmail.addEventListener("keydown", (e) => {
|
|
1179
|
+
if (e.key === "Enter") {
|
|
1180
|
+
const email = devTeleportEmail.value.trim();
|
|
1181
|
+
if (email) handler(email);
|
|
1182
|
+
}
|
|
1183
|
+
});
|
|
1184
|
+
}
|
|
1103
1185
|
const backBtn = this.shadowRoot.getElementById("back-btn");
|
|
1104
1186
|
if (backBtn) {
|
|
1105
1187
|
backBtn.addEventListener("click", () => {
|
|
@@ -1136,9 +1218,42 @@ var SessionManager = class {
|
|
|
1136
1218
|
refreshTimer = null;
|
|
1137
1219
|
apiUrl;
|
|
1138
1220
|
publishableKey;
|
|
1221
|
+
storageKey;
|
|
1139
1222
|
constructor(publishableKey, apiUrl) {
|
|
1140
1223
|
this.publishableKey = publishableKey;
|
|
1141
1224
|
this.apiUrl = apiUrl;
|
|
1225
|
+
this.storageKey = `authon_session_${publishableKey.slice(0, 16)}`;
|
|
1226
|
+
this.restoreFromStorage();
|
|
1227
|
+
}
|
|
1228
|
+
restoreFromStorage() {
|
|
1229
|
+
if (typeof window === "undefined") return;
|
|
1230
|
+
try {
|
|
1231
|
+
const stored = localStorage.getItem(this.storageKey);
|
|
1232
|
+
if (!stored) return;
|
|
1233
|
+
const data = JSON.parse(stored);
|
|
1234
|
+
if (data.accessToken && data.refreshToken && data.user) {
|
|
1235
|
+
this.accessToken = data.accessToken;
|
|
1236
|
+
this.refreshToken = data.refreshToken;
|
|
1237
|
+
this.user = data.user;
|
|
1238
|
+
this.scheduleRefresh(5);
|
|
1239
|
+
}
|
|
1240
|
+
} catch {
|
|
1241
|
+
}
|
|
1242
|
+
}
|
|
1243
|
+
persistToStorage() {
|
|
1244
|
+
if (typeof window === "undefined") return;
|
|
1245
|
+
try {
|
|
1246
|
+
if (this.accessToken && this.refreshToken && this.user) {
|
|
1247
|
+
localStorage.setItem(this.storageKey, JSON.stringify({
|
|
1248
|
+
accessToken: this.accessToken,
|
|
1249
|
+
refreshToken: this.refreshToken,
|
|
1250
|
+
user: this.user
|
|
1251
|
+
}));
|
|
1252
|
+
} else {
|
|
1253
|
+
localStorage.removeItem(this.storageKey);
|
|
1254
|
+
}
|
|
1255
|
+
} catch {
|
|
1256
|
+
}
|
|
1142
1257
|
}
|
|
1143
1258
|
getToken() {
|
|
1144
1259
|
return this.accessToken;
|
|
@@ -1150,6 +1265,7 @@ var SessionManager = class {
|
|
|
1150
1265
|
this.accessToken = tokens.accessToken;
|
|
1151
1266
|
this.refreshToken = tokens.refreshToken;
|
|
1152
1267
|
this.user = tokens.user;
|
|
1268
|
+
this.persistToStorage();
|
|
1153
1269
|
if (tokens.expiresIn && tokens.expiresIn > 0) {
|
|
1154
1270
|
this.scheduleRefresh(tokens.expiresIn);
|
|
1155
1271
|
}
|
|
@@ -1161,6 +1277,7 @@ var SessionManager = class {
|
|
|
1161
1277
|
this.accessToken = null;
|
|
1162
1278
|
this.refreshToken = null;
|
|
1163
1279
|
this.user = null;
|
|
1280
|
+
this.persistToStorage();
|
|
1164
1281
|
if (this.refreshTimer) {
|
|
1165
1282
|
clearTimeout(this.refreshTimer);
|
|
1166
1283
|
this.refreshTimer = null;
|
|
@@ -1956,6 +2073,18 @@ var Authon = class {
|
|
|
1956
2073
|
await this.apiPostAuth(`/v1/auth/organizations/${orgId}/leave`, void 0, token);
|
|
1957
2074
|
}
|
|
1958
2075
|
};
|
|
2076
|
+
/** Testing utilities — only available when initialized with a pk_test_ key */
|
|
2077
|
+
get testing() {
|
|
2078
|
+
if (!this.publishableKey.startsWith("pk_test_")) return void 0;
|
|
2079
|
+
return {
|
|
2080
|
+
signIn: async (params) => {
|
|
2081
|
+
const res = await this.apiPost("/v1/auth/testing/token", params);
|
|
2082
|
+
this.session.setSession(res);
|
|
2083
|
+
this.emit("signedIn", res.user);
|
|
2084
|
+
return res.user;
|
|
2085
|
+
}
|
|
2086
|
+
};
|
|
2087
|
+
}
|
|
1959
2088
|
destroy() {
|
|
1960
2089
|
this.modal?.close();
|
|
1961
2090
|
this.session.destroy();
|
|
@@ -2007,6 +2136,17 @@ var Authon = class {
|
|
|
2007
2136
|
containerId: this.config.containerId,
|
|
2008
2137
|
branding: this.branding || void 0,
|
|
2009
2138
|
captchaSiteKey: this.captchaEnabled ? this.turnstileSiteKey : void 0,
|
|
2139
|
+
isTestMode: this.publishableKey.startsWith("pk_test_"),
|
|
2140
|
+
onDevTeleport: this.publishableKey.startsWith("pk_test_") ? async (email) => {
|
|
2141
|
+
this.modal?.clearError();
|
|
2142
|
+
try {
|
|
2143
|
+
await this.testing.signIn({ email });
|
|
2144
|
+
this.modal?.close();
|
|
2145
|
+
} catch (err) {
|
|
2146
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
2147
|
+
this.modal?.showError(msg || "Dev teleport failed");
|
|
2148
|
+
}
|
|
2149
|
+
} : void 0,
|
|
2010
2150
|
onProviderClick: (provider) => this.startOAuthFlow(provider),
|
|
2011
2151
|
onEmailSubmit: (email, password, isSignUp) => {
|
|
2012
2152
|
this.modal?.clearError();
|