@antglobal/copilot-cards-web 1.0.0 → 1.0.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/README.md CHANGED
@@ -1 +1,172 @@
1
- # Marmot NPM
1
+ # @antglobal/copilot-cards-web
2
+
3
+ Web renderer for schema-driven cards in AI conversations. It turns one JSON schema into interactive Custom Elements for desktop browsers, mobile browsers, and WebViews.
4
+
5
+ The package includes the core schema and action APIs, responsive rendering, Shadow DOM style isolation, streaming updates, and extensible component registration.
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ npm install @antglobal/copilot-cards-web
11
+ ```
12
+
13
+ `@antglobal/copilot-cards-core` is installed automatically.
14
+
15
+ ## Quick start
16
+
17
+ ```ts
18
+ import { renderCard } from "@antglobal/copilot-cards-web";
19
+
20
+ const container = document.getElementById("card");
21
+ if (!container) throw new Error("Missing #card container");
22
+
23
+ const schema = {
24
+ version: "1.0",
25
+ rootID: "root",
26
+ elements: {
27
+ root: {
28
+ id: "root",
29
+ type: "Text",
30
+ props: {
31
+ content: { type: "static", value: "Hello, Copilot Cards!" },
32
+ },
33
+ },
34
+ },
35
+ variables: {},
36
+ };
37
+
38
+ const card = renderCard(container, schema, {
39
+ emit: (eventName, payload) => {
40
+ console.log(eventName, payload);
41
+ },
42
+ showToast: (message, level) => {
43
+ console.log(`[${level ?? "info"}] ${message}`);
44
+ },
45
+ });
46
+
47
+ card.updateVariables({ userName: "Alice" });
48
+
49
+ // Dispose when the host view is removed.
50
+ card.dispose();
51
+ ```
52
+
53
+ ## Framework usage
54
+
55
+ The renderer accesses browser APIs and should be loaded on the client in frameworks that perform server-side rendering.
56
+
57
+ ```ts
58
+ const { renderCard } = await import("@antglobal/copilot-cards-web");
59
+ ```
60
+
61
+ In React or Next.js, run the dynamic import inside a client component effect. In Vue, run it after the component is mounted.
62
+
63
+ ## Main API
64
+
65
+ ### `renderCard(container, schema, options?)`
66
+
67
+ Renders a complete schema and returns a `CardInstance`:
68
+
69
+ ```ts
70
+ interface CardInstance {
71
+ updateVariables(variables: Record<string, unknown>): void;
72
+ dispose(): void;
73
+ }
74
+ ```
75
+
76
+ Common render options include:
77
+
78
+ | Option | Purpose |
79
+ | --- | --- |
80
+ | `variables` | Overrides initial schema variables |
81
+ | `botId` | Selects bot-scoped custom action handlers |
82
+ | `isMobile` | Overrides automatic viewport detection |
83
+ | `fetch` | Supplies a custom request implementation |
84
+ | `showToast` | Connects toast actions to the host UI |
85
+ | `navigate` | Connects URL actions to host navigation |
86
+ | `emit` | Receives events emitted by a card |
87
+ | `copyText` | Connects copy actions to the host clipboard |
88
+
89
+ ### Streaming
90
+
91
+ Use `renderStreamingCard` when the card arrives incrementally from an AI model or server:
92
+
93
+ ```ts
94
+ import { renderStreamingCard } from "@antglobal/copilot-cards-web";
95
+
96
+ const stream = renderStreamingCard(container);
97
+
98
+ stream.feed(chunk);
99
+ stream.flush();
100
+ stream.dispose();
101
+ ```
102
+
103
+ The package also exports `connectStreaming` and `connectSSE` helpers, plus partial-schema and A2UI adapters.
104
+
105
+ ### `BotSDK`
106
+
107
+ `BotSDK` groups card instances, bot-scoped action handlers, and declarative action providers behind one host-facing API.
108
+
109
+ ```ts
110
+ import { BotSDK } from "@antglobal/copilot-cards-web";
111
+
112
+ const bot = new BotSDK({
113
+ botId: "support-bot",
114
+ onAction: {
115
+ trackEvent: async (step) => {
116
+ console.log(step.params);
117
+ },
118
+ },
119
+ });
120
+
121
+ await bot.renderCard(container, schema);
122
+ ```
123
+
124
+ ## Built-in components
125
+
126
+ The renderer includes:
127
+
128
+ - Text, Button, Input, Image, Divider
129
+ - Rate, Tag, Select, PasscodeInput
130
+ - Icon, Form, Loading, Progress
131
+ - Steps, Collapse, and sanitized HTML
132
+
133
+ Components render as isolated `ai-card-*` Custom Elements.
134
+
135
+ ## Custom components
136
+
137
+ ```ts
138
+ import {
139
+ registerComponent,
140
+ type ComponentRenderer,
141
+ } from "@antglobal/copilot-cards-web";
142
+
143
+ const renderStatus: ComponentRenderer = (_node, props) => {
144
+ const element = document.createElement("div");
145
+ element.textContent = String(props.label ?? "");
146
+ return element;
147
+ };
148
+
149
+ registerComponent("Status", renderStatus);
150
+ ```
151
+
152
+ ## Actions
153
+
154
+ Cards can declaratively request `emit`, `request`, `setVariable`, `toast`, `url`, and `copy` actions. The host remains in control of network access, navigation, notifications, clipboard behavior, and custom business actions.
155
+
156
+ ## Browser requirements
157
+
158
+ - Custom Elements
159
+ - Shadow DOM
160
+ - `AbortController`
161
+ - Modern JavaScript with ES2020 support
162
+
163
+ Provide appropriate polyfills when targeting older WebViews.
164
+
165
+ ## Related packages
166
+
167
+ - `@antglobal/copilot-cards-core` — UI-independent schema, expression, action, lifecycle, and streaming logic.
168
+ - `@antglobal/copilot-cards-mini-program` — native renderer for Alipay and WeChat mini-programs.
169
+
170
+ ## License
171
+
172
+ MIT
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { ActionRunnerContext, CardSchemaInput, StreamingCommand, CardSchema, StreamingParserOptions, SimpleActionHandler, ActionConfigProvider, ActionChainConfig, RenderTreeNode } from '@antglobal/copilot-cards-core';
2
- export { A2UIComponent, A2UIEnvelope, ActionChainConfig, ActionConfigProvider, ActionRegistry, ActionRunnerContext, ActionStep, CardSchema, CardSchemaInput, ElementLifecycle, ElementNode, ExpressionContext, ExpressionValue, LegacyCardContentItem, LegacyCardSchema, LegacyTracking, LegacyTrackingType, LifecycleManager, RenderTreeNode, SimpleActionHandler, SlotContent, SlotLayout, a2uiComponentToElement, a2uiToCommand, convertLegacySchema, createLifecycleManager, hasExpression, isA2UIEnvelope, isLegacySchema, normalizeSchema, parseSchema, registerActionHandler, registry, resolveActionRef, resolveDeep, resolveExpression, resolveExpressionValue, runActionStep, runActionSteps, validateSchema } from '@antglobal/copilot-cards-core';
2
+ export { A2UIComponent, A2UIEnvelope, ActionChainConfig, ActionConfigProvider, ActionRegistry, ActionRunnerContext, ActionStep, BuiltinIconName, CardSchema, CardSchemaInput, ElementLifecycle, ElementNode, ExpressionContext, ExpressionValue, LegacyCardContentItem, LegacyCardSchema, LegacyTracking, LegacyTrackingType, LifecycleManager, RenderTreeNode, SimpleActionHandler, SlotContent, SlotLayout, a2uiComponentToElement, a2uiToCommand, convertLegacySchema, createLifecycleManager, hasExpression, isA2UIEnvelope, isLegacySchema, normalizeSchema, parseSchema, registerActionHandler, registry, resolveActionRef, resolveDeep, resolveExpression, resolveExpressionValue, runActionStep, runActionSteps, validateSchema } from '@antglobal/copilot-cards-core';
3
3
 
4
4
  /**
5
5
  * Core Adapter — bridges @antglobal/copilot-cards-core logic for the web-component layer.
@@ -780,7 +780,7 @@ declare class CardPasscodeInput extends BaseElement {
780
780
  * {
781
781
  * "type": "Icon",
782
782
  * "props": {
783
- * "name": "check",
783
+ * "name": "check_circle",
784
784
  * "src": "https://...",
785
785
  * "size": 24,
786
786
  * "color": "#1677ff"
@@ -1006,13 +1006,13 @@ interface PasscodeInputProps {
1006
1006
  style?: Record<string, any>;
1007
1007
  }
1008
1008
  interface IconProps {
1009
- /** Built-in icon name (check/close/info/warning/error/success/star/heart/search/arrow_right) or emoji */
1009
+ /** Built-in snake_case icon name or fallback text/emoji */
1010
1010
  name?: string;
1011
- /** URL to a remote icon image */
1011
+ /** External image URL; takes precedence over name and is not recolored */
1012
1012
  src?: string;
1013
1013
  /** Icon size in px (default 24) */
1014
1014
  size?: number;
1015
- /** Icon color (default 'currentColor') */
1015
+ /** Built-in SVG color (default currentColor); does not affect src images */
1016
1016
  color?: string;
1017
1017
  /** Inline style object */
1018
1018
  style?: Record<string, any>;
@@ -1,4 +1,4 @@
1
- import { normalizeSchema, validateSchema, parseSchema, createLifecycleManager, hasExpression, resolveExpression, resolveDeep, resolveExpressionValue, resolveActionRef, runActionSteps, StreamingParser, StreamingEngine, extractPartialSchema, runActionStep, registry } from '@antglobal/copilot-cards-core';
1
+ import { getBuiltinIcon, normalizeSchema, validateSchema, parseSchema, createLifecycleManager, hasExpression, resolveExpression, resolveDeep, resolveExpressionValue, resolveActionRef, runActionSteps, StreamingParser, StreamingEngine, extractPartialSchema, runActionStep, registry } from '@antglobal/copilot-cards-core';
2
2
  export { ActionRegistry, a2uiComponentToElement, a2uiToCommand, convertLegacySchema, createLifecycleManager, hasExpression, isA2UIEnvelope, isLegacySchema, normalizeSchema, parseSchema, registerActionHandler, registry, resolveActionRef, resolveDeep, resolveExpression, resolveExpressionValue, runActionStep, runActionSteps, validateSchema } from '@antglobal/copilot-cards-core';
3
3
  import * as echarts from 'echarts/core';
4
4
  import { LineChart, BarChart, PieChart, ScatterChart, FunnelChart, HeatmapChart } from 'echarts/charts';
@@ -2083,10 +2083,11 @@ class CardButton extends BaseElement {
2083
2083
  max-width: 100%;
2084
2084
  }
2085
2085
  .card-btn {
2086
+ position: relative;
2087
+ isolation: isolate;
2086
2088
  display: inline-flex;
2087
2089
  align-items: center;
2088
2090
  justify-content: center;
2089
- gap: 6px;
2090
2091
  border: none;
2091
2092
  border-radius: 6px;
2092
2093
  cursor: pointer;
@@ -2104,6 +2105,37 @@ class CardButton extends BaseElement {
2104
2105
  width: ${block ? '100%' : 'auto'};
2105
2106
  }
2106
2107
 
2108
+ /* ─── Custom-background-safe interaction overlay ──────── */
2109
+ .card-btn::before {
2110
+ position: absolute;
2111
+ inset: 0;
2112
+ z-index: 0;
2113
+ border-radius: inherit;
2114
+ background: currentColor;
2115
+ opacity: 0;
2116
+ pointer-events: none;
2117
+ content: '';
2118
+ transition: opacity 0.2s ease;
2119
+ }
2120
+ .card-btn:hover:not(:disabled)::before {
2121
+ opacity: 0.08;
2122
+ }
2123
+ .card-btn:active:not(:disabled)::before {
2124
+ opacity: 0.12;
2125
+ }
2126
+ .card-btn-content {
2127
+ position: relative;
2128
+ z-index: 1;
2129
+ display: inline-flex;
2130
+ min-width: 0;
2131
+ max-width: 100%;
2132
+ align-items: center;
2133
+ justify-content: center;
2134
+ gap: 6px;
2135
+ overflow: hidden;
2136
+ text-overflow: ellipsis;
2137
+ }
2138
+
2107
2139
  /* ─── Variants ─────────────────────────── */
2108
2140
  .card-btn.primary {
2109
2141
  background-color: #1677ff;
@@ -2187,7 +2219,7 @@ class CardButton extends BaseElement {
2187
2219
  class="card-btn ${variant} ${isMobile ? 'card-mobile' : 'card-desktop'}"
2188
2220
  ${disabled ? 'disabled' : ''}
2189
2221
  style="${inlineStyle}"
2190
- >${icon ? `<span class="card-btn-icon">${sanitizeIconHtml(String(icon))}</span>` : ''}${displayText}</button>
2222
+ ><span class="card-btn-content">${icon ? `<span class="card-btn-icon">${sanitizeIconHtml(String(icon))}</span>` : ''}${displayText}</span></button>
2191
2223
  `;
