@atlasauth/svelte 0.7.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.
@@ -1,22 +1,69 @@
1
1
  <script>import { onDestroy } from "svelte";
2
+ import { lastUsedMethodLabel, pendingRecoveryCodes, signUp as hostedSignUp } from "@atlasauth/js";
2
3
  import { signIn } from "../accessors";
4
+ import { useAtlas } from "../context";
5
+ import { classFor } from "../appearance";
6
+ import { translate } from "../i18n";
3
7
  import AttemptFlow from "./AttemptFlow.svelte";
8
+ import RecoveryCodes from "./RecoveryCodes.svelte";
4
9
  export let afterUrl = void 0;
10
+ export let signUpUrl = void 0;
11
+ const atlas = useAtlas();
12
+ const t = (key) => translate(atlas.catalog, key);
13
+ function signUpHref(url, after) {
14
+ if (url === null) return null;
15
+ if (url) return url;
16
+ try {
17
+ return hostedSignUp({
18
+ frontendApi: atlas.frontendApi,
19
+ redirectUrl: after ?? (typeof window !== "undefined" ? window.location.href : void 0),
20
+ navigate: false
21
+ });
22
+ } catch {
23
+ return null;
24
+ }
25
+ }
26
+ $: promptHref = $flowState.attempt?.status !== "complete" ? signUpHref(signUpUrl, afterUrl) : null;
5
27
  const flow = signIn();
6
28
  const flowState = flow.state;
7
29
  const settings = flow.settings;
30
+ const lastMethod = flow.lastMethod;
31
+ const enrollmentState = flow.enrollmentState;
8
32
  onDestroy(() => flow.destroy());
33
+ $: recoveryCodes = pendingRecoveryCodes($flowState);
34
+ $: lastLabel = !$flowState.attempt ? lastUsedMethodLabel($lastMethod, t) : null;
9
35
  const drawn = (..._deps) => flow.captcha.needed ? flow.captcha : null;
10
36
  $: captcha = drawn($settings, $flowState);
11
37
  </script>
12
38
 
