@farcaster/frame-sdk 0.0.21 → 0.0.23
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/endpoint.d.ts +1 -1
- package/dist/endpoint.js +5 -5
- package/dist/frameHost.d.ts +1 -1
- package/dist/frameHost.js +2 -2
- package/dist/index.d.ts +3 -3
- package/dist/index.js +3 -3
- package/dist/index.min.js +2 -2
- package/dist/index.min.js.map +4 -4
- package/dist/provider.d.ts +1 -7
- package/dist/provider.js +48 -9
- package/dist/sdk.d.ts +1 -1
- package/dist/sdk.js +48 -37
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types.d.ts +9 -13
- package/package.json +6 -5
- package/src/endpoint.ts +10 -10
- package/src/frameHost.ts +4 -4
- package/src/index.ts +4 -4
- package/src/provider.ts +95 -35
- package/src/sdk.ts +71 -57
- package/src/types.ts +33 -36
package/dist/types.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type {
|
|
3
|
-
import type {
|
|
1
|
+
import type { AddFrame, FrameContext, FrameNotificationDetails, ReadyOptions, SetPrimaryButtonOptions, SignIn } from '@farcaster/frame-core';
|
|
2
|
+
import type { EventEmitter } from 'eventemitter3';
|
|
3
|
+
import type { Provider } from 'ox';
|
|
4
4
|
declare global {
|
|
5
5
|
interface Window {
|
|
6
6
|
ReactNativeWebView: {
|
|
@@ -9,7 +9,7 @@ declare global {
|
|
|
9
9
|
}
|
|
10
10
|
}
|
|
11
11
|
/** Combines members of an intersection into a readable type. */
|
|
12
|
-
|
|
12
|
+
type Compute<type> = {
|
|
13
13
|
[key in keyof type]: type[key];
|
|
14
14
|
} & unknown;
|
|
15
15
|
export type EventMap = {
|
|
@@ -17,8 +17,8 @@ export type EventMap = {
|
|
|
17
17
|
frameAdded: ({ notificationDetails, }: {
|
|
18
18
|
notificationDetails?: FrameNotificationDetails;
|
|
19
19
|
}) => void;
|
|
20
|
-
frameAddRejected: ({ reason }: {
|
|
21
|
-
reason: AddFrameRejectedReason;
|
|
20
|
+
frameAddRejected: ({ reason, }: {
|
|
21
|
+
reason: AddFrame.AddFrameRejectedReason;
|
|
22
22
|
}) => void;
|
|
23
23
|
frameRemoved: () => void;
|
|
24
24
|
notificationsEnabled: ({ notificationDetails, }: {
|
|
@@ -27,12 +27,7 @@ export type EventMap = {
|
|
|
27
27
|
notificationsDisabled: () => void;
|
|
28
28
|
};
|
|
29
29
|
export type Emitter = Compute<EventEmitter<EventMap>>;
|
|
30
|
-
|
|
31
|
-
text: string;
|
|
32
|
-
loading?: boolean;
|
|
33
|
-
disabled?: boolean;
|
|
34
|
-
hidden?: boolean;
|
|
35
|
-
}) => Promise<void>;
|
|
30
|
+
type SetPrimaryButton = (options: SetPrimaryButtonOptions) => Promise<void>;
|
|
36
31
|
export type FrameSDK = {
|
|
37
32
|
context: Promise<FrameContext>;
|
|
38
33
|
actions: {
|
|
@@ -41,9 +36,10 @@ export type FrameSDK = {
|
|
|
41
36
|
signIn: SignIn.SignIn;
|
|
42
37
|
close: () => Promise<void>;
|
|
43
38
|
setPrimaryButton: SetPrimaryButton;
|
|
44
|
-
addFrame: AddFrame;
|
|
39
|
+
addFrame: AddFrame.AddFrame;
|
|
45
40
|
};
|
|
46
41
|
wallet: {
|
|
47
42
|
ethProvider: Provider.Provider;
|
|
48
43
|
};
|
|
49
44
|
} & Emitter;
|
|
45
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,21 +1,22 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@farcaster/frame-sdk",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.23",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"files": [
|
|
6
6
|
"dist",
|
|
7
7
|
"src"
|
|
8
8
|
],
|
|
9
9
|
"devDependencies": {
|
|
10
|
-
"esbuild": "^0.24.
|
|
11
|
-
"
|
|
10
|
+
"esbuild": "^0.24.2",
|
|
11
|
+
"mipd": "^0.0.7",
|
|
12
|
+
"typescript": "^5.7.2",
|
|
12
13
|
"@farcaster/tsconfig": "0.0.2"
|
|
13
14
|
},
|
|
14
15
|
"dependencies": {
|
|
15
16
|
"comlink": "^4.4.2",
|
|
16
17
|
"eventemitter3": "^5.0.1",
|
|
17
|
-
"ox": "^0.4.
|
|
18
|
-
"@farcaster/frame-core": "0.0.
|
|
18
|
+
"ox": "^0.4.4",
|
|
19
|
+
"@farcaster/frame-core": "0.0.22"
|
|
19
20
|
},
|
|
20
21
|
"scripts": {
|
|
21
22
|
"clean": "rm -rf dist",
|
package/src/endpoint.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type Endpoint, windowEndpoint } from
|
|
1
|
+
import { type Endpoint, windowEndpoint } from 'comlink'
|
|
2
2
|
|
|
3
3
|
const mockEndpoint: Endpoint = {
|
|
4
4
|
postMessage() {
|
|
@@ -10,25 +10,25 @@ const mockEndpoint: Endpoint = {
|
|
|
10
10
|
removeEventListener: () => {
|
|
11
11
|
// noop
|
|
12
12
|
},
|
|
13
|
-
}
|
|
13
|
+
}
|
|
14
14
|
|
|
15
15
|
const webViewEndpoint: Endpoint = {
|
|
16
16
|
postMessage: (data: unknown) => {
|
|
17
|
-
console.debug(
|
|
18
|
-
window.ReactNativeWebView.postMessage(JSON.stringify(data))
|
|
17
|
+
console.debug('[webview:req]', data)
|
|
18
|
+
window.ReactNativeWebView.postMessage(JSON.stringify(data))
|
|
19
19
|
},
|
|
20
20
|
addEventListener: (_, listener, ...args) => {
|
|
21
|
-
document.addEventListener(
|
|
21
|
+
document.addEventListener('FarcasterFrameCallback', listener, ...args)
|
|
22
22
|
},
|
|
23
23
|
removeEventListener: (_, listener) => {
|
|
24
|
-
document.removeEventListener(
|
|
24
|
+
document.removeEventListener('FarcasterFrameCallback', listener)
|
|
25
25
|
},
|
|
26
|
-
}
|
|
26
|
+
}
|
|
27
27
|
|
|
28
28
|
export const endpoint = (() => {
|
|
29
29
|
// No actions are actually gonna take place during SSR, thus it's safe to return mocked endpoint
|
|
30
|
-
if (typeof window ===
|
|
30
|
+
if (typeof window === 'undefined') return mockEndpoint
|
|
31
31
|
return window?.ReactNativeWebView
|
|
32
32
|
? webViewEndpoint
|
|
33
|
-
: windowEndpoint(window?.parent ?? window)
|
|
34
|
-
})()
|
|
33
|
+
: windowEndpoint(window?.parent ?? window)
|
|
34
|
+
})()
|
package/src/frameHost.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import type { WireFrameHost } from '@farcaster/frame-core'
|
|
2
|
+
import { wrap } from 'comlink'
|
|
3
|
+
import { endpoint } from './endpoint'
|
|
4
4
|
|
|
5
|
-
export const frameHost = wrap<WireFrameHost>(endpoint)
|
|
5
|
+
export const frameHost = wrap<WireFrameHost>(endpoint)
|
package/src/index.ts
CHANGED
package/src/provider.ts
CHANGED
|
@@ -1,35 +1,44 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import type {
|
|
2
|
+
EthProviderWireEvent,
|
|
3
|
+
FrameClientEvent,
|
|
4
|
+
} from '@farcaster/frame-core'
|
|
5
|
+
import type {
|
|
6
|
+
AnnounceProviderParameters,
|
|
7
|
+
AnnounceProviderReturnType,
|
|
8
|
+
EIP1193Provider,
|
|
9
|
+
EIP6963ProviderDetail,
|
|
10
|
+
} from 'mipd'
|
|
11
|
+
import { Provider, RpcRequest, RpcResponse } from 'ox'
|
|
12
|
+
import { frameHost } from './frameHost'
|
|
4
13
|
|
|
5
|
-
const emitter = Provider.createEmitter()
|
|
6
|
-
const store = RpcRequest.createStore()
|
|
14
|
+
const emitter = Provider.createEmitter()
|
|
15
|
+
const store = RpcRequest.createStore()
|
|
7
16
|
|
|
8
17
|
type GenericProviderRpcError = {
|
|
9
|
-
code: number
|
|
10
|
-
details?: string
|
|
11
|
-
}
|
|
18
|
+
code: number
|
|
19
|
+
details?: string
|
|
20
|
+
}
|
|
12
21
|
|
|
13
|
-
|
|
22
|
+
function toProviderRpcError({
|
|
14
23
|
code,
|
|
15
24
|
details,
|
|
16
25
|
}: GenericProviderRpcError): Provider.ProviderRpcError {
|
|
17
26
|
switch (code) {
|
|
18
27
|
case 4001:
|
|
19
|
-
return new Provider.UserRejectedRequestError()
|
|
28
|
+
return new Provider.UserRejectedRequestError()
|
|
20
29
|
case 4100:
|
|
21
|
-
return new Provider.UnauthorizedError()
|
|
30
|
+
return new Provider.UnauthorizedError()
|
|
22
31
|
case 4200:
|
|
23
|
-
return new Provider.UnsupportedMethodError()
|
|
32
|
+
return new Provider.UnsupportedMethodError()
|
|
24
33
|
case 4900:
|
|
25
|
-
return new Provider.DisconnectedError()
|
|
34
|
+
return new Provider.DisconnectedError()
|
|
26
35
|
case 4901:
|
|
27
|
-
return new Provider.ChainDisconnectedError()
|
|
36
|
+
return new Provider.ChainDisconnectedError()
|
|
28
37
|
default:
|
|
29
38
|
return new Provider.ProviderRpcError(
|
|
30
39
|
code,
|
|
31
|
-
details ??
|
|
32
|
-
)
|
|
40
|
+
details ?? 'Unknown provider RPC error',
|
|
41
|
+
)
|
|
33
42
|
}
|
|
34
43
|
}
|
|
35
44
|
|
|
@@ -37,63 +46,114 @@ export const provider: Provider.Provider = Provider.from({
|
|
|
37
46
|
...emitter,
|
|
38
47
|
async request(args) {
|
|
39
48
|
// @ts-expect-error
|
|
40
|
-
const request = store.prepare(args)
|
|
49
|
+
const request = store.prepare(args)
|
|
41
50
|
|
|
42
51
|
try {
|
|
43
52
|
const response = await frameHost
|
|
44
53
|
.ethProviderRequestV2(request)
|
|
45
|
-
.then((res) => RpcResponse.parse(res, { request, raw: true }))
|
|
54
|
+
.then((res) => RpcResponse.parse(res, { request, raw: true }))
|
|
46
55
|
|
|
47
56
|
if (response.error) {
|
|
48
|
-
throw toProviderRpcError(response.error)
|
|
57
|
+
throw toProviderRpcError(response.error)
|
|
49
58
|
}
|
|
50
59
|
|
|
51
|
-
return response.result
|
|
60
|
+
return response.result
|
|
52
61
|
} catch (e) {
|
|
53
62
|
// ethProviderRequestV2 not supported, fall back to v1
|
|
54
63
|
if (
|
|
55
64
|
e instanceof Error &&
|
|
56
65
|
e.message.match(/cannot read property 'apply'/i)
|
|
57
66
|
) {
|
|
58
|
-
return await frameHost.ethProviderRequest(request)
|
|
67
|
+
return await frameHost.ethProviderRequest(request)
|
|
59
68
|
}
|
|
60
69
|
|
|
61
70
|
if (
|
|
62
71
|
e instanceof Provider.ProviderRpcError ||
|
|
63
72
|
e instanceof RpcResponse.BaseError
|
|
64
73
|
) {
|
|
65
|
-
throw e
|
|
74
|
+
throw e
|
|
66
75
|
}
|
|
67
76
|
|
|
68
77
|
throw new RpcResponse.InternalError({
|
|
69
78
|
message: e instanceof Error ? e.message : undefined,
|
|
70
|
-
})
|
|
79
|
+
})
|
|
71
80
|
}
|
|
72
81
|
},
|
|
73
|
-
})
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
function announceProvider(
|
|
85
|
+
detail: AnnounceProviderParameters,
|
|
86
|
+
): AnnounceProviderReturnType {
|
|
87
|
+
const event: CustomEvent<EIP6963ProviderDetail> = new CustomEvent(
|
|
88
|
+
'eip6963:announceProvider',
|
|
89
|
+
{ detail: Object.freeze(detail) },
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
window.dispatchEvent(event)
|
|
93
|
+
|
|
94
|
+
const handler = () => window.dispatchEvent(event)
|
|
95
|
+
window.addEventListener('eip6963:requestProvider', handler)
|
|
96
|
+
return () => window.removeEventListener('eip6963:requestProvider', handler)
|
|
97
|
+
}
|
|
74
98
|
|
|
75
99
|
// Required to pass SSR
|
|
76
|
-
if (typeof document !==
|
|
100
|
+
if (typeof document !== 'undefined') {
|
|
101
|
+
// forward eip6963:requestProvider events to the host
|
|
102
|
+
document.addEventListener('eip6963:requestProvider', () => {
|
|
103
|
+
frameHost.eip6963RequestProvider()
|
|
104
|
+
})
|
|
105
|
+
|
|
77
106
|
// react native webview events
|
|
78
|
-
document.addEventListener(
|
|
107
|
+
document.addEventListener('FarcasterFrameEthProviderEvent', (event) => {
|
|
79
108
|
if (event instanceof MessageEvent) {
|
|
80
|
-
const ethProviderEvent = event.data as EthProviderWireEvent
|
|
109
|
+
const ethProviderEvent = event.data as EthProviderWireEvent
|
|
81
110
|
// @ts-expect-error
|
|
82
|
-
emitter.emit(ethProviderEvent.event, ...ethProviderEvent.params)
|
|
111
|
+
emitter.emit(ethProviderEvent.event, ...ethProviderEvent.params)
|
|
83
112
|
}
|
|
84
|
-
})
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
window.addEventListener('FarcasterFrameEvent', (event) => {
|
|
116
|
+
if (event instanceof MessageEvent) {
|
|
117
|
+
const frameEvent = event.data.event as FrameClientEvent
|
|
118
|
+
if (frameEvent.event === 'eip6963:announceProvider') {
|
|
119
|
+
announceProvider({
|
|
120
|
+
info: frameEvent.info,
|
|
121
|
+
provider: provider as EIP1193Provider,
|
|
122
|
+
})
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
})
|
|
85
126
|
}
|
|
86
127
|
|
|
87
128
|
// Required to pass SSR
|
|
88
|
-
if (typeof window !==
|
|
129
|
+
if (typeof window !== 'undefined') {
|
|
130
|
+
// forward eip6963:requestProvider events to the host
|
|
131
|
+
window.addEventListener('eip6963:requestProvider', () => {
|
|
132
|
+
frameHost.eip6963RequestProvider()
|
|
133
|
+
})
|
|
134
|
+
|
|
89
135
|
// web events
|
|
90
|
-
window.addEventListener(
|
|
136
|
+
window.addEventListener('message', (event) => {
|
|
91
137
|
if (event instanceof MessageEvent) {
|
|
92
|
-
if (event.data.type ===
|
|
93
|
-
const ethProviderEvent = event.data as EthProviderWireEvent
|
|
138
|
+
if (event.data.type === 'frameEthProviderEvent') {
|
|
139
|
+
const ethProviderEvent = event.data as EthProviderWireEvent
|
|
94
140
|
// @ts-expect-error
|
|
95
|
-
emitter.emit(ethProviderEvent.event, ...ethProviderEvent.params)
|
|
141
|
+
emitter.emit(ethProviderEvent.event, ...ethProviderEvent.params)
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
})
|
|
145
|
+
|
|
146
|
+
window.addEventListener('message', (event) => {
|
|
147
|
+
if (event instanceof MessageEvent) {
|
|
148
|
+
if (event.data.type === 'frameEvent') {
|
|
149
|
+
const frameEvent = event.data.event as FrameClientEvent
|
|
150
|
+
if (frameEvent.event === 'eip6963:announceProvider') {
|
|
151
|
+
announceProvider({
|
|
152
|
+
info: frameEvent.info,
|
|
153
|
+
provider: provider as EIP1193Provider,
|
|
154
|
+
})
|
|
155
|
+
}
|
|
96
156
|
}
|
|
97
157
|
}
|
|
98
|
-
})
|
|
158
|
+
})
|
|
99
159
|
}
|
package/src/sdk.ts
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { frameHost } from
|
|
4
|
-
import { provider } from
|
|
5
|
-
import {
|
|
1
|
+
import { AddFrame, type FrameClientEvent, SignIn } from '@farcaster/frame-core'
|
|
2
|
+
import { EventEmitter } from 'eventemitter3'
|
|
3
|
+
import { frameHost } from './frameHost'
|
|
4
|
+
import { provider } from './provider'
|
|
5
|
+
import type { Emitter, EventMap, FrameSDK } from './types'
|
|
6
6
|
|
|
7
7
|
export function createEmitter(): Emitter {
|
|
8
|
-
const emitter = new EventEmitter<EventMap>()
|
|
8
|
+
const emitter = new EventEmitter<EventMap>()
|
|
9
9
|
|
|
10
10
|
return {
|
|
11
11
|
get eventNames() {
|
|
12
|
-
return emitter.eventNames.bind(emitter)
|
|
12
|
+
return emitter.eventNames.bind(emitter)
|
|
13
13
|
},
|
|
14
14
|
get listenerCount() {
|
|
15
|
-
return emitter.listenerCount.bind(emitter)
|
|
15
|
+
return emitter.listenerCount.bind(emitter)
|
|
16
16
|
},
|
|
17
17
|
get listeners() {
|
|
18
|
-
return emitter.listeners.bind(emitter)
|
|
18
|
+
return emitter.listeners.bind(emitter)
|
|
19
19
|
},
|
|
20
20
|
addListener: emitter.addListener.bind(emitter),
|
|
21
21
|
emit: emitter.emit.bind(emitter),
|
|
@@ -24,10 +24,10 @@ export function createEmitter(): Emitter {
|
|
|
24
24
|
once: emitter.once.bind(emitter),
|
|
25
25
|
removeAllListeners: emitter.removeAllListeners.bind(emitter),
|
|
26
26
|
removeListener: emitter.removeListener.bind(emitter),
|
|
27
|
-
}
|
|
27
|
+
}
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
const emitter = createEmitter()
|
|
30
|
+
const emitter = createEmitter()
|
|
31
31
|
|
|
32
32
|
export const sdk: FrameSDK = {
|
|
33
33
|
...emitter,
|
|
@@ -37,80 +37,94 @@ export const sdk: FrameSDK = {
|
|
|
37
37
|
ready: frameHost.ready.bind(frameHost),
|
|
38
38
|
close: frameHost.close.bind(frameHost),
|
|
39
39
|
signIn: async (options) => {
|
|
40
|
-
const response = await frameHost.signIn(options)
|
|
41
|
-
console.log(response);
|
|
40
|
+
const response = await frameHost.signIn(options)
|
|
42
41
|
if (response.result) {
|
|
43
|
-
return response.result
|
|
42
|
+
return response.result
|
|
44
43
|
}
|
|
45
44
|
|
|
46
|
-
if (response.error.type ===
|
|
47
|
-
throw new SignIn.RejectedByUser()
|
|
45
|
+
if (response.error.type === 'rejected_by_user') {
|
|
46
|
+
throw new SignIn.RejectedByUser()
|
|
48
47
|
}
|
|
49
48
|
|
|
50
|
-
throw new Error(
|
|
49
|
+
throw new Error('Unreachable')
|
|
51
50
|
},
|
|
52
51
|
openUrl: (url: string) => {
|
|
53
|
-
return frameHost.openUrl(url.trim())
|
|
52
|
+
return frameHost.openUrl(url.trim())
|
|
53
|
+
},
|
|
54
|
+
addFrame: async () => {
|
|
55
|
+
const response = await frameHost.addFrame()
|
|
56
|
+
if (response.result) {
|
|
57
|
+
return response.result
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (response.error.type === 'invalid_domain_manifest') {
|
|
61
|
+
throw new AddFrame.InvalidDomainManifest()
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (response.error.type === 'rejected_by_user') {
|
|
65
|
+
throw new AddFrame.RejectedByUser()
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
throw new Error('Unreachable')
|
|
54
69
|
},
|
|
55
|
-
addFrame: frameHost.addFrame.bind(frameHost),
|
|
56
70
|
},
|
|
57
71
|
wallet: {
|
|
58
72
|
ethProvider: provider,
|
|
59
73
|
},
|
|
60
|
-
}
|
|
74
|
+
}
|
|
61
75
|
|
|
62
76
|
// Required to pass SSR
|
|
63
|
-
if (typeof document !==
|
|
77
|
+
if (typeof document !== 'undefined') {
|
|
64
78
|
// react native webview events
|
|
65
|
-
document.addEventListener(
|
|
79
|
+
document.addEventListener('FarcasterFrameEvent', (event) => {
|
|
66
80
|
if (event instanceof MessageEvent) {
|
|
67
|
-
const frameEvent = event.data as FrameClientEvent
|
|
68
|
-
if (frameEvent.event ===
|
|
69
|
-
emitter.emit(
|
|
70
|
-
} else if (frameEvent.event ===
|
|
71
|
-
emitter.emit(
|
|
81
|
+
const frameEvent = event.data as FrameClientEvent
|
|
82
|
+
if (frameEvent.event === 'primary_button_clicked') {
|
|
83
|
+
emitter.emit('primaryButtonClicked')
|
|
84
|
+
} else if (frameEvent.event === 'frame_added') {
|
|
85
|
+
emitter.emit('frameAdded', {
|
|
72
86
|
notificationDetails: frameEvent.notificationDetails,
|
|
73
|
-
})
|
|
74
|
-
} else if (frameEvent.event ===
|
|
75
|
-
emitter.emit(
|
|
76
|
-
} else if (frameEvent.event ===
|
|
77
|
-
emitter.emit(
|
|
78
|
-
} else if (frameEvent.event ===
|
|
79
|
-
emitter.emit(
|
|
87
|
+
})
|
|
88
|
+
} else if (frameEvent.event === 'frame_add_rejected') {
|
|
89
|
+
emitter.emit('frameAddRejected', { reason: frameEvent.reason })
|
|
90
|
+
} else if (frameEvent.event === 'frame_removed') {
|
|
91
|
+
emitter.emit('frameRemoved')
|
|
92
|
+
} else if (frameEvent.event === 'notifications_enabled') {
|
|
93
|
+
emitter.emit('notificationsEnabled', {
|
|
80
94
|
notificationDetails: frameEvent.notificationDetails,
|
|
81
|
-
})
|
|
82
|
-
} else if (frameEvent.event ===
|
|
83
|
-
emitter.emit(
|
|
95
|
+
})
|
|
96
|
+
} else if (frameEvent.event === 'notifications_disabled') {
|
|
97
|
+
emitter.emit('notificationsDisabled')
|
|
84
98
|
}
|
|
85
99
|
}
|
|
86
|
-
})
|
|
100
|
+
})
|
|
87
101
|
}
|
|
88
102
|
|
|
89
103
|
// Required to pass SSR
|
|
90
|
-
if (typeof window !==
|
|
104
|
+
if (typeof window !== 'undefined') {
|
|
91
105
|
// web events
|
|
92
|
-
window.addEventListener(
|
|
106
|
+
window.addEventListener('message', (event) => {
|
|
93
107
|
if (event instanceof MessageEvent) {
|
|
94
|
-
if (event.data.type ===
|
|
95
|
-
const frameEvent = event.data.event as FrameClientEvent
|
|
96
|
-
if (frameEvent.event ===
|
|
97
|
-
emitter.emit(
|
|
98
|
-
} else if (frameEvent.event ===
|
|
99
|
-
emitter.emit(
|
|
108
|
+
if (event.data.type === 'frameEvent') {
|
|
109
|
+
const frameEvent = event.data.event as FrameClientEvent
|
|
110
|
+
if (frameEvent.event === 'primary_button_clicked') {
|
|
111
|
+
emitter.emit('primaryButtonClicked')
|
|
112
|
+
} else if (frameEvent.event === 'frame_added') {
|
|
113
|
+
emitter.emit('frameAdded', {
|
|
100
114
|
notificationDetails: frameEvent.notificationDetails,
|
|
101
|
-
})
|
|
102
|
-
} else if (frameEvent.event ===
|
|
103
|
-
emitter.emit(
|
|
104
|
-
} else if (frameEvent.event ===
|
|
105
|
-
emitter.emit(
|
|
106
|
-
} else if (frameEvent.event ===
|
|
107
|
-
emitter.emit(
|
|
115
|
+
})
|
|
116
|
+
} else if (frameEvent.event === 'frame_add_rejected') {
|
|
117
|
+
emitter.emit('frameAddRejected', { reason: frameEvent.reason })
|
|
118
|
+
} else if (frameEvent.event === 'frame_removed') {
|
|
119
|
+
emitter.emit('frameRemoved')
|
|
120
|
+
} else if (frameEvent.event === 'notifications_enabled') {
|
|
121
|
+
emitter.emit('notificationsEnabled', {
|
|
108
122
|
notificationDetails: frameEvent.notificationDetails,
|
|
109
|
-
})
|
|
110
|
-
} else if (frameEvent.event ===
|
|
111
|
-
emitter.emit(
|
|
123
|
+
})
|
|
124
|
+
} else if (frameEvent.event === 'notifications_disabled') {
|
|
125
|
+
emitter.emit('notificationsDisabled')
|
|
112
126
|
}
|
|
113
127
|
}
|
|
114
128
|
}
|
|
115
|
-
})
|
|
129
|
+
})
|
|
116
130
|
}
|
package/src/types.ts
CHANGED
|
@@ -1,64 +1,61 @@
|
|
|
1
|
-
import type { EventEmitter } from "eventemitter3";
|
|
2
|
-
import type { Provider } from "ox";
|
|
3
1
|
import type {
|
|
4
|
-
FrameContext,
|
|
5
2
|
AddFrame,
|
|
3
|
+
FrameContext,
|
|
4
|
+
FrameNotificationDetails,
|
|
6
5
|
ReadyOptions,
|
|
6
|
+
SetPrimaryButtonOptions,
|
|
7
7
|
SignIn,
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
} from
|
|
8
|
+
} from '@farcaster/frame-core'
|
|
9
|
+
import type { EventEmitter } from 'eventemitter3'
|
|
10
|
+
import type { Provider } from 'ox'
|
|
11
11
|
|
|
12
12
|
declare global {
|
|
13
13
|
interface Window {
|
|
14
14
|
// Exposed by react-native-webview
|
|
15
15
|
ReactNativeWebView: {
|
|
16
|
-
postMessage: (message: string) => void
|
|
17
|
-
}
|
|
16
|
+
postMessage: (message: string) => void
|
|
17
|
+
}
|
|
18
18
|
}
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
/** Combines members of an intersection into a readable type. */
|
|
22
22
|
// https://twitter.com/mattpocockuk/status/1622730173446557697?s=20&t=v01xkqU3KO0Mg
|
|
23
|
-
|
|
23
|
+
type Compute<type> = { [key in keyof type]: type[key] } & unknown
|
|
24
24
|
|
|
25
25
|
export type EventMap = {
|
|
26
|
-
primaryButtonClicked: () => void
|
|
26
|
+
primaryButtonClicked: () => void
|
|
27
27
|
frameAdded: ({
|
|
28
28
|
notificationDetails,
|
|
29
29
|
}: {
|
|
30
|
-
notificationDetails?: FrameNotificationDetails
|
|
31
|
-
}) => void
|
|
32
|
-
frameAddRejected: ({
|
|
33
|
-
|
|
30
|
+
notificationDetails?: FrameNotificationDetails
|
|
31
|
+
}) => void
|
|
32
|
+
frameAddRejected: ({
|
|
33
|
+
reason,
|
|
34
|
+
}: { reason: AddFrame.AddFrameRejectedReason }) => void
|
|
35
|
+
frameRemoved: () => void
|
|
34
36
|
notificationsEnabled: ({
|
|
35
37
|
notificationDetails,
|
|
36
38
|
}: {
|
|
37
|
-
notificationDetails: FrameNotificationDetails
|
|
38
|
-
}) => void
|
|
39
|
-
notificationsDisabled: () => void
|
|
40
|
-
}
|
|
39
|
+
notificationDetails: FrameNotificationDetails
|
|
40
|
+
}) => void
|
|
41
|
+
notificationsDisabled: () => void
|
|
42
|
+
}
|
|
41
43
|
|
|
42
|
-
export type Emitter = Compute<EventEmitter<EventMap
|
|
44
|
+
export type Emitter = Compute<EventEmitter<EventMap>>
|
|
43
45
|
|
|
44
|
-
|
|
45
|
-
text: string;
|
|
46
|
-
loading?: boolean;
|
|
47
|
-
disabled?: boolean;
|
|
48
|
-
hidden?: boolean;
|
|
49
|
-
}) => Promise<void>;
|
|
46
|
+
type SetPrimaryButton = (options: SetPrimaryButtonOptions) => Promise<void>
|
|
50
47
|
|
|
51
48
|
export type FrameSDK = {
|
|
52
|
-
context: Promise<FrameContext
|
|
49
|
+
context: Promise<FrameContext>
|
|
53
50
|
actions: {
|
|
54
|
-
ready: (options?: Partial<ReadyOptions>) => Promise<void
|
|
55
|
-
openUrl: (url: string) => Promise<void
|
|
56
|
-
signIn: SignIn.SignIn
|
|
57
|
-
close: () => Promise<void
|
|
58
|
-
setPrimaryButton: SetPrimaryButton
|
|
59
|
-
addFrame: AddFrame
|
|
60
|
-
}
|
|
51
|
+
ready: (options?: Partial<ReadyOptions>) => Promise<void>
|
|
52
|
+
openUrl: (url: string) => Promise<void>
|
|
53
|
+
signIn: SignIn.SignIn
|
|
54
|
+
close: () => Promise<void>
|
|
55
|
+
setPrimaryButton: SetPrimaryButton
|
|
56
|
+
addFrame: AddFrame.AddFrame
|
|
57
|
+
}
|
|
61
58
|
wallet: {
|
|
62
|
-
ethProvider: Provider.Provider
|
|
63
|
-
}
|
|
64
|
-
} & Emitter
|
|
59
|
+
ethProvider: Provider.Provider
|
|
60
|
+
}
|
|
61
|
+
} & Emitter
|