@proveanything/smartlinks 1.0.51 → 1.0.52

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/API_SUMMARY.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Smartlinks API Summary
2
2
 
3
- Version: 1.0.51 | Generated: 2025-11-23T12:27:09.228Z
3
+ Version: 1.0.52 | Generated: 2025-11-24T19:18:29.127Z
4
4
 
5
5
  This is a concise summary of all available API functions and types.
6
6
 
@@ -37,6 +37,7 @@ Core HTTP functions for API configuration and communication:
37
37
  proxyMode?: boolean
38
38
  ngrokSkipBrowserWarning?: boolean
39
39
  extraHeaders?: Record<string, string>
40
+ iframeAutoResize?: boolean // default true when in iframe
40
41
  }) → `void`
41
42
  Call this once (e.g. at app startup) to configure baseURL/auth.
42
43
 
package/README.md CHANGED
@@ -141,6 +141,58 @@ const collections = await collection.list(false)
141
141
 
142
142
  For a fuller UI example, see `examples/react-demo.tsx`.
143
143
 
144
+ ## Iframe Integration
145
+
146
+ When embedding Smartlinks inside an iframe (set `proxyMode: true` in `initializeApi` if you need parent-proxy API calls), you can also send UI/control messages to the parent window. The SDK provides lightweight helpers in `iframe.ts`:
147
+
148
+ ```ts
149
+ import { enableAutoIframeResize, disableAutoIframeResize, redirectParent, sendParentCustom, isIframe } from '@proveanything/smartlinks'
150
+
151
+ // Automatically push height changes to parent so it can resize the iframe.
152
+ enableAutoIframeResize({ intervalMs: 150 })
153
+
154
+ // Later disable if not needed:
155
+ disableAutoIframeResize()
156
+
157
+ // Redirect parent window to a URL (e.g. after login):
158
+ redirectParent('https://app.example.com/dashboard')
159
+
160
+ // Send any custom event + payload:
161
+ sendParentCustom('smartlinks:navigate', { url: '/profile' })
162
+
163
+ if (isIframe()) {
164
+ console.log('Running inside an iframe')
165
+ }
166
+ ```
167
+
168
+ Parent page can listen for these messages:
169
+
170
+ ```ts
171
+ window.addEventListener('message', (e) => {
172
+ const msg = e.data
173
+ if (!msg || !msg._smartlinksIframeMessage) return
174
+ switch (msg.type) {
175
+ case 'smartlinks:resize':
176
+ // adjust iframe height
177
+ const iframeEl = document.getElementById('smartlinks-frame') as HTMLIFrameElement
178
+ if (iframeEl) iframeEl.style.height = msg.payload.height + 'px'
179
+ break
180
+ case 'smartlinks:redirect':
181
+ window.location.href = msg.payload.url
182
+ break
183
+ case 'smartlinks:navigate':
184
+ // Custom example
185
+ console.log('Navigate request:', msg.payload.url)
186
+ break
187
+ }
188
+ })
189
+ ```
190
+
191
+ Notes:
192
+ - Auto-resize uses `ResizeObserver` when available, falling back to `MutationObserver` + polling.
193
+ - In non-browser or Node environments these helpers safely no-op.
194
+ - Use `sendParentCustom` for any domain-specific integration events.
195
+
144
196
  ## Configuration reference
145
197
 
146
198
  ```ts
@@ -151,10 +203,12 @@ initializeApi({
151
203
  proxyMode?: boolean // set true if running inside an iframe and using parent proxy
152
204
  ngrokSkipBrowserWarning?: boolean // forces header 'ngrok-skip-browser-warning: true'
153
205
  extraHeaders?: Record<string,string> // custom headers merged in each request
206
+ iframeAutoResize?: boolean // default true when embedded in an iframe
154
207
  })
155
208
 
156
209
  // Auto-detection: If baseURL contains '.ngrok.io' or '.ngrok-free.dev' the header is added automatically
157
210
  // unless you explicitly set ngrokSkipBrowserWarning: false.
211
+ // Auto iframe resize: When in an iframe, resize messages are sent by default unless iframeAutoResize: false.
158
212
  ```
159
213
 
160
214
  When embedding the SDK in an iframe with `proxyMode: true`, you can also use:
