iframe-finder 1.0.0
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/LICENSE +21 -0
- package/README.md +223 -0
- package/dist/index.d.ts +87 -0
- package/dist/index.js +128 -0
- package/package.json +35 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Artem Deikun
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
# iframe-finder
|
|
2
|
+
|
|
3
|
+
A lightweight TypeScript library for recursively finding nested iframes in the DOM tree.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- 🔍 **Recursive Search** - Find iframes at any nesting depth
|
|
8
|
+
- 🎯 **Multiple Search Methods** - By id, name, or custom criteria
|
|
9
|
+
- 🛡️ **Safe** - Handles cross-origin iframes gracefully
|
|
10
|
+
- 📦 **Lightweight** - Zero dependencies, ~1KB gzipped
|
|
11
|
+
- 💪 **TypeScript** - Full type safety and IntelliSense support
|
|
12
|
+
- ⚡ **Fast** - Optimized search with depth limiting
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install iframe-finder
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Usage
|
|
21
|
+
|
|
22
|
+
### Find by ID
|
|
23
|
+
|
|
24
|
+
```typescript
|
|
25
|
+
import { findIframeById } from 'iframe-finder';
|
|
26
|
+
|
|
27
|
+
// Find iframe with id="myFrame" anywhere in the DOM tree
|
|
28
|
+
const iframe = findIframeById('myFrame');
|
|
29
|
+
|
|
30
|
+
if (iframe) {
|
|
31
|
+
console.log('Found iframe:', iframe);
|
|
32
|
+
// Access iframe content
|
|
33
|
+
const content = iframe.contentDocument;
|
|
34
|
+
}
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Find by Name
|
|
38
|
+
|
|
39
|
+
```typescript
|
|
40
|
+
import { findIframeByName } from 'iframe-finder';
|
|
41
|
+
|
|
42
|
+
const iframe = findIframeByName('contentFrame');
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Custom Search Criteria
|
|
46
|
+
|
|
47
|
+
```typescript
|
|
48
|
+
import { findIframe } from 'iframe-finder';
|
|
49
|
+
|
|
50
|
+
// Find iframe by src
|
|
51
|
+
const iframe = findIframe((frame) =>
|
|
52
|
+
frame.src.includes('example.com')
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
// Find iframe by class
|
|
56
|
+
const iframe = findIframe((frame) =>
|
|
57
|
+
frame.classList.contains('special-frame')
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
// Find iframe by data attribute
|
|
61
|
+
const iframe = findIframe((frame) =>
|
|
62
|
+
frame.dataset.type === 'content'
|
|
63
|
+
);
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Advanced Options
|
|
67
|
+
|
|
68
|
+
```typescript
|
|
69
|
+
import { findIframeById } from 'iframe-finder';
|
|
70
|
+
|
|
71
|
+
// Limit search depth
|
|
72
|
+
const iframe = findIframeById('myFrame', {
|
|
73
|
+
maxDepth: 3 // Only search 3 levels deep
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
// Start from specific document
|
|
77
|
+
const iframe = findIframeById('myFrame', {
|
|
78
|
+
rootDocument: someIframe.contentDocument
|
|
79
|
+
});
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Find All Matching Iframes
|
|
83
|
+
|
|
84
|
+
```typescript
|
|
85
|
+
import { findAllIframes } from 'iframe-finder';
|
|
86
|
+
|
|
87
|
+
// Find all iframes with specific class
|
|
88
|
+
const iframes = findAllIframes((frame) =>
|
|
89
|
+
frame.classList.contains('content')
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
console.log(`Found ${iframes.length} iframes`);
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## API Reference
|
|
96
|
+
|
|
97
|
+
### `findIframeById(id: string, options?: FindIframeOptions): HTMLIFrameElement | null`
|
|
98
|
+
|
|
99
|
+
Recursively searches for an iframe by its `id` attribute.
|
|
100
|
+
|
|
101
|
+
**Parameters:**
|
|
102
|
+
- `id` - The id attribute to search for
|
|
103
|
+
- `options` - Optional search options
|
|
104
|
+
|
|
105
|
+
**Returns:** The found iframe element or `null`
|
|
106
|
+
|
|
107
|
+
### `findIframeByName(name: string, options?: FindIframeOptions): HTMLIFrameElement | null`
|
|
108
|
+
|
|
109
|
+
Recursively searches for an iframe by its `name` attribute.
|
|
110
|
+
|
|
111
|
+
**Parameters:**
|
|
112
|
+
- `name` - The name attribute to search for
|
|
113
|
+
- `options` - Optional search options
|
|
114
|
+
|
|
115
|
+
**Returns:** The found iframe element or `null`
|
|
116
|
+
|
|
117
|
+
### `findIframe(predicate: IframePredicate, options?: FindIframeOptions): HTMLIFrameElement | null`
|
|
118
|
+
|
|
119
|
+
Recursively searches for an iframe using a custom predicate function.
|
|
120
|
+
|
|
121
|
+
**Parameters:**
|
|
122
|
+
- `predicate` - Function that returns `true` when iframe matches criteria
|
|
123
|
+
- `options` - Optional search options
|
|
124
|
+
|
|
125
|
+
**Returns:** The found iframe element or `null`
|
|
126
|
+
|
|
127
|
+
### `findAllIframes(predicate: IframePredicate, rootDocument?: Document): HTMLIFrameElement[]`
|
|
128
|
+
|
|
129
|
+
Finds all iframes matching the predicate (single level, non-recursive).
|
|
130
|
+
|
|
131
|
+
**Parameters:**
|
|
132
|
+
- `predicate` - Function to test each iframe
|
|
133
|
+
- `rootDocument` - Starting document (defaults to `window.document`)
|
|
134
|
+
|
|
135
|
+
**Returns:** Array of matching iframes
|
|
136
|
+
|
|
137
|
+
### `FindIframeOptions`
|
|
138
|
+
|
|
139
|
+
```typescript
|
|
140
|
+
interface FindIframeOptions {
|
|
141
|
+
rootDocument?: Document; // Starting document (default: window.document)
|
|
142
|
+
maxDepth?: number; // Maximum search depth (default: Infinity)
|
|
143
|
+
}
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### `IframePredicate`
|
|
147
|
+
|
|
148
|
+
```typescript
|
|
149
|
+
type IframePredicate = (iframe: HTMLIFrameElement) => boolean;
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
## Real-World Examples
|
|
153
|
+
|
|
154
|
+
### Finding Nested Game Frames
|
|
155
|
+
|
|
156
|
+
```typescript
|
|
157
|
+
import { findIframeById } from 'iframe-finder';
|
|
158
|
+
|
|
159
|
+
// Game UI often has deeply nested iframes
|
|
160
|
+
const showInfoFrame = findIframeById('showInfo');
|
|
161
|
+
if (showInfoFrame?.contentDocument) {
|
|
162
|
+
const healthElement = showInfoFrame.contentDocument
|
|
163
|
+
.querySelector('[title="Character Info"]');
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
### Finding Ad Frames
|
|
168
|
+
|
|
169
|
+
```typescript
|
|
170
|
+
import { findIframe } from 'iframe-finder';
|
|
171
|
+
|
|
172
|
+
// Find advertisement iframe
|
|
173
|
+
const adFrame = findIframe((frame) =>
|
|
174
|
+
frame.src.includes('doubleclick.net') ||
|
|
175
|
+
frame.classList.contains('ad-frame')
|
|
176
|
+
);
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### Finding Communication Frames
|
|
180
|
+
|
|
181
|
+
```typescript
|
|
182
|
+
import { findIframeByName } from 'iframe-finder';
|
|
183
|
+
|
|
184
|
+
// Find chat or messaging iframe
|
|
185
|
+
const chatFrame = findIframeByName('chat-widget');
|
|
186
|
+
if (chatFrame) {
|
|
187
|
+
// Setup postMessage communication
|
|
188
|
+
chatFrame.contentWindow?.postMessage({ type: 'init' }, '*');
|
|
189
|
+
}
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
## Browser Support
|
|
193
|
+
|
|
194
|
+
Works in all modern browsers that support:
|
|
195
|
+
- `querySelector` / `querySelectorAll`
|
|
196
|
+
- `HTMLIFrameElement.contentDocument`
|
|
197
|
+
- `Array.from`
|
|
198
|
+
|
|
199
|
+
This includes:
|
|
200
|
+
- Chrome/Edge 45+
|
|
201
|
+
- Firefox 40+
|
|
202
|
+
- Safari 10+
|
|
203
|
+
- Opera 32+
|
|
204
|
+
|
|
205
|
+
## Security Notes
|
|
206
|
+
|
|
207
|
+
- Cross-origin iframes are automatically skipped due to browser security restrictions
|
|
208
|
+
- The library catches and silently handles cross-origin access errors
|
|
209
|
+
- Always validate and sanitize any data retrieved from iframe content
|
|
210
|
+
|
|
211
|
+
## License
|
|
212
|
+
|
|
213
|
+
MIT © Artem Deikun
|
|
214
|
+
|
|
215
|
+
## Contributing
|
|
216
|
+
|
|
217
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
218
|
+
|
|
219
|
+
## Links
|
|
220
|
+
|
|
221
|
+
- [GitHub Repository](https://github.com/artemhp/iframe-finder)
|
|
222
|
+
- [npm Package](https://www.npmjs.com/package/iframe-finder)
|
|
223
|
+
- [Report Issues](https://github.com/artemhp/iframe-finder/issues)
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Options for finding iframes
|
|
3
|
+
*/
|
|
4
|
+
export interface FindIframeOptions {
|
|
5
|
+
/**
|
|
6
|
+
* Starting document to search from (defaults to window.document)
|
|
7
|
+
*/
|
|
8
|
+
rootDocument?: Document;
|
|
9
|
+
/**
|
|
10
|
+
* Maximum depth to search (defaults to unlimited)
|
|
11
|
+
*/
|
|
12
|
+
maxDepth?: number;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Predicate function for custom iframe matching
|
|
16
|
+
*/
|
|
17
|
+
export type IframePredicate = (iframe: HTMLIFrameElement) => boolean;
|
|
18
|
+
/**
|
|
19
|
+
* Recursively searches for an iframe by its id attribute
|
|
20
|
+
*
|
|
21
|
+
* @param id - The id attribute to search for
|
|
22
|
+
* @param options - Search options
|
|
23
|
+
* @returns The found iframe element or null if not found
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```typescript
|
|
27
|
+
* const iframe = findIframeById('myFrame');
|
|
28
|
+
* if (iframe) {
|
|
29
|
+
* console.log('Found iframe:', iframe);
|
|
30
|
+
* }
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
export declare function findIframeById(id: string, options?: FindIframeOptions): HTMLIFrameElement | null;
|
|
34
|
+
/**
|
|
35
|
+
* Recursively searches for an iframe by its name attribute
|
|
36
|
+
*
|
|
37
|
+
* @param name - The name attribute to search for
|
|
38
|
+
* @param options - Search options
|
|
39
|
+
* @returns The found iframe element or null if not found
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* ```typescript
|
|
43
|
+
* const iframe = findIframeByName('contentFrame');
|
|
44
|
+
* if (iframe) {
|
|
45
|
+
* console.log('Found iframe:', iframe);
|
|
46
|
+
* }
|
|
47
|
+
* ```
|
|
48
|
+
*/
|
|
49
|
+
export declare function findIframeByName(name: string, options?: FindIframeOptions): HTMLIFrameElement | null;
|
|
50
|
+
/**
|
|
51
|
+
* Recursively searches for an iframe using a custom predicate function
|
|
52
|
+
*
|
|
53
|
+
* @param predicate - Function that returns true when iframe matches criteria
|
|
54
|
+
* @param options - Search options
|
|
55
|
+
* @returns The found iframe element or null if not found
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* ```typescript
|
|
59
|
+
* // Find iframe with specific src
|
|
60
|
+
* const iframe = findIframe((frame) => frame.src.includes('example.com'));
|
|
61
|
+
*
|
|
62
|
+
* // Find iframe with specific class
|
|
63
|
+
* const iframe = findIframe((frame) => frame.classList.contains('special'));
|
|
64
|
+
* ```
|
|
65
|
+
*/
|
|
66
|
+
export declare function findIframe(predicate: IframePredicate, options?: FindIframeOptions): HTMLIFrameElement | null;
|
|
67
|
+
/**
|
|
68
|
+
* Finds all iframes matching the predicate (non-recursive, single level)
|
|
69
|
+
*
|
|
70
|
+
* @param predicate - Function to test each iframe
|
|
71
|
+
* @param rootDocument - Starting document (defaults to window.document)
|
|
72
|
+
* @returns Array of matching iframes
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* ```typescript
|
|
76
|
+
* // Find all iframes with specific class
|
|
77
|
+
* const iframes = findAllIframes((frame) => frame.classList.contains('content'));
|
|
78
|
+
* ```
|
|
79
|
+
*/
|
|
80
|
+
export declare function findAllIframes(predicate: IframePredicate, rootDocument?: Document): HTMLIFrameElement[];
|
|
81
|
+
declare const _default: {
|
|
82
|
+
findIframeById: typeof findIframeById;
|
|
83
|
+
findIframeByName: typeof findIframeByName;
|
|
84
|
+
findIframe: typeof findIframe;
|
|
85
|
+
findAllIframes: typeof findAllIframes;
|
|
86
|
+
};
|
|
87
|
+
export default _default;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.findIframeById = findIframeById;
|
|
4
|
+
exports.findIframeByName = findIframeByName;
|
|
5
|
+
exports.findIframe = findIframe;
|
|
6
|
+
exports.findAllIframes = findAllIframes;
|
|
7
|
+
/**
|
|
8
|
+
* Recursively searches for an iframe by its id attribute
|
|
9
|
+
*
|
|
10
|
+
* @param id - The id attribute to search for
|
|
11
|
+
* @param options - Search options
|
|
12
|
+
* @returns The found iframe element or null if not found
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```typescript
|
|
16
|
+
* const iframe = findIframeById('myFrame');
|
|
17
|
+
* if (iframe) {
|
|
18
|
+
* console.log('Found iframe:', iframe);
|
|
19
|
+
* }
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
function findIframeById(id, options = {}) {
|
|
23
|
+
const { rootDocument = document, maxDepth = Infinity } = options;
|
|
24
|
+
return findIframeRecursive((iframe) => iframe.id === id, rootDocument, 0, maxDepth);
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Recursively searches for an iframe by its name attribute
|
|
28
|
+
*
|
|
29
|
+
* @param name - The name attribute to search for
|
|
30
|
+
* @param options - Search options
|
|
31
|
+
* @returns The found iframe element or null if not found
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```typescript
|
|
35
|
+
* const iframe = findIframeByName('contentFrame');
|
|
36
|
+
* if (iframe) {
|
|
37
|
+
* console.log('Found iframe:', iframe);
|
|
38
|
+
* }
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
function findIframeByName(name, options = {}) {
|
|
42
|
+
const { rootDocument = document, maxDepth = Infinity } = options;
|
|
43
|
+
return findIframeRecursive((iframe) => iframe.name === name, rootDocument, 0, maxDepth);
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Recursively searches for an iframe using a custom predicate function
|
|
47
|
+
*
|
|
48
|
+
* @param predicate - Function that returns true when iframe matches criteria
|
|
49
|
+
* @param options - Search options
|
|
50
|
+
* @returns The found iframe element or null if not found
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* ```typescript
|
|
54
|
+
* // Find iframe with specific src
|
|
55
|
+
* const iframe = findIframe((frame) => frame.src.includes('example.com'));
|
|
56
|
+
*
|
|
57
|
+
* // Find iframe with specific class
|
|
58
|
+
* const iframe = findIframe((frame) => frame.classList.contains('special'));
|
|
59
|
+
* ```
|
|
60
|
+
*/
|
|
61
|
+
function findIframe(predicate, options = {}) {
|
|
62
|
+
const { rootDocument = document, maxDepth = Infinity } = options;
|
|
63
|
+
return findIframeRecursive(predicate, rootDocument, 0, maxDepth);
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Internal recursive function to search for iframes
|
|
67
|
+
*
|
|
68
|
+
* @param predicate - Function to test each iframe
|
|
69
|
+
* @param doc - Current document to search
|
|
70
|
+
* @param currentDepth - Current recursion depth
|
|
71
|
+
* @param maxDepth - Maximum allowed depth
|
|
72
|
+
* @returns Found iframe or null
|
|
73
|
+
*/
|
|
74
|
+
function findIframeRecursive(predicate, doc, currentDepth, maxDepth) {
|
|
75
|
+
// Check depth limit
|
|
76
|
+
if (currentDepth > maxDepth) {
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
// Get all iframes in current document
|
|
80
|
+
const iframes = doc.querySelectorAll('iframe');
|
|
81
|
+
// First pass: check current level
|
|
82
|
+
for (const iframe of Array.from(iframes)) {
|
|
83
|
+
if (predicate(iframe)) {
|
|
84
|
+
return iframe;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
// Second pass: recurse into nested iframes
|
|
88
|
+
for (const iframe of Array.from(iframes)) {
|
|
89
|
+
try {
|
|
90
|
+
const contentDoc = iframe.contentDocument;
|
|
91
|
+
if (!contentDoc)
|
|
92
|
+
continue;
|
|
93
|
+
const foundInNested = findIframeRecursive(predicate, contentDoc, currentDepth + 1, maxDepth);
|
|
94
|
+
if (foundInNested) {
|
|
95
|
+
return foundInNested;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
catch (error) {
|
|
99
|
+
// Skip iframes we can't access (cross-origin security)
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Finds all iframes matching the predicate (non-recursive, single level)
|
|
107
|
+
*
|
|
108
|
+
* @param predicate - Function to test each iframe
|
|
109
|
+
* @param rootDocument - Starting document (defaults to window.document)
|
|
110
|
+
* @returns Array of matching iframes
|
|
111
|
+
*
|
|
112
|
+
* @example
|
|
113
|
+
* ```typescript
|
|
114
|
+
* // Find all iframes with specific class
|
|
115
|
+
* const iframes = findAllIframes((frame) => frame.classList.contains('content'));
|
|
116
|
+
* ```
|
|
117
|
+
*/
|
|
118
|
+
function findAllIframes(predicate, rootDocument = document) {
|
|
119
|
+
const iframes = rootDocument.querySelectorAll('iframe');
|
|
120
|
+
return Array.from(iframes).filter(predicate);
|
|
121
|
+
}
|
|
122
|
+
// Export default object with all functions
|
|
123
|
+
exports.default = {
|
|
124
|
+
findIframeById,
|
|
125
|
+
findIframeByName,
|
|
126
|
+
findIframe,
|
|
127
|
+
findAllIframes,
|
|
128
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "iframe-finder",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Recursively find nested iframes by id, name, or custom criteria in the DOM tree",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"build": "tsc",
|
|
9
|
+
"prepublishOnly": "npm run build",
|
|
10
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
11
|
+
},
|
|
12
|
+
"keywords": [
|
|
13
|
+
"iframe",
|
|
14
|
+
"nested",
|
|
15
|
+
"recursive",
|
|
16
|
+
"dom",
|
|
17
|
+
"find",
|
|
18
|
+
"search",
|
|
19
|
+
"traverse"
|
|
20
|
+
],
|
|
21
|
+
"author": "Artem Deikun",
|
|
22
|
+
"license": "MIT",
|
|
23
|
+
"repository": {
|
|
24
|
+
"type": "git",
|
|
25
|
+
"url": "https://github.com/artemhp/iframe-finder.git"
|
|
26
|
+
},
|
|
27
|
+
"files": [
|
|
28
|
+
"dist",
|
|
29
|
+
"README.md",
|
|
30
|
+
"LICENSE"
|
|
31
|
+
],
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"typescript": "^5.0.0"
|
|
34
|
+
}
|
|
35
|
+
}
|