39
+ {#if lastLabel}
40
+ <p class={classFor('badge', atlas.appearance, 'atlas-text atlas-last-used-hint')} data-atlas="last-used" data-atlas-method={$lastMethod}>
41
+ {t('signIn.lastUsed')}: {lastLabel}
42
+ </p>
43
+ {/if}
44
+
45
+ {#if recoveryCodes}
46
+ <RecoveryCodes codes={recoveryCodes} busy={$flowState.busy} onSaved={flow.saveRecoveryCodes} />
47
+ {:else}
13
48
  <AttemptFlow
14
49
  attempt={$flowState.attempt}
15
50
  busy={$flowState.busy}
16
51
  errors={$flowState.errors}
52
+ sessionKept={$flowState.sessionKept}
17
53
  titleKey="signIn.title"
18
54
  onSubmit={flow.submit}
19
55
  onPrepare={flow.prepare}
56
+ onEmailSecondFactor={$settings?.account.emailSecondFactor ? flow.sendEmailSecondFactor : null}
57
+ onSmsSecondFactor={$settings && flow.mfaChoices().sms ? flow.sendSmsSecondFactor : null}
58
+ enrollment={flow.enrollment}
59
+ enrollmentState={$enrollmentState}
20
60
  emailDelivery={$settings?.emailDelivery ?? null}
21
61
  {captcha}
22
62
  />
63
+ {/if}
64
+
65
+ {#if promptHref}
66
+ <p class={classFor('footerAction', atlas.appearance, 'atlas-footer')} data-atlas-sign-up-prompt="">
67
+ {t('signIn.noAccount')} <a class="atlas-link" href={promptHref}>{t('signIn.signUpLink')}</a>
68
+ </p>
69
+ {/if}
@@ -9,6 +9,11 @@ declare const __propDef: {
9
9
  * Offers emailed first factors (code / link) only while the app can deliver
10
10
  * email (`settings.emailDelivery`).
11
11
  */ afterUrl?: string | undefined;
12
+ /**
13
+ * Where "No account? Sign up" goes. Default: the instance's hosted sign-up
14
+ * page (carrying the visitor's referral). `null` hides it. Always shown, never
15
+ * only after a failed sign-in, so it says nothing about whether an email has an account.
16
+ */ signUpUrl?: string | null | undefined;
12
17
  };
13
18
  events: {
14
19
  [evt: string]: CustomEvent<any>;
@@ -1,6 +1,8 @@
1
1
  <script>import { onDestroy } from "svelte";
2
+ import { awaitingPasskey, passkeysSupported } from "@atlasauth/js";
2
3
  import { signUp } from "../accessors";
3
4
  import AttemptFlow from "./AttemptFlow.svelte";
5
+ import PasskeySignUpStep from "./PasskeySignUpStep.svelte";
4
6
  import SignUpForm from "./SignUpForm.svelte";
5
7
  export let afterUrl = void 0;
6
8
  const flow = signUp();
@@ -9,15 +11,27 @@ const settings = flow.settings;
9
11
  onDestroy(() => flow.destroy());
10
12
  const drawn = (..._deps) => flow.signUpCaptcha.needed ? flow.signUpCaptcha : null;
11
13
  $: captcha = drawn($settings, $flowState);
14
+ let mode = "password";
15
+ $: offer = $settings?.account.passkeySignUp ?? null;
16
+ $: canPasskey = !!offer && passkeysSupported();
17
+ $: usingPasskey = mode === "passkey" && canPasskey;
18
+ function switchMode() {
19
+ mode = usingPasskey ? "password" : "passkey";
20
+ }
12
21
  </script>
13
22
 
14
- {#if $flowState.attempt}
23
+ {#if $flowState.attempt && awaitingPasskey($flowState.attempt)}
24
+ <PasskeySignUpStep busy={$flowState.busy} errors={$flowState.errors} onCreate={flow.createPasskey} />
25
+ {:else if $flowState.attempt}
15
26
  <AttemptFlow
16
27
  attempt={$flowState.attempt}
17
28
  busy={$flowState.busy}
18
29
  errors={$flowState.errors}
30
+ sessionKept={$flowState.sessionKept}
19
31
  titleKey="signUp.title"
20
32
  onSubmit={flow.submit}
33
+ emailVerification={$settings?.account.emailVerification ?? 'code'}
34
+ onResend={flow.resendSignUp}
21
35
  />
22
36
  {:else}
23
37
  <SignUpForm
@@ -25,6 +39,8 @@ $: captcha = drawn($settings, $flowState);
25
39
  busy={$flowState.busy}
26
40
  errors={$flowState.errors}
27
41
  {captcha}
28
- onSubmit={flow.create}
42
+ onSubmit={usingPasskey ? flow.createWithPasskey : flow.create}
43
+ passkey={usingPasskey && offer ? { email: offer.email } : null}
44
+ onSwitchMode={canPasskey ? switchMode : undefined}
29
45
  />
30
46
  {/if}
@@ -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
- <label class={cls('formField', 'atlas-field')}>
127
- <span class={cls('formFieldLabel', 'atlas-field-label')}>{t('signUp.emailLabel')}</span>
128
- <input
129
- class={cls('formFieldInput', 'atlas-input')}
130
- type="email"
131
- name="email"
132
- autocomplete="email"
133
- required
134
- value={values.email ?? ''}
135
- on:input={(e) => (values.email = e.currentTarget.value)}
136
- />
137
- {#each errors.filter((e) => e.param === 'email') as error (error.code)}
138
- <span class={cls('formFieldError', 'atlas-error')}>{errorText(error)}</span>
139
- {/each}
140
- </label>
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,7 +126,15 @@ export interface AtlasClient extends AtlasStores {
126
126
  */
127
127
  signOut(options?: SignOutOptions): Promise<SignOutResult>;
128
128
  setActiveOrganization(organizationId: string | null): Promise<void>;
129
- reload(): 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>;
136
+ /** Re-boot from the Frontend API. Resolves true when a session now exists in this browser. */
137
+ reload(): Promise<boolean>;
130
138
  /**
131
139
  * Redirect handling + the first `/v1/client` load. Runs once, in the browser
132
140
  * only. {@link initAtlas} calls it automatically unless `manualBoot` is set;
package/dist/context.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { getContext, setContext } from 'svelte';
2
2
  import { derived, get, writable } from 'svelte/store';
3
- import { FapiClient, SignOutGuard, TokenCache, closeOAuthPopupAfterSignIn, completeOAuthPopupLanding, getProviderToken as fetchProviderToken, mapOAuthPopupPayload, msUntilRefresh, readExpiry, readRedirectResult, resolveFrontendApi, stripRedirectParams, catalogLocale, SDK_HEADER, SignOutNotifier, getTemplateToken, reportSdkAdvisory, sdkHeaderValue, signOutReasonFromClient, configureReferralCapture, } from '@atlasauth/js';
3
+ import { FapiClient, SignOutGuard, TokenCache, closeOAuthPopupAfterSignIn, completeOAuthPopupLanding, getProviderToken as fetchProviderToken, mapOAuthPopupPayload, msUntilRefresh, readExpiry, readRedirectResult, resolveFrontendApi, stripRedirectParams, catalogLocale, SDK_HEADER, SignOutNotifier, getTemplateToken, reportSdkAdvisory, sdkHeaderValue, signOutReasonFromClient, configureReferralCapture, withDevBrowser, } from '@atlasauth/js';
4
4
  import { ATLAS_SVELTE_SDK } from './version';
5
5
  import { EN_US, withFallback } from './i18n';
6
6
  import { instanceDesignFrom } from './appearance';
@@ -28,7 +28,9 @@ export function createAtlasClient(options) {
28
28
  const baseUrl = resolveFrontendApi(options.frontendApi, {
29
29
  component: '<AtlasProvider> / initAtlas()',
30
30
  });
31
- const doFetch = options.fetchImpl ?? (typeof fetch !== 'undefined' ? fetch : undefined);
31
+ const rawFetch = options.fetchImpl ?? (typeof fetch !== 'undefined' ? fetch : undefined);
32
+ // Development instances keep the session in a header where the browser blocks the cookie.
33
+ const doFetch = rawFetch ? withDevBrowser(options.publishableKey, rawFetch) : undefined;
32
34
  const catalog = options.localization ? withFallback(options.localization) : EN_US;
33
35
  const errorCatalog = options.localization ?? EN_US;
34
36
  const locale = catalogLocale(options.localization);
@@ -139,7 +141,7 @@ export function createAtlasClient(options) {
139
141
  // refused: stay signed out; the guard re-tries the revoke in the background.
140
142
  if (!body.session || !body.user || guard.refuse(body.session.id)) {
141
143
  clearSession(body.session ? 'other_tab' : signOutReasonFromClient(body));
142
- return;
144
+ return false;
143
145
  }
144
146
  notifier.clear();
145
147
  user.set(body.user);
@@ -149,6 +151,7 @@ export function createAtlasClient(options) {
149
151
  applyToken(body.jwt, body.session.id);
150
152
  status.set('signed_in');
151
153
  scheduleRefresh();
154
+ return true;
152
155
  }
153
156
  catch {
154
157
  /**
@@ -157,6 +160,7 @@ export function createAtlasClient(options) {
157
160
  * re-authenticate for no reason.
158
161
  */
159
162
  status.update((current) => (current === 'loading' ? 'signed_out' : current));
163
+ return false;
160
164
  }
161
165
  }
162
166
  async function refresh() {
@@ -231,6 +235,22 @@ export function createAtlasClient(options) {
231
235
  applyToken(body.jwt, current.sessionId);
232
236
  await reload();
233
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
+ }
234
254
  async function boot() {
235
255
  if (booted)
236
256
  return;
@@ -318,6 +338,7 @@ export function createAtlasClient(options) {
318
338
  getProviderToken,
319
339
  signOut,
320
340
  setActiveOrganization,
341
+ endImpersonation,
321
342
  reload,
322
343
  boot,
323
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}',
@@ -31,6 +32,8 @@ export const EN_US = {
31
32
  'signIn.resendCode': 'Resend code',
32
33
  'signIn.resendLink': 'Resend link',
33
34
  'signIn.passwordOption': 'Use your password instead',
35
+ 'signIn.signedIn': 'You\'re signed in.',
36
+ 'signIn.sessionNotKept': 'You signed in, but this browser didn\'t keep the session. If it blocks third-party cookies, allow cookies for this site and try again.',
34
37
  'signIn.checkOtherTab': 'You can close this tab — you are signed in where you started.',
35
38
  'signUp.title': 'Create your account',
36
39
  'signUp.submit': 'Continue',
@@ -47,6 +50,13 @@ export const EN_US = {
47
50
  'signUp.and': 'and',
48
51
  // Shown instead of the email + password form when the app cannot send email.
49
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.',
50
60
  'captcha.prompt': 'Complete the security check to continue.',
51
61
  'captcha.required': 'Please complete the security check, then try again.',
52
62
  'captcha.failed': "The security check didn't pass. Please try again.",
@@ -64,6 +74,24 @@ export const EN_US = {
64
74
  'mfa.usePasskey': 'Use a passkey instead',
65
75
  'mfa.useBackupCode': 'Use a recovery code',
66
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",
67
95
  'reset.title': 'Reset your password',
68
96
  'reset.submit': 'Send reset code',
69
97
  'reset.newPasswordLabel': 'New password',
@@ -91,6 +119,35 @@ export const EN_US = {
91
119
  'organization.members': 'Members',
92
120
  'organization.invite': 'Invite member',
93
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',
94
151
  'error.generic': 'Something went wrong. Please try again.',
95
152
  'error.network': 'We could not reach the server. Check your connection.',
96
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.7.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.7.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.7.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/backend": "0.10.0",
27
- "@atlasauth/authz": "0.1.1",
28
- "@atlasauth/js": "0.13.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",