package/dist/http.d.ts CHANGED
@@ -1,12 +1,3 @@
1
- /**
2
- * Call this once (e.g. at app startup) to configure baseURL/auth.
3
- *
4
- * @param options - Configuration options
5
- * @property {string} options.baseURL - The root URL of the Smartlinks API (e.g. "https://smartlinks.app/api/v1")
6
- * @property {string} [options.apiKey] - (Optional) API key for X-API-Key header
7
- * @property {string} [options.bearerToken] - (Optional) Bearer token for AUTHORIZATION header
8
- * @property {boolean} [options.proxyMode] - (Optional) Tells the API that it is running in an iframe via parent proxy
9
- */
10
1
  export declare function initializeApi(options: {
11
2
  baseURL: string;
12
3
  apiKey?: string;
@@ -14,6 +5,7 @@ export declare function initializeApi(options: {
14
5
  proxyMode?: boolean;
15
6
  ngrokSkipBrowserWarning?: boolean;
16
7
  extraHeaders?: Record<string, string>;
8
+ iframeAutoResize?: boolean;
17
9
  }): void;
18
10
  /** Enable/disable automatic "ngrok-skip-browser-warning" header. */
19
11
  export declare function setNgrokSkipBrowserWarning(flag: boolean): void;
package/dist/http.js CHANGED
@@ -17,6 +17,7 @@ let extraHeadersGlobal = {};
17
17
  * @property {string} [options.bearerToken] - (Optional) Bearer token for AUTHORIZATION header
18
18
  * @property {boolean} [options.proxyMode] - (Optional) Tells the API that it is running in an iframe via parent proxy
19
19
  */
20
+ import { enableAutoIframeResize, isIframe } from './iframe';
20
21
  export function initializeApi(options) {
21
22
  // Normalize baseURL by removing trailing slashes.
22
23
  baseURL = options.baseURL.replace(/\/+$/g, "");
@@ -30,6 +31,10 @@ export function initializeApi(options) {
30
31
  ? !!options.ngrokSkipBrowserWarning
31
32
  : inferredNgrok;
32
33
  extraHeadersGlobal = options.extraHeaders ? Object.assign({}, options.extraHeaders) : {};
34
+ // Auto-enable iframe resize unless explicitly disabled
35
+ if (isIframe() && options.iframeAutoResize !== false) {
36
+ enableAutoIframeResize();
37
+ }
33
38
  }
34
39
  /** Enable/disable automatic "ngrok-skip-browser-warning" header. */
35
40
  export function setNgrokSkipBrowserWarning(flag) {
@@ -0,0 +1,25 @@
1
+ interface IframeResizeOptions {
2
+ /** Minimum ms between height postMessages (default 100). */
3
+ intervalMs?: number;
4
+ /** Post even if height unchanged (default false). */
5
+ alwaysSend?: boolean;
6
+ /** Additional payload properties to include with each resize message. */
7
+ extra?: Record<string, any>;
8
+ /** Custom message type name (default 'smartlinks:resize'). */
9
+ messageType?: string;
10
+ }
11
+ /** Redirect parent window to a URL (if in iframe). */
12
+ export declare function redirectParent(url: string): void;
13
+ /** Request parent to adjust iframe height to current content height. */
14
+ export declare function sendHeight(height?: number, extra?: Record<string, any>): void;
15
+ /** Enable automatic height reporting to parent iframe. */
16
+ export declare function enableAutoIframeResize(options?: IframeResizeOptions): void;
17
+ /** Disable automatic height reporting. */
18
+ export declare function disableAutoIframeResize(): void;
19
+ /** Send a custom message to parent (browser-only). */
20
+ export declare function sendParentCustom(type: string, payload: Record<string, any>): void;
21
+ /** Returns true if running inside an iframe (browser). */
22
+ export declare function isIframe(): boolean;
23
+ /** Returns true if ResizeObserver is supported in current environment. */
24
+ export declare function supportsResizeObserver(): boolean;
25
+ export {};
package/dist/iframe.js ADDED
@@ -0,0 +1,123 @@
1
+ // iframe.ts
2
+ // Utilities to communicate with parent window when running inside an iframe.
3
+ // These helpers are optional and safe in non-browser / Node environments.
4
+ // They build on the existing proxyMode infrastructure but can also be used standalone.
5
+ let autoResizeTimer;
6
+ let lastHeight = 0;
7
+ let resizeOptions;
8
+ let resizeObserver;
9
+ let mutationObserver;
10
+ function isBrowser() {
11
+ return typeof window !== 'undefined' && typeof document !== 'undefined';
12
+ }
13
+ function inIframe() {
14
+ return isBrowser() && window.parent && window.parent !== window;
15
+ }
16
+ function postParentMessage(type, payload) {
17
+ if (!inIframe())
18
+ return;
19
+ try {
20
+ window.parent.postMessage({ _smartlinksIframeMessage: true, type, payload }, '*');
21
+ }
22
+ catch (_a) {
23
+ // swallow errors silently
24
+ }
25
+ }
26
+ /** Redirect parent window to a URL (if in iframe). */
27
+ export function redirectParent(url) {
28
+ postParentMessage('smartlinks:redirect', { url });
29
+ }
30
+ /** Request parent to adjust iframe height to current content height. */
31
+ export function sendHeight(height, extra) {
32
+ if (!inIframe())
33
+ return;
34
+ const h = height !== null && height !== void 0 ? height : document.documentElement.scrollHeight;
35
+ postParentMessage((resizeOptions === null || resizeOptions === void 0 ? void 0 : resizeOptions.messageType) || 'smartlinks:resize', Object.assign(Object.assign({ height: h }, resizeOptions === null || resizeOptions === void 0 ? void 0 : resizeOptions.extra), extra));
36
+ }
37
+ function measureHeight() {
38
+ if (!isBrowser())
39
+ return 0;
40
+ const doc = document.documentElement;
41
+ // Use max of several properties for robustness
42
+ return Math.max(doc.scrollHeight, doc.offsetHeight, doc.clientHeight, document.body ? document.body.scrollHeight : 0, document.body ? document.body.offsetHeight : 0);
43
+ }
44
+ function scheduleManualPolling() {
45
+ var _a;
46
+ if (!isBrowser())
47
+ return;
48
+ clearInterval(autoResizeTimer);
49
+ const interval = (_a = resizeOptions === null || resizeOptions === void 0 ? void 0 : resizeOptions.intervalMs) !== null && _a !== void 0 ? _a : 100;
50
+ autoResizeTimer = window.setInterval(() => {
51
+ const h = measureHeight();
52
+ if ((resizeOptions === null || resizeOptions === void 0 ? void 0 : resizeOptions.alwaysSend) || h !== lastHeight) {
53
+ lastHeight = h;
54
+ sendHeight(h);
55
+ }
56
+ }, interval);
57
+ }
58
+ function setupObservers() {
59
+ if (!isBrowser())
60
+ return;
61
+ // Prefer ResizeObserver for layout changes
62
+ if (typeof ResizeObserver !== 'undefined') {
63
+ resizeObserver = new ResizeObserver(() => {
64
+ const h = measureHeight();
65
+ if ((resizeOptions === null || resizeOptions === void 0 ? void 0 : resizeOptions.alwaysSend) || h !== lastHeight) {
66
+ lastHeight = h;
67
+ sendHeight(h);
68
+ }
69
+ });
70
+ resizeObserver.observe(document.body);
71
+ }
72
+ else {
73
+ // Fallback: MutationObserver for DOM changes
74
+ mutationObserver = new MutationObserver(() => {
75
+ const h = measureHeight();
76
+ if ((resizeOptions === null || resizeOptions === void 0 ? void 0 : resizeOptions.alwaysSend) || h !== lastHeight) {
77
+ lastHeight = h;
78
+ sendHeight(h);
79
+ }
80
+ });
81
+ mutationObserver.observe(document.body, { childList: true, subtree: true, attributes: true });
82
+ // Manual polling as additional safeguard
83
+ scheduleManualPolling();
84
+ }
85
+ }
86
+ /** Enable automatic height reporting to parent iframe. */
87
+ export function enableAutoIframeResize(options) {
88
+ if (!inIframe())
89
+ return;
90
+ resizeOptions = options || {};
91
+ lastHeight = measureHeight();
92
+ sendHeight(lastHeight);
93
+ setupObservers();
94
+ if (!resizeObserver) {
95
+ // If no ResizeObserver, MutationObserver is active and we also poll
96
+ scheduleManualPolling();
97
+ }
98
+ }
99
+ /** Disable automatic height reporting. */
100
+ export function disableAutoIframeResize() {
101
+ if (resizeObserver)
102
+ resizeObserver.disconnect();
103
+ if (mutationObserver)
104
+ mutationObserver.disconnect();
105
+ if (isBrowser())
106
+ clearInterval(autoResizeTimer);
107
+ resizeObserver = undefined;
108
+ mutationObserver = undefined;
109
+ autoResizeTimer = undefined;
110
+ resizeOptions = undefined;
111
+ }
112
+ /** Send a custom message to parent (browser-only). */
113
+ export function sendParentCustom(type, payload) {
114
+ postParentMessage(type, payload);
115
+ }
116
+ /** Returns true if running inside an iframe (browser). */
117
+ export function isIframe() {
118
+ return inIframe();
119
+ }
120
+ /** Returns true if ResizeObserver is supported in current environment. */
121
+ export function supportsResizeObserver() {
122
+ return typeof ResizeObserver !== 'undefined';
123
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@proveanything/smartlinks",
3
- "version": "1.0.51",
3
+ "version": "1.0.52",
4
4
  "description": "Official JavaScript/TypeScript SDK for the Smartlinks API",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",