@atlasauth/svelte 0.8.0 → 0.9.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 +16 -0
- package/dist/accessors.d.ts +57 -1
- package/dist/accessors.js +99 -2
- package/dist/appearance.d.ts +1 -1
- package/dist/components/AttemptFlow.svelte +181 -4
- package/dist/components/AttemptFlow.svelte.d.ts +27 -1
- package/dist/components/ImpersonationBanner.svelte +38 -0
- package/dist/components/ImpersonationBanner.svelte.d.ts +19 -0
- package/dist/components/OrganizationAuditLog.svelte +45 -0
- package/dist/components/OrganizationAuditLog.svelte.d.ts +31 -0
- package/dist/components/OrganizationProfile.svelte +308 -12
- package/dist/components/OrganizationProfile.svelte.d.ts +2 -0
- package/dist/components/PasskeySignUpStep.svelte +23 -0
- package/dist/components/PasskeySignUpStep.svelte.d.ts +24 -0
- package/dist/components/RecoveryCodes.svelte +55 -0
- package/dist/components/RecoveryCodes.svelte.d.ts +25 -0
- package/dist/components/SignIn.svelte +20 -1
- package/dist/components/SignUp.svelte +17 -2
- package/dist/components/SignUpForm.svelte +41 -16
- package/dist/components/SignUpForm.svelte.d.ts +4 -0
- package/dist/context.d.ts +8 -1
- package/dist/context.js +17 -0
- package/dist/i18n.js +55 -0
- package/dist/index.d.ts +4 -1
- package/dist/index.js +3 -1
- package/dist/types.d.ts +6 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +4 -4
|
@@ -10,6 +10,8 @@ export let busy = false;
|
|
|
10
10
|
export let errors = [];
|
|
11
11
|
export let captcha = null;
|
|
12
12
|
export let onSubmit;
|
|
13
|
+
export let passkey = null;
|
|
14
|
+
export let onSwitchMode = void 0;
|
|
13
15
|
const atlas = useAtlas();
|
|
14
16
|
const cls = (key, base) => classFor(key, atlas.appearance, base);
|
|
15
17
|
const t = (key, vars) => translate(atlas.catalog, key, vars);
|
|
@@ -20,7 +22,9 @@ $: legal = settings?.legal;
|
|
|
20
22
|
$: showLegal = !!legal && (!!legal.termsUrl || !!legal.privacyUrl);
|
|
21
23
|
$: consentOk = !legal?.required || agreed;
|
|
22
24
|
$: fields = settings?.signUpFields ?? [];
|
|
23
|
-
$: emailUnavailable = settings?.emailDelivery?.passwordSignUp === false;
|
|
25
|
+
$: emailUnavailable = settings?.emailDelivery?.passwordSignUp === false && !(passkey && passkey.email !== "required");
|
|
26
|
+
$: showEmail = !passkey || passkey.email !== "off";
|
|
27
|
+
$: emailRequired = !passkey || passkey.email === "required";
|
|
24
28
|
const label = (f) => f.required ? f.label : t("signUp.optionalField", { label: f.label });
|
|
25
29
|
const inputType = (f) => ["email", "tel", "url", "number", "date"].includes(f.type) ? f.type : "text";
|
|
26
30
|
const picked = (key) => values[key] ? values[key].split(", ") : [];
|
|
@@ -123,22 +127,29 @@ function handleSubmit(event) {
|
|
|
123
127
|
{/if}
|
|
124
128
|
{/each}
|
|
125
129
|
|
|
126
|
-
|
|
127
|
-
<
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
130
|
+
{#if showEmail}
|
|
131
|
+
<label class={cls('formField', 'atlas-field')}>
|
|
132
|
+
<span class={cls('formFieldLabel', 'atlas-field-label')}
|
|
133
|
+
>{emailRequired ? t('signUp.emailLabel') : t('signUp.optionalField', { label: t('signUp.emailLabel') })}</span
|
|
134
|
+
>
|
|
135
|
+
<input
|
|
136
|
+
class={cls('formFieldInput', 'atlas-input')}
|
|
137
|
+
type="email"
|
|
138
|
+
name="email"
|
|
139
|
+
autocomplete="email"
|
|
140
|
+
required={emailRequired}
|
|
141
|
+
value={values.email ?? ''}
|
|
142
|
+
on:input={(e) => (values.email = e.currentTarget.value)}
|
|
143
|
+
/>
|
|
144
|
+
{#each errors.filter((e) => e.param === 'email') as error (error.code)}
|
|
145
|
+
<span class={cls('formFieldError', 'atlas-error')}>{errorText(error)}</span>
|
|
146
|
+
{/each}
|
|
147
|
+
</label>
|
|
148
|
+
{/if}
|
|
141
149
|
|
|
150
|
+
{#if passkey}
|
|
151
|
+
<p class="atlas-text">{t('signUp.passkeyIntro')}</p>
|
|
152
|
+
{:else}
|
|
142
153
|
<label class={cls('formField', 'atlas-field')}>
|
|
143
154
|
<span class={cls('formFieldLabel', 'atlas-field-label')}>{t('signUp.passwordLabel')}</span>
|
|
144
155
|
<input
|
|
@@ -154,6 +165,7 @@ function handleSubmit(event) {
|
|
|
154
165
|
<span class={cls('formFieldError', 'atlas-error')}>{errorText(error)}</span>
|
|
155
166
|
{/each}
|
|
156
167
|
</label>
|
|
168
|
+
{/if}
|
|
157
169
|
|
|
158
170
|
{#if showLegal && legal}
|
|
159
171
|
<label class={cls('formField', 'atlas-consent')}>
|
|
@@ -187,6 +199,19 @@ function handleSubmit(event) {
|
|
|
187
199
|
>
|
|
188
200
|
{t('signUp.submit')}
|
|
189
201
|
</button>
|
|
202
|
+
{#if onSwitchMode}
|
|
203
|
+
<div class="atlas-alternatives">
|
|
204
|
+
<button
|
|
205
|
+
type="button"
|
|
206
|
+
class={cls('formButtonSecondary', 'atlas-button-secondary')}
|
|
207
|
+
data-atlas-sign-up-mode={passkey ? 'password' : 'passkey'}
|
|
208
|
+
disabled={busy}
|
|
209
|
+
on:click={() => onSwitchMode?.()}
|
|
210
|
+
>
|
|
211
|
+
{t(passkey ? 'signUp.passwordOption' : 'signUp.passkeyOption')}
|
|
212
|
+
</button>
|
|
213
|
+
</div>
|
|
214
|
+
{/if}
|
|
190
215
|
</form>
|
|
191
216
|
{/if}
|
|
192
217
|
</div>
|
|
@@ -16,6 +16,10 @@ declare const __propDef: {
|
|
|
16
16
|
errors?: FieldError[];
|
|
17
17
|
captcha?: CaptchaController | null;
|
|
18
18
|
onSubmit: (values: Record<string, string>, consent: boolean) => void;
|
|
19
|
+
/** Passkey-only sign-up: no password field; the email per the instance's mode. */ passkey?: {
|
|
20
|
+
email: "off" | "optional" | "required";
|
|
21
|
+
} | null;
|
|
22
|
+
/** Toggle between the password and passkey forms (only when both are offered). */ onSwitchMode?: (() => void) | undefined;
|
|
19
23
|
};
|
|
20
24
|
events: {
|
|
21
25
|
[evt: string]: CustomEvent<any>;
|
package/dist/context.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type Readable } from 'svelte/store';
|
|
2
|
-
import { type ProviderToken, type SignOutOptions, type SignOutResult, type SignOutEvent, type SignOutListener, type ReferralConsent } from '@atlasauth/js';
|
|
2
|
+
import { type ProviderToken, type SignOutOptions, type SignOutResult, type EndImpersonationResult, type SignOutEvent, type SignOutListener, type ReferralConsent } from '@atlasauth/js';
|
|
3
3
|
import { type Catalog } from './i18n';
|
|
4
4
|
import { type Appearance, type InstanceDesign } from './appearance';
|
|
5
5
|
import type { AtlasOrganizationMembership, AtlasSession, AtlasUser, SessionClaims } from './types';
|
|
@@ -126,6 +126,13 @@ export interface AtlasClient extends AtlasStores {
|
|
|
126
126
|
*/
|
|
127
127
|
signOut(options?: SignOutOptions): Promise<SignOutResult>;
|
|
128
128
|
setActiveOrganization(organizationId: string | null): Promise<void>;
|
|
129
|
+
/**
|
|
130
|
+
* End the active impersonation ("return to admin"): the impersonator's own
|
|
131
|
+
* session on this browser becomes active again with no sign-in
|
|
132
|
+
* (`resumed: true`); with none, another account signed in here is adopted,
|
|
133
|
+
* or this browser is signed out.
|
|
134
|
+
*/
|
|
135
|
+
endImpersonation(): Promise<EndImpersonationResult>;
|
|
129
136
|
/** Re-boot from the Frontend API. Resolves true when a session now exists in this browser. */
|
|
130
137
|
reload(): Promise<boolean>;
|
|
131
138
|
/**
|
package/dist/context.js
CHANGED
|
@@ -235,6 +235,22 @@ export function createAtlasClient(options) {
|
|
|
235
235
|
applyToken(body.jwt, current.sessionId);
|
|
236
236
|
await reload();
|
|
237
237
|
}
|
|
238
|
+
async function endImpersonation() {
|
|
239
|
+
const outcome = await guard.endImpersonation(cache.peek()?.sessionId ?? get(session)?.id ?? null);
|
|
240
|
+
if (!outcome.ended)
|
|
241
|
+
return outcome;
|
|
242
|
+
if (!outcome.activeSessionId) {
|
|
243
|
+
if (timer)
|
|
244
|
+
clearTimeout(timer);
|
|
245
|
+
timer = null;
|
|
246
|
+
clearSession('user');
|
|
247
|
+
return outcome;
|
|
248
|
+
}
|
|
249
|
+
if (outcome.jwt)
|
|
250
|
+
applyToken(outcome.jwt, outcome.activeSessionId);
|
|
251
|
+
await reload();
|
|
252
|
+
return outcome;
|
|
253
|
+
}
|
|
238
254
|
async function boot() {
|
|
239
255
|
if (booted)
|
|
240
256
|
return;
|
|
@@ -322,6 +338,7 @@ export function createAtlasClient(options) {
|
|
|
322
338
|
getProviderToken,
|
|
323
339
|
signOut,
|
|
324
340
|
setActiveOrganization,
|
|
341
|
+
endImpersonation,
|
|
325
342
|
reload,
|
|
326
343
|
boot,
|
|
327
344
|
loadInstanceDesign,
|
package/dist/i18n.js
CHANGED
|
@@ -18,6 +18,7 @@ export const EN_US = {
|
|
|
18
18
|
'signIn.submit': 'Continue',
|
|
19
19
|
'signIn.forgotPassword': 'Forgot password?',
|
|
20
20
|
'signIn.noAccount': 'No account?',
|
|
21
|
+
'signIn.lastUsed': 'Last used',
|
|
21
22
|
'signIn.signUpLink': 'Sign up',
|
|
22
23
|
'signIn.orDivider': 'or',
|
|
23
24
|
'signIn.socialButton': 'Continue with {provider}',
|
|
@@ -49,6 +50,13 @@ export const EN_US = {
|
|
|
49
50
|
'signUp.and': 'and',
|
|
50
51
|
// Shown instead of the email + password form when the app cannot send email.
|
|
51
52
|
'signUp.emailUnavailable': EMAIL_UNAVAILABLE_MESSAGE,
|
|
53
|
+
'signUp.passkeyOption': 'Sign up with a passkey instead',
|
|
54
|
+
'signUp.passwordOption': 'Sign up with a password instead',
|
|
55
|
+
'signUp.passkeyIntro': "No password needed: you'll sign in with a passkey saved on this device or in your password manager.",
|
|
56
|
+
'signUp.passkeyPrompt': 'Create a passkey to finish setting up your account.',
|
|
57
|
+
'signUp.passkeyCreate': 'Create passkey',
|
|
58
|
+
'signUp.passkeyCancelled': "The passkey wasn't created. Try again when you're ready.",
|
|
59
|
+
'signUp.linkSentTo': 'We sent a confirmation link to {email}. Open it on any device; this page continues on its own.',
|
|
52
60
|
'captcha.prompt': 'Complete the security check to continue.',
|
|
53
61
|
'captcha.required': 'Please complete the security check, then try again.',
|
|
54
62
|
'captcha.failed': "The security check didn't pass. Please try again.",
|
|
@@ -66,6 +74,24 @@ export const EN_US = {
|
|
|
66
74
|
'mfa.usePasskey': 'Use a passkey instead',
|
|
67
75
|
'mfa.useBackupCode': 'Use a recovery code',
|
|
68
76
|
'mfa.submit': 'Verify',
|
|
77
|
+
'mfa.enrollChoose': 'Set up a second step for signing in.',
|
|
78
|
+
'mfa.enrollTotpOption': 'Use an authenticator app',
|
|
79
|
+
'mfa.enrollSmsOption': 'Use text messages',
|
|
80
|
+
'mfa.enrollScan': 'Scan this QR code with your authenticator app, or enter the setup key.',
|
|
81
|
+
'mfa.enrollQrAlt': 'QR code for your authenticator app',
|
|
82
|
+
'mfa.enrollSetupKey': 'Setup key',
|
|
83
|
+
'mfa.enrollPreparing': 'Setting up…',
|
|
84
|
+
'mfa.phoneLabel': 'Mobile number',
|
|
85
|
+
'mfa.phoneHint': 'Include the country code, for example +14155550101.',
|
|
86
|
+
'mfa.sendCode': 'Text me a code',
|
|
87
|
+
'mfa.codeTextedTo': 'Enter the code we texted to {phone}.',
|
|
88
|
+
'mfa.smsCodeOption': 'Text me a code instead',
|
|
89
|
+
'mfa.recoveryCodesTitle': 'Save your recovery codes',
|
|
90
|
+
'mfa.recoveryCodesHelp': "Each code works once. If you can't use your second step, sign in with one of these. Keep them somewhere safe: they won't be shown again.",
|
|
91
|
+
'mfa.recoveryCodesCopy': 'Copy codes',
|
|
92
|
+
'mfa.recoveryCodesCopied': 'Copied.',
|
|
93
|
+
'mfa.recoveryCodesDownload': 'Download as .txt',
|
|
94
|
+
'mfa.recoveryCodesSaved': "I've saved my codes",
|
|
69
95
|
'reset.title': 'Reset your password',
|
|
70
96
|
'reset.submit': 'Send reset code',
|
|
71
97
|
'reset.newPasswordLabel': 'New password',
|
|
@@ -93,6 +119,35 @@ export const EN_US = {
|
|
|
93
119
|
'organization.members': 'Members',
|
|
94
120
|
'organization.invite': 'Invite member',
|
|
95
121
|
'organization.roleLabel': 'Role',
|
|
122
|
+
'organization.invitations': 'Invitations',
|
|
123
|
+
'organization.settings': 'Settings',
|
|
124
|
+
'organization.emailLabel': 'Email address',
|
|
125
|
+
'organization.sendInvite': 'Send invitation',
|
|
126
|
+
'organization.noInvitations': 'No pending invitations.',
|
|
127
|
+
'organization.remove': 'Remove',
|
|
128
|
+
'organization.revoke': 'Revoke',
|
|
129
|
+
'organization.resend': 'Resend',
|
|
130
|
+
'organization.you': '(you)',
|
|
131
|
+
'organization.leave': 'Leave organization',
|
|
132
|
+
'organization.leaveConfirm': 'Leave {name}? You will lose access until you are invited again.',
|
|
133
|
+
'organization.delete': 'Delete organization',
|
|
134
|
+
'organization.deleteConfirm': 'Delete {name} for every member? This cannot be undone.',
|
|
135
|
+
'organization.confirm': 'Confirm',
|
|
136
|
+
'organization.cancel': 'Cancel',
|
|
137
|
+
'organization.unnamedMember': 'Unnamed member',
|
|
138
|
+
'organization.passwordPrompt': 'Enter your password to confirm.',
|
|
139
|
+
'organization.roles': 'Roles',
|
|
140
|
+
'organization.roleName': 'Role name',
|
|
141
|
+
'organization.roleKey': 'Role key (for example org:auditor)',
|
|
142
|
+
'organization.rolePermissions': 'Permissions',
|
|
143
|
+
'organization.createRole': 'Create role',
|
|
144
|
+
'organization.saveRole': 'Save role',
|
|
145
|
+
'organization.editRole': 'Edit',
|
|
146
|
+
'organization.deleteRole': 'Delete',
|
|
147
|
+
'organization.noCustomRoles': 'This organization has no roles of its own yet.',
|
|
148
|
+
'impersonation.banner': 'You are signed in as {name} on someone else\'s behalf.',
|
|
149
|
+
'impersonation.returnToAdmin': 'Return to admin',
|
|
150
|
+
'impersonation.end': 'End impersonation',
|
|
96
151
|
'error.generic': 'Something went wrong. Please try again.',
|
|
97
152
|
'error.network': 'We could not reach the server. Check your connection.',
|
|
98
153
|
// Server errors, by the stable `reason` the Frontend API sends. Shown instead
|
package/dist/index.d.ts
CHANGED
|
@@ -16,7 +16,7 @@ export * from './i18n';
|
|
|
16
16
|
export * from './types';
|
|
17
17
|
export * from './fapi';
|
|
18
18
|
export { ATLAS_KEY, initAtlas, createAtlasClient, useAtlas, type AuthStatus, type AtlasInitOptions, type AtlasStores, type AtlasClient, } from './context';
|
|
19
|
-
export { getUser, getSession, getAuth, getOrganization, getToken, signIn, signUp, signOut, type UseUser, type UseSession, type UseAuth, type UseOrganization, type FlowController, } from './accessors';
|
|
19
|
+
export { getUser, getSession, getAuth, getOrganization, getOrganizationAuditLog, getToken, signIn, signUp, signOut, type UseUser, type UseSession, type UseAuth, type UseOrganization, type OrganizationAuditLogStore, type FlowController, } from './accessors';
|
|
20
20
|
export { default as AtlasProvider } from './components/AtlasProvider.svelte';
|
|
21
21
|
export { default as SignedIn } from './components/SignedIn.svelte';
|
|
22
22
|
export { default as SignedOut } from './components/SignedOut.svelte';
|
|
@@ -29,6 +29,9 @@ export { default as UserButton } from './components/UserButton.svelte';
|
|
|
29
29
|
export { default as UserProfile } from './components/UserProfile.svelte';
|
|
30
30
|
export { default as OrganizationSwitcher } from './components/OrganizationSwitcher.svelte';
|
|
31
31
|
export { default as OrganizationProfile } from './components/OrganizationProfile.svelte';
|
|
32
|
+
export { default as OrganizationAuditLog } from './components/OrganizationAuditLog.svelte';
|
|
33
|
+
export type { OrganizationAuditLogEntry, OrganizationAuditLogState } from '@atlasauth/js';
|
|
34
|
+
export { default as ImpersonationBanner } from './components/ImpersonationBanner.svelte';
|
|
32
35
|
export type { InstanceSettings, EmailDelivery, PublicSignUpField, CaptchaController, CaptchaFlowKey, CaptchaWidgetMode, FlowCaptcha, } from '@atlasauth/js';
|
|
33
36
|
export { SignOutError } from '@atlasauth/js';
|
|
34
37
|
export type { SignOutOptions, SignOutResult } from '@atlasauth/js';
|
package/dist/index.js
CHANGED
|
@@ -19,7 +19,7 @@ export * from './fapi';
|
|
|
19
19
|
// The client, context install, and the base accessor.
|
|
20
20
|
export { ATLAS_KEY, initAtlas, createAtlasClient, useAtlas, } from './context';
|
|
21
21
|
// Store accessors (peers of the React hooks) and action helpers.
|
|
22
|
-
export { getUser, getSession, getAuth, getOrganization, getToken, signIn, signUp, signOut, } from './accessors';
|
|
22
|
+
export { getUser, getSession, getAuth, getOrganization, getOrganizationAuditLog, getToken, signIn, signUp, signOut, } from './accessors';
|
|
23
23
|
// Components.
|
|
24
24
|
export { default as AtlasProvider } from './components/AtlasProvider.svelte';
|
|
25
25
|
export { default as SignedIn } from './components/SignedIn.svelte';
|
|
@@ -33,6 +33,8 @@ export { default as UserButton } from './components/UserButton.svelte';
|
|
|
33
33
|
export { default as UserProfile } from './components/UserProfile.svelte';
|
|
34
34
|
export { default as OrganizationSwitcher } from './components/OrganizationSwitcher.svelte';
|
|
35
35
|
export { default as OrganizationProfile } from './components/OrganizationProfile.svelte';
|
|
36
|
+
export { default as OrganizationAuditLog } from './components/OrganizationAuditLog.svelte';
|
|
37
|
+
export { default as ImpersonationBanner } from './components/ImpersonationBanner.svelte';
|
|
36
38
|
// What `signOut()` resolves with, and what it rejects with under `{ strict: true }`.
|
|
37
39
|
export { SignOutError } from '@atlasauth/js';
|
|
38
40
|
// `onSignOut({ reason })` event types + the `atlas:signout` window event; this SDK's version.
|
package/dist/types.d.ts
CHANGED
|
@@ -39,4 +39,10 @@ export interface AtlasSession {
|
|
|
39
39
|
id: string;
|
|
40
40
|
status: string;
|
|
41
41
|
last_active_organization_id: string | null;
|
|
42
|
+
/** On an impersonation session: who is acting (the token's `act` claim). */
|
|
43
|
+
actor?: {
|
|
44
|
+
sub: string;
|
|
45
|
+
} | null;
|
|
46
|
+
/** On an impersonation session: the impersonator's own session that "return to admin" resumes, or null. */
|
|
47
|
+
actor_session_id?: string | null;
|
|
42
48
|
}
|
package/dist/version.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import type { AtlasSdkInfo } from '@atlasauth/js';
|
|
2
2
|
/** This package's version, sent as `X-Atlas-SDK` (kept in step with package.json by a test). */
|
|
3
|
-
export declare const ATLAS_SVELTE_VERSION = "0.
|
|
3
|
+
export declare const ATLAS_SVELTE_VERSION = "0.9.0";
|
|
4
4
|
export declare const ATLAS_SVELTE_SDK: AtlasSdkInfo;
|
package/dist/version.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
/** This package's version, sent as `X-Atlas-SDK` (kept in step with package.json by a test). */
|
|
2
|
-
export const ATLAS_SVELTE_VERSION = '0.
|
|
2
|
+
export const ATLAS_SVELTE_VERSION = '0.9.0';
|
|
3
3
|
export const ATLAS_SVELTE_SDK = { name: '@atlasauth/svelte', version: ATLAS_SVELTE_VERSION };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlasauth/svelte",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"svelte": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -23,9 +23,9 @@
|
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
25
|
"@atlasauth/design": "0.2.0",
|
|
26
|
-
"@atlasauth/
|
|
27
|
-
"@atlasauth/
|
|
28
|
-
"@atlasauth/js": "0.
|
|
26
|
+
"@atlasauth/authz": "0.2.0",
|
|
27
|
+
"@atlasauth/backend": "0.15.0",
|
|
28
|
+
"@atlasauth/js": "0.16.0"
|
|
29
29
|
},
|
|
30
30
|
"peerDependencies": {
|
|
31
31
|
"svelte": ">=4",
|