forgeframe 0.0.1 → 0.0.3

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
@@ -55,6 +55,7 @@ Imagine a payment company (like Stripe) wants to let merchants embed a checkout
55
55
  ## Table of Contents
56
56
 
57
57
  - [Installation](#installation)
58
+ - [Start Here (Most Users)](#start-here-most-users)
58
59
  - [Quick Start](#quick-start)
59
60
  - [Step-by-Step Guide](#step-by-step-guide)
60
61
  - [1. Define a Component](#1-define-a-component)
@@ -63,8 +64,8 @@ Imagine a payment company (like Stripe) wants to let merchants embed a checkout
63
64
  - [4. Handle Events](#4-handle-events)
64
65
  - [Props System](#props-system)
65
66
  - [Host Window API (hostProps)](#host-window-api-hostprops)
66
- - [Templates](#templates)
67
- - [React Integration](#react-integration)
67
+ - [Templates (Advanced)](#templates-advanced)
68
+ - [React Integration (Optional)](#react-integration-optional)
68
69
  - [Advanced Features](#advanced-features)
69
70
  - [API Reference](#api-reference)
70
71
  - [TypeScript](#typescript)
@@ -80,6 +81,17 @@ npm install forgeframe
80
81
 
81
82
  ---
82
83
 
84
+ ## Start Here (Most Users)
85
+
86
+ Use this path for typical integrations:
87
+
88
+ 1. Follow [Quick Start](#quick-start) to get a working component.
89
+ 2. Use [Step-by-Step Guide](#step-by-step-guide) to add typed props and callbacks.
90
+ 3. Use [Props System](#props-system) and [Host Window API (hostProps)](#host-window-api-hostprops) as your primary references.
91
+ 4. Treat sections marked **Advanced** as optional unless you specifically need them.
92
+
93
+ ---
94
+
83
95
  ## Quick Start
84
96
 
85
97
  > **`Consumer`**
@@ -108,7 +120,7 @@ await payment.render('#payment-container');
108
120
  > **`Host`**
109
121
 
110
122
  ```typescript
111
- import { type HostProps } from 'forgeframe';
123
+ import ForgeFrame, { type HostProps } from 'forgeframe';
112
124
 
113
125
  interface PaymentProps {
114
126
  amount: number;
@@ -121,6 +133,10 @@ declare global {
121
133
  }
122
134
  }
123
135
 
136
+ // Required when the host page doesn't use ForgeFrame.create().
137
+ // If your host defines a component via create(), init is handled automatically.
138
+ ForgeFrame.initHost();
139
+
124
140
  const { amount, onSuccess, close } = window.hostProps;
125
141
 
126
142
  document.getElementById('total')!.textContent = `$${amount}`;
@@ -180,7 +196,7 @@ const LoginForm = ForgeFrame.create<LoginProps>({
180
196
  The host page runs inside the iframe at the URL you specified. It receives props via `window.hostProps`.
181
197
 
182
198
  ```typescript
183
- import { type HostProps } from 'forgeframe';
199
+ import ForgeFrame, { type HostProps } from 'forgeframe';
184
200
 
185
201
  interface LoginProps {
186
202
  email?: string;
@@ -194,6 +210,10 @@ declare global {
194
210
  }
195
211
  }
196
212
 
213
+ // Required when the host page doesn't use ForgeFrame.create().
214
+ // If your host defines a component via create(), init is handled automatically.
215
+ ForgeFrame.initHost();
216
+
197
217
  const { email, onLogin, onCancel, close } = window.hostProps;
198
218
 
199
219
  if (email) document.getElementById('email')!.value = email;
@@ -218,7 +238,8 @@ document.getElementById('cancel')!.onclick = async () => {
218
238
  <summary>Explanation</summary>
219
239
 
220
240
  - **`HostProps<LoginProps>`**: Combines your props with built-in methods (`close`, `resize`, etc.)
221
- - **`window.hostProps`**: Automatically available in ForgeFrame hosts, contains all props passed from the consumer
241
+ - **`ForgeFrame.initHost()`**: Flushes host initialization so the consumer can complete render. Only required when the host page doesn't use `ForgeFrame.create()` — if your host defines a component via `create()`, init is handled automatically.
242
+ - **`window.hostProps`**: Contains all props passed from the consumer plus built-in methods
222
243
  - **`close()`**: Built-in method to close the iframe/popup
223
244
 
224
245
  </details>
@@ -272,6 +293,8 @@ await instance.render('#container');
272
293
  | `resize` | Component was resized |
273
294
  | `focus` | Component received focus |
274
295
 
296
+ If all you need is embed + typed props + callbacks, you can stop here and use the API reference as needed.
297
+
275
298
  ---
276
299
 
277
300
  ## Props System
@@ -377,6 +400,28 @@ const MyComponent = ForgeFrame.create({
377
400
  });
378
401
  ```
379
402
 
403
+ ### Passing Props via URL or POST Body (Advanced)
404
+
405
+ Use prop definition flags to include specific values in the host page's initial HTTP request:
406
+
407
+ ```typescript
408
+ const Checkout = ForgeFrame.create({
409
+ tag: 'checkout',
410
+ url: 'https://payments.example.com/checkout',
411
+ props: {
412
+ sessionToken: { schema: prop.string(), queryParam: true }, // ?sessionToken=...
413
+ csrf: { schema: prop.string(), bodyParam: true }, // POST body field "csrf"
414
+ userId: { schema: prop.string(), bodyParam: 'user_id' }, // custom body field name
415
+ },
416
+ });
417
+ ```
418
+
419
+ - `queryParam`: appends to the URL query string for initial load.
420
+ - `bodyParam`: sends values in a hidden form `POST` for initial load (iframe and popup).
421
+ - `bodyParam` only affects the initial navigation; later `updateProps()` uses postMessage.
422
+ - Object values are JSON-stringified. Function and `undefined` values are skipped.
423
+ - Most apps do not need this unless the host server requires initial URL/body parameters.
424
+
380
425
  ### Updating Props
381
426
 
382
427
  Props can be updated after rendering.
@@ -404,7 +449,7 @@ In host windows, `window.hostProps` provides access to props and control methods
404
449
  ### TypeScript Setup
405
450
 
406
451
  ```typescript
407
- import { type HostProps } from 'forgeframe';
452
+ import ForgeFrame, { type HostProps } from 'forgeframe';
408
453
 
409
454
  interface MyProps {
410
455
  email: string;
@@ -417,6 +462,10 @@ declare global {
417
462
  }
418
463
  }
419
464
 
465
+ // Required when the host page doesn't use ForgeFrame.create().
466
+ // If your host defines a component via create(), init is handled automatically.
467
+ ForgeFrame.initHost();
468
+
420
469
  const { email, onLogin, close, resize } = window.hostProps!;
421
470
  ```
422
471
 
@@ -494,7 +543,9 @@ const data = await instance.exports.getFormData();
494
543
 
495
544
  ---
496
545
 
497
- ## Templates
546
+ ## Templates (Advanced)
547
+
548
+ Use this section only when you need custom containers/loading UI beyond the default behavior.
498
549
 
499
550
  ### Container Template
500
551
 
@@ -568,7 +619,7 @@ const MyComponent = ForgeFrame.create({
568
619
 
569
620
  ---
570
621
 
571
- ## React Integration
622
+ ## React Integration (Optional)
572
623
 
573
624
  ### Basic Usage
574
625
 
@@ -639,6 +690,8 @@ const ProfileReact = createComponent(ProfileComponent);
639
690
 
640
691
  ## Advanced Features
641
692
 
693
+ Most integrations can skip this section initially and return only when a specific requirement appears.
694
+
642
695
  ### Popup Windows
643
696
 
644
697
  Render as a popup instead of iframe.
@@ -740,6 +793,7 @@ ForgeFrame.destroyByTag(tag) // Destroy all instances of a tag
740
793
  ForgeFrame.destroyAll() // Destroy all instances
741
794
  ForgeFrame.isHost() // Check if in host context
742
795
  ForgeFrame.isEmbedded() // Alias for isHost() - more intuitive naming
796
+ ForgeFrame.initHost() // Flush host handshake (only needed when create() is not used on the host)
743
797
  ForgeFrame.getHostProps() // Get hostProps in host context
744
798
  ForgeFrame.isStandardSchema(val) // Check if value is a Standard Schema
745
799
 
@@ -72,6 +72,12 @@ export declare class Messenger {
72
72
  * @param domain - Domain pattern to trust (string, RegExp, or array)
73
73
  */
74
74
  addTrustedDomain(domain: DomainMatcher): void;
75
+ /**
76
+ * Removes a trusted domain from this messenger.
77
+ *
78
+ * @param domain - Domain pattern to remove (string, RegExp, or array)
79
+ */
80
+ removeTrustedDomain(domain: DomainMatcher): void;
75
81
  /**
76
82
  * Checks if an origin is trusted.
77
83
  *
@@ -154,8 +154,4 @@ export type MessageName = (typeof MESSAGE_NAME)[keyof typeof MESSAGE_NAME];
154
154
  * @internal
155
155
  */
156
156
  export declare const WINDOW_NAME_PREFIX = "__forgeframe__";
157
- /**
158
- * Current library version.
159
- * @public
160
- */
161
- export declare const VERSION = "0.0.1";
157
+ export declare const VERSION: string;
@@ -60,6 +60,11 @@ export declare function create<P extends Record<string, unknown> = Record<string
60
60
  * @public
61
61
  */
62
62
  export declare function getComponent<P extends Record<string, unknown> = Record<string, unknown>, X = unknown>(tag: string): ForgeFrameComponent<P, X> | undefined;
63
+ /**
64
+ * Returns the internal options metadata for a component factory.
65
+ * @internal
66
+ */
67
+ export declare function getComponentOptions<P extends Record<string, unknown> = Record<string, unknown>, X = unknown>(component: ForgeFrameComponent<P, X>): ComponentOptions<P> | undefined;
63
68
  /**
64
69
  * Destroys a single component instance.
65
70
  *
@@ -60,6 +60,10 @@ export declare class ConsumerComponent<P extends Record<string, unknown>, X = un
60
60
  /** @internal */
61
61
  private hostWindow;
62
62
  /** @internal */
63
+ private openedHostDomain;
64
+ /** @internal */
65
+ private dynamicUrlTrustedOrigin;
66
+ /** @internal */
63
67
  private iframe;
64
68
  /** @internal */
65
69
  private container;
@@ -174,6 +178,31 @@ export declare class ConsumerComponent<P extends Record<string, unknown>, X = un
174
178
  * @internal
175
179
  */
176
180
  private normalizeOptions;
181
+ /**
182
+ * Resolves the host URL from static or function options.
183
+ * @internal
184
+ */
185
+ private resolveUrl;
186
+ /**
187
+ * Resolves dimensions from static or function options.
188
+ * @internal
189
+ */
190
+ private resolveDimensions;
191
+ /**
192
+ * Resolves a URL to an origin, supporting relative URLs.
193
+ * @internal
194
+ */
195
+ private resolveUrlOrigin;
196
+ /**
197
+ * Returns true when the domain option explicitly includes this origin.
198
+ * @internal
199
+ */
200
+ private isExplicitDomainTrust;
201
+ /**
202
+ * Ensures the messenger trusts the origin for a resolved host URL.
203
+ * @internal
204
+ */
205
+ private syncTrustedDomainForUrl;
177
206
  /**
178
207
  * Creates the prop context passed to prop callbacks and validators.
179
208
  * @internal
@@ -210,6 +239,16 @@ export declare class ConsumerComponent<P extends Record<string, unknown>, X = un
210
239
  * @internal
211
240
  */
212
241
  private buildUrl;
242
+ /**
243
+ * Builds POST body parameters from props marked with bodyParam.
244
+ * @internal
245
+ */
246
+ private buildBodyParams;
247
+ /**
248
+ * Submits a hidden form to navigate a target window via POST.
249
+ * @internal
250
+ */
251
+ private submitBodyForm;
213
252
  /**
214
253
  * Builds the window.name payload for the host window.
215
254
  * @internal
@@ -7,7 +7,7 @@
7
7
  * or popup and handles communication with the consumer window. It also provides
8
8
  * utilities for detecting host context and accessing hostProps.
9
9
  */
10
- import type { HostProps, WindowNamePayload, PropsDefinition } from '../types';
10
+ import type { HostProps, WindowNamePayload, PropsDefinition, DomainMatcher } from '../types';
11
11
  import { EventEmitter } from '../events/emitter';
12
12
  /**
13
13
  * Host-side component implementation.
@@ -32,6 +32,8 @@ import { EventEmitter } from '../events/emitter';
32
32
  */
33
33
  export declare class HostComponent<P extends Record<string, unknown>> {
34
34
  private propDefinitions;
35
+ private allowedConsumerDomains?;
36
+ private deferInit;
35
37
  /** The hostProps object containing props and control methods passed from the consumer. */
36
38
  hostProps: HostProps<P>;
37
39
  /** Event emitter for lifecycle events. */
@@ -54,13 +56,43 @@ export declare class HostComponent<P extends Record<string, unknown>> {
54
56
  private consumerProps;
55
57
  /** @internal */
56
58
  private initError;
59
+ /** @internal */
60
+ private destroyed;
61
+ /** @internal */
62
+ private initSent;
63
+ /** @internal */
64
+ private deferredInitFlushScheduled;
57
65
  /**
58
66
  * Creates a new HostComponent instance.
59
67
  *
60
68
  * @param payload - The payload parsed from window.name
61
69
  * @param propDefinitions - Optional prop definitions for deserialization
70
+ * @param allowedConsumerDomains - Optional allowlist of consumer domains
71
+ * @param deferInit - Whether to defer INIT until a later explicit flush
72
+ */
73
+ constructor(payload: WindowNamePayload<P>, propDefinitions?: PropsDefinition<P>, allowedConsumerDomains?: DomainMatcher | undefined, deferInit?: boolean);
74
+ /**
75
+ * Ensures the INIT handshake is sent at most once.
76
+ * @internal
77
+ */
78
+ flushInit(): void;
79
+ /**
80
+ * Schedules deferred INIT flush on the next microtask.
81
+ * This preserves legacy hostProps-only usage while giving same-tick
82
+ * host configuration a chance to run allowlist checks first.
83
+ * @internal
62
84
  */
63
- constructor(payload: WindowNamePayload<P>, propDefinitions?: PropsDefinition<P>);
85
+ private scheduleDeferredInitFlush;
86
+ /**
87
+ * Exposes hostProps on window and lazily flushes deferred init on first access.
88
+ * @internal
89
+ */
90
+ private exposeHostProps;
91
+ /**
92
+ * Validates that the consumer domain is allowed.
93
+ * @internal
94
+ */
95
+ private validateConsumerDomain;
64
96
  /**
65
97
  * Returns the hostProps object.
66
98
  *
@@ -176,7 +208,9 @@ export declare class HostComponent<P extends Record<string, unknown>> {
176
208
  *
177
209
  * @public
178
210
  */
179
- export declare function initHost<P extends Record<string, unknown>>(propDefinitions?: PropsDefinition<P>): HostComponent<P> | null;
211
+ export declare function initHost<P extends Record<string, unknown>>(propDefinitions?: PropsDefinition<P>, allowedConsumerDomains?: DomainMatcher, options?: {
212
+ deferInit?: boolean;
213
+ }): HostComponent<P> | null;
180
214
  /**
181
215
  * Gets the current host component instance.
182
216
  *
@@ -247,3 +281,9 @@ export declare function isEmbedded(): boolean;
247
281
  * @public
248
282
  */
249
283
  export declare function getHostProps<P extends Record<string, unknown>>(): HostProps<P> | undefined;
284
+ /**
285
+ * Clears and destroys the global host instance.
286
+ * Primarily intended for testing.
287
+ * @internal
288
+ */
289
+ export declare function clearHostInstance(): void;