@farcaster/snap 2.0.0 → 2.0.1
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/colors.d.ts +4 -4
- package/dist/colors.js +20 -20
- package/dist/constants.d.ts +17 -1
- package/dist/constants.js +19 -1
- package/dist/index.d.ts +4 -6
- package/dist/index.js +2 -4
- package/dist/react/accent-context.d.ts +3 -1
- package/dist/react/accent-context.js +7 -4
- package/dist/react/catalog-renderer.js +4 -0
- package/dist/react/components/action-button.d.ts +2 -1
- package/dist/react/components/action-button.js +32 -13
- package/dist/react/components/badge.js +8 -8
- package/dist/react/components/bar-chart.d.ts +5 -0
- package/dist/react/components/bar-chart.js +26 -0
- package/dist/react/components/cell-grid.d.ts +5 -0
- package/dist/react/components/cell-grid.js +87 -0
- package/dist/react/components/icon.js +4 -10
- package/dist/react/components/input.js +12 -6
- package/dist/react/components/item-group.js +3 -1
- package/dist/react/components/item.d.ts +3 -3
- package/dist/react/components/item.js +4 -3
- package/dist/react/components/progress.js +3 -3
- package/dist/react/components/separator.js +3 -1
- package/dist/react/components/slider.js +15 -10
- package/dist/react/components/switch.js +10 -12
- package/dist/react/components/text.js +6 -14
- package/dist/react/components/toggle-group.js +20 -6
- package/dist/react/hooks/use-snap-colors.d.ts +38 -0
- package/dist/react/hooks/use-snap-colors.js +81 -0
- package/dist/react/index.d.ts +13 -1
- package/dist/react/index.js +9 -188
- package/dist/react/snap-view-core.d.ts +11 -0
- package/dist/react/snap-view-core.js +224 -0
- package/dist/react/v1/snap-view.d.ts +16 -0
- package/dist/react/v1/snap-view.js +90 -0
- package/dist/react/v2/snap-view.d.ts +23 -0
- package/dist/react/v2/snap-view.js +91 -0
- package/dist/react-native/catalog-renderer.d.ts +5 -0
- package/dist/react-native/catalog-renderer.js +40 -0
- package/dist/react-native/components/snap-action-button.d.ts +2 -0
- package/dist/react-native/components/snap-action-button.js +69 -0
- package/dist/react-native/components/snap-badge.d.ts +2 -0
- package/dist/react-native/components/snap-badge.js +41 -0
- package/dist/react-native/components/snap-bar-chart.d.ts +2 -0
- package/dist/react-native/components/snap-bar-chart.js +39 -0
- package/dist/react-native/components/snap-cell-grid.d.ts +2 -0
- package/dist/react-native/components/snap-cell-grid.js +94 -0
- package/dist/react-native/components/snap-icon.d.ts +5 -0
- package/dist/react-native/components/snap-icon.js +56 -0
- package/dist/react-native/components/snap-image.d.ts +2 -0
- package/dist/react-native/components/snap-image.js +23 -0
- package/dist/react-native/components/snap-input.d.ts +2 -0
- package/dist/react-native/components/snap-input.js +37 -0
- package/dist/react-native/components/snap-item-group.d.ts +5 -0
- package/dist/react-native/components/snap-item-group.js +23 -0
- package/dist/react-native/components/snap-item.d.ts +5 -0
- package/dist/react-native/components/snap-item.js +42 -0
- package/dist/react-native/components/snap-progress.d.ts +2 -0
- package/dist/react-native/components/snap-progress.js +26 -0
- package/dist/react-native/components/snap-separator.d.ts +2 -0
- package/dist/react-native/components/snap-separator.js +23 -0
- package/dist/react-native/components/snap-slider.d.ts +2 -0
- package/dist/react-native/components/snap-slider.js +43 -0
- package/dist/react-native/components/snap-stack.d.ts +5 -0
- package/dist/react-native/components/snap-stack.js +49 -0
- package/dist/react-native/components/snap-switch.d.ts +2 -0
- package/dist/react-native/components/snap-switch.js +31 -0
- package/dist/react-native/components/snap-text.d.ts +2 -0
- package/dist/react-native/components/snap-text.js +35 -0
- package/dist/react-native/components/snap-toggle-group.d.ts +2 -0
- package/dist/react-native/components/snap-toggle-group.js +99 -0
- package/dist/react-native/confetti-overlay.d.ts +1 -0
- package/dist/react-native/confetti-overlay.js +106 -0
- package/dist/react-native/index.d.ts +28 -0
- package/dist/react-native/index.js +15 -0
- package/dist/react-native/snap-view-core.d.ts +11 -0
- package/dist/react-native/snap-view-core.js +153 -0
- package/dist/react-native/theme.d.ts +27 -0
- package/dist/react-native/theme.js +43 -0
- package/dist/react-native/types.d.ts +42 -0
- package/dist/react-native/types.js +1 -0
- package/dist/react-native/use-snap-palette.d.ts +13 -0
- package/dist/react-native/use-snap-palette.js +48 -0
- package/dist/react-native/v1/snap-view.d.ts +24 -0
- package/dist/react-native/v1/snap-view.js +96 -0
- package/dist/react-native/v2/snap-view.d.ts +33 -0
- package/dist/react-native/v2/snap-view.js +114 -0
- package/dist/schemas.d.ts +100 -13
- package/dist/schemas.js +28 -10
- package/dist/server/parseRequest.d.ts +10 -0
- package/dist/server/parseRequest.js +48 -7
- package/dist/server/verify.d.ts +1 -0
- package/dist/server/verify.js +1 -0
- package/dist/ui/badge.d.ts +7 -2
- package/dist/ui/badge.js +2 -0
- package/dist/ui/bar-chart.d.ts +30 -0
- package/dist/ui/bar-chart.js +30 -0
- package/dist/ui/button.d.ts +4 -6
- package/dist/ui/button.js +1 -1
- package/dist/ui/catalog.d.ts +90 -16
- package/dist/ui/catalog.js +17 -3
- package/dist/ui/cell-grid.d.ts +34 -0
- package/dist/ui/cell-grid.js +39 -0
- package/dist/ui/icon.d.ts +2 -2
- package/dist/ui/image.d.ts +1 -2
- package/dist/ui/image.js +1 -1
- package/dist/ui/index.d.ts +4 -0
- package/dist/ui/index.js +2 -0
- package/dist/ui/item.d.ts +1 -3
- package/dist/ui/item.js +1 -1
- package/dist/ui/schema.d.ts +6 -2
- package/dist/ui/schema.js +2 -2
- package/dist/ui/slider.d.ts +1 -0
- package/dist/ui/slider.js +2 -0
- package/dist/ui/text.d.ts +2 -4
- package/dist/ui/text.js +2 -2
- package/dist/validator.d.ts +3 -2
- package/dist/validator.js +198 -2
- package/llms.txt +199 -0
- package/package.json +9 -3
- package/src/colors.ts +20 -20
- package/src/constants.ts +23 -1
- package/src/index.ts +16 -13
- package/src/react/accent-context.tsx +13 -6
- package/src/react/catalog-renderer.tsx +4 -0
- package/src/react/components/action-button.tsx +47 -20
- package/src/react/components/badge.tsx +14 -18
- package/src/react/components/bar-chart.tsx +69 -0
- package/src/react/components/cell-grid.tsx +128 -0
- package/src/react/components/icon.tsx +5 -18
- package/src/react/components/input.tsx +20 -9
- package/src/react/components/item-group.tsx +4 -1
- package/src/react/components/item.tsx +13 -10
- package/src/react/components/progress.tsx +12 -7
- package/src/react/components/separator.tsx +8 -1
- package/src/react/components/slider.tsx +28 -15
- package/src/react/components/switch.tsx +12 -16
- package/src/react/components/text.tsx +14 -23
- package/src/react/components/toggle-group.tsx +26 -9
- package/src/react/hooks/use-snap-colors.ts +128 -0
- package/src/react/index.tsx +49 -265
- package/src/react/snap-view-core.tsx +340 -0
- package/src/react/v1/snap-view.tsx +176 -0
- package/src/react/v2/snap-view.tsx +199 -0
- package/src/react-native/catalog-renderer.tsx +41 -0
- package/src/react-native/components/snap-action-button.tsx +96 -0
- package/src/react-native/components/snap-badge.tsx +60 -0
- package/src/react-native/components/snap-bar-chart.tsx +73 -0
- package/src/react-native/components/snap-cell-grid.tsx +150 -0
- package/src/react-native/components/snap-icon.tsx +102 -0
- package/src/react-native/components/snap-image.tsx +37 -0
- package/src/react-native/components/snap-input.tsx +58 -0
- package/src/react-native/components/snap-item-group.tsx +43 -0
- package/src/react-native/components/snap-item.tsx +66 -0
- package/src/react-native/components/snap-progress.tsx +40 -0
- package/src/react-native/components/snap-separator.tsx +32 -0
- package/src/react-native/components/snap-slider.tsx +85 -0
- package/src/react-native/components/snap-stack.tsx +66 -0
- package/src/react-native/components/snap-switch.tsx +46 -0
- package/src/react-native/components/snap-text.tsx +51 -0
- package/src/react-native/components/snap-toggle-group.tsx +127 -0
- package/src/react-native/confetti-overlay.tsx +134 -0
- package/src/react-native/index.tsx +83 -0
- package/src/react-native/snap-view-core.tsx +209 -0
- package/src/react-native/theme.tsx +85 -0
- package/src/react-native/types.ts +38 -0
- package/src/react-native/use-snap-palette.ts +64 -0
- package/src/react-native/v1/snap-view.tsx +229 -0
- package/src/react-native/v2/snap-view.tsx +283 -0
- package/src/schemas.ts +68 -17
- package/src/server/parseRequest.ts +68 -9
- package/src/server/verify.ts +2 -0
- package/src/ui/README.md +8 -8
- package/src/ui/badge.ts +2 -0
- package/src/ui/bar-chart.ts +38 -0
- package/src/ui/button.ts +1 -1
- package/src/ui/catalog.ts +19 -3
- package/src/ui/cell-grid.ts +49 -0
- package/src/ui/image.ts +1 -1
- package/src/ui/index.ts +6 -0
- package/src/ui/item.ts +1 -1
- package/src/ui/schema.ts +2 -2
- package/src/ui/slider.ts +2 -0
- package/src/ui/text.ts +2 -2
- package/src/validator.ts +246 -2
- package/dist/dataStore.d.ts +0 -12
- package/dist/dataStore.js +0 -35
- package/dist/middleware.d.ts +0 -3
- package/dist/middleware.js +0 -3
- package/dist/react/hooks/use-snap-accent.d.ts +0 -13
- package/dist/react/hooks/use-snap-accent.js +0 -32
- package/src/dataStore.ts +0 -62
- package/src/middleware.ts +0 -7
- package/src/react/hooks/use-snap-accent.ts +0 -45
package/dist/schemas.d.ts
CHANGED
|
@@ -1,8 +1,21 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import type { Spec } from "@json-render/core";
|
|
3
|
-
import { type
|
|
3
|
+
import { type SpecVersion } from "./constants.js";
|
|
4
|
+
declare const themeAccentSchema: z.ZodEnum<{
|
|
5
|
+
gray: "gray";
|
|
6
|
+
blue: "blue";
|
|
7
|
+
red: "red";
|
|
8
|
+
amber: "amber";
|
|
9
|
+
green: "green";
|
|
10
|
+
teal: "teal";
|
|
11
|
+
purple: "purple";
|
|
12
|
+
pink: "pink";
|
|
13
|
+
}>;
|
|
4
14
|
export declare const snapResponseSchema: z.ZodObject<{
|
|
5
|
-
version: z.
|
|
15
|
+
version: z.ZodEnum<{
|
|
16
|
+
"1.0": "1.0";
|
|
17
|
+
"2.0": "2.0";
|
|
18
|
+
}>;
|
|
6
19
|
theme: z.ZodDefault<z.ZodOptional<z.ZodObject<{
|
|
7
20
|
accent: z.ZodDefault<z.ZodEnum<{
|
|
8
21
|
gray: "gray";
|
|
@@ -21,13 +34,60 @@ export declare const snapResponseSchema: z.ZodObject<{
|
|
|
21
34
|
ui: z.ZodCustom<Spec, Spec>;
|
|
22
35
|
}, z.core.$strict>;
|
|
23
36
|
export type SnapResponse = z.infer<typeof snapResponseSchema>;
|
|
24
|
-
|
|
37
|
+
/**
|
|
38
|
+
* Permissive element input type for snap handler authors.
|
|
39
|
+
* Allows dynamic element construction without requiring exact UIElement types.
|
|
40
|
+
*/
|
|
41
|
+
export type SnapElementInput = {
|
|
42
|
+
type: string;
|
|
43
|
+
props?: Record<string, unknown>;
|
|
44
|
+
children?: string[];
|
|
45
|
+
on?: Record<string, unknown>;
|
|
46
|
+
[key: string]: unknown;
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* Permissive input type for the `ui` field in snap handler return values.
|
|
50
|
+
* Accepts dynamically-built element maps (e.g. `Record<string, SnapElementInput>`)
|
|
51
|
+
* without requiring exact UIElement types.
|
|
52
|
+
*/
|
|
53
|
+
export type SnapSpecInput = {
|
|
54
|
+
root: string;
|
|
55
|
+
elements: Record<string, SnapElementInput>;
|
|
56
|
+
state?: Record<string, unknown>;
|
|
57
|
+
};
|
|
58
|
+
/**
|
|
59
|
+
* Return type for snap handler functions.
|
|
60
|
+
* Uses permissive input types so handlers can build elements dynamically
|
|
61
|
+
* without type casts. Runtime validation via the Zod schema still catches invalid shapes.
|
|
62
|
+
*/
|
|
63
|
+
export type SnapHandlerResult = {
|
|
64
|
+
version: SpecVersion;
|
|
65
|
+
theme?: {
|
|
66
|
+
accent?: z.input<typeof themeAccentSchema>;
|
|
67
|
+
};
|
|
68
|
+
effects?: z.input<typeof snapResponseSchema>["effects"];
|
|
69
|
+
ui: SnapSpecInput;
|
|
70
|
+
};
|
|
25
71
|
export declare const payloadSchema: z.ZodObject<{
|
|
26
|
-
fid: z.ZodNumber
|
|
72
|
+
fid: z.ZodOptional<z.ZodNumber>;
|
|
27
73
|
inputs: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodArray<z.ZodString>]>>>;
|
|
28
|
-
button_index: z.ZodNumber;
|
|
29
74
|
timestamp: z.ZodNumber;
|
|
30
|
-
|
|
75
|
+
audience: z.ZodString;
|
|
76
|
+
user: z.ZodObject<{
|
|
77
|
+
fid: z.ZodNumber;
|
|
78
|
+
}, z.core.$strip>;
|
|
79
|
+
surface: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
80
|
+
type: z.ZodLiteral<"cast">;
|
|
81
|
+
cast: z.ZodObject<{
|
|
82
|
+
hash: z.ZodString;
|
|
83
|
+
author: z.ZodObject<{
|
|
84
|
+
fid: z.ZodNumber;
|
|
85
|
+
}, z.core.$strip>;
|
|
86
|
+
}, z.core.$strip>;
|
|
87
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
88
|
+
type: z.ZodLiteral<"standalone">;
|
|
89
|
+
}, z.core.$strip>], "type">;
|
|
90
|
+
}, z.core.$strip>;
|
|
31
91
|
export type SnapPayload = z.infer<typeof payloadSchema>;
|
|
32
92
|
export declare const ACTION_TYPE_GET: "get";
|
|
33
93
|
export declare const ACTION_TYPE_POST: "post";
|
|
@@ -36,27 +96,54 @@ declare const snapGetActionSchema: z.ZodObject<{
|
|
|
36
96
|
}, z.core.$strip>;
|
|
37
97
|
export type SnapGetAction = z.infer<typeof snapGetActionSchema>;
|
|
38
98
|
declare const snapPostActionSchema: z.ZodObject<{
|
|
39
|
-
fid: z.ZodNumber
|
|
99
|
+
fid: z.ZodOptional<z.ZodNumber>;
|
|
40
100
|
inputs: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodArray<z.ZodString>]>>>;
|
|
41
|
-
button_index: z.ZodNumber;
|
|
42
101
|
timestamp: z.ZodNumber;
|
|
102
|
+
audience: z.ZodString;
|
|
103
|
+
user: z.ZodObject<{
|
|
104
|
+
fid: z.ZodNumber;
|
|
105
|
+
}, z.core.$strip>;
|
|
106
|
+
surface: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
107
|
+
type: z.ZodLiteral<"cast">;
|
|
108
|
+
cast: z.ZodObject<{
|
|
109
|
+
hash: z.ZodString;
|
|
110
|
+
author: z.ZodObject<{
|
|
111
|
+
fid: z.ZodNumber;
|
|
112
|
+
}, z.core.$strip>;
|
|
113
|
+
}, z.core.$strip>;
|
|
114
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
115
|
+
type: z.ZodLiteral<"standalone">;
|
|
116
|
+
}, z.core.$strip>], "type">;
|
|
43
117
|
type: z.ZodLiteral<"post">;
|
|
44
|
-
}, z.core.$
|
|
118
|
+
}, z.core.$strip>;
|
|
45
119
|
export type SnapPostAction = z.infer<typeof snapPostActionSchema>;
|
|
46
120
|
export declare const snapActionSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
47
121
|
type: z.ZodLiteral<"get">;
|
|
48
122
|
}, z.core.$strip>, z.ZodObject<{
|
|
49
|
-
fid: z.ZodNumber
|
|
123
|
+
fid: z.ZodOptional<z.ZodNumber>;
|
|
50
124
|
inputs: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodArray<z.ZodString>]>>>;
|
|
51
|
-
button_index: z.ZodNumber;
|
|
52
125
|
timestamp: z.ZodNumber;
|
|
126
|
+
audience: z.ZodString;
|
|
127
|
+
user: z.ZodObject<{
|
|
128
|
+
fid: z.ZodNumber;
|
|
129
|
+
}, z.core.$strip>;
|
|
130
|
+
surface: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
131
|
+
type: z.ZodLiteral<"cast">;
|
|
132
|
+
cast: z.ZodObject<{
|
|
133
|
+
hash: z.ZodString;
|
|
134
|
+
author: z.ZodObject<{
|
|
135
|
+
fid: z.ZodNumber;
|
|
136
|
+
}, z.core.$strip>;
|
|
137
|
+
}, z.core.$strip>;
|
|
138
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
139
|
+
type: z.ZodLiteral<"standalone">;
|
|
140
|
+
}, z.core.$strip>], "type">;
|
|
53
141
|
type: z.ZodLiteral<"post">;
|
|
54
|
-
}, z.core.$
|
|
142
|
+
}, z.core.$strip>], "type">;
|
|
55
143
|
export type SnapAction = z.infer<typeof snapActionSchema>;
|
|
56
144
|
export type SnapContext = {
|
|
57
145
|
action: SnapAction;
|
|
58
146
|
request: Request;
|
|
59
|
-
data: SnapDataStore;
|
|
60
147
|
};
|
|
61
148
|
export type SnapFunction = (ctx: SnapContext) => Promise<SnapHandlerResult>;
|
|
62
149
|
export {};
|
package/dist/schemas.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import { EFFECT_VALUES,
|
|
3
|
-
import { DEFAULT_THEME_ACCENT, PALETTE_COLOR_VALUES
|
|
2
|
+
import { EFFECT_VALUES, SUPPORTED_SPEC_VERSIONS, } from "./constants.js";
|
|
3
|
+
import { DEFAULT_THEME_ACCENT, PALETTE_COLOR_VALUES } from "./colors.js";
|
|
4
4
|
// ─── Theme ─────────────────────────────────────────────
|
|
5
5
|
const themeAccentSchema = z.enum(PALETTE_COLOR_VALUES, {
|
|
6
6
|
message: `accent must be a palette color: ${PALETTE_COLOR_VALUES.join(", ")}`,
|
|
@@ -15,7 +15,7 @@ const themeSchema = z
|
|
|
15
15
|
// typed here via the json-render Spec type.
|
|
16
16
|
export const snapResponseSchema = z
|
|
17
17
|
.object({
|
|
18
|
-
version: z.
|
|
18
|
+
version: z.enum(SUPPORTED_SPEC_VERSIONS),
|
|
19
19
|
theme: themeSchema.optional().default({ accent: DEFAULT_THEME_ACCENT }),
|
|
20
20
|
effects: z.array(z.enum(EFFECT_VALUES)).optional(),
|
|
21
21
|
ui: z.custom((val) => val != null &&
|
|
@@ -31,24 +31,42 @@ const postInputValueSchema = z.union([
|
|
|
31
31
|
z.boolean(),
|
|
32
32
|
z.array(z.string()),
|
|
33
33
|
]);
|
|
34
|
+
const standaloneSurfaceSchema = z.object({
|
|
35
|
+
type: z.literal("standalone"),
|
|
36
|
+
});
|
|
37
|
+
const castSurfaceSchema = z.object({
|
|
38
|
+
type: z.literal("cast"),
|
|
39
|
+
cast: z.object({
|
|
40
|
+
hash: z.string(),
|
|
41
|
+
author: z.object({
|
|
42
|
+
fid: z.number().int().nonnegative(),
|
|
43
|
+
}),
|
|
44
|
+
}),
|
|
45
|
+
});
|
|
46
|
+
const surfaceSchema = z.discriminatedUnion("type", [
|
|
47
|
+
castSurfaceSchema,
|
|
48
|
+
standaloneSurfaceSchema,
|
|
49
|
+
]);
|
|
34
50
|
export const payloadSchema = z
|
|
35
51
|
.object({
|
|
36
|
-
fid: z.number().int().nonnegative(),
|
|
52
|
+
fid: z.number().int().nonnegative().optional(), // deprecated in favor of user.fid
|
|
37
53
|
inputs: z.record(z.string(), postInputValueSchema).default({}),
|
|
38
|
-
button_index: z.number().int().nonnegative(),
|
|
39
54
|
timestamp: z.number().int(),
|
|
55
|
+
audience: z.string(),
|
|
56
|
+
user: z.object({
|
|
57
|
+
fid: z.number().int().nonnegative(),
|
|
58
|
+
}),
|
|
59
|
+
surface: surfaceSchema,
|
|
40
60
|
})
|
|
41
|
-
.
|
|
61
|
+
.strip();
|
|
42
62
|
export const ACTION_TYPE_GET = "get";
|
|
43
63
|
export const ACTION_TYPE_POST = "post";
|
|
44
64
|
const snapGetActionSchema = z.object({
|
|
45
65
|
type: z.literal(ACTION_TYPE_GET),
|
|
46
66
|
});
|
|
47
|
-
const snapPostActionSchema = payloadSchema
|
|
48
|
-
.extend({
|
|
67
|
+
const snapPostActionSchema = payloadSchema.extend({
|
|
49
68
|
type: z.literal(ACTION_TYPE_POST),
|
|
50
|
-
})
|
|
51
|
-
.strict();
|
|
69
|
+
});
|
|
52
70
|
export const snapActionSchema = z.discriminatedUnion("type", [
|
|
53
71
|
snapGetActionSchema,
|
|
54
72
|
snapPostActionSchema,
|
|
@@ -15,6 +15,12 @@ export type ParseRequestError = {
|
|
|
15
15
|
} | {
|
|
16
16
|
type: "signature";
|
|
17
17
|
message: string;
|
|
18
|
+
} | {
|
|
19
|
+
type: "origin_mismatch";
|
|
20
|
+
message: string;
|
|
21
|
+
} | {
|
|
22
|
+
type: "fid_mismatch";
|
|
23
|
+
message: string;
|
|
18
24
|
};
|
|
19
25
|
export type ParseRequestOptions = {
|
|
20
26
|
/**
|
|
@@ -27,6 +33,10 @@ export type ParseRequestOptions = {
|
|
|
27
33
|
* potential replays. Defaults to 300 (5 minutes) when not provided.
|
|
28
34
|
*/
|
|
29
35
|
maxSkewSeconds?: number;
|
|
36
|
+
/**
|
|
37
|
+
* The origin of the request. Derived from the request when not provided.
|
|
38
|
+
*/
|
|
39
|
+
requestOrigin?: string;
|
|
30
40
|
};
|
|
31
41
|
export type ParseRequestResult = {
|
|
32
42
|
success: true;
|
|
@@ -51,6 +51,14 @@ export async function parseRequest(request, options = {}) {
|
|
|
51
51
|
error: { type: "invalid_json", message: parsed.error.message },
|
|
52
52
|
};
|
|
53
53
|
}
|
|
54
|
+
const payloadParsed = payloadSchema.safeParse(decodePayload(parsed.data.payload));
|
|
55
|
+
if (!payloadParsed.success) {
|
|
56
|
+
return {
|
|
57
|
+
success: false,
|
|
58
|
+
error: { type: "validation", issues: payloadParsed.error.issues },
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
const body = payloadParsed.data;
|
|
54
62
|
if (!options.skipJFSVerification) {
|
|
55
63
|
const jfs = await verifyJFSRequestBody(parsed.data);
|
|
56
64
|
if (!jfs.valid) {
|
|
@@ -59,21 +67,54 @@ export async function parseRequest(request, options = {}) {
|
|
|
59
67
|
error: { type: "signature", message: jfs.error.message },
|
|
60
68
|
};
|
|
61
69
|
}
|
|
70
|
+
if (jfs.signingUserFid !== body.user.fid) {
|
|
71
|
+
return {
|
|
72
|
+
success: false,
|
|
73
|
+
error: {
|
|
74
|
+
type: "fid_mismatch",
|
|
75
|
+
message: `JFS header fid "${jfs.signingUserFid}" does not match user.fid "${body.user.fid}"`,
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
}
|
|
62
79
|
}
|
|
63
|
-
|
|
64
|
-
if (!payloadParsed.success) {
|
|
80
|
+
if (Math.abs(nowSec - body.timestamp) > maxSkew) {
|
|
65
81
|
return {
|
|
66
82
|
success: false,
|
|
67
|
-
error: {
|
|
83
|
+
error: {
|
|
84
|
+
type: "replay",
|
|
85
|
+
message: `timestamp outside allowed skew of ${maxSkew}s`,
|
|
86
|
+
},
|
|
68
87
|
};
|
|
69
88
|
}
|
|
70
|
-
|
|
71
|
-
|
|
89
|
+
// Audience validation: ensure the payload audience matches the server origin.
|
|
90
|
+
let expectedOrigin = options.requestOrigin;
|
|
91
|
+
if (expectedOrigin === undefined) {
|
|
92
|
+
try {
|
|
93
|
+
const url = new URL(request.url);
|
|
94
|
+
const proto = request.headers.get("x-forwarded-proto") ??
|
|
95
|
+
url.protocol.replace(":", "");
|
|
96
|
+
const host = request.headers.get("x-forwarded-host") ?? url.host;
|
|
97
|
+
expectedOrigin = `${proto}://${host}`;
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
// do nothing
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
if (expectedOrigin !== undefined && body.audience !== expectedOrigin) {
|
|
72
104
|
return {
|
|
73
105
|
success: false,
|
|
74
106
|
error: {
|
|
75
|
-
type: "
|
|
76
|
-
message: `
|
|
107
|
+
type: "origin_mismatch",
|
|
108
|
+
message: `payload audience "${body.audience}" does not match expected origin "${expectedOrigin}"`,
|
|
109
|
+
},
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
if (body.fid !== undefined && body.fid !== body.user.fid) {
|
|
113
|
+
return {
|
|
114
|
+
success: false,
|
|
115
|
+
error: {
|
|
116
|
+
type: "fid_mismatch",
|
|
117
|
+
message: `fid "${body.fid}" does not match user.fid "${body.user.fid}"`,
|
|
77
118
|
},
|
|
78
119
|
};
|
|
79
120
|
}
|
package/dist/server/verify.d.ts
CHANGED
package/dist/server/verify.js
CHANGED
package/dist/ui/badge.d.ts
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
+
export declare const BADGE_VARIANTS: readonly ["default", "outline"];
|
|
2
3
|
export declare const BADGE_MAX_LABEL_CHARS = 30;
|
|
3
4
|
export declare const badgeProps: z.ZodObject<{
|
|
4
5
|
label: z.ZodString;
|
|
6
|
+
variant: z.ZodOptional<z.ZodEnum<{
|
|
7
|
+
default: "default";
|
|
8
|
+
outline: "outline";
|
|
9
|
+
}>>;
|
|
5
10
|
color: z.ZodOptional<z.ZodEnum<{
|
|
6
11
|
gray: "gray";
|
|
7
12
|
blue: "blue";
|
|
@@ -14,18 +19,18 @@ export declare const badgeProps: z.ZodObject<{
|
|
|
14
19
|
accent: "accent";
|
|
15
20
|
}>>;
|
|
16
21
|
icon: z.ZodOptional<z.ZodEnum<{
|
|
17
|
-
check: "check";
|
|
18
|
-
repeat: "repeat";
|
|
19
22
|
"arrow-right": "arrow-right";
|
|
20
23
|
"arrow-left": "arrow-left";
|
|
21
24
|
"external-link": "external-link";
|
|
22
25
|
"chevron-right": "chevron-right";
|
|
26
|
+
check: "check";
|
|
23
27
|
x: "x";
|
|
24
28
|
"alert-triangle": "alert-triangle";
|
|
25
29
|
info: "info";
|
|
26
30
|
clock: "clock";
|
|
27
31
|
heart: "heart";
|
|
28
32
|
"message-circle": "message-circle";
|
|
33
|
+
repeat: "repeat";
|
|
29
34
|
share: "share";
|
|
30
35
|
user: "user";
|
|
31
36
|
users: "users";
|
package/dist/ui/badge.js
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { PROGRESS_COLOR_VALUES } from "../colors.js";
|
|
3
3
|
import { ICON_NAMES } from "./icon.js";
|
|
4
|
+
export const BADGE_VARIANTS = ["default", "outline"];
|
|
4
5
|
export const BADGE_MAX_LABEL_CHARS = 30;
|
|
5
6
|
export const badgeProps = z.object({
|
|
6
7
|
label: z.string().min(1).max(BADGE_MAX_LABEL_CHARS),
|
|
8
|
+
variant: z.enum(BADGE_VARIANTS).optional(),
|
|
7
9
|
color: z.enum(PROGRESS_COLOR_VALUES).optional(),
|
|
8
10
|
icon: z.enum(ICON_NAMES).optional(),
|
|
9
11
|
});
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export declare const barChartProps: z.ZodObject<{
|
|
3
|
+
bars: z.ZodArray<z.ZodObject<{
|
|
4
|
+
label: z.ZodString;
|
|
5
|
+
value: z.ZodNumber;
|
|
6
|
+
color: z.ZodOptional<z.ZodEnum<{
|
|
7
|
+
gray: "gray";
|
|
8
|
+
blue: "blue";
|
|
9
|
+
red: "red";
|
|
10
|
+
amber: "amber";
|
|
11
|
+
green: "green";
|
|
12
|
+
teal: "teal";
|
|
13
|
+
purple: "purple";
|
|
14
|
+
pink: "pink";
|
|
15
|
+
}>>;
|
|
16
|
+
}, z.core.$strip>>;
|
|
17
|
+
max: z.ZodOptional<z.ZodNumber>;
|
|
18
|
+
color: z.ZodOptional<z.ZodEnum<{
|
|
19
|
+
gray: "gray";
|
|
20
|
+
blue: "blue";
|
|
21
|
+
red: "red";
|
|
22
|
+
amber: "amber";
|
|
23
|
+
green: "green";
|
|
24
|
+
teal: "teal";
|
|
25
|
+
purple: "purple";
|
|
26
|
+
pink: "pink";
|
|
27
|
+
accent: "accent";
|
|
28
|
+
}>>;
|
|
29
|
+
}, z.core.$strip>;
|
|
30
|
+
export type BarChartProps = z.infer<typeof barChartProps>;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { BAR_CHART_COLOR_VALUES, PALETTE_COLOR_VALUES } from "../colors.js";
|
|
3
|
+
import { BAR_CHART_MAX_BARS, BAR_CHART_LABEL_MAX_CHARS, } from "../constants.js";
|
|
4
|
+
export const barChartProps = z
|
|
5
|
+
.object({
|
|
6
|
+
bars: z
|
|
7
|
+
.array(z.object({
|
|
8
|
+
label: z.string().min(1).max(BAR_CHART_LABEL_MAX_CHARS),
|
|
9
|
+
value: z.number().nonnegative(),
|
|
10
|
+
color: z.enum(PALETTE_COLOR_VALUES).optional(),
|
|
11
|
+
}))
|
|
12
|
+
.min(1)
|
|
13
|
+
.max(BAR_CHART_MAX_BARS),
|
|
14
|
+
max: z.number().nonnegative().optional(),
|
|
15
|
+
color: z.enum(BAR_CHART_COLOR_VALUES).optional(),
|
|
16
|
+
})
|
|
17
|
+
.superRefine((val, ctx) => {
|
|
18
|
+
if (val.max !== undefined) {
|
|
19
|
+
for (let i = 0; i < val.bars.length; i++) {
|
|
20
|
+
const bar = val.bars[i];
|
|
21
|
+
if (bar.value > val.max) {
|
|
22
|
+
ctx.addIssue({
|
|
23
|
+
code: "custom",
|
|
24
|
+
message: `bar value (${bar.value}) exceeds chart max (${val.max})`,
|
|
25
|
+
path: ["bars", i, "value"],
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
});
|
package/dist/ui/button.d.ts
CHANGED
|
@@ -1,27 +1,25 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
export declare const BUTTON_VARIANTS: readonly ["
|
|
2
|
+
export declare const BUTTON_VARIANTS: readonly ["secondary", "primary"];
|
|
3
3
|
export declare const BUTTON_MAX_LABEL_CHARS = 30;
|
|
4
4
|
export declare const buttonProps: z.ZodObject<{
|
|
5
5
|
label: z.ZodString;
|
|
6
6
|
variant: z.ZodOptional<z.ZodEnum<{
|
|
7
|
-
default: "default";
|
|
8
7
|
secondary: "secondary";
|
|
9
|
-
|
|
10
|
-
ghost: "ghost";
|
|
8
|
+
primary: "primary";
|
|
11
9
|
}>>;
|
|
12
10
|
icon: z.ZodOptional<z.ZodEnum<{
|
|
13
|
-
check: "check";
|
|
14
|
-
repeat: "repeat";
|
|
15
11
|
"arrow-right": "arrow-right";
|
|
16
12
|
"arrow-left": "arrow-left";
|
|
17
13
|
"external-link": "external-link";
|
|
18
14
|
"chevron-right": "chevron-right";
|
|
15
|
+
check: "check";
|
|
19
16
|
x: "x";
|
|
20
17
|
"alert-triangle": "alert-triangle";
|
|
21
18
|
info: "info";
|
|
22
19
|
clock: "clock";
|
|
23
20
|
heart: "heart";
|
|
24
21
|
"message-circle": "message-circle";
|
|
22
|
+
repeat: "repeat";
|
|
25
23
|
share: "share";
|
|
26
24
|
user: "user";
|
|
27
25
|
users: "users";
|
package/dist/ui/button.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { ICON_NAMES } from "./icon.js";
|
|
3
|
-
export const BUTTON_VARIANTS = ["
|
|
3
|
+
export const BUTTON_VARIANTS = ["secondary", "primary"];
|
|
4
4
|
export const BUTTON_MAX_LABEL_CHARS = 30;
|
|
5
5
|
export const buttonProps = z.object({
|
|
6
6
|
label: z.string().min(1).max(BUTTON_MAX_LABEL_CHARS),
|