@shotstack/shotstack-canvas 1.6.6 → 1.7.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.
@@ -1,105 +1,124 @@
1
+ import { z } from 'zod';
1
2
  import { components } from '@shotstack/schemas';
2
3
 
3
- declare const CANVAS_CONFIG: {
4
- DEFAULTS: {
5
- width: number;
6
- height: number;
7
- pixelRatio: number;
8
- fontFamily: string;
9
- fontSize: number;
10
- color: string;
11
- textAlign: "center";
12
- };
13
- LIMITS: {
14
- minWidth: number;
15
- maxWidth: number;
16
- minHeight: number;
17
- maxHeight: number;
18
- minFontSize: number;
19
- maxFontSize: number;
20
- minDuration: number;
21
- maxDuration: number;
22
- maxTextLength: number;
23
- };
24
- ANIMATION_TYPES: readonly ["typewriter", "fadeIn", "slideIn", "shift", "ascend", "movingLetters"];
25
- };
4
+ declare const CanvasRichTextAssetSchema: z.ZodObject<{
5
+ type: z.ZodLiteral<"rich-text">;
6
+ text: z.ZodDefault<z.ZodString>;
7
+ width: z.ZodOptional<z.ZodDefault<z.ZodNumber>>;
8
+ height: z.ZodOptional<z.ZodDefault<z.ZodNumber>>;
9
+ font: z.ZodOptional<z.ZodObject<{
10
+ style: z.ZodOptional<z.ZodEnum<{
11
+ normal: "normal";
12
+ italic: "italic";
13
+ oblique: "oblique";
14
+ }>>;
15
+ family: z.ZodDefault<z.ZodString>;
16
+ size: z.ZodDefault<z.ZodNumber>;
17
+ weight: z.ZodDefault<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>;
18
+ color: z.ZodDefault<z.ZodString>;
19
+ opacity: z.ZodDefault<z.ZodNumber>;
20
+ background: z.ZodOptional<z.ZodString>;
21
+ }, z.core.$strip>>;
22
+ style: z.ZodOptional<z.ZodObject<{
23
+ letterSpacing: z.ZodDefault<z.ZodNumber>;
24
+ lineHeight: z.ZodDefault<z.ZodNumber>;
25
+ textTransform: z.ZodDefault<z.ZodEnum<{
26
+ none: "none";
27
+ uppercase: "uppercase";
28
+ lowercase: "lowercase";
29
+ capitalize: "capitalize";
30
+ }>>;
31
+ textDecoration: z.ZodDefault<z.ZodEnum<{
32
+ none: "none";
33
+ underline: "underline";
34
+ "line-through": "line-through";
35
+ }>>;
36
+ gradient: z.ZodOptional<z.ZodObject<{
37
+ type: z.ZodDefault<z.ZodEnum<{
38
+ linear: "linear";
39
+ radial: "radial";
40
+ }>>;
41
+ angle: z.ZodDefault<z.ZodNumber>;
42
+ stops: z.ZodArray<z.ZodObject<{
43
+ offset: z.ZodNumber;
44
+ color: z.ZodString;
45
+ }, z.core.$strip>>;
46
+ }, z.core.$strip>>;
47
+ }, z.core.$strip>>;
48
+ stroke: z.ZodOptional<z.ZodObject<{
49
+ width: z.ZodDefault<z.ZodNumber>;
50
+ color: z.ZodDefault<z.ZodString>;
51
+ opacity: z.ZodDefault<z.ZodNumber>;
52
+ }, z.core.$strip>>;
53
+ shadow: z.ZodOptional<z.ZodObject<{
54
+ offsetX: z.ZodDefault<z.ZodNumber>;
55
+ offsetY: z.ZodDefault<z.ZodNumber>;
56
+ blur: z.ZodDefault<z.ZodNumber>;
57
+ color: z.ZodDefault<z.ZodString>;
58
+ opacity: z.ZodDefault<z.ZodNumber>;
59
+ }, z.core.$strip>>;
60
+ background: z.ZodOptional<z.ZodObject<{
61
+ borderRadius: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
62
+ color: z.ZodOptional<z.ZodString>;
63
+ opacity: z.ZodDefault<z.ZodNumber>;
64
+ }, z.core.$strip>>;
65
+ border: z.ZodOptional<z.ZodObject<{
66
+ width: z.ZodDefault<z.ZodNumber>;
67
+ color: z.ZodDefault<z.ZodString>;
68
+ opacity: z.ZodDefault<z.ZodNumber>;
69
+ radius: z.ZodDefault<z.ZodNumber>;
70
+ }, z.core.$strip>>;
71
+ padding: z.ZodOptional<z.ZodUnion<readonly [z.ZodNumber, z.ZodObject<{
72
+ top: z.ZodDefault<z.ZodNumber>;
73
+ right: z.ZodDefault<z.ZodNumber>;
74
+ bottom: z.ZodDefault<z.ZodNumber>;
75
+ left: z.ZodDefault<z.ZodNumber>;
76
+ }, z.core.$strip>]>>;
77
+ align: z.ZodOptional<z.ZodObject<{
78
+ horizontal: z.ZodDefault<z.ZodEnum<{
79
+ center: "center";
80
+ right: "right";
81
+ left: "left";
82
+ }>>;
83
+ vertical: z.ZodDefault<z.ZodEnum<{
84
+ top: "top";
85
+ bottom: "bottom";
86
+ middle: "middle";
87
+ }>>;
88
+ }, z.core.$strip>>;
89
+ animation: z.ZodOptional<z.ZodObject<{
90
+ preset: z.ZodEnum<{
91
+ typewriter: "typewriter";
92
+ fadeIn: "fadeIn";
93
+ slideIn: "slideIn";
94
+ shift: "shift";
95
+ ascend: "ascend";
96
+ movingLetters: "movingLetters";
97
+ }>;
98
+ speed: z.ZodDefault<z.ZodNumber>;
99
+ duration: z.ZodOptional<z.ZodNumber>;
100
+ style: z.ZodOptional<z.ZodEnum<{
101
+ character: "character";
102
+ word: "word";
103
+ }>>;
104
+ direction: z.ZodOptional<z.ZodEnum<{
105
+ right: "right";
106
+ left: "left";
107
+ up: "up";
108
+ down: "down";
109
+ }>>;
110
+ }, z.core.$strip>>;
111
+ customFonts: z.ZodOptional<z.ZodArray<z.ZodObject<{
112
+ src: z.ZodString;
113
+ family: z.ZodString;
114
+ weight: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>;
115
+ style: z.ZodOptional<z.ZodString>;
116
+ originalFamily: z.ZodOptional<z.ZodString>;
117
+ }, z.core.$strip>>>;
118
+ }, z.core.$strict>;
119
+ type CanvasRichTextAsset = z.infer<typeof CanvasRichTextAssetSchema>;
26
120
 
