@farcaster/snap 1.9.0 → 1.13.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.
Files changed (45) hide show
  1. package/dist/constants.d.ts +8 -0
  2. package/dist/constants.js +10 -0
  3. package/dist/index.d.ts +4 -6
  4. package/dist/index.js +2 -4
  5. package/dist/react/catalog-renderer.js +4 -0
  6. package/dist/react/components/bar-chart.d.ts +5 -0
  7. package/dist/react/components/bar-chart.js +31 -0
  8. package/dist/react/components/cell-grid.d.ts +5 -0
  9. package/dist/react/components/cell-grid.js +86 -0
  10. package/dist/react-native/catalog-renderer.js +4 -0
  11. package/dist/react-native/components/snap-bar-chart.d.ts +2 -0
  12. package/dist/react-native/components/snap-bar-chart.js +39 -0
  13. package/dist/react-native/components/snap-cell-grid.d.ts +2 -0
  14. package/dist/react-native/components/snap-cell-grid.js +96 -0
  15. package/dist/schemas.d.ts +45 -3
  16. package/dist/schemas.js +2 -2
  17. package/dist/ui/bar-chart.d.ts +30 -0
  18. package/dist/ui/bar-chart.js +30 -0
  19. package/dist/ui/catalog.d.ts +65 -0
  20. package/dist/ui/catalog.js +10 -0
  21. package/dist/ui/cell-grid.d.ts +33 -0
  22. package/dist/ui/cell-grid.js +38 -0
  23. package/dist/ui/index.d.ts +4 -0
  24. package/dist/ui/index.js +2 -0
  25. package/llms.txt +19 -4
  26. package/package.json +1 -1
  27. package/src/constants.ts +12 -0
  28. package/src/index.ts +8 -12
  29. package/src/react/catalog-renderer.tsx +4 -0
  30. package/src/react/components/bar-chart.tsx +67 -0
  31. package/src/react/components/cell-grid.tsx +131 -0
  32. package/src/react-native/catalog-renderer.tsx +4 -0
  33. package/src/react-native/components/snap-bar-chart.tsx +73 -0
  34. package/src/react-native/components/snap-cell-grid.tsx +152 -0
  35. package/src/schemas.ts +37 -11
  36. package/src/ui/bar-chart.ts +38 -0
  37. package/src/ui/catalog.ts +12 -0
  38. package/src/ui/cell-grid.ts +48 -0
  39. package/src/ui/index.ts +6 -0
  40. package/dist/dataStore.d.ts +0 -9
  41. package/dist/dataStore.js +0 -22
  42. package/dist/middleware.d.ts +0 -3
  43. package/dist/middleware.js +0 -3
  44. package/src/dataStore.ts +0 -38
  45. package/src/middleware.ts +0 -7
package/src/schemas.ts CHANGED
@@ -1,14 +1,7 @@
1
1
  import { z } from "zod";
2
2
  import type { Spec } from "@json-render/core";
3
- import {
4
- EFFECT_VALUES,
5
- SPEC_VERSION,
6
- } from "./constants";
7
- import {
8
- DEFAULT_THEME_ACCENT,
9
- PALETTE_COLOR_VALUES,
10
- } from "./colors";
11
- import { type SnapDataStore } from "./dataStore";
3
+ import { EFFECT_VALUES, SPEC_VERSION } from "./constants";
4
+ import { DEFAULT_THEME_ACCENT, PALETTE_COLOR_VALUES } from "./colors";
12
5
 
13
6
  // ─── Theme ─────────────────────────────────────────────
14
7
 
@@ -43,7 +36,41 @@ export const snapResponseSchema = z
43
36
  .strict();
44
37
 
45
38
  export type SnapResponse = z.infer<typeof snapResponseSchema>;
46
- export type SnapHandlerResult = z.input<typeof snapResponseSchema>;
39
+
40
+ /**
41
+ * Permissive element input type for snap handler authors.
42
+ * Allows dynamic element construction without requiring exact UIElement types.
43
+ */
44
+ export type SnapElementInput = {
45
+ type: string;
46
+ props?: Record<string, unknown>;
47
+ children?: string[];
48
+ on?: Record<string, unknown>;
49
+ [key: string]: unknown;
50
+ };
51
+
52
+ /**
53
+ * Permissive input type for the `ui` field in snap handler return values.
54
+ * Accepts dynamically-built element maps (e.g. `Record<string, SnapElementInput>`)
55
+ * without requiring exact UIElement types.
56
+ */
57
+ export type SnapSpecInput = {
58
+ root: string;
59
+ elements: Record<string, SnapElementInput>;
60
+ state?: Record<string, unknown>;
61
+ };
62
+
63
+ /**
64
+ * Return type for snap handler functions.
65
+ * Uses permissive input types so handlers can build elements dynamically
66
+ * without type casts. Runtime validation via the Zod schema still catches invalid shapes.
67
+ */
68
+ export type SnapHandlerResult = {
69
+ version: typeof SPEC_VERSION;
70
+ theme?: { accent?: z.input<typeof themeAccentSchema> };
71
+ effects?: z.input<typeof snapResponseSchema>["effects"];
72
+ ui: SnapSpecInput;
73
+ };
47
74
 
