waf-captcha-frontend 0.0.5

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 ADDED
@@ -0,0 +1,283 @@
1
+ # AWS WAF Captcha Interceptor
2
+
3
+ ## Overview
4
+
5
+ AWS WAF Captcha Interceptor is a lightweight JavaScript/TypeScript library that provides seamless integration with AWS WAF Captcha for fetch-based HTTP requests. The package handles captcha challenges transparently, intercepting requests and displaying captcha modals when required by AWS WAF.
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ npm install aws-waf-captcha-interceptor
11
+ # or
12
+ yarn add aws-waf-captcha-interceptor
13
+ ```
14
+
15
+ ## Prerequisites
16
+
17
+ Before using this package, ensure you have AWS WAF configured with CAPTCHA rules
18
+
19
+ ## Quick Start
20
+
21
+ ```typescript
22
+ import { createCaptchaInterceptor } from 'aws-waf-captcha-interceptor';
23
+
24
+ // Initialize the interceptor
25
+ const captchaFetch = createCaptchaInterceptor({
26
+ API_KEY: 'your-api-key',
27
+ JSAPI_URL: 'https://your-domain.aws.captcha.jsapi',
28
+ captchaContainerId: 'captcha-container',
29
+ });
30
+
31
+ // Use it like regular fetch
32
+ const response = await captchaFetch('/api/protected-endpoint', {
33
+ method: 'POST',
34
+ headers: {
35
+ 'Content-Type': 'application/json',
36
+ },
37
+ body: JSON.stringify({ data: 'example' }),
38
+ });
39
+ ```
40
+
41
+ ## Configuration
42
+
43
+ The package accepts the following configuration object:
44
+
45
+ ```typescript
46
+ export interface AWSWAFInterceptorConfig {
47
+ // Required: API credentials
48
+ API_KEY: string;
49
+ JSAPI_URL: string;
50
+
51
+ // Event handlers
52
+ onSuccess?: () => void;
53
+ onLoad?: () => void;
54
+ onError?: (err: string) => void;
55
+ onPuzzleTimeout?: () => void;
56
+ onPuzzleIncorrect?: () => void;
57
+ onPuzzleCorrect?: () => void;
58
+
59
+ // Container IDs for DOM injection
60
+ captchaContainerId: string; // Main container for captcha modal
61
+ captchaContentId?: string; // Container for captcha form
62
+ overlayId?: string; // Overlay element ID
63
+ modalId?: string; // Modal container ID
64
+ }
65
+ ```
66
+
67
+ ### Default Values
68
+
69
+ If containers IDs not provided, the package will use these default IDs:
70
+ - `captchaContentId`: `'captcha-content'`
71
+ - `overlayId`: `'captcha-overlay'`
72
+ - `modalId`: `'captcha-modal'`
73
+
74
+ ## Usage
75
+
76
+ ### Basic Implementation
77
+
78
+ ```typescript
79
+ import { createCaptchaInterceptor } from 'aws-waf-captcha-interceptor';
80
+
81
+ const config = {
82
+ API_KEY: 'your-api-key',
83
+ JSAPI_URL: 'https://your-domain.aws.captcha.jsapi',
84
+ captchaContainerId: 'aws-captcha-container',
85
+
86
+ // Optional event handlers
87
+ onSuccess: () => console.log('Captcha solved successfully'),
88
+ onError: (err) => console.error('Captcha error:', err),
89
+ onPuzzleTimeout: () => console.error('Captcha puzzle timed out'),
90
+ };
91
+
92
+ const captchaFetch = createCaptchaInterceptor(config);
93
+
94
+ // Make authenticated requests
95
+ async function fetchProtectedData() {
96
+ try {
97
+ const data = await captchaFetch('/api/data', {
98
+ method: 'GET',
99
+ credentials: 'include',
100
+ });
101
+ return data;
102
+ } catch (error) {
103
+ console.error('Request failed:', error);
104
+ throw error;
105
+ }
106
+ }
107
+ ```
108
+
109
+ ### React Example
110
+
111
+ ```tsx
112
+ import React, { useEffect } from 'react';
113
+ import { createCaptchaInterceptor } from 'aws-waf-captcha-interceptor';
114
+
115
+ const App = () => {
116
+ useEffect(() => {
117
+ // Initialize once when component mounts
118
+ const captchaFetch = createCaptchaInterceptor({
119
+ API_KEY: 'your-aws-api-key',
120
+ JSAPI_URL: 'https://your-domain.aws.captcha.jsapi',
121
+ captchaContainerId: 'captcha-root',
122
+ });
123
+
124
+ // Store in context or make globally available
125
+ window.captchaFetch = captchaFetch;
126
+ }, []);
127
+
128
+ const handleSubmit = async () => {
129
+ try {
130
+ const response = await window.captchaFetch('/api/submit', {
131
+ method: 'POST',
132
+ body: JSON.stringify({ formData: 'test' }),
133
+ });
134
+ console.log('Success:', response);
135
+ } catch (error) {
136
+ console.error('Failed:', error);
137
+ }
138
+ };
139
+
140
+ return (
141
+ <div>
142
+ {/* Container for captcha - must exist in DOM */}
143
+ <div id="captcha-root" />
144
+ <button onClick={handleSubmit}>Submit</button>
145
+ </div>
146
+ );
147
+ };
148
+ ```
149
+
150
+ ### Advanced Configuration with All Options
151
+
152
+ ```typescript
153
+ const advancedConfig = {
154
+ API_KEY: 'your-aws-api-key',
155
+ JSAPI_URL: 'https://your-domain.aws.captcha.jsapi',
156
+
157
+ // Custom container IDs
158
+ captchaContainerId: 'captcha-root-container',
159
+ captchaContentId: 'custom-captcha-content',
160
+ overlayId: 'custom-overlay',
161
+ modalId: 'custom-modal',
162
+
163
+ // Event handlers
164
+ onLoad: () => {
165
+ console.log('Captcha library loaded');
166
+ },
167
+ onSuccess: () => {
168
+ console.log('Captcha verification successful');
169
+ },
170
+ onError: (errorMessage) => {
171
+ console.error('Captcha error:', errorMessage);
172
+ },
173
+ onPuzzleTimeout: () => {
174
+ console.warn('User took too long to solve captcha');
175
+ },
176
+ onPuzzleIncorrect: () => {
177
+ console.log('Incorrect captcha solution');
178
+ },
179
+ onPuzzleCorrect: () => {
180
+ console.log('Captcha solved correctly');
181
+ },
182
+ };
183
+
184
+ const captchaFetch = createCaptchaInterceptor(advancedConfig);
185
+ ```
186
+
187
+ ## API Reference
188
+
189
+ ### `createCaptchaInterceptor(config: AWSWAFInterceptorConfig)`
190
+
191
+ Creates and returns a fetch wrapper function that automatically handles AWS WAF captcha challenges.
192
+
193
+ **Parameters:**
194
+ - `config`: Configuration object as defined in `AWSWAFInterceptorConfig`
195
+
196
+ **Returns:**
197
+ - A function with the same signature as `fetch()`, but with automatic captcha handling.
198
+
199
+ ### The Wrapped Fetch Function
200
+
201
+ The returned function has the following signature:
202
+
203
+ ```typescript
204
+ (input: RequestInfo | URL, init?: RequestInit): Promise<Response>
205
+ ```
206
+
207
+ It behaves exactly like the native `fetch` API, but will automatically:
208
+ 1. Detect when AWS WAF requires a captcha challenge
209
+ 2. Display the captcha modal when needed
210
+ 3. Retry the original request after successful captcha completion
211
+ 4. Pass through all response data transparently
212
+
213
+ ## How It Works
214
+
215
+ 1. **Initialization**: The interceptor is created with your AWS WAF configuration
216
+ 2. **Request Interception**: When you make a fetch request, the interceptor checks if AWS WAF returns a captcha challenge
217
+ 3. **Modal Display**: If a captcha is required, a modal is automatically injected into your specified container
218
+ 4. **User Interaction**: Users solve the captcha puzzle in the modal
219
+ 5. **Request Retry**: After successful captcha completion, the original request is retried with the captcha token
220
+ 6. **Transparent Response**: You receive the API response as if no captcha interruption occurred
221
+
222
+ For more details check the WAF documentation: https://aws.amazon.com/ru/blogs/networking-and-content-delivery/optimizing-web-application-user-experiences-with-aws-waf-javascript-integrations/. Now realized only the Scenario 5.
223
+
224
+ ## Error Handling
225
+
226
+ The interceptor will throw errors in these cases:
227
+ - AWS WAF configuration is incorrect
228
+ - Captcha cannot be displayed (missing container, etc.)
229
+ - User fails to solve captcha within allowed attempts
230
+ - Network errors during the request
231
+
232
+ ## DOM Requirements
233
+
234
+ The package requires certain DOM elements to exist or will create them automatically:
235
+
236
+ ```html
237
+ <!-- The container you specify in config must exist -->
238
+ <div id="your-captcha-container-id">
239
+ <!-- The following elements will be created automatically if not present -->
240
+ <!-- <div id="captcha-overlay"> -->
241
+ <!-- <div id="captcha-modal"> -->
242
+ <!-- <div id="captcha-content"></div> -->
243
+ <!-- </div> -->
244
+ <!-- </div> -->
245
+ </div>
246
+ ```
247
+
248
+ ## TypeScript Support
249
+
250
+ The package includes full TypeScript definitions. No additional `@types` package is required.
251
+
252
+ ## Development
253
+
254
+ ```bash
255
+ # Clone the repository
256
+ git clone https://github.com/your-org/aws-waf-captcha-interceptor.git
257
+
258
+ # Install dependencies
259
+ npm install
260
+
261
+ # Build the project
262
+ npm run build
263
+
264
+ # Run tests
265
+ npm test
266
+ ```
267
+
268
+ ## Future Roadmap
269
+
270
+ - [ ] Axios interceptor support
271
+ - [ ] Additional WAF captcha scenarios
272
+ - [ ] Custom UI theming options
273
+
274
+ ## Security
275
+
276
+ This package handles sensitive operations. Ensure you:
277
+ - Keep your API keys secure
278
+ - Use HTTPS for all requests
279
+ - Follow AWS WAF security best practices
280
+
281
+ ---
282
+
283
+ **Note**: This package currently only supports fetch-based requests. Axios support is planned for future releases.
@@ -0,0 +1,2 @@
1
+ "use strict";const n=(n,e="captchaForm")=>{var t;let o=document.getElementById(e);const l=null!==(t=document.getElementById(n))&&void 0!==t?t:document.body;return o||(o=document.createElement("div"),o.id=e,l.appendChild(o)),o},e=(e,t,o,l)=>{const{overlay:a,modal:d}=((n,e="modalOverlay",t="modal")=>{var o;const l=null!==(o=document.getElementById(n))&&void 0!==o?o:document.body;let a=document.getElementById(e),d=document.getElementById(t);return a||(a=document.createElement("div"),a.id="modalOverlay",a.style.cssText="\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background: rgba(0,0,0,0.5);\n display: none;\n z-index: 9999;\n align-items: center;\n justify-content: center;\n ",l.appendChild(a)),d||(d=document.createElement("div"),d.id="modal",d.style.cssText="\n background: white;\n padding: 20px;\n border-radius: 8px;\n min-width: 300px;\n ",a.appendChild(d)),{overlay:a,modal:d}})(e,o,l),r=n(e,t);r.parentElement!==d&&d.appendChild(r),a.style.display="flex"},t="AwsWAFScript";exports.createCaptchaFetchHandler=o=>{!function(n){if(!n.API_KEY)throw new Error("API_KEY is not set");if(!n.JSAPI_URL)throw new Error("JSAPI_URL is not set");if(!n.captchaContainerId)throw new Error("the captcha container Id is not set")}(o),function(n){if(document.getElementById(t)||!n)return;const e=document.createElement("script");e.id=t,e.async=!1,e.src=n,document.head.appendChild(e)}(o.JSAPI_URL);return(t,l)=>{const a=n(o.captchaContainerId,null==o?void 0:o.captchaContentId);return e(o.captchaContainerId,null==o?void 0:o.captchaContentId,null==o?void 0:o.overlayId,null==o?void 0:o.modalId),new Promise((n,e)=>{window.AwsWafCaptcha?window.AwsWafIntegration?window.AwsWafCaptcha.renderCaptcha(a,{onSuccess:()=>{var e;((n="modalOverlay")=>{const e=document.getElementById(n);e&&(e.style.display="none")})(null==o?void 0:o.overlayId),null===(e=null==o?void 0:o.onSuccess)||void 0===e||e.call(o),n(window.AwsWafIntegration.fetch(t,l))},onLoad:()=>{var n;null===(n=null==o?void 0:o.onLoad)||void 0===n||n.call(o)},onError:n=>{var t;null===(t=null==o?void 0:o.onError)||void 0===t||t.call(o,n),e(n)},onPuzzleTimeout:()=>{var n;null===(n=null==o?void 0:o.onError)||void 0===n||n.call(o,"CAPTCHA timeout"),e(new Error("CAPTCHA timeout"))},onPuzzleIncorrect:()=>{var n;null===(n=null==o?void 0:o.onPuzzleIncorrect)||void 0===n||n.call(o)},onPuzzleCorrect:()=>{var n;null===(n=null==o?void 0:o.onPuzzleCorrect)||void 0===n||n.call(o)},apiKey:o.API_KEY}):e(new Error("AwsWafIntegration is not available")):e(new Error("AwsWafCaptcha is not available"))})}};
2
+ //# sourceMappingURL=bundle.cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bundle.cjs.js","sources":["../src/utils/modalUtils.ts","../src/utils/WAFScriptUtils.ts","../src/createCaptchaFetchHandler.ts"],"sourcesContent":[null,null,null],"names":["ensureCaptchaContainer","captchaContainerId","captchaContentId","container","document","getElementById","captchaContainer","_a","body","createElement","id","appendChild","showCaptchaModal","overlayId","modalId","overlay","modal","style","cssText","ensureModalContainer","captchaForm","parentElement","display","WAF_SCRIPT_ID","config","API_KEY","Error","JSAPI_URL","checkWAFconfig","AwsWafScript","async","src","head","loadCaptchaScript","path","init","Promise","resolve","reject","window","AwsWafCaptcha","AwsWafIntegration","renderCaptcha","onSuccess","hideCaptchaModal","fetch","onLoad","onError","error","call","onPuzzleTimeout","onPuzzleIncorrect","onPuzzleCorrect","apiKey"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ const n=(n,e="captchaForm")=>{var t;let o=document.getElementById(e);const l=null!==(t=document.getElementById(n))&&void 0!==t?t:document.body;return o||(o=document.createElement("div"),o.id=e,l.appendChild(o)),o},e=(e,t,o,l)=>{const{overlay:d,modal:a}=((n,e="modalOverlay",t="modal")=>{var o;const l=null!==(o=document.getElementById(n))&&void 0!==o?o:document.body;let d=document.getElementById(e),a=document.getElementById(t);return d||(d=document.createElement("div"),d.id="modalOverlay",d.style.cssText="\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background: rgba(0,0,0,0.5);\n display: none;\n z-index: 9999;\n align-items: center;\n justify-content: center;\n ",l.appendChild(d)),a||(a=document.createElement("div"),a.id="modal",a.style.cssText="\n background: white;\n padding: 20px;\n border-radius: 8px;\n min-width: 300px;\n ",d.appendChild(a)),{overlay:d,modal:a}})(e,o,l),r=n(e,t);r.parentElement!==a&&a.appendChild(r),d.style.display="flex"},t="AwsWAFScript";const o=o=>{!function(n){if(!n.API_KEY)throw new Error("API_KEY is not set");if(!n.JSAPI_URL)throw new Error("JSAPI_URL is not set");if(!n.captchaContainerId)throw new Error("the captcha container Id is not set")}(o),function(n){if(document.getElementById(t)||!n)return;const e=document.createElement("script");e.id=t,e.async=!1,e.src=n,document.head.appendChild(e)}(o.JSAPI_URL);return(t,l)=>{const d=n(o.captchaContainerId,null==o?void 0:o.captchaContentId);return e(o.captchaContainerId,null==o?void 0:o.captchaContentId,null==o?void 0:o.overlayId,null==o?void 0:o.modalId),new Promise((n,e)=>{window.AwsWafCaptcha?window.AwsWafIntegration?window.AwsWafCaptcha.renderCaptcha(d,{onSuccess:()=>{var e;((n="modalOverlay")=>{const e=document.getElementById(n);e&&(e.style.display="none")})(null==o?void 0:o.overlayId),null===(e=null==o?void 0:o.onSuccess)||void 0===e||e.call(o),n(window.AwsWafIntegration.fetch(t,l))},onLoad:()=>{var n;null===(n=null==o?void 0:o.onLoad)||void 0===n||n.call(o)},onError:n=>{var t;null===(t=null==o?void 0:o.onError)||void 0===t||t.call(o,n),e(n)},onPuzzleTimeout:()=>{var n;null===(n=null==o?void 0:o.onError)||void 0===n||n.call(o,"CAPTCHA timeout"),e(new Error("CAPTCHA timeout"))},onPuzzleIncorrect:()=>{var n;null===(n=null==o?void 0:o.onPuzzleIncorrect)||void 0===n||n.call(o)},onPuzzleCorrect:()=>{var n;null===(n=null==o?void 0:o.onPuzzleCorrect)||void 0===n||n.call(o)},apiKey:o.API_KEY}):e(new Error("AwsWafIntegration is not available")):e(new Error("AwsWafCaptcha is not available"))})}};export{o as createCaptchaFetchHandler};
2
+ //# sourceMappingURL=bundle.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bundle.esm.js","sources":["../src/utils/modalUtils.ts","../src/utils/WAFScriptUtils.ts","../src/createCaptchaFetchHandler.ts"],"sourcesContent":[null,null,null],"names":["ensureCaptchaContainer","captchaContainerId","captchaContentId","container","document","getElementById","captchaContainer","_a","body","createElement","id","appendChild","showCaptchaModal","overlayId","modalId","overlay","modal","style","cssText","ensureModalContainer","captchaForm","parentElement","display","WAF_SCRIPT_ID","createCaptchaFetchHandler","config","API_KEY","Error","JSAPI_URL","checkWAFconfig","AwsWafScript","async","src","head","loadCaptchaScript","path","init","Promise","resolve","reject","window","AwsWafCaptcha","AwsWafIntegration","renderCaptcha","onSuccess","hideCaptchaModal","fetch","onLoad","onError","error","call","onPuzzleTimeout","onPuzzleIncorrect","onPuzzleCorrect","apiKey"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import { AWSWAFInterceptorConfig } from "./types";
2
+ export declare const createCaptchaFetchHandler: (config: AWSWAFInterceptorConfig) => (path: RequestInfo | URL, init: RequestInit) => Promise<Response>;
@@ -0,0 +1,41 @@
1
+ interface AwsWafCaptchaConfig {
2
+ onSuccess: (wafToken: string) => void;
3
+ onLoad?: () => void;
4
+ onError?: (err: string) => void;
5
+ onPuzzleTimeout?: () => void;
6
+ onPuzzleIncorrect?: () => void;
7
+ onPuzzleCorrect?: () => void;
8
+ apiKey: string;
9
+ }
10
+ interface AwsWafCaptcha {
11
+ renderCaptcha: (container: string | HTMLElement, config: AwsWafCaptchaConfig) => void;
12
+ }
13
+ interface AwsWafIntegration {
14
+ fetch: typeof fetch;
15
+ hasToken: () => boolean;
16
+ getToken: () => Promise<string>;
17
+ }
18
+ declare global {
19
+ interface Window {
20
+ AwsWafIntegration: AwsWafIntegration;
21
+ AwsWafCaptcha: AwsWafCaptcha;
22
+ }
23
+ }
24
+ interface AWSWAFInterceptorConfig {
25
+ API_KEY: string;
26
+ JSAPI_URL: string;
27
+ onSuccess?: () => void;
28
+ onLoad?: () => void;
29
+ onError?: (err: string) => void;
30
+ onPuzzleTimeout?: () => void;
31
+ onPuzzleIncorrect?: () => void;
32
+ onPuzzleCorrect?: () => void;
33
+ captchaContainerId: string;
34
+ captchaContentId?: string;
35
+ overlayId?: string;
36
+ modalId?: string;
37
+ }
38
+
39
+ declare const createCaptchaFetchHandler: (config: AWSWAFInterceptorConfig) => (path: RequestInfo | URL, init: RequestInit) => Promise<Response>;
40
+
41
+ export { createCaptchaFetchHandler };
@@ -0,0 +1,44 @@
1
+ export interface AwsWafCaptchaConfig {
2
+ onSuccess: (wafToken: string) => void;
3
+ onLoad?: () => void;
4
+ onError?: (err: string) => void;
5
+ onPuzzleTimeout?: () => void;
6
+ onPuzzleIncorrect?: () => void;
7
+ onPuzzleCorrect?: () => void;
8
+ apiKey: string;
9
+ }
10
+ export interface AwsWafCaptcha {
11
+ renderCaptcha: (container: string | HTMLElement, config: AwsWafCaptchaConfig) => void;
12
+ }
13
+ export interface AwsWafIntegration {
14
+ fetch: typeof fetch;
15
+ hasToken: () => boolean;
16
+ getToken: () => Promise<string>;
17
+ }
18
+ declare global {
19
+ interface Window {
20
+ AwsWafIntegration: AwsWafIntegration;
21
+ AwsWafCaptcha: AwsWafCaptcha;
22
+ }
23
+ }
24
+ export interface CaptchaOptions {
25
+ apiKey: string;
26
+ captchaContentId: string;
27
+ onCaptchaRequired: () => void;
28
+ onSuccess: () => void;
29
+ onError: (error: string) => void;
30
+ }
31
+ export interface AWSWAFInterceptorConfig {
32
+ API_KEY: string;
33
+ JSAPI_URL: string;
34
+ onSuccess?: () => void;
35
+ onLoad?: () => void;
36
+ onError?: (err: string) => void;
37
+ onPuzzleTimeout?: () => void;
38
+ onPuzzleIncorrect?: () => void;
39
+ onPuzzleCorrect?: () => void;
40
+ captchaContainerId: string;
41
+ captchaContentId?: string;
42
+ overlayId?: string;
43
+ modalId?: string;
44
+ }
@@ -0,0 +1,4 @@
1
+ import { AWSWAFInterceptorConfig } from "../types";
2
+ export declare const WAF_SCRIPT_ID = "AwsWAFScript";
3
+ export declare function checkWAFconfig(config: AWSWAFInterceptorConfig): void;
4
+ export declare function loadCaptchaScript(JSAPI_URL: string): void;
@@ -0,0 +1,7 @@
1
+ export declare const ensureCaptchaContainer: (captchaContainerId: string, captchaContentId?: string) => HTMLElement;
2
+ export declare const ensureModalContainer: (captchaContainerId: string, overlayId?: string, modalId?: string) => {
3
+ overlay: HTMLElement;
4
+ modal: HTMLElement;
5
+ };
6
+ export declare const showCaptchaModal: (captchaContainerId: string, captchaContentId?: string, overlayId?: string, modalId?: string) => void;
7
+ export declare const hideCaptchaModal: (overlayId?: string) => void;
package/package.json ADDED
@@ -0,0 +1,29 @@
1
+ {
2
+ "name": "waf-captcha-frontend",
3
+ "version": "0.0.5",
4
+ "description": "is a lightweight JavaScript/TypeScript library that provides seamless integration with AWS WAF Captcha for fetch-based HTTP requests. The package handles captcha challenges transparently, intercepting requests and displaying captcha modals when required by AWS WAF.",
5
+ "main": "dist/bundle.cjs.js",
6
+ "module": "dist/bundle.esm.js",
7
+ "types": "dist/index.d.ts",
8
+ "files": [
9
+ "dist",
10
+ "README.md"
11
+ ],
12
+ "scripts": {
13
+ "test": "echo \"Error: no test specified\" && exit 1",
14
+ "build": "rollup -c",
15
+ "build:types": "tsc --emitDeclarationOnly"
16
+ },
17
+ "keywords": [],
18
+ "author": "",
19
+ "license": "ISC",
20
+ "type": "module",
21
+ "devDependencies": {
22
+ "@rollup/plugin-terser": "^0.4.4",
23
+ "@rollup/plugin-typescript": "^12.3.0",
24
+ "rollup": "^4.55.1",
25
+ "rollup-plugin-dts": "^6.3.0",
26
+ "tslib": "^2.8.1",
27
+ "typescript": "^5.9.3"
28
+ }
29
+ }