@ankhorage/studio 0.11.7 → 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 +67 -9
- 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> {
|
|
@@ -171,15 +224,15 @@ export async function completeOAuthCallback(
|
|
|
171
224
|
}
|
|
172
225
|
|
|
173
226
|
function resolveOAuthRedirectUri(): string {
|
|
174
|
-
|
|
227
|
+
let callbackPath = OAUTH_CALLBACK_ROUTE;
|
|
228
|
+
while (callbackPath.startsWith('/')) {
|
|
229
|
+
callbackPath = callbackPath.slice(1);
|
|
230
|
+
}
|
|
175
231
|
if (Platform.OS === 'web') {
|
|
176
|
-
const location =
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
typeof Reflect.get(location, 'origin') === 'string'
|
|
181
|
-
) {
|
|
182
|
-
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();
|
|
183
236
|
}
|
|
184
237
|
throw new Error('Web OAuth requires a canonical browser origin.');
|
|
185
238
|
}
|
|
@@ -187,6 +240,11 @@ function resolveOAuthRedirectUri(): string {
|
|
|
187
240
|
return Linking.createURL(callbackPath);
|
|
188
241
|
}
|
|
189
242
|
|
|
243
|
+
function getBrowserLocation(): object | null {
|
|
244
|
+
const location = Reflect.get(globalThis, 'location');
|
|
245
|
+
return typeof location === 'object' && location !== null ? location : null;
|
|
246
|
+
}
|
|
247
|
+
|
|
190
248
|
function toTransportOutcome(
|
|
191
249
|
result: AuthOAuthCompletionResult,
|
|
192
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"}
|