@atlasauth/svelte 0.4.0 → 0.5.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 +12 -0
- package/dist/accessors.js +1 -0
- package/dist/components/AttemptFlow.svelte +4 -2
- package/dist/components/SignUpForm.svelte +11 -7
- package/dist/components/SignUpForm.svelte.d.ts +1 -1
- package/dist/context.d.ts +8 -0
- package/dist/context.js +6 -2
- package/dist/i18n.js +40 -0
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# @atlasauth/svelte changelog
|
|
2
2
|
|
|
3
|
+
## 0.5.0
|
|
4
|
+
Requires `@atlasauth/js` 0.9.0.
|
|
5
|
+
- **Server errors render in the app's language.** `<SignIn>` / `<SignUp>` show the catalog string
|
|
6
|
+
`error.<reason>` for an error's `reason` (placeholders filled from its `meta`), falling back to the server's
|
|
7
|
+
message, then `error.generic`. With `localization: esES` a refused password reads
|
|
8
|
+
"Esas credenciales son incorrectas." instead of the server's English sentence.
|
|
9
|
+
- **`Accept-Language`.** The client's and the flows' Frontend API requests carry the `locale` tag of the
|
|
10
|
+
`localization` bundle, so the server localises `message` too.
|
|
11
|
+
- **Added 38 `error.<reason>` keys** to the built-in `EN_US` catalog (see `@atlasauth/localizations` 0.4.0).
|
|
12
|
+
- `AtlasClient` gains `errorCatalog?: Catalog` and `locale?: string`.
|
|
13
|
+
|
|
14
|
+
|
|
3
15
|
## 0.4.0
|
|
4
16
|
- **Safer sign-out.** `signOut(options?)` (on the client, `getAuth()` and the `signOut()` helper) now
|
|
5
17
|
resolves `SignOutResult` — `{ revoked: boolean; activeSessionId?: string }` — instead of `void`
|
package/dist/accessors.js
CHANGED
|
@@ -67,6 +67,7 @@ function createFlow() {
|
|
|
67
67
|
const client = new FapiClient({
|
|
68
68
|
publishableKey: atlas.publishableKey,
|
|
69
69
|
baseUrl: atlas.frontendApi,
|
|
70
|
+
locale: atlas.locale,
|
|
70
71
|
});
|
|
71
72
|
// Seeded from a redirect that came back mid-flow (e.g. OAuth needing a second
|
|
72
73
|
// factor), so the user resumes at the demanded step instead of starting over.
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
<script>import {
|
|
2
|
+
localizedErrorMessage,
|
|
2
3
|
nextStep,
|
|
3
4
|
offeredFirstFactors
|
|
4
5
|
} from "@atlasauth/js";
|
|
@@ -17,6 +18,7 @@ export let onPrepare = null;
|
|
|
17
18
|
const atlas = useAtlas();
|
|
18
19
|
const cls = (key, base) => classFor(key, atlas.appearance, base);
|
|
19
20
|
const t = (key, vars) => translate(atlas.catalog, key, vars);
|
|
21
|
+
const errorText = (error) => localizedErrorMessage(error, atlas.errorCatalog ?? atlas.catalog, atlas.catalog);
|
|
20
22
|
let values = {};
|
|
21
23
|
$: step = attempt ? nextStep(attempt) : { kind: "collect_identifier" };
|
|
22
24
|
const strategyName = (s) => typeof s === "string" ? s : String(s?.strategy ?? "");
|
|
@@ -89,7 +91,7 @@ function handleSubmit(event) {
|
|
|
89
91
|
<h1 class={cls('headerTitle', 'atlas-title')}>{t(titleKey)}</h1>
|
|
90
92
|
|
|
91
93
|
{#each errors.filter((e) => !e.param) as error (error.code)}
|
|
92
|
-
<p class={cls('formFieldError', 'atlas-error')} role="alert">{error
|
|
94
|
+
<p class={cls('formFieldError', 'atlas-error')} role="alert">{errorText(error)}</p>
|
|
93
95
|
{/each}
|
|
94
96
|
|
|
95
97
|
<form on:submit={handleSubmit}>
|
|
@@ -112,7 +114,7 @@ function handleSubmit(event) {
|
|
|
112
114
|
on:input={(e) => (values[f.name] = e.currentTarget.value)}
|
|
113
115
|
/>
|
|
114
116
|
{#each errors.filter((e) => e.param === f.name) as error (error.code)}
|
|
115
|
-
<span class={cls('formFieldError', 'atlas-error')}>{error
|
|
117
|
+
<span class={cls('formFieldError', 'atlas-error')}>{errorText(error)}</span>
|
|
116
118
|
{/each}
|
|
117
119
|
</label>
|
|
118
120
|
{/each}
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
<script>import {
|
|
1
|
+
<script>import {
|
|
2
|
+
localizedErrorMessage
|
|
3
|
+
} from "@atlasauth/js";
|
|
4
|
+
import { useAtlas } from "../context";
|
|
2
5
|
import { classFor } from "../appearance";
|
|
3
6
|
import { translate } from "../i18n";
|
|
4
7
|
import CaptchaSlot from "./CaptchaSlot.svelte";
|
|
@@ -10,6 +13,7 @@ export let onSubmit;
|
|
|
10
13
|
const atlas = useAtlas();
|
|
11
14
|
const cls = (key, base) => classFor(key, atlas.appearance, base);
|
|
12
15
|
const t = (key, vars) => translate(atlas.catalog, key, vars);
|
|
16
|
+
const errorText = (error) => localizedErrorMessage(error, atlas.errorCatalog ?? atlas.catalog, atlas.catalog);
|
|
13
17
|
let values = {};
|
|
14
18
|
let agreed = false;
|
|
15
19
|
$: legal = settings?.legal;
|
|
@@ -38,7 +42,7 @@ function handleSubmit(event) {
|
|
|
38
42
|
<h1 class={cls('headerTitle', 'atlas-title')}>{t('signUp.title')}</h1>
|
|
39
43
|
|
|
40
44
|
{#each errors.filter((e) => !e.param) as error (error.code)}
|
|
41
|
-
<p class={cls('formFieldError', 'atlas-error')} role="alert">{error
|
|
45
|
+
<p class={cls('formFieldError', 'atlas-error')} role="alert">{errorText(error)}</p>
|
|
42
46
|
{/each}
|
|
43
47
|
|
|
44
48
|
{#if emailUnavailable}
|
|
@@ -65,7 +69,7 @@ function handleSubmit(event) {
|
|
|
65
69
|
{/each}
|
|
66
70
|
</span>
|
|
67
71
|
{#each errors.filter((e) => e.param === f.key) as error (error.code)}
|
|
68
|
-
<span class={cls('formFieldError', 'atlas-error')}>{error
|
|
72
|
+
<span class={cls('formFieldError', 'atlas-error')}>{errorText(error)}</span>
|
|
69
73
|
{/each}
|
|
70
74
|
</div>
|
|
71
75
|
{:else}
|
|
@@ -113,7 +117,7 @@ function handleSubmit(event) {
|
|
|
113
117
|
/>
|
|
114
118
|
{/if}
|
|
115
119
|
{#each errors.filter((e) => e.param === f.key) as error (error.code)}
|
|
116
|
-
<span class={cls('formFieldError', 'atlas-error')}>{error
|
|
120
|
+
<span class={cls('formFieldError', 'atlas-error')}>{errorText(error)}</span>
|
|
117
121
|
{/each}
|
|
118
122
|
</label>
|
|
119
123
|
{/if}
|
|
@@ -131,7 +135,7 @@ function handleSubmit(event) {
|
|
|
131
135
|
on:input={(e) => (values.email = e.currentTarget.value)}
|
|
132
136
|
/>
|
|
133
137
|
{#each errors.filter((e) => e.param === 'email') as error (error.code)}
|
|
134
|
-
<span class={cls('formFieldError', 'atlas-error')}>{error
|
|
138
|
+
<span class={cls('formFieldError', 'atlas-error')}>{errorText(error)}</span>
|
|
135
139
|
{/each}
|
|
136
140
|
</label>
|
|
137
141
|
|
|
@@ -147,7 +151,7 @@ function handleSubmit(event) {
|
|
|
147
151
|
on:input={(e) => (values.password = e.currentTarget.value)}
|
|
148
152
|
/>
|
|
149
153
|
{#each errors.filter((e) => e.param === 'password') as error (error.code)}
|
|
150
|
-
<span class={cls('formFieldError', 'atlas-error')}>{error
|
|
154
|
+
<span class={cls('formFieldError', 'atlas-error')}>{errorText(error)}</span>
|
|
151
155
|
{/each}
|
|
152
156
|
</label>
|
|
153
157
|
|
|
@@ -167,7 +171,7 @@ function handleSubmit(event) {
|
|
|
167
171
|
>{/if}.
|
|
168
172
|
</span>
|
|
169
173
|
{#each errors.filter((e) => e.param === 'consent') as error (error.code)}
|
|
170
|
-
<span class={cls('formFieldError', 'atlas-error')}>{error
|
|
174
|
+
<span class={cls('formFieldError', 'atlas-error')}>{errorText(error)}</span>
|
|
171
175
|
{/each}
|
|
172
176
|
</label>
|
|
173
177
|
{/if}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { SvelteComponent } from "svelte";
|
|
2
|
-
import type
|
|
2
|
+
import { type CaptchaController, type FieldError, type InstanceSettings } from '@atlasauth/js';
|
|
3
3
|
declare const __propDef: {
|
|
4
4
|
props: {
|
|
5
5
|
/**
|
package/dist/context.d.ts
CHANGED
|
@@ -62,6 +62,14 @@ export interface AtlasClient extends AtlasStores {
|
|
|
62
62
|
frontendApi: string;
|
|
63
63
|
appearance?: Appearance;
|
|
64
64
|
catalog: Catalog;
|
|
65
|
+
/**
|
|
66
|
+
* The language layer of `catalog` (the `localization` bundle, without the
|
|
67
|
+
* English defaults underneath; `EN_US` when none is set). Server errors are
|
|
68
|
+
* looked up here as `error.<reason>`, falling back to the server's message.
|
|
69
|
+
*/
|
|
70
|
+
errorCatalog?: Catalog;
|
|
71
|
+
/** Sent to the Frontend API as `Accept-Language`: the `locale` tag of the `localization` bundle. */
|
|
72
|
+
locale?: string;
|
|
65
73
|
/**
|
|
66
74
|
* §5.3: a sign-in attempt handed back by an OAuth redirect that still needs a
|
|
67
75
|
* second factor (no session was issued). Null in the ordinary case. `<SignIn>`
|
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, } from '@atlasauth/js';
|
|
3
|
+
import { FapiClient, SignOutGuard, TokenCache, closeOAuthPopupAfterSignIn, completeOAuthPopupLanding, getProviderToken as fetchProviderToken, mapOAuthPopupPayload, msUntilRefresh, readExpiry, readRedirectResult, resolveFrontendApi, stripRedirectParams, catalogLocale, } from '@atlasauth/js';
|
|
4
4
|
import { EN_US, withFallback } from './i18n';
|
|
5
5
|
import { instanceDesignFrom } from './appearance';
|
|
6
6
|
/** The context key. A `Symbol` so it cannot collide with an app's own context. */
|
|
@@ -29,6 +29,8 @@ export function createAtlasClient(options) {
|
|
|
29
29
|
});
|
|
30
30
|
const doFetch = options.fetchImpl ?? (typeof fetch !== 'undefined' ? fetch : undefined);
|
|
31
31
|
const catalog = options.localization ? withFallback(options.localization) : EN_US;
|
|
32
|
+
const errorCatalog = options.localization ?? EN_US;
|
|
33
|
+
const locale = catalogLocale(options.localization);
|
|
32
34
|
const status = writable('loading');
|
|
33
35
|
const user = writable(null);
|
|
34
36
|
const session = writable(null);
|
|
@@ -168,7 +170,7 @@ export function createAtlasClient(options) {
|
|
|
168
170
|
await refresh();
|
|
169
171
|
return cache.get(5_000)?.jwt ?? null;
|
|
170
172
|
}
|
|
171
|
-
const fapiClient = new FapiClient({ publishableKey, baseUrl, fetchImpl: doFetch });
|
|
173
|
+
const fapiClient = new FapiClient({ publishableKey, baseUrl, fetchImpl: doFetch, locale });
|
|
172
174
|
function getProviderToken(provider) {
|
|
173
175
|
return fetchProviderToken(fapiClient, provider);
|
|
174
176
|
}
|
|
@@ -277,6 +279,8 @@ export function createAtlasClient(options) {
|
|
|
277
279
|
frontendApi: baseUrl,
|
|
278
280
|
appearance: options.appearance,
|
|
279
281
|
catalog,
|
|
282
|
+
errorCatalog,
|
|
283
|
+
locale,
|
|
280
284
|
pendingAttempt,
|
|
281
285
|
status: { subscribe: status.subscribe },
|
|
282
286
|
user: { subscribe: user.subscribe },
|
package/dist/i18n.js
CHANGED
|
@@ -76,6 +76,46 @@ export const EN_US = {
|
|
|
76
76
|
'organization.roleLabel': 'Role',
|
|
77
77
|
'error.generic': 'Something went wrong. Please try again.',
|
|
78
78
|
'error.network': 'We could not reach the server. Check your connection.',
|
|
79
|
+
// Server errors, by the stable `reason` the Frontend API sends. Shown instead
|
|
80
|
+
// of the server's `message` (see `localizedErrorMessage` in @atlasauth/js).
|
|
81
|
+
'error.form_password_incorrect': 'Those credentials are incorrect.',
|
|
82
|
+
'error.form_code_incorrect': 'That code is incorrect.',
|
|
83
|
+
'error.form_code_already_used': 'That code has already been used. Wait for a new one.',
|
|
84
|
+
'error.form_code_expired': 'That code has expired. Request a new one.',
|
|
85
|
+
'error.form_code_max_attempts': 'Too many incorrect codes. Request a new code.',
|
|
86
|
+
'error.form_link_invalid': 'That sign-in link is invalid or has already been used.',
|
|
87
|
+
'error.form_identifier_not_found': "We couldn't find an account with those details.",
|
|
88
|
+
'error.form_identifier_exists': "There's already an account for this email. Sign in with {methods}.",
|
|
89
|
+
'error.form_password_pwned': 'This password has appeared in a known data breach. Please choose a different one.',
|
|
90
|
+
'error.form_password_too_short': 'Password must be at least {min_length} characters.',
|
|
91
|
+
'error.form_password_too_long': 'Password must be at most {max_length} characters.',
|
|
92
|
+
'error.form_password_requires_uppercase': 'Password must contain an uppercase letter.',
|
|
93
|
+
'error.form_password_requires_lowercase': 'Password must contain a lowercase letter.',
|
|
94
|
+
'error.form_password_requires_number': 'Password must contain a number.',
|
|
95
|
+
'error.form_password_requires_symbol': 'Password must contain a symbol.',
|
|
96
|
+
'error.form_password_not_allowed': 'That password is not allowed. Choose a different one.',
|
|
97
|
+
'error.form_password_contains_identifier': 'Password must not contain your email or username.',
|
|
98
|
+
'error.form_password_same_as_current': 'Your new password must be different from your current one.',
|
|
99
|
+
'error.form_password_reused': 'Your new password must not match any of your last {history_count} passwords.',
|
|
100
|
+
'error.password_expired': 'Your password has expired. Reset it to continue.',
|
|
101
|
+
'error.email_not_verified': 'Your email address is not verified yet. Verify it before signing in with your password.',
|
|
102
|
+
'error.sign_in_token_invalid': 'That sign-in token is invalid or has expired.',
|
|
103
|
+
'error.too_many_attempts': 'Too many failed attempts. Try again later.',
|
|
104
|
+
'error.too_many_requests': 'Too many requests. Please try again later.',
|
|
105
|
+
'error.captcha_required': 'Please complete the security check, then try again.',
|
|
106
|
+
'error.captcha_failed': "The security check didn't pass. Please try again.",
|
|
107
|
+
'error.captcha_unavailable': 'The security check is unavailable right now. Please try again later.',
|
|
108
|
+
'error.email_delivery_unavailable': "This app can't send email right now. Try another sign-in method or contact the app owner.",
|
|
109
|
+
'error.strategy_disabled': 'This sign-in method is not available for this app.',
|
|
110
|
+
'error.sign_up_restricted': 'Sign-up on this app is by invitation only.',
|
|
111
|
+
'error.waitlisted': "You're on the waitlist. We'll email you when a place opens up.",
|
|
112
|
+
'error.identifier_not_allowed': 'This email or phone number is not allowed on this app.',
|
|
113
|
+
'error.disposable_email_blocked': 'Sign-up with a disposable or temporary email address is not allowed.',
|
|
114
|
+
'error.sso_required': 'This organization requires signing in through single sign-on.',
|
|
115
|
+
'error.sign_ins_disabled': 'Sign-ins are temporarily disabled.',
|
|
116
|
+
'error.sign_ups_disabled': 'Sign-ups are temporarily disabled.',
|
|
117
|
+
'error.high_risk_blocked': 'This sign-in was blocked because it looked unusual.',
|
|
118
|
+
'error.sms_region_blocked': 'Text messages are not available for this phone number.',
|
|
79
119
|
};
|
|
80
120
|
/**
|
|
81
121
|
* Look up a key and interpolate `{placeholders}`.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlasauth/svelte",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"svelte": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -23,8 +23,8 @@
|
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
25
|
"@atlasauth/design": "0.2.0",
|
|
26
|
+
"@atlasauth/js": "0.9.0",
|
|
26
27
|
"@atlasauth/authz": "0.1.1",
|
|
27
|
-
"@atlasauth/js": "0.8.0",
|
|
28
28
|
"@atlasauth/backend": "0.7.2"
|
|
29
29
|
},
|
|
30
30
|
"peerDependencies": {
|