@elementor/editor-interactions 4.0.0-609 → 4.0.0-621
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/index.d.mts +0 -5
- package/dist/index.d.ts +0 -5
- package/dist/index.js +154 -132
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +154 -132
- package/dist/index.mjs.map +1 -1
- package/package.json +11 -11
- package/src/mcp/index.ts +65 -4
- package/src/mcp/resources/interactions-schema-resource.ts +6 -39
- package/src/mcp/tools/manage-element-interaction-tool.ts +44 -111
- package/src/mcp/tools/schema.ts +73 -0
- package/src/types.ts +0 -6
- package/src/utils/get-interactions-config.ts +0 -1
- package/src/utils/prop-value-utils.ts +11 -11
package/dist/index.mjs
CHANGED
|
@@ -280,13 +280,13 @@ var createInteractionItem = ({
|
|
|
280
280
|
$$type: "interaction-item",
|
|
281
281
|
value: {
|
|
282
282
|
...interactionId && { interaction_id: createString(interactionId) },
|
|
283
|
-
trigger: createString(trigger),
|
|
283
|
+
trigger: createString(trigger ?? ""),
|
|
284
284
|
animation: createAnimationPreset({
|
|
285
|
-
effect,
|
|
286
|
-
type,
|
|
285
|
+
effect: effect ?? "",
|
|
286
|
+
type: type ?? "",
|
|
287
287
|
direction,
|
|
288
|
-
duration,
|
|
289
|
-
delay,
|
|
288
|
+
duration: duration ?? 0,
|
|
289
|
+
delay: delay ?? 0,
|
|
290
290
|
replay,
|
|
291
291
|
easing,
|
|
292
292
|
relativeTo,
|
|
@@ -889,8 +889,7 @@ var DEFAULT_CONFIG = {
|
|
|
889
889
|
slideDistance: 100,
|
|
890
890
|
scaleStart: 0.5,
|
|
891
891
|
easing: "linear"
|
|
892
|
-
}
|
|
893
|
-
animationOptions: []
|
|
892
|
+
}
|
|
894
893
|
};
|
|
895
894
|
function getInteractionsConfig() {
|
|
896
895
|
return window.ElementorInteractionsConfig || DEFAULT_CONFIG;
|
|
@@ -1347,53 +1346,73 @@ import { getMCPByDomain } from "@elementor/editor-mcp";
|
|
|
1347
1346
|
var MAX_INTERACTIONS_PER_ELEMENT = 5;
|
|
1348
1347
|
|
|
1349
1348
|
// src/mcp/resources/interactions-schema-resource.ts
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
directions: [
|
|
1366
|
-
{ value: "top", label: "Top", note: "" },
|
|
1367
|
-
{ value: "bottom", label: "Bottom", note: "" },
|
|
1368
|
-
{ value: "left", label: "Left", note: "" },
|
|
1369
|
-
{ value: "right", label: "Right", note: "" },
|
|
1370
|
-
{ value: "", label: "None", note: "Slide animation must have a direction" }
|
|
1371
|
-
],
|
|
1372
|
-
easings: Object.entries(EASING_OPTIONS).map(([value, label]) => ({ value, label })),
|
|
1373
|
-
timing: {
|
|
1374
|
-
duration: { min: 0, max: 1e4, unit: "ms", description: "Animation duration in milliseconds" },
|
|
1375
|
-
delay: { min: 0, max: 1e4, unit: "ms", description: "Animation delay in milliseconds" }
|
|
1376
|
-
},
|
|
1377
|
-
excludedBreakpoints: {
|
|
1378
|
-
type: "string[]",
|
|
1379
|
-
description: "List of breakpoint IDs on which this interaction is disabled. Omit to enable on all breakpoints."
|
|
1380
|
-
},
|
|
1381
|
-
maxInteractionsPerElement: MAX_INTERACTIONS_PER_ELEMENT
|
|
1349
|
+
import { isProActive } from "@elementor/utils";
|
|
1350
|
+
|
|
1351
|
+
// src/mcp/tools/schema.ts
|
|
1352
|
+
import { z } from "@elementor/schema";
|
|
1353
|
+
var baseSchema = {
|
|
1354
|
+
trigger: z.enum(["load", "scrollIn"]).optional().describe("Event that triggers the animation"),
|
|
1355
|
+
effect: z.enum(["fade", "slide", "scale"]).optional().describe("Animation effect type"),
|
|
1356
|
+
effectType: z.enum(["in", "out"]).optional().describe("Whether the animation plays in or out"),
|
|
1357
|
+
direction: z.enum(["top", "bottom", "left", "right", ""]).optional().describe("Direction for slide effect. Use empty string for fade/scale."),
|
|
1358
|
+
duration: z.number().min(0).max(1e4).optional().describe("Animation duration in milliseconds"),
|
|
1359
|
+
delay: z.number().min(0).max(1e4).optional().describe("Animation delay in milliseconds"),
|
|
1360
|
+
easing: z.string().optional().describe("Easing function. See interactions schema for options."),
|
|
1361
|
+
excludedBreakpoints: z.array(z.string()).optional().describe(
|
|
1362
|
+
'Breakpoint IDs on which this interaction is disabled (e.g. ["mobile", "tablet"]). Omit to enable on all breakpoints.'
|
|
1363
|
+
)
|
|
1382
1364
|
};
|
|
1365
|
+
var proSchema = {
|
|
1366
|
+
trigger: z.enum(["load", "scrollIn", "scrollOut", "scrollOn", "hover", "click"]).optional().describe("Event that triggers the animation"),
|
|
1367
|
+
effect: z.enum(["fade", "slide", "scale", "custom"]).optional().describe("Animation effect type"),
|
|
1368
|
+
customEffect: z.object({
|
|
1369
|
+
keyframes: z.array(
|
|
1370
|
+
z.object({
|
|
1371
|
+
stop: z.number().describe("The stop of the keyframe in percent, can be either 0 or 100"),
|
|
1372
|
+
value: z.object({
|
|
1373
|
+
opacity: z.number().min(0).max(1).describe("The opacity of the keyframe"),
|
|
1374
|
+
scale: z.object({
|
|
1375
|
+
x: z.number().min(0).max(1).describe("The x scale of the keyframe"),
|
|
1376
|
+
y: z.number().min(0).max(1).describe("The y scale of the keyframe")
|
|
1377
|
+
}).optional().describe("The scale of the keyframe"),
|
|
1378
|
+
rotate: z.object({
|
|
1379
|
+
x: z.number().min(0).max(360).describe("The x rotate of the keyframe"),
|
|
1380
|
+
y: z.number().min(0).max(360).describe("The y rotate of the keyframe"),
|
|
1381
|
+
z: z.number().min(0).max(360).describe("The z rotate of the keyframe")
|
|
1382
|
+
}).optional().describe("The rotate of the keyframe"),
|
|
1383
|
+
move: z.object({
|
|
1384
|
+
x: z.number().min(0).max(1).describe("The x move of the keyframe"),
|
|
1385
|
+
y: z.number().min(0).max(1).describe("The y move of the keyframe"),
|
|
1386
|
+
z: z.number().min(0).max(1).describe("The z move of the keyframe")
|
|
1387
|
+
}).optional().describe("The move of the keyframe"),
|
|
1388
|
+
skew: z.object({
|
|
1389
|
+
x: z.number().min(0).max(360).describe("The x skew of the keyframe"),
|
|
1390
|
+
y: z.number().min(0).max(360).describe("The y skew of the keyframe")
|
|
1391
|
+
}).optional().describe("The skew of the keyframe")
|
|
1392
|
+
})
|
|
1393
|
+
})
|
|
1394
|
+
).describe("The keyframes of the custom effect")
|
|
1395
|
+
}).optional().describe("The custom effect to use for the animation")
|
|
1396
|
+
};
|
|
1397
|
+
|
|
1398
|
+
// src/mcp/resources/interactions-schema-resource.ts
|
|
1399
|
+
var INTERACTIONS_SCHEMA_URI = "elementor://interactions/schema";
|
|
1383
1400
|
var initInteractionsSchemaResource = (reg) => {
|
|
1384
1401
|
const { resource } = reg;
|
|
1402
|
+
const schema = isProActive() ? { ...baseSchema, ...proSchema } : baseSchema;
|
|
1385
1403
|
resource(
|
|
1386
1404
|
"interactions-schema",
|
|
1387
1405
|
INTERACTIONS_SCHEMA_URI,
|
|
1388
1406
|
{
|
|
1389
|
-
description: "Schema describing all available options for element interactions
|
|
1407
|
+
description: "Schema describing all available options for element interactions."
|
|
1390
1408
|
},
|
|
1391
1409
|
async () => {
|
|
1392
1410
|
return {
|
|
1393
1411
|
contents: [
|
|
1394
1412
|
{
|
|
1395
1413
|
uri: INTERACTIONS_SCHEMA_URI,
|
|
1396
|
-
|
|
1414
|
+
mimeType: "application/json",
|
|
1415
|
+
text: JSON.stringify(schema)
|
|
1397
1416
|
}
|
|
1398
1417
|
]
|
|
1399
1418
|
};
|
|
@@ -1403,85 +1422,49 @@ var initInteractionsSchemaResource = (reg) => {
|
|
|
1403
1422
|
|
|
1404
1423
|
// src/mcp/tools/manage-element-interaction-tool.ts
|
|
1405
1424
|
import { updateElementInteractions as updateElementInteractions2 } from "@elementor/editor-elements";
|
|
1406
|
-
import { z } from "@elementor/schema";
|
|
1425
|
+
import { z as z2 } from "@elementor/schema";
|
|
1426
|
+
import { isProActive as isProActive2 } from "@elementor/utils";
|
|
1407
1427
|
var EMPTY_INTERACTIONS = {
|
|
1408
1428
|
version: 1,
|
|
1409
1429
|
items: []
|
|
1410
1430
|
};
|
|
1411
1431
|
var initManageElementInteractionTool = (reg) => {
|
|
1412
1432
|
const { addTool } = reg;
|
|
1433
|
+
const extendedSchema = isProActive2() ? { ...baseSchema, ...proSchema } : baseSchema;
|
|
1434
|
+
const schema = {
|
|
1435
|
+
elementId: z2.string().describe("The ID of the element to read or modify interactions on"),
|
|
1436
|
+
action: z2.enum(["get", "add", "update", "delete", "clear"]).describe('Operation to perform. Use "get" first to inspect existing interactions.'),
|
|
1437
|
+
interactionId: z2.string().optional().describe('Interaction ID \u2014 required for update and delete. Obtain from a prior "get" call.'),
|
|
1438
|
+
...extendedSchema
|
|
1439
|
+
};
|
|
1413
1440
|
addTool({
|
|
1414
1441
|
name: "manage-element-interaction",
|
|
1415
|
-
description: `
|
|
1416
|
-
|
|
1417
|
-
Actions:
|
|
1418
|
-
- get: Read the current interactions on the element.
|
|
1419
|
-
- add: Add a new interaction (max ${MAX_INTERACTIONS_PER_ELEMENT} per element).
|
|
1420
|
-
- update: Update an existing interaction by its interactionId.
|
|
1421
|
-
- delete: Remove a specific interaction by its interactionId.
|
|
1422
|
-
- clear: Remove all interactions from the element.
|
|
1423
|
-
|
|
1424
|
-
For add/update, provide: trigger, effect, effectType, direction (empty string for non-slide effects), duration, delay, easing.
|
|
1425
|
-
Use excludedBreakpoints to disable the animation on specific responsive breakpoints (e.g. ["mobile", "tablet"]).`,
|
|
1426
|
-
schema: {
|
|
1427
|
-
elementId: z.string().describe("The ID of the element to read or modify interactions on"),
|
|
1428
|
-
action: z.enum(["get", "add", "update", "delete", "clear"]).describe('Operation to perform. Use "get" first to inspect existing interactions.'),
|
|
1429
|
-
interactionId: z.string().optional().describe('Interaction ID \u2014 required for update and delete. Obtain from a prior "get" call.'),
|
|
1430
|
-
trigger: z.enum(["load", "scrollIn"]).optional().describe("Event that triggers the animation"),
|
|
1431
|
-
effect: z.enum(["fade", "slide", "scale"]).optional().describe("Animation effect type"),
|
|
1432
|
-
effectType: z.enum(["in", "out"]).optional().describe("Whether the animation plays in or out"),
|
|
1433
|
-
direction: z.enum(["top", "bottom", "left", "right", ""]).optional().describe("Direction for slide effect. Use empty string for fade/scale."),
|
|
1434
|
-
duration: z.number().min(0).max(1e4).optional().describe("Animation duration in milliseconds"),
|
|
1435
|
-
delay: z.number().min(0).max(1e4).optional().describe("Animation delay in milliseconds"),
|
|
1436
|
-
easing: z.string().optional().describe("Easing function. See interactions schema for options."),
|
|
1437
|
-
excludedBreakpoints: z.array(z.string()).optional().describe(
|
|
1438
|
-
'Breakpoint IDs on which this interaction is disabled (e.g. ["mobile", "tablet"]). Omit to enable on all breakpoints.'
|
|
1439
|
-
)
|
|
1440
|
-
},
|
|
1442
|
+
description: `Manage the element interaction.`,
|
|
1443
|
+
schema,
|
|
1441
1444
|
requiredResources: [
|
|
1442
1445
|
{ uri: INTERACTIONS_SCHEMA_URI, description: "Interactions schema with all available options" }
|
|
1443
1446
|
],
|
|
1444
1447
|
isDestructive: true,
|
|
1448
|
+
outputSchema: {
|
|
1449
|
+
success: z2.boolean().describe("Whether the action was successful"),
|
|
1450
|
+
action: z2.enum(["get", "add", "update", "delete", "clear"]).describe('Operation to perform. Use "get" first to inspect existing interactions.'),
|
|
1451
|
+
elementId: z2.string().optional().describe("The ID of the element to read or modify interactions on"),
|
|
1452
|
+
interactions: z2.array(z2.any()).optional().describe("The interactions on the element"),
|
|
1453
|
+
count: z2.number().optional().describe("The number of interactions on the element")
|
|
1454
|
+
},
|
|
1445
1455
|
handler: (input) => {
|
|
1446
|
-
const {
|
|
1447
|
-
elementId,
|
|
1448
|
-
action,
|
|
1449
|
-
interactionId,
|
|
1450
|
-
trigger,
|
|
1451
|
-
effect,
|
|
1452
|
-
effectType,
|
|
1453
|
-
direction,
|
|
1454
|
-
duration,
|
|
1455
|
-
delay,
|
|
1456
|
-
easing,
|
|
1457
|
-
excludedBreakpoints
|
|
1458
|
-
} = input;
|
|
1456
|
+
const { elementId, action, interactionId, ...animationData } = input;
|
|
1459
1457
|
const allInteractions = interactionsRepository.all();
|
|
1460
1458
|
const elementData = allInteractions.find((data) => data.elementId === elementId);
|
|
1461
1459
|
const currentInteractions = elementData?.interactions ?? EMPTY_INTERACTIONS;
|
|
1462
1460
|
if (action === "get") {
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
const animValue = value.animation.value;
|
|
1466
|
-
const timingValue = animValue.timing_config.value;
|
|
1467
|
-
const configValue = animValue.config.value;
|
|
1468
|
-
return {
|
|
1469
|
-
id: extractString(value.interaction_id),
|
|
1470
|
-
trigger: extractString(value.trigger),
|
|
1471
|
-
effect: extractString(animValue.effect),
|
|
1472
|
-
effectType: extractString(animValue.type),
|
|
1473
|
-
direction: extractString(animValue.direction),
|
|
1474
|
-
duration: extractSize(timingValue.duration),
|
|
1475
|
-
delay: extractSize(timingValue.delay),
|
|
1476
|
-
easing: extractString(configValue.easing),
|
|
1477
|
-
excludedBreakpoints: extractExcludedBreakpoints(value.breakpoints)
|
|
1478
|
-
};
|
|
1479
|
-
});
|
|
1480
|
-
return JSON.stringify({
|
|
1461
|
+
return {
|
|
1462
|
+
success: true,
|
|
1481
1463
|
elementId,
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1464
|
+
action,
|
|
1465
|
+
interactions: currentInteractions.items,
|
|
1466
|
+
count: currentInteractions.items.length
|
|
1467
|
+
};
|
|
1485
1468
|
}
|
|
1486
1469
|
let updatedItems = [...currentInteractions.items];
|
|
1487
1470
|
switch (action) {
|
|
@@ -1493,15 +1476,7 @@ Use excludedBreakpoints to disable the animation on specific responsive breakpoi
|
|
|
1493
1476
|
}
|
|
1494
1477
|
const newItem = createInteractionItem({
|
|
1495
1478
|
interactionId: generateTempInteractionId(),
|
|
1496
|
-
|
|
1497
|
-
effect: effect ?? DEFAULT_VALUES.effect,
|
|
1498
|
-
type: effectType ?? DEFAULT_VALUES.type,
|
|
1499
|
-
direction: direction ?? DEFAULT_VALUES.direction,
|
|
1500
|
-
duration: duration ?? DEFAULT_VALUES.duration,
|
|
1501
|
-
delay: delay ?? DEFAULT_VALUES.delay,
|
|
1502
|
-
replay: DEFAULT_VALUES.replay,
|
|
1503
|
-
easing: easing ?? DEFAULT_VALUES.easing,
|
|
1504
|
-
excludedBreakpoints
|
|
1479
|
+
...animationData
|
|
1505
1480
|
});
|
|
1506
1481
|
updatedItems = [...updatedItems, newItem];
|
|
1507
1482
|
break;
|
|
@@ -1518,23 +1493,9 @@ Use excludedBreakpoints to disable the animation on specific responsive breakpoi
|
|
|
1518
1493
|
`Interaction with ID "${interactionId}" not found on element "${elementId}".`
|
|
1519
1494
|
);
|
|
1520
1495
|
}
|
|
1521
|
-
const existingItem = updatedItems[itemIndex];
|
|
1522
|
-
const existingValue = existingItem.value;
|
|
1523
|
-
const existingAnimation = existingValue.animation.value;
|
|
1524
|
-
const existingTiming = existingAnimation.timing_config.value;
|
|
1525
|
-
const existingConfig = existingAnimation.config.value;
|
|
1526
|
-
const existingExcludedBreakpoints = extractExcludedBreakpoints(existingValue.breakpoints);
|
|
1527
1496
|
const updatedItem = createInteractionItem({
|
|
1528
1497
|
interactionId,
|
|
1529
|
-
|
|
1530
|
-
effect: effect ?? extractString(existingAnimation.effect),
|
|
1531
|
-
type: effectType ?? extractString(existingAnimation.type),
|
|
1532
|
-
direction: direction !== void 0 ? direction : extractString(existingAnimation.direction),
|
|
1533
|
-
duration: duration !== void 0 ? duration : extractSize(existingTiming.duration),
|
|
1534
|
-
delay: delay !== void 0 ? delay : extractSize(existingTiming.delay),
|
|
1535
|
-
replay: existingConfig.replay?.value ?? DEFAULT_VALUES.replay,
|
|
1536
|
-
easing: easing ?? extractString(existingConfig.easing),
|
|
1537
|
-
excludedBreakpoints: excludedBreakpoints !== void 0 ? excludedBreakpoints : existingExcludedBreakpoints
|
|
1498
|
+
...animationData
|
|
1538
1499
|
});
|
|
1539
1500
|
updatedItems = [
|
|
1540
1501
|
...updatedItems.slice(0, itemIndex),
|
|
@@ -1574,12 +1535,12 @@ Use excludedBreakpoints to disable the animation on specific responsive breakpoi
|
|
|
1574
1535
|
`Failed to update interactions for element "${elementId}": ${error instanceof Error ? error.message : "Unknown error"}`
|
|
1575
1536
|
);
|
|
1576
1537
|
}
|
|
1577
|
-
return
|
|
1538
|
+
return {
|
|
1578
1539
|
success: true,
|
|
1579
1540
|
action,
|
|
1580
1541
|
elementId,
|
|
1581
|
-
|
|
1582
|
-
}
|
|
1542
|
+
count: updatedItems.length
|
|
1543
|
+
};
|
|
1583
1544
|
}
|
|
1584
1545
|
});
|
|
1585
1546
|
};
|
|
@@ -1587,10 +1548,71 @@ Use excludedBreakpoints to disable the animation on specific responsive breakpoi
|
|
|
1587
1548
|
// src/mcp/index.ts
|
|
1588
1549
|
var initMcpInteractions = () => {
|
|
1589
1550
|
const reg = getMCPByDomain("interactions", {
|
|
1590
|
-
instructions:
|
|
1551
|
+
instructions: `
|
|
1552
|
+
MCP server for managing element interactions and animations. Use this to add, modify, or remove animations and motion effects triggered by user events such as page load or scroll-into-view.
|
|
1553
|
+
** IMPORTANT **
|
|
1554
|
+
Use the "interactions-schema" resource to get the schema of the interactions.
|
|
1555
|
+
Actions:
|
|
1556
|
+
- get: Read the current interactions on the element.
|
|
1557
|
+
- add: Add a new interaction (max ${MAX_INTERACTIONS_PER_ELEMENT} per element).
|
|
1558
|
+
- update: Update an existing interaction by its interactionId.
|
|
1559
|
+
- delete: Remove a specific interaction by its interactionId.
|
|
1560
|
+
- clear: Remove all interactions from the element.
|
|
1561
|
+
|
|
1562
|
+
For add/update, provide: trigger, effect, effectType, direction (required for slide effect), duration, delay, easing.
|
|
1563
|
+
Use excludedBreakpoints to disable the animation on specific responsive breakpoints (e.g. ["mobile", "tablet"]).
|
|
1564
|
+
Example Get Request:
|
|
1565
|
+
{
|
|
1566
|
+
"elementId": "123",
|
|
1567
|
+
"action": "get",
|
|
1568
|
+
"interactionId": "123",
|
|
1569
|
+
"animationData": {
|
|
1570
|
+
"trigger": "click",
|
|
1571
|
+
"effect": "fade",
|
|
1572
|
+
}
|
|
1573
|
+
}
|
|
1574
|
+
Example Add Request:
|
|
1575
|
+
{
|
|
1576
|
+
"elementId": "123",
|
|
1577
|
+
"action": "add",
|
|
1578
|
+
"animationData": {
|
|
1579
|
+
"effectType": "in",
|
|
1580
|
+
"direction": "top",
|
|
1581
|
+
"trigger": "click",
|
|
1582
|
+
"effect": "fade",
|
|
1583
|
+
"duration": 1000,
|
|
1584
|
+
"delay": 0,
|
|
1585
|
+
"easing": "easeIn",
|
|
1586
|
+
"excludedBreakpoints": ["mobile", "tablet"],
|
|
1587
|
+
}
|
|
1588
|
+
}
|
|
1589
|
+
Example Update Request:
|
|
1590
|
+
{
|
|
1591
|
+
"elementId": "123",
|
|
1592
|
+
"action": "update",
|
|
1593
|
+
"interactionId": "123",
|
|
1594
|
+
"animationData": {
|
|
1595
|
+
"trigger": "click",
|
|
1596
|
+
"effect": "fade",
|
|
1597
|
+
}
|
|
1598
|
+
}
|
|
1599
|
+
Example Delete Request:
|
|
1600
|
+
{
|
|
1601
|
+
"elementId": "123",
|
|
1602
|
+
"action": "delete",
|
|
1603
|
+
"interactionId": "123",
|
|
1604
|
+
}
|
|
1605
|
+
Example Clear Request:
|
|
1606
|
+
{
|
|
1607
|
+
"elementId": "123",
|
|
1608
|
+
"action": "clear",
|
|
1609
|
+
}
|
|
1610
|
+
`
|
|
1611
|
+
});
|
|
1612
|
+
reg.waitForReady().then(() => {
|
|
1613
|
+
initInteractionsSchemaResource(reg);
|
|
1614
|
+
initManageElementInteractionTool(reg);
|
|
1591
1615
|
});
|
|
1592
|
-
initInteractionsSchemaResource(reg);
|
|
1593
|
-
initManageElementInteractionTool(reg);
|
|
1594
1616
|
};
|
|
1595
1617
|
|
|
1596
1618
|
// src/init.ts
|