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 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)
@@ -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
+ }