@ankhorage/studio 0.11.8 → 0.11.9
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/dist/host/layout/templates/auth/callback.d.ts.map +1 -1
- package/dist/host/layout/templates/auth/callback.js +30 -11
- package/dist/host/layout/templates/auth/callback.js.map +1 -1
- package/dist/host/layout/templates/auth/oauth.d.ts.map +1 -1
- package/dist/host/layout/templates/auth/oauth.js +63 -8
- package/dist/host/layout/templates/auth/oauth.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"callback.d.ts","sourceRoot":"","sources":["../../../../../src/host/layout/templates/auth/callback.ts"],"names":[],"mappings":"AAGA,wBAAgB,uBAAuB,CAAC,IAAI,EAAE;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,eAAe,EAAE,MAAM,CAAA;CAAE,
|
|
1
|
+
{"version":3,"file":"callback.d.ts","sourceRoot":"","sources":["../../../../../src/host/layout/templates/auth/callback.ts"],"names":[],"mappings":"AAGA,wBAAgB,uBAAuB,CAAC,IAAI,EAAE;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,eAAe,EAAE,MAAM,CAAA;CAAE,UAkI7F"}
|
|
@@ -5,38 +5,57 @@ export function getAuthOAuthCallbackTsx(args) {
|
|
|
5
5
|
const postSignInTarget = escapeStringLiteral(routeNameToGroupedHref(args.postSignInRoute, 'app'));
|
|
6
6
|
return `import * as Linking from 'expo-linking';
|
|
7
7
|
import { Stack, useRouter } from 'expo-router';
|
|
8
|
-
import * as WebBrowser from 'expo-web-browser';
|
|
9
8
|
import { useEffect, useRef, useState } from 'react';
|
|
10
|
-
import { ActivityIndicator,
|
|
9
|
+
import { ActivityIndicator, Pressable, StyleSheet, View } from 'react-native';
|
|
11
10
|
import { Text, useZoraTheme } from '@ankhorage/zora';
|
|
12
11
|
|
|
13
12
|
import { completeOAuthCallback } from '@/auth/oauth';
|
|
14
13
|
|
|
15
14
|
const SIGN_IN_ROUTE = '${signInTarget}';
|
|
16
15
|
const POST_SIGN_IN_ROUTE = '${postSignInTarget}';
|
|
17
|
-
const webBrowserCompletion =
|
|
18
|
-
Platform.OS === 'web' ? WebBrowser.maybeCompleteAuthSession() : null;
|
|
19
16
|
const callbackScreenOptions = { title: 'Completing sign in' };
|
|
20
17
|
|
|
18
|
+
interface ActiveCallbackCompletion {
|
|
19
|
+
callbackUrl: string;
|
|
20
|
+
promise: ReturnType<typeof completeOAuthCallback>;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
let activeCallbackCompletion: ActiveCallbackCompletion | null = null;
|
|
24
|
+
|
|
25
|
+
function completeOAuthCallbackOnce(callbackUrl: string) {
|
|
26
|
+
if (!activeCallbackCompletion || activeCallbackCompletion.callbackUrl !== callbackUrl) {
|
|
27
|
+
activeCallbackCompletion = {
|
|
28
|
+
callbackUrl,
|
|
29
|
+
promise: completeOAuthCallback(callbackUrl),
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
return activeCallbackCompletion.promise;
|
|
33
|
+
}
|
|
34
|
+
|
|
21
35
|
export default function OAuthCallbackScreen() {
|
|
22
36
|
const router = useRouter();
|
|
23
37
|
const callbackUrl = Linking.useURL();
|
|
24
38
|
const { theme } = useZoraTheme();
|
|
25
|
-
const
|
|
39
|
+
const handledOutcomeRef = useRef(false);
|
|
26
40
|
const [message, setMessage] = useState('Completing secure sign in…');
|
|
27
41
|
const [failed, setFailed] = useState(false);
|
|
28
42
|
|
|
29
43
|
useEffect(() => {
|
|
30
|
-
if (webBrowserCompletion?.type === 'success' || handledRef.current) return;
|
|
31
|
-
|
|
32
44
|
let active = true;
|
|
33
45
|
void (async () => {
|
|
34
46
|
const deliveredUrl = callbackUrl ?? (await Linking.getInitialURL());
|
|
35
|
-
if (!deliveredUrl
|
|
36
|
-
|
|
47
|
+
if (!deliveredUrl) {
|
|
48
|
+
if (active && !handledOutcomeRef.current) {
|
|
49
|
+
handledOutcomeRef.current = true;
|
|
50
|
+
setFailed(true);
|
|
51
|
+
setMessage('The OAuth callback URL is unavailable.');
|
|
52
|
+
}
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
37
55
|
|
|
38
|
-
const outcome = await
|
|
39
|
-
if (!active) return;
|
|
56
|
+
const outcome = await completeOAuthCallbackOnce(deliveredUrl);
|
|
57
|
+
if (!active || handledOutcomeRef.current) return;
|
|
58
|
+
handledOutcomeRef.current = true;
|
|
40
59
|
|
|
41
60
|
if (outcome.status === 'authenticated') {
|
|
42
61
|
router.replace(POST_SIGN_IN_ROUTE);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"callback.js","sourceRoot":"","sources":["../../../../../src/host/layout/templates/auth/callback.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AACtE,OAAO,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AAEzD,MAAM,UAAU,uBAAuB,CAAC,IAAsD;IAC5F,MAAM,YAAY,GAAG,mBAAmB,CAAC,sBAAsB,CAAC,IAAI,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC,CAAC;IAC3F,MAAM,gBAAgB,GAAG,mBAAmB,CAAC,sBAAsB,CAAC,IAAI,CAAC,eAAe,EAAE,KAAK,CAAC,CAAC,CAAC;IAElG,OAAO
|
|
1
|
+
{"version":3,"file":"callback.js","sourceRoot":"","sources":["../../../../../src/host/layout/templates/auth/callback.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AACtE,OAAO,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AAEzD,MAAM,UAAU,uBAAuB,CAAC,IAAsD;IAC5F,MAAM,YAAY,GAAG,mBAAmB,CAAC,sBAAsB,CAAC,IAAI,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC,CAAC;IAC3F,MAAM,gBAAgB,GAAG,mBAAmB,CAAC,sBAAsB,CAAC,IAAI,CAAC,eAAe,EAAE,KAAK,CAAC,CAAC,CAAC;IAElG,OAAO;;;;;;;;yBAQgB,YAAY;8BACP,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAoH7C,CAAC;AACF,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"oauth.d.ts","sourceRoot":"","sources":["../../../../../src/host/layout/templates/auth/oauth.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AAG5E,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,mBAAmB,
|
|
1
|
+
{"version":3,"file":"oauth.d.ts","sourceRoot":"","sources":["../../../../../src/host/layout/templates/auth/oauth.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AAG5E,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,mBAAmB,UAoU9D"}
|
|
@@ -70,7 +70,17 @@ async function runOAuthAuthorization(
|
|
|
70
70
|
};
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
-
|
|
73
|
+
let redirectUri: string;
|
|
74
|
+
try {
|
|
75
|
+
redirectUri = resolveOAuthRedirectUri();
|
|
76
|
+
} catch {
|
|
77
|
+
return {
|
|
78
|
+
status: 'error',
|
|
79
|
+
message: 'The OAuth redirect URI could not be resolved in this environment.',
|
|
80
|
+
recoverable: true,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
|
|
74
84
|
const started = await oauth.startAuthorization({
|
|
75
85
|
provider: provider.id,
|
|
76
86
|
redirectUri,
|
|
@@ -101,6 +111,13 @@ async function runOAuthAuthorization(
|
|
|
101
111
|
};
|
|
102
112
|
}
|
|
103
113
|
|
|
114
|
+
if (Platform.OS === 'web') {
|
|
115
|
+
return redirectWebAuthorization({
|
|
116
|
+
attemptId: started.data.attemptId,
|
|
117
|
+
authorizationUrl: started.data.authorizationUrl,
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
|
|
104
121
|
let browserResult: WebBrowser.WebBrowserAuthSessionResult;
|
|
105
122
|
try {
|
|
106
123
|
browserResult = await WebBrowser.openAuthSessionAsync(
|
|
@@ -131,6 +148,42 @@ async function runOAuthAuthorization(
|
|
|
131
148
|
return toTransportOutcome(completed);
|
|
132
149
|
}
|
|
133
150
|
|
|
151
|
+
async function redirectWebAuthorization(args: {
|
|
152
|
+
attemptId: string;
|
|
153
|
+
authorizationUrl: string;
|
|
154
|
+
}): Promise<GeneratedOAuthTransportOutcome> {
|
|
155
|
+
const location = getBrowserLocation();
|
|
156
|
+
const assign = location ? Reflect.get(location, 'assign') : undefined;
|
|
157
|
+
if (typeof assign !== 'function') {
|
|
158
|
+
await cancelOAuthAttempt(args.attemptId, 'browser_dismissed');
|
|
159
|
+
await clearTransportAttempt();
|
|
160
|
+
return {
|
|
161
|
+
status: 'error',
|
|
162
|
+
message: 'Web OAuth requires full-page browser navigation.',
|
|
163
|
+
recoverable: true,
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
try {
|
|
168
|
+
Reflect.apply(assign, location, [args.authorizationUrl]);
|
|
169
|
+
return waitForFullPageNavigation();
|
|
170
|
+
} catch {
|
|
171
|
+
await cancelOAuthAttempt(args.attemptId, 'browser_dismissed');
|
|
172
|
+
await clearTransportAttempt();
|
|
173
|
+
return {
|
|
174
|
+
status: 'error',
|
|
175
|
+
message: 'The browser could not navigate to the OAuth provider.',
|
|
176
|
+
recoverable: true,
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function waitForFullPageNavigation(): Promise<never> {
|
|
182
|
+
return new Promise<never>(() => {
|
|
183
|
+
// Full-page navigation replaces this document before the promise settles.
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
|
|
134
187
|
export async function completeOAuthCallback(
|
|
135
188
|
callbackUrl: string,
|
|
136
189
|
): Promise<GeneratedOAuthTransportOutcome> {
|
|
@@ -176,13 +229,10 @@ function resolveOAuthRedirectUri(): string {
|
|
|
176
229
|
callbackPath = callbackPath.slice(1);
|
|
177
230
|
}
|
|
178
231
|
if (Platform.OS === 'web') {
|
|
179
|
-
const location =
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
typeof Reflect.get(location, 'origin') === 'string'
|
|
184
|
-
) {
|
|
185
|
-
return new URL(\`/\${callbackPath}\`, Reflect.get(location, 'origin')).toString();
|
|
232
|
+
const location = getBrowserLocation();
|
|
233
|
+
const origin = location ? Reflect.get(location, 'origin') : undefined;
|
|
234
|
+
if (typeof origin === 'string' && origin.length > 0) {
|
|
235
|
+
return new URL(\`/\${callbackPath}\`, origin).toString();
|
|
186
236
|
}
|
|
187
237
|
throw new Error('Web OAuth requires a canonical browser origin.');
|
|
188
238
|
}
|
|
@@ -190,6 +240,11 @@ function resolveOAuthRedirectUri(): string {
|
|
|
190
240
|
return Linking.createURL(callbackPath);
|
|
191
241
|
}
|
|
192
242
|
|
|
243
|
+
function getBrowserLocation(): object | null {
|
|
244
|
+
const location = Reflect.get(globalThis, 'location');
|
|
245
|
+
return typeof location === 'object' && location !== null ? location : null;
|
|
246
|
+
}
|
|
247
|
+
|
|
193
248
|
function toTransportOutcome(
|
|
194
249
|
result: AuthOAuthCompletionResult,
|
|
195
250
|
): GeneratedOAuthTransportOutcome {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"oauth.js","sourceRoot":"","sources":["../../../../../src/host/layout/templates/auth/oauth.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AAEtE,MAAM,UAAU,qBAAqB,CAAC,IAAyB;IAC7D,MAAM,aAAa,GAAG,mBAAmB,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;IAC9D,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAEjD,OAAO;;;;;;;;;;;;;;;gCAeuB,aAAa;;oCAET,SAAS
|
|
1
|
+
{"version":3,"file":"oauth.js","sourceRoot":"","sources":["../../../../../src/host/layout/templates/auth/oauth.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AAEtE,MAAM,UAAU,qBAAqB,CAAC,IAAyB;IAC7D,MAAM,aAAa,GAAG,mBAAmB,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;IAC9D,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAEjD,OAAO;;;;;;;;;;;;;;;gCAeuB,aAAa;;oCAET,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8S5C,CAAC;AACF,CAAC"}
|