@farcaster/frame-sdk 0.0.60 → 0.0.63

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/types.d.ts CHANGED
@@ -2,6 +2,7 @@ import type { AddMiniApp, ComposeCast, Context, FrameNotificationDetails, GetCap
2
2
  import type { EventEmitter } from 'eventemitter3';
3
3
  import type * as Provider from 'ox/Provider';
4
4
  import type { Back } from './back.ts';
5
+ import type { QuickAuth } from './quickAuth.ts';
5
6
  declare global {
6
7
  interface Window {
7
8
  ReactNativeWebView: {
@@ -30,23 +31,13 @@ export type EventMap = {
30
31
  };
31
32
  export type Emitter = Compute<EventEmitter<EventMap>>;
32
33
  type SetPrimaryButton = (options: SetPrimaryButtonOptions) => Promise<void>;
33
- type QuickAuth = (options?: {
34
- /**
35
- * Use a custom Quick Auth server, otherwise defaults to the public
36
- * instance provided by Farcaster.
37
- *
38
- * @default https://auth.farcaster.xyz
39
- */
40
- quickAuthServerOrigin?: string;
41
- }) => Promise<{
42
- token: string;
43
- }>;
44
34
  export type FrameSDK = {
45
35
  getCapabilities: GetCapabilities;
46
36
  getChains: GetChains;
47
37
  isInMiniApp: () => Promise<boolean>;
48
38
  context: Promise<Context.FrameContext>;
49
39
  back: Back;
40
+ quickAuth: QuickAuth;
50
41
  actions: {
51
42
  ready: (options?: Partial<Ready.ReadyOptions>) => Promise<void>;
52
43
  openUrl: (url: string) => Promise<void>;
@@ -61,14 +52,13 @@ export type FrameSDK = {
61
52
  viewToken: ViewToken.ViewToken;
62
53
  sendToken: SendToken.SendToken;
63
54
  swapToken: SwapToken.SwapToken;
64
- quickAuth: QuickAuth;
65
55
  };
66
56
  experimental: {
67
57
  getSolanaProvider: () => Promise<SolanaWalletProvider | undefined>;
68
58
  /**
69
- * @deprecated - use `sdk.actions.quickAuth`
59
+ * @deprecated - use `sdk.quickAuth.getToken`
70
60
  */
71
- quickAuth: QuickAuth;
61
+ quickAuth: QuickAuth['getToken'];
72
62
  };
73
63
  wallet: {
74
64
  ethProvider: Provider.Provider;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@farcaster/frame-sdk",
3
- "version": "0.0.60",
3
+ "version": "0.0.63",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -19,11 +19,11 @@
19
19
  "@farcaster/tsconfig": "0.0.5"
20
20
  },
21
21
  "dependencies": {
22
- "@farcaster/quick-auth": "^0.0.5",
22
+ "@farcaster/quick-auth": "^0.0.6",
23
23
  "comlink": "^4.4.2",
24
24
  "eventemitter3": "^5.0.1",
25
25
  "ox": "^0.4.4",
26
- "@farcaster/frame-core": "0.1.8"
26
+ "@farcaster/frame-core": "0.1.10"
27
27
  },
28
28
  "scripts": {
29
29
  "clean": "rm -rf dist",
package/src/index.ts CHANGED
@@ -4,4 +4,8 @@ export * from './frameHost.ts'
4
4
  export * from './sdk.ts'
5
5
  export * from '@farcaster/frame-core'
6
6
 
7
+ export * as QuickAuth from './quickAuth.ts'
8
+
9
+ export { quickAuth } from './quickAuth.ts'
10
+
7
11
  export default sdk
@@ -0,0 +1,148 @@
1
+ import { SignIn } from '@farcaster/frame-core'
2
+ import type { JWTPayload } from '@farcaster/quick-auth'
3
+ import { decodeJwt } from '@farcaster/quick-auth/decodeJwt'
4
+ import { createLightClient } from '@farcaster/quick-auth/light'
5
+ import * as Siwe from 'ox/Siwe'
6
+
7
+ import { frameHost } from './frameHost.js'
8
+
9
+ export declare namespace getToken {
10
+ type Options = {
11
+ /**
12
+ * Use a custom Quick Auth server, otherwise defaults to the public
13
+ * instance provided by Farcaster.
14
+ *
15
+ * @default https://auth.farcaster.xyz
16
+ */
17
+ quickAuthServerOrigin?: string
18
+
19
+ /**
20
+ * Acquire a new token even if one is already in memory and not expired.
21
+ *
22
+ * @default false
23
+ */
24
+ force?: string
25
+ }
26
+
27
+ type ReturnValue = { token: string }
28
+ type ReturnType = Promise<ReturnValue>
29
+
30
+ type ErrorType = SignIn.RejectedByUser | Error
31
+ }
32
+
33
+ export type QuickAuth = {
34
+ /**
35
+ * Returns the session token if one is present and not expired.
36
+ */
37
+ readonly token: string | undefined
38
+
39
+ /**
40
+ * Get a Quick Auth JWT.
41
+ *
42
+ * If a token is already in memory and not expired it will be returned unless
43
+ * `force` is used. Otherwise a new token will be acquired.
44
+ */
45
+ getToken: (options?: getToken.Options) => getToken.ReturnType
46
+
47
+ /**
48
+ * Make an authenticated fetch request. The `Authorization` header will
49
+ * contain `Bearer ${token}` where token is a Quick Auth session token.
50
+ */
51
+ fetch: typeof fetch
52
+ }
53
+
54
+ export const quickAuth: QuickAuth = (() => {
55
+ let current:
56
+ | {
57
+ token: string
58
+ payload: JWTPayload
59
+ }
60
+ | undefined
61
+ let pendingPromise: Promise<getToken.ReturnValue> | undefined = undefined
62
+
63
+ async function getTokenInner(options: getToken.Options): getToken.ReturnType {
64
+ const quickAuthClient = createLightClient({
65
+ origin: options.quickAuthServerOrigin,
66
+ })
67
+
68
+ const { nonce } = await quickAuthClient.generateNonce()
69
+ const response = await frameHost.signIn({
70
+ nonce,
71
+ acceptAuthAddress: true,
72
+ })
73
+
74
+ if (response.result) {
75
+ const parsedSiwe = Siwe.parseMessage(response.result.message)
76
+
77
+ // The Farcaster Client rendering the Mini App will set the domain
78
+ // based on the URL it's rendering. It should always be set.
79
+ if (!parsedSiwe.domain) {
80
+ throw new Error('Missing domain on SIWE message')
81
+ }
82
+
83
+ const verifyResult = await quickAuthClient.verifySiwf({
84
+ domain: parsedSiwe.domain,
85
+ message: response.result.message,
86
+ signature: response.result.signature,
87
+ })
88
+
89
+ current = {
90
+ token: verifyResult.token,
91
+ payload: decodeJwt(verifyResult.token),
92
+ }
93
+
94
+ return verifyResult
95
+ }
96
+
97
+ if (response.error.type === 'rejected_by_user') {
98
+ throw new SignIn.RejectedByUser()
99
+ }
100
+
101
+ throw new Error('Unreachable')
102
+ }
103
+
104
+ return {
105
+ get token() {
106
+ if (
107
+ current &&
108
+ new Date(current.payload.exp * 1000) > new Date(Date.now() + 15000)
109
+ ) {
110
+ return current.token
111
+ }
112
+
113
+ return undefined
114
+ },
115
+ async getToken(options = {}) {
116
+ const force = options.force ?? false
117
+
118
+ if (
119
+ current &&
120
+ !force &&
121
+ new Date(current.payload.exp * 1000) > new Date(Date.now() + 15000)
122
+ ) {
123
+ return { token: current.token }
124
+ }
125
+
126
+ if (!pendingPromise) {
127
+ pendingPromise = getTokenInner(options)
128
+ }
129
+
130
+ pendingPromise.finally(() => {
131
+ pendingPromise = undefined
132
+ })
133
+
134
+ return pendingPromise
135
+ },
136
+ async fetch(url, options) {
137
+ const { token } = await this.getToken()
138
+
139
+ const headers = new Headers(options?.headers)
140
+ headers.set('Authorization', `Bearer ${token}`)
141
+
142
+ return fetch(url, {
143
+ ...options,
144
+ headers,
145
+ })
146
+ },
147
+ }
148
+ })()
package/src/sdk.ts CHANGED
@@ -3,11 +3,10 @@ import {
3
3
  type FrameClientEvent,
4
4
  SignIn,
5
5
  } from '@farcaster/frame-core'
6
- import { createLightClient } from '@farcaster/quick-auth/light'
7
- import * as Siwe from 'ox/Siwe'
8
6
  import { createBack } from './back.ts'
9
7
  import { ethereumProvider, getEthereumProvider } from './ethereumProvider.ts'
10
8
  import { frameHost } from './frameHost.ts'
9
+ import { quickAuth } from './quickAuth.ts'
11
10
  import { emitter } from './sdkEmitter.ts'
12
11
  import { getSolanaProvider } from './solanaProvider.ts'
13
12
  import type { FrameSDK } from './types.ts'
@@ -55,40 +54,6 @@ async function isInMiniApp(timeoutMs = 50): Promise<boolean> {
55
54
  return isInMiniApp
56
55
  }
57
56
 
58
- const quickAuth: FrameSDK['actions']['quickAuth'] = async (options = {}) => {
59
- const quickAuthClient = createLightClient({
60
- origin: options.quickAuthServerOrigin,
61
- })
62
-
63
- const { nonce } = await quickAuthClient.generateNonce()
64
- const response = await frameHost.signIn({
65
- nonce,
66
- acceptAuthAddress: true,
67
- })
68
-
69
- if (response.result) {
70
- const parsedSiwe = Siwe.parseMessage(response.result.message)
71
-
72
- // The Farcaster Client rendering the Mini App will set the domain
73
- // based on the URL it's rendering. It should always be set.
74
- if (!parsedSiwe.domain) {
75
- throw new Error('Missing domain on SIWE message')
76
- }
77
-
78
- return await quickAuthClient.verifySiwf({
79
- domain: parsedSiwe.domain,
80
- message: response.result.message,
81
- signature: response.result.signature,
82
- })
83
- }
84
-
85
- if (response.error.type === 'rejected_by_user') {
86
- throw new SignIn.RejectedByUser()
87
- }
88
-
89
- throw new Error('Unreachable')
90
- }
91
-
92
57
  const addMiniApp = async () => {
93
58
  const response = await frameHost.addFrame()
94
59
  if (response.result) {
@@ -113,6 +78,7 @@ export const sdk: FrameSDK = {
113
78
  isInMiniApp,
114
79
  context: frameHost.context,
115
80
  back: createBack({ frameHost, emitter }),
81
+ quickAuth,
116
82
  actions: {
117
83
  setPrimaryButton: frameHost.setPrimaryButton.bind(frameHost),
118
84
  ready: async (options = {}) => {
@@ -145,11 +111,12 @@ export const sdk: FrameSDK = {
145
111
  viewToken: frameHost.viewToken.bind(frameHost),
146
112
  sendToken: frameHost.sendToken.bind(frameHost),
147
113
  swapToken: frameHost.swapToken.bind(frameHost),
148
- quickAuth,
149
114
  },
150
115
  experimental: {
151
116
  getSolanaProvider,
152
- quickAuth,
117
+ quickAuth(options) {
118
+ return quickAuth.getToken(options)
119
+ },
153
120
  },
154
121
  wallet: {
155
122
  ethProvider: ethereumProvider,
package/src/types.ts CHANGED
@@ -21,6 +21,7 @@ import type {
21
21
  import type { EventEmitter } from 'eventemitter3'
22
22
  import type * as Provider from 'ox/Provider'
23
23
  import type { Back } from './back.ts'
24
+ import type { QuickAuth } from './quickAuth.ts'
24
25
 
25
26
  declare global {
26
27
  interface Window {
@@ -58,17 +59,6 @@ export type EventMap = {
58
59
  export type Emitter = Compute<EventEmitter<EventMap>>
59
60
 
60
61
  type SetPrimaryButton = (options: SetPrimaryButtonOptions) => Promise<void>
61
- type QuickAuth = (options?: {
62
- /**
63
- * Use a custom Quick Auth server, otherwise defaults to the public
64
- * instance provided by Farcaster.
65
- *
66
- * @default https://auth.farcaster.xyz
67
- */
68
- quickAuthServerOrigin?: string
69
- }) => Promise<{
70
- token: string
71
- }>
72
62
 
73
63
  export type FrameSDK = {
74
64
  getCapabilities: GetCapabilities
@@ -76,6 +66,7 @@ export type FrameSDK = {
76
66
  isInMiniApp: () => Promise<boolean>
77
67
  context: Promise<Context.FrameContext>
78
68
  back: Back
69
+ quickAuth: QuickAuth
79
70
  actions: {
80
71
  ready: (options?: Partial<Ready.ReadyOptions>) => Promise<void>
81
72
  openUrl: (url: string) => Promise<void>
@@ -93,15 +84,14 @@ export type FrameSDK = {
93
84
  viewToken: ViewToken.ViewToken
94
85
  sendToken: SendToken.SendToken
95
86
  swapToken: SwapToken.SwapToken
96
- quickAuth: QuickAuth
97
87
  }
98
88
  experimental: {
99
89
  getSolanaProvider: () => Promise<SolanaWalletProvider | undefined>
100
90
 
101
91
  /**
102
- * @deprecated - use `sdk.actions.quickAuth`
92
+ * @deprecated - use `sdk.quickAuth.getToken`
103
93
  */
104
- quickAuth: QuickAuth
94
+ quickAuth: QuickAuth['getToken']
105
95
  }
106
96
  wallet: {
107
97
  // Deprecated in favor of getEthereumProvider