@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/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/index.min.js +8 -8
- package/dist/index.min.js.map +4 -4
- package/dist/quickAuth.d.ts +42 -0
- package/dist/quickAuth.js +74 -0
- package/dist/sdk.js +5 -31
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types.d.ts +4 -14
- package/package.json +3 -3
- package/src/index.ts +4 -0
- package/src/quickAuth.ts +148 -0
- package/src/sdk.ts +5 -38
- package/src/types.ts +4 -14
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.
|
|
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.
|
|
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.
|
|
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.
|
|
26
|
+
"@farcaster/frame-core": "0.1.10"
|
|
27
27
|
},
|
|
28
28
|
"scripts": {
|
|
29
29
|
"clean": "rm -rf dist",
|
package/src/index.ts
CHANGED
package/src/quickAuth.ts
ADDED
|
@@ -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.
|
|
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
|