@@ -15,15 +15,14 @@ import {
1515import { observable } from "@trpc/server/observable" ;
1616import { Spinner } from "@std/cli/unstable-spinner" ;
1717import { error } from "./util.ts" ;
18- import token_storage , { tokenIsTemp } from "./token_storage.ts" ;
1918import { EventSourcePolyfill } from "event-source-polyfill" ;
19+ import type { GlobalContext } from "./main.ts" ;
2020
2121export function createTrpcClient (
22- debug : boolean ,
23- deployUrl : string ,
22+ context : GlobalContext ,
2423 quiet : boolean = false ,
2524) {
26- let storedAuth = token_storage . get ( ) ;
25+ let storedAuth = tokenStorage . get ( ) ;
2726
2827 // deno-lint-ignore no-explicit-any
2928 const errorLink : TRPCLink < any > = ( ) => {
@@ -34,11 +33,11 @@ export function createTrpcClient(
3433 observer . next ( value ) ;
3534 } ,
3635 error ( err ) {
37- if ( debug ) {
36+ if ( context . debug ) {
3837 console . error ( err ) ;
3938 }
4039 error (
41- debug ,
40+ context ,
4241 err . message || Deno . inspect ( err ) ,
4342 err . meta ?. response as Response | undefined ,
4443 ) ;
@@ -70,7 +69,7 @@ export function createTrpcClient(
7069 errorLink ,
7170 retryLink ( {
7271 retry ( opts ) {
73- if ( debug ) {
72+ if ( context . debug ) {
7473 console . log ( opts ) ;
7574 }
7675
@@ -82,21 +81,21 @@ export function createTrpcClient(
8281
8382 if ( tokenIsTemp ) {
8483 error (
85- debug ,
84+ context ,
8685 "The token specified via 'DENO_DEPLOY_TOKEN' or the '--token' flag is invalid." ,
8786 ) ;
8887 }
8988
9089 if ( typeof retryPromise !== "undefined" ) {
91- token_storage . remove ( ) ;
90+ tokenStorage . remove ( ) ;
9291 error (
93- debug ,
92+ context ,
9493 "Already re-attempted authorization, please re-run this command" ,
9594 ) ;
9695 }
9796
98- token_storage . remove ( ) ;
99- retryPromise = getAuth ( debug , deployUrl , quiet ) . then ( ( auth ) => {
97+ tokenStorage . remove ( ) ;
98+ retryPromise = getAuth ( context , quiet ) . then ( ( auth ) => {
10099 storedAuth = auth ;
101100 } ) ;
102101 return true ;
@@ -106,7 +105,7 @@ export function createTrpcClient(
106105 // uses the httpSubscriptionLink for subscriptions
107106 condition : ( op ) => op . type === "subscription" ,
108107 false : httpBatchStreamLink ( {
109- url : deployUrl + "/api" ,
108+ url : context . endpoint + "/api" ,
110109 fetch : async ( url , options ) => {
111110 // deno-lint-ignore no-explicit-any
112111 const response = await fetch ( url , options as any ) ;
@@ -144,7 +143,7 @@ export function createTrpcClient(
144143 transformer,
145144 } ) ,
146145 true : httpSubscriptionLink ( {
147- url : deployUrl + "/api" ,
146+ url : context . endpoint + "/api" ,
148147 EventSource : EventSourcePolyfill ,
149148 async eventSourceOptions ( ) {
150149 if ( retryPromise ) {
@@ -170,18 +169,17 @@ export function createTrpcClient(
170169}
171170
172171export async function getAuth (
173- debug : boolean ,
174- deployUrl : string ,
172+ context : GlobalContext ,
175173 quiet : boolean = false ,
176174) : Promise < string > {
177- const storedAuth = token_storage . get ( ) ;
175+ const storedAuth = tokenStorage . get ( ) ;
178176 if ( storedAuth ) {
179177 return storedAuth ;
180178 }
181179
182- const { code, exchangeToken, verifier } = await interactive ( debug , deployUrl ) ;
180+ const { code, exchangeToken, verifier } = await interactive ( context ) ;
183181
184- const authUrl = `${ deployUrl } /auth?code=${ code } ` ;
182+ const authUrl = `${ context . endpoint } /auth?code=${ code } ` ;
185183
186184 const spinner = new Spinner ( {
187185 message : `Visit ${ authUrl } to authorize deploying your project.` ,
@@ -192,31 +190,30 @@ export async function getAuth(
192190 await open ( authUrl ) ;
193191
194192 return await tokenExchange (
195- debug ,
196- deployUrl ,
193+ context ,
197194 exchangeToken ,
198195 verifier ,
199196 spinner ,
200197 quiet ,
201198 ) ;
202199}
203200
204- export async function interactive ( debug : boolean , deployUrl : string ) : Promise <
201+ export async function interactive ( context : GlobalContext ) : Promise <
205202 { code : string ; exchangeToken : string ; verifier : string }
206203> {
207204 const verifier = crypto . randomUUID ( ) ;
208205 const data = ( new TextEncoder ( ) ) . encode ( verifier ) ;
209206 const hash = await crypto . subtle . digest ( "SHA-256" , data ) ;
210207 const challenge = encodeBase64 ( hash ) ;
211208
212- const res = await fetch ( `${ deployUrl } /auth/interactive` , {
209+ const res = await fetch ( `${ context . endpoint } /auth/interactive` , {
213210 method : "POST" ,
214211 body : JSON . stringify ( { challenge } ) ,
215212 } ) ;
216213
217214 if ( ! res . ok ) {
218215 console . error ( "An error occurred during authentication, exiting..." ) ;
219- if ( debug ) {
216+ if ( context . debug ) {
220217 console . log ( res ) ;
221218 console . log ( await res . json ( ) ) ;
222219 }
@@ -233,16 +230,15 @@ export async function interactive(debug: boolean, deployUrl: string): Promise<
233230}
234231
235232export function tokenExchange (
236- debug : boolean ,
237- deployUrl : string ,
233+ context : GlobalContext ,
238234 exchangeToken : string ,
239235 verifier : string ,
240236 spinner : Spinner ,
241237 quiet : boolean ,
242238) : Promise < string > {
243239 return new Promise ( ( resolve ) => {
244240 const interval = setInterval ( async ( ) => {
245- const res = await fetch ( `${ deployUrl } /auth/exchange` , {
241+ const res = await fetch ( `${ context . endpoint } /auth/exchange` , {
246242 method : "POST" ,
247243 body : JSON . stringify ( {
248244 exchangeToken,
@@ -261,7 +257,7 @@ export function tokenExchange(
261257 ) ;
262258 }
263259 clearInterval ( interval ) ;
264- token_storage . set ( token ) ;
260+ tokenStorage . set ( token ) ;
265261 resolve ( token ) ;
266262 } else {
267263 const err = await res . json ( ) ;
@@ -273,23 +269,22 @@ export function tokenExchange(
273269 ) {
274270 clearInterval ( interval ) ;
275271 spinner . stop ( ) ;
276- error ( debug , err . message , res ) ;
272+ error ( context , err . message , res ) ;
277273 }
278274 }
279275 } , 2000 ) ;
280276 } ) ;
281277}
282278
283279export async function authedFetch (
284- debug : boolean ,
285- deployUrl : string ,
280+ context : GlobalContext ,
286281 endpoint : string ,
287282 init : RequestInit ,
288283) {
289- let auth = await token_storage . get ( ) ;
284+ let auth = await tokenStorage . get ( ) ;
290285
291286 if ( ! auth ) {
292- auth = await getAuth ( debug , deployUrl ) ;
287+ auth = await getAuth ( context ) ;
293288 }
294289
295290 const headers = new Headers ( init . headers ) ;
@@ -298,7 +293,7 @@ export async function authedFetch(
298293 `token=${ auth } ; deno_auth_ghid=force` ,
299294 ) ;
300295
301- const url = new URL ( endpoint , deployUrl ) ;
296+ const url = new URL ( endpoint , context . endpoint ) ;
302297
303298 let fallbackBody : ReadableStream | undefined ;
304299 if ( init . body instanceof ReadableStream ) {
@@ -314,8 +309,8 @@ export async function authedFetch(
314309
315310 if ( res . status === 401 ) {
316311 console . log ( await res . text ( ) ) ;
317- token_storage . remove ( ) ;
318- auth = await getAuth ( debug , deployUrl ) ;
312+ tokenStorage . remove ( ) ;
313+ auth = await getAuth ( context ) ;
319314
320315 const headers = new Headers ( init . headers ) ;
321316 headers . set (
@@ -330,11 +325,68 @@ export async function authedFetch(
330325
331326 if ( retryRes . status === 401 ) {
332327 const err = await retryRes . json ( ) ;
333- error ( debug , `unexpected authentication failure\n${ err . message } ` ) ;
328+ error ( context , `unexpected authentication failure\n${ err . message } ` ) ;
334329 } else {
335330 return retryRes ;
336331 }
337332 } else {
338333 return res ;
339334 }
340335}
336+
337+ let cachedToken : string | null = null ;
338+ export let tokenIsTemp = false ;
339+ let cannotInteractWithKeychain = false ;
340+
341+ const KEYCHAIN_WARNING =
342+ "Unable to interact with keychain.\nThe authentication will not be stored and will only work on this execution." ;
343+
344+ export const tokenStorage = {
345+ get ( ) : string | null {
346+ if ( cachedToken ) {
347+ return cachedToken ;
348+ } else {
349+ try {
350+ // @ts -ignore deno internals
351+ return Deno [ Deno . internal ] . core . ops . op_deploy_token_get ( ) ;
352+ } catch {
353+ if ( ! cannotInteractWithKeychain ) {
354+ cannotInteractWithKeychain = true ;
355+ console . log ( KEYCHAIN_WARNING ) ;
356+ }
357+ return null ;
358+ }
359+ }
360+ } ,
361+ set ( token : string , temp : boolean = false ) {
362+ cachedToken = token ;
363+ if ( ! temp ) {
364+ try {
365+ // @ts -ignore deno internals
366+ Deno [ Deno . internal ] . core . ops . op_deploy_token_set ( token ) ;
367+ } catch {
368+ if ( ! cannotInteractWithKeychain ) {
369+ cannotInteractWithKeychain = true ;
370+ console . log ( KEYCHAIN_WARNING ) ;
371+ }
372+ }
373+ } else {
374+ tokenIsTemp = temp ;
375+ }
376+ } ,
377+ remove ( ) {
378+ if ( tokenIsTemp ) {
379+ return ;
380+ }
381+ cachedToken = null ;
382+ try {
383+ // @ts -ignore deno internals
384+ Deno [ Deno . internal ] . core . ops . op_deploy_token_delete ( ) ;
385+ } catch {
386+ if ( ! cannotInteractWithKeychain ) {
387+ cannotInteractWithKeychain = true ;
388+ console . log ( KEYCHAIN_WARNING ) ;
389+ }
390+ }
391+ } ,
392+ } ;
0 commit comments