@farcaster/snap 2.9.0 → 2.10.0
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 +1 -1
- package/dist/index.js +1 -1
- package/dist/react/catalog-renderer.d.ts +5 -5
- package/dist/react/catalog-renderer.js +16 -4
- package/dist/react/components/action-button.js +23 -5
- package/dist/react/index.d.ts +2 -1
- package/dist/react/snap-view-core.js +90 -25
- package/dist/react/v1/snap-view.js +1 -1
- package/dist/react/v2/snap-view.js +1 -1
- package/dist/react-native/components/snap-action-button.js +6 -1
- package/dist/react-native/snap-view-core.js +77 -24
- package/dist/react-native/types.d.ts +2 -1
- package/dist/render-state.d.ts +9 -0
- package/dist/render-state.js +27 -0
- package/dist/schemas.d.ts +123 -3
- package/dist/schemas.js +53 -2
- package/dist/server/parseRequest.js +19 -3
- package/dist/ui/button.d.ts +1 -0
- package/dist/ui/button.js +1 -0
- package/dist/ui/catalog.d.ts +13 -0
- package/dist/ui/catalog.js +15 -8
- package/package.json +1 -1
- package/src/index.ts +7 -0
- package/src/react/catalog-renderer.tsx +57 -3
- package/src/react/components/action-button.tsx +32 -3
- package/src/react/index.tsx +4 -1
- package/src/react/snap-view-core.tsx +144 -27
- package/src/react/v1/snap-view.tsx +1 -0
- package/src/react/v2/snap-view.tsx +1 -0
- package/src/react-native/components/snap-action-button.tsx +6 -1
- package/src/react-native/snap-view-core.tsx +114 -27
- package/src/react-native/types.ts +4 -1
- package/src/render-state.ts +46 -0
- package/src/schemas.ts +73 -2
- package/src/server/parseRequest.ts +37 -6
- package/src/ui/button.ts +1 -0
- package/src/ui/catalog.ts +16 -8
package/dist/render-state.d.ts
CHANGED
|
@@ -5,6 +5,15 @@ export type SnapRenderStateChanges = {
|
|
|
5
5
|
}[] | Record<string, unknown> | null | undefined;
|
|
6
6
|
export declare function cloneSnapRenderState<T>(value: T): T;
|
|
7
7
|
export declare function applyStatePaths(model: Record<string, unknown>, changes: SnapRenderStateChanges): void;
|
|
8
|
+
export declare function buildActionActivityStateChanges({ actionName, params, pending, }: {
|
|
9
|
+
actionName: unknown;
|
|
10
|
+
params: Record<string, unknown>;
|
|
11
|
+
pending: boolean;
|
|
12
|
+
}): {
|
|
13
|
+
path: string;
|
|
14
|
+
value: unknown;
|
|
15
|
+
}[];
|
|
16
|
+
export declare function hasPendingSnapAction(model: SnapRenderState): boolean;
|
|
8
17
|
export declare function getUnpresentedSnapEffects(model: SnapRenderState, effects: readonly string[] | undefined): string[];
|
|
9
18
|
export declare function markSnapEffectsPresented(model: SnapRenderState, effects: readonly string[] | undefined): boolean;
|
|
10
19
|
export declare function buildInitialRenderState({ specState, initialRenderState, themeAccent, }: {
|
package/dist/render-state.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const SNAP_RENDER_STATE_META_KEY = "__snapRender";
|
|
2
|
+
const ACTION_ACTIVITY_KEY_MAX_LENGTH = 64;
|
|
2
3
|
function isRecord(value) {
|
|
3
4
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
4
5
|
}
|
|
@@ -75,6 +76,32 @@ export function applyStatePaths(model, changes) {
|
|
|
75
76
|
setStateValue(model, parts, value);
|
|
76
77
|
}
|
|
77
78
|
}
|
|
79
|
+
function sanitizeActionActivityKey(value) {
|
|
80
|
+
const sanitized = value
|
|
81
|
+
.trim()
|
|
82
|
+
.slice(0, ACTION_ACTIVITY_KEY_MAX_LENGTH)
|
|
83
|
+
.replace(/[^A-Za-z0-9_.-]/g, "_");
|
|
84
|
+
return sanitized || "action";
|
|
85
|
+
}
|
|
86
|
+
function getActionActivityKey(actionName, params) {
|
|
87
|
+
const explicitKey = params.activityKey;
|
|
88
|
+
return sanitizeActionActivityKey(typeof explicitKey === "string" && explicitKey.trim()
|
|
89
|
+
? explicitKey
|
|
90
|
+
: String(actionName || "action"));
|
|
91
|
+
}
|
|
92
|
+
export function buildActionActivityStateChanges({ actionName, params, pending, }) {
|
|
93
|
+
const key = getActionActivityKey(actionName, params);
|
|
94
|
+
return [
|
|
95
|
+
{ path: `/actions/${key}/name`, value: String(actionName || "action") },
|
|
96
|
+
{ path: `/actions/${key}/pending`, value: pending },
|
|
97
|
+
];
|
|
98
|
+
}
|
|
99
|
+
export function hasPendingSnapAction(model) {
|
|
100
|
+
const actions = model.actions;
|
|
101
|
+
if (!isRecord(actions))
|
|
102
|
+
return false;
|
|
103
|
+
return Object.values(actions).some((action) => isRecord(action) && action.pending === true);
|
|
104
|
+
}
|
|
78
105
|
export function getUnpresentedSnapEffects(model, effects) {
|
|
79
106
|
const presentedEffects = getPresentedSnapEffects(model);
|
|
80
107
|
return normalizeEffects(effects).filter((effect) => !presentedEffects.has(effect));
|
package/dist/schemas.d.ts
CHANGED
|
@@ -69,9 +69,34 @@ export type SnapHandlerResult = {
|
|
|
69
69
|
effects?: z.input<typeof snapResponseSchema>["effects"];
|
|
70
70
|
ui: SnapSpecInput;
|
|
71
71
|
};
|
|
72
|
+
declare const snapSendTransactionParamsSchema: z.ZodObject<{
|
|
73
|
+
chainId: z.ZodString;
|
|
74
|
+
to: z.ZodString;
|
|
75
|
+
data: z.ZodOptional<z.ZodString>;
|
|
76
|
+
value: z.ZodOptional<z.ZodString>;
|
|
77
|
+
gas: z.ZodOptional<z.ZodString>;
|
|
78
|
+
gasPrice: z.ZodOptional<z.ZodString>;
|
|
79
|
+
maxFeePerGas: z.ZodOptional<z.ZodString>;
|
|
80
|
+
maxPriorityFeePerGas: z.ZodOptional<z.ZodString>;
|
|
81
|
+
}, z.core.$strict>;
|
|
82
|
+
export type SnapSendTransactionParams = z.infer<typeof snapSendTransactionParamsSchema>;
|
|
83
|
+
export declare const snapTransactionResultSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
84
|
+
success: z.ZodLiteral<true>;
|
|
85
|
+
transactionHash: z.ZodString;
|
|
86
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
87
|
+
success: z.ZodLiteral<false>;
|
|
88
|
+
reason: z.ZodDefault<z.ZodOptional<z.ZodEnum<{
|
|
89
|
+
unknown: "unknown";
|
|
90
|
+
rejected_by_user: "rejected_by_user";
|
|
91
|
+
failed: "failed";
|
|
92
|
+
}>>>;
|
|
93
|
+
message: z.ZodOptional<z.ZodString>;
|
|
94
|
+
code: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>;
|
|
95
|
+
transactionHash: z.ZodOptional<z.ZodString>;
|
|
96
|
+
}, z.core.$strict>], "success">;
|
|
97
|
+
export type SnapTransactionResult = z.infer<typeof snapTransactionResultSchema>;
|
|
72
98
|
export declare const payloadSchema: z.ZodObject<{
|
|
73
99
|
fid: z.ZodOptional<z.ZodNumber>;
|
|
74
|
-
inputs: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodArray<z.ZodString>]>>>;
|
|
75
100
|
timestamp: z.ZodNumber;
|
|
76
101
|
audience: z.ZodString;
|
|
77
102
|
user: z.ZodObject<{
|
|
@@ -88,6 +113,7 @@ export declare const payloadSchema: z.ZodObject<{
|
|
|
88
113
|
}, z.core.$strip>, z.ZodObject<{
|
|
89
114
|
type: z.ZodLiteral<"standalone">;
|
|
90
115
|
}, z.core.$strip>], "type">;
|
|
116
|
+
inputs: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodArray<z.ZodString>]>>>;
|
|
91
117
|
}, z.core.$strip>;
|
|
92
118
|
export type SnapPayload = z.infer<typeof payloadSchema>;
|
|
93
119
|
/** JFS payload shape for POST minus deprecated `fid`; used for GET auth via payload header. */
|
|
@@ -112,6 +138,7 @@ export declare const getPayloadSchema: z.ZodObject<{
|
|
|
112
138
|
export type SnapGetPayload = z.infer<typeof getPayloadSchema>;
|
|
113
139
|
export declare const ACTION_TYPE_GET: "get";
|
|
114
140
|
export declare const ACTION_TYPE_POST: "post";
|
|
141
|
+
export declare const ACTION_TYPE_TRANSACTION_RESULT: "transaction_result";
|
|
115
142
|
declare const snapGetActionSchema: z.ZodObject<{
|
|
116
143
|
type: z.ZodLiteral<"get">;
|
|
117
144
|
user: z.ZodOptional<z.ZodObject<{
|
|
@@ -134,7 +161,6 @@ declare const snapGetActionSchema: z.ZodObject<{
|
|
|
134
161
|
export type SnapGetAction = z.infer<typeof snapGetActionSchema>;
|
|
135
162
|
declare const snapPostActionSchema: z.ZodObject<{
|
|
136
163
|
fid: z.ZodOptional<z.ZodNumber>;
|
|
137
|
-
inputs: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodArray<z.ZodString>]>>>;
|
|
138
164
|
timestamp: z.ZodNumber;
|
|
139
165
|
audience: z.ZodString;
|
|
140
166
|
user: z.ZodObject<{
|
|
@@ -151,9 +177,58 @@ declare const snapPostActionSchema: z.ZodObject<{
|
|
|
151
177
|
}, z.core.$strip>, z.ZodObject<{
|
|
152
178
|
type: z.ZodLiteral<"standalone">;
|
|
153
179
|
}, z.core.$strip>], "type">;
|
|
180
|
+
inputs: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodArray<z.ZodString>]>>>;
|
|
154
181
|
type: z.ZodLiteral<"post">;
|
|
155
182
|
}, z.core.$strip>;
|
|
156
183
|
export type SnapPostAction = z.infer<typeof snapPostActionSchema>;
|
|
184
|
+
export declare const transactionResultPayloadSchema: z.ZodObject<{
|
|
185
|
+
fid: z.ZodOptional<z.ZodNumber>;
|
|
186
|
+
timestamp: z.ZodNumber;
|
|
187
|
+
audience: z.ZodString;
|
|
188
|
+
user: z.ZodObject<{
|
|
189
|
+
fid: z.ZodNumber;
|
|
190
|
+
}, z.core.$strip>;
|
|
191
|
+
surface: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
192
|
+
type: z.ZodLiteral<"cast">;
|
|
193
|
+
cast: z.ZodObject<{
|
|
194
|
+
hash: z.ZodString;
|
|
195
|
+
author: z.ZodObject<{
|
|
196
|
+
fid: z.ZodNumber;
|
|
197
|
+
}, z.core.$strip>;
|
|
198
|
+
}, z.core.$strip>;
|
|
199
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
200
|
+
type: z.ZodLiteral<"standalone">;
|
|
201
|
+
}, z.core.$strip>], "type">;
|
|
202
|
+
type: z.ZodLiteral<"transaction_result">;
|
|
203
|
+
transaction: z.ZodObject<{
|
|
204
|
+
request: z.ZodObject<{
|
|
205
|
+
chainId: z.ZodString;
|
|
206
|
+
to: z.ZodString;
|
|
207
|
+
data: z.ZodOptional<z.ZodString>;
|
|
208
|
+
value: z.ZodOptional<z.ZodString>;
|
|
209
|
+
gas: z.ZodOptional<z.ZodString>;
|
|
210
|
+
gasPrice: z.ZodOptional<z.ZodString>;
|
|
211
|
+
maxFeePerGas: z.ZodOptional<z.ZodString>;
|
|
212
|
+
maxPriorityFeePerGas: z.ZodOptional<z.ZodString>;
|
|
213
|
+
}, z.core.$strict>;
|
|
214
|
+
result: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
215
|
+
success: z.ZodLiteral<true>;
|
|
216
|
+
transactionHash: z.ZodString;
|
|
217
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
218
|
+
success: z.ZodLiteral<false>;
|
|
219
|
+
reason: z.ZodDefault<z.ZodOptional<z.ZodEnum<{
|
|
220
|
+
unknown: "unknown";
|
|
221
|
+
rejected_by_user: "rejected_by_user";
|
|
222
|
+
failed: "failed";
|
|
223
|
+
}>>>;
|
|
224
|
+
message: z.ZodOptional<z.ZodString>;
|
|
225
|
+
code: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>;
|
|
226
|
+
transactionHash: z.ZodOptional<z.ZodString>;
|
|
227
|
+
}, z.core.$strict>], "success">;
|
|
228
|
+
}, z.core.$strict>;
|
|
229
|
+
}, z.core.$strip>;
|
|
230
|
+
export type SnapTransactionResultPayload = z.infer<typeof transactionResultPayloadSchema>;
|
|
231
|
+
export type SnapTransactionResultAction = SnapTransactionResultPayload;
|
|
157
232
|
export declare const snapActionSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
158
233
|
type: z.ZodLiteral<"get">;
|
|
159
234
|
user: z.ZodOptional<z.ZodObject<{
|
|
@@ -174,7 +249,6 @@ export declare const snapActionSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
174
249
|
}, z.core.$strip>], "type">>;
|
|
175
250
|
}, z.core.$strip>, z.ZodObject<{
|
|
176
251
|
fid: z.ZodOptional<z.ZodNumber>;
|
|
177
|
-
inputs: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodArray<z.ZodString>]>>>;
|
|
178
252
|
timestamp: z.ZodNumber;
|
|
179
253
|
audience: z.ZodString;
|
|
180
254
|
user: z.ZodObject<{
|
|
@@ -191,7 +265,53 @@ export declare const snapActionSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
191
265
|
}, z.core.$strip>, z.ZodObject<{
|
|
192
266
|
type: z.ZodLiteral<"standalone">;
|
|
193
267
|
}, z.core.$strip>], "type">;
|
|
268
|
+
inputs: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodArray<z.ZodString>]>>>;
|
|
194
269
|
type: z.ZodLiteral<"post">;
|
|
270
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
271
|
+
fid: z.ZodOptional<z.ZodNumber>;
|
|
272
|
+
timestamp: z.ZodNumber;
|
|
273
|
+
audience: z.ZodString;
|
|
274
|
+
user: z.ZodObject<{
|
|
275
|
+
fid: z.ZodNumber;
|
|
276
|
+
}, z.core.$strip>;
|
|
277
|
+
surface: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
278
|
+
type: z.ZodLiteral<"cast">;
|
|
279
|
+
cast: z.ZodObject<{
|
|
280
|
+
hash: z.ZodString;
|
|
281
|
+
author: z.ZodObject<{
|
|
282
|
+
fid: z.ZodNumber;
|
|
283
|
+
}, z.core.$strip>;
|
|
284
|
+
}, z.core.$strip>;
|
|
285
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
286
|
+
type: z.ZodLiteral<"standalone">;
|
|
287
|
+
}, z.core.$strip>], "type">;
|
|
288
|
+
type: z.ZodLiteral<"transaction_result">;
|
|
289
|
+
transaction: z.ZodObject<{
|
|
290
|
+
request: z.ZodObject<{
|
|
291
|
+
chainId: z.ZodString;
|
|
292
|
+
to: z.ZodString;
|
|
293
|
+
data: z.ZodOptional<z.ZodString>;
|
|
294
|
+
value: z.ZodOptional<z.ZodString>;
|
|
295
|
+
gas: z.ZodOptional<z.ZodString>;
|
|
296
|
+
gasPrice: z.ZodOptional<z.ZodString>;
|
|
297
|
+
maxFeePerGas: z.ZodOptional<z.ZodString>;
|
|
298
|
+
maxPriorityFeePerGas: z.ZodOptional<z.ZodString>;
|
|
299
|
+
}, z.core.$strict>;
|
|
300
|
+
result: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
301
|
+
success: z.ZodLiteral<true>;
|
|
302
|
+
transactionHash: z.ZodString;
|
|
303
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
304
|
+
success: z.ZodLiteral<false>;
|
|
305
|
+
reason: z.ZodDefault<z.ZodOptional<z.ZodEnum<{
|
|
306
|
+
unknown: "unknown";
|
|
307
|
+
rejected_by_user: "rejected_by_user";
|
|
308
|
+
failed: "failed";
|
|
309
|
+
}>>>;
|
|
310
|
+
message: z.ZodOptional<z.ZodString>;
|
|
311
|
+
code: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>;
|
|
312
|
+
transactionHash: z.ZodOptional<z.ZodString>;
|
|
313
|
+
}, z.core.$strict>], "success">;
|
|
314
|
+
}, z.core.$strict>;
|
|
195
315
|
}, z.core.$strip>], "type">;
|
|
196
316
|
export type SnapAction = z.infer<typeof snapActionSchema>;
|
|
197
317
|
export type SnapContext = {
|
package/dist/schemas.js
CHANGED
|
@@ -49,20 +49,59 @@ const surfaceSchema = z.discriminatedUnion("type", [
|
|
|
49
49
|
]);
|
|
50
50
|
const fidSchema = z.number().int().nonnegative();
|
|
51
51
|
const userSchema = z.object({ fid: fidSchema });
|
|
52
|
-
|
|
52
|
+
const basePayloadSchema = z
|
|
53
53
|
.object({
|
|
54
54
|
fid: fidSchema.optional(), // deprecated in favor of user.fid
|
|
55
|
-
inputs: z.record(z.string(), postInputValueSchema).default({}),
|
|
56
55
|
timestamp: z.number().int(),
|
|
57
56
|
audience: z.string(),
|
|
58
57
|
user: userSchema,
|
|
59
58
|
surface: surfaceSchema,
|
|
60
59
|
})
|
|
61
60
|
.strip();
|
|
61
|
+
const snapSendTransactionParamsSchema = z
|
|
62
|
+
.object({
|
|
63
|
+
chainId: z.string(),
|
|
64
|
+
to: z.string(),
|
|
65
|
+
data: z.string().optional(),
|
|
66
|
+
value: z.string().optional(),
|
|
67
|
+
gas: z.string().optional(),
|
|
68
|
+
gasPrice: z.string().optional(),
|
|
69
|
+
maxFeePerGas: z.string().optional(),
|
|
70
|
+
maxPriorityFeePerGas: z.string().optional(),
|
|
71
|
+
})
|
|
72
|
+
.strict();
|
|
73
|
+
const snapTransactionSuccessSchema = z
|
|
74
|
+
.object({
|
|
75
|
+
success: z.literal(true),
|
|
76
|
+
transactionHash: z.string(),
|
|
77
|
+
})
|
|
78
|
+
.strict();
|
|
79
|
+
const snapTransactionFailureSchema = z
|
|
80
|
+
.object({
|
|
81
|
+
success: z.literal(false),
|
|
82
|
+
reason: z
|
|
83
|
+
.enum(["rejected_by_user", "failed", "unknown"])
|
|
84
|
+
.optional()
|
|
85
|
+
.default("unknown"),
|
|
86
|
+
message: z.string().optional(),
|
|
87
|
+
code: z.union([z.string(), z.number()]).optional(),
|
|
88
|
+
transactionHash: z.string().optional(),
|
|
89
|
+
})
|
|
90
|
+
.strict();
|
|
91
|
+
export const snapTransactionResultSchema = z.discriminatedUnion("success", [
|
|
92
|
+
snapTransactionSuccessSchema,
|
|
93
|
+
snapTransactionFailureSchema,
|
|
94
|
+
]);
|
|
95
|
+
export const payloadSchema = basePayloadSchema
|
|
96
|
+
.extend({
|
|
97
|
+
inputs: z.record(z.string(), postInputValueSchema).default({}),
|
|
98
|
+
})
|
|
99
|
+
.strip();
|
|
62
100
|
/** JFS payload shape for POST minus deprecated `fid`; used for GET auth via payload header. */
|
|
63
101
|
export const getPayloadSchema = payloadSchema.omit({ inputs: true, fid: true });
|
|
64
102
|
export const ACTION_TYPE_GET = "get";
|
|
65
103
|
export const ACTION_TYPE_POST = "post";
|
|
104
|
+
export const ACTION_TYPE_TRANSACTION_RESULT = "transaction_result";
|
|
66
105
|
const snapGetActionSchema = z.object({
|
|
67
106
|
type: z.literal(ACTION_TYPE_GET),
|
|
68
107
|
user: userSchema.optional(),
|
|
@@ -73,7 +112,19 @@ const snapGetActionSchema = z.object({
|
|
|
73
112
|
const snapPostActionSchema = payloadSchema.extend({
|
|
74
113
|
type: z.literal(ACTION_TYPE_POST),
|
|
75
114
|
});
|
|
115
|
+
export const transactionResultPayloadSchema = basePayloadSchema
|
|
116
|
+
.extend({
|
|
117
|
+
type: z.literal(ACTION_TYPE_TRANSACTION_RESULT),
|
|
118
|
+
transaction: z
|
|
119
|
+
.object({
|
|
120
|
+
request: snapSendTransactionParamsSchema,
|
|
121
|
+
result: snapTransactionResultSchema,
|
|
122
|
+
})
|
|
123
|
+
.strict(),
|
|
124
|
+
})
|
|
125
|
+
.strip();
|
|
76
126
|
export const snapActionSchema = z.discriminatedUnion("type", [
|
|
77
127
|
snapGetActionSchema,
|
|
78
128
|
snapPostActionSchema,
|
|
129
|
+
transactionResultPayloadSchema,
|
|
79
130
|
]);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ACTION_TYPE_GET, ACTION_TYPE_POST, getPayloadSchema, payloadSchema, } from "../schemas.js";
|
|
1
|
+
import { ACTION_TYPE_TRANSACTION_RESULT, ACTION_TYPE_GET, ACTION_TYPE_POST, getPayloadSchema, payloadSchema, transactionResultPayloadSchema, } from "../schemas.js";
|
|
2
2
|
import { decodePayload, parseJfs, verifyJFS } from "./verify.js";
|
|
3
3
|
import { SNAP_PAYLOAD_HEADER } from "../constants.js";
|
|
4
4
|
const DEFAULT_SNAP_POST_MAX_SKEW_SECONDS = 300;
|
|
@@ -46,7 +46,9 @@ async function parseGetRequest(request, options) {
|
|
|
46
46
|
async function parsePostRequest(request, options) {
|
|
47
47
|
const result = await validateJfsPayload({
|
|
48
48
|
jfsText: await request.text(),
|
|
49
|
-
schema:
|
|
49
|
+
schema: (decodedPayload) => isTransactionResultPayload(decodedPayload)
|
|
50
|
+
? transactionResultPayloadSchema
|
|
51
|
+
: payloadSchema,
|
|
50
52
|
request,
|
|
51
53
|
options,
|
|
52
54
|
});
|
|
@@ -63,11 +65,23 @@ async function parsePostRequest(request, options) {
|
|
|
63
65
|
},
|
|
64
66
|
};
|
|
65
67
|
}
|
|
68
|
+
if (isTransactionResultPayload(payload)) {
|
|
69
|
+
return {
|
|
70
|
+
success: true,
|
|
71
|
+
action: payload,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
66
74
|
return {
|
|
67
75
|
success: true,
|
|
68
76
|
action: { type: ACTION_TYPE_POST, ...payload },
|
|
69
77
|
};
|
|
70
78
|
}
|
|
79
|
+
function isTransactionResultPayload(payload) {
|
|
80
|
+
return (payload !== null &&
|
|
81
|
+
typeof payload === "object" &&
|
|
82
|
+
"type" in payload &&
|
|
83
|
+
payload.type === ACTION_TYPE_TRANSACTION_RESULT);
|
|
84
|
+
}
|
|
71
85
|
/**
|
|
72
86
|
* Shared pipeline for authenticated snap requests: parse the JFS envelope,
|
|
73
87
|
* decode and schema-validate the payload, optionally verify the JFS signature
|
|
@@ -88,7 +102,9 @@ async function validateJfsPayload({ jfsText, schema, request, options, invalidJs
|
|
|
88
102
|
};
|
|
89
103
|
}
|
|
90
104
|
const jfs = parsed.jfs;
|
|
91
|
-
const
|
|
105
|
+
const decodedPayload = decodePayload(jfs.payload);
|
|
106
|
+
const selectedSchema = typeof schema === "function" ? schema(decodedPayload) : schema;
|
|
107
|
+
const payloadParsed = selectedSchema.safeParse(decodedPayload);
|
|
92
108
|
if (!payloadParsed.success) {
|
|
93
109
|
return {
|
|
94
110
|
ok: false,
|
package/dist/ui/button.d.ts
CHANGED
package/dist/ui/button.js
CHANGED
package/dist/ui/catalog.d.ts
CHANGED
|
@@ -136,6 +136,7 @@ export declare const snapJsonRenderCatalog: import("@json-render/core").Catalog<
|
|
|
136
136
|
"trending-up": "trending-up";
|
|
137
137
|
"trending-down": "trending-down";
|
|
138
138
|
}>>;
|
|
139
|
+
disabled: z.ZodOptional<z.ZodBoolean>;
|
|
139
140
|
}, z.core.$strip>;
|
|
140
141
|
description: string;
|
|
141
142
|
};
|
|
@@ -509,48 +510,56 @@ export declare const snapJsonRenderCatalog: import("@json-render/core").Catalog<
|
|
|
509
510
|
submit: {
|
|
510
511
|
description: string;
|
|
511
512
|
params: z.ZodObject<{
|
|
513
|
+
activityKey: z.ZodOptional<z.ZodString>;
|
|
512
514
|
target: z.ZodString;
|
|
513
515
|
}, z.core.$strip>;
|
|
514
516
|
};
|
|
515
517
|
open_url: {
|
|
516
518
|
description: string;
|
|
517
519
|
params: z.ZodObject<{
|
|
520
|
+
activityKey: z.ZodOptional<z.ZodString>;
|
|
518
521
|
target: z.ZodString;
|
|
519
522
|
}, z.core.$strip>;
|
|
520
523
|
};
|
|
521
524
|
open_snap: {
|
|
522
525
|
description: string;
|
|
523
526
|
params: z.ZodObject<{
|
|
527
|
+
activityKey: z.ZodOptional<z.ZodString>;
|
|
524
528
|
target: z.ZodString;
|
|
525
529
|
}, z.core.$strip>;
|
|
526
530
|
};
|
|
527
531
|
open_mini_app: {
|
|
528
532
|
description: string;
|
|
529
533
|
params: z.ZodObject<{
|
|
534
|
+
activityKey: z.ZodOptional<z.ZodString>;
|
|
530
535
|
target: z.ZodString;
|
|
531
536
|
}, z.core.$strip>;
|
|
532
537
|
};
|
|
533
538
|
view_cast: {
|
|
534
539
|
description: string;
|
|
535
540
|
params: z.ZodObject<{
|
|
541
|
+
activityKey: z.ZodOptional<z.ZodString>;
|
|
536
542
|
hash: z.ZodString;
|
|
537
543
|
}, z.core.$strip>;
|
|
538
544
|
};
|
|
539
545
|
view_profile: {
|
|
540
546
|
description: string;
|
|
541
547
|
params: z.ZodObject<{
|
|
548
|
+
activityKey: z.ZodOptional<z.ZodString>;
|
|
542
549
|
fid: z.ZodNumber;
|
|
543
550
|
}, z.core.$strip>;
|
|
544
551
|
};
|
|
545
552
|
view_channel: {
|
|
546
553
|
description: string;
|
|
547
554
|
params: z.ZodObject<{
|
|
555
|
+
activityKey: z.ZodOptional<z.ZodString>;
|
|
548
556
|
channelKey: z.ZodString;
|
|
549
557
|
}, z.core.$strip>;
|
|
550
558
|
};
|
|
551
559
|
compose_cast: {
|
|
552
560
|
description: string;
|
|
553
561
|
params: z.ZodObject<{
|
|
562
|
+
activityKey: z.ZodOptional<z.ZodString>;
|
|
554
563
|
text: z.ZodOptional<z.ZodString>;
|
|
555
564
|
channelKey: z.ZodOptional<z.ZodString>;
|
|
556
565
|
embeds: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
@@ -559,12 +568,14 @@ export declare const snapJsonRenderCatalog: import("@json-render/core").Catalog<
|
|
|
559
568
|
view_token: {
|
|
560
569
|
description: string;
|
|
561
570
|
params: z.ZodObject<{
|
|
571
|
+
activityKey: z.ZodOptional<z.ZodString>;
|
|
562
572
|
token: z.ZodString;
|
|
563
573
|
}, z.core.$strip>;
|
|
564
574
|
};
|
|
565
575
|
send_token: {
|
|
566
576
|
description: string;
|
|
567
577
|
params: z.ZodObject<{
|
|
578
|
+
activityKey: z.ZodOptional<z.ZodString>;
|
|
568
579
|
token: z.ZodString;
|
|
569
580
|
amount: z.ZodOptional<z.ZodString>;
|
|
570
581
|
recipientFid: z.ZodOptional<z.ZodNumber>;
|
|
@@ -574,6 +585,7 @@ export declare const snapJsonRenderCatalog: import("@json-render/core").Catalog<
|
|
|
574
585
|
swap_token: {
|
|
575
586
|
description: string;
|
|
576
587
|
params: z.ZodObject<{
|
|
588
|
+
activityKey: z.ZodOptional<z.ZodString>;
|
|
577
589
|
sellToken: z.ZodOptional<z.ZodString>;
|
|
578
590
|
buyToken: z.ZodOptional<z.ZodString>;
|
|
579
591
|
}, z.core.$strip>;
|
|
@@ -581,6 +593,7 @@ export declare const snapJsonRenderCatalog: import("@json-render/core").Catalog<
|
|
|
581
593
|
send_transaction: {
|
|
582
594
|
description: string;
|
|
583
595
|
params: z.ZodObject<{
|
|
596
|
+
activityKey: z.ZodOptional<z.ZodString>;
|
|
584
597
|
chainId: z.ZodString;
|
|
585
598
|
to: z.ZodString;
|
|
586
599
|
data: z.ZodOptional<z.ZodString>;
|
package/dist/ui/catalog.js
CHANGED
|
@@ -21,6 +21,9 @@ import { cellGridProps } from "./cell-grid.js";
|
|
|
21
21
|
const snapClientParams = z.object({
|
|
22
22
|
client_action: z.record(z.string(), z.unknown()),
|
|
23
23
|
});
|
|
24
|
+
const activityParams = {
|
|
25
|
+
activityKey: z.string().min(1).max(64).optional(),
|
|
26
|
+
};
|
|
24
27
|
/**
|
|
25
28
|
* json-render catalog for snap elements.
|
|
26
29
|
*
|
|
@@ -101,31 +104,31 @@ export const snapJsonRenderCatalog = defineCatalog(snapJsonRenderSchema, {
|
|
|
101
104
|
actions: {
|
|
102
105
|
submit: {
|
|
103
106
|
description: "POST to snap server with signed body (fid, inputs, timestamp, signature); response is next snap page.",
|
|
104
|
-
params: z.object({ target: z.string() }),
|
|
107
|
+
params: z.object({ target: z.string(), ...activityParams }),
|
|
105
108
|
},
|
|
106
109
|
open_url: {
|
|
107
110
|
description: "Open external URL in browser.",
|
|
108
|
-
params: z.object({ target: z.string() }),
|
|
111
|
+
params: z.object({ target: z.string(), ...activityParams }),
|
|
109
112
|
},
|
|
110
113
|
open_snap: {
|
|
111
114
|
description: "Open a snap URL inline. The client renders the target as a snap rather than opening a browser.",
|
|
112
|
-
params: z.object({ target: z.string() }),
|
|
115
|
+
params: z.object({ target: z.string(), ...activityParams }),
|
|
113
116
|
},
|
|
114
117
|
open_mini_app: {
|
|
115
118
|
description: "Open target URL as a Farcaster mini app.",
|
|
116
|
-
params: z.object({ target: z.string() }),
|
|
119
|
+
params: z.object({ target: z.string(), ...activityParams }),
|
|
117
120
|
},
|
|
118
121
|
view_cast: {
|
|
119
122
|
description: "Navigate to a cast by hash.",
|
|
120
|
-
params: z.object({ hash: z.string() }),
|
|
123
|
+
params: z.object({ hash: z.string(), ...activityParams }),
|
|
121
124
|
},
|
|
122
125
|
view_profile: {
|
|
123
126
|
description: "Navigate to a user profile by FID.",
|
|
124
|
-
params: z.object({ fid: z.number() }),
|
|
127
|
+
params: z.object({ fid: z.number(), ...activityParams }),
|
|
125
128
|
},
|
|
126
129
|
view_channel: {
|
|
127
130
|
description: "Navigate to a Farcaster channel by channel key.",
|
|
128
|
-
params: z.object({ channelKey: z.string() }),
|
|
131
|
+
params: z.object({ channelKey: z.string(), ...activityParams }),
|
|
129
132
|
},
|
|
130
133
|
compose_cast: {
|
|
131
134
|
description: "Open the cast composer with optional pre-filled content.",
|
|
@@ -133,11 +136,12 @@ export const snapJsonRenderCatalog = defineCatalog(snapJsonRenderSchema, {
|
|
|
133
136
|
text: z.string().optional(),
|
|
134
137
|
channelKey: z.string().optional(),
|
|
135
138
|
embeds: z.array(z.string()).optional(),
|
|
139
|
+
...activityParams,
|
|
136
140
|
}),
|
|
137
141
|
},
|
|
138
142
|
view_token: {
|
|
139
143
|
description: "View a token in the wallet. Token is a CAIP-19 identifier.",
|
|
140
|
-
params: z.object({ token: z.string() }),
|
|
144
|
+
params: z.object({ token: z.string(), ...activityParams }),
|
|
141
145
|
},
|
|
142
146
|
send_token: {
|
|
143
147
|
description: "Open send flow for a token. Token is CAIP-19.",
|
|
@@ -146,6 +150,7 @@ export const snapJsonRenderCatalog = defineCatalog(snapJsonRenderSchema, {
|
|
|
146
150
|
amount: z.string().optional(),
|
|
147
151
|
recipientFid: z.number().optional(),
|
|
148
152
|
recipientAddress: z.string().optional(),
|
|
153
|
+
...activityParams,
|
|
149
154
|
}),
|
|
150
155
|
},
|
|
151
156
|
swap_token: {
|
|
@@ -153,6 +158,7 @@ export const snapJsonRenderCatalog = defineCatalog(snapJsonRenderSchema, {
|
|
|
153
158
|
params: z.object({
|
|
154
159
|
sellToken: z.string().optional(),
|
|
155
160
|
buyToken: z.string().optional(),
|
|
161
|
+
...activityParams,
|
|
156
162
|
}),
|
|
157
163
|
},
|
|
158
164
|
send_transaction: {
|
|
@@ -166,6 +172,7 @@ export const snapJsonRenderCatalog = defineCatalog(snapJsonRenderSchema, {
|
|
|
166
172
|
gasPrice: z.string().optional(),
|
|
167
173
|
maxFeePerGas: z.string().optional(),
|
|
168
174
|
maxPriorityFeePerGas: z.string().optional(),
|
|
175
|
+
...activityParams,
|
|
169
176
|
}),
|
|
170
177
|
},
|
|
171
178
|
paginator_next: {
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -32,11 +32,15 @@ export {
|
|
|
32
32
|
export {
|
|
33
33
|
ACTION_TYPE_GET,
|
|
34
34
|
ACTION_TYPE_POST,
|
|
35
|
+
ACTION_TYPE_TRANSACTION_RESULT,
|
|
35
36
|
snapResponseSchema,
|
|
36
37
|
payloadSchema,
|
|
37
38
|
getPayloadSchema,
|
|
39
|
+
transactionResultPayloadSchema,
|
|
40
|
+
snapTransactionResultSchema,
|
|
38
41
|
type SnapAction,
|
|
39
42
|
type SnapGetAction,
|
|
43
|
+
type SnapTransactionResultAction,
|
|
40
44
|
type SnapContext,
|
|
41
45
|
type SnapResponse,
|
|
42
46
|
type SnapHandlerResult,
|
|
@@ -45,6 +49,9 @@ export {
|
|
|
45
49
|
type SnapFunction,
|
|
46
50
|
type SnapPayload,
|
|
47
51
|
type SnapGetPayload,
|
|
52
|
+
type SnapSendTransactionParams,
|
|
53
|
+
type SnapTransactionResult,
|
|
54
|
+
type SnapTransactionResultPayload,
|
|
48
55
|
} from "./schemas";
|
|
49
56
|
export { validateSnapResponse, type ValidationResult } from "./validator";
|
|
50
57
|
export type { SnapRenderState } from "./render-state";
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
JSONUIProvider,
|
|
5
|
+
Renderer,
|
|
6
|
+
type ComponentRegistry,
|
|
7
|
+
type CreateRendererProps,
|
|
8
|
+
} from "@json-render/react";
|
|
9
|
+
import { useMemo, type ReactNode } from "react";
|
|
4
10
|
import { snapJsonRenderCatalog } from "@farcaster/snap/ui";
|
|
5
11
|
import { SnapActionButton } from "./components/action-button";
|
|
6
12
|
import { SnapBadge } from "./components/badge";
|
|
@@ -24,7 +30,7 @@ import { SnapCellGrid } from "./components/cell-grid";
|
|
|
24
30
|
* Maps snap json-render catalog types to React components.
|
|
25
31
|
* Keys match the snap wire-format `type` strings exactly.
|
|
26
32
|
*/
|
|
27
|
-
|
|
33
|
+
const snapCatalogRegistry = {
|
|
28
34
|
badge: SnapBadge,
|
|
29
35
|
button: SnapActionButton,
|
|
30
36
|
icon: SnapIcon,
|
|
@@ -42,4 +48,52 @@ export const SnapCatalogView = createRenderer(snapJsonRenderCatalog, {
|
|
|
42
48
|
toggle_group: SnapToggleGroup,
|
|
43
49
|
bar_chart: SnapBarChart,
|
|
44
50
|
cell_grid: SnapCellGrid,
|
|
45
|
-
}
|
|
51
|
+
} satisfies ComponentRegistry;
|
|
52
|
+
|
|
53
|
+
export function SnapCatalogView({
|
|
54
|
+
spec,
|
|
55
|
+
store,
|
|
56
|
+
state,
|
|
57
|
+
onAction,
|
|
58
|
+
onStateChange,
|
|
59
|
+
functions,
|
|
60
|
+
loading,
|
|
61
|
+
fallback,
|
|
62
|
+
children,
|
|
63
|
+
}: CreateRendererProps & { children?: ReactNode }) {
|
|
64
|
+
const actionHandlers = useMemo(
|
|
65
|
+
() =>
|
|
66
|
+
onAction
|
|
67
|
+
? new Proxy<Record<string, (params: Record<string, unknown>) => unknown>>(
|
|
68
|
+
{},
|
|
69
|
+
{
|
|
70
|
+
get: (_target, prop) => {
|
|
71
|
+
return (params: Record<string, unknown>) =>
|
|
72
|
+
onAction(String(prop), params);
|
|
73
|
+
},
|
|
74
|
+
has: () => true,
|
|
75
|
+
},
|
|
76
|
+
)
|
|
77
|
+
: undefined,
|
|
78
|
+
[onAction],
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
return (
|
|
82
|
+
<JSONUIProvider
|
|
83
|
+
registry={snapCatalogRegistry}
|
|
84
|
+
store={store}
|
|
85
|
+
initialState={state}
|
|
86
|
+
handlers={actionHandlers}
|
|
87
|
+
functions={functions}
|
|
88
|
+
onStateChange={onStateChange}
|
|
89
|
+
>
|
|
90
|
+
<Renderer
|
|
91
|
+
spec={spec}
|
|
92
|
+
registry={snapCatalogRegistry}
|
|
93
|
+
loading={loading}
|
|
94
|
+
fallback={fallback}
|
|
95
|
+
/>
|
|
96
|
+
{children}
|
|
97
|
+
</JSONUIProvider>
|
|
98
|
+
);
|
|
99
|
+
}
|