@rool-dev/sdk 0.12.5 → 2.0.0-dev.36748aa
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/README.md +436 -784
- package/dist/agents.d.ts +138 -0
- package/dist/agents.d.ts.map +1 -0
- package/dist/agents.js +563 -0
- package/dist/agents.js.map +1 -0
- package/dist/auth-base.d.ts +43 -88
- package/dist/auth-base.d.ts.map +1 -1
- package/dist/auth-base.js +178 -302
- package/dist/auth-base.js.map +1 -1
- package/dist/auth-browser.d.ts +7 -25
- package/dist/auth-browser.d.ts.map +1 -1
- package/dist/auth-browser.js +45 -82
- package/dist/auth-browser.js.map +1 -1
- package/dist/auth-native.d.ts +9 -56
- package/dist/auth-native.d.ts.map +1 -1
- package/dist/auth-native.js +88 -177
- package/dist/auth-native.js.map +1 -1
- package/dist/auth-node.d.ts +32 -36
- package/dist/auth-node.d.ts.map +1 -1
- package/dist/auth-node.js +338 -265
- package/dist/auth-node.js.map +1 -1
- package/dist/auth-url.d.ts +6 -0
- package/dist/auth-url.d.ts.map +1 -0
- package/dist/auth-url.js +30 -0
- package/dist/auth-url.js.map +1 -0
- package/dist/client.d.ts +35 -290
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +323 -635
- package/dist/client.js.map +1 -1
- package/dist/events.d.ts +40 -0
- package/dist/events.d.ts.map +1 -0
- package/dist/events.js +175 -0
- package/dist/events.js.map +1 -0
- package/dist/files.d.ts +174 -0
- package/dist/files.d.ts.map +1 -0
- package/dist/files.js +846 -0
- package/dist/files.js.map +1 -0
- package/dist/index.d.ts +16 -19
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -20
- package/dist/index.js.map +1 -1
- package/dist/machine.d.ts +51 -0
- package/dist/machine.d.ts.map +1 -0
- package/dist/machine.js +142 -0
- package/dist/machine.js.map +1 -0
- package/dist/problem.d.ts +11 -0
- package/dist/problem.d.ts.map +1 -0
- package/dist/problem.js +20 -0
- package/dist/problem.js.map +1 -0
- package/dist/structured.d.ts +84 -0
- package/dist/structured.d.ts.map +1 -0
- package/dist/structured.js +405 -0
- package/dist/structured.js.map +1 -0
- package/dist/types.d.ts +119 -520
- package/dist/types.d.ts.map +1 -1
- package/package.json +11 -16
- package/dist/auth.d.ts +0 -99
- package/dist/auth.d.ts.map +0 -1
- package/dist/auth.js +0 -217
- package/dist/auth.js.map +0 -1
- package/dist/client-info.d.ts +0 -18
- package/dist/client-info.d.ts.map +0 -1
- package/dist/client-info.js +0 -25
- package/dist/client-info.js.map +0 -1
- package/dist/event-emitter.d.ts +0 -45
- package/dist/event-emitter.d.ts.map +0 -1
- package/dist/event-emitter.js +0 -86
- package/dist/event-emitter.js.map +0 -1
- package/dist/graphql.d.ts +0 -90
- package/dist/graphql.d.ts.map +0 -1
- package/dist/graphql.js +0 -471
- package/dist/graphql.js.map +0 -1
- package/dist/logger.d.ts +0 -13
- package/dist/logger.d.ts.map +0 -1
- package/dist/logger.js +0 -17
- package/dist/logger.js.map +0 -1
- package/dist/path.d.ts +0 -6
- package/dist/path.d.ts.map +0 -1
- package/dist/path.js +0 -47
- package/dist/path.js.map +0 -1
- package/dist/reroute.d.ts +0 -22
- package/dist/reroute.d.ts.map +0 -1
- package/dist/reroute.js +0 -70
- package/dist/reroute.js.map +0 -1
- package/dist/rest.d.ts +0 -54
- package/dist/rest.d.ts.map +0 -1
- package/dist/rest.js +0 -171
- package/dist/rest.js.map +0 -1
- package/dist/router.d.ts +0 -20
- package/dist/router.d.ts.map +0 -1
- package/dist/router.js +0 -54
- package/dist/router.js.map +0 -1
- package/dist/space-session.d.ts +0 -30
- package/dist/space-session.d.ts.map +0 -1
- package/dist/space-session.js +0 -83
- package/dist/space-session.js.map +0 -1
- package/dist/space.d.ts +0 -161
- package/dist/space.d.ts.map +0 -1
- package/dist/space.js +0 -618
- package/dist/space.js.map +0 -1
- package/dist/subscription.d.ts +0 -36
- package/dist/subscription.d.ts.map +0 -1
- package/dist/subscription.js +0 -419
- package/dist/subscription.js.map +0 -1
- package/dist/webdav.d.ts +0 -171
- package/dist/webdav.d.ts.map +0 -1
- package/dist/webdav.js +0 -481
- package/dist/webdav.js.map +0 -1
package/dist/auth-browser.js
CHANGED
|
@@ -1,105 +1,73 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
// =============================================================================
|
|
7
|
-
import { BaseTokenAuthProvider } from './auth-base.js';
|
|
8
|
-
export class BrowserAuthProvider extends BaseTokenAuthProvider {
|
|
9
|
-
/**
|
|
10
|
-
* Initialize auth manager - should be called on app startup.
|
|
11
|
-
* Processes any auth callback in the URL and sets up auto-refresh.
|
|
12
|
-
*/
|
|
13
|
-
initialize() {
|
|
14
|
-
const wasCallback = this.processCallback();
|
|
15
|
-
this.initBase();
|
|
16
|
-
return wasCallback;
|
|
1
|
+
import { TokenAuth } from "./auth-base.js";
|
|
2
|
+
export class BrowserAuth extends TokenAuth {
|
|
3
|
+
async initialize() {
|
|
4
|
+
this.processCallback();
|
|
5
|
+
return this.isAuthenticated();
|
|
17
6
|
}
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
* @param appName - The name of the application requesting login (displayed on auth page)
|
|
21
|
-
*/
|
|
22
|
-
login(appName, params) {
|
|
23
|
-
this.redirectToAuth('login', appName, params);
|
|
7
|
+
async login(appName, params) {
|
|
8
|
+
this.redirectToAuth("login", appName, params);
|
|
24
9
|
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
* @param appName - The name of the application requesting signup (displayed on auth page)
|
|
28
|
-
*/
|
|
29
|
-
signup(appName, params) {
|
|
30
|
-
this.redirectToAuth('signup', appName, params);
|
|
10
|
+
async signup(appName, params) {
|
|
11
|
+
this.redirectToAuth("signup", appName, params);
|
|
31
12
|
}
|
|
32
|
-
/**
|
|
33
|
-
* Process auth callback from URL fragment.
|
|
34
|
-
* Should be called on page load.
|
|
35
|
-
* @returns true if callback was processed
|
|
36
|
-
*/
|
|
37
13
|
processCallback() {
|
|
38
|
-
const hash = window.location.hash
|
|
39
|
-
|
|
40
|
-
|
|
14
|
+
const hash = window.location.hash.startsWith("#")
|
|
15
|
+
? window.location.hash.slice(1)
|
|
16
|
+
: window.location.hash;
|
|
17
|
+
if (!hash)
|
|
41
18
|
return false;
|
|
42
|
-
const params = new URLSearchParams(
|
|
43
|
-
const idToken = params.get(
|
|
19
|
+
const params = new URLSearchParams(hash);
|
|
20
|
+
const idToken = params.get("id_token");
|
|
44
21
|
if (!idToken)
|
|
45
22
|
return false;
|
|
46
|
-
const
|
|
47
|
-
const roolToken = params.get('rool_token');
|
|
48
|
-
const expiresIn = params.get('expires_in');
|
|
49
|
-
const expiresAt = expiresIn ? Date.now() + Number(expiresIn) * 1000 : NaN;
|
|
50
|
-
const incomingState = params.get('state');
|
|
23
|
+
const incomingState = params.get("state");
|
|
51
24
|
const storedState = this.readState();
|
|
52
|
-
// Validate state — only enforce when both sides have one (SDK-initiated
|
|
53
|
-
// flow). When the auth page is opened directly (e.g., link from the
|
|
54
|
-
// website), there's no incoming state and nothing to validate against.
|
|
55
25
|
if (storedState && incomingState && incomingState !== storedState) {
|
|
56
|
-
|
|
26
|
+
console.error("[RoolAuth] Browser auth state mismatch");
|
|
57
27
|
return false;
|
|
58
28
|
}
|
|
59
|
-
|
|
60
|
-
|
|
29
|
+
const accepted = this.acceptTokenResponse({
|
|
30
|
+
id_token: idToken,
|
|
31
|
+
refresh_token: params.get("refresh_token"),
|
|
32
|
+
rool_token: params.get("rool_token"),
|
|
33
|
+
expires_in: params.get("expires_in"),
|
|
34
|
+
});
|
|
35
|
+
if (!accepted)
|
|
61
36
|
return false;
|
|
62
|
-
}
|
|
63
|
-
// Clear state and store tokens
|
|
64
37
|
this.clearState();
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
38
|
+
const cleanUrl = window.location.origin +
|
|
39
|
+
window.location.pathname +
|
|
40
|
+
window.location.search;
|
|
68
41
|
window.history.replaceState({}, document.title, cleanUrl);
|
|
69
|
-
this.
|
|
42
|
+
this.emitAuthState(true);
|
|
70
43
|
return true;
|
|
71
44
|
}
|
|
72
|
-
// ===========================================================================
|
|
73
|
-
// Private
|
|
74
|
-
// ===========================================================================
|
|
75
45
|
redirectToAuth(flow, appName, params) {
|
|
76
|
-
const
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
url.searchParams.set(
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
url.searchParams.set(key, value);
|
|
84
|
-
}
|
|
46
|
+
const url = new URL(`/${flow}`, new URL(this.authBaseUrl).origin);
|
|
47
|
+
url.searchParams.set("redirect_uri", window.location.origin +
|
|
48
|
+
window.location.pathname +
|
|
49
|
+
window.location.search);
|
|
50
|
+
url.searchParams.set("app_name", appName);
|
|
51
|
+
for (const [name, value] of Object.entries(params ?? {})) {
|
|
52
|
+
url.searchParams.set(name, value);
|
|
85
53
|
}
|
|
86
|
-
const state =
|
|
54
|
+
const state = randomState();
|
|
87
55
|
this.storeState(state);
|
|
88
|
-
url.searchParams.set(
|
|
56
|
+
url.searchParams.set("state", state);
|
|
89
57
|
window.location.href = url.toString();
|
|
90
58
|
}
|
|
91
59
|
clearTransientState() {
|
|
92
60
|
this.clearState();
|
|
93
61
|
}
|
|
94
62
|
get stateKey() {
|
|
95
|
-
return this.keyFor(
|
|
63
|
+
return this.keyFor("auth_state");
|
|
96
64
|
}
|
|
97
65
|
storeState(value) {
|
|
98
66
|
try {
|
|
99
67
|
sessionStorage.setItem(this.stateKey, value);
|
|
100
68
|
}
|
|
101
69
|
catch {
|
|
102
|
-
//
|
|
70
|
+
// Storage can be unavailable in restricted browser contexts.
|
|
103
71
|
}
|
|
104
72
|
}
|
|
105
73
|
readState() {
|
|
@@ -115,18 +83,13 @@ export class BrowserAuthProvider extends BaseTokenAuthProvider {
|
|
|
115
83
|
sessionStorage.removeItem(this.stateKey);
|
|
116
84
|
}
|
|
117
85
|
catch {
|
|
118
|
-
//
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
generateState() {
|
|
122
|
-
try {
|
|
123
|
-
const buffer = new Uint8Array(16);
|
|
124
|
-
window.crypto.getRandomValues(buffer);
|
|
125
|
-
return Array.from(buffer, (value) => value.toString(16).padStart(2, '0')).join('');
|
|
126
|
-
}
|
|
127
|
-
catch {
|
|
128
|
-
return Math.random().toString(36).slice(2) + Math.random().toString(36).slice(2);
|
|
86
|
+
// Storage can be unavailable in restricted browser contexts.
|
|
129
87
|
}
|
|
130
88
|
}
|
|
131
89
|
}
|
|
90
|
+
function randomState() {
|
|
91
|
+
const bytes = new Uint8Array(16);
|
|
92
|
+
crypto.getRandomValues(bytes);
|
|
93
|
+
return Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
94
|
+
}
|
|
132
95
|
//# sourceMappingURL=auth-browser.js.map
|
package/dist/auth-browser.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth-browser.js","sourceRoot":"","sources":["../src/auth-browser.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"auth-browser.js","sourceRoot":"","sources":["../src/auth-browser.ts"],"names":[],"mappings":"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"}
|
package/dist/auth-native.d.ts
CHANGED
|
@@ -1,72 +1,25 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import type { PasswordSignInResult } from
|
|
3
|
-
export type
|
|
4
|
-
export interface
|
|
5
|
-
/**
|
|
6
|
-
* Deep-link redirect URI registered by the app. Must match the auth
|
|
7
|
-
* server's native-client allowlist exactly, e.g.
|
|
8
|
-
* 'roolandroidauth://auth/callback' or 'rooliosauth://auth/callback'.
|
|
9
|
-
*/
|
|
1
|
+
import { TokenAuth, type TokenAuthConfig } from "./auth-base.js";
|
|
2
|
+
import type { PasswordSignInResult } from "./types.js";
|
|
3
|
+
export type NativeAuthProvider = "google" | "apple";
|
|
4
|
+
export interface NativeAuthConfig extends TokenAuthConfig {
|
|
10
5
|
redirectUri: string;
|
|
11
|
-
|
|
12
|
-
defaultProvider?: NativeAuthFlowProvider;
|
|
13
|
-
/**
|
|
14
|
-
* Open a URL in an external system browser (NOT the app webview), e.g.
|
|
15
|
-
* Capacitor's `Browser.open({ url })`. PKCE requires the authorization
|
|
16
|
-
* step to happen outside the app so the app never sees provider secrets.
|
|
17
|
-
*/
|
|
6
|
+
defaultProvider?: NativeAuthProvider;
|
|
18
7
|
openExternal: (url: string) => void | Promise<void>;
|
|
19
8
|
}
|
|
20
|
-
export declare class
|
|
9
|
+
export declare class NativeAuth extends TokenAuth {
|
|
21
10
|
private readonly redirectUri;
|
|
22
11
|
private readonly defaultProvider;
|
|
23
12
|
private readonly openExternal;
|
|
24
|
-
constructor(config:
|
|
25
|
-
|
|
26
|
-
* No synchronous callback to process — the app drives completion via
|
|
27
|
-
* handleRedirect(). Just arm refresh for any persisted session.
|
|
28
|
-
*/
|
|
29
|
-
initialize(): boolean;
|
|
30
|
-
/**
|
|
31
|
-
* Begin sign-in. `params.provider` ('google' | 'apple') overrides the
|
|
32
|
-
* default; `params.rvid` is forwarded for signup attribution.
|
|
33
|
-
*/
|
|
13
|
+
constructor(config: NativeAuthConfig);
|
|
14
|
+
initialize(): Promise<boolean>;
|
|
34
15
|
login(_appName: string, params?: Record<string, string>): Promise<void>;
|
|
35
|
-
/**
|
|
36
|
-
* Same flow as login — the providers don't distinguish signup from login
|
|
37
|
-
* for native, and the auth server creates the account on first sign-in.
|
|
38
|
-
*/
|
|
39
16
|
signup(_appName: string, params?: Record<string, string>): Promise<void>;
|
|
40
|
-
/**
|
|
41
|
-
* Complete a sign-in from the deep link the app received (e.g. Capacitor's
|
|
42
|
-
* appUrlOpen). Validates state, exchanges the code + stored verifier at
|
|
43
|
-
* /token, and persists the session. Returns true once signed in.
|
|
44
|
-
*/
|
|
45
17
|
handleRedirect(url: string): Promise<boolean>;
|
|
46
|
-
/**
|
|
47
|
-
* Sign in with email + password. No redirect involved — the auth server
|
|
48
|
-
* returns the token set as JSON, which we persist directly.
|
|
49
|
-
*
|
|
50
|
-
* Resolves `signed_in` on success, or `verify_required` when the account's
|
|
51
|
-
* email isn't verified (the server has emailed a magic link). Rejects with
|
|
52
|
-
* a human-readable Error on bad credentials or server failure.
|
|
53
|
-
*/
|
|
54
18
|
signInWithPassword(email: string, password: string): Promise<PasswordSignInResult>;
|
|
55
|
-
/**
|
|
56
|
-
* Request a magic sign-in link by email. The server emails a link carrying
|
|
57
|
-
* a verify token; the user completes sign-in by following it, which lands
|
|
58
|
-
* back in the app and is finished via `verify(token)`. Resolves once the
|
|
59
|
-
* email is accepted; rejects with a human-readable Error if the address is
|
|
60
|
-
* rejected (invalid / disposable / unreachable).
|
|
61
|
-
*
|
|
62
|
-
* NOTE: the emailed link is an https URL (`<appsDomain>/?verify=…`), so on
|
|
63
|
-
* native it only re-opens the app if Universal Links / App Links are set up
|
|
64
|
-
* for that domain. Without them the link completes on the website instead.
|
|
65
|
-
*/
|
|
66
19
|
requestMagicLink(email: string): Promise<void>;
|
|
20
|
+
protected clearTransientState(): void;
|
|
67
21
|
private get verifierKey();
|
|
68
22
|
private get stateKey();
|
|
69
23
|
private startPkce;
|
|
70
|
-
protected clearTransientState(): void;
|
|
71
24
|
}
|
|
72
25
|
//# sourceMappingURL=auth-native.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth-native.d.ts","sourceRoot":"","sources":["../src/auth-native.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"auth-native.d.ts","sourceRoot":"","sources":["../src/auth-native.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,SAAS,EAET,KAAK,eAAe,EACrB,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAEvD,MAAM,MAAM,kBAAkB,GAAG,QAAQ,GAAG,OAAO,CAAC;AAEpD,MAAM,WAAW,gBAAiB,SAAQ,eAAe;IACvD,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,kBAAkB,CAAC;IACrC,YAAY,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACrD;AAED,qBAAa,UAAW,SAAQ,SAAS;IACvC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAqB;IACrD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAwC;gBAEzD,MAAM,EAAE,gBAAgB;IAO9B,UAAU,IAAI,OAAO,CAAC,OAAO,CAAC;IAI9B,KAAK,CACT,QAAQ,EAAE,MAAM,EAChB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC9B,OAAO,CAAC,IAAI,CAAC;IAIV,MAAM,CACV,QAAQ,EAAE,MAAM,EAChB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC9B,OAAO,CAAC,IAAI,CAAC;IAIV,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAgD7C,kBAAkB,CACtB,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,oBAAoB,CAAC;IAmC1B,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAqBpD,SAAS,CAAC,mBAAmB,IAAI,IAAI;IAKrC,OAAO,KAAK,WAAW,GAEtB;IAED,OAAO,KAAK,QAAQ,GAEnB;YAEa,SAAS;CAyBxB"}
|
package/dist/auth-native.js
CHANGED
|
@@ -1,52 +1,23 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
// For app shells that run JavaScript but sign in through an external system
|
|
4
|
-
// browser (Capacitor, Cordova, Tauri, ...). The app hands off to the auth
|
|
5
|
-
// server's /authorize in an external browser, then feeds the deep-link callback
|
|
6
|
-
// back into handleRedirect(), which exchanges the code + verifier at /token.
|
|
7
|
-
//
|
|
8
|
-
// The SDK stays platform-agnostic: the app injects how to open an external URL
|
|
9
|
-
// (openExternal) and calls handleRedirect() from its own deep-link listener.
|
|
10
|
-
// Token storage and refresh are inherited from BaseTokenAuthProvider.
|
|
11
|
-
// =============================================================================
|
|
12
|
-
import { BaseTokenAuthProvider } from './auth-base.js';
|
|
13
|
-
export class NativePkceAuthProvider extends BaseTokenAuthProvider {
|
|
1
|
+
import { TokenAuth, } from "./auth-base.js";
|
|
2
|
+
export class NativeAuth extends TokenAuth {
|
|
14
3
|
redirectUri;
|
|
15
4
|
defaultProvider;
|
|
16
5
|
openExternal;
|
|
17
6
|
constructor(config) {
|
|
18
|
-
super();
|
|
7
|
+
super(config);
|
|
19
8
|
this.redirectUri = config.redirectUri;
|
|
20
|
-
this.defaultProvider = config.defaultProvider ??
|
|
9
|
+
this.defaultProvider = config.defaultProvider ?? "google";
|
|
21
10
|
this.openExternal = config.openExternal;
|
|
22
11
|
}
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
* handleRedirect(). Just arm refresh for any persisted session.
|
|
26
|
-
*/
|
|
27
|
-
initialize() {
|
|
28
|
-
this.initBase();
|
|
29
|
-
return false;
|
|
12
|
+
async initialize() {
|
|
13
|
+
return this.isAuthenticated();
|
|
30
14
|
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
* default; `params.rvid` is forwarded for signup attribution.
|
|
34
|
-
*/
|
|
35
|
-
login(_appName, params) {
|
|
36
|
-
return this.startPkce(params);
|
|
15
|
+
async login(_appName, params) {
|
|
16
|
+
await this.startPkce(params);
|
|
37
17
|
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
* for native, and the auth server creates the account on first sign-in.
|
|
41
|
-
*/
|
|
42
|
-
signup(_appName, params) {
|
|
43
|
-
return this.startPkce(params);
|
|
18
|
+
async signup(_appName, params) {
|
|
19
|
+
await this.startPkce(params);
|
|
44
20
|
}
|
|
45
|
-
/**
|
|
46
|
-
* Complete a sign-in from the deep link the app received (e.g. Capacitor's
|
|
47
|
-
* appUrlOpen). Validates state, exchanges the code + stored verifier at
|
|
48
|
-
* /token, and persists the session. Returns true once signed in.
|
|
49
|
-
*/
|
|
50
21
|
async handleRedirect(url) {
|
|
51
22
|
if (!url.startsWith(this.redirectUri))
|
|
52
23
|
return false;
|
|
@@ -57,204 +28,144 @@ export class NativePkceAuthProvider extends BaseTokenAuthProvider {
|
|
|
57
28
|
catch {
|
|
58
29
|
return false;
|
|
59
30
|
}
|
|
60
|
-
const error = parsed.searchParams.get(
|
|
31
|
+
const error = parsed.searchParams.get("error");
|
|
61
32
|
if (error) {
|
|
62
|
-
|
|
33
|
+
console.warn(`[RoolAuth] Native auth error: ${error}`);
|
|
63
34
|
this.clearTransientState();
|
|
64
35
|
return false;
|
|
65
36
|
}
|
|
66
|
-
const code = parsed.searchParams.get(
|
|
67
|
-
const incomingState = parsed.searchParams.get(
|
|
68
|
-
if (!code)
|
|
69
|
-
return false;
|
|
37
|
+
const code = parsed.searchParams.get("code");
|
|
38
|
+
const incomingState = parsed.searchParams.get("state");
|
|
70
39
|
const verifier = this.readString(this.verifierKey);
|
|
71
40
|
const storedState = this.readString(this.stateKey);
|
|
72
|
-
if (!verifier)
|
|
73
|
-
this.logger.error('[RoolClient] No PKCE verifier for redirect. Ignored.');
|
|
41
|
+
if (!code || !verifier)
|
|
74
42
|
return false;
|
|
75
|
-
}
|
|
76
43
|
if (storedState && incomingState !== storedState) {
|
|
77
|
-
this.logger.error('[RoolClient] Native auth state mismatch. Ignored.');
|
|
78
44
|
this.clearTransientState();
|
|
79
45
|
return false;
|
|
80
46
|
}
|
|
81
47
|
let response;
|
|
82
48
|
try {
|
|
83
|
-
response = await
|
|
84
|
-
method:
|
|
85
|
-
headers: {
|
|
49
|
+
response = await this.fetchAuth("/token", {
|
|
50
|
+
method: "POST",
|
|
51
|
+
headers: { "Content-Type": "application/json" },
|
|
86
52
|
body: JSON.stringify({ code, code_verifier: verifier }),
|
|
87
53
|
});
|
|
88
54
|
}
|
|
89
|
-
catch (
|
|
90
|
-
|
|
91
|
-
this.logger.error('[RoolClient] /token network error:', err);
|
|
55
|
+
catch (error) {
|
|
56
|
+
console.error("[RoolAuth] Native token exchange failed:", error);
|
|
92
57
|
return false;
|
|
93
58
|
}
|
|
94
|
-
// The code is single-use and the verifier is now spent either way.
|
|
95
59
|
this.clearTransientState();
|
|
96
|
-
if (!response.ok)
|
|
97
|
-
this.logger.warn(`[RoolClient] /token failed: ${response.status}`);
|
|
60
|
+
if (!response.ok)
|
|
98
61
|
return false;
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
try {
|
|
102
|
-
data = await response.json();
|
|
103
|
-
}
|
|
104
|
-
catch (err) {
|
|
105
|
-
this.logger.error('[RoolClient] /token response parse error:', err);
|
|
106
|
-
return false;
|
|
107
|
-
}
|
|
108
|
-
const idToken = data.id_token ?? null;
|
|
109
|
-
const refreshToken = data.refresh_token ?? null;
|
|
110
|
-
const expiresAt = data.expires_in ? Date.now() + data.expires_in * 1000 : NaN;
|
|
111
|
-
if (!idToken || !Number.isFinite(expiresAt)) {
|
|
112
|
-
this.logger.error('[RoolClient] /token response missing id_token or expires_in');
|
|
62
|
+
const data = await readJson(response);
|
|
63
|
+
if (!data || !this.acceptTokenResponse(data))
|
|
113
64
|
return false;
|
|
114
|
-
|
|
115
|
-
this.acceptTokens(idToken, refreshToken, data.rool_token ?? null, expiresAt);
|
|
116
|
-
this.notifyAuthState(true);
|
|
65
|
+
this.emitAuthState(true);
|
|
117
66
|
return true;
|
|
118
67
|
}
|
|
119
|
-
/**
|
|
120
|
-
* Sign in with email + password. No redirect involved — the auth server
|
|
121
|
-
* returns the token set as JSON, which we persist directly.
|
|
122
|
-
*
|
|
123
|
-
* Resolves `signed_in` on success, or `verify_required` when the account's
|
|
124
|
-
* email isn't verified (the server has emailed a magic link). Rejects with
|
|
125
|
-
* a human-readable Error on bad credentials or server failure.
|
|
126
|
-
*/
|
|
127
68
|
async signInWithPassword(email, password) {
|
|
128
69
|
let response;
|
|
129
70
|
try {
|
|
130
|
-
response = await
|
|
131
|
-
method:
|
|
132
|
-
headers: {
|
|
71
|
+
response = await this.fetchAuth("/login-password", {
|
|
72
|
+
method: "POST",
|
|
73
|
+
headers: { "Content-Type": "application/json" },
|
|
133
74
|
body: JSON.stringify({ email, password }),
|
|
134
75
|
});
|
|
135
76
|
}
|
|
136
|
-
catch (
|
|
137
|
-
|
|
138
|
-
throw new Error(
|
|
139
|
-
}
|
|
140
|
-
let data;
|
|
141
|
-
try {
|
|
142
|
-
data = await response.json();
|
|
143
|
-
}
|
|
144
|
-
catch {
|
|
145
|
-
throw new Error('Unexpected response. Please try again.');
|
|
77
|
+
catch (error) {
|
|
78
|
+
console.error("[RoolAuth] Password sign-in failed:", error);
|
|
79
|
+
throw new Error("Network error. Please try again.");
|
|
146
80
|
}
|
|
81
|
+
const data = await readJson(response);
|
|
82
|
+
if (!data)
|
|
83
|
+
throw new Error("Unexpected response. Please try again.");
|
|
147
84
|
if (!response.ok || data.ok === false) {
|
|
148
|
-
throw new Error(data.error ||
|
|
85
|
+
throw new Error(data.error || "Invalid email or password.");
|
|
149
86
|
}
|
|
150
|
-
if (data.status ===
|
|
151
|
-
return { status:
|
|
87
|
+
if (data.status === "verify_required") {
|
|
88
|
+
return { status: "verify_required" };
|
|
152
89
|
}
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
const expiresAt = data.expires_in ? Date.now() + data.expires_in * 1000 : NaN;
|
|
156
|
-
if (!idToken || !Number.isFinite(expiresAt)) {
|
|
157
|
-
this.logger.error('[RoolClient] login-password response missing id_token or expires_in');
|
|
158
|
-
throw new Error('Sign-in failed. Please try again.');
|
|
90
|
+
if (!this.acceptTokenResponse(data)) {
|
|
91
|
+
throw new Error("Sign-in failed. Please try again.");
|
|
159
92
|
}
|
|
160
|
-
this.
|
|
161
|
-
|
|
162
|
-
return { status: 'signed_in' };
|
|
93
|
+
this.emitAuthState(true);
|
|
94
|
+
return { status: "signed_in" };
|
|
163
95
|
}
|
|
164
|
-
/**
|
|
165
|
-
* Request a magic sign-in link by email. The server emails a link carrying
|
|
166
|
-
* a verify token; the user completes sign-in by following it, which lands
|
|
167
|
-
* back in the app and is finished via `verify(token)`. Resolves once the
|
|
168
|
-
* email is accepted; rejects with a human-readable Error if the address is
|
|
169
|
-
* rejected (invalid / disposable / unreachable).
|
|
170
|
-
*
|
|
171
|
-
* NOTE: the emailed link is an https URL (`<appsDomain>/?verify=…`), so on
|
|
172
|
-
* native it only re-opens the app if Universal Links / App Links are set up
|
|
173
|
-
* for that domain. Without them the link completes on the website instead.
|
|
174
|
-
*/
|
|
175
96
|
async requestMagicLink(email) {
|
|
176
97
|
let response;
|
|
177
98
|
try {
|
|
178
|
-
response = await
|
|
179
|
-
method:
|
|
180
|
-
headers: {
|
|
99
|
+
response = await this.fetchAuth("/magic-link", {
|
|
100
|
+
method: "POST",
|
|
101
|
+
headers: { "Content-Type": "application/json" },
|
|
181
102
|
body: JSON.stringify({ email }),
|
|
182
103
|
});
|
|
183
104
|
}
|
|
184
|
-
catch (
|
|
185
|
-
|
|
186
|
-
throw new Error(
|
|
187
|
-
}
|
|
188
|
-
let data;
|
|
189
|
-
try {
|
|
190
|
-
data = await response.json();
|
|
191
|
-
}
|
|
192
|
-
catch {
|
|
193
|
-
data = {};
|
|
105
|
+
catch (error) {
|
|
106
|
+
console.error("[RoolAuth] Magic-link request failed:", error);
|
|
107
|
+
throw new Error("Network error. Please try again.");
|
|
194
108
|
}
|
|
195
|
-
|
|
196
|
-
|
|
109
|
+
const data = await readJson(response);
|
|
110
|
+
if (!response.ok || data?.ok === false) {
|
|
111
|
+
throw new Error(data?.error || "Could not send the sign-in link. Please try again.");
|
|
197
112
|
}
|
|
198
113
|
}
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
114
|
+
clearTransientState() {
|
|
115
|
+
this.removeString(this.verifierKey);
|
|
116
|
+
this.removeString(this.stateKey);
|
|
117
|
+
}
|
|
202
118
|
get verifierKey() {
|
|
203
|
-
return this.keyFor(
|
|
119
|
+
return this.keyFor("pkce_verifier");
|
|
204
120
|
}
|
|
205
121
|
get stateKey() {
|
|
206
|
-
return this.keyFor(
|
|
122
|
+
return this.keyFor("pkce_state");
|
|
207
123
|
}
|
|
208
124
|
async startPkce(params) {
|
|
209
|
-
const
|
|
210
|
-
const
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
125
|
+
const requestedProvider = params?.provider;
|
|
126
|
+
const provider = isProvider(requestedProvider)
|
|
127
|
+
? requestedProvider
|
|
128
|
+
: this.defaultProvider;
|
|
129
|
+
const verifier = base64Url(randomBytes(32));
|
|
130
|
+
const challenge = base64Url(await crypto.subtle.digest("SHA-256", new TextEncoder().encode(verifier)));
|
|
131
|
+
const state = Array.from(randomBytes(16), (byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
216
132
|
this.writeString(this.verifierKey, verifier);
|
|
217
133
|
this.writeString(this.stateKey, state);
|
|
218
134
|
const url = new URL(`${this.authBaseUrl}/authorize`);
|
|
219
|
-
url.searchParams.set(
|
|
220
|
-
url.searchParams.set(
|
|
221
|
-
url.searchParams.set(
|
|
222
|
-
url.searchParams.set(
|
|
223
|
-
url.searchParams.set(
|
|
135
|
+
url.searchParams.set("provider", provider);
|
|
136
|
+
url.searchParams.set("redirect_uri", this.redirectUri);
|
|
137
|
+
url.searchParams.set("state", state);
|
|
138
|
+
url.searchParams.set("code_challenge", challenge);
|
|
139
|
+
url.searchParams.set("code_challenge_method", "S256");
|
|
224
140
|
if (params?.rvid)
|
|
225
|
-
url.searchParams.set(
|
|
141
|
+
url.searchParams.set("rvid", params.rvid);
|
|
226
142
|
await this.openExternal(url.toString());
|
|
227
143
|
}
|
|
228
|
-
clearTransientState() {
|
|
229
|
-
this.removeString(this.verifierKey);
|
|
230
|
-
this.removeString(this.stateKey);
|
|
231
|
-
}
|
|
232
144
|
}
|
|
233
|
-
function
|
|
234
|
-
return value ===
|
|
145
|
+
function isProvider(value) {
|
|
146
|
+
return value === "google" || value === "apple";
|
|
235
147
|
}
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
const bytes = new Uint8Array(32);
|
|
148
|
+
function randomBytes(length) {
|
|
149
|
+
const bytes = new Uint8Array(length);
|
|
239
150
|
crypto.getRandomValues(bytes);
|
|
240
|
-
return
|
|
151
|
+
return bytes;
|
|
241
152
|
}
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
153
|
+
function base64Url(buffer) {
|
|
154
|
+
const bytes = buffer instanceof Uint8Array ? buffer : new Uint8Array(buffer);
|
|
155
|
+
let binary = "";
|
|
156
|
+
for (const byte of bytes)
|
|
157
|
+
binary += String.fromCharCode(byte);
|
|
158
|
+
return btoa(binary)
|
|
159
|
+
.replace(/\+/g, "-")
|
|
160
|
+
.replace(/\//g, "_")
|
|
161
|
+
.replace(/=+$/, "");
|
|
246
162
|
}
|
|
247
|
-
function
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
const bytes = new Uint8Array(buffer);
|
|
254
|
-
let binary = '';
|
|
255
|
-
for (let i = 0; i < bytes.length; i++) {
|
|
256
|
-
binary += String.fromCharCode(bytes[i]);
|
|
163
|
+
async function readJson(response) {
|
|
164
|
+
try {
|
|
165
|
+
return (await response.json());
|
|
166
|
+
}
|
|
167
|
+
catch {
|
|
168
|
+
return null;
|
|
257
169
|
}
|
|
258
|
-
return btoa(binary).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
|
|
259
170
|
}
|
|
260
171
|
//# sourceMappingURL=auth-native.js.map
|