@atlasauth/lit 0.0.0-stage → 0.1.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/CHANGELOG.md +5 -0
- package/README.md +33 -2
- package/dist/client.d.ts +81 -0
- package/dist/client.js +269 -0
- package/dist/client.js.map +1 -0
- package/dist/context.d.ts +16 -0
- package/dist/context.js +10 -0
- package/dist/context.js.map +1 -0
- package/dist/elements.d.ts +113 -0
- package/dist/elements.js +211 -0
- package/dist/elements.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +56 -0
- package/dist/types.js +6 -0
- package/dist/types.js.map +1 -0
- package/dist/widget.d.ts +21 -0
- package/dist/widget.js +33 -0
- package/dist/widget.js.map +1 -0
- package/package.json +44 -3
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
# @atlasauth/lit
|
|
2
|
+
|
|
3
|
+
## 0.1.0
|
|
4
|
+
|
|
5
|
+
- First release: `<atlas-provider>`, `<atlas-signed-in>`, `<atlas-signed-out>`, `<atlas-loading>`, `<atlas-protect>`, `<atlas-sign-in>`, `<atlas-sign-up>` and `<atlas-sign-out-button>`, plus `createAtlasClient` and the context for building your own elements.
|
package/README.md
CHANGED
|
@@ -1,3 +1,34 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @atlasauth/lit
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Atlas for web components. Lit elements over `@atlasauth/js`: a provider, signed-in and signed-out gates, a permission gate, and the sign-in and sign-up panels. They are plain custom elements, so they work in any framework or in none.
|
|
4
|
+
|
|
5
|
+
```html
|
|
6
|
+
<script type="module">
|
|
7
|
+
import '@atlasauth/lit';
|
|
8
|
+
</script>
|
|
9
|
+
|
|
10
|
+
<atlas-provider publishable-key="pk_live_..." frontend-api="https://auth.example.com">
|
|
11
|
+
<atlas-signed-out>
|
|
12
|
+
<atlas-sign-in redirect="/app"></atlas-sign-in>
|
|
13
|
+
</atlas-signed-out>
|
|
14
|
+
|
|
15
|
+
<atlas-signed-in>
|
|
16
|
+
<p>Welcome back.</p>
|
|
17
|
+
<atlas-protect permission="org:billing:read">
|
|
18
|
+
<a href="/billing">Billing</a>
|
|
19
|
+
<span slot="fallback">Ask an admin for billing access.</span>
|
|
20
|
+
</atlas-protect>
|
|
21
|
+
<atlas-sign-out-button>Sign out</atlas-sign-out-button>
|
|
22
|
+
</atlas-signed-in>
|
|
23
|
+
</atlas-provider>
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
| Element | Does |
|
|
27
|
+
| --- | --- |
|
|
28
|
+
| `<atlas-provider publishable-key frontend-api>` | Creates the client, boots the session, refreshes the token before it expires, shares the state. `frontend-api` is required. |
|
|
29
|
+
| `<atlas-signed-in>` / `<atlas-signed-out>` / `<atlas-loading>` | Render their children for that state. Signed-out renders only after the first boot settles, so a network blip never flashes a sign-in form. |
|
|
30
|
+
| `<atlas-protect permission require-role>` | Children when the session satisfies the condition, else the `fallback` slot. Hides UI only; your API enforces access. |
|
|
31
|
+
| `<atlas-sign-in redirect locale>` / `<atlas-sign-up>` | Mount the Atlas panel. |
|
|
32
|
+
| `<atlas-sign-out-button>` | Revokes the session and fires `atlas-signed-out`. |
|
|
33
|
+
|
|
34
|
+
For your own elements, extend `AtlasElement` and read `this.atlas` (`client`, `snapshot`, `publishableKey`, `frontendApi`), or use `createAtlasClient` directly. Get a fresh token for an API call with `client.getToken()`; verify it on the server with `@atlasauth/backend`.
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { type ProtectCondition, type ProviderToken, type SignOutOptions, type SignOutResult } from '@atlasauth/js';
|
|
2
|
+
import type { AtlasSnapshot } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* The browser Atlas client — the framework-agnostic heart of the Lit SDK.
|
|
5
|
+
*
|
|
6
|
+
* The live auth engine is a plain object with a change-listener, built on the
|
|
7
|
+
* `@atlasauth/js` primitives (`FapiClient`, `TokenCache`, the redirect and token
|
|
8
|
+
* helpers). `<atlas-provider>` creates one in the browser and republishes each
|
|
9
|
+
* snapshot to the elements below it through {@link AtlasClient.subscribe}.
|
|
10
|
+
*
|
|
11
|
+
* It holds exactly one thing that matters in memory: the token. Not
|
|
12
|
+
* localStorage, not a cookie this code writes — the refresh token is HttpOnly
|
|
13
|
+
* so browser script never touches it, and the short-lived JWT lives only as
|
|
14
|
+
* long as the tab. A client that persisted either would survive the tab and
|
|
15
|
+
* become the thing an XSS reads first.
|
|
16
|
+
*/
|
|
17
|
+
export interface AtlasClient {
|
|
18
|
+
readonly publishableKey: string;
|
|
19
|
+
/** The instance's FAPI origin. */
|
|
20
|
+
readonly frontendApi: string;
|
|
21
|
+
/** A snapshot of the current auth state — a plain, serializable value. */
|
|
22
|
+
snapshot(): AtlasSnapshot;
|
|
23
|
+
/**
|
|
24
|
+
* Subscribe to state changes. The listener fires on every transition with the
|
|
25
|
+
* fresh snapshot, and once synchronously is NOT implied — call {@link snapshot}
|
|
26
|
+
* for the current value. Returns an unsubscribe function.
|
|
27
|
+
*/
|
|
28
|
+
subscribe(listener: (snapshot: AtlasSnapshot) => void): () => void;
|
|
29
|
+
/**
|
|
30
|
+
* §5.3: a sign-in attempt handed back by an OAuth redirect that still needs a
|
|
31
|
+
* second factor (no session was issued). Null in the ordinary case. Captured
|
|
32
|
+
* synchronously at construction — before any component reads it.
|
|
33
|
+
*/
|
|
34
|
+
readonly pendingAttempt: {
|
|
35
|
+
id: string;
|
|
36
|
+
status: string;
|
|
37
|
+
} | null;
|
|
38
|
+
/** Always fresh: refreshes first if the cached token is close to expiry. */
|
|
39
|
+
getToken(): Promise<string | null>;
|
|
40
|
+
/**
|
|
41
|
+
* §6.6 the signed-in user's OWN live token at a connected provider (Google,
|
|
42
|
+
* GitHub, …), so the app can call that provider's API. Null when there is no
|
|
43
|
+
* usable token. The server refreshes a stale token on read; the refresh token
|
|
44
|
+
* is never exposed.
|
|
45
|
+
*/
|
|
46
|
+
getProviderToken(provider: string): Promise<ProviderToken | null>;
|
|
47
|
+
/** Evaluate a role/permission condition against the live claims. */
|
|
48
|
+
has(condition: ProtectCondition): boolean;
|
|
49
|
+
/**
|
|
50
|
+
* Sign out: revoke the session on the Frontend API (retried once), run OIDC
|
|
51
|
+
* front-channel logout, then drop all local state. Resolves whether the
|
|
52
|
+
* server confirmed the revoke (`{ revoked, activeSessionId? }`); with
|
|
53
|
+
* `{ strict: true }` an unconfirmed revoke rejects with a `SignOutError`
|
|
54
|
+
* AFTER the local sign-out. Either way this browser remembers the session id
|
|
55
|
+
* and never re-adopts it on a reload, refresh, sibling tab or new tab.
|
|
56
|
+
*/
|
|
57
|
+
signOut(options?: SignOutOptions): Promise<SignOutResult>;
|
|
58
|
+
setActiveOrganization(organizationId: string | null): Promise<void>;
|
|
59
|
+
reload(): Promise<void>;
|
|
60
|
+
/**
|
|
61
|
+
* §6.3: complete a redirect-based sign-in (or, inside the OAuth popup, hand
|
|
62
|
+
* the result back to the opener), then boot the session.
|
|
63
|
+
*/
|
|
64
|
+
boot(): Promise<void>;
|
|
65
|
+
/** Tear down the refresh timer, the sibling-tab watch and all listeners. */
|
|
66
|
+
destroy(): void;
|
|
67
|
+
}
|
|
68
|
+
export interface CreateAtlasClientOptions {
|
|
69
|
+
publishableKey: string;
|
|
70
|
+
/**
|
|
71
|
+
* The instance's Frontend API: an absolute URL such as
|
|
72
|
+
* `"https://auth.example.com"`, or `"same-origin"` / a path such as `"/atlas"`
|
|
73
|
+
* behind a reverse proxy on the app's own origin. Required at runtime — a
|
|
74
|
+
* missing or malformed value throws an `AtlasConfigError`
|
|
75
|
+
* (`FRONTEND_API_REQUIRED` / `FRONTEND_API_INVALID`). Optional in the type
|
|
76
|
+
* only so existing call sites keep compiling.
|
|
77
|
+
*/
|
|
78
|
+
frontendApi?: string;
|
|
79
|
+
fetchImpl?: typeof fetch;
|
|
80
|
+
}
|
|
81
|
+
export declare function createAtlasClient(options: CreateAtlasClientOptions): AtlasClient;
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
import { FapiClient, SignOutGuard, TokenCache, closeOAuthPopupAfterSignIn, completeOAuthPopupLanding, getProviderToken as fetchProviderToken, mapOAuthPopupPayload, msUntilRefresh, readExpiry, readRedirectResult, resolveFrontendApi, stripRedirectParams, evaluate, } from '@atlasauth/js';
|
|
2
|
+
export function createAtlasClient(options) {
|
|
3
|
+
const publishableKey = options.publishableKey;
|
|
4
|
+
// Throws on a missing/invalid value rather than quietly sending every request
|
|
5
|
+
// to a relative path on the app's origin.
|
|
6
|
+
const baseUrl = resolveFrontendApi(options.frontendApi, { component: 'createAtlasClient()' });
|
|
7
|
+
const doFetch = options.fetchImpl ?? fetch;
|
|
8
|
+
// The live state. Plain fields, not reactive — changes are broadcast to
|
|
9
|
+
// subscribers, who copy a fresh snapshot into whatever reactive store they own.
|
|
10
|
+
let status = 'loading';
|
|
11
|
+
let user = null;
|
|
12
|
+
let session = null;
|
|
13
|
+
let claims = null;
|
|
14
|
+
let memberships = [];
|
|
15
|
+
const cache = new TokenCache();
|
|
16
|
+
let timer = null;
|
|
17
|
+
const listeners = new Set();
|
|
18
|
+
const snapshot = () => ({
|
|
19
|
+
status,
|
|
20
|
+
user,
|
|
21
|
+
session,
|
|
22
|
+
claims,
|
|
23
|
+
memberships,
|
|
24
|
+
});
|
|
25
|
+
const emit = () => {
|
|
26
|
+
const snap = snapshot();
|
|
27
|
+
for (const listener of listeners)
|
|
28
|
+
listener(snap);
|
|
29
|
+
scheduleRefresh();
|
|
30
|
+
};
|
|
31
|
+
const pendingAttempt = (() => {
|
|
32
|
+
if (typeof window === 'undefined')
|
|
33
|
+
return null;
|
|
34
|
+
const result = readRedirectResult(window.location.search);
|
|
35
|
+
return result?.status && !result.ticket
|
|
36
|
+
? { id: result.attemptId, status: result.status }
|
|
37
|
+
: null;
|
|
38
|
+
})();
|
|
39
|
+
const call = (path, init) => doFetch(`${baseUrl}${path}`, {
|
|
40
|
+
...init,
|
|
41
|
+
// Cookies carry the session; a fetch without this looks identical to being
|
|
42
|
+
// signed out.
|
|
43
|
+
credentials: 'include',
|
|
44
|
+
headers: {
|
|
45
|
+
'x-publishable-key': publishableKey,
|
|
46
|
+
...(init?.body ? { 'content-type': 'application/json' } : {}),
|
|
47
|
+
...init?.headers,
|
|
48
|
+
},
|
|
49
|
+
});
|
|
50
|
+
// Safer sign-out: tombstones (localStorage, per FAPI origin, shared by every
|
|
51
|
+
// tab) of the sessions this browser signed out of, the revoke with retry, and
|
|
52
|
+
// the background re-try of a revoke that did not land.
|
|
53
|
+
const guard = new SignOutGuard({ request: call, frontendApi: baseUrl });
|
|
54
|
+
const clearLocal = () => {
|
|
55
|
+
cache.clear();
|
|
56
|
+
status = 'signed_out';
|
|
57
|
+
user = null;
|
|
58
|
+
session = null;
|
|
59
|
+
claims = null;
|
|
60
|
+
memberships = [];
|
|
61
|
+
};
|
|
62
|
+
const applyToken = (jwt, sessionId) => {
|
|
63
|
+
// An in-flight refresh must not resurrect a session signed out meanwhile.
|
|
64
|
+
if (guard.isSignedOut(sessionId))
|
|
65
|
+
return;
|
|
66
|
+
const expiresAt = readExpiry(jwt);
|
|
67
|
+
if (!expiresAt)
|
|
68
|
+
return;
|
|
69
|
+
cache.set({ jwt, expiresAt, sessionId });
|
|
70
|
+
claims = decodeClaims(jwt);
|
|
71
|
+
};
|
|
72
|
+
const reload = async () => {
|
|
73
|
+
try {
|
|
74
|
+
const response = await call('/v1/client');
|
|
75
|
+
if (!response.ok)
|
|
76
|
+
throw new Error('boot failed');
|
|
77
|
+
const body = (await response.json());
|
|
78
|
+
// A session this browser signed out of is never re-adopted from a refresh
|
|
79
|
+
// cookie the revoke did not clear; the guard re-tries the revoke.
|
|
80
|
+
const refused = !!body.session && guard.refuse(body.session.id);
|
|
81
|
+
if (!body.session || !body.user || refused) {
|
|
82
|
+
clearLocal();
|
|
83
|
+
emit();
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
user = body.user;
|
|
87
|
+
session = body.session;
|
|
88
|
+
memberships = body.organization_memberships ?? [];
|
|
89
|
+
if (body.jwt)
|
|
90
|
+
applyToken(body.jwt, body.session.id);
|
|
91
|
+
status = 'signed_in';
|
|
92
|
+
emit();
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
// A failed boot is NOT signed-out. Rendering a sign-in form because the
|
|
96
|
+
// network hiccuped throws away a perfectly good session and makes the user
|
|
97
|
+
// re-authenticate for no reason.
|
|
98
|
+
if (status === 'loading') {
|
|
99
|
+
status = 'signed_out';
|
|
100
|
+
emit();
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
const refresh = async () => {
|
|
105
|
+
const current = cache.peek();
|
|
106
|
+
if (!current)
|
|
107
|
+
return;
|
|
108
|
+
try {
|
|
109
|
+
const response = await call(`/v1/client/sessions/${current.sessionId}/tokens`, {
|
|
110
|
+
method: 'POST',
|
|
111
|
+
});
|
|
112
|
+
if (!response.ok)
|
|
113
|
+
throw new Error('refresh failed');
|
|
114
|
+
const body = (await response.json());
|
|
115
|
+
applyToken(body.jwt, body.session_id);
|
|
116
|
+
emit();
|
|
117
|
+
}
|
|
118
|
+
catch {
|
|
119
|
+
// The session may genuinely be gone. Re-boot rather than guess.
|
|
120
|
+
await reload();
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
/** §7.4: proactive, jittered refresh scheduled from the token's own expiry. */
|
|
124
|
+
function scheduleRefresh() {
|
|
125
|
+
if (timer) {
|
|
126
|
+
clearTimeout(timer);
|
|
127
|
+
timer = null;
|
|
128
|
+
}
|
|
129
|
+
if (status !== 'signed_in')
|
|
130
|
+
return;
|
|
131
|
+
const token = cache.peek();
|
|
132
|
+
if (!token)
|
|
133
|
+
return;
|
|
134
|
+
const delay = msUntilRefresh({ token, now: Date.now() });
|
|
135
|
+
timer = setTimeout(() => void refresh(), delay);
|
|
136
|
+
}
|
|
137
|
+
const getToken = async () => {
|
|
138
|
+
// A 5s skew so a token that would die inside the caller's request is
|
|
139
|
+
// refreshed first rather than handed over.
|
|
140
|
+
const usable = cache.get(5_000);
|
|
141
|
+
if (usable)
|
|
142
|
+
return usable.jwt;
|
|
143
|
+
await refresh();
|
|
144
|
+
return cache.get(5_000)?.jwt ?? null;
|
|
145
|
+
};
|
|
146
|
+
// The FAPI client for the token-vault read. Reuses the same publishable key
|
|
147
|
+
// and fetch so the framework-agnostic `@atlasauth/js` helper is the single
|
|
148
|
+
// implementation this SDK surfaces.
|
|
149
|
+
const fapiClient = new FapiClient({ publishableKey, baseUrl, fetchImpl: doFetch });
|
|
150
|
+
const getProviderToken = (provider) => fetchProviderToken(fapiClient, provider);
|
|
151
|
+
const signOut = async (options) => {
|
|
152
|
+
// The session to end: from the token cache, else the booted session, else
|
|
153
|
+
// (none known yet) whatever session the cookies carry — the guard looks it
|
|
154
|
+
// up, so a missing in-memory token never skips the server-side sign-out. It
|
|
155
|
+
// tombstones the id first, revokes (retried once) and runs OIDC
|
|
156
|
+
// front-channel logout.
|
|
157
|
+
const attempt = await guard.revoke(cache.peek()?.sessionId ?? session?.id ?? null, options);
|
|
158
|
+
clearLocal();
|
|
159
|
+
emit();
|
|
160
|
+
// §L1 the server promoted another account signed in on this browser: adopt
|
|
161
|
+
// it deliberately (the revoke response already set its cookies).
|
|
162
|
+
if (guard.promoted(attempt))
|
|
163
|
+
await reload();
|
|
164
|
+
return guard.settle(attempt, options);
|
|
165
|
+
};
|
|
166
|
+
// Another tab signed out of THIS session (its tombstone reached the shared
|
|
167
|
+
// store): drop the token and re-check, which refuses the session.
|
|
168
|
+
const stopWatching = guard.watch(() => cache.peek()?.sessionId ?? session?.id, () => {
|
|
169
|
+
cache.clear();
|
|
170
|
+
void reload();
|
|
171
|
+
});
|
|
172
|
+
const setActiveOrganization = async (organizationId) => {
|
|
173
|
+
const current = cache.peek();
|
|
174
|
+
if (!current)
|
|
175
|
+
return;
|
|
176
|
+
const response = await call(`/v1/client/sessions/${current.sessionId}/touch`, {
|
|
177
|
+
method: 'POST',
|
|
178
|
+
body: JSON.stringify({ active_organization_id: organizationId }),
|
|
179
|
+
});
|
|
180
|
+
if (!response.ok)
|
|
181
|
+
return;
|
|
182
|
+
const body = (await response.json());
|
|
183
|
+
// The new token carries the new org claims; re-boot would work too but costs
|
|
184
|
+
// a round trip for information already in hand.
|
|
185
|
+
applyToken(body.jwt, current.sessionId);
|
|
186
|
+
await reload();
|
|
187
|
+
};
|
|
188
|
+
/*
|
|
189
|
+
* §oauth popup mode: this page may also be running INSIDE the sign-in popup.
|
|
190
|
+
* - As the landing of a popup whose opener was severed by a
|
|
191
|
+
* Cross-Origin-Opener-Policy (`#atlas_popup_result=…`): relay the result
|
|
192
|
+
* to the opener over BroadcastChannel and close. If no opener takes it
|
|
193
|
+
* (its tab is gone), finish the sign-in here like a redirect.
|
|
194
|
+
* - After finishing a sign-in here (the redirect flow ran in the popup): tell
|
|
195
|
+
* the waiting opener and close the popup.
|
|
196
|
+
*/
|
|
197
|
+
const boot = async () => {
|
|
198
|
+
const browser = typeof window !== 'undefined';
|
|
199
|
+
const fromUrl = browser ? readRedirectResult(window.location.search) : null;
|
|
200
|
+
let result = fromUrl;
|
|
201
|
+
const landing = browser ? await completeOAuthPopupLanding().catch(() => null) : null;
|
|
202
|
+
if (landing && !landing.delivered) {
|
|
203
|
+
const outcome = mapOAuthPopupPayload(landing.payload);
|
|
204
|
+
if (outcome?.ticket && outcome.attemptId) {
|
|
205
|
+
result = { attemptId: outcome.attemptId, ticket: outcome.ticket };
|
|
206
|
+
}
|
|
207
|
+
else if (outcome?.continuationUrl) {
|
|
208
|
+
// A second factor / connect / provider error: the redirect flow's page.
|
|
209
|
+
window.location.replace(outcome.continuationUrl);
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
// When the landing was delivered the opener redeems the ticket, not us.
|
|
214
|
+
let exchanged = false;
|
|
215
|
+
if (result?.ticket) {
|
|
216
|
+
const response = await call('/v1/client/tickets/exchange', {
|
|
217
|
+
method: 'POST',
|
|
218
|
+
body: JSON.stringify({ attempt_id: result.attemptId, ticket: result.ticket }),
|
|
219
|
+
}).catch(() => undefined);
|
|
220
|
+
exchanged = !!response?.ok;
|
|
221
|
+
}
|
|
222
|
+
if (fromUrl && browser) {
|
|
223
|
+
window.history.replaceState({}, document.title, stripRedirectParams(window.location.href));
|
|
224
|
+
}
|
|
225
|
+
await reload();
|
|
226
|
+
// Signed in inside the Atlas popup: hand back to the opener and close.
|
|
227
|
+
if (exchanged)
|
|
228
|
+
void closeOAuthPopupAfterSignIn();
|
|
229
|
+
};
|
|
230
|
+
const destroy = () => {
|
|
231
|
+
if (timer) {
|
|
232
|
+
clearTimeout(timer);
|
|
233
|
+
timer = null;
|
|
234
|
+
}
|
|
235
|
+
stopWatching();
|
|
236
|
+
guard.dispose();
|
|
237
|
+
listeners.clear();
|
|
238
|
+
};
|
|
239
|
+
return {
|
|
240
|
+
publishableKey,
|
|
241
|
+
frontendApi: baseUrl,
|
|
242
|
+
snapshot,
|
|
243
|
+
subscribe(listener) {
|
|
244
|
+
listeners.add(listener);
|
|
245
|
+
return () => listeners.delete(listener);
|
|
246
|
+
},
|
|
247
|
+
pendingAttempt,
|
|
248
|
+
getToken,
|
|
249
|
+
getProviderToken,
|
|
250
|
+
has: (condition) => evaluate(claims, condition).allowed,
|
|
251
|
+
signOut,
|
|
252
|
+
setActiveOrganization,
|
|
253
|
+
reload,
|
|
254
|
+
boot,
|
|
255
|
+
destroy,
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
function decodeClaims(jwt) {
|
|
259
|
+
const parts = jwt.split('.');
|
|
260
|
+
if (parts.length !== 3)
|
|
261
|
+
return null;
|
|
262
|
+
try {
|
|
263
|
+
return JSON.parse(atob(parts[1].replace(/-/g, '+').replace(/_/g, '/')));
|
|
264
|
+
}
|
|
265
|
+
catch {
|
|
266
|
+
return null;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { AtlasClient } from './client';
|
|
2
|
+
import type { AtlasSnapshot } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* What `<atlas-provider>` shares with every element below it. `client` is null on the server and
|
|
5
|
+
* before the provider connects; `snapshot.status` is `loading` until the first boot settles.
|
|
6
|
+
*/
|
|
7
|
+
export interface AtlasState {
|
|
8
|
+
client: AtlasClient | null;
|
|
9
|
+
snapshot: AtlasSnapshot;
|
|
10
|
+
publishableKey: string;
|
|
11
|
+
frontendApi: string;
|
|
12
|
+
}
|
|
13
|
+
export declare const atlasContext: {
|
|
14
|
+
__context__: AtlasState;
|
|
15
|
+
};
|
|
16
|
+
export declare const loadingSnapshot: AtlasSnapshot;
|
package/dist/context.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { createContext } from '@lit/context';
|
|
2
|
+
export const atlasContext = createContext(Symbol.for('atlasauth.lit.state'));
|
|
3
|
+
export const loadingSnapshot = {
|
|
4
|
+
status: 'loading',
|
|
5
|
+
user: null,
|
|
6
|
+
session: null,
|
|
7
|
+
claims: null,
|
|
8
|
+
memberships: [],
|
|
9
|
+
};
|
|
10
|
+
//# sourceMappingURL=context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.js","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAe7C,MAAM,CAAC,MAAM,YAAY,GAAG,aAAa,CAAa,MAAM,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAAC,CAAC;AAEzF,MAAM,CAAC,MAAM,eAAe,GAAkB;IAC5C,MAAM,EAAE,SAAS;IACjB,IAAI,EAAE,IAAI;IACV,OAAO,EAAE,IAAI;IACb,MAAM,EAAE,IAAI;IACZ,WAAW,EAAE,EAAE;CAChB,CAAC"}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { LitElement, nothing, type PropertyValues } from 'lit';
|
|
2
|
+
import { type AtlasState } from './context';
|
|
3
|
+
import { type WidgetMode, type WidgetMounter } from './widget';
|
|
4
|
+
/**
|
|
5
|
+
* `<atlas-provider publishable-key="pk_…" frontend-api="https://auth.example.com">`
|
|
6
|
+
*
|
|
7
|
+
* Creates the Atlas client in the browser, boots the session (completing an OAuth redirect if the
|
|
8
|
+
* page is one), refreshes the token before it expires, and shares the state with every Atlas
|
|
9
|
+
* element below it. Put it once near the top of the page. `frontend-api` is required; a missing
|
|
10
|
+
* or malformed value throws an `AtlasConfigError` when the element connects.
|
|
11
|
+
*/
|
|
12
|
+
export declare class AtlasProvider extends LitElement {
|
|
13
|
+
static properties: {
|
|
14
|
+
publishableKey: {
|
|
15
|
+
type: StringConstructor;
|
|
16
|
+
attribute: string;
|
|
17
|
+
};
|
|
18
|
+
frontendApi: {
|
|
19
|
+
type: StringConstructor;
|
|
20
|
+
attribute: string;
|
|
21
|
+
};
|
|
22
|
+
};
|
|
23
|
+
publishableKey: string;
|
|
24
|
+
frontendApi: string;
|
|
25
|
+
/** Replace `fetch` (tests, custom transports). */
|
|
26
|
+
fetchImpl?: typeof fetch;
|
|
27
|
+
private client;
|
|
28
|
+
private unsubscribe;
|
|
29
|
+
private readonly provider;
|
|
30
|
+
constructor();
|
|
31
|
+
connectedCallback(): void;
|
|
32
|
+
disconnectedCallback(): void;
|
|
33
|
+
protected willUpdate(changed: PropertyValues): void;
|
|
34
|
+
private start;
|
|
35
|
+
private stop;
|
|
36
|
+
protected render(): import("lit").TemplateResult<1>;
|
|
37
|
+
}
|
|
38
|
+
/** Base class for elements that read the Atlas state: re-renders on every change. */
|
|
39
|
+
export declare abstract class AtlasElement extends LitElement {
|
|
40
|
+
private readonly consumer;
|
|
41
|
+
protected get atlas(): AtlasState;
|
|
42
|
+
}
|
|
43
|
+
/** `<atlas-signed-in>…</atlas-signed-in>` renders its children only for a signed-in user. */
|
|
44
|
+
export declare class AtlasSignedIn extends AtlasElement {
|
|
45
|
+
protected render(): import("lit").TemplateResult<1> | typeof nothing;
|
|
46
|
+
}
|
|
47
|
+
/** `<atlas-signed-out>…</atlas-signed-out>` renders its children only once the session is known to be signed out. */
|
|
48
|
+
export declare class AtlasSignedOut extends AtlasElement {
|
|
49
|
+
protected render(): import("lit").TemplateResult<1> | typeof nothing;
|
|
50
|
+
}
|
|
51
|
+
/** `<atlas-loading>…</atlas-loading>` renders its children until the first boot settles. */
|
|
52
|
+
export declare class AtlasLoading extends AtlasElement {
|
|
53
|
+
protected render(): import("lit").TemplateResult<1> | typeof nothing;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* `<atlas-protect permission="org:billing:read">…</atlas-protect>` renders its children when the
|
|
57
|
+
* signed-in session satisfies the condition, else the `fallback` slot. Conditions: `permission`,
|
|
58
|
+
* `require-role` (the `role` attribute is ARIA's). A signed-out visitor, or an unknown state, never passes. This hides UI only; your API
|
|
59
|
+
* is what enforces access.
|
|
60
|
+
*/
|
|
61
|
+
export declare class AtlasProtect extends AtlasElement {
|
|
62
|
+
static properties: {
|
|
63
|
+
permission: {
|
|
64
|
+
type: StringConstructor;
|
|
65
|
+
};
|
|
66
|
+
requireRole: {
|
|
67
|
+
type: StringConstructor;
|
|
68
|
+
attribute: string;
|
|
69
|
+
};
|
|
70
|
+
};
|
|
71
|
+
permission: string | undefined;
|
|
72
|
+
requireRole: string | undefined;
|
|
73
|
+
protected render(): import("lit").TemplateResult<1>;
|
|
74
|
+
}
|
|
75
|
+
/** `<atlas-sign-out-button>Sign out</atlas-sign-out-button>` signs out and fires `atlas-signed-out`. */
|
|
76
|
+
export declare class AtlasSignOutButton extends AtlasElement {
|
|
77
|
+
protected render(): import("lit").TemplateResult<1> | typeof nothing;
|
|
78
|
+
private readonly onClick;
|
|
79
|
+
}
|
|
80
|
+
/** Shared by the two widget elements: mounts the Atlas panel into this element's light DOM. */
|
|
81
|
+
declare abstract class AtlasWidgetElement extends AtlasElement {
|
|
82
|
+
static properties: {
|
|
83
|
+
redirect: {
|
|
84
|
+
type: StringConstructor;
|
|
85
|
+
};
|
|
86
|
+
locale: {
|
|
87
|
+
type: StringConstructor;
|
|
88
|
+
};
|
|
89
|
+
};
|
|
90
|
+
redirect: string | undefined;
|
|
91
|
+
locale: string | undefined;
|
|
92
|
+
/** Replace the mount function (tests). */
|
|
93
|
+
mounter?: WidgetMounter;
|
|
94
|
+
protected abstract readonly mode: WidgetMode;
|
|
95
|
+
private cleanup;
|
|
96
|
+
private mountedFor;
|
|
97
|
+
private readonly slotEl;
|
|
98
|
+
protected createRenderRoot(): HTMLElement;
|
|
99
|
+
protected updated(): void;
|
|
100
|
+
disconnectedCallback(): void;
|
|
101
|
+
protected render(): symbol;
|
|
102
|
+
}
|
|
103
|
+
/** `<atlas-sign-in redirect="/app">` mounts the Atlas sign-in panel. */
|
|
104
|
+
export declare class AtlasSignIn extends AtlasWidgetElement {
|
|
105
|
+
protected readonly mode: "sign-in";
|
|
106
|
+
}
|
|
107
|
+
/** `<atlas-sign-up redirect="/app">` mounts the Atlas sign-up panel. */
|
|
108
|
+
export declare class AtlasSignUp extends AtlasWidgetElement {
|
|
109
|
+
protected readonly mode: "sign-up";
|
|
110
|
+
}
|
|
111
|
+
/** Register every element (idempotent). Importing the package already does this. */
|
|
112
|
+
export declare function defineAtlasElements(): void;
|
|
113
|
+
export {};
|
package/dist/elements.js
ADDED
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import { ContextConsumer, ContextProvider } from '@lit/context';
|
|
2
|
+
import { LitElement, html, nothing } from 'lit';
|
|
3
|
+
import { resolveFrontendApi } from '@atlasauth/js';
|
|
4
|
+
import { createAtlasClient } from './client';
|
|
5
|
+
import { atlasContext, loadingSnapshot } from './context';
|
|
6
|
+
import { mountAtlasWidget } from './widget';
|
|
7
|
+
/**
|
|
8
|
+
* `<atlas-provider publishable-key="pk_…" frontend-api="https://auth.example.com">`
|
|
9
|
+
*
|
|
10
|
+
* Creates the Atlas client in the browser, boots the session (completing an OAuth redirect if the
|
|
11
|
+
* page is one), refreshes the token before it expires, and shares the state with every Atlas
|
|
12
|
+
* element below it. Put it once near the top of the page. `frontend-api` is required; a missing
|
|
13
|
+
* or malformed value throws an `AtlasConfigError` when the element connects.
|
|
14
|
+
*/
|
|
15
|
+
export class AtlasProvider extends LitElement {
|
|
16
|
+
static { this.properties = {
|
|
17
|
+
publishableKey: { type: String, attribute: 'publishable-key' },
|
|
18
|
+
frontendApi: { type: String, attribute: 'frontend-api' },
|
|
19
|
+
}; }
|
|
20
|
+
constructor() {
|
|
21
|
+
super();
|
|
22
|
+
this.client = null;
|
|
23
|
+
this.unsubscribe = null;
|
|
24
|
+
this.provider = new ContextProvider(this, {
|
|
25
|
+
context: atlasContext,
|
|
26
|
+
initialValue: { client: null, snapshot: loadingSnapshot, publishableKey: '', frontendApi: '' },
|
|
27
|
+
});
|
|
28
|
+
this.publishableKey = '';
|
|
29
|
+
this.frontendApi = '';
|
|
30
|
+
}
|
|
31
|
+
connectedCallback() {
|
|
32
|
+
super.connectedCallback();
|
|
33
|
+
this.start();
|
|
34
|
+
}
|
|
35
|
+
disconnectedCallback() {
|
|
36
|
+
this.stop();
|
|
37
|
+
super.disconnectedCallback();
|
|
38
|
+
}
|
|
39
|
+
willUpdate(changed) {
|
|
40
|
+
// A changed key or API origin means a different instance: rebuild the client.
|
|
41
|
+
if (this.isConnected && this.client && (changed.has('publishableKey') || changed.has('frontendApi'))) {
|
|
42
|
+
this.stop();
|
|
43
|
+
this.start();
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
start() {
|
|
47
|
+
if (this.client || !this.publishableKey)
|
|
48
|
+
return;
|
|
49
|
+
const frontendApi = resolveFrontendApi(this.frontendApi, { component: '<atlas-provider>' });
|
|
50
|
+
const client = createAtlasClient({
|
|
51
|
+
publishableKey: this.publishableKey,
|
|
52
|
+
frontendApi: this.frontendApi,
|
|
53
|
+
...(this.fetchImpl ? { fetchImpl: this.fetchImpl } : {}),
|
|
54
|
+
});
|
|
55
|
+
this.client = client;
|
|
56
|
+
const publish = () => this.provider.setValue({ client, snapshot: client.snapshot(), publishableKey: this.publishableKey, frontendApi });
|
|
57
|
+
this.unsubscribe = client.subscribe(publish);
|
|
58
|
+
publish();
|
|
59
|
+
void client.boot();
|
|
60
|
+
}
|
|
61
|
+
stop() {
|
|
62
|
+
this.unsubscribe?.();
|
|
63
|
+
this.unsubscribe = null;
|
|
64
|
+
this.client?.destroy();
|
|
65
|
+
this.client = null;
|
|
66
|
+
this.provider.setValue({ client: null, snapshot: loadingSnapshot, publishableKey: '', frontendApi: '' });
|
|
67
|
+
}
|
|
68
|
+
render() {
|
|
69
|
+
return html `<slot></slot>`;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
/** Base class for elements that read the Atlas state: re-renders on every change. */
|
|
73
|
+
export class AtlasElement extends LitElement {
|
|
74
|
+
constructor() {
|
|
75
|
+
super(...arguments);
|
|
76
|
+
this.consumer = new ContextConsumer(this, { context: atlasContext, subscribe: true });
|
|
77
|
+
}
|
|
78
|
+
get atlas() {
|
|
79
|
+
return this.consumer.value ?? { client: null, snapshot: loadingSnapshot, publishableKey: '', frontendApi: '' };
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
/** `<atlas-signed-in>…</atlas-signed-in>` renders its children only for a signed-in user. */
|
|
83
|
+
export class AtlasSignedIn extends AtlasElement {
|
|
84
|
+
render() {
|
|
85
|
+
return this.atlas.snapshot.status === 'signed_in' ? html `<slot></slot>` : nothing;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
/** `<atlas-signed-out>…</atlas-signed-out>` renders its children only once the session is known to be signed out. */
|
|
89
|
+
export class AtlasSignedOut extends AtlasElement {
|
|
90
|
+
render() {
|
|
91
|
+
return this.atlas.snapshot.status === 'signed_out' ? html `<slot></slot>` : nothing;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
/** `<atlas-loading>…</atlas-loading>` renders its children until the first boot settles. */
|
|
95
|
+
export class AtlasLoading extends AtlasElement {
|
|
96
|
+
render() {
|
|
97
|
+
return this.atlas.snapshot.status === 'loading' ? html `<slot></slot>` : nothing;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* `<atlas-protect permission="org:billing:read">…</atlas-protect>` renders its children when the
|
|
102
|
+
* signed-in session satisfies the condition, else the `fallback` slot. Conditions: `permission`,
|
|
103
|
+
* `require-role` (the `role` attribute is ARIA's). A signed-out visitor, or an unknown state, never passes. This hides UI only; your API
|
|
104
|
+
* is what enforces access.
|
|
105
|
+
*/
|
|
106
|
+
export class AtlasProtect extends AtlasElement {
|
|
107
|
+
static { this.properties = {
|
|
108
|
+
permission: { type: String },
|
|
109
|
+
requireRole: { type: String, attribute: 'require-role' },
|
|
110
|
+
}; }
|
|
111
|
+
render() {
|
|
112
|
+
const { client, snapshot } = this.atlas;
|
|
113
|
+
const allowed = snapshot.status === 'signed_in' &&
|
|
114
|
+
!!client &&
|
|
115
|
+
client.has({
|
|
116
|
+
...(this.permission ? { permission: this.permission } : {}),
|
|
117
|
+
...(this.requireRole ? { role: this.requireRole } : {}),
|
|
118
|
+
});
|
|
119
|
+
return allowed ? html `<slot></slot>` : html `<slot name="fallback"></slot>`;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
/** `<atlas-sign-out-button>Sign out</atlas-sign-out-button>` signs out and fires `atlas-signed-out`. */
|
|
123
|
+
export class AtlasSignOutButton extends AtlasElement {
|
|
124
|
+
constructor() {
|
|
125
|
+
super(...arguments);
|
|
126
|
+
this.onClick = async () => {
|
|
127
|
+
await this.atlas.client?.signOut();
|
|
128
|
+
this.dispatchEvent(new CustomEvent('atlas-signed-out', { bubbles: true, composed: true }));
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
render() {
|
|
132
|
+
if (this.atlas.snapshot.status !== 'signed_in')
|
|
133
|
+
return nothing;
|
|
134
|
+
return html `<button type="button" @click=${this.onClick}><slot>Sign out</slot></button>`;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
/** Shared by the two widget elements: mounts the Atlas panel into this element's light DOM. */
|
|
138
|
+
class AtlasWidgetElement extends AtlasElement {
|
|
139
|
+
constructor() {
|
|
140
|
+
super(...arguments);
|
|
141
|
+
this.cleanup = null;
|
|
142
|
+
this.mountedFor = '';
|
|
143
|
+
this.slotEl = document.createElement('div');
|
|
144
|
+
}
|
|
145
|
+
static { this.properties = {
|
|
146
|
+
redirect: { type: String },
|
|
147
|
+
locale: { type: String },
|
|
148
|
+
}; }
|
|
149
|
+
// The widget draws its own panel, so render into this element, not a shadow root.
|
|
150
|
+
createRenderRoot() {
|
|
151
|
+
return this;
|
|
152
|
+
}
|
|
153
|
+
updated() {
|
|
154
|
+
const { publishableKey, frontendApi } = this.atlas;
|
|
155
|
+
const key = `${publishableKey}|${frontendApi}|${this.redirect ?? ''}|${this.locale ?? ''}`;
|
|
156
|
+
if (!publishableKey || !frontendApi || key === this.mountedFor)
|
|
157
|
+
return;
|
|
158
|
+
this.cleanup?.();
|
|
159
|
+
this.mountedFor = key;
|
|
160
|
+
// Mount into a child Lit does not manage: writing into `this` would wipe Lit's own render markers.
|
|
161
|
+
if (!this.slotEl.isConnected)
|
|
162
|
+
this.append(this.slotEl);
|
|
163
|
+
this.cleanup = mountAtlasWidget(this.slotEl, this.mode, {
|
|
164
|
+
publishableKey,
|
|
165
|
+
frontendApi,
|
|
166
|
+
...(this.redirect ? { redirect: this.redirect } : {}),
|
|
167
|
+
...(this.locale ? { locale: this.locale } : {}),
|
|
168
|
+
...(this.mounter ? { mounter: this.mounter } : {}),
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
disconnectedCallback() {
|
|
172
|
+
this.cleanup?.();
|
|
173
|
+
this.cleanup = null;
|
|
174
|
+
this.mountedFor = '';
|
|
175
|
+
super.disconnectedCallback();
|
|
176
|
+
}
|
|
177
|
+
render() {
|
|
178
|
+
return nothing;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
/** `<atlas-sign-in redirect="/app">` mounts the Atlas sign-in panel. */
|
|
182
|
+
export class AtlasSignIn extends AtlasWidgetElement {
|
|
183
|
+
constructor() {
|
|
184
|
+
super(...arguments);
|
|
185
|
+
this.mode = 'sign-in';
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
/** `<atlas-sign-up redirect="/app">` mounts the Atlas sign-up panel. */
|
|
189
|
+
export class AtlasSignUp extends AtlasWidgetElement {
|
|
190
|
+
constructor() {
|
|
191
|
+
super(...arguments);
|
|
192
|
+
this.mode = 'sign-up';
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
const TAGS = [
|
|
196
|
+
['atlas-provider', AtlasProvider],
|
|
197
|
+
['atlas-signed-in', AtlasSignedIn],
|
|
198
|
+
['atlas-signed-out', AtlasSignedOut],
|
|
199
|
+
['atlas-loading', AtlasLoading],
|
|
200
|
+
['atlas-protect', AtlasProtect],
|
|
201
|
+
['atlas-sign-out-button', AtlasSignOutButton],
|
|
202
|
+
['atlas-sign-in', AtlasSignIn],
|
|
203
|
+
['atlas-sign-up', AtlasSignUp],
|
|
204
|
+
];
|
|
205
|
+
/** Register every element (idempotent). Importing the package already does this. */
|
|
206
|
+
export function defineAtlasElements() {
|
|
207
|
+
for (const [tag, ctor] of TAGS)
|
|
208
|
+
if (!customElements.get(tag))
|
|
209
|
+
customElements.define(tag, ctor);
|
|
210
|
+
}
|
|
211
|
+
//# sourceMappingURL=elements.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"elements.js","sourceRoot":"","sources":["../src/elements.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export * from './types';
|
|
2
|
+
export * from './client';
|
|
3
|
+
export * from './context';
|
|
4
|
+
export * from './widget';
|
|
5
|
+
export { AtlasProvider, AtlasElement, AtlasSignedIn, AtlasSignedOut, AtlasLoading, AtlasProtect, AtlasSignOutButton, AtlasSignIn, AtlasSignUp, defineAtlasElements, } from './elements';
|
|
6
|
+
export { SignOutError } from '@atlasauth/js';
|
|
7
|
+
export type { SignOutOptions, SignOutResult } from '@atlasauth/js';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export * from './types';
|
|
2
|
+
export * from './client';
|
|
3
|
+
export * from './context';
|
|
4
|
+
export * from './widget';
|
|
5
|
+
export { AtlasProvider, AtlasElement, AtlasSignedIn, AtlasSignedOut, AtlasLoading, AtlasProtect, AtlasSignOutButton, AtlasSignIn, AtlasSignUp, defineAtlasElements, } from './elements';
|
|
6
|
+
export { SignOutError } from '@atlasauth/js';
|
|
7
|
+
import { defineAtlasElements } from './elements';
|
|
8
|
+
// Registering on import is what makes `<atlas-provider>` work from a plain <script type="module">.
|
|
9
|
+
if (typeof customElements !== 'undefined')
|
|
10
|
+
defineAtlasElements();
|
|
11
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,cAAc,UAAU,CAAC;AACzB,cAAc,WAAW,CAAC;AAC1B,cAAc,UAAU,CAAC;AACzB,OAAO,EACL,aAAa,EACb,YAAY,EACZ,aAAa,EACb,cAAc,EACd,YAAY,EACZ,YAAY,EACZ,kBAAkB,EAClB,WAAW,EACX,WAAW,EACX,mBAAmB,GACpB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAG7C,OAAO,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAEjD,mGAAmG;AACnG,IAAI,OAAO,cAAc,KAAK,WAAW;IAAE,mBAAmB,EAAE,CAAC"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The public auth shapes, identical to the React and Vue SDKs so a team moving
|
|
3
|
+
* between frameworks reads the same `user` / `session` / `claims` everywhere.
|
|
4
|
+
*/
|
|
5
|
+
export interface SessionClaims {
|
|
6
|
+
sub: string;
|
|
7
|
+
sid: string;
|
|
8
|
+
exp: number;
|
|
9
|
+
org_id?: string;
|
|
10
|
+
org_slug?: string;
|
|
11
|
+
org_role?: string;
|
|
12
|
+
org_permissions?: string[];
|
|
13
|
+
mfa?: boolean;
|
|
14
|
+
[claim: string]: unknown;
|
|
15
|
+
}
|
|
16
|
+
export interface AtlasUser {
|
|
17
|
+
id: string;
|
|
18
|
+
first_name: string | null;
|
|
19
|
+
last_name: string | null;
|
|
20
|
+
username: string | null;
|
|
21
|
+
image_url: string | null;
|
|
22
|
+
public_metadata: Record<string, unknown>;
|
|
23
|
+
unsafe_metadata: Record<string, unknown>;
|
|
24
|
+
mfa_enabled: boolean;
|
|
25
|
+
has_password: boolean;
|
|
26
|
+
email_addresses?: Array<{
|
|
27
|
+
id: string;
|
|
28
|
+
email_address: string;
|
|
29
|
+
verified: boolean;
|
|
30
|
+
primary: boolean;
|
|
31
|
+
}>;
|
|
32
|
+
}
|
|
33
|
+
export interface AtlasOrganizationMembership {
|
|
34
|
+
role: string;
|
|
35
|
+
organization: {
|
|
36
|
+
id: string;
|
|
37
|
+
name: string;
|
|
38
|
+
slug: string;
|
|
39
|
+
image_url: string | null;
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
export interface AtlasSession {
|
|
43
|
+
id: string;
|
|
44
|
+
status: string;
|
|
45
|
+
last_active_organization_id: string | null;
|
|
46
|
+
}
|
|
47
|
+
/** `loading` until the first boot settles, then `signed_in` / `signed_out`. */
|
|
48
|
+
export type AuthStatus = 'loading' | 'signed_in' | 'signed_out';
|
|
49
|
+
/** The plain snapshot of auth state: values only, never functions or timers. */
|
|
50
|
+
export interface AtlasSnapshot {
|
|
51
|
+
status: AuthStatus;
|
|
52
|
+
user: AtlasUser | null;
|
|
53
|
+
session: AtlasSession | null;
|
|
54
|
+
claims: SessionClaims | null;
|
|
55
|
+
memberships: AtlasOrganizationMembership[];
|
|
56
|
+
}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
|
package/dist/widget.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type WidgetOptions } from '@atlasauth/embed';
|
|
2
|
+
export type WidgetMode = 'sign-in' | 'sign-up';
|
|
3
|
+
/** A mount function with the shape of `@atlasauth/embed`'s `mountSignIn`. */
|
|
4
|
+
export type WidgetMounter = (host: HTMLElement, overrides: Partial<WidgetOptions>) => unknown;
|
|
5
|
+
export interface MountWidgetOptions {
|
|
6
|
+
publishableKey: string;
|
|
7
|
+
frontendApi: string;
|
|
8
|
+
/** Where to go on success. Validated same-origin / absolute-https by the widget. */
|
|
9
|
+
redirect?: string;
|
|
10
|
+
/** The UI language as a BCP-47 tag (`"es"`). */
|
|
11
|
+
locale?: string;
|
|
12
|
+
localization?: WidgetOptions['localization'];
|
|
13
|
+
/** Replace the mount function (tests). */
|
|
14
|
+
mounter?: WidgetMounter;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Mount the Atlas DOM widget into `host` and return a cleanup function. The widget renders into
|
|
18
|
+
* the host's light DOM and has no `unmount()`, so cleanup clears the host's children, which lets
|
|
19
|
+
* the widget (and its background passkey AbortController) be garbage collected.
|
|
20
|
+
*/
|
|
21
|
+
export declare function mountAtlasWidget(host: HTMLElement, mode: WidgetMode, options: MountWidgetOptions): () => void;
|
package/dist/widget.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { mountSignIn, mountSignUp } from '@atlasauth/embed';
|
|
2
|
+
const DEFAULT_MOUNTERS = {
|
|
3
|
+
'sign-in': (host, overrides) => mountSignIn(host, overrides),
|
|
4
|
+
'sign-up': (host, overrides) => mountSignUp(host, overrides),
|
|
5
|
+
};
|
|
6
|
+
/**
|
|
7
|
+
* Mount the Atlas DOM widget into `host` and return a cleanup function. The widget renders into
|
|
8
|
+
* the host's light DOM and has no `unmount()`, so cleanup clears the host's children, which lets
|
|
9
|
+
* the widget (and its background passkey AbortController) be garbage collected.
|
|
10
|
+
*/
|
|
11
|
+
export function mountAtlasWidget(host, mode, options) {
|
|
12
|
+
const mounter = options.mounter ?? DEFAULT_MOUNTERS[mode];
|
|
13
|
+
const overrides = {
|
|
14
|
+
publishableKey: options.publishableKey,
|
|
15
|
+
frontendApi: options.frontendApi,
|
|
16
|
+
};
|
|
17
|
+
if (options.redirect)
|
|
18
|
+
overrides.redirect = options.redirect;
|
|
19
|
+
if (options.locale)
|
|
20
|
+
overrides.locale = options.locale;
|
|
21
|
+
if (options.localization)
|
|
22
|
+
overrides.localization = options.localization;
|
|
23
|
+
mounter(host, overrides);
|
|
24
|
+
return () => {
|
|
25
|
+
try {
|
|
26
|
+
host.replaceChildren();
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
// The host may already be gone (navigation); nothing to clean.
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=widget.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"widget.js","sourceRoot":"","sources":["../src/widget.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,WAAW,EAAsB,MAAM,kBAAkB,CAAC;AAOhF,MAAM,gBAAgB,GAAsC;IAC1D,SAAS,EAAE,CAAC,IAAI,EAAE,SAAS,EAAE,EAAE,CAAC,WAAW,CAAC,IAAI,EAAE,SAAS,CAAC;IAC5D,SAAS,EAAE,CAAC,IAAI,EAAE,SAAS,EAAE,EAAE,CAAC,WAAW,CAAC,IAAI,EAAE,SAAS,CAAC;CAC7D,CAAC;AAcF;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAiB,EAAE,IAAgB,EAAE,OAA2B;IAC/F,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,gBAAgB,CAAC,IAAI,CAAC,CAAC;IAC1D,MAAM,SAAS,GAA2B;QACxC,cAAc,EAAE,OAAO,CAAC,cAAc;QACtC,WAAW,EAAE,OAAO,CAAC,WAAW;KACjC,CAAC;IACF,IAAI,OAAO,CAAC,QAAQ;QAAE,SAAS,CAAC,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;IAC5D,IAAI,OAAO,CAAC,MAAM;QAAE,SAAS,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IACtD,IAAI,OAAO,CAAC,YAAY;QAAE,SAAS,CAAC,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC;IACxE,OAAO,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;IACzB,OAAO,GAAG,EAAE;QACV,IAAI,CAAC;YACH,IAAI,CAAC,eAAe,EAAE,CAAC;QACzB,CAAC;QAAC,MAAM,CAAC;YACP,+DAA+D;QACjE,CAAC;IACH,CAAC,CAAC;AACJ,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,47 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlasauth/lit",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Atlas for web components: Lit elements (provider, signed-in/out gates, permission gate, sign-in and sign-up widgets) over @atlasauth/js. Works in any framework or none.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"default": "./dist/index.js"
|
|
13
|
+
},
|
|
14
|
+
"./package.json": "./package.json"
|
|
15
|
+
},
|
|
16
|
+
"sideEffects": [
|
|
17
|
+
"./dist/index.js"
|
|
18
|
+
],
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"@lit/context": "^1.1.3",
|
|
21
|
+
"@atlasauth/js": "0.26.1",
|
|
22
|
+
"@atlasauth/embed": "^0.14.0"
|
|
23
|
+
},
|
|
24
|
+
"peerDependencies": {
|
|
25
|
+
"lit": ">=3"
|
|
26
|
+
},
|
|
27
|
+
"devDependencies": {
|
|
28
|
+
"happy-dom": "^15.11.0",
|
|
29
|
+
"lit": "^3.2.1",
|
|
30
|
+
"typescript": "^5.6.3",
|
|
31
|
+
"vitest": "^2.1.4"
|
|
32
|
+
},
|
|
33
|
+
"publishConfig": {
|
|
34
|
+
"access": "public"
|
|
35
|
+
},
|
|
36
|
+
"files": [
|
|
37
|
+
"dist",
|
|
38
|
+
"!dist/*.tsbuildinfo",
|
|
39
|
+
"README.md",
|
|
40
|
+
"CHANGELOG.md"
|
|
41
|
+
],
|
|
42
|
+
"scripts": {
|
|
43
|
+
"build": "tsc -p tsconfig.build.json",
|
|
44
|
+
"typecheck": "tsgo -p tsconfig.json --noEmit --module preserve --moduleResolution bundler --incremental --tsBuildInfoFile node_modules/.cache/typecheck.tsbuildinfo",
|
|
45
|
+
"test": "vitest run"
|
|
46
|
+
}
|
|
6
47
|
}
|