48
75
  // ─── POST payload ──────────────────────────────────────
49
76
 
@@ -92,7 +119,6 @@ export type SnapAction = z.infer<typeof snapActionSchema>;
92
119
  export type SnapContext = {
93
120
  action: SnapAction;
94
121
  request: Request;
95
- data: SnapDataStore;
96
122
  };
97
123
 
98
124
  export type SnapFunction = (ctx: SnapContext) => Promise<SnapHandlerResult>;
@@ -0,0 +1,38 @@
1
+ import { z } from "zod";
2
+ import { BAR_CHART_COLOR_VALUES, PALETTE_COLOR_VALUES } from "../colors.js";
3
+ import {
4
+ BAR_CHART_MAX_BARS,
5
+ BAR_CHART_LABEL_MAX_CHARS,
6
+ } from "../constants.js";
7
+
8
+ export const barChartProps = z
9
+ .object({
10
+ bars: z
11
+ .array(
12
+ z.object({
13
+ label: z.string().min(1).max(BAR_CHART_LABEL_MAX_CHARS),
14
+ value: z.number().nonnegative(),
15
+ color: z.enum(PALETTE_COLOR_VALUES).optional(),
16
+ }),
17
+ )
18
+ .min(1)
19
+ .max(BAR_CHART_MAX_BARS),
20
+ max: z.number().nonnegative().optional(),
21
+ color: z.enum(BAR_CHART_COLOR_VALUES).optional(),
22
+ })
23
+ .superRefine((val, ctx) => {
24
+ if (val.max !== undefined) {
25
+ for (let i = 0; i < val.bars.length; i++) {
26
+ const bar = val.bars[i]!;
27
+ if (bar.value > val.max) {
28
+ ctx.addIssue({
29
+ code: "custom",
30
+ message: `bar value (${bar.value}) exceeds chart max (${val.max})`,
31
+ path: ["bars", i, "value"],
32
+ });
33
+ }
34
+ }
35
+ }
36
+ });
37
+
38
+ export type BarChartProps = z.infer<typeof barChartProps>;
package/src/ui/catalog.ts CHANGED
@@ -15,6 +15,8 @@ import { separatorProps } from "./separator.js";
15
15
  import { sliderProps } from "./slider.js";
16
16
  import { stackProps } from "./stack.js";
17
17
  import { textProps } from "./text.js";
18
+ import { barChartProps } from "./bar-chart.js";
19
+ import { cellGridProps } from "./cell-grid.js";
18
20
 
