@farcaster/snap 1.4.1 → 1.5.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 +32 -0
- package/dist/colors.js +64 -0
- package/dist/constants.d.ts +12 -35
- package/dist/constants.js +19 -67
- package/dist/index.d.ts +3 -2
- package/dist/index.js +3 -2
- package/dist/schemas.d.ts +143 -10
- package/dist/schemas.js +140 -32
- package/dist/server/parseRequest.d.ts +6 -0
- package/dist/server/parseRequest.js +1 -2
- package/dist/ui/bar-chart.js +2 -1
- package/dist/ui/button-group.d.ts +10 -2
- package/dist/ui/button-group.js +12 -4
- package/dist/ui/button.d.ts +6 -4
- package/dist/ui/button.js +2 -1
- package/dist/ui/catalog.d.ts +17 -9
- package/dist/ui/catalog.js +7 -4
- package/dist/ui/group.d.ts +0 -1
- package/dist/ui/group.js +2 -1
- package/dist/ui/progress.js +1 -1
- package/dist/ui/schema.js +1 -1
- package/dist/ui/spacer.d.ts +1 -1
- package/dist/ui/spacer.js +2 -2
- package/dist/ui/toggle.d.ts +1 -1
- package/dist/ui/toggle.js +1 -1
- package/package.json +1 -1
- package/src/colors.ts +73 -0
- package/src/constants.ts +22 -77
- package/src/index.ts +14 -2
- package/src/schemas.ts +181 -43
- package/src/server/parseRequest.ts +8 -2
- package/src/ui/bar-chart.ts +2 -5
- package/src/ui/button-group.ts +22 -9
- package/src/ui/button.ts +2 -1
- package/src/ui/catalog.ts +8 -4
- package/src/ui/group.ts +2 -1
- package/src/ui/progress.ts +1 -1
- package/src/ui/schema.ts +1 -1
- package/src/ui/spacer.ts +2 -2
- package/src/ui/toggle.ts +1 -1
package/dist/schemas.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import {
|
|
2
|
+
import { BUTTON_ACTION, BUTTON_ACTION_VALUES, CLIENT_ACTION, BUTTON_GROUP_STYLE, BUTTON_GROUP_STYLE_VALUES, BUTTON_LAYOUT_VALUES, BUTTON_STYLE_VALUES, DEFAULT_BUTTON_LAYOUT, DEFAULT_GRID_GAP, DEFAULT_LIST_STYLE, DEFAULT_SLIDER_STEP, EFFECT_VALUES, ELEMENT_TYPE, GRID_CELL_SIZE_VALUES, GRID_GAP_VALUES, GROUP_LAYOUT_VALUES, HEX_COLOR_6_RE, HTTP_PREFIX, HTTPS_PREFIX, IMAGE_ASPECT_VALUES, INTERACTIVE_ELEMENT_TYPES, LIMITS, LIST_STYLE_VALUES, MEDIA_ELEMENT_TYPES, PAGE_ROOT_TYPE, SLIDER_STEP_ALIGN_EPS, SPACER_SIZE, SPACER_SIZE_VALUES, SPEC_VERSION, TEXT_ALIGN_VALUES, TEXT_CONTENT_MAX, TEXT_STYLE, TEXT_STYLE_VALUES, } from "./constants.js";
|
|
3
|
+
import { BAR_CHART_COLOR_VALUES, DEFAULT_THEME_ACCENT, PALETTE_COLOR_VALUES, PROGRESS_COLOR_VALUES, } from "./colors.js";
|
|
3
4
|
/**
|
|
4
5
|
* post/link/mini_app targets must be HTTPS in production; allow HTTP only for
|
|
5
6
|
* loopback hosts so local snap servers (e.g. http://localhost:3014/snap) validate.
|
|
@@ -28,25 +29,8 @@ const themeSchema = z
|
|
|
28
29
|
accent: themeAccentSchema.default(DEFAULT_THEME_ACCENT),
|
|
29
30
|
})
|
|
30
31
|
.strict();
|
|
31
|
-
const
|
|
32
|
-
message: "URL must use HTTPS",
|
|
33
|
-
});
|
|
34
|
-
function hasAllowedMediaExtension(urlString, allowedExtensions) {
|
|
35
|
-
try {
|
|
36
|
-
const url = new URL(urlString);
|
|
37
|
-
if (url.protocol !== "https:")
|
|
38
|
-
return false;
|
|
39
|
-
const lowerPathname = url.pathname.toLowerCase();
|
|
40
|
-
return allowedExtensions.some((extension) => lowerPathname.endsWith(`.${extension}`));
|
|
41
|
-
}
|
|
42
|
-
catch {
|
|
43
|
-
return false;
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
const imageUrlSchema = z
|
|
47
|
-
.string()
|
|
48
|
-
.refine((s) => hasAllowedMediaExtension(s, ["jpg", "png", "gif", "webp"]), {
|
|
49
|
-
message: "image URL must use HTTPS and end with a supported extension (.jpg, .png, .gif, .webp)",
|
|
32
|
+
const imageUrlSchema = z.string().refine((s) => s.startsWith(HTTPS_PREFIX), {
|
|
33
|
+
message: "image URL must use HTTPS",
|
|
50
34
|
});
|
|
51
35
|
const textAlignSchema = z.enum(TEXT_ALIGN_VALUES);
|
|
52
36
|
const textElementSchema = z
|
|
@@ -152,7 +136,7 @@ const gridElementSchema = z
|
|
|
152
136
|
rows: z.number().int().min(LIMITS.minGridRows).max(LIMITS.maxGridRows),
|
|
153
137
|
cells: z.array(gridCellSchema),
|
|
154
138
|
cellSize: z.enum(GRID_CELL_SIZE_VALUES).optional(),
|
|
155
|
-
gap: z.enum(GRID_GAP_VALUES).
|
|
139
|
+
gap: z.enum(GRID_GAP_VALUES).default(DEFAULT_GRID_GAP),
|
|
156
140
|
interactive: z.boolean().optional(),
|
|
157
141
|
})
|
|
158
142
|
.superRefine((val, ctx) => {
|
|
@@ -300,24 +284,134 @@ const barChartElementSchema = z
|
|
|
300
284
|
});
|
|
301
285
|
const buttonActionSchema = z.enum(BUTTON_ACTION_VALUES);
|
|
302
286
|
const buttonStyleSchema = z.enum(BUTTON_STYLE_VALUES);
|
|
287
|
+
/* ------------------------------------------------------------------ */
|
|
288
|
+
/* Client action schemas */
|
|
289
|
+
/* ------------------------------------------------------------------ */
|
|
290
|
+
const viewCastClientActionSchema = z
|
|
291
|
+
.object({
|
|
292
|
+
type: z.literal(CLIENT_ACTION.view_cast),
|
|
293
|
+
hash: z.string().min(1),
|
|
294
|
+
})
|
|
295
|
+
.strict();
|
|
296
|
+
const viewProfileClientActionSchema = z
|
|
297
|
+
.object({
|
|
298
|
+
type: z.literal(CLIENT_ACTION.view_profile),
|
|
299
|
+
fid: z.number().int().nonnegative(),
|
|
300
|
+
})
|
|
301
|
+
.strict();
|
|
302
|
+
const composeCastClientActionSchema = z
|
|
303
|
+
.object({
|
|
304
|
+
type: z.literal(CLIENT_ACTION.compose_cast),
|
|
305
|
+
text: z.string().optional(),
|
|
306
|
+
embeds: z
|
|
307
|
+
.array(z.string())
|
|
308
|
+
.max(2, { message: "compose_cast embeds: max 2 URLs" })
|
|
309
|
+
.optional(),
|
|
310
|
+
parent: z
|
|
311
|
+
.object({
|
|
312
|
+
type: z.literal("cast"),
|
|
313
|
+
hash: z.string().min(1),
|
|
314
|
+
})
|
|
315
|
+
.strict()
|
|
316
|
+
.optional(),
|
|
317
|
+
channelKey: z.string().optional(),
|
|
318
|
+
})
|
|
319
|
+
.strict();
|
|
320
|
+
const viewTokenClientActionSchema = z
|
|
321
|
+
.object({
|
|
322
|
+
type: z.literal(CLIENT_ACTION.view_token),
|
|
323
|
+
/** CAIP-19 asset ID (e.g. "eip155:8453/erc20:0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913") */
|
|
324
|
+
token: z.string().min(1),
|
|
325
|
+
})
|
|
326
|
+
.strict();
|
|
327
|
+
const sendTokenClientActionSchema = z
|
|
328
|
+
.object({
|
|
329
|
+
type: z.literal(CLIENT_ACTION.send_token),
|
|
330
|
+
/** CAIP-19 asset ID */
|
|
331
|
+
token: z.string().optional(),
|
|
332
|
+
/** Amount in raw token units (e.g. "1000000" for 1 USDC) */
|
|
333
|
+
amount: z.string().optional(),
|
|
334
|
+
recipientFid: z.number().int().nonnegative().optional(),
|
|
335
|
+
recipientAddress: z.string().optional(),
|
|
336
|
+
})
|
|
337
|
+
.strict();
|
|
338
|
+
const swapTokenClientActionSchema = z
|
|
339
|
+
.object({
|
|
340
|
+
type: z.literal(CLIENT_ACTION.swap_token),
|
|
341
|
+
/** CAIP-19 asset ID to sell */
|
|
342
|
+
sellToken: z.string().optional(),
|
|
343
|
+
/** CAIP-19 asset ID to buy */
|
|
344
|
+
buyToken: z.string().optional(),
|
|
345
|
+
/** Amount in raw token units */
|
|
346
|
+
sellAmount: z.string().optional(),
|
|
347
|
+
})
|
|
348
|
+
.strict();
|
|
349
|
+
export const clientActionSchema = z.discriminatedUnion("type", [
|
|
350
|
+
viewCastClientActionSchema,
|
|
351
|
+
viewProfileClientActionSchema,
|
|
352
|
+
composeCastClientActionSchema,
|
|
353
|
+
viewTokenClientActionSchema,
|
|
354
|
+
sendTokenClientActionSchema,
|
|
355
|
+
swapTokenClientActionSchema,
|
|
356
|
+
]);
|
|
357
|
+
/* ------------------------------------------------------------------ */
|
|
358
|
+
/* Button schema */
|
|
359
|
+
/* ------------------------------------------------------------------ */
|
|
303
360
|
const buttonSchema = z
|
|
304
361
|
.object({
|
|
305
362
|
label: z.string().min(1).max(LIMITS.maxButtonLabelChars),
|
|
306
363
|
action: buttonActionSchema,
|
|
307
|
-
/** URL
|
|
308
|
-
target: z.string().min(1),
|
|
364
|
+
/** URL target for post/link/mini_app buttons */
|
|
365
|
+
target: z.string().min(1).optional(),
|
|
366
|
+
/** Structured client action for client buttons */
|
|
367
|
+
client_action: clientActionSchema.optional(),
|
|
309
368
|
style: buttonStyleSchema.optional(),
|
|
310
369
|
})
|
|
311
370
|
.superRefine((val, ctx) => {
|
|
312
|
-
if (
|
|
313
|
-
|
|
314
|
-
val.
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
}
|
|
371
|
+
if (val.action === BUTTON_ACTION.client) {
|
|
372
|
+
// client buttons require client_action, must not have target
|
|
373
|
+
if (val.client_action === undefined) {
|
|
374
|
+
ctx.addIssue({
|
|
375
|
+
code: "custom",
|
|
376
|
+
message: `button with action "client" must include a "client_action" object`,
|
|
377
|
+
path: ["client_action"],
|
|
378
|
+
});
|
|
379
|
+
}
|
|
380
|
+
if (val.target !== undefined) {
|
|
381
|
+
ctx.addIssue({
|
|
382
|
+
code: "custom",
|
|
383
|
+
message: `button with action "client" must not include "target"`,
|
|
384
|
+
path: ["target"],
|
|
385
|
+
});
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
else {
|
|
389
|
+
// post/link/mini_app buttons require target, must not have client_action
|
|
390
|
+
if (val.target === undefined) {
|
|
391
|
+
ctx.addIssue({
|
|
392
|
+
code: "custom",
|
|
393
|
+
message: `button with action "${val.action}" must include a "target" URL`,
|
|
394
|
+
path: ["target"],
|
|
395
|
+
});
|
|
396
|
+
}
|
|
397
|
+
if (val.client_action !== undefined) {
|
|
398
|
+
ctx.addIssue({
|
|
399
|
+
code: "custom",
|
|
400
|
+
message: `button with action "${val.action}" must not include "client_action"`,
|
|
401
|
+
path: ["client_action"],
|
|
402
|
+
});
|
|
403
|
+
}
|
|
404
|
+
if (val.target &&
|
|
405
|
+
(val.action === BUTTON_ACTION.post ||
|
|
406
|
+
val.action === BUTTON_ACTION.link ||
|
|
407
|
+
val.action === BUTTON_ACTION.mini_app) &&
|
|
408
|
+
!isSecureOrLoopbackHttpButtonTarget(val.target)) {
|
|
409
|
+
ctx.addIssue({
|
|
410
|
+
code: "custom",
|
|
411
|
+
message: `button target must use HTTPS (or http:// on localhost / 127.0.0.1 for development) for action "${val.action}" (received: ${val.target})`,
|
|
412
|
+
path: ["target"],
|
|
413
|
+
});
|
|
414
|
+
}
|
|
321
415
|
}
|
|
322
416
|
});
|
|
323
417
|
/** Child elements allowed inside `group` (no media, no nested group) */
|
|
@@ -457,3 +551,17 @@ export const snapActionSchema = z.discriminatedUnion("type", [
|
|
|
457
551
|
snapGetActionSchema,
|
|
458
552
|
snapPostActionSchema,
|
|
459
553
|
]);
|
|
554
|
+
export function createDefaultDataStore() {
|
|
555
|
+
const err = new Error("Data store is not configured. Use withUpstash() from @farcaster/snap-upstash or provide a data store implementation.");
|
|
556
|
+
return {
|
|
557
|
+
get(_key) {
|
|
558
|
+
return Promise.reject(err);
|
|
559
|
+
},
|
|
560
|
+
set(_key, _value) {
|
|
561
|
+
return Promise.reject(err);
|
|
562
|
+
},
|
|
563
|
+
withLock(_fn) {
|
|
564
|
+
return Promise.reject(err);
|
|
565
|
+
},
|
|
566
|
+
};
|
|
567
|
+
}
|
|
@@ -21,6 +21,12 @@ export type ParseRequestOptions = {
|
|
|
21
21
|
* When true, skip {@link verifyJFSRequestBody} (signature checks).
|
|
22
22
|
*/
|
|
23
23
|
skipJFSVerification?: boolean;
|
|
24
|
+
/**
|
|
25
|
+
* Maximum allowed absolute difference between the request timestamp and the
|
|
26
|
+
* server clock, in seconds. Requests outside this window are rejected as
|
|
27
|
+
* potential replays. Defaults to 300 (5 minutes) when not provided.
|
|
28
|
+
*/
|
|
29
|
+
maxSkewSeconds?: number;
|
|
24
30
|
};
|
|
25
31
|
export type ParseRequestResult = {
|
|
26
32
|
success: true;
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { ACTION_TYPE_GET, ACTION_TYPE_POST, payloadSchema, } from "../schemas.js";
|
|
2
2
|
import { decodePayload, verifyJFSRequestBody } from "./verify.js";
|
|
3
3
|
import { z } from "zod";
|
|
4
|
-
/** Default replay window per SPEC.md § Replay Protection (5 minutes). */
|
|
5
4
|
const DEFAULT_SNAP_POST_MAX_SKEW_SECONDS = 300;
|
|
6
5
|
const requestBodySchema = z.object({
|
|
7
6
|
header: z.string(),
|
|
@@ -29,7 +28,7 @@ export async function parseRequest(request, options = {}) {
|
|
|
29
28
|
action: { type: ACTION_TYPE_GET },
|
|
30
29
|
};
|
|
31
30
|
}
|
|
32
|
-
const maxSkew = DEFAULT_SNAP_POST_MAX_SKEW_SECONDS;
|
|
31
|
+
const maxSkew = options.maxSkewSeconds ?? DEFAULT_SNAP_POST_MAX_SKEW_SECONDS;
|
|
33
32
|
const nowSec = Math.floor(Date.now() / 1000);
|
|
34
33
|
const text = await request.text();
|
|
35
34
|
let jsonBody;
|
package/dist/ui/bar-chart.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import {
|
|
2
|
+
import { LIMITS } from "../constants.js";
|
|
3
|
+
import { BAR_CHART_COLOR_VALUES, PALETTE_COLOR_VALUES } from "../colors.js";
|
|
3
4
|
export const barChartProps = z.object({
|
|
4
5
|
bars: z
|
|
5
6
|
.array(z.object({
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
export declare const buttonGroupProps: z.ZodObject<{
|
|
2
|
+
export declare const buttonGroupProps: z.ZodPipe<z.ZodObject<{
|
|
3
3
|
name: z.ZodString;
|
|
4
4
|
options: z.ZodArray<z.ZodString>;
|
|
5
5
|
style: z.ZodOptional<z.ZodEnum<{
|
|
@@ -7,5 +7,13 @@ export declare const buttonGroupProps: z.ZodObject<{
|
|
|
7
7
|
stack: "stack";
|
|
8
8
|
grid: "grid";
|
|
9
9
|
}>>;
|
|
10
|
-
}, z.core.$strip
|
|
10
|
+
}, z.core.$strip>, z.ZodTransform<{
|
|
11
|
+
style: "row" | "stack" | "grid";
|
|
12
|
+
name: string;
|
|
13
|
+
options: string[];
|
|
14
|
+
}, {
|
|
15
|
+
name: string;
|
|
16
|
+
options: string[];
|
|
17
|
+
style?: "row" | "stack" | "grid" | undefined;
|
|
18
|
+
}>>;
|
|
11
19
|
export type ButtonGroupProps = z.infer<typeof buttonGroupProps>;
|
package/dist/ui/button-group.js
CHANGED
|
@@ -1,10 +1,18 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import { BUTTON_GROUP_STYLE_VALUES, LIMITS } from "../constants.js";
|
|
3
|
-
export const buttonGroupProps = z
|
|
2
|
+
import { BUTTON_GROUP_STYLE, BUTTON_GROUP_STYLE_VALUES, LIMITS, } from "../constants.js";
|
|
3
|
+
export const buttonGroupProps = z
|
|
4
|
+
.object({
|
|
4
5
|
name: z.string().min(1),
|
|
5
6
|
options: z
|
|
6
|
-
.array(z.string())
|
|
7
|
+
.array(z.string().max(LIMITS.maxButtonGroupOptionChars))
|
|
7
8
|
.min(LIMITS.minButtonGroupOptions)
|
|
8
9
|
.max(LIMITS.maxButtonGroupOptions),
|
|
9
10
|
style: z.enum(BUTTON_GROUP_STYLE_VALUES).optional(),
|
|
10
|
-
})
|
|
11
|
+
})
|
|
12
|
+
.transform((val) => ({
|
|
13
|
+
...val,
|
|
14
|
+
style: val.style ??
|
|
15
|
+
(val.options.length <= 3
|
|
16
|
+
? BUTTON_GROUP_STYLE.row
|
|
17
|
+
: BUTTON_GROUP_STYLE.stack),
|
|
18
|
+
}));
|
package/dist/ui/button.d.ts
CHANGED
|
@@ -5,9 +5,10 @@ export declare const actionButtonProps: z.ZodObject<{
|
|
|
5
5
|
post: "post";
|
|
6
6
|
link: "link";
|
|
7
7
|
mini_app: "mini_app";
|
|
8
|
-
|
|
8
|
+
client: "client";
|
|
9
9
|
}>;
|
|
10
|
-
target: z.ZodString
|
|
10
|
+
target: z.ZodOptional<z.ZodString>;
|
|
11
|
+
client_action: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
11
12
|
style: z.ZodOptional<z.ZodEnum<{
|
|
12
13
|
primary: "primary";
|
|
13
14
|
secondary: "secondary";
|
|
@@ -21,9 +22,10 @@ export declare const buttonProps: z.ZodObject<{
|
|
|
21
22
|
post: "post";
|
|
22
23
|
link: "link";
|
|
23
24
|
mini_app: "mini_app";
|
|
24
|
-
|
|
25
|
+
client: "client";
|
|
25
26
|
}>;
|
|
26
|
-
target: z.ZodString
|
|
27
|
+
target: z.ZodOptional<z.ZodString>;
|
|
28
|
+
client_action: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
27
29
|
style: z.ZodOptional<z.ZodEnum<{
|
|
28
30
|
primary: "primary";
|
|
29
31
|
secondary: "secondary";
|
package/dist/ui/button.js
CHANGED
|
@@ -3,7 +3,8 @@ import { BUTTON_ACTION_VALUES, BUTTON_STYLE_VALUES } from "../constants.js";
|
|
|
3
3
|
export const actionButtonProps = z.object({
|
|
4
4
|
label: z.string(),
|
|
5
5
|
action: z.enum(BUTTON_ACTION_VALUES),
|
|
6
|
-
target: z.string(),
|
|
6
|
+
target: z.string().optional(),
|
|
7
|
+
client_action: z.record(z.string(), z.unknown()).optional(),
|
|
7
8
|
style: z.enum(BUTTON_STYLE_VALUES).optional(),
|
|
8
9
|
});
|
|
9
10
|
/** Same schema as `actionButtonProps` (legacy export name). */
|
package/dist/ui/catalog.d.ts
CHANGED
|
@@ -69,7 +69,7 @@ export declare const snapJsonRenderCatalog: import("@json-render/core").Catalog<
|
|
|
69
69
|
};
|
|
70
70
|
Spacer: {
|
|
71
71
|
props: z.ZodObject<{
|
|
72
|
-
size: z.
|
|
72
|
+
size: z.ZodDefault<z.ZodEnum<{
|
|
73
73
|
small: "small";
|
|
74
74
|
medium: "medium";
|
|
75
75
|
large: "large";
|
|
@@ -155,7 +155,7 @@ export declare const snapJsonRenderCatalog: import("@json-render/core").Catalog<
|
|
|
155
155
|
description: string;
|
|
156
156
|
};
|
|
157
157
|
ButtonGroup: {
|
|
158
|
-
props: z.ZodObject<{
|
|
158
|
+
props: z.ZodPipe<z.ZodObject<{
|
|
159
159
|
name: z.ZodString;
|
|
160
160
|
options: z.ZodArray<z.ZodString>;
|
|
161
161
|
style: z.ZodOptional<z.ZodEnum<{
|
|
@@ -163,14 +163,22 @@ export declare const snapJsonRenderCatalog: import("@json-render/core").Catalog<
|
|
|
163
163
|
stack: "stack";
|
|
164
164
|
grid: "grid";
|
|
165
165
|
}>>;
|
|
166
|
-
}, z.core.$strip
|
|
166
|
+
}, z.core.$strip>, z.ZodTransform<{
|
|
167
|
+
style: "row" | "stack" | "grid";
|
|
168
|
+
name: string;
|
|
169
|
+
options: string[];
|
|
170
|
+
}, {
|
|
171
|
+
name: string;
|
|
172
|
+
options: string[];
|
|
173
|
+
style?: "row" | "stack" | "grid" | undefined;
|
|
174
|
+
}>>;
|
|
167
175
|
description: string;
|
|
168
176
|
};
|
|
169
177
|
Toggle: {
|
|
170
178
|
props: z.ZodObject<{
|
|
171
179
|
name: z.ZodString;
|
|
172
180
|
label: z.ZodString;
|
|
173
|
-
value: z.
|
|
181
|
+
value: z.ZodDefault<z.ZodBoolean>;
|
|
174
182
|
}, z.core.$strip>;
|
|
175
183
|
description: string;
|
|
176
184
|
};
|
|
@@ -209,7 +217,6 @@ export declare const snapJsonRenderCatalog: import("@json-render/core").Catalog<
|
|
|
209
217
|
props: z.ZodObject<{
|
|
210
218
|
layout: z.ZodEnum<{
|
|
211
219
|
row: "row";
|
|
212
|
-
grid: "grid";
|
|
213
220
|
}>;
|
|
214
221
|
}, z.core.$strip>;
|
|
215
222
|
description: string;
|
|
@@ -225,9 +232,10 @@ export declare const snapJsonRenderCatalog: import("@json-render/core").Catalog<
|
|
|
225
232
|
post: "post";
|
|
226
233
|
link: "link";
|
|
227
234
|
mini_app: "mini_app";
|
|
228
|
-
|
|
235
|
+
client: "client";
|
|
229
236
|
}>;
|
|
230
|
-
target: z.ZodString
|
|
237
|
+
target: z.ZodOptional<z.ZodString>;
|
|
238
|
+
client_action: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
231
239
|
style: z.ZodOptional<z.ZodEnum<{
|
|
232
240
|
primary: "primary";
|
|
233
241
|
secondary: "secondary";
|
|
@@ -261,10 +269,10 @@ export declare const snapJsonRenderCatalog: import("@json-render/core").Catalog<
|
|
|
261
269
|
target: z.ZodString;
|
|
262
270
|
}, z.core.$strip>;
|
|
263
271
|
};
|
|
264
|
-
|
|
272
|
+
snap_client: {
|
|
265
273
|
description: string;
|
|
266
274
|
params: z.ZodObject<{
|
|
267
|
-
|
|
275
|
+
client_action: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
268
276
|
}, z.core.$strip>;
|
|
269
277
|
};
|
|
270
278
|
};
|
package/dist/ui/catalog.js
CHANGED
|
@@ -26,6 +26,9 @@ const snapPostParams = z.object({
|
|
|
26
26
|
const snapTargetParams = z.object({
|
|
27
27
|
target: z.string(),
|
|
28
28
|
});
|
|
29
|
+
const snapClientParams = z.object({
|
|
30
|
+
client_action: z.record(z.string(), z.unknown()),
|
|
31
|
+
});
|
|
29
32
|
/**
|
|
30
33
|
* Basic catalog: one json-render component per snap element type, plus ActionButton for snap buttons.
|
|
31
34
|
* Does not validate cross-field rules (media count, height budget); snap JSON still goes through `@farcaster/snap` validation.
|
|
@@ -90,7 +93,7 @@ export const snapJsonRenderCatalog = defineCatalog(snapJsonRenderSchema, {
|
|
|
90
93
|
},
|
|
91
94
|
ActionButton: {
|
|
92
95
|
props: actionButtonProps,
|
|
93
|
-
description: "Snap action button: post (next page), link (browser), mini_app,
|
|
96
|
+
description: "Snap action button: post (next page), link (browser), mini_app, client — target is HTTPS URL or client_action object.",
|
|
94
97
|
},
|
|
95
98
|
},
|
|
96
99
|
actions: {
|
|
@@ -106,9 +109,9 @@ export const snapJsonRenderCatalog = defineCatalog(snapJsonRenderSchema, {
|
|
|
106
109
|
description: "Open `target` as an in-app Farcaster mini app.",
|
|
107
110
|
params: snapTargetParams,
|
|
108
111
|
},
|
|
109
|
-
|
|
110
|
-
description: "
|
|
111
|
-
params:
|
|
112
|
+
snap_client: {
|
|
113
|
+
description: "Trigger a Farcaster client action (view_cast, view_profile, compose_cast, …).",
|
|
114
|
+
params: snapClientParams,
|
|
112
115
|
},
|
|
113
116
|
},
|
|
114
117
|
});
|
package/dist/ui/group.d.ts
CHANGED
package/dist/ui/group.js
CHANGED
package/dist/ui/progress.js
CHANGED
package/dist/ui/schema.js
CHANGED
|
@@ -26,6 +26,6 @@ export const snapJsonRenderSchema = defineSchema((s) => ({
|
|
|
26
26
|
defaultRules: [
|
|
27
27
|
"You are generating auxiliary UI for a Farcaster Snap. Prefer components matching snap element types (Text, Image, ButtonGroup, …).",
|
|
28
28
|
"Snap pages use a Stack root with at most 5 body children and 1 media element (Image or Grid); keep generated trees small.",
|
|
29
|
-
"Bottom-of-card snap buttons are ActionButton components; use actions post / link / mini_app /
|
|
29
|
+
"Bottom-of-card snap buttons are ActionButton components; use actions post / link / mini_app / client.",
|
|
30
30
|
],
|
|
31
31
|
});
|
package/dist/ui/spacer.d.ts
CHANGED
package/dist/ui/spacer.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import { SPACER_SIZE_VALUES } from "../constants.js";
|
|
2
|
+
import { SPACER_SIZE, SPACER_SIZE_VALUES } from "../constants.js";
|
|
3
3
|
export const spacerProps = z.object({
|
|
4
|
-
size: z.enum(SPACER_SIZE_VALUES).
|
|
4
|
+
size: z.enum(SPACER_SIZE_VALUES).default(SPACER_SIZE.medium),
|
|
5
5
|
});
|
package/dist/ui/toggle.d.ts
CHANGED
|
@@ -2,6 +2,6 @@ import { z } from "zod";
|
|
|
2
2
|
export declare const toggleProps: z.ZodObject<{
|
|
3
3
|
name: z.ZodString;
|
|
4
4
|
label: z.ZodString;
|
|
5
|
-
value: z.
|
|
5
|
+
value: z.ZodDefault<z.ZodBoolean>;
|
|
6
6
|
}, z.core.$strip>;
|
|
7
7
|
export type ToggleProps = z.infer<typeof toggleProps>;
|
package/dist/ui/toggle.js
CHANGED
package/package.json
CHANGED
package/src/colors.ts
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Named color palette for snaps. Snap authors specify a name; the client maps
|
|
3
|
+
* it to a hex value appropriate for its current light/dark mode.
|
|
4
|
+
*
|
|
5
|
+
* Light-mode hex values (used by emulator):
|
|
6
|
+
* gray=#8F8F8F blue=#006BFF red=#FC0036 amber=#FFAE00
|
|
7
|
+
* green=#28A948 teal=#00AC96 purple=#8B5CF6 pink=#F32782
|
|
8
|
+
*
|
|
9
|
+
* Dark-mode hex values (for reference; client-owned):
|
|
10
|
+
* gray=#8F8F8F blue=#006FFE red=#F13342 amber=#FFAE00
|
|
11
|
+
* green=#00AC3A teal=#00AA96 purple=#A78BFA pink=#F12B82
|
|
12
|
+
*/
|
|
13
|
+
export const PALETTE_COLOR = {
|
|
14
|
+
gray: "gray",
|
|
15
|
+
blue: "blue",
|
|
16
|
+
red: "red",
|
|
17
|
+
amber: "amber",
|
|
18
|
+
green: "green",
|
|
19
|
+
teal: "teal",
|
|
20
|
+
purple: "purple",
|
|
21
|
+
pink: "pink",
|
|
22
|
+
} as const;
|
|
23
|
+
|
|
24
|
+
export const PALETTE_COLOR_ACCENT = "accent" as const;
|
|
25
|
+
|
|
26
|
+
export const DEFAULT_THEME_ACCENT = PALETTE_COLOR.purple;
|
|
27
|
+
|
|
28
|
+
export const PALETTE_COLOR_VALUES = [
|
|
29
|
+
PALETTE_COLOR.gray,
|
|
30
|
+
PALETTE_COLOR.blue,
|
|
31
|
+
PALETTE_COLOR.red,
|
|
32
|
+
PALETTE_COLOR.amber,
|
|
33
|
+
PALETTE_COLOR.green,
|
|
34
|
+
PALETTE_COLOR.teal,
|
|
35
|
+
PALETTE_COLOR.purple,
|
|
36
|
+
PALETTE_COLOR.pink,
|
|
37
|
+
] as const;
|
|
38
|
+
|
|
39
|
+
export type PaletteColor = (typeof PALETTE_COLOR_VALUES)[number];
|
|
40
|
+
|
|
41
|
+
/** Light-mode hex for each palette color (emulator / reference client). */
|
|
42
|
+
export const PALETTE_LIGHT_HEX: Record<PaletteColor, string> = {
|
|
43
|
+
gray: "#8F8F8F",
|
|
44
|
+
blue: "#006BFF",
|
|
45
|
+
red: "#FC0036",
|
|
46
|
+
amber: "#FFAE00",
|
|
47
|
+
green: "#28A948",
|
|
48
|
+
teal: "#00AC96",
|
|
49
|
+
purple: "#8B5CF6",
|
|
50
|
+
pink: "#F32782",
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
/** Dark-mode hex for each palette color (reference). */
|
|
54
|
+
export const PALETTE_DARK_HEX: Record<PaletteColor, string> = {
|
|
55
|
+
gray: "#8F8F8F",
|
|
56
|
+
blue: "#006FFE",
|
|
57
|
+
red: "#F13342",
|
|
58
|
+
amber: "#FFAE00",
|
|
59
|
+
green: "#00AC3A",
|
|
60
|
+
teal: "#00AA96",
|
|
61
|
+
purple: "#A78BFA",
|
|
62
|
+
pink: "#F12B82",
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
export const PROGRESS_COLOR_VALUES = [
|
|
66
|
+
PALETTE_COLOR_ACCENT,
|
|
67
|
+
...PALETTE_COLOR_VALUES,
|
|
68
|
+
] as const;
|
|
69
|
+
|
|
70
|
+
export const BAR_CHART_COLOR_VALUES = [
|
|
71
|
+
PALETTE_COLOR_ACCENT,
|
|
72
|
+
...PALETTE_COLOR_VALUES,
|
|
73
|
+
] as const;
|