@remotion/studio-server 4.0.493 → 4.0.495

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.
@@ -10,6 +10,7 @@ export type KeyframeOperation = {
10
10
  } | {
11
11
  type: 'remove';
12
12
  frame: number;
13
+ valueWhenLastKeyframeDeleted: unknown | null;
13
14
  } | {
14
15
  type: 'settings';
15
16
  clamping: {
@@ -682,7 +682,7 @@ const addKeyframe = ({ expression, key, frame, value, schema, videoConfigValues,
682
682
  },
683
683
  };
684
684
  };
685
- const removeKeyframe = ({ expression, frame, videoConfigValues, }) => {
685
+ const removeKeyframe = ({ expression, frame, videoConfigValues, valueWhenLastKeyframeDeleted, }) => {
686
686
  const existing = getInterpolationExpression(expression, videoConfigValues);
687
687
  if (!existing) {
688
688
  throw new Error('Cannot remove keyframe from non-interpolated expression');
@@ -694,7 +694,9 @@ const removeKeyframe = ({ expression, frame, videoConfigValues, }) => {
694
694
  const nextKeyframes = existing.keyframes.filter((_keyframe, index) => index !== keyframeIndex);
695
695
  if (nextKeyframes.length === 0) {
696
696
  return {
697
- expression: existing.keyframes[keyframeIndex].output,
697
+ expression: valueWhenLastKeyframeDeleted === null
698
+ ? existing.keyframes[keyframeIndex].output
699
+ : (0, update_nested_prop_1.parseValueExpression)(valueWhenLastKeyframeDeleted),
698
700
  introduced: noIntroducedIdentifiers,
699
701
  };
700
702
  }
@@ -828,6 +830,7 @@ const applyKeyframeOperation = ({ expression, key, operation, schema, videoConfi
828
830
  expression,
829
831
  frame: operation.frame,
830
832
  videoConfigValues,
833
+ valueWhenLastKeyframeDeleted: operation.valueWhenLastKeyframeDeleted,
831
834
  });
832
835
  };
833
836
  const getExpressionFromJsxAttribute = (attr) => {
@@ -907,6 +910,23 @@ const getInitialValueForMissingProp = ({ schema, key, newValue, }) => {
907
910
  }
908
911
  return newValue;
909
912
  };
913
+ const shouldRemovePropAfterKeyframeOperation = ({ expression, key, operation, schema, videoConfigValues, }) => {
914
+ if (operation.type !== 'remove' || !schema) {
915
+ return false;
916
+ }
917
+ const existing = getInterpolationExpression(expression, videoConfigValues);
918
+ if (!existing || existing.keyframes.length !== 1) {
919
+ return false;
920
+ }
921
+ const field = findFieldInSchema(schema, key);
922
+ if (!field || field.type === 'hidden' || field.default === undefined) {
923
+ return false;
924
+ }
925
+ const valueAfterRemoval = operation.valueWhenLastKeyframeDeleted === null
926
+ ? existing.keyframes[0].value
927
+ : operation.valueWhenLastKeyframeDeleted;
928
+ return JSON.stringify(valueAfterRemoval) === JSON.stringify(field.default);
929
+ };
910
930
  const getObjectExpression = (attr) => {
911
931
  if (!attr.value || attr.value.type !== 'JSXExpressionContainer') {
912
932
  return null;
@@ -931,7 +951,7 @@ const createMissingPropExpression = (missingPropInitialValue) => {
931
951
  const getSequenceWritableProp = ({ attributes, key, missingPropInitialValue, }) => {
932
952
  const dotIndex = key.indexOf('.');
933
953
  if (dotIndex === -1) {
934
- const { attr: topLevelAttr } = findJsxAttribute(attributes, key);
954
+ const { attrIndex, attr: topLevelAttr } = findJsxAttribute(attributes, key);
935
955
  if (!topLevelAttr) {
936
956
  if (missingPropInitialValue) {
937
957
  return {
@@ -939,6 +959,7 @@ const getSequenceWritableProp = ({ attributes, key, missingPropInitialValue, })
939
959
  setExpression: (nextExpression) => {
940
960
  attributes.push(createJsxExpressionAttribute(key, nextExpression));
941
961
  },
962
+ remove: () => undefined,
942
963
  };
943
964
  }
944
965
  throw new Error(`Cannot update keyframes: "${key}" is not set`);
@@ -952,11 +973,14 @@ const getSequenceWritableProp = ({ attributes, key, missingPropInitialValue, })
952
973
  setExpression: (nextExpression) => {
953
974
  topLevelAttr.value = b.jsxExpressionContainer(nextExpression);
954
975
  },
976
+ remove: () => {
977
+ attributes.splice(attrIndex, 1);
978
+ },
955
979
  };
956
980
  }
957
981
  const parentKey = key.slice(0, dotIndex);
958
982
  const childKey = key.slice(dotIndex + 1);
959
- const { attr: parentAttr } = findJsxAttribute(attributes, parentKey);
983
+ const { attrIndex: parentAttrIndex, attr: parentAttr } = findJsxAttribute(attributes, parentKey);
960
984
  if (!parentAttr) {
961
985
  if (missingPropInitialValue) {
962
986
  return {
@@ -968,6 +992,7 @@ const getSequenceWritableProp = ({ attributes, key, missingPropInitialValue, })
968
992
  expression: nextExpression,
969
993
  }));
970
994
  },
995
+ remove: () => undefined,
971
996
  };
972
997
  }
973
998
  throw new Error(`Cannot update keyframes: "${parentKey}" is not set`);
@@ -976,7 +1001,7 @@ const getSequenceWritableProp = ({ attributes, key, missingPropInitialValue, })
976
1001
  if (!objExpr) {
977
1002
  throw new Error(`Cannot update keyframes: "${parentKey}" is computed`);
978
1003
  }
979
- const { prop } = findObjectProperty(objExpr, childKey);
1004
+ const { propIndex, prop } = findObjectProperty(objExpr, childKey);
980
1005
  if (!prop) {
981
1006
  if (missingPropInitialValue) {
982
1007
  return {
@@ -984,6 +1009,7 @@ const getSequenceWritableProp = ({ attributes, key, missingPropInitialValue, })
984
1009
  setExpression: (nextExpression) => {
985
1010
  objExpr.properties.push(createObjectProperty(childKey, nextExpression));
986
1011
  },
1012
+ remove: () => undefined,
987
1013
  };
988
1014
  }
989
1015
  throw new Error(`Cannot update keyframes: "${key}" is not set`);
@@ -993,10 +1019,16 @@ const getSequenceWritableProp = ({ attributes, key, missingPropInitialValue, })
993
1019
  setExpression: (nextExpression) => {
994
1020
  prop.value = nextExpression;
995
1021
  },
1022
+ remove: () => {
1023
+ objExpr.properties.splice(propIndex, 1);
1024
+ if (objExpr.properties.length === 0) {
1025
+ attributes.splice(parentAttrIndex, 1);
1026
+ }
1027
+ },
996
1028
  };
997
1029
  };
998
1030
  const getEffectWritableProp = ({ objExpr, key, missingPropInitialValue, }) => {
999
- const { prop } = findObjectProperty(objExpr, key);
1031
+ const { propIndex, prop } = findObjectProperty(objExpr, key);
1000
1032
  if (!prop) {
1001
1033
  if (missingPropInitialValue) {
1002
1034
  return {
@@ -1004,6 +1036,7 @@ const getEffectWritableProp = ({ objExpr, key, missingPropInitialValue, }) => {
1004
1036
  setExpression: (nextExpression) => {
1005
1037
  objExpr.properties.push(createObjectProperty(key, nextExpression));
1006
1038
  },
1039
+ remove: () => undefined,
1007
1040
  };
1008
1041
  }
1009
1042
  throw new Error(`Cannot update keyframes: "${key}" is not set`);
@@ -1013,6 +1046,9 @@ const getEffectWritableProp = ({ objExpr, key, missingPropInitialValue, }) => {
1013
1046
  setExpression: (nextExpression) => {
1014
1047
  prop.value = nextExpression;
1015
1048
  },
1049
+ remove: () => {
1050
+ objExpr.properties.splice(propIndex, 1);
1051
+ },
1016
1052
  };
1017
1053
  };
1018
1054
  const getEffectPropsObjectExpression = (call) => {
@@ -1069,7 +1105,18 @@ const updateSequenceKeyframesAst = ({ input, nodePath, updates, schema, videoCon
1069
1105
  videoConfigValues: videoConfigIdentifierValues,
1070
1106
  });
1071
1107
  newValueStrings.push(recast.print(nextExpression).code);
1072
- prop.setExpression(nextExpression);
1108
+ if (shouldRemovePropAfterKeyframeOperation({
1109
+ expression: prop.expression,
1110
+ key: update.key,
1111
+ operation: update.operation,
1112
+ schema: schema !== null && schema !== void 0 ? schema : null,
1113
+ videoConfigValues: videoConfigIdentifierValues,
1114
+ })) {
1115
+ prop.remove();
1116
+ }
1117
+ else {
1118
+ prop.setExpression(nextExpression);
1119
+ }
1073
1120
  if (introduced.calleeName) {
1074
1121
  requiredImports.add(introduced.calleeName);
1075
1122
  }
@@ -1177,7 +1224,18 @@ const updateEffectKeyframesAst = ({ input, sequenceNodePath, effectIndex, update
1177
1224
  videoConfigValues: videoConfigIdentifierValues,
1178
1225
  });
1179
1226
  newValueStrings.push(recast.print(nextExpression).code);
1180
- prop.setExpression(nextExpression);
1227
+ if (shouldRemovePropAfterKeyframeOperation({
1228
+ expression: prop.expression,
1229
+ key: update.key,
1230
+ operation: update.operation,
1231
+ schema: schema !== null && schema !== void 0 ? schema : null,
1232
+ videoConfigValues: videoConfigIdentifierValues,
1233
+ })) {
1234
+ prop.remove();
1235
+ }
1236
+ else {
1237
+ prop.setExpression(nextExpression);
1238
+ }
1181
1239
  if (introduced.calleeName) {
1182
1240
  requiredImports.add(introduced.calleeName);
1183
1241
  }
@@ -0,0 +1,6 @@
1
+ export declare const getFigmaClipboardPasteSupportError: (zstdDecompressSync: unknown) => "Figma paste is only available with Node.js 22.15 or newer" | null;
2
+ export declare const convertFigmaClipboardToSvg: (html: string) => {
3
+ height: number;
4
+ svg: string;
5
+ width: number;
6
+ };
@@ -0,0 +1,312 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.convertFigmaClipboardToSvg = exports.getFigmaClipboardPasteSupportError = void 0;
37
+ const node_buffer_1 = require("node:buffer");
38
+ const zlib = __importStar(require("node:zlib"));
39
+ const kiwi_schema_1 = require("kiwi-schema");
40
+ const figma_to_svg_1 = require("./figma-to-svg");
41
+ const figmaMetaStart = '<!--(figmeta)';
42
+ const figmaMetaEnd = '(/figmeta)-->';
43
+ const figmaDataStart = '<!--(figma)';
44
+ const figmaDataEnd = '(/figma)-->';
45
+ const figKiwiPrelude = 'fig-kiwi';
46
+ const maxClipboardHtmlBytes = 25 * 1024 * 1024;
47
+ const maxMetaBytes = 1024 * 1024;
48
+ const maxArchiveBytes = 16 * 1024 * 1024;
49
+ const maxCompressedSchemaBytes = 5 * 1024 * 1024;
50
+ const maxCompressedMessageBytes = 10 * 1024 * 1024;
51
+ const maxSchemaBytes = 10 * 1024 * 1024;
52
+ const maxMessageBytes = 40 * 1024 * 1024;
53
+ const maxSchemaDefinitions = 2000;
54
+ const maxSchemaFields = 50000;
55
+ const maxNodeChanges = 20000;
56
+ const maxBlobs = 20000;
57
+ const nodeVersionRequirement = 'Figma paste is only available with Node.js 22.15 or newer';
58
+ const nativeZstdDecompressSync = zlib.zstdDecompressSync;
59
+ const fail = (message) => {
60
+ throw new Error(`Cannot import Figma selection: ${message}`);
61
+ };
62
+ const withFriendlyFailure = (operation, fallback) => {
63
+ try {
64
+ return operation();
65
+ }
66
+ catch (error) {
67
+ if (error instanceof Error &&
68
+ error.message.startsWith('Cannot import Figma selection:')) {
69
+ throw error;
70
+ }
71
+ return fail(fallback);
72
+ }
73
+ };
74
+ const getFigmaClipboardPasteSupportError = (zstdDecompressSync) => {
75
+ return typeof zstdDecompressSync === 'function'
76
+ ? null
77
+ : nodeVersionRequirement;
78
+ };
79
+ exports.getFigmaClipboardPasteSupportError = getFigmaClipboardPasteSupportError;
80
+ const extractMarker = ({ end, html, label, start, }) => {
81
+ const startIndex = html.indexOf(start);
82
+ if (startIndex === -1) {
83
+ fail(`clipboard is missing its ${label}`);
84
+ }
85
+ const valueStart = startIndex + start.length;
86
+ const endIndex = html.indexOf(end, valueStart);
87
+ if (endIndex === -1) {
88
+ fail(`clipboard has an incomplete ${label}`);
89
+ }
90
+ return html.slice(valueStart, endIndex);
91
+ };
92
+ const decodeBase64 = ({ label, limit, value, }) => {
93
+ const compact = value.replace(/[\t\n\r ]/g, '');
94
+ if (compact.length === 0 ||
95
+ compact.length % 4 !== 0 ||
96
+ !/^[A-Za-z0-9+/]*={0,2}$/.test(compact)) {
97
+ fail(`${label} is not valid Base64`);
98
+ }
99
+ if (compact.length > Math.ceil(limit / 3) * 4) {
100
+ fail(`${label} is too large`);
101
+ }
102
+ const decoded = node_buffer_1.Buffer.from(compact, 'base64');
103
+ if (decoded.byteLength > limit) {
104
+ fail(`${label} is too large`);
105
+ }
106
+ return new Uint8Array(decoded.buffer, decoded.byteOffset, decoded.byteLength);
107
+ };
108
+ const parseMeta = (base64) => {
109
+ const bytes = decodeBase64({
110
+ label: 'Figma metadata',
111
+ limit: maxMetaBytes,
112
+ value: base64,
113
+ });
114
+ let parsed;
115
+ try {
116
+ parsed = JSON.parse(new TextDecoder().decode(bytes));
117
+ }
118
+ catch (_a) {
119
+ fail('clipboard metadata is invalid');
120
+ }
121
+ if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {
122
+ fail('clipboard metadata is invalid');
123
+ }
124
+ const meta = parsed;
125
+ if (meta.dataType !== 'scene') {
126
+ fail('clipboard does not contain a Figma scene');
127
+ }
128
+ const { selectedNodeData } = meta;
129
+ if (typeof selectedNodeData !== 'string') {
130
+ fail('clipboard does not identify its selected node');
131
+ }
132
+ const selectedNodeId = selectedNodeData.split('|')[0];
133
+ if (!/^\d+:\d+$/.test(selectedNodeId)) {
134
+ fail('clipboard has an invalid selected node ID');
135
+ }
136
+ return selectedNodeId;
137
+ };
138
+ const parseArchive = (base64) => {
139
+ const bytes = decodeBase64({
140
+ label: 'Figma scene',
141
+ limit: maxArchiveBytes,
142
+ value: base64,
143
+ });
144
+ if (bytes.length < figKiwiPrelude.length + 4) {
145
+ fail('clipboard scene is truncated');
146
+ }
147
+ const prelude = new TextDecoder().decode(bytes.subarray(0, figKiwiPrelude.length));
148
+ if (prelude !== figKiwiPrelude) {
149
+ fail('clipboard scene has an unknown format');
150
+ }
151
+ const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
152
+ const version = view.getUint32(figKiwiPrelude.length, true);
153
+ if (version === 0) {
154
+ fail('clipboard scene has an invalid archive version');
155
+ }
156
+ let offset = figKiwiPrelude.length + 4;
157
+ const chunks = [];
158
+ while (offset < bytes.length) {
159
+ if (offset + 4 > bytes.length) {
160
+ fail('clipboard scene has a truncated chunk header');
161
+ }
162
+ const size = view.getUint32(offset, true);
163
+ offset += 4;
164
+ if (size === 0 || offset + size > bytes.length) {
165
+ fail('clipboard scene has an invalid chunk');
166
+ }
167
+ chunks.push(bytes.slice(offset, offset + size));
168
+ offset += size;
169
+ }
170
+ if (chunks.length !== 2) {
171
+ fail('clipboard scene uses an unsupported archive layout');
172
+ }
173
+ if (chunks[0].length > maxCompressedSchemaBytes) {
174
+ fail('clipboard schema is too large');
175
+ }
176
+ if (chunks[1].length > maxCompressedMessageBytes) {
177
+ fail('clipboard scene is too large');
178
+ }
179
+ return { message: chunks[1], schema: chunks[0] };
180
+ };
181
+ const inflateSchema = (compressed) => {
182
+ const inflated = zlib.inflateRawSync(compressed, {
183
+ maxOutputLength: maxSchemaBytes,
184
+ });
185
+ return new Uint8Array(inflated.buffer, inflated.byteOffset, inflated.byteLength);
186
+ };
187
+ const readLimitedLittleEndian = ({ bytes, limit, length, offset, }) => {
188
+ let result = 0;
189
+ for (let index = length - 1; index >= 0; index--) {
190
+ const nextByte = bytes[offset + index];
191
+ if (result > Math.floor((limit - nextByte) / 256)) {
192
+ fail('clipboard scene expands beyond the size limit');
193
+ }
194
+ result = result * 256 + nextByte;
195
+ }
196
+ return result;
197
+ };
198
+ const getZstandardContentSize = (compressed) => {
199
+ if (compressed.length < 6 ||
200
+ compressed[0] !== 0x28 ||
201
+ compressed[1] !== 0xb5 ||
202
+ compressed[2] !== 0x2f ||
203
+ compressed[3] !== 0xfd) {
204
+ fail('clipboard scene uses an unsupported compression format');
205
+ }
206
+ const descriptor = compressed[4];
207
+ if ((descriptor & 8) !== 0) {
208
+ fail('clipboard scene has an invalid Zstandard frame');
209
+ }
210
+ const singleSegment = (descriptor >> 5) & 1;
211
+ const dictionaryFlag = descriptor & 3;
212
+ const contentSizeFlag = descriptor >> 6;
213
+ const dictionaryBytes = dictionaryFlag === 3 ? 4 : dictionaryFlag;
214
+ const contentSizeBytes = contentSizeFlag
215
+ ? 1 << contentSizeFlag
216
+ : singleSegment;
217
+ if (contentSizeBytes === 0) {
218
+ fail('clipboard scene does not declare its expanded size');
219
+ }
220
+ const contentSizeOffset = 6 - singleSegment + dictionaryBytes;
221
+ if (contentSizeOffset + contentSizeBytes > compressed.length) {
222
+ fail('clipboard scene has a truncated Zstandard header');
223
+ }
224
+ let contentSize = readLimitedLittleEndian({
225
+ bytes: compressed,
226
+ limit: maxMessageBytes,
227
+ length: contentSizeBytes,
228
+ offset: contentSizeOffset,
229
+ });
230
+ if (contentSizeFlag === 1) {
231
+ contentSize += 256;
232
+ }
233
+ if (contentSize <= 0 || contentSize > maxMessageBytes) {
234
+ fail('clipboard scene expands beyond the size limit');
235
+ }
236
+ return contentSize;
237
+ };
238
+ const decompressMessage = ({ compressed, zstdDecompressSync, }) => {
239
+ const expectedBytes = getZstandardContentSize(compressed);
240
+ const decompressed = zstdDecompressSync(compressed, {
241
+ maxOutputLength: expectedBytes,
242
+ });
243
+ if (decompressed.byteLength !== expectedBytes) {
244
+ fail('clipboard scene did not match its declared size');
245
+ }
246
+ return new Uint8Array(decompressed.buffer, decompressed.byteOffset, decompressed.byteLength);
247
+ };
248
+ const decodeMessage = ({ messageBytes, schemaBytes, }) => {
249
+ var _a, _b;
250
+ var _c, _d;
251
+ const schema = (0, kiwi_schema_1.decodeBinarySchema)(schemaBytes);
252
+ if (schema.package !== null &&
253
+ (typeof schema.package !== 'string' ||
254
+ !/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(schema.package))) {
255
+ fail('clipboard schema has an invalid package name');
256
+ }
257
+ if (schema.definitions.length > maxSchemaDefinitions) {
258
+ fail('clipboard schema has too many definitions');
259
+ }
260
+ const fieldCount = schema.definitions.reduce((total, definition) => total + definition.fields.length, 0);
261
+ if (fieldCount > maxSchemaFields) {
262
+ fail('clipboard schema has too many fields');
263
+ }
264
+ const compiled = (0, kiwi_schema_1.compileSchema)(schema);
265
+ const decoded = compiled.decodeMessage(messageBytes);
266
+ if (typeof decoded !== 'object' ||
267
+ decoded === null ||
268
+ Array.isArray(decoded)) {
269
+ fail('clipboard scene decoded to an invalid message');
270
+ }
271
+ const message = decoded;
272
+ if (((_c = (_a = message.nodeChanges) === null || _a === void 0 ? void 0 : _a.length) !== null && _c !== void 0 ? _c : 0) > maxNodeChanges ||
273
+ ((_d = (_b = message.blobs) === null || _b === void 0 ? void 0 : _b.length) !== null && _d !== void 0 ? _d : 0) > maxBlobs) {
274
+ fail('clipboard scene has too many objects');
275
+ }
276
+ return message;
277
+ };
278
+ const convertFigmaClipboardToSvg = (html) => {
279
+ if (typeof html !== 'string' || html.length === 0) {
280
+ fail('clipboard HTML is empty');
281
+ }
282
+ if (node_buffer_1.Buffer.byteLength(html, 'utf8') > maxClipboardHtmlBytes) {
283
+ fail('clipboard HTML is too large');
284
+ }
285
+ const supportError = (0, exports.getFigmaClipboardPasteSupportError)(nativeZstdDecompressSync);
286
+ if (supportError !== null) {
287
+ fail(supportError);
288
+ }
289
+ const zstdDecompressSync = nativeZstdDecompressSync;
290
+ const metaBase64 = extractMarker({
291
+ end: figmaMetaEnd,
292
+ html,
293
+ label: 'figmeta section',
294
+ start: figmaMetaStart,
295
+ });
296
+ const figmaBase64 = extractMarker({
297
+ end: figmaDataEnd,
298
+ html,
299
+ label: 'figma section',
300
+ start: figmaDataStart,
301
+ });
302
+ const selectedNodeId = parseMeta(metaBase64);
303
+ const archive = parseArchive(figmaBase64);
304
+ const schemaBytes = withFriendlyFailure(() => inflateSchema(archive.schema), 'clipboard schema could not be decompressed');
305
+ const messageBytes = withFriendlyFailure(() => decompressMessage({
306
+ compressed: archive.message,
307
+ zstdDecompressSync,
308
+ }), 'clipboard scene could not be decompressed');
309
+ const message = withFriendlyFailure(() => decodeMessage({ messageBytes, schemaBytes }), 'clipboard scene could not be decoded');
310
+ return (0, figma_to_svg_1.renderFigmaMessageToSvg)({ message, selectedNodeId });
311
+ };
312
+ exports.convertFigmaClipboardToSvg = convertFigmaClipboardToSvg;
@@ -0,0 +1,116 @@
1
+ type FigmaVector = {
2
+ x: number;
3
+ y: number;
4
+ };
5
+ type FigmaGuid = {
6
+ sessionID?: number;
7
+ localID?: number;
8
+ };
9
+ type FigmaColor = {
10
+ r?: number;
11
+ g?: number;
12
+ b?: number;
13
+ a?: number;
14
+ };
15
+ type FigmaPaint = {
16
+ type?: string;
17
+ color?: FigmaColor;
18
+ opacity?: number;
19
+ visible?: boolean;
20
+ blendMode?: string;
21
+ };
22
+ type FigmaTransform = {
23
+ m00?: number;
24
+ m01?: number;
25
+ m02?: number;
26
+ m10?: number;
27
+ m11?: number;
28
+ m12?: number;
29
+ };
30
+ type FigmaArcData = {
31
+ startingAngle?: number;
32
+ endingAngle?: number;
33
+ innerRadius?: number;
34
+ };
35
+ export type FigmaNode = {
36
+ guid?: FigmaGuid;
37
+ phase?: string;
38
+ parentIndex?: {
39
+ guid?: FigmaGuid;
40
+ position?: string;
41
+ };
42
+ type?: string;
43
+ name?: string;
44
+ visible?: boolean;
45
+ opacity?: number;
46
+ blendMode?: string;
47
+ size?: FigmaVector;
48
+ transform?: FigmaTransform;
49
+ mask?: boolean;
50
+ maskType?: string;
51
+ maskIsOutline?: boolean;
52
+ fillPaints?: FigmaPaint[];
53
+ backgroundPaints?: FigmaPaint[];
54
+ strokePaints?: FigmaPaint[];
55
+ strokeWeight?: number;
56
+ borderTopWeight?: number;
57
+ borderBottomWeight?: number;
58
+ borderLeftWeight?: number;
59
+ borderRightWeight?: number;
60
+ borderStrokeWeightsIndependent?: boolean;
61
+ strokeAlign?: string;
62
+ strokeCap?: string;
63
+ strokeJoin?: string;
64
+ dashPattern?: number[];
65
+ miterLimit?: number;
66
+ cornerRadius?: number;
67
+ cornerSmoothing?: number;
68
+ rectangleTopLeftCornerRadius?: number;
69
+ rectangleTopRightCornerRadius?: number;
70
+ rectangleBottomLeftCornerRadius?: number;
71
+ rectangleBottomRightCornerRadius?: number;
72
+ rectangleCornerRadiiIndependent?: boolean;
73
+ frameMaskDisabled?: boolean;
74
+ resizeToFit?: boolean;
75
+ effects?: Array<{
76
+ visible?: boolean;
77
+ }>;
78
+ vectorData?: {
79
+ vectorNetworkBlob?: number;
80
+ normalizedSize?: FigmaVector;
81
+ };
82
+ arcData?: FigmaArcData;
83
+ };
84
+ export type FigmaMessage = {
85
+ type?: string;
86
+ nodeChanges?: FigmaNode[];
87
+ blobs?: Array<{
88
+ bytes?: Uint8Array;
89
+ }>;
90
+ };
91
+ type VectorVertex = FigmaVector;
92
+ type VectorSegment = {
93
+ start: number;
94
+ end: number;
95
+ tangentStart: FigmaVector;
96
+ tangentEnd: FigmaVector;
97
+ };
98
+ type VectorRegion = {
99
+ windingRule: 'evenodd' | 'nonzero';
100
+ loops: number[][];
101
+ };
102
+ type VectorNetwork = {
103
+ vertices: VectorVertex[];
104
+ segments: VectorSegment[];
105
+ regions: VectorRegion[];
106
+ };
107
+ export declare const decodeFigmaVectorNetwork: (data: Uint8Array<ArrayBufferLike>) => VectorNetwork;
108
+ export declare const renderFigmaMessageToSvg: ({ message, selectedNodeId, }: {
109
+ message: FigmaMessage;
110
+ selectedNodeId: string;
111
+ }) => {
112
+ height: number;
113
+ svg: string;
114
+ width: number;
115
+ };
116
+ export {};