19
21
  const snapClientParams = z.object({
20
22
  client_action: z.record(z.string(), z.unknown()),
@@ -97,6 +99,16 @@ export const snapJsonRenderCatalog = defineCatalog(snapJsonRenderSchema, {
97
99
  description:
98
100
  "Text block — size: md (body, default), sm (caption). Optional weight and align.",
99
101
  },
102
+ bar_chart: {
103
+ props: barChartProps,
104
+ description:
105
+ "Horizontal bar chart — 1–6 bars with label, value, and optional per-bar color. Optional max and default color.",
106
+ },
107
+ cell_grid: {
108
+ props: cellGridProps,
109
+ description:
110
+ "Cell grid — sparse colored cells on a rows×cols grid. Optional gap and selection mode (taps write to inputs[name]).",
111
+ },
100
112
  },
101
113
  actions: {
102
114
  submit: {
@@ -0,0 +1,48 @@
1
+ import { z } from "zod";
2
+ import { PALETTE_COLOR_VALUES } from "../colors.js";
3
+ import {
4
+ GRID_MIN_COLS,
5
+ GRID_MAX_COLS,
6
+ GRID_MIN_ROWS,
7
+ GRID_MAX_ROWS,
8
+ GRID_GAP_VALUES,
9
+ } from "../constants.js";
10
+
11
+ const cellGridCellSchema = z.object({
12
+ row: z.number().int().nonnegative(),
13
+ col: z.number().int().nonnegative(),
14
+ color: z.enum(PALETTE_COLOR_VALUES).optional(),
15
+ content: z.string().optional(),
16
+ });
17
+
18
+ export const cellGridProps = z
19
+ .object({
20
+ name: z.string().min(1).optional(),
21
+ cols: z.number().int().min(GRID_MIN_COLS).max(GRID_MAX_COLS),
22
+ rows: z.number().int().min(GRID_MIN_ROWS).max(GRID_MAX_ROWS),
23
+ cells: z.array(cellGridCellSchema),
24
+ gap: z.enum(GRID_GAP_VALUES).optional(),
25
+ select: z.enum(["off", "single", "multiple"]).optional(),
26
+ })
27
+ .superRefine((val, ctx) => {
28
+ const { cols, rows, cells } = val;
29
+ for (let i = 0; i < cells.length; i++) {
30
+ const c = cells[i]!;
31
+ if (c.row < 0 || c.row >= rows) {
32
+ ctx.addIssue({
33
+ code: "custom",
34
+ message: `cell_grid cell row ${c.row} out of bounds (0–${rows - 1})`,
35
+ path: ["cells", i, "row"],
36
+ });
37
+ }
38
+ if (c.col < 0 || c.col >= cols) {
39
+ ctx.addIssue({
40
+ code: "custom",
41
+ message: `cell_grid cell col ${c.col} out of bounds (0–${cols - 1})`,
42
+ path: ["cells", i, "col"],
43
+ });
44
+ }
45
+ }
46
+ });
47
+
48
+ export type CellGridProps = z.infer<typeof cellGridProps>;
package/src/ui/index.ts CHANGED
@@ -42,3 +42,9 @@ export type { StackProps } from "./stack.js";
42
42
 
43
43
  export { textProps } from "./text.js";
44
44
  export type { TextProps } from "./text.js";
45
+
46
+ export { barChartProps } from "./bar-chart.js";
47
+ export type { BarChartProps } from "./bar-chart.js";
48
+
49
+ export { cellGridProps } from "./cell-grid.js";
50
+ export type { CellGridProps } from "./cell-grid.js";
@@ -1,9 +0,0 @@
1
- export type DataStoreValue = string | number | boolean | null | DataStoreValue[] | {
2
- [key: string]: DataStoreValue;
3
- };
4
- export type SnapDataStore = {
5
- get(key: string): Promise<DataStoreValue | null>;
6
- set(key: string, value: DataStoreValue): Promise<void>;
7
- };
8
- export declare function createDefaultDataStore(): SnapDataStore;
9
- export declare function createInMemoryDataStore(): SnapDataStore;
package/dist/dataStore.js DELETED
@@ -1,22 +0,0 @@
1
- export function createDefaultDataStore() {
2
- const err = new Error("Data store is not configured. Use withTursoServerless() from @farcaster/snap-turso or provide a data store implementation.");
3
- return {
4
- get(_key) {
5
- return Promise.reject(err);
6
- },
7
- set(_key, _value) {
8
- return Promise.reject(err);
9
- },
10
- };
11
- }
12
- export function createInMemoryDataStore() {
13
- const data = new Map();
14
- return {
15
- async get(key) {
16
- return data.get(key) ?? null;
17
- },
18
- async set(key, value) {
19
- data.set(key, value);
20
- },
21
- };
22
- }
@@ -1,3 +0,0 @@
1
- import { SnapFunction } from "./schemas.js";
2
- export type Middleware = (fn: SnapFunction) => SnapFunction;
3
- export declare function useMiddleware(fn: SnapFunction, middleware: Middleware[]): SnapFunction;
@@ -1,3 +0,0 @@
1
- export function useMiddleware(fn, middleware) {
2
- return middleware.reduce((acc, middleware) => middleware(acc), fn);
3
- }
package/src/dataStore.ts DELETED
@@ -1,38 +0,0 @@
1
- export type DataStoreValue =
2
- | string
3
- | number
4
- | boolean
5
- | null
6
- | DataStoreValue[]
7
- | { [key: string]: DataStoreValue };
8
-
9
- export type SnapDataStore = {
10
- get(key: string): Promise<DataStoreValue | null>;
11
- set(key: string, value: DataStoreValue): Promise<void>;
12
- };
13
-
14
- export function createDefaultDataStore(): SnapDataStore {
15
- const err = new Error(
16
- "Data store is not configured. Use withTursoServerless() from @farcaster/snap-turso or provide a data store implementation.",
17
- );
18
- return {
19
- get(_key: string): Promise<never> {
20
- return Promise.reject(err);
21
- },
22
- set(_key: string, _value: DataStoreValue): Promise<never> {
23
- return Promise.reject(err);
24
- },
25
- };
26
- }
27
-
28
- export function createInMemoryDataStore(): SnapDataStore {
29
- const data = new Map<string, DataStoreValue>();
30
- return {
31
- async get(key: string): Promise<DataStoreValue | null> {
32
- return data.get(key) ?? null;
33
- },
34
- async set(key: string, value: DataStoreValue): Promise<void> {
35
- data.set(key, value);
36
- },
37
- };
38
- }
package/src/middleware.ts DELETED
@@ -1,7 +0,0 @@
1
- import { SnapFunction } from "./schemas";
2
-
3
- export type Middleware = (fn: SnapFunction) => SnapFunction;
4
-
5
- export function useMiddleware(fn: SnapFunction, middleware: Middleware[]) {
6
- return middleware.reduce((acc, middleware) => middleware(acc), fn);
7
- }