2192
2224
  }
2193
2225
  }
@@ -3396,25 +3428,6 @@ if (typeof customElements !== 'undefined' && !customElements.get(CardPasscodeInp
3396
3428
  customElements.define(CardPasscodeInput.is, CardPasscodeInput);
3397
3429
  }
3398
3430
 
3399
- /**
3400
- * CardIcon — Custom Element for rendering icons.
3401
- *
3402
- * Supports URL-based icons (png/svg) and built-in emoji/SVG icons.
3403
- *
3404
- * Schema example:
3405
- * ```json
3406
- * {
3407
- * "type": "Icon",
3408
- * "props": {
3409
- * "name": "check",
3410
- * "src": "https://...",
3411
- * "size": 24,
3412
- * "color": "#1677ff"
3413
- * }
3414
- * }
3415
- * ```
3416
- */
3417
- /** Escape a value for safe interpolation into an HTML attribute (double-quoted). */
3418
3431
  function escapeAttr$1(value) {
3419
3432
  return value
3420
3433
  .replace(/&/g, '&amp;')
@@ -3422,43 +3435,56 @@ function escapeAttr$1(value) {
3422
3435
  .replace(/</g, '&lt;')
3423
3436
  .replace(/>/g, '&gt;');
3424
3437
  }
3425
- /** Escape a value for safe interpolation as HTML element text. */
3426
3438
  function escapeText(value) {
3427
3439
  return value
3428
3440
  .replace(/&/g, '&amp;')
3429
3441
  .replace(/</g, '&lt;')
3430
3442
  .replace(/>/g, '&gt;');
3431
3443
  }
3432
- /**
3433
- * Reject only genuinely dangerous src schemes (script-bearing / non-image
3434
- * data URIs); everything else — http(s), protocol-relative, absolute and
3435
- * relative paths, blob:, image data URIs — passes through unchanged so no
3436
- * legitimate icon URL is broken. Blocked values fall back to empty.
3437
- */
3438
3444
  function sanitizeImageSrc(src) {
3439
- const trimmed = String(src).trim();
3440
- // Strip HTML-entity / whitespace obfuscation, then test the leading scheme.
3445
+ const trimmed = String(src ?? '').trim();
3441
3446
  const scheme = trimmed.replace(/[\s\x00-\x1f]/g, '').toLowerCase();
3442
3447
  if (/^(javascript|vbscript|file):/.test(scheme))
3443
3448
  return '';
3444
- // Allow data: only for images; block data:text/html and friends.
3445
3449
  if (/^data:/.test(scheme) && !/^data:image\//.test(scheme))
3446
3450
  return '';
3447
3451
  return trimmed;
3448
3452
  }
3449
- // Built-in SVG icon paths (minimal set)
3450
- const BUILTIN_ICONS = {
3451
- check: '<path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"/>',
3452
- close: '<path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/>',
3453
- info: '<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z"/>',
3454
- warning: '<path d="M1 21h22L12 2 1 21zm12-3h-2v-2h2v2zm0-4h-2v-4h2v4z"/>',
3455
- error: '<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z"/>',
3456
- success: '<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z"/>',
3457
- star: '<path d="M12 17.27L18.18 21l-1.64-7.03L22 9.24l-7.19-.61L12 2 9.19 8.63 2 9.24l5.46 4.73L5.82 21z"/>',
3458
- heart: '<path d="M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z"/>',
3459
- search: '<path d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"/>',
3460
- arrow_right: '<path d="M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z"/>',
3461
- };
3453
+ function renderIconContent(input) {
3454
+ const size = Number(input.size) || 24;
3455
+ const name = input.name == null ? undefined : String(input.name);
3456
+ if (input.src) {
3457
+ return `<img class="icon-img" src="${escapeAttr$1(sanitizeImageSrc(input.src))}" ` +
3458
+ `width="${size}" height="${size}" alt="${escapeAttr$1(name ?? 'icon')}" />`;
3459
+ }
3460
+ const icon = getBuiltinIcon(name);
3461
+ if (icon) {
3462
+ return `<svg class="icon-svg" viewBox="${escapeAttr$1(icon.viewBox)}" width="${size}" ` +
3463
+ `height="${size}" color="${escapeAttr$1(String(input.color ?? 'currentColor'))}" ` +
3464
+ `aria-hidden="true">${icon.body}</svg>`;
3465
+ }
3466
+ return `<span class="icon-text" style="font-size:${size}px; line-height:1;">` +
3467
+ `${escapeText(name ?? '?')}</span>`;
3468
+ }
3469
+
3470
+ /**
3471
+ * CardIcon — Custom Element for rendering icons.
3472
+ *
3473
+ * Supports URL-based icons (png/svg) and built-in emoji/SVG icons.
3474
+ *
3475
+ * Schema example:
3476
+ * ```json
3477
+ * {
3478
+ * "type": "Icon",
3479
+ * "props": {
3480
+ * "name": "check_circle",
3481
+ * "src": "https://...",
3482
+ * "size": 24,
3483
+ * "color": "#1677ff"
3484
+ * }
3485
+ * }
3486
+ * ```
3487
+ */
3462
3488
  class CardIcon extends BaseElement {
3463
3489
  render() {
3464
3490
  if (!this.shadowRoot || !this._node)
@@ -3466,26 +3492,12 @@ class CardIcon extends BaseElement {
3466
3492
  const { name, src, size = 24, color = 'currentColor', style, isExpressionResultStyle, } = this._props;
3467
3493
  const inlineStyle = this.buildInlineStyle(style, isExpressionResultStyle);
3468
3494
  const iconSize = Number(size) || 24;
3469
- let iconContent;
3470
- if (src) {
3471
- // URL-based icon (image). Both src and alt are interpolated into HTML
3472
- // attributes, so they must be escaped — an unescaped `"` in src would
3473
- // break out of the attribute and inject markup (e.g. onerror handlers).
3474
- // src is additionally protocol-gated to http(s)/data-image only.
3475
- const safeSrc = escapeAttr$1(sanitizeImageSrc(src));
3476
- const safeAlt = escapeAttr$1(String(name ?? 'icon'));
3477
- iconContent = `<img class="icon-img" src="${safeSrc}" width="${iconSize}" height="${iconSize}" alt="${safeAlt}" />`;
3478
- }
3479
- else if (name && BUILTIN_ICONS[name]) {
3480
- // Built-in SVG — `name` is validated against the allow-list, so the SVG
3481
- // body is a trusted constant; `color` is escaped defensively.
3482
- iconContent = `<svg class="icon-svg" viewBox="0 0 24 24" width="${iconSize}" height="${iconSize}" fill="${escapeAttr$1(String(color))}">${BUILTIN_ICONS[name]}</svg>`;
3483
- }
3484
- else {
3485
- // Fallback: show name as text (emoji support). Escape as element text so
3486
- // an arbitrary `name` can't inject markup.
3487
- iconContent = `<span class="icon-text" style="font-size:${iconSize}px; line-height:1;">${escapeText(String(name ?? '?'))}</span>`;
3488
- }
3495
+ const iconContent = renderIconContent({
3496
+ name,
3497
+ src,
3498
+ size: iconSize,
3499
+ color,
3500
+ });
3489
3501
  this.shadowRoot.innerHTML = `
3490
3502
  <style>
3491
3503
  :host {
@@ -7078,4 +7090,3 @@ class RemoteActionConfigProvider {
7078
7090
  }
7079
7091
 
7080
7092
  export { BaseElement, BotSDK, CardButton, CardCollapse, CardDivider, CardForm, CardHtml, CardIcon, CardImage, CardInput, CardLoading, CardPasscodeInput, CardProgress, CardRate, CardSelect, CardSteps, CardTag, CardText, LocalActionConfigProvider, RemoteActionConfigProvider, buildStyleString, componentRenderers, connectSSE, connectStreaming, createWebActionContext, isMobileViewport, onViewportChange, pxToRem, pxToVw, registerComponent, renderCard, renderStreamingCard, resolveSize, sanitizeHtml, trimIncompleteTag };
7081
- //# sourceMappingURL=index.esm.js.map
package/package.json CHANGED
@@ -1,22 +1,23 @@
1
1
  {
2
2
  "name": "@antglobal/copilot-cards-web",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "Web Component renderer for copilot bot card SDK — PC + Mobile + WebView unified rendering via Custom Elements",
5
- "main": "dist/index.cjs.js",
6
- "module": "dist/index.esm.js",
7
- "types": "dist/index.d.ts",
5
+ "type": "module",
6
+ "module": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
8
  "exports": {
9
9
  ".": {
10
- "import": "./dist/index.esm.js",
11
- "require": "./dist/index.cjs.js",
12
- "types": "./dist/index.d.ts"
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js",
12
+ "default": "./dist/index.js"
13
13
  }
14
14
  },
15
15
  "files": [
16
16
  "dist"
17
17
  ],
18
18
  "scripts": {
19
- "build": "rollup -c"
19
+ "clean": "node -e \"require('node:fs').rmSync('dist', { recursive: true, force: true })\"",
20
+ "build": "npm run clean && tsc -p ../copilot-cards-web/tsconfig.json --noEmit && rollup -c"
20
21
  },
21
22
  "keywords": [
22
23
  "copilot",
@@ -27,14 +28,13 @@
27
28
  ],
28
29
  "license": "MIT",
29
30
  "dependencies": {
30
- "@antglobal/copilot-cards-core": "^1.0.0",
31
+ "@antglobal/copilot-cards-core": "^1.0.1",
31
32
  "echarts": "^5.6.0",
32
33
  "marked": "^18.0.5",
33
34
  "tslib": "^2.8.1",
34
35
  "vanilla-calendar-pro": "^3.1.0"
35
36
  },
36
37
  "devDependencies": {
37
- "@rollup/plugin-typescript": "^11.1.0",
38
38
  "@types/node": "^20",
39
39
  "rollup": "^4.9.0",
40
40
  "rollup-plugin-dts": "^6.1.0",