@metapages/metapage 1.10.1 → 1.10.2

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
@@ -36,7 +36,7 @@ import {
36
36
  renderMetapage,
37
37
  Metapage,
38
38
  Metaframe,
39
- } from "https://cdn.jsdelivr.net/npm/@metapages/metapage@1.10.1";
39
+ } from "https://cdn.jsdelivr.net/npm/@metapages/metapage@1.10.2";
40
40
  ```
41
41
 
42
42
  ## Quick Start
@@ -82,7 +82,7 @@ The `renderMetapage` function the `react-grid-layout` layout in `metapage.json`:
82
82
  If you're building a component to use in a metapage:
83
83
 
84
84
  ```javascript
85
- import { Metaframe } from "https://cdn.jsdelivr.net/npm/@metapages/metapage@1.10.1";
85
+ import { Metaframe } from "https://cdn.jsdelivr.net/npm/@metapages/metapage@1.10.2";
86
86
 
87
87
  const metaframe = new Metaframe();
88
88
 
@@ -223,7 +223,7 @@ metaframe.onInput("file", (file) => {
223
223
  <div id="metapage-container"></div>
224
224
 
225
225
  <script type="module">
226
- import { renderMetapage } from "https://cdn.jsdelivr.net/npm/@metapages/metapage@1.10.1";
226
+ import { renderMetapage } from "https://cdn.jsdelivr.net/npm/@metapages/metapage@1.10.2";
227
227
 
228
228
  const definition = await fetch(
229
229
  "https://metapage.io/m/87ae11673508447e883b598bf7da9c5d/metapage.json",
@@ -258,7 +258,7 @@ metaframe.onInput("file", (file) => {
258
258
  ### Building a Metaframe Component
259
259
 
260
260
  ```javascript
261
- import { Metaframe } from "https://cdn.jsdelivr.net/npm/@metapages/metapage@1.10.1";
261
+ import { Metaframe } from "https://cdn.jsdelivr.net/npm/@metapages/metapage@1.10.2";
262
262
 
263
263
  const metaframe = new Metaframe();
264
264
 
@@ -335,7 +335,7 @@ Metaframes can read and write to their URL hash parameters:
335
335
  import {
336
336
  getHashParamValueJsonFromWindow,
337
337
  setHashParamValueJsonInWindow,
338
- } from "https://cdn.jsdelivr.net/npm/@metapages/metapage@1.10.1";
338
+ } from "https://cdn.jsdelivr.net/npm/@metapages/metapage@1.10.2";
339
339
 
340
340
  // Read from URL hash
341
341
  const config = getHashParamValueJsonFromWindow("config");
@@ -375,6 +375,177 @@ metaframe.onInput("image", async (data) => {
375
375
  });
376
376
  ```
377
377
 
378
+ ## Secrets
379
+
380
+ Inject sensitive credentials (API keys, tokens, etc.) into metaframe URLs at runtime while ensuring they are never exposed when retrieving the metapage definition.
381
+
382
+ ### API
383
+
384
+ ```typescript
385
+ import { Metapage, InjectSecretsPayload } from "@metapages/metapage";
386
+
387
+ const metapage = new Metapage();
388
+ await metapage.setDefinition(definition);
389
+
390
+ const secrets: InjectSecretsPayload = {
391
+ frameSecrets: {
392
+ myMetaframe: {
393
+ hashParams: {
394
+ apiKey: "sk-abc123",
395
+ token: "secret-token",
396
+ },
397
+ queryParams: {
398
+ auth: "bearer-token",
399
+ },
400
+ },
401
+ },
402
+ };
403
+
404
+ metapage.injectSecrets(secrets);
405
+ ```
406
+
407
+ ### Type Definition
408
+
409
+ ```typescript
410
+ type InjectSecretsPayload = {
411
+ frameSecrets: {
412
+ [metaframeName: string]: {
413
+ hashParams?: { [name: string]: string };
414
+ queryParams?: { [name: string]: string };
415
+ };
416
+ };
417
+ };
418
+ ```
419
+
420
+ ### Behavior
421
+
422
+ - **Injection**: Secrets are base64-encoded into metaframe URL hash/query parameters using `setHashParamValueBase64EncodedInUrl` from `@metapages/hash-query`
423
+ - **Accumulation**: Multiple calls to `injectSecrets()` accumulate secrets rather than replacing previous ones
424
+ - **Safe removal**: `getDefinition()` and definition change events automatically strip secrets, restoring original parameter values
425
+ - **Persistence across updates**: Secrets survive `setDefinition()` calls — if a metaframe still exists in the new definition, its secrets are re-injected
426
+ - **Cleanup**: Secrets are removed when metaframes are removed via `removeMetaframe()` or `removeAll()`
427
+
428
+ ### Example
429
+
430
+ ```typescript
431
+ const metapage = new Metapage();
432
+ await metapage.setDefinition(definition);
433
+
434
+ // Inject a secret
435
+ metapage.injectSecrets({
436
+ frameSecrets: {
437
+ secret1test: {
438
+ hashParams: {
439
+ secret1: "injected secret",
440
+ },
441
+ },
442
+ },
443
+ });
444
+
445
+ // The metaframe iframe URL now contains the secret (base64-encoded in hash)
446
+ // But getDefinition() returns the original URL without secrets:
447
+ const def = metapage.getDefinition();
448
+ // def.metaframes.secret1test.url has NO secret params
449
+
450
+ // Definition events also exclude secrets:
451
+ metapage.on(Metapage.DEFINITION, (cleanDef) => {
452
+ // cleanDef has no secrets
453
+ });
454
+ ```
455
+
456
+ ### Security Notes
457
+
458
+ - Secrets are base64-encoded (not encrypted) in URLs
459
+ - Metaframe iframes receive secrets via their URL hash/query params at runtime
460
+ - Secrets are stripped from all definition retrieval methods and events
461
+ - Secret storage is cleared on `dispose()`
462
+
463
+ ## updateDefinition
464
+
465
+ `updateDefinition` is the preferred way to change the metapage definition at runtime when you need to react to what changed. Unlike `setDefinition`, it:
466
+
467
+ - Always emits a `DefinitionUpdate` event — even on the very first call
468
+ - Includes a structured diff of which metaframes were added and removed
469
+ - Automatically emits a `State` event when metaframes are added or removed
470
+
471
+ ### API
472
+
473
+ ```typescript
474
+ await metapage.updateDefinition(definition, state?);
475
+ ```
476
+
477
+ | Parameter | Type | Description |
478
+ | ------------ | -------------------------- | ------------------------------------------------------ |
479
+ | `definition` | `MetapageDefinition` | The new metapage definition |
480
+ | `state` | `MetapageState` (optional) | Initial state to apply alongside the definition update |
481
+
482
+ ### Event Payload
483
+
484
+ Listen with `Metapage.DEFINITION_UPDATE`. The event payload has this shape:
485
+
486
+ ```typescript
487
+ interface MetapageEventDefinitionUpdate {
488
+ definition: MetapageDefinition; // current definition (secrets stripped)
489
+ metaframes: {
490
+ current: { [id: string]: MetapageIFrameRpcClient }; // all metaframes after update
491
+ added: { [id: string]: MetapageIFrameRpcClient }; // metaframes that were added
492
+ removed: { [id: string]: MetapageIFrameRpcClient }; // metaframes that were removed (disposed)
493
+ };
494
+ }
495
+ ```
496
+
497
+ ### Example
498
+
499
+ ```typescript
500
+ import { Metapage, MetapageEventDefinitionUpdate } from "@metapages/metapage";
501
+
502
+ const metapage = new Metapage();
503
+
504
+ metapage.on(
505
+ Metapage.DEFINITION_UPDATE,
506
+ (event: MetapageEventDefinitionUpdate) => {
507
+ const { added, removed, current } = event.metaframes;
508
+
509
+ console.log("Current metaframes:", Object.keys(current));
510
+ console.log("Added:", Object.keys(added));
511
+ console.log("Removed:", Object.keys(removed));
512
+ },
513
+ );
514
+
515
+ // First call — fires immediately (unlike setDefinition)
516
+ await metapage.updateDefinition({
517
+ metaframes: {
518
+ viewer: { url: "https://markdown.mtfm.io/" },
519
+ },
520
+ });
521
+
522
+ // Second call — event reports frame2 in `added`
523
+ await metapage.updateDefinition({
524
+ metaframes: {
525
+ viewer: { url: "https://markdown.mtfm.io/" },
526
+ editor: { url: "https://editor.mtfm.io/" },
527
+ },
528
+ });
529
+ ```
530
+
531
+ ### Comparison with setDefinition
532
+
533
+ | Behaviour | `setDefinition` | `updateDefinition` |
534
+ | ----------------------------- | --------------- | ------------------ |
535
+ | Emits event on first call | No | Yes |
536
+ | Event type | `Definition` | `DefinitionUpdate` |
537
+ | Diff of added/removed frames | No | Yes |
538
+ | Emits `State` on frame change | No | Yes |
539
+
540
+ ### State event
541
+
542
+ `State` is automatically emitted (to any listeners) when:
543
+
544
+ - Metaframes are added or removed, OR
545
+ - An explicit `state` argument is passed and is non-empty
546
+
547
+ ---
548
+
378
549
  ## API Overview
379
550
 
380
551
  ### renderMetapage(options)
@@ -398,8 +569,11 @@ Render a metapage into a DOM element.
398
569
 
399
570
  **Methods:**
400
571
 
572
+ - `setDefinition(def, state?)`: Set the metapage definition; emits `Definition` on subsequent calls only
573
+ - `updateDefinition(def, state?)`: Set the definition and always emit `DefinitionUpdate` with added/removed diff (see [updateDefinition](#updatedefinition))
401
574
  - `setInputs(inputs)`: Set inputs for metaframes
402
575
  - `getState()`: Get current state (inputs/outputs)
576
+ - `injectSecrets(secrets)`: Inject secrets into metaframe URLs (see [Secrets](#secrets))
403
577
  - `dispose()`: Clean up and remove all listeners
404
578
  - `on(event, handler)`: Listen to events
405
579
 
@@ -407,7 +581,9 @@ Render a metapage into a DOM element.
407
581
 
408
582
  - `Metapage.OUTPUTS`: When metaframe outputs change
409
583
  - `Metapage.INPUTS`: When metapage inputs change
410
- - `Metapage.DEFINITION`: When definition changes
584
+ - `Metapage.DEFINITION`: When definition changes (not emitted on first `setDefinition` call)
585
+ - `Metapage.DEFINITION_UPDATE`: When `updateDefinition` is called; payload includes added/removed metaframe diff (see [updateDefinition](#updatedefinition))
586
+ - `Metapage.STATE`: When metapage state changes
411
587
 
412
588
  ### Metaframe Class
413
589
 
@@ -445,7 +621,7 @@ Example minimal metaframe:
445
621
  </head>
446
622
  <body>
447
623
  <script type="module">
448
- import { Metaframe } from "https://cdn.jsdelivr.net/npm/@metapages/metapage@1.10.1";
624
+ import { Metaframe } from "https://cdn.jsdelivr.net/npm/@metapages/metapage@1.10.2";
449
625
 
450
626
  const metaframe = new Metaframe();
451
627
 
@@ -466,13 +642,12 @@ Full TypeScript definitions are included:
466
642
  import {
467
643
  Metapage,
468
644
  Metaframe,
469
- MetapageDefinitionV2,
645
+ MetapageDefinition,
470
646
  MetaframeInputMap,
471
647
  MetapageInstanceInputs,
472
- } from "https://cdn.jsdelivr.net/npm/@metapages/metapage@1.10.1";
648
+ } from "https://cdn.jsdelivr.net/npm/@metapages/metapage@1.10.2";
473
649
 
474
- const definition: MetapageDefinitionV2 = {
475
- version: "2",
650
+ const definition: MetapageDefinition = {
476
651
  metaframes: {
477
652
  example: {
478
653
  url: "https://example.com",