@remotion/studio-shared 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.
- package/dist/api-requests.d.ts +17 -0
- package/dist/detect-file-type.d.ts +1 -0
- package/dist/detect-file-type.js +23 -2
- package/dist/event-source-event.d.ts +3 -2
- package/dist/index.d.ts +1 -1
- package/dist/optimistic-delete-keyframe.d.ts +6 -2
- package/dist/optimistic-delete-keyframe.js +18 -6
- package/dist/required-package.js +1 -1
- package/package.json +4 -4
package/dist/api-requests.d.ts
CHANGED
|
@@ -353,6 +353,7 @@ export type DeleteSequenceKeyframe = {
|
|
|
353
353
|
key: string;
|
|
354
354
|
frame: number;
|
|
355
355
|
schema: InteractivitySchema;
|
|
356
|
+
valueWhenLastKeyframeDeleted?: unknown;
|
|
356
357
|
};
|
|
357
358
|
export type MoveSequenceKeyframe = {
|
|
358
359
|
fileName: string;
|
|
@@ -380,6 +381,7 @@ export type DeleteEffectKeyframe = {
|
|
|
380
381
|
key: string;
|
|
381
382
|
frame: number;
|
|
382
383
|
schema: InteractivitySchema;
|
|
384
|
+
valueWhenLastKeyframeDeleted?: unknown;
|
|
383
385
|
};
|
|
384
386
|
export type MoveEffectKeyframe = {
|
|
385
387
|
fileName: string;
|
|
@@ -550,6 +552,10 @@ export type InsertableCompositionElement = {
|
|
|
550
552
|
height: number;
|
|
551
553
|
} | null;
|
|
552
554
|
position: InsertableCompositionElementPosition | null;
|
|
555
|
+
} | {
|
|
556
|
+
type: 'svg';
|
|
557
|
+
markup: string;
|
|
558
|
+
position: InsertableCompositionElementPosition | null;
|
|
553
559
|
} | {
|
|
554
560
|
type: 'composition';
|
|
555
561
|
compositionId: string;
|
|
@@ -576,6 +582,16 @@ export type InsertJsxElementResponse = {
|
|
|
576
582
|
reason: string;
|
|
577
583
|
stack: string;
|
|
578
584
|
};
|
|
585
|
+
export type ConvertFigmaClipboardToSvgRequest = {
|
|
586
|
+
html: string;
|
|
587
|
+
};
|
|
588
|
+
export type ConvertFigmaClipboardToSvgResponse = {
|
|
589
|
+
success: true;
|
|
590
|
+
svg: string;
|
|
591
|
+
} | {
|
|
592
|
+
success: false;
|
|
593
|
+
reason: string;
|
|
594
|
+
};
|
|
579
595
|
export type InsertElementRequest = {
|
|
580
596
|
compositionFile: string;
|
|
581
597
|
compositionId: string;
|
|
@@ -695,6 +711,7 @@ export type ApiRoutes = {
|
|
|
695
711
|
'/api/duplicate-jsx-node': ReqAndRes<DuplicateJsxNodeRequest, DuplicateJsxNodeResponse>;
|
|
696
712
|
'/api/split-jsx-sequence': ReqAndRes<SplitJsxSequenceRequest, SplitJsxSequenceResponse>;
|
|
697
713
|
'/api/insert-jsx-element': ReqAndRes<InsertJsxElementRequest, InsertJsxElementResponse>;
|
|
714
|
+
'/api/convert-figma-clipboard-to-svg': ReqAndRes<ConvertFigmaClipboardToSvgRequest, ConvertFigmaClipboardToSvgResponse>;
|
|
698
715
|
'/api/insert-element': ReqAndRes<InsertElementRequest, InsertElementResponse>;
|
|
699
716
|
'/api/update-element-install-target': ReqAndRes<UpdateElementInstallTargetRequest, UpdateElementInstallTargetResponse>;
|
|
700
717
|
'/api/download-remote-asset': ReqAndRes<DownloadRemoteAssetRequest, DownloadRemoteAssetResponse>;
|
package/dist/detect-file-type.js
CHANGED
|
@@ -225,12 +225,33 @@ const getWebPDimensions = (bytes) => {
|
|
|
225
225
|
}
|
|
226
226
|
return null;
|
|
227
227
|
};
|
|
228
|
+
const isAnimatedWebp = (data) => {
|
|
229
|
+
const animationChunk = new Uint8Array([0x41, 0x4e, 0x49, 0x4d]);
|
|
230
|
+
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
231
|
+
let offset = 12;
|
|
232
|
+
while (offset + 8 <= data.length) {
|
|
233
|
+
const chunkType = data.subarray(offset, offset + 4);
|
|
234
|
+
if ((0, exports.matchesPattern)(animationChunk)(chunkType)) {
|
|
235
|
+
return true;
|
|
236
|
+
}
|
|
237
|
+
const chunkLength = view.getUint32(offset + 4, true);
|
|
238
|
+
const nextOffset = offset + 8 + chunkLength + (chunkLength % 2);
|
|
239
|
+
if (nextOffset <= offset) {
|
|
240
|
+
return false;
|
|
241
|
+
}
|
|
242
|
+
offset = nextOffset;
|
|
243
|
+
}
|
|
244
|
+
return false;
|
|
245
|
+
};
|
|
228
246
|
const isWebp = (data) => {
|
|
229
|
-
const
|
|
230
|
-
|
|
247
|
+
const riffPattern = new Uint8Array([0x52, 0x49, 0x46, 0x46]);
|
|
248
|
+
const webpPattern = new Uint8Array([0x57, 0x45, 0x42, 0x50]);
|
|
249
|
+
if ((0, exports.matchesPattern)(riffPattern)(data.subarray(0, 4)) &&
|
|
250
|
+
(0, exports.matchesPattern)(webpPattern)(data.subarray(8, 12))) {
|
|
231
251
|
return {
|
|
232
252
|
type: 'webp',
|
|
233
253
|
dimensions: getWebPDimensions(data),
|
|
254
|
+
animated: isAnimatedWebp(data),
|
|
234
255
|
};
|
|
235
256
|
}
|
|
236
257
|
return null;
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import type { StaticFile } from 'remotion';
|
|
2
|
-
import type { CanUpdateSequencePropsResponse, SequencePropsSubscriptionKey } from 'remotion';
|
|
1
|
+
import type { CanUpdateSequencePropsResponse, SequencePropsSubscriptionKey, StaticFile } from 'remotion';
|
|
3
2
|
import type { CanUpdateDefaultPropsResponse, ElementInstallRequest } from './api-requests';
|
|
4
3
|
import type { HotMiddlewareMessage } from './hot-middleware';
|
|
5
4
|
import type { CompletedClientRender, RenderJob } from './render-job';
|
|
@@ -14,6 +13,8 @@ export type EventSourceEvent = {
|
|
|
14
13
|
} | {
|
|
15
14
|
type: 'new-env-variables';
|
|
16
15
|
newEnvVariables: Record<string, string>;
|
|
16
|
+
} | {
|
|
17
|
+
type: 'config-file-changed';
|
|
17
18
|
} | {
|
|
18
19
|
type: 'root-file-changed';
|
|
19
20
|
} | {
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { splitAnsi, stripAnsi } from './ansi';
|
|
2
|
-
export { AddEffectKeyframeRequest, AddEffectKeyframeResponse, AddEffectRequest, AddEffectResponse, AddKeyframesRequest, AddKeyframesResponse, AddRenderRequest, AddSequenceKeyframeRequest, AddSequenceKeyframeResponse, ApiRoutes, ApplyCodemodRequest, ApplyCodemodResponse, ApplyVisualControlRequest, ApplyVisualControlResponse, CanUpdateDefaultPropsResponse, CanUpdateSequencePropsRequest, CancelRenderRequest, CancelRenderResponse, CompositionComponentInfoRequest, CompositionComponentInfoResponse, CopyStillToClipboardRequest, DeleteEffectKeyframe, DeleteEffectRequest, DeleteEffectRequestItem, DeleteEffectResponse, DeleteJsxNodeRequest, DeleteJsxNodeRequestItem, DeleteJsxNodeResponse, DeleteKeyframesRequest, DeleteKeyframesResponse, DeleteSequenceKeyframe, DeleteStaticFileRequest, DeleteStaticFileResponse, DownloadRemoteAssetRequest, DownloadRemoteAssetResponse, DuplicateEffectRequest, DuplicateEffectRequestItem, DuplicateEffectResponse, DuplicateJsxNodeRequest, DuplicateJsxNodeResponse, ElementInstallRequest, GoogleFontSourceEdit, InsertElementRequest, InsertElementResponse, InsertJsxElementRequest, InsertJsxElementResponse, InsertableCompositionElement, InsertableCompositionElementPosition, InstallPackageRequest, InstallPackageResponse, LogStudioErrorRequest, LogStudioErrorResponse, MoveEffectKeyframe, MoveKeyframesRequest, MoveKeyframesResponse, MoveSequenceKeyframe, OpenInEditorRequest, OpenInEditorResponse, OpenInFileExplorerRequest, PasteEffectsRequest, PasteEffectsResponse, ProjectInfoRequest, ProjectInfoResponse, RedoRequest, RedoResponse, RemoveRenderRequest, RenameStaticFileRequest, RenameStaticFileResponse, ReorderEffectRequest, ReorderEffectResponse, ReorderSequencePosition, ReorderSequenceRequest, ReorderSequenceResponse, RestartStudioRequest, RestartStudioResponse, SaveEffectPropsRequest, SaveEffectPropsResponse, SaveSequencePropEdit, SaveSequencePropSourceEdit, SaveSequencePropsRequest, SaveSequencePropsResponse, SaveSequencePropsResult, SimpleDiff, SplitJsxSequenceRequest, SplitJsxSequenceResponse, SubscribeToDefaultPropsRequest, SubscribeToDefaultPropsResponse, SubscribeToFileExistenceRequest, SubscribeToFileExistenceResponse, SubscribeToSequencePropsRequest, SubscribeToSequencePropsResponse, UndoRequest, UndoResponse, UnsubscribeFromDefaultPropsRequest, UnsubscribeFromFileExistenceRequest, UnsubscribeFromSequencePropsRequest, UpdateAvailableRequest, UpdateAvailableResponse, UpdateDefaultPropsRequest, UpdateDefaultPropsResponse, UpdateEffectKeyframeSettingsRequest, UpdateEffectKeyframeSettingsResponse, UpdateElementInstallTargetRequest, UpdateElementInstallTargetResponse, UpdateSequenceKeyframeSettingsRequest, UpdateSequenceKeyframeSettingsResponse, type AddEffectKeyframe, type AddSequenceKeyframe, type KeyframeSettings, } from './api-requests';
|
|
2
|
+
export { AddEffectKeyframeRequest, AddEffectKeyframeResponse, AddEffectRequest, AddEffectResponse, AddKeyframesRequest, AddKeyframesResponse, AddRenderRequest, AddSequenceKeyframeRequest, AddSequenceKeyframeResponse, ApiRoutes, ApplyCodemodRequest, ApplyCodemodResponse, ApplyVisualControlRequest, ApplyVisualControlResponse, CanUpdateDefaultPropsResponse, CanUpdateSequencePropsRequest, CancelRenderRequest, CancelRenderResponse, CompositionComponentInfoRequest, CompositionComponentInfoResponse, ConvertFigmaClipboardToSvgRequest, ConvertFigmaClipboardToSvgResponse, CopyStillToClipboardRequest, DeleteEffectKeyframe, DeleteEffectRequest, DeleteEffectRequestItem, DeleteEffectResponse, DeleteJsxNodeRequest, DeleteJsxNodeRequestItem, DeleteJsxNodeResponse, DeleteKeyframesRequest, DeleteKeyframesResponse, DeleteSequenceKeyframe, DeleteStaticFileRequest, DeleteStaticFileResponse, DownloadRemoteAssetRequest, DownloadRemoteAssetResponse, DuplicateEffectRequest, DuplicateEffectRequestItem, DuplicateEffectResponse, DuplicateJsxNodeRequest, DuplicateJsxNodeResponse, ElementInstallRequest, GoogleFontSourceEdit, InsertElementRequest, InsertElementResponse, InsertJsxElementRequest, InsertJsxElementResponse, InsertableCompositionElement, InsertableCompositionElementPosition, InstallPackageRequest, InstallPackageResponse, LogStudioErrorRequest, LogStudioErrorResponse, MoveEffectKeyframe, MoveKeyframesRequest, MoveKeyframesResponse, MoveSequenceKeyframe, OpenInEditorRequest, OpenInEditorResponse, OpenInFileExplorerRequest, PasteEffectsRequest, PasteEffectsResponse, ProjectInfoRequest, ProjectInfoResponse, RedoRequest, RedoResponse, RemoveRenderRequest, RenameStaticFileRequest, RenameStaticFileResponse, ReorderEffectRequest, ReorderEffectResponse, ReorderSequencePosition, ReorderSequenceRequest, ReorderSequenceResponse, RestartStudioRequest, RestartStudioResponse, SaveEffectPropsRequest, SaveEffectPropsResponse, SaveSequencePropEdit, SaveSequencePropSourceEdit, SaveSequencePropsRequest, SaveSequencePropsResponse, SaveSequencePropsResult, SimpleDiff, SplitJsxSequenceRequest, SplitJsxSequenceResponse, SubscribeToDefaultPropsRequest, SubscribeToDefaultPropsResponse, SubscribeToFileExistenceRequest, SubscribeToFileExistenceResponse, SubscribeToSequencePropsRequest, SubscribeToSequencePropsResponse, UndoRequest, UndoResponse, UnsubscribeFromDefaultPropsRequest, UnsubscribeFromFileExistenceRequest, UnsubscribeFromSequencePropsRequest, UpdateAvailableRequest, UpdateAvailableResponse, UpdateDefaultPropsRequest, UpdateDefaultPropsResponse, UpdateEffectKeyframeSettingsRequest, UpdateEffectKeyframeSettingsResponse, UpdateElementInstallTargetRequest, UpdateElementInstallTargetResponse, UpdateSequenceKeyframeSettingsRequest, UpdateSequenceKeyframeSettingsResponse, type AddEffectKeyframe, type AddSequenceKeyframe, type KeyframeSettings, } from './api-requests';
|
|
3
3
|
export { ASSET_DRAG_MIME_TYPE, makeAssetDragData, parseAssetDragData, type AssetDragData, } from './asset-drag-data';
|
|
4
4
|
export type { ApplyVisualControlCodemod, RecastCodemod } from './codemods';
|
|
5
5
|
export { COMPONENT_DRAG_MIME_TYPE, areComponentProps, isComponentIdentifier, isComponentImportPath, makeComponentDragData, parseComponentDragData, type ComponentDimensions, type ComponentDragData, type ComponentProp, } from './component-drag-data';
|
|
@@ -1,21 +1,24 @@
|
|
|
1
1
|
import { type CanUpdateSequencePropsResponse } from 'remotion';
|
|
2
|
-
export declare const optimisticDeleteSequenceKeyframe: ({ previous, fieldKey, frame, }: {
|
|
2
|
+
export declare const optimisticDeleteSequenceKeyframe: ({ previous, fieldKey, frame, valueWhenLastKeyframeDeleted, }: {
|
|
3
3
|
previous: CanUpdateSequencePropsResponse;
|
|
4
4
|
fieldKey: string;
|
|
5
5
|
frame: number;
|
|
6
|
+
valueWhenLastKeyframeDeleted?: unknown;
|
|
6
7
|
}) => CanUpdateSequencePropsResponse;
|
|
7
8
|
export declare const optimisticDeleteSequenceKeyframes: ({ previous, keyframes, }: {
|
|
8
9
|
previous: CanUpdateSequencePropsResponse;
|
|
9
10
|
keyframes: {
|
|
10
11
|
fieldKey: string;
|
|
11
12
|
frame: number;
|
|
13
|
+
valueWhenLastKeyframeDeleted?: unknown;
|
|
12
14
|
}[];
|
|
13
15
|
}) => CanUpdateSequencePropsResponse;
|
|
14
|
-
export declare const optimisticDeleteEffectKeyframe: ({ previous, effectIndex, fieldKey, frame, }: {
|
|
16
|
+
export declare const optimisticDeleteEffectKeyframe: ({ previous, effectIndex, fieldKey, frame, valueWhenLastKeyframeDeleted, }: {
|
|
15
17
|
previous: CanUpdateSequencePropsResponse;
|
|
16
18
|
effectIndex: number;
|
|
17
19
|
fieldKey: string;
|
|
18
20
|
frame: number;
|
|
21
|
+
valueWhenLastKeyframeDeleted?: unknown;
|
|
19
22
|
}) => CanUpdateSequencePropsResponse;
|
|
20
23
|
export declare const optimisticDeleteEffectKeyframes: ({ previous, keyframes, }: {
|
|
21
24
|
previous: CanUpdateSequencePropsResponse;
|
|
@@ -23,5 +26,6 @@ export declare const optimisticDeleteEffectKeyframes: ({ previous, keyframes, }:
|
|
|
23
26
|
effectIndex: number;
|
|
24
27
|
fieldKey: string;
|
|
25
28
|
frame: number;
|
|
29
|
+
valueWhenLastKeyframeDeleted?: unknown;
|
|
26
30
|
}[];
|
|
27
31
|
}) => CanUpdateSequencePropsResponse;
|
|
@@ -10,7 +10,7 @@ const getEasingIndexToRemove = ({ removedKeyframeIndex, keyframeCountBeforeRemov
|
|
|
10
10
|
}
|
|
11
11
|
return removedKeyframeIndex;
|
|
12
12
|
};
|
|
13
|
-
const removeKeyframeFromPropStatus = ({ status, frame, }) => {
|
|
13
|
+
const removeKeyframeFromPropStatus = ({ status, frame, valueWhenLastKeyframeDeleted, }) => {
|
|
14
14
|
if (status.status !== 'keyframed') {
|
|
15
15
|
return status;
|
|
16
16
|
}
|
|
@@ -22,7 +22,9 @@ const removeKeyframeFromPropStatus = ({ status, frame, }) => {
|
|
|
22
22
|
if (keyframes.length === 0) {
|
|
23
23
|
return {
|
|
24
24
|
status: 'static',
|
|
25
|
-
codeValue:
|
|
25
|
+
codeValue: valueWhenLastKeyframeDeleted === null
|
|
26
|
+
? status.keyframes[index].value
|
|
27
|
+
: valueWhenLastKeyframeDeleted,
|
|
26
28
|
};
|
|
27
29
|
}
|
|
28
30
|
// Easing holds one segment per gap between consecutive keyframes
|
|
@@ -42,7 +44,7 @@ const removeKeyframeFromPropStatus = ({ status, frame, }) => {
|
|
|
42
44
|
easing,
|
|
43
45
|
};
|
|
44
46
|
};
|
|
45
|
-
const optimisticDeleteSequenceKeyframe = ({ previous, fieldKey, frame, }) => {
|
|
47
|
+
const optimisticDeleteSequenceKeyframe = ({ previous, fieldKey, frame, valueWhenLastKeyframeDeleted, }) => {
|
|
46
48
|
if (!previous.canUpdate) {
|
|
47
49
|
return previous;
|
|
48
50
|
}
|
|
@@ -54,7 +56,11 @@ const optimisticDeleteSequenceKeyframe = ({ previous, fieldKey, frame, }) => {
|
|
|
54
56
|
...previous,
|
|
55
57
|
props: {
|
|
56
58
|
...previous.props,
|
|
57
|
-
[fieldKey]: removeKeyframeFromPropStatus({
|
|
59
|
+
[fieldKey]: removeKeyframeFromPropStatus({
|
|
60
|
+
status,
|
|
61
|
+
frame,
|
|
62
|
+
valueWhenLastKeyframeDeleted: valueWhenLastKeyframeDeleted !== null && valueWhenLastKeyframeDeleted !== void 0 ? valueWhenLastKeyframeDeleted : null,
|
|
63
|
+
}),
|
|
58
64
|
},
|
|
59
65
|
};
|
|
60
66
|
};
|
|
@@ -64,10 +70,11 @@ const optimisticDeleteSequenceKeyframes = ({ previous, keyframes, }) => {
|
|
|
64
70
|
previous: current,
|
|
65
71
|
fieldKey: keyframe.fieldKey,
|
|
66
72
|
frame: keyframe.frame,
|
|
73
|
+
valueWhenLastKeyframeDeleted: keyframe.valueWhenLastKeyframeDeleted,
|
|
67
74
|
}), previous);
|
|
68
75
|
};
|
|
69
76
|
exports.optimisticDeleteSequenceKeyframes = optimisticDeleteSequenceKeyframes;
|
|
70
|
-
const optimisticDeleteEffectKeyframe = ({ previous, effectIndex, fieldKey, frame, }) => {
|
|
77
|
+
const optimisticDeleteEffectKeyframe = ({ previous, effectIndex, fieldKey, frame, valueWhenLastKeyframeDeleted, }) => {
|
|
71
78
|
if (!previous.canUpdate) {
|
|
72
79
|
return previous;
|
|
73
80
|
}
|
|
@@ -87,7 +94,11 @@ const optimisticDeleteEffectKeyframe = ({ previous, effectIndex, fieldKey, frame
|
|
|
87
94
|
...target,
|
|
88
95
|
props: {
|
|
89
96
|
...target.props,
|
|
90
|
-
[fieldKey]: removeKeyframeFromPropStatus({
|
|
97
|
+
[fieldKey]: removeKeyframeFromPropStatus({
|
|
98
|
+
status,
|
|
99
|
+
frame,
|
|
100
|
+
valueWhenLastKeyframeDeleted: valueWhenLastKeyframeDeleted !== null && valueWhenLastKeyframeDeleted !== void 0 ? valueWhenLastKeyframeDeleted : null,
|
|
101
|
+
}),
|
|
91
102
|
},
|
|
92
103
|
};
|
|
93
104
|
const effects = [...previous.effects];
|
|
@@ -104,6 +115,7 @@ const optimisticDeleteEffectKeyframes = ({ previous, keyframes, }) => {
|
|
|
104
115
|
effectIndex: keyframe.effectIndex,
|
|
105
116
|
fieldKey: keyframe.fieldKey,
|
|
106
117
|
frame: keyframe.frame,
|
|
118
|
+
valueWhenLastKeyframeDeleted: keyframe.valueWhenLastKeyframeDeleted,
|
|
107
119
|
}), previous);
|
|
108
120
|
};
|
|
109
121
|
exports.optimisticDeleteEffectKeyframes = optimisticDeleteEffectKeyframes;
|
package/dist/required-package.js
CHANGED
|
@@ -20,7 +20,7 @@ const getRequiredPackageForImportPath = (importPath) => {
|
|
|
20
20
|
};
|
|
21
21
|
exports.getRequiredPackageForImportPath = getRequiredPackageForImportPath;
|
|
22
22
|
const getRequiredPackageForInsertableElement = (element) => {
|
|
23
|
-
if (element.type === 'solid') {
|
|
23
|
+
if (element.type === 'solid' || element.type === 'svg') {
|
|
24
24
|
return null;
|
|
25
25
|
}
|
|
26
26
|
if (element.type === 'component') {
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"url": "https://github.com/remotion-dev/remotion/tree/main/packages/studio-shared"
|
|
4
4
|
},
|
|
5
5
|
"name": "@remotion/studio-shared",
|
|
6
|
-
"version": "4.0.
|
|
6
|
+
"version": "4.0.495",
|
|
7
7
|
"description": "Internal package for shared objects between the Studio backend and frontend",
|
|
8
8
|
"main": "dist",
|
|
9
9
|
"scripts": {
|
|
@@ -20,11 +20,11 @@
|
|
|
20
20
|
"url": "https://github.com/remotion-dev/remotion/issues"
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"remotion": "4.0.
|
|
23
|
+
"remotion": "4.0.495"
|
|
24
24
|
},
|
|
25
25
|
"devDependencies": {
|
|
26
|
-
"@remotion/renderer": "4.0.
|
|
27
|
-
"@remotion/eslint-config-internal": "4.0.
|
|
26
|
+
"@remotion/renderer": "4.0.495",
|
|
27
|
+
"@remotion/eslint-config-internal": "4.0.495",
|
|
28
28
|
"eslint": "9.19.0",
|
|
29
29
|
"@typescript/native-preview": "7.0.0-dev.20260217.1"
|
|
30
30
|
},
|