@farcaster/frame-node 0.0.17 → 0.0.18
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/LICENSE +21 -0
- package/esm/farcaster.d.ts +29 -19
- package/esm/farcaster.js +57 -49
- package/esm/index.d.ts +7 -7
- package/esm/index.js +7 -7
- package/esm/jfs.d.ts +33 -16
- package/esm/jfs.js +93 -74
- package/esm/neynar.d.ts +2 -2
- package/esm/neynar.js +14 -12
- package/esm/types.d.ts +27 -20
- package/esm/types.js +6 -6
- package/esm/util.d.ts +2 -2
- package/esm/util.js +4 -2
- package/esm/webhook.d.ts +17 -6
- package/esm/webhook.js +23 -18
- package/package.json +8 -2
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024-present Merkle Manufactory Inc.
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/esm/farcaster.d.ts
CHANGED
|
@@ -1,19 +1,29 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export declare const signedKeyRequestAbi: readonly [
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
readonly
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
readonly name:
|
|
11
|
-
readonly type:
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
readonly
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
1
|
+
import type { VerifyAppKey } from './types'
|
|
2
|
+
export declare const signedKeyRequestAbi: readonly [
|
|
3
|
+
{
|
|
4
|
+
readonly components: readonly [
|
|
5
|
+
{
|
|
6
|
+
readonly name: 'requestFid'
|
|
7
|
+
readonly type: 'uint256'
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
readonly name: 'requestSigner'
|
|
11
|
+
readonly type: 'address'
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
readonly name: 'signature'
|
|
15
|
+
readonly type: 'bytes'
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
readonly name: 'deadline'
|
|
19
|
+
readonly type: 'uint256'
|
|
20
|
+
},
|
|
21
|
+
]
|
|
22
|
+
readonly name: 'SignedKeyRequest'
|
|
23
|
+
readonly type: 'tuple'
|
|
24
|
+
},
|
|
25
|
+
]
|
|
26
|
+
export declare const createVerifyAppKeyWithHub: (
|
|
27
|
+
hubUrl: string,
|
|
28
|
+
requestOptions?: RequestInit,
|
|
29
|
+
) => VerifyAppKey
|
package/esm/farcaster.js
CHANGED
|
@@ -1,59 +1,67 @@
|
|
|
1
|
-
import { AbiParameters } from 'ox'
|
|
2
|
-
import { z } from 'zod'
|
|
3
|
-
import { BaseError } from './types'
|
|
1
|
+
import { AbiParameters } from 'ox'
|
|
2
|
+
import { z } from 'zod'
|
|
3
|
+
import { BaseError } from './types'
|
|
4
4
|
export const signedKeyRequestAbi = [
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
]
|
|
5
|
+
{
|
|
6
|
+
components: [
|
|
7
|
+
{
|
|
8
|
+
name: 'requestFid',
|
|
9
|
+
type: 'uint256',
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
name: 'requestSigner',
|
|
13
|
+
type: 'address',
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
name: 'signature',
|
|
17
|
+
type: 'bytes',
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
name: 'deadline',
|
|
21
|
+
type: 'uint256',
|
|
22
|
+
},
|
|
23
|
+
],
|
|
24
|
+
name: 'SignedKeyRequest',
|
|
25
|
+
type: 'tuple',
|
|
26
|
+
},
|
|
27
|
+
]
|
|
28
28
|
const hubResponseSchema = z.object({
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
})
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
29
|
+
events: z.array(
|
|
30
|
+
z.object({
|
|
31
|
+
signerEventBody: z.object({
|
|
32
|
+
key: z.string(),
|
|
33
|
+
metadata: z.string(),
|
|
34
|
+
}),
|
|
35
|
+
}),
|
|
36
|
+
),
|
|
37
|
+
})
|
|
38
|
+
export const createVerifyAppKeyWithHub =
|
|
39
|
+
(hubUrl, requestOptions) => async (fid, appKey) => {
|
|
40
|
+
const url = new URL('/v1/onChainSignersByFid', hubUrl)
|
|
41
|
+
url.searchParams.append('fid', fid.toString())
|
|
42
|
+
const response = await fetch(url, requestOptions)
|
|
40
43
|
if (response.status !== 200) {
|
|
41
|
-
|
|
44
|
+
throw new BaseError(`Non-200 response received: ${await response.text()}`)
|
|
42
45
|
}
|
|
43
|
-
const responseJson = await response.json()
|
|
44
|
-
const parsedResponse = hubResponseSchema.safeParse(responseJson)
|
|
46
|
+
const responseJson = await response.json()
|
|
47
|
+
const parsedResponse = hubResponseSchema.safeParse(responseJson)
|
|
45
48
|
if (parsedResponse.error) {
|
|
46
|
-
|
|
49
|
+
throw new BaseError('Error parsing Hub response', parsedResponse.error)
|
|
47
50
|
}
|
|
48
|
-
const appKeyLower = appKey.toLowerCase()
|
|
49
|
-
const signerEvent = parsedResponse.data.events.find(
|
|
51
|
+
const appKeyLower = appKey.toLowerCase()
|
|
52
|
+
const signerEvent = parsedResponse.data.events.find(
|
|
53
|
+
(event) => event.signerEventBody.key.toLowerCase() === appKeyLower,
|
|
54
|
+
)
|
|
50
55
|
if (!signerEvent) {
|
|
51
|
-
|
|
56
|
+
return { valid: false }
|
|
52
57
|
}
|
|
53
|
-
const decoded = AbiParameters.decode(
|
|
58
|
+
const decoded = AbiParameters.decode(
|
|
59
|
+
signedKeyRequestAbi,
|
|
60
|
+
Buffer.from(signerEvent.signerEventBody.metadata, 'base64'),
|
|
61
|
+
)
|
|
54
62
|
if (decoded.length !== 1) {
|
|
55
|
-
|
|
63
|
+
throw new BaseError('Error decoding metadata')
|
|
56
64
|
}
|
|
57
|
-
const appFid = Number(decoded[0].requestFid)
|
|
58
|
-
return { valid: true, appFid }
|
|
59
|
-
}
|
|
65
|
+
const appFid = Number(decoded[0].requestFid)
|
|
66
|
+
return { valid: true, appFid }
|
|
67
|
+
}
|
package/esm/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
export * from '@farcaster/frame-core'
|
|
2
|
-
export * from './jfs'
|
|
3
|
-
export * from './neynar'
|
|
4
|
-
export * from './farcaster'
|
|
5
|
-
export * from './types'
|
|
6
|
-
export * from './webhook'
|
|
7
|
-
export * from './util'
|
|
1
|
+
export * from '@farcaster/frame-core'
|
|
2
|
+
export * from './jfs'
|
|
3
|
+
export * from './neynar'
|
|
4
|
+
export * from './farcaster'
|
|
5
|
+
export * from './types'
|
|
6
|
+
export * from './webhook'
|
|
7
|
+
export * from './util'
|
package/esm/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
export * from '@farcaster/frame-core'
|
|
2
|
-
export * from './jfs'
|
|
3
|
-
export * from './neynar'
|
|
4
|
-
export * from './farcaster'
|
|
5
|
-
export * from './types'
|
|
6
|
-
export * from './webhook'
|
|
7
|
-
export * from './util'
|
|
1
|
+
export * from '@farcaster/frame-core'
|
|
2
|
+
export * from './jfs'
|
|
3
|
+
export * from './neynar'
|
|
4
|
+
export * from './farcaster'
|
|
5
|
+
export * from './types'
|
|
6
|
+
export * from './webhook'
|
|
7
|
+
export * from './util'
|
package/esm/jfs.d.ts
CHANGED
|
@@ -1,21 +1,38 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { BaseError, type VerifyAppKey, type VerifyJfsResult } from './types'
|
|
1
|
+
import type { EncodedJsonFarcasterSignatureSchema } from '@farcaster/frame-core'
|
|
2
|
+
import { BaseError, type VerifyAppKey, type VerifyJfsResult } from './types'
|
|
3
3
|
export declare namespace VerifyJsonFarcasterSignature {
|
|
4
|
-
|
|
4
|
+
type ErrorType =
|
|
5
|
+
| InvalidJfsDataError
|
|
6
|
+
| InvalidJfsAppKeyError
|
|
7
|
+
| VerifyAppKeyError
|
|
5
8
|
}
|
|
6
|
-
export declare class InvalidJfsDataError<
|
|
7
|
-
|
|
9
|
+
export declare class InvalidJfsDataError<
|
|
10
|
+
C extends Error | undefined = undefined,
|
|
11
|
+
> extends BaseError<C> {
|
|
12
|
+
readonly name = 'VerifyJsonFarcasterSignature.InvalidDataError'
|
|
8
13
|
}
|
|
9
|
-
export declare class InvalidJfsAppKeyError<
|
|
10
|
-
|
|
14
|
+
export declare class InvalidJfsAppKeyError<
|
|
15
|
+
C extends Error | undefined = undefined,
|
|
16
|
+
> extends BaseError<C> {
|
|
17
|
+
readonly name = 'VerifyJsonFarcasterSignature.InvalidAppKeyError'
|
|
11
18
|
}
|
|
12
|
-
export declare class VerifyAppKeyError<
|
|
13
|
-
|
|
19
|
+
export declare class VerifyAppKeyError<
|
|
20
|
+
C extends Error | undefined = undefined,
|
|
21
|
+
> extends BaseError<C> {
|
|
22
|
+
readonly name = 'VerifyJsonFarcasterSignature.VerifyAppKeyError'
|
|
14
23
|
}
|
|
15
|
-
export declare function verifyJsonFarcasterSignature(
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
24
|
+
export declare function verifyJsonFarcasterSignature(
|
|
25
|
+
data: unknown,
|
|
26
|
+
verifyAppKey: VerifyAppKey,
|
|
27
|
+
): Promise<VerifyJfsResult>
|
|
28
|
+
export declare function createJsonFarcasterSignature({
|
|
29
|
+
fid,
|
|
30
|
+
type,
|
|
31
|
+
privateKey,
|
|
32
|
+
payload,
|
|
33
|
+
}: {
|
|
34
|
+
fid: number
|
|
35
|
+
type: 'app_key'
|
|
36
|
+
privateKey: Uint8Array
|
|
37
|
+
payload: Uint8Array
|
|
38
|
+
}): EncodedJsonFarcasterSignatureSchema
|
package/esm/jfs.js
CHANGED
|
@@ -1,83 +1,102 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import {
|
|
2
|
+
encodedJsonFarcasterSignatureSchema,
|
|
3
|
+
jsonFarcasterSignatureHeaderSchema,
|
|
4
|
+
} from '@farcaster/frame-core'
|
|
5
|
+
import { ed25519 } from '@noble/curves/ed25519'
|
|
6
|
+
import { BaseError } from './types'
|
|
7
|
+
import { bytesToHex, hexToBytes } from './util'
|
|
5
8
|
export class InvalidJfsDataError extends BaseError {
|
|
6
|
-
|
|
9
|
+
name = 'VerifyJsonFarcasterSignature.InvalidDataError'
|
|
7
10
|
}
|
|
8
11
|
export class InvalidJfsAppKeyError extends BaseError {
|
|
9
|
-
|
|
12
|
+
name = 'VerifyJsonFarcasterSignature.InvalidAppKeyError'
|
|
10
13
|
}
|
|
11
14
|
export class VerifyAppKeyError extends BaseError {
|
|
12
|
-
|
|
15
|
+
name = 'VerifyJsonFarcasterSignature.VerifyAppKeyError'
|
|
13
16
|
}
|
|
14
17
|
export async function verifyJsonFarcasterSignature(data, verifyAppKey) {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
18
|
+
//
|
|
19
|
+
// Parse, decode and validate data
|
|
20
|
+
//
|
|
21
|
+
const body = encodedJsonFarcasterSignatureSchema.safeParse(data)
|
|
22
|
+
if (body.success === false) {
|
|
23
|
+
throw new InvalidJfsDataError('Error parsing data', body.error)
|
|
24
|
+
}
|
|
25
|
+
let headerData
|
|
26
|
+
try {
|
|
27
|
+
headerData = JSON.parse(
|
|
28
|
+
Buffer.from(body.data.header, 'base64url').toString('utf-8'),
|
|
29
|
+
)
|
|
30
|
+
} catch (error) {
|
|
31
|
+
throw new InvalidJfsDataError('Error decoding and parsing header')
|
|
32
|
+
}
|
|
33
|
+
const header = jsonFarcasterSignatureHeaderSchema.safeParse(headerData)
|
|
34
|
+
if (header.success === false) {
|
|
35
|
+
throw new InvalidJfsDataError('Error parsing header', header.error)
|
|
36
|
+
}
|
|
37
|
+
const payload = Buffer.from(body.data.payload, 'base64url')
|
|
38
|
+
const signature = Buffer.from(body.data.signature, 'base64url')
|
|
39
|
+
if (signature.byteLength !== 64) {
|
|
40
|
+
throw new InvalidJfsDataError('Invalid signature length')
|
|
41
|
+
}
|
|
42
|
+
//
|
|
43
|
+
// Verify the signature
|
|
44
|
+
//
|
|
45
|
+
const fid = header.data.fid
|
|
46
|
+
const appKey = header.data.key
|
|
47
|
+
const appKeyBytes = hexToBytes(appKey)
|
|
48
|
+
const signedInput = new Uint8Array(
|
|
49
|
+
Buffer.from(body.data.header + '.' + body.data.payload),
|
|
50
|
+
)
|
|
51
|
+
let verifyResult
|
|
52
|
+
try {
|
|
53
|
+
verifyResult = ed25519.verify(signature, signedInput, appKeyBytes)
|
|
54
|
+
} catch (e) {
|
|
55
|
+
throw new InvalidJfsDataError(
|
|
56
|
+
'Error checking signature',
|
|
57
|
+
e instanceof Error ? e : undefined,
|
|
58
|
+
)
|
|
59
|
+
}
|
|
60
|
+
if (!verifyResult) {
|
|
61
|
+
throw new InvalidJfsDataError('Invalid signature')
|
|
62
|
+
}
|
|
63
|
+
//
|
|
64
|
+
// Verify that the app key belongs to the FID
|
|
65
|
+
//
|
|
66
|
+
let appKeyResult
|
|
67
|
+
try {
|
|
68
|
+
appKeyResult = await verifyAppKey(fid, appKey)
|
|
69
|
+
} catch (error) {
|
|
70
|
+
throw new VerifyAppKeyError(
|
|
71
|
+
'Error verifying app key',
|
|
72
|
+
error instanceof Error ? error : undefined,
|
|
73
|
+
)
|
|
74
|
+
}
|
|
75
|
+
if (!appKeyResult.valid) {
|
|
76
|
+
throw new InvalidJfsAppKeyError('App key not valid for FID')
|
|
77
|
+
}
|
|
78
|
+
return { fid, appFid: appKeyResult.appFid, payload }
|
|
69
79
|
}
|
|
70
|
-
export function createJsonFarcasterSignature({
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
80
|
+
export function createJsonFarcasterSignature({
|
|
81
|
+
fid,
|
|
82
|
+
type,
|
|
83
|
+
privateKey,
|
|
84
|
+
payload,
|
|
85
|
+
}) {
|
|
86
|
+
const publicKey = ed25519.getPublicKey(privateKey)
|
|
87
|
+
const header = { fid, type, key: bytesToHex(publicKey) }
|
|
88
|
+
const encodedHeader = Buffer.from(JSON.stringify(header)).toString(
|
|
89
|
+
'base64url',
|
|
90
|
+
)
|
|
91
|
+
const encodedPayload = Buffer.from(payload).toString('base64url')
|
|
92
|
+
const signatureInput = new Uint8Array(
|
|
93
|
+
Buffer.from(encodedHeader + '.' + encodedPayload, 'utf-8'),
|
|
94
|
+
)
|
|
95
|
+
const signature = ed25519.sign(signatureInput, privateKey)
|
|
96
|
+
const encodedSignature = Buffer.from(signature).toString('base64url')
|
|
97
|
+
return {
|
|
98
|
+
header: encodedHeader,
|
|
99
|
+
payload: encodedPayload,
|
|
100
|
+
signature: encodedSignature,
|
|
101
|
+
}
|
|
83
102
|
}
|
package/esm/neynar.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import type { VerifyAppKey } from './types'
|
|
2
|
-
export declare const verifyAppKeyWithNeynar: VerifyAppKey
|
|
1
|
+
import type { VerifyAppKey } from './types'
|
|
2
|
+
export declare const verifyAppKeyWithNeynar: VerifyAppKey
|
package/esm/neynar.js
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
|
-
import { createVerifyAppKeyWithHub } from './farcaster'
|
|
2
|
-
const apiKey = process.env.NEYNAR_API_KEY || ''
|
|
1
|
+
import { createVerifyAppKeyWithHub } from './farcaster'
|
|
2
|
+
const apiKey = process.env.NEYNAR_API_KEY || ''
|
|
3
3
|
export const verifyAppKeyWithNeynar = async (fid, appKey) => {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
}
|
|
4
|
+
if (!apiKey) {
|
|
5
|
+
throw new Error(
|
|
6
|
+
'Environment variable NEYNAR_API_KEY needs to be set to use Neynar for app key verification',
|
|
7
|
+
)
|
|
8
|
+
}
|
|
9
|
+
const verifier = createVerifyAppKeyWithHub('https://hub-api.neynar.com', {
|
|
10
|
+
headers: {
|
|
11
|
+
'x-api-key': apiKey,
|
|
12
|
+
},
|
|
13
|
+
})
|
|
14
|
+
return verifier(fid, appKey)
|
|
15
|
+
}
|
package/esm/types.d.ts
CHANGED
|
@@ -1,23 +1,30 @@
|
|
|
1
|
-
import type { FrameServerEvent } from '@farcaster/frame-core'
|
|
2
|
-
export type VerifyAppKeyResult =
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
1
|
+
import type { FrameServerEvent } from '@farcaster/frame-core'
|
|
2
|
+
export type VerifyAppKeyResult =
|
|
3
|
+
| {
|
|
4
|
+
valid: true
|
|
5
|
+
appFid: number
|
|
6
|
+
}
|
|
7
|
+
| {
|
|
8
|
+
valid: false
|
|
9
|
+
}
|
|
10
|
+
export type VerifyAppKey = (
|
|
11
|
+
fid: number,
|
|
12
|
+
appKey: string,
|
|
13
|
+
) => Promise<VerifyAppKeyResult>
|
|
9
14
|
export type VerifyJfsResult = {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
}
|
|
15
|
+
fid: number
|
|
16
|
+
appFid: number
|
|
17
|
+
payload: Uint8Array
|
|
18
|
+
}
|
|
14
19
|
export type ParseWebhookEventResult = {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
}
|
|
19
|
-
export declare class BaseError<
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
fid: number
|
|
21
|
+
appFid: number
|
|
22
|
+
event: FrameServerEvent
|
|
23
|
+
}
|
|
24
|
+
export declare class BaseError<
|
|
25
|
+
C extends Error | undefined = undefined,
|
|
26
|
+
> extends Error {
|
|
27
|
+
name: string
|
|
28
|
+
cause: C
|
|
29
|
+
constructor(message: string, cause?: C)
|
|
23
30
|
}
|
package/esm/types.js
CHANGED
package/esm/util.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare function bytesToHex(bytes: Uint8Array): string
|
|
2
|
-
export declare function hexToBytes(hex: string): Uint8Array
|
|
1
|
+
export declare function bytesToHex(bytes: Uint8Array): string
|
|
2
|
+
export declare function hexToBytes(hex: string): Uint8Array
|
package/esm/util.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
export function bytesToHex(bytes) {
|
|
2
|
-
|
|
2
|
+
return `0x${Buffer.from(bytes).toString('hex')}`
|
|
3
3
|
}
|
|
4
4
|
export function hexToBytes(hex) {
|
|
5
|
-
|
|
5
|
+
return Uint8Array.from(
|
|
6
|
+
Buffer.from(hex.startsWith('0x') ? hex.slice(2) : hex, 'hex'),
|
|
7
|
+
)
|
|
6
8
|
}
|
package/esm/webhook.d.ts
CHANGED
|
@@ -1,9 +1,20 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import type { VerifyJsonFarcasterSignature } from './jfs'
|
|
2
|
+
import {
|
|
3
|
+
BaseError,
|
|
4
|
+
type ParseWebhookEventResult,
|
|
5
|
+
type VerifyAppKey,
|
|
6
|
+
} from './types'
|
|
3
7
|
export declare namespace ParseWebhookEvent {
|
|
4
|
-
|
|
8
|
+
type ErrorType =
|
|
9
|
+
| VerifyJsonFarcasterSignature.ErrorType
|
|
10
|
+
| InvalidEventDataError
|
|
5
11
|
}
|
|
6
|
-
export declare class InvalidEventDataError<
|
|
7
|
-
|
|
12
|
+
export declare class InvalidEventDataError<
|
|
13
|
+
C extends Error | undefined = undefined,
|
|
14
|
+
> extends BaseError<C> {
|
|
15
|
+
readonly name = 'VerifyJsonFarcasterSignature.InvalidEventDataError'
|
|
8
16
|
}
|
|
9
|
-
export declare function parseWebhookEvent(
|
|
17
|
+
export declare function parseWebhookEvent(
|
|
18
|
+
rawData: unknown,
|
|
19
|
+
verifyAppKey: VerifyAppKey,
|
|
20
|
+
): Promise<ParseWebhookEventResult>
|
package/esm/webhook.js
CHANGED
|
@@ -1,22 +1,27 @@
|
|
|
1
|
-
import { serverEventSchema } from '@farcaster/frame-core'
|
|
2
|
-
import { verifyJsonFarcasterSignature
|
|
3
|
-
import { BaseError
|
|
1
|
+
import { serverEventSchema } from '@farcaster/frame-core'
|
|
2
|
+
import { verifyJsonFarcasterSignature } from './jfs'
|
|
3
|
+
import { BaseError } from './types'
|
|
4
4
|
export class InvalidEventDataError extends BaseError {
|
|
5
|
-
|
|
5
|
+
name = 'VerifyJsonFarcasterSignature.InvalidEventDataError'
|
|
6
6
|
}
|
|
7
7
|
export async function parseWebhookEvent(rawData, verifyAppKey) {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
8
|
+
const { fid, appFid, payload } = await verifyJsonFarcasterSignature(
|
|
9
|
+
rawData,
|
|
10
|
+
verifyAppKey,
|
|
11
|
+
)
|
|
12
|
+
// Pase and validate event payload
|
|
13
|
+
let payloadJson
|
|
14
|
+
try {
|
|
15
|
+
payloadJson = JSON.parse(Buffer.from(payload).toString('utf-8'))
|
|
16
|
+
} catch (error) {
|
|
17
|
+
throw new InvalidEventDataError(
|
|
18
|
+
'Error decoding and parsing payload',
|
|
19
|
+
error instanceof Error ? error : undefined,
|
|
20
|
+
)
|
|
21
|
+
}
|
|
22
|
+
const event = serverEventSchema.safeParse(payloadJson)
|
|
23
|
+
if (event.success === false) {
|
|
24
|
+
throw new InvalidEventDataError('Invalid event payload', event.error)
|
|
25
|
+
}
|
|
26
|
+
return { fid, appFid, event: event.data }
|
|
22
27
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@farcaster/frame-node",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.18",
|
|
4
|
+
"license": "MIT",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "https://github.com/farcasterxyz/frames.git",
|
|
8
|
+
"directory": "packages/frame-node"
|
|
9
|
+
},
|
|
4
10
|
"main": "dist/index.js",
|
|
5
11
|
"module": "esm/index.js",
|
|
6
12
|
"files": [
|
|
@@ -19,7 +25,7 @@
|
|
|
19
25
|
"@noble/curves": "^1.7.0",
|
|
20
26
|
"ox": "^0.4.4",
|
|
21
27
|
"zod": "^3.24.1",
|
|
22
|
-
"@farcaster/frame-core": "0.0.
|
|
28
|
+
"@farcaster/frame-core": "0.0.29"
|
|
23
29
|
},
|
|
24
30
|
"publishConfig": {
|
|
25
31
|
"access": "public"
|