27
121
  type ShotstackRichTextAsset = components["schemas"]["RichTextAsset"];
28
- type RichTextValidated = Required<{
29
- type: "rich-text";
30
- text: string;
31
- width?: number;
32
- height?: number;
33
- font?: {
34
- family: string;
35
- size: number;
36
- weight: string | number;
37
- color: string;
38
- opacity: number;
39
- background?: string;
40
- };
41
- style?: {
42
- letterSpacing: number;
43
- lineHeight: number;
44
- textTransform: "none" | "uppercase" | "lowercase" | "capitalize";
45
- textDecoration: "none" | "underline" | "line-through";
46
- gradient?: {
47
- type: "linear" | "radial";
48
- angle: number;
49
- stops: {
50
- offset: number;
51
- color: string;
52
- }[];
53
- };
54
- };
55
- stroke?: {
56
- width: number;
57
- color: string;
58
- opacity: number;
59
- };
60
- shadow?: {
61
- offsetX: number;
62
- offsetY: number;
63
- blur: number;
64
- color: string;
65
- opacity: number;
66
- };
67
- background?: {
68
- color?: string;
69
- opacity: number;
70
- };
71
- border?: {
72
- width: number;
73
- color: string;
74
- opacity: number;
75
- radius: number;
76
- };
77
- padding?: number | {
78
- top: number;
79
- right: number;
80
- bottom: number;
81
- left: number;
82
- };
83
- align?: {
84
- horizontal: "left" | "center" | "right";
85
- vertical: "top" | "middle" | "bottom";
86
- };
87
- animation?: {
88
- preset: typeof CANVAS_CONFIG.ANIMATION_TYPES[number];
89
- speed: number;
90
- duration?: number;
91
- style?: "character" | "word";
92
- direction?: "left" | "right" | "up" | "down";
93
- };
94
- customFonts?: {
95
- src: string;
96
- family: string;
97
- weight?: string | number;
98
- style?: string;
99
- originalFamily?: string;
100
- }[];
101
- }>;
102
-
103
122
  type RGBA = {
104
123
  r: number;
105
124
  g: number;
@@ -221,7 +240,7 @@ type Renderer = {
221
240
  render(ops: DrawOp[]): Promise<void>;
222
241
  toPNG?: () => Promise<Buffer>;
223
242
  };
224
- type ValidAsset = RichTextValidated;
243
+ type ValidAsset = CanvasRichTextAsset;
225
244
  declare const isShadowFill: (op: DrawOp) => op is Extract<DrawOp, {
226
245
  op: "FillPath";
227
246
  }> & {
@@ -241,7 +260,7 @@ declare function createTextEngine(opts?: {
241
260
  wasmBaseURL?: string;
242
261
  }): Promise<{
243
262
  validate(input: unknown): {
244
- value: RichTextValidated;
263
+ value: CanvasRichTextAsset;
245
264
  };
246
265
  registerFontFromUrl(url: string, desc: {
247
266
  family: string;
@@ -251,11 +270,11 @@ declare function createTextEngine(opts?: {
251
270
  family: string;
252
271
  weight?: string | number;
253
272
  }): Promise<void>;
254
- renderFrame(asset: RichTextValidated, tSeconds: number, clipDuration?: number): Promise<DrawOp[]>;
273
+ renderFrame(asset: CanvasRichTextAsset, tSeconds: number, clipDuration?: number): Promise<DrawOp[]>;
255
274
  createRenderer(canvas: HTMLCanvasElement | OffscreenCanvas): {
256
275
  render(ops: DrawOp[]): Promise<void>;
257
276
  };
258
277
  destroy(): void;
259
278
  }>;
260
279
 
261
- export { type DrawOp, type EngineInit, type Glyph, type GradientSpec, type RGBA, type Renderer, type ShapedLine, type ShotstackRichTextAsset, type ValidAsset, createTextEngine, isGlyphFill, isShadowFill };
280
+ export { type CanvasRichTextAsset, CanvasRichTextAssetSchema, type DrawOp, type EngineInit, type Glyph, type GradientSpec, type RGBA, type Renderer, type ShapedLine, type ShotstackRichTextAsset, type ValidAsset, createTextEngine, isGlyphFill, isShadowFill };
package/dist/entry.web.js CHANGED
@@ -2,8 +2,18 @@ import {
2
2
  __publicField
3
3
  } from "./chunk-HYGMWVDX.js";
4
4
 
5
- // src/schema/asset-schema.ts
6
- import Joi from "joi";
5
+ // src/schema/zod-schema.ts
6
+ import { z } from "zod";
7
+ import {
8
+ richTextAssetSchema,
9
+ richTextFontSchema,
10
+ richTextStyleSchema,
11
+ richTextStrokeSchema,
12
+ richTextShadowSchema,
13
+ richTextBackgroundSchema,
14
+ richTextAlignmentSchema,
15
+ richTextAnimationSchema
16
+ } from "@shotstack/schemas/zod";
7
17
 
8
18
  // src/config/canvas-constants.ts
9
19
  var CANVAS_CONFIG = {
@@ -37,110 +47,127 @@ var CANVAS_CONFIG = {
37
47
  ]
38
48
  };
39
49
 
40
- // src/schema/asset-schema.ts
50
+ // src/schema/zod-schema.ts
41
51
  var HEX6 = /^#[A-Fa-f0-9]{6}$/;
42
- var gradientSchema = Joi.object({
43
- type: Joi.string().valid("linear", "radial").default("linear"),
44
- angle: Joi.number().min(0).max(360).default(0),
45
- stops: Joi.array().items(
46
- Joi.object({
47
- offset: Joi.number().min(0).max(1).required(),
48
- color: Joi.string().pattern(HEX6).required()
49
- }).unknown(false)
50
- ).min(2).required()
51
- }).unknown(false);
52
- var shadowSchema = Joi.object({
53
- offsetX: Joi.number().default(0),
54
- offsetY: Joi.number().default(0),
55
- blur: Joi.number().min(0).default(0),
56
- color: Joi.string().pattern(HEX6).default("#000000"),
57
- opacity: Joi.number().min(0).max(1).default(0.5)
58
- }).unknown(false);
59
- var strokeSchema = Joi.object({
60
- width: Joi.number().min(0).default(0),
61
- color: Joi.string().pattern(HEX6).default("#000000"),
62
- opacity: Joi.number().min(0).max(1).default(1)
63
- }).unknown(false);
64
- var fontSchema = Joi.object({
65
- family: Joi.string().default(CANVAS_CONFIG.DEFAULTS.fontFamily),
66
- size: Joi.number().min(CANVAS_CONFIG.LIMITS.minFontSize).max(CANVAS_CONFIG.LIMITS.maxFontSize).default(CANVAS_CONFIG.DEFAULTS.fontSize),
67
- weight: Joi.alternatives().try(Joi.string(), Joi.number()).default("400"),
68
- color: Joi.string().pattern(HEX6).default(CANVAS_CONFIG.DEFAULTS.color),
69
- opacity: Joi.number().min(0).max(1).default(1),
70
- background: Joi.string().pattern(HEX6).optional()
71
- }).unknown(false);
72
- var styleSchema = Joi.object({
73
- letterSpacing: Joi.number().default(0),
74
- lineHeight: Joi.number().min(0).max(10).default(1.2),
75
- textTransform: Joi.string().valid("none", "uppercase", "lowercase", "capitalize").default("none"),
76
- textDecoration: Joi.string().valid("none", "underline", "line-through").default("none"),
77
- gradient: gradientSchema.optional()
78
- }).unknown(false);
79
- var alignmentSchema = Joi.object({
80
- horizontal: Joi.string().valid("left", "center", "right").default(CANVAS_CONFIG.DEFAULTS.textAlign),
81
- vertical: Joi.string().valid("top", "middle", "bottom").default("middle")
82
- }).unknown(false);
83
- var animationSchema = Joi.object({
84
- preset: Joi.string().valid(...CANVAS_CONFIG.ANIMATION_TYPES),
85
- speed: Joi.number().min(0.1).max(10).default(1),
86
- duration: Joi.number().min(CANVAS_CONFIG.LIMITS.minDuration).max(CANVAS_CONFIG.LIMITS.maxDuration).optional(),
87
- style: Joi.string().valid("character", "word").optional().when("preset", {
88
- is: Joi.valid("typewriter", "shift", "fadeIn", "slideIn"),
89
- then: Joi.optional(),
90
- otherwise: Joi.forbidden()
91
- }),
92
- direction: Joi.string().optional().when("preset", {
93
- switch: [
94
- { is: "ascend", then: Joi.valid("up", "down") },
95
- { is: "shift", then: Joi.valid("left", "right", "up", "down") },
96
- { is: "slideIn", then: Joi.valid("left", "right", "up", "down") },
97
- { is: "movingLetters", then: Joi.valid("left", "right", "up", "down") }
98
- ],
99
- otherwise: Joi.forbidden()
52
+ var customFontSchema = z.object({
53
+ src: z.string().url(),
54
+ family: z.string(),
55
+ weight: z.union([z.string(), z.number()]).optional(),
56
+ style: z.string().optional(),
57
+ originalFamily: z.string().optional()
58
+ });
59
+ var borderSchema = z.object({
60
+ width: z.number().min(0).default(0),
61
+ color: z.string().regex(HEX6).default("#000000"),
62
+ opacity: z.number().min(0).max(1).default(1),
63
+ radius: z.number().min(0).default(0)
64
+ });
65
+ var paddingSchema = z.union([
66
+ z.number().min(0),
67
+ z.object({
68
+ top: z.number().min(0).default(0),
69
+ right: z.number().min(0).default(0),
70
+ bottom: z.number().min(0).default(0),
71
+ left: z.number().min(0).default(0)
100
72
  })
101
- }).unknown(false);
102
- var borderSchema = Joi.object({
103
- width: Joi.number().min(0).default(0),
104
- color: Joi.string().pattern(HEX6).default("#000000"),
105
- opacity: Joi.number().min(0).max(1).default(1),
106
- radius: Joi.number().min(0).default(0)
107
- }).unknown(false);
108
- var backgroundSchema = Joi.object({
109
- color: Joi.string().pattern(HEX6).optional(),
110
- opacity: Joi.number().min(0).max(1).default(1)
111
- }).unknown(false);
112
- var paddingSchema = Joi.alternatives().try(
113
- Joi.number().min(0).default(0),
114
- Joi.object({
115
- top: Joi.number().min(0).default(0),
116
- right: Joi.number().min(0).default(0),
117
- bottom: Joi.number().min(0).default(0),
118
- left: Joi.number().min(0).default(0)
119
- }).unknown(false)
120
- );
121
- var customFontSchema = Joi.object({
122
- src: Joi.string().uri().required(),
123
- family: Joi.string().required(),
124
- weight: Joi.alternatives().try(Joi.string(), Joi.number()).optional(),
125
- style: Joi.string().optional(),
126
- originalFamily: Joi.string().optional()
127
- }).unknown(false);
128
- var RichTextAssetSchema = Joi.object({
129
- type: Joi.string().valid("rich-text").required(),
130
- text: Joi.string().allow("").max(CANVAS_CONFIG.LIMITS.maxTextLength).default(""),
131
- width: Joi.number().min(CANVAS_CONFIG.LIMITS.minWidth).max(CANVAS_CONFIG.LIMITS.maxWidth).default(CANVAS_CONFIG.DEFAULTS.width).optional(),
132
- height: Joi.number().min(CANVAS_CONFIG.LIMITS.minHeight).max(CANVAS_CONFIG.LIMITS.maxHeight).default(CANVAS_CONFIG.DEFAULTS.height).optional(),
133
- font: fontSchema.optional(),
134
- style: styleSchema.optional(),
135
- stroke: strokeSchema.optional(),
136
- shadow: shadowSchema.optional(),
137
- background: backgroundSchema.optional(),
73
+ ]);
74
+ var canvasFontSchema = richTextFontSchema.extend({
75
+ family: z.string().default(CANVAS_CONFIG.DEFAULTS.fontFamily),
76
+ size: z.number().int().min(CANVAS_CONFIG.LIMITS.minFontSize).max(CANVAS_CONFIG.LIMITS.maxFontSize).default(CANVAS_CONFIG.DEFAULTS.fontSize),
77
+ weight: z.union([z.string(), z.number()]).default("400"),
78
+ color: z.string().regex(HEX6).default(CANVAS_CONFIG.DEFAULTS.color),
79
+ opacity: z.number().min(0).max(1).default(1),
80
+ background: z.string().regex(HEX6).optional()
81
+ });
82
+ var canvasGradientSchema = z.object({
83
+ type: z.enum(["linear", "radial"]).default("linear"),
84
+ angle: z.number().min(0).max(360).default(0),
85
+ stops: z.array(z.object({
86
+ offset: z.number().min(0).max(1),
87
+ color: z.string().regex(HEX6)
88
+ })).min(2)
89
+ });
90
+ var canvasStyleSchema = richTextStyleSchema.extend({
91
+ letterSpacing: z.number().default(0),
92
+ lineHeight: z.number().min(0).max(10).default(1.2),
93
+ textTransform: z.enum(["none", "uppercase", "lowercase", "capitalize"]).default("none"),
94
+ textDecoration: z.enum(["none", "underline", "line-through"]).default("none"),
95
+ gradient: canvasGradientSchema.optional()
96
+ });
97
+ var canvasStrokeSchema = richTextStrokeSchema.extend({
98
+ width: z.number().min(0).default(0),
99
+ color: z.string().regex(HEX6).default("#000000"),
100
+ opacity: z.number().min(0).max(1).default(1)
101
+ });
102
+ var canvasShadowSchema = richTextShadowSchema.extend({
103
+ offsetX: z.number().default(0),
104
+ offsetY: z.number().default(0),
105
+ blur: z.number().min(0).default(0),
106
+ color: z.string().regex(HEX6).default("#000000"),
107
+ opacity: z.number().min(0).max(1).default(0.5)
108
+ });
109
+ var canvasBackgroundSchema = richTextBackgroundSchema.extend({
110
+ color: z.string().regex(HEX6).optional(),
111
+ opacity: z.number().min(0).max(1).default(1)
112
+ });
113
+ var canvasAlignmentSchema = richTextAlignmentSchema.extend({
114
+ horizontal: z.enum(["left", "center", "right"]).default(CANVAS_CONFIG.DEFAULTS.textAlign),
115
+ vertical: z.enum(["top", "middle", "bottom"]).default("middle")
116
+ });
117
+ var canvasAnimationSchema = richTextAnimationSchema.extend({
118
+ preset: z.enum(CANVAS_CONFIG.ANIMATION_TYPES),
119
+ speed: z.number().min(0.1).max(10).default(1),
120
+ duration: z.number().min(CANVAS_CONFIG.LIMITS.minDuration).max(CANVAS_CONFIG.LIMITS.maxDuration).optional(),
121
+ style: z.enum(["character", "word"]).optional(),
122
+ direction: z.enum(["left", "right", "up", "down"]).optional()
123
+ }).superRefine((data, ctx) => {
124
+ const presetsWithStyle = ["typewriter", "shift", "fadeIn", "slideIn"];
125
+ if (data.style && !presetsWithStyle.includes(data.preset)) {
126
+ ctx.addIssue({
127
+ code: z.ZodIssueCode.custom,
128
+ message: `style is not allowed for preset "${data.preset}"`,
129
+ path: ["style"]
130
+ });
131
+ }
132
+ const directionRules = {
133
+ ascend: ["up", "down"],
134
+ shift: ["left", "right", "up", "down"],
135
+ slideIn: ["left", "right", "up", "down"],
136
+ movingLetters: ["left", "right", "up", "down"]
137
+ };
138
+ if (data.direction) {
139
+ const allowedDirections = directionRules[data.preset];
140
+ if (!allowedDirections) {
141
+ ctx.addIssue({
142
+ code: z.ZodIssueCode.custom,
143
+ message: `direction is not allowed for preset "${data.preset}"`,
144
+ path: ["direction"]
145
+ });
146
+ } else if (!allowedDirections.includes(data.direction)) {
147
+ ctx.addIssue({
148
+ code: z.ZodIssueCode.custom,
149
+ message: `direction "${data.direction}" is not valid for preset "${data.preset}"`,
150
+ path: ["direction"]
151
+ });
152
+ }
153
+ }
154
+ });
155
+ var CanvasRichTextAssetSchema = richTextAssetSchema.extend({
156
+ type: z.literal("rich-text"),
157
+ text: z.string().max(CANVAS_CONFIG.LIMITS.maxTextLength).default(""),
158
+ width: z.number().int().min(CANVAS_CONFIG.LIMITS.minWidth).max(CANVAS_CONFIG.LIMITS.maxWidth).default(CANVAS_CONFIG.DEFAULTS.width).optional(),
159
+ height: z.number().int().min(CANVAS_CONFIG.LIMITS.minHeight).max(CANVAS_CONFIG.LIMITS.maxHeight).default(CANVAS_CONFIG.DEFAULTS.height).optional(),
160
+ font: canvasFontSchema.optional(),
161
+ style: canvasStyleSchema.optional(),
162
+ stroke: canvasStrokeSchema.optional(),
163
+ shadow: canvasShadowSchema.optional(),
164
+ background: canvasBackgroundSchema.optional(),
138
165
  border: borderSchema.optional(),
139
166
  padding: paddingSchema.optional(),
140
- align: alignmentSchema.optional(),
141
- animation: animationSchema.optional(),
142
- customFonts: Joi.array().items(customFontSchema).optional()
143
- }).unknown(false);
167
+ align: canvasAlignmentSchema.optional(),
168
+ animation: canvasAnimationSchema.optional(),
169
+ customFonts: z.array(customFontSchema).optional()
170
+ }).strict();
144
171
 
145
172
  // src/wasm/hb-loader.ts
146
173
  var hbSingleton = null;
@@ -2133,19 +2160,12 @@ async function createTextEngine(opts = {}) {
2133
2160
  }
2134
2161
  return {
2135
2162
  validate(input) {
2136
- try {
2137
- const { value, error } = RichTextAssetSchema.validate(input, {
2138
- abortEarly: false,
2139
- convert: true
2140
- });
2141
- if (error) throw error;
2142
- return { value };
2143
- } catch (err) {
2144
- if (err instanceof Error) {
2145
- throw new Error(`Validation failed: ${err.message}`);
2146
- }
2147
- throw new Error(`Validation failed: ${String(err)}`);
2163
+ const result = CanvasRichTextAssetSchema.safeParse(input);
2164
+ if (!result.success) {
2165
+ const messages = result.error.issues.map((i) => i.message).join(". ");
2166
+ throw new Error(`Validation failed: ${messages}`);
2148
2167
  }
2168
+ return { value: result.data };
2149
2169
  },
2150
2170
  async registerFontFromUrl(url, desc) {
2151
2171
  try {
@@ -2321,6 +2341,7 @@ async function createTextEngine(opts = {}) {
2321
2341
  };
2322
2342
  }
2323
2343
  export {
2344
+ CanvasRichTextAssetSchema,
2324
2345
  createTextEngine,
2325
2346
  isGlyphFill2 as isGlyphFill,
2326
2347
  isShadowFill2 as isShadowFill
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shotstack/shotstack-canvas",
3
- "version": "1.6.6",
3
+ "version": "1.7.1",
4
4
  "description": "Text layout & animation engine (HarfBuzz) for Node & Web - fully self-contained.",
5
5
  "type": "module",
6
6
  "main": "./dist/entry.node.cjs",
@@ -42,13 +42,13 @@
42
42
  },
43
43
  "sideEffects": false,
44
44
  "dependencies": {
45
- "@shotstack/schemas": "^1.0.1",
45
+ "@shotstack/schemas": "^1.3.0",
46
46
  "canvas": "npm:@napi-rs/canvas@^0.1.54",
47
47
  "ffmpeg-static": "^5.2.0",
48
48
  "fontkit": "^2.0.4",
49
49
  "harfbuzzjs": "0.4.12",
50
- "joi": "^17.13.3",
51
- "opentype.js": "^1.3.4"
50
+ "opentype.js": "^1.3.4",
51
+ "zod": "^4.2.0"
52
52
  },
53
53
  "devDependencies": {
54
54
  "@types/fluent-ffmpeg": "2.1.27",