@atlasauth/capacitor 0.1.1 → 0.3.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 +32 -0
- package/README.md +17 -0
- package/dist/index.d.ts +35 -4
- package/dist/index.js +100 -9
- package/dist/index.js.map +1 -1
- package/dist/native-session.d.ts +9 -1
- package/dist/native-session.js +11 -1
- package/dist/native-session.js.map +1 -1
- package/dist/policies.d.ts +83 -0
- package/dist/policies.js +159 -0
- package/dist/policies.js.map +1 -0
- package/dist/token-store.d.ts +14 -0
- package/dist/token-store.js +25 -0
- package/dist/token-store.js.map +1 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,37 @@
|
|
|
1
1
|
# @atlasauth/capacitor changelog
|
|
2
2
|
|
|
3
|
+
## 0.3.0 — 2026-10-24
|
|
4
|
+
Requires `@atlasauth/js` with policy acceptance.
|
|
5
|
+
- **Policy acceptance** (terms of service, privacy, any policy the app defines). The system-browser sign-in runs on Atlas's
|
|
6
|
+
hosted pages, which collect and hold for the policies themselves. For the app's own WebView screens, the handle gains
|
|
7
|
+
`policies()` (a `PolicyAcceptanceController` for a sign-up form), `pendingPolicies(attempt)`, `policyGate()` (in-app
|
|
8
|
+
re-acceptance with the session's bearer token) and `fapi`; new `locale` option. `mountPolicyGate(host, gate)` draws the
|
|
9
|
+
signed-in banner, and the DOM pieces (`mountPolicyConsent`, `mountPolicyClickwrap`, `mountPolicyAcceptStep`) are re-exported.
|
|
10
|
+
|
|
11
|
+
## 0.2.0
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
- **`signOut(options?: SignOutOptions)` now resolves `Promise<SignOutResult>`** (`{ revoked: boolean; activeSessionId?: string }`)
|
|
15
|
+
instead of `Promise<void>`, and revokes the session on the Frontend API (it used to only clear local state). Existing
|
|
16
|
+
`await atlas.signOut()` call sites keep working. The revoke is authenticated as the session being dropped, retried once,
|
|
17
|
+
then re-tried in the background (a 401 from an expired JWT rotates it once with the refresh token). `{ strict: true }`
|
|
18
|
+
rejects with `SignOutError` (`code: 'SIGN_OUT_REVOKE_FAILED'`, `sessionId`, `status`) after the local sign-out.
|
|
19
|
+
`activeSessionId` (a server-promoted session) is reported but not adopted: the bearer revoke never returns a credential
|
|
20
|
+
for it.
|
|
21
|
+
- **A signed-out session is never re-adopted.** Its id is remembered (a tombstone, via `SignOutGuard` from
|
|
22
|
+
`@atlasauth/js`) in the platform store before the revoke; the next app start refuses a stored session that is tombstoned
|
|
23
|
+
(and clears it), and a refresh still in flight at sign-out can no longer write the session back or resurrect it in
|
|
24
|
+
memory. A refused session's revoke is re-tried in the background and its tombstone dropped once the server confirms.
|
|
25
|
+
- `getToken()` / `authHeaders()` return no bearer for a session signed out while a refresh was in flight; `onChange()`
|
|
26
|
+
listeners are not called for a signed-out session.
|
|
27
|
+
|
|
28
|
+
### Added
|
|
29
|
+
- `CreateAtlasCapacitorConfig.tombstoneStore?: TombstoneStore` (default: `@capacitor/preferences` when present, else the
|
|
30
|
+
WebView's `localStorage`) and `CreateAtlasCapacitorConfig.signOutRetryDelaysMs?: number[]`.
|
|
31
|
+
- `createPreferencesTombstoneStore(preferences)` and `tombstoneStoreFromTokenStore(store)` adapters.
|
|
32
|
+
- `NativeSessionConfig.refuse?: (session: NativeSession) => boolean` on `createNativeSessionManager()`.
|
|
33
|
+
- Re-exports `SignOutError`, `SignOutOptions`, `SignOutResult` and `TombstoneStore` from `@atlasauth/js`.
|
|
34
|
+
|
|
3
35
|
## 0.1.1
|
|
4
36
|
- **`frontendApi` is validated at `createAtlasCapacitor()`.** A missing, empty or malformed value now throws an
|
|
5
37
|
`AtlasConfigError` (from `@atlasauth/js`; `code: 'FRONTEND_API_REQUIRED'` or `'FRONTEND_API_INVALID'`)
|
package/README.md
CHANGED
|
@@ -109,6 +109,23 @@ const secureStore: TokenStore = {
|
|
|
109
109
|
const atlas = await createAtlasCapacitor({ /* … */ storage: secureStore });
|
|
110
110
|
```
|
|
111
111
|
|
|
112
|
+
## Policy acceptance (terms of service, privacy)
|
|
113
|
+
|
|
114
|
+
The system-browser sign-in (`atlas.signIn()`) happens on Atlas's hosted pages, which already collect the acceptances at sign-up
|
|
115
|
+
and hold a sign-in until a newer version is accepted. For screens in your own WebView:
|
|
116
|
+
|
|
117
|
+
```ts
|
|
118
|
+
// A custom sign-up form
|
|
119
|
+
const policies = await atlas.policies();
|
|
120
|
+
mountPolicyConsent(consentHost, policies, { t: policyText() });
|
|
121
|
+
// on submit: send policies.build() as policy_acceptances
|
|
122
|
+
|
|
123
|
+
// A signed-in user whose policies changed
|
|
124
|
+
mountPolicyGate(gateHost, atlas.policyGate(), { onAccepted: () => refresh() });
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Pass `locale` to `createAtlasCapacitor` to get translated policy versions.
|
|
128
|
+
|
|
112
129
|
## Driving the pieces yourself
|
|
113
130
|
|
|
114
131
|
The flow is also exposed à la carte: `createPkcePair`, `buildAuthorizeUrl`,
|
package/dist/index.d.ts
CHANGED
|
@@ -16,10 +16,11 @@
|
|
|
16
16
|
* (the sign-in flow, the token store, the PKCE helpers) is exposed for apps that
|
|
17
17
|
* want to drive the pieces themselves.
|
|
18
18
|
*/
|
|
19
|
-
import { type NativeSession, type
|
|
19
|
+
import { NativeSessionManager, type NativeSession, type SignOutOptions, type SignOutResult, type TombstoneStore } from '@atlasauth/js';
|
|
20
20
|
import { type CapacitorPlugins } from './plugins';
|
|
21
21
|
import { type SignInOutcome } from './sign-in';
|
|
22
22
|
import { type TokenStore } from './token-store';
|
|
23
|
+
import { type PolicyApi } from './policies';
|
|
23
24
|
export interface CreateAtlasCapacitorConfig {
|
|
24
25
|
/** The instance publishable key (`pk_…`). */
|
|
25
26
|
publishableKey: string;
|
|
@@ -40,10 +41,28 @@ export interface CreateAtlasCapacitorConfig {
|
|
|
40
41
|
storage?: TokenStore;
|
|
41
42
|
/** Where the transient PKCE material is stashed on the WEB redirect path. */
|
|
42
43
|
pkceStore?: TokenStore;
|
|
44
|
+
/**
|
|
45
|
+
* Where the ids of sessions this app signed out of are kept, so a restart
|
|
46
|
+
* never re-adopts one (even when the revoke never reached the server).
|
|
47
|
+
* Defaults to `@capacitor/preferences` when present, else the WebView's
|
|
48
|
+
* `localStorage`. Adapt a secure-storage {@link TokenStore} with
|
|
49
|
+
* `tombstoneStoreFromTokenStore()` (give it its own slot).
|
|
50
|
+
*/
|
|
51
|
+
tombstoneStore?: TombstoneStore;
|
|
52
|
+
/**
|
|
53
|
+
* Delays (ms) between background re-tries of a revoke `signOut()` could not
|
|
54
|
+
* complete. @default `[15_000, 60_000, 300_000]`
|
|
55
|
+
*/
|
|
56
|
+
signOutRetryDelaysMs?: number[];
|
|
43
57
|
/** Inject the Capacitor plugins (tests). Defaults to a lazy, guarded load. */
|
|
44
58
|
plugins?: CapacitorPlugins;
|
|
45
59
|
/** Injectable for tests; defaults to the platform `fetch`. */
|
|
46
60
|
fetchImpl?: typeof fetch;
|
|
61
|
+
/**
|
|
62
|
+
* The app's UI language (`"es"`), sent as `Accept-Language` on the policy calls
|
|
63
|
+
* so the server picks a translated policy version. @default none
|
|
64
|
+
*/
|
|
65
|
+
locale?: string;
|
|
47
66
|
/** Injectable clock, epoch ms. Defaults to `Date.now`. */
|
|
48
67
|
now?: () => number;
|
|
49
68
|
/** Navigate the page on the web redirect path. @default `window.location.assign` */
|
|
@@ -61,7 +80,7 @@ export interface SignInOptions {
|
|
|
61
80
|
* the manager, {@link getToken} hands out a live (auto-refreshing) JWT, and
|
|
62
81
|
* {@link onChange} fires on every session change.
|
|
63
82
|
*/
|
|
64
|
-
export interface AtlasCapacitor {
|
|
83
|
+
export interface AtlasCapacitor extends PolicyApi {
|
|
65
84
|
/**
|
|
66
85
|
* Run the native-session sign-in: open the system browser, catch the deep-link
|
|
67
86
|
* callback, complete PKCE, exchange for a session, and store it. On the web
|
|
@@ -75,8 +94,18 @@ export interface AtlasCapacitor {
|
|
|
75
94
|
* (or null when there is nothing to complete).
|
|
76
95
|
*/
|
|
77
96
|
handleRedirectCallback(url?: string): Promise<NativeSession | null>;
|
|
78
|
-
/**
|
|
79
|
-
|
|
97
|
+
/**
|
|
98
|
+
* Sign out: remember the session id (so nothing re-adopts it — not a refresh
|
|
99
|
+
* in flight, not the next app start), revoke it on the Frontend API (retried
|
|
100
|
+
* once, then in the background, authenticated as the dropped session), and
|
|
101
|
+
* forget it locally. Resolves `{ revoked }` — `false` when the server could
|
|
102
|
+
* not be reached (the app is signed out regardless). With `{ strict: true }`
|
|
103
|
+
* it rejects with a `SignOutError` instead, after the local sign-out.
|
|
104
|
+
*
|
|
105
|
+
* A bearer client never gets a server-promoted session's credential back from
|
|
106
|
+
* the revoke, so `activeSessionId` is reported (when present) but not adopted.
|
|
107
|
+
*/
|
|
108
|
+
signOut(options?: SignOutOptions): Promise<SignOutResult>;
|
|
80
109
|
/** The current session JWT, auto-refreshed near expiry; null when signed out. */
|
|
81
110
|
getToken(): Promise<string | null>;
|
|
82
111
|
/** The headers an authenticated `/v1/client/me/*` call needs (bearer + pk). */
|
|
@@ -109,8 +138,10 @@ export interface AtlasCapacitor {
|
|
|
109
138
|
* ```
|
|
110
139
|
*/
|
|
111
140
|
export declare function createAtlasCapacitor(config: CreateAtlasCapacitorConfig): Promise<AtlasCapacitor>;
|
|
141
|
+
export { SignOutError, type SignOutOptions, type SignOutResult, type TombstoneStore, } from '@atlasauth/js';
|
|
112
142
|
export * from './plugins';
|
|
113
143
|
export * from './pkce';
|
|
114
144
|
export * from './token-store';
|
|
115
145
|
export * from './sign-in';
|
|
116
146
|
export { createNativeSessionManager, clearNativeSession, NativeSessionManager, exchangeForSession, refreshNativeSession, type NativeSession, type NativeSessionConfig, } from './native-session';
|
|
147
|
+
export * from './policies';
|
package/dist/index.js
CHANGED
|
@@ -32,13 +32,14 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
32
32
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
33
33
|
};
|
|
34
34
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
35
|
-
exports.refreshNativeSession = exports.exchangeForSession = exports.NativeSessionManager = exports.clearNativeSession = exports.createNativeSessionManager = void 0;
|
|
35
|
+
exports.refreshNativeSession = exports.exchangeForSession = exports.NativeSessionManager = exports.clearNativeSession = exports.createNativeSessionManager = exports.SignOutError = void 0;
|
|
36
36
|
exports.createAtlasCapacitor = createAtlasCapacitor;
|
|
37
37
|
const js_1 = require("@atlasauth/js");
|
|
38
38
|
const plugins_1 = require("./plugins");
|
|
39
39
|
const sign_in_1 = require("./sign-in");
|
|
40
40
|
const token_store_1 = require("./token-store");
|
|
41
41
|
const native_session_1 = require("./native-session");
|
|
42
|
+
const policies_1 = require("./policies");
|
|
42
43
|
/**
|
|
43
44
|
* Create the Atlas handle for a Capacitor app.
|
|
44
45
|
*
|
|
@@ -77,6 +78,47 @@ async function createAtlasCapacitor(config) {
|
|
|
77
78
|
(plugins.Preferences
|
|
78
79
|
? (0, token_store_1.createPreferencesTokenStore)(plugins.Preferences, sign_in_1.PKCE_STASH_KEY)
|
|
79
80
|
: (0, token_store_1.createInMemoryTokenStore)());
|
|
81
|
+
const doFetch = config.fetchImpl ?? ((input, init) => fetch(input, init));
|
|
82
|
+
/**
|
|
83
|
+
* A Frontend API request authenticated as `session` — and only it. Holds its
|
|
84
|
+
* own copy (never persisted), so a revoke re-tried after sign-out dropped the
|
|
85
|
+
* session can still authenticate: a 401 (the short-lived JWT expired) rotates
|
|
86
|
+
* it once with the refresh token and tries again.
|
|
87
|
+
*/
|
|
88
|
+
const sessionBoundRequest = (session) => {
|
|
89
|
+
const holder = new js_1.NativeSessionManager({
|
|
90
|
+
baseUrl: frontendApi,
|
|
91
|
+
publishableKey: config.publishableKey,
|
|
92
|
+
initial: session,
|
|
93
|
+
fetchImpl: config.fetchImpl,
|
|
94
|
+
now: config.now,
|
|
95
|
+
});
|
|
96
|
+
return async (path, init) => {
|
|
97
|
+
const send = async () => doFetch(`${frontendApi}${path}`, {
|
|
98
|
+
...init,
|
|
99
|
+
headers: { ...(await holder.authHeaders()), ...init?.headers },
|
|
100
|
+
});
|
|
101
|
+
const response = await send();
|
|
102
|
+
if (response.status !== 401 || !(await holder.refresh()))
|
|
103
|
+
return response;
|
|
104
|
+
return send();
|
|
105
|
+
};
|
|
106
|
+
};
|
|
107
|
+
// The sessions this app signed out of, kept in the platform store so a
|
|
108
|
+
// restart never re-adopts one. Loaded before the stored session is trusted.
|
|
109
|
+
const tombstoneStore = config.tombstoneStore ??
|
|
110
|
+
(plugins.Preferences ? (0, token_store_1.createPreferencesTombstoneStore)(plugins.Preferences) : undefined);
|
|
111
|
+
const guard = new js_1.SignOutGuard({
|
|
112
|
+
// Every revoke passes its own session-bound request; this one carries none.
|
|
113
|
+
request: (path, init) => doFetch(`${frontendApi}${path}`, {
|
|
114
|
+
...init,
|
|
115
|
+
headers: { 'x-publishable-key': config.publishableKey, ...init?.headers },
|
|
116
|
+
}),
|
|
117
|
+
frontendApi,
|
|
118
|
+
...(tombstoneStore ? { store: tombstoneStore } : {}),
|
|
119
|
+
...(config.signOutRetryDelaysMs ? { retryDelaysMs: config.signOutRetryDelaysMs } : {}),
|
|
120
|
+
});
|
|
121
|
+
await guard.ready;
|
|
80
122
|
const manager = await (0, native_session_1.createNativeSessionManager)({
|
|
81
123
|
frontendApi,
|
|
82
124
|
publishableKey: config.publishableKey,
|
|
@@ -84,14 +126,39 @@ async function createAtlasCapacitor(config) {
|
|
|
84
126
|
storage,
|
|
85
127
|
fetchImpl: config.fetchImpl,
|
|
86
128
|
now: config.now,
|
|
129
|
+
// Never adopt (nor write back) a session this app signed out of; a stored
|
|
130
|
+
// one is revoked again in the background, as itself.
|
|
131
|
+
refuse: (session) => guard.isSignedOut(session.sessionId) && guard.refuse(session.sessionId, sessionBoundRequest(session)),
|
|
87
132
|
});
|
|
133
|
+
// A refresh still in flight at sign-out must not put the session back in memory.
|
|
134
|
+
manager.onChange((session) => {
|
|
135
|
+
if (guard.isSignedOut(session.sessionId))
|
|
136
|
+
manager.clear();
|
|
137
|
+
});
|
|
138
|
+
const getToken = async () => {
|
|
139
|
+
const token = await manager.getToken();
|
|
140
|
+
// Signed out while a refresh was in flight: the rotated token is not ours.
|
|
141
|
+
return token && manager.current ? token : null;
|
|
142
|
+
};
|
|
88
143
|
const requireString = (value, name) => {
|
|
89
144
|
if (!value)
|
|
90
145
|
throw new Error(`Atlas: \`${name}\` is required to sign in.`);
|
|
91
146
|
return value;
|
|
92
147
|
};
|
|
148
|
+
// Policy acceptance (terms, privacy, any policy) over the same bearer session.
|
|
149
|
+
const policyApi = (0, policies_1.createPolicyApi)({
|
|
150
|
+
publishableKey: config.publishableKey,
|
|
151
|
+
frontendApi,
|
|
152
|
+
authHeaders: async () => {
|
|
153
|
+
const token = await getToken();
|
|
154
|
+
return token ? { Authorization: `Bearer ${token}` } : {};
|
|
155
|
+
},
|
|
156
|
+
fetchImpl: config.fetchImpl,
|
|
157
|
+
locale: config.locale,
|
|
158
|
+
});
|
|
93
159
|
return {
|
|
94
160
|
manager,
|
|
161
|
+
...policyApi,
|
|
95
162
|
async signIn(options = {}) {
|
|
96
163
|
const clientId = requireString(options.clientId ?? config.clientId, 'clientId');
|
|
97
164
|
const redirectUri = requireString(options.redirectUri ?? config.redirectUri, 'redirectUri');
|
|
@@ -132,25 +199,47 @@ async function createAtlasCapacitor(config) {
|
|
|
132
199
|
manager.setSession(session);
|
|
133
200
|
return session;
|
|
134
201
|
},
|
|
135
|
-
async signOut() {
|
|
202
|
+
async signOut(options = {}) {
|
|
203
|
+
const session = manager.current;
|
|
204
|
+
// Tombstones the session synchronously, before anything below can yield;
|
|
205
|
+
// the revoke itself rides on the session being dropped.
|
|
206
|
+
const pending = session
|
|
207
|
+
? guard.revoke(session.sessionId, { ...options, request: sessionBoundRequest(session) })
|
|
208
|
+
: null;
|
|
136
209
|
manager.clear();
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
210
|
+
// The tombstone already keeps a restart from re-adopting a session this
|
|
211
|
+
// clear fails to remove, so a store error does not fail the sign-out.
|
|
212
|
+
await Promise.resolve()
|
|
213
|
+
.then(() => (0, native_session_1.clearNativeSession)(storage))
|
|
214
|
+
.catch(() => undefined);
|
|
215
|
+
// Nothing to revoke when signed out (a bearer client has no cookie to find one by).
|
|
216
|
+
const attempt = pending ? await pending : { sessionId: null, outcome: { revoked: true, status: 200 } };
|
|
217
|
+
// A promoted session (`activeSessionId`) comes with cookies only — the
|
|
218
|
+
// bearer revoke never hands this client a credential for it — so it is
|
|
219
|
+
// reported, not adopted.
|
|
220
|
+
return guard.settle(attempt, options);
|
|
141
221
|
},
|
|
142
|
-
|
|
143
|
-
|
|
222
|
+
getToken,
|
|
223
|
+
async authHeaders() {
|
|
224
|
+
const token = await getToken();
|
|
225
|
+
return token
|
|
226
|
+
? { Authorization: `Bearer ${token}`, 'x-publishable-key': config.publishableKey }
|
|
227
|
+
: { 'x-publishable-key': config.publishableKey };
|
|
144
228
|
},
|
|
145
229
|
getSession() {
|
|
146
230
|
return manager.current;
|
|
147
231
|
},
|
|
148
232
|
onChange(listener) {
|
|
149
|
-
return manager.onChange(
|
|
233
|
+
return manager.onChange((session) => {
|
|
234
|
+
if (!guard.isSignedOut(session.sessionId))
|
|
235
|
+
listener(session);
|
|
236
|
+
});
|
|
150
237
|
},
|
|
151
238
|
};
|
|
152
239
|
}
|
|
153
240
|
// ── Re-exports: the pieces, for apps that drive the flow themselves ──────────
|
|
241
|
+
var js_2 = require("@atlasauth/js");
|
|
242
|
+
Object.defineProperty(exports, "SignOutError", { enumerable: true, get: function () { return js_2.SignOutError; } });
|
|
154
243
|
__exportStar(require("./plugins"), exports);
|
|
155
244
|
__exportStar(require("./pkce"), exports);
|
|
156
245
|
__exportStar(require("./token-store"), exports);
|
|
@@ -161,4 +250,6 @@ Object.defineProperty(exports, "clearNativeSession", { enumerable: true, get: fu
|
|
|
161
250
|
Object.defineProperty(exports, "NativeSessionManager", { enumerable: true, get: function () { return native_session_2.NativeSessionManager; } });
|
|
162
251
|
Object.defineProperty(exports, "exchangeForSession", { enumerable: true, get: function () { return native_session_2.exchangeForSession; } });
|
|
163
252
|
Object.defineProperty(exports, "refreshNativeSession", { enumerable: true, get: function () { return native_session_2.refreshNativeSession; } });
|
|
253
|
+
// Policy acceptance: the DOM pieces for a WebView screen, the gate banner, and the API builder.
|
|
254
|
+
__exportStar(require("./policies"), exports);
|
|
164
255
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;GAiBG;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/native-session.d.ts
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* session id the refresh call needs and the current JWT. Give the native session
|
|
13
13
|
* its OWN store/key, separate from any other value the app keeps.
|
|
14
14
|
*/
|
|
15
|
-
import { NativeSessionManager } from '@atlasauth/js';
|
|
15
|
+
import { NativeSessionManager, type NativeSession } from '@atlasauth/js';
|
|
16
16
|
import { type TokenStore } from './token-store';
|
|
17
17
|
export interface NativeSessionConfig {
|
|
18
18
|
/** The instance's FAPI origin, e.g. `https://fapi.acme.atlasauth.net`. */
|
|
@@ -31,6 +31,14 @@ export interface NativeSessionConfig {
|
|
|
31
31
|
fetchImpl?: typeof fetch;
|
|
32
32
|
/** Injectable clock, epoch ms. Defaults to `Date.now`. */
|
|
33
33
|
now?: () => number;
|
|
34
|
+
/**
|
|
35
|
+
* Asked before a session is adopted from the store on boot, and before a
|
|
36
|
+
* (rotated) session is persisted. Return true for a session the app signed
|
|
37
|
+
* out of: it is not seeded (and is cleared from the store), nor written back
|
|
38
|
+
* by a refresh that was still in flight at sign-out. `createAtlasCapacitor`
|
|
39
|
+
* wires this to its `SignOutGuard`.
|
|
40
|
+
*/
|
|
41
|
+
refuse?: (session: NativeSession) => boolean;
|
|
34
42
|
}
|
|
35
43
|
/**
|
|
36
44
|
* Build a {@link NativeSessionManager} wired to a Capacitor token store.
|
package/dist/native-session.js
CHANGED
|
@@ -35,7 +35,15 @@ async function createNativeSessionManager(config) {
|
|
|
35
35
|
allowSameOrigin: false,
|
|
36
36
|
});
|
|
37
37
|
const storage = config.storage ?? (0, token_store_1.createInMemoryTokenStore)();
|
|
38
|
-
|
|
38
|
+
let initial = (0, js_1.parseNativeSession)(await storage.getToken()) ?? undefined;
|
|
39
|
+
if (initial && config.refuse?.(initial)) {
|
|
40
|
+
// A session this app signed out of (the clear never landed, or a refresh
|
|
41
|
+
// in flight at sign-out wrote it back): boot signed out.
|
|
42
|
+
initial = undefined;
|
|
43
|
+
await Promise.resolve()
|
|
44
|
+
.then(() => storage.clearToken())
|
|
45
|
+
.catch(() => undefined);
|
|
46
|
+
}
|
|
39
47
|
return new js_1.NativeSessionManager({
|
|
40
48
|
baseUrl,
|
|
41
49
|
publishableKey: config.publishableKey,
|
|
@@ -47,6 +55,8 @@ async function createNativeSessionManager(config) {
|
|
|
47
55
|
// the rotated refresh token survives an app restart. Fire-and-forget — the
|
|
48
56
|
// store may be async, and a write failure must not break the live session.
|
|
49
57
|
persist: (session) => {
|
|
58
|
+
if (config.refuse?.(session))
|
|
59
|
+
return;
|
|
50
60
|
void Promise.resolve(storage.setToken((0, js_1.serializeNativeSession)(session))).catch(() => undefined);
|
|
51
61
|
},
|
|
52
62
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"native-session.js","sourceRoot":"","sources":["../src/native-session.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;GAaG;;;
|
|
1
|
+
{"version":3,"file":"native-session.js","sourceRoot":"","sources":["../src/native-session.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;GAaG;;;AA8CH,gEAqCC;AAGD,gDAEC;AAtFD,sCAMuB;AACvB,+CAA0E;AA6B1E;;;;;;;GAOG;AACI,KAAK,UAAU,0BAA0B,CAC9C,MAA2B;IAE3B,2EAA2E;IAC3E,sCAAsC;IACtC,MAAM,OAAO,GAAG,IAAA,uBAAkB,EAAC,MAAM,CAAC,WAAW,EAAE;QACrD,SAAS,EAAE,8BAA8B;QACzC,eAAe,EAAE,KAAK;KACvB,CAAC,CAAC;IACH,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,IAAI,IAAA,sCAAwB,GAAE,CAAC;IAC7D,IAAI,OAAO,GAAG,IAAA,uBAAkB,EAAC,MAAM,OAAO,CAAC,QAAQ,EAAE,CAAC,IAAI,SAAS,CAAC;IACxE,IAAI,OAAO,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC;QACxC,yEAAyE;QACzE,yDAAyD;QACzD,OAAO,GAAG,SAAS,CAAC;QACpB,MAAM,OAAO,CAAC,OAAO,EAAE;aACpB,IAAI,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC;aAChC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;IAC5B,CAAC;IAED,OAAO,IAAI,yBAAoB,CAAC;QAC9B,OAAO;QACP,cAAc,EAAE,MAAM,CAAC,cAAc;QACrC,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,OAAO;QACP,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,GAAG,EAAE,MAAM,CAAC,GAAG;QACf,2EAA2E;QAC3E,2EAA2E;QAC3E,2EAA2E;QAC3E,OAAO,EAAE,CAAC,OAAsB,EAAE,EAAE;YAClC,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC;gBAAE,OAAO;YACrC,KAAK,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAA,2BAAsB,EAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAC3E,GAAG,EAAE,CAAC,SAAS,CAChB,CAAC;QACJ,CAAC;KACF,CAAC,CAAC;AACL,CAAC;AAED,qDAAqD;AAC9C,KAAK,UAAU,kBAAkB,CAAC,OAAmB;IAC1D,MAAM,OAAO,CAAC,UAAU,EAAE,CAAC;AAC7B,CAAC;AAED,oCAKuB;AAJrB,0GAAA,oBAAoB,OAAA;AACpB,wGAAA,kBAAkB,OAAA;AAClB,0GAAA,oBAAoB,OAAA"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Policy acceptance (terms of service, privacy, any policy) for Capacitor.
|
|
3
|
+
*
|
|
4
|
+
* The native-session sign-in runs in the SYSTEM browser on Atlas's hosted pages,
|
|
5
|
+
* which already collect the acceptances (sign-up) and hold a sign-in until a
|
|
6
|
+
* newer version is accepted, so {@link AtlasCapacitor.signIn} needs nothing more.
|
|
7
|
+
* What the app's own WebView layer needs is:
|
|
8
|
+
*
|
|
9
|
+
* - the policies for its own screens (a custom sign-up form): `policies()`
|
|
10
|
+
* returns a `PolicyAcceptanceController`, and the DOM pieces re-exported below
|
|
11
|
+
* (`mountPolicyConsent`, `mountPolicyClickwrap`, `mountPolicyAcceptStep`) draw
|
|
12
|
+
* it;
|
|
13
|
+
* - in-app re-acceptance for the signed-in user: `policyGate()` and
|
|
14
|
+
* {@link mountPolicyGate}'s banner, which post `/v1/client/me/policies/accept`
|
|
15
|
+
* with the session's bearer token.
|
|
16
|
+
*
|
|
17
|
+
* Everything is `@atlasauth/js`; this file only supplies a bearer-authenticated
|
|
18
|
+
* client (a Capacitor app has no cookie against the FAPI origin).
|
|
19
|
+
*/
|
|
20
|
+
import { FapiClient, PolicyAcceptanceController, PolicyGateController, type PolicyClasses, type PolicyT } from '@atlasauth/js';
|
|
21
|
+
export interface PolicyApiConfig {
|
|
22
|
+
publishableKey: string;
|
|
23
|
+
frontendApi: string;
|
|
24
|
+
/** The headers an authenticated `/v1/client/me/*` call needs (bearer + pk); empty-bearer when signed out. */
|
|
25
|
+
authHeaders: () => Promise<Record<string, string>>;
|
|
26
|
+
fetchImpl?: typeof fetch;
|
|
27
|
+
/** The UI language, sent as `Accept-Language` and used to pick a translation. */
|
|
28
|
+
locale?: string;
|
|
29
|
+
}
|
|
30
|
+
/** What the Atlas handle exposes for policy acceptance. */
|
|
31
|
+
export interface PolicyApi {
|
|
32
|
+
/** The bearer-authenticated Frontend API client (for `@atlasauth/js` helpers). */
|
|
33
|
+
readonly fapi: FapiClient;
|
|
34
|
+
/**
|
|
35
|
+
* Load the instance's policies (`GET /v1/client/policies`) into a controller
|
|
36
|
+
* for a sign-up form of your own. `signIn` keeps only the policies that also
|
|
37
|
+
* apply at sign-in.
|
|
38
|
+
*/
|
|
39
|
+
policies(options?: {
|
|
40
|
+
combined?: boolean;
|
|
41
|
+
signIn?: boolean;
|
|
42
|
+
locale?: string;
|
|
43
|
+
}): Promise<PolicyAcceptanceController>;
|
|
44
|
+
/**
|
|
45
|
+
* The controller for an attempt the server holds at `needs_policy_acceptance`
|
|
46
|
+
* (an attempt view with `pending_policies`), with the content filled in.
|
|
47
|
+
*/
|
|
48
|
+
pendingPolicies(attempt: {
|
|
49
|
+
pending_policies?: unknown;
|
|
50
|
+
} | null | undefined, options?: {
|
|
51
|
+
combined?: boolean;
|
|
52
|
+
locale?: string;
|
|
53
|
+
}): Promise<PolicyAcceptanceController>;
|
|
54
|
+
/**
|
|
55
|
+
* In-app re-acceptance for the signed-in user: `load()` the standing,
|
|
56
|
+
* `begin()` a controller for what needs accepting, `accept(controller)` to send it.
|
|
57
|
+
*/
|
|
58
|
+
policyGate(locale?: string): PolicyGateController;
|
|
59
|
+
}
|
|
60
|
+
/** Build the policy API over a bearer-authenticated client. */
|
|
61
|
+
export declare function createPolicyApi(config: PolicyApiConfig): PolicyApi;
|
|
62
|
+
/** The English policy strings, with any `policy.*` overrides on top. */
|
|
63
|
+
export declare function policyText(strings?: Record<string, string>): PolicyT;
|
|
64
|
+
export interface MountPolicyGateOptions {
|
|
65
|
+
/** Override any `policy.*` string. */
|
|
66
|
+
strings?: Record<string, string>;
|
|
67
|
+
/** Extra class names per element. */
|
|
68
|
+
classes?: PolicyClasses;
|
|
69
|
+
/** Called after the user accepted and the server confirmed. */
|
|
70
|
+
onAccepted?(): void;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Mount the signed-in re-acceptance banner into `host`: it loads the user's
|
|
74
|
+
* standing from `gate`, shows a banner when a policy needs accepting (with the
|
|
75
|
+
* end of any grace window), and "Review and accept" opens the acceptance step
|
|
76
|
+
* and posts the result. Draws nothing when there is nothing to accept. Call it
|
|
77
|
+
* only for a signed-in user; `ready` resolves once the standing has loaded.
|
|
78
|
+
*/
|
|
79
|
+
export declare function mountPolicyGate(host: HTMLElement, gate: PolicyGateController, options?: MountPolicyGateOptions): {
|
|
80
|
+
destroy(): void;
|
|
81
|
+
ready: Promise<void>;
|
|
82
|
+
};
|
|
83
|
+
export { PolicyAcceptanceController, PolicyGateController, buildPolicyAcceptances, injectPolicyStyles, isPolicyAcceptanceRequired, mountPolicyAcceptStep, mountPolicyClickwrap, mountPolicyConsent, runScrollPolicies, type Policy, type PolicyAcceptancePayload, } from '@atlasauth/js';
|
package/dist/policies.js
ADDED
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Policy acceptance (terms of service, privacy, any policy) for Capacitor.
|
|
4
|
+
*
|
|
5
|
+
* The native-session sign-in runs in the SYSTEM browser on Atlas's hosted pages,
|
|
6
|
+
* which already collect the acceptances (sign-up) and hold a sign-in until a
|
|
7
|
+
* newer version is accepted, so {@link AtlasCapacitor.signIn} needs nothing more.
|
|
8
|
+
* What the app's own WebView layer needs is:
|
|
9
|
+
*
|
|
10
|
+
* - the policies for its own screens (a custom sign-up form): `policies()`
|
|
11
|
+
* returns a `PolicyAcceptanceController`, and the DOM pieces re-exported below
|
|
12
|
+
* (`mountPolicyConsent`, `mountPolicyClickwrap`, `mountPolicyAcceptStep`) draw
|
|
13
|
+
* it;
|
|
14
|
+
* - in-app re-acceptance for the signed-in user: `policyGate()` and
|
|
15
|
+
* {@link mountPolicyGate}'s banner, which post `/v1/client/me/policies/accept`
|
|
16
|
+
* with the session's bearer token.
|
|
17
|
+
*
|
|
18
|
+
* Everything is `@atlasauth/js`; this file only supplies a bearer-authenticated
|
|
19
|
+
* client (a Capacitor app has no cookie against the FAPI origin).
|
|
20
|
+
*/
|
|
21
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
22
|
+
exports.runScrollPolicies = exports.mountPolicyConsent = exports.mountPolicyClickwrap = exports.mountPolicyAcceptStep = exports.isPolicyAcceptanceRequired = exports.injectPolicyStyles = exports.buildPolicyAcceptances = exports.PolicyGateController = exports.PolicyAcceptanceController = void 0;
|
|
23
|
+
exports.createPolicyApi = createPolicyApi;
|
|
24
|
+
exports.policyText = policyText;
|
|
25
|
+
exports.mountPolicyGate = mountPolicyGate;
|
|
26
|
+
const js_1 = require("@atlasauth/js");
|
|
27
|
+
/** Build the policy API over a bearer-authenticated client. */
|
|
28
|
+
function createPolicyApi(config) {
|
|
29
|
+
const doFetch = config.fetchImpl ?? ((input, init) => fetch(input, init));
|
|
30
|
+
const fapi = new js_1.FapiClient({
|
|
31
|
+
publishableKey: config.publishableKey,
|
|
32
|
+
baseUrl: config.frontendApi,
|
|
33
|
+
locale: config.locale,
|
|
34
|
+
fetchImpl: async (input, init) => {
|
|
35
|
+
const headers = new Headers(init?.headers);
|
|
36
|
+
for (const [k, v] of Object.entries(await config.authHeaders()))
|
|
37
|
+
if (!headers.has(k))
|
|
38
|
+
headers.set(k, v);
|
|
39
|
+
return doFetch(input, { ...init, headers });
|
|
40
|
+
},
|
|
41
|
+
});
|
|
42
|
+
return {
|
|
43
|
+
fapi,
|
|
44
|
+
async policies(options = {}) {
|
|
45
|
+
const controller = new js_1.PolicyAcceptanceController([], { combined: options.combined });
|
|
46
|
+
controller.setPolicies(await (0, js_1.loadPolicies)(fapi, { locale: options.locale ?? config.locale, signIn: options.signIn }));
|
|
47
|
+
return controller;
|
|
48
|
+
},
|
|
49
|
+
pendingPolicies: (attempt, options = {}) => (0, js_1.controllerForPending)(fapi, attempt, { combined: options.combined, locale: options.locale ?? config.locale }),
|
|
50
|
+
policyGate: (locale) => new js_1.PolicyGateController(fapi, locale ?? config.locale),
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
/** The English policy strings, with any `policy.*` overrides on top. */
|
|
54
|
+
function policyText(strings) {
|
|
55
|
+
return (0, js_1.policyTranslator)((key, vars) => {
|
|
56
|
+
const template = strings?.[key];
|
|
57
|
+
return template ? template.replace(/\{(\w+)\}/g, (m, n) => vars?.[n] ?? m) : '';
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Mount the signed-in re-acceptance banner into `host`: it loads the user's
|
|
62
|
+
* standing from `gate`, shows a banner when a policy needs accepting (with the
|
|
63
|
+
* end of any grace window), and "Review and accept" opens the acceptance step
|
|
64
|
+
* and posts the result. Draws nothing when there is nothing to accept. Call it
|
|
65
|
+
* only for a signed-in user; `ready` resolves once the standing has loaded.
|
|
66
|
+
*/
|
|
67
|
+
function mountPolicyGate(host, gate, options = {}) {
|
|
68
|
+
const doc = host.ownerDocument;
|
|
69
|
+
const t = policyText(options.strings);
|
|
70
|
+
let step = null;
|
|
71
|
+
let open = false;
|
|
72
|
+
let alive = true;
|
|
73
|
+
(0, js_1.injectPolicyStyles)(doc);
|
|
74
|
+
const showError = (message) => {
|
|
75
|
+
const p = doc.createElement('p');
|
|
76
|
+
p.setAttribute('role', 'alert');
|
|
77
|
+
p.textContent = message;
|
|
78
|
+
host.append(p);
|
|
79
|
+
};
|
|
80
|
+
const draw = () => {
|
|
81
|
+
if (!alive || open)
|
|
82
|
+
return;
|
|
83
|
+
host.textContent = '';
|
|
84
|
+
host.setAttribute('data-atlas-policy-gate', '');
|
|
85
|
+
if (gate.pending.length === 0)
|
|
86
|
+
return;
|
|
87
|
+
const banner = doc.createElement('div');
|
|
88
|
+
banner.className = 'atlas-policy-banner';
|
|
89
|
+
banner.setAttribute('role', 'status');
|
|
90
|
+
banner.setAttribute('data-atlas-policy-banner', '');
|
|
91
|
+
const text = doc.createElement('span');
|
|
92
|
+
const strong = doc.createElement('strong');
|
|
93
|
+
strong.textContent = `${t('policy.bannerTitle')}. `;
|
|
94
|
+
text.append(strong, t('policy.bannerBody', { policies: (0, js_1.joinTitles)(gate.pending.map((p) => p.title), t('policy.and')) }));
|
|
95
|
+
if (gate.graceEndsAt)
|
|
96
|
+
text.append(` ${t('policy.bannerGrace', { date: (0, js_1.formatPolicyDate)(gate.graceEndsAt) })}`);
|
|
97
|
+
const button = doc.createElement('button');
|
|
98
|
+
button.type = 'button';
|
|
99
|
+
button.className = ['atlas-policy-link', options.classes?.link].filter(Boolean).join(' ');
|
|
100
|
+
button.textContent = t('policy.bannerReview');
|
|
101
|
+
button.addEventListener('click', () => void begin());
|
|
102
|
+
banner.append(text, button);
|
|
103
|
+
host.append(banner);
|
|
104
|
+
};
|
|
105
|
+
const close = () => {
|
|
106
|
+
step?.destroy();
|
|
107
|
+
step = null;
|
|
108
|
+
open = false;
|
|
109
|
+
draw();
|
|
110
|
+
};
|
|
111
|
+
const begin = async () => {
|
|
112
|
+
const controller = await gate.begin();
|
|
113
|
+
if (!alive)
|
|
114
|
+
return;
|
|
115
|
+
open = true;
|
|
116
|
+
host.textContent = '';
|
|
117
|
+
const stepHost = doc.createElement('div');
|
|
118
|
+
host.append(stepHost);
|
|
119
|
+
step = (0, js_1.mountPolicyAcceptStep)(stepHost, controller, {
|
|
120
|
+
t,
|
|
121
|
+
classes: options.classes,
|
|
122
|
+
onSubmit: async () => {
|
|
123
|
+
step?.setBusy(true);
|
|
124
|
+
const res = await gate.accept(controller);
|
|
125
|
+
step?.setBusy(false);
|
|
126
|
+
if (!res.ok) {
|
|
127
|
+
showError(res.errors[0]?.message ?? t('policy.requiredGeneric'));
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
close();
|
|
131
|
+
options.onAccepted?.();
|
|
132
|
+
},
|
|
133
|
+
onDecline: close,
|
|
134
|
+
});
|
|
135
|
+
};
|
|
136
|
+
const off = gate.subscribe(draw);
|
|
137
|
+
const ready = gate.load().then(draw, draw);
|
|
138
|
+
return {
|
|
139
|
+
ready,
|
|
140
|
+
destroy() {
|
|
141
|
+
alive = false;
|
|
142
|
+
off();
|
|
143
|
+
step?.destroy();
|
|
144
|
+
host.textContent = '';
|
|
145
|
+
},
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
// The DOM pieces and helpers a WebView screen draws with (all from `@atlasauth/js`).
|
|
149
|
+
var js_2 = require("@atlasauth/js");
|
|
150
|
+
Object.defineProperty(exports, "PolicyAcceptanceController", { enumerable: true, get: function () { return js_2.PolicyAcceptanceController; } });
|
|
151
|
+
Object.defineProperty(exports, "PolicyGateController", { enumerable: true, get: function () { return js_2.PolicyGateController; } });
|
|
152
|
+
Object.defineProperty(exports, "buildPolicyAcceptances", { enumerable: true, get: function () { return js_2.buildPolicyAcceptances; } });
|
|
153
|
+
Object.defineProperty(exports, "injectPolicyStyles", { enumerable: true, get: function () { return js_2.injectPolicyStyles; } });
|
|
154
|
+
Object.defineProperty(exports, "isPolicyAcceptanceRequired", { enumerable: true, get: function () { return js_2.isPolicyAcceptanceRequired; } });
|
|
155
|
+
Object.defineProperty(exports, "mountPolicyAcceptStep", { enumerable: true, get: function () { return js_2.mountPolicyAcceptStep; } });
|
|
156
|
+
Object.defineProperty(exports, "mountPolicyClickwrap", { enumerable: true, get: function () { return js_2.mountPolicyClickwrap; } });
|
|
157
|
+
Object.defineProperty(exports, "mountPolicyConsent", { enumerable: true, get: function () { return js_2.mountPolicyConsent; } });
|
|
158
|
+
Object.defineProperty(exports, "runScrollPolicies", { enumerable: true, get: function () { return js_2.runScrollPolicies; } });
|
|
159
|
+
//# sourceMappingURL=policies.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"policies.js","sourceRoot":"","sources":["../src/policies.ts"],"names":[],"mappings":"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"}
|
package/dist/token-store.d.ts
CHANGED
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
* `capacitor-secure-storage-plugin` — behind this same {@link TokenStore}
|
|
21
21
|
* interface. See {@link createPreferencesTokenStore} for the drop-in shape.
|
|
22
22
|
*/
|
|
23
|
+
import type { TombstoneStore } from '@atlasauth/js';
|
|
23
24
|
import type { PreferencesPlugin } from './plugins';
|
|
24
25
|
/**
|
|
25
26
|
* A single-slot token store: read, write, clear one string value. This is the
|
|
@@ -61,3 +62,16 @@ export declare function createPreferencesTokenStore(preferences: PreferencesPlug
|
|
|
61
62
|
* adapter) in production.
|
|
62
63
|
*/
|
|
63
64
|
export declare function createInMemoryTokenStore(): TokenStore;
|
|
65
|
+
/**
|
|
66
|
+
* A {@link TombstoneStore} over `@capacitor/preferences` — where the ids of the
|
|
67
|
+
* sessions this app signed out of are kept, so a restart never re-adopts one
|
|
68
|
+
* (see `SignOutGuard` in `@atlasauth/js`). The default when the plugin is
|
|
69
|
+
* present. Tombstones are session ids, never credentials, so plaintext is fine.
|
|
70
|
+
*/
|
|
71
|
+
export declare function createPreferencesTombstoneStore(preferences: PreferencesPlugin): TombstoneStore;
|
|
72
|
+
/**
|
|
73
|
+
* Adapt a single-slot {@link TokenStore} (e.g. a secure-storage-backed one) to
|
|
74
|
+
* a {@link TombstoneStore}. Give it its OWN slot — never the session's: the
|
|
75
|
+
* key `SignOutGuard` asks for is ignored, every read and write hits that slot.
|
|
76
|
+
*/
|
|
77
|
+
export declare function tombstoneStoreFromTokenStore(store: TokenStore): TombstoneStore;
|
package/dist/token-store.js
CHANGED
|
@@ -25,6 +25,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
25
25
|
exports.DEFAULT_SESSION_KEY = void 0;
|
|
26
26
|
exports.createPreferencesTokenStore = createPreferencesTokenStore;
|
|
27
27
|
exports.createInMemoryTokenStore = createInMemoryTokenStore;
|
|
28
|
+
exports.createPreferencesTombstoneStore = createPreferencesTombstoneStore;
|
|
29
|
+
exports.tombstoneStoreFromTokenStore = tombstoneStoreFromTokenStore;
|
|
28
30
|
/** The default key the serialized native session is stored under. */
|
|
29
31
|
exports.DEFAULT_SESSION_KEY = 'atlas.native_session';
|
|
30
32
|
/**
|
|
@@ -67,4 +69,27 @@ function createInMemoryTokenStore() {
|
|
|
67
69
|
},
|
|
68
70
|
};
|
|
69
71
|
}
|
|
72
|
+
/**
|
|
73
|
+
* A {@link TombstoneStore} over `@capacitor/preferences` — where the ids of the
|
|
74
|
+
* sessions this app signed out of are kept, so a restart never re-adopts one
|
|
75
|
+
* (see `SignOutGuard` in `@atlasauth/js`). The default when the plugin is
|
|
76
|
+
* present. Tombstones are session ids, never credentials, so plaintext is fine.
|
|
77
|
+
*/
|
|
78
|
+
function createPreferencesTombstoneStore(preferences) {
|
|
79
|
+
return {
|
|
80
|
+
getItem: async (key) => (await preferences.get({ key })).value ?? null,
|
|
81
|
+
setItem: (key, value) => preferences.set({ key, value }),
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Adapt a single-slot {@link TokenStore} (e.g. a secure-storage-backed one) to
|
|
86
|
+
* a {@link TombstoneStore}. Give it its OWN slot — never the session's: the
|
|
87
|
+
* key `SignOutGuard` asks for is ignored, every read and write hits that slot.
|
|
88
|
+
*/
|
|
89
|
+
function tombstoneStoreFromTokenStore(store) {
|
|
90
|
+
return {
|
|
91
|
+
getItem: () => store.getToken(),
|
|
92
|
+
setItem: (_key, value) => store.setToken(value),
|
|
93
|
+
};
|
|
94
|
+
}
|
|
70
95
|
//# sourceMappingURL=token-store.js.map
|
package/dist/token-store.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"token-store.js","sourceRoot":"","sources":["../src/token-store.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;;;
|
|
1
|
+
{"version":3,"file":"token-store.js","sourceRoot":"","sources":["../src/token-store.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;;;AAuCH,kEASC;AAQD,4DAWC;AAQD,0EAKC;AAOD,oEAKC;AAvED,qEAAqE;AACxD,QAAA,mBAAmB,GAAG,sBAAsB,CAAC;AAE1D;;;;;;;;;;;;;;GAcG;AACH,SAAgB,2BAA2B,CACzC,WAA8B,EAC9B,MAAc,2BAAmB;IAEjC,OAAO;QACL,QAAQ,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,MAAM,WAAW,CAAC,GAAG,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI;QACpE,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC;QACpD,UAAU,EAAE,GAAG,EAAE,CAAC,WAAW,CAAC,MAAM,CAAC,EAAE,GAAG,EAAE,CAAC;KAC9C,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,SAAgB,wBAAwB;IACtC,IAAI,KAAK,GAAkB,IAAI,CAAC;IAChC,OAAO;QACL,QAAQ,EAAE,GAAG,EAAE,CAAC,KAAK;QACrB,QAAQ,EAAE,CAAC,IAAY,EAAE,EAAE;YACzB,KAAK,GAAG,IAAI,CAAC;QACf,CAAC;QACD,UAAU,EAAE,GAAG,EAAE;YACf,KAAK,GAAG,IAAI,CAAC;QACf,CAAC;KACF,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,SAAgB,+BAA+B,CAAC,WAA8B;IAC5E,OAAO;QACL,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,MAAM,WAAW,CAAC,GAAG,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI;QACtE,OAAO,EAAE,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC;KACzD,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,SAAgB,4BAA4B,CAAC,KAAiB;IAC5D,OAAO;QACL,OAAO,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,QAAQ,EAAE;QAC/B,OAAO,EAAE,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC;KAChD,CAAC;AACJ,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlasauth/capacitor",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"main": "./dist/index.js",
|
|
5
5
|
"types": "./dist/index.d.ts",
|
|
6
6
|
"exports": {
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"./package.json": "./package.json"
|
|
12
12
|
},
|
|
13
13
|
"dependencies": {
|
|
14
|
-
"@atlasauth/js": "0.
|
|
14
|
+
"@atlasauth/js": "0.19.0"
|
|
15
15
|
},
|
|
16
16
|
"peerDependencies": {
|
|
17
17
|
"@capacitor/core": ">=6",
|