ampless 1.0.0-alpha.31 → 1.0.0-alpha.32

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/dist/index.d.ts CHANGED
@@ -302,7 +302,7 @@ type TrustLevel = 'untrusted' | 'trusted' | 'privileged';
302
302
  * capability today is harmless, but the runtime won't expose any new
303
303
  * surface for it until the matching phase ships.
304
304
  */
305
- type PluginCapability = 'publicHead' | 'publicBody' | 'metadata' | 'eventHooks' | 'adminSettings' | 'writePublicAsset' | 'schema' | 'publicHtmlForPost' | 'secretSettings' | 'contentFields' | 'adminPage' | 'serverRoute' | 'network' | 'scheduler' | 'storageWrite' | 'privilegedSystem';
305
+ type PluginCapability = 'publicHead' | 'publicBody' | 'metadata' | 'eventHooks' | 'adminSettings' | 'writePublicAsset' | 'schema' | 'publicHtmlForPost' | 'secretSettings' | 'contentFields' | 'adminPage' | 'serverRoute' | 'network' | 'scheduler' | 'storageWrite' | 'privilegedSystem' | 'cspReady';
306
306
  /**
307
307
  * Loading strategy for `script` / `inlineScript` descriptors.
308
308
  *
@@ -344,6 +344,16 @@ interface PluginPublicRenderContext {
344
344
  * field's declared shape, so the cast is safe in practice.
345
345
  */
346
346
  setting<T = unknown>(key: string): T | undefined;
347
+ /**
348
+ * Request-scoped CSP nonce reservation. Always `undefined` in Phase 1
349
+ * — the runtime does not populate this field yet. Middleware/SSR
350
+ * threading lands with the future CSP RFP. Plugin authors who want to
351
+ * be ready for the future stamping can declare
352
+ * `inlineScript.nonce: 'auto'` today; once the middleware-driven
353
+ * threading PR lands, those descriptors will become candidates for
354
+ * runtime nonce stamping.
355
+ */
356
+ cspNonce?: string;
347
357
  }
348
358
  /**
349
359
  * Descriptor returned by `publicHead()`. The runtime validates each
@@ -364,6 +374,15 @@ type PublicHeadDescriptor = {
364
374
  defer?: boolean;
365
375
  /** Allow-listed attributes only (data-*, crossorigin, referrerpolicy, ...). */
366
376
  attrs?: Record<string, string | boolean>;
377
+ /**
378
+ * Optional CSP nonce. Same semantics as inlineScript.nonce
379
+ * (`'auto'` is the sentinel for future runtime stamping; any
380
+ * other string is an explicit literal; undefined emits no
381
+ * `nonce` attribute). Phase 1 reservation: runtime accepts
382
+ * but does not propagate. See `inlineScript.nonce` JSDoc for
383
+ * the full description.
384
+ */
385
+ nonce?: 'auto' | string;
367
386
  } | {
368
387
  type: 'inlineScript';
369
388
  /** Required for duplicate detection and dev warnings. */
@@ -391,9 +410,25 @@ type PublicHeadDescriptor = {
391
410
  */
392
411
  scriptType?: 'application/ld+json';
393
412
  /**
394
- * Type-only reservation. CSP nonce resolution (including the
395
- * planned `'auto'` mode) is deferred to a future RFP; Phase 1
396
- * does not propagate this field to the rendered element.
413
+ * Optional CSP nonce.
414
+ *
415
+ * - `'auto'`: sentinel reserved for future runtime stamping.
416
+ * When the middleware/SSR CSP nonce threading PR lands, the
417
+ * runtime will read `ctx.cspNonce` from the request scope
418
+ * and stamp the rendered `<script>` tag automatically.
419
+ * - any other `string`: explicit nonce literal (advanced;
420
+ * rarely needed).
421
+ * - `undefined`: no `nonce` attribute emitted (default,
422
+ * backward-compatible with non-CSP sites).
423
+ *
424
+ * Phase 1 reservation: the runtime accepts the field but does
425
+ * not propagate it to the rendered element. Declaring
426
+ * `nonce: 'auto'` today is a forward-compatibility hint and
427
+ * does not change the rendered HTML.
428
+ *
429
+ * Note: TypeScript does not type-widen here — `string` already
430
+ * accepts `'auto'` as a literal. The semantic reservation is
431
+ * documented above.
397
432
  */
398
433
  nonce?: string;
399
434
  } | {
@@ -441,7 +441,7 @@ runtime は `body` を `sanitize-html` の厳格 allowlist で sanitize し(
441
441
  - **`attrs` allowlist**: `data-*`、`crossorigin`、`referrerpolicy`、`integrity`、`fetchpriority`、`loading`、`sandbox`、`allow`、`allowfullscreen`。それ以外は dev warn 付きで drop
442
442
  - **`inlineScript.id` は必須**。無いとプラグイン同士が似たスニペットを emit したときに dedup できず、dev warning も index 番号を指すだけで原因プラグインを特定できません
443
443
  - **id 重複**: 最後の出現が勝ち。dev warning でどの key が重複したか表示されます
444
- - **CSP nonce**: Phase 1 では伝搬しません。`nonce` attr は型上は宣言してありますが今のところ無視されます
444
+ - **CSP nonce**: `inlineScript.nonce` と `script.nonce` は型として受け入れられます(`'auto'` は将来の runtime スタンプ用 sentinel。文字列リテラルも可)。Phase 1 予約: runtime はフィールドを受け入れますが描画要素には伝搬しません。詳細は下記の [CSP nonce(Phase 1 予約)](#csp-nonce-phase-1-) を参照。
445
445
  - **strategy**: `afterInteractive` は外部 script に `async` を付ける。`lazyOnload` は `defer`。明示的な `async` / `defer` が常に勝ち。`beforeInteractive` は非対応
446
446
 
447
447
  ### runtime が描画する形
@@ -563,6 +563,56 @@ React 19 はさらに、クライアントコンポーネントのレンダー
563
563
 
564
564
  投稿単位の見える出力には `publicHtmlForPost` を使ってください(Phase 6d — 上の例と §6 の `PublicPostHtmlDescriptor` 参照)。runtime が post 本文の周囲の固定スロットにサーバーサイド HTML を出すので、hydration と競合しません。
565
565
 
566
+
567
+ ### CSP nonce(Phase 1 予約)
568
+
569
+ CSP(Content Security Policy)は本番公開サイトのほぼ必須要件です。nonce 伝搬を後から追加した場合に既存プラグインが一斉に動かなくなるのを防ぐため、ampless は今のうちに API サーフェスだけ予約しておきます(Phase 1 は完全 no-op)。
570
+
571
+ 3 層設計:
572
+
573
+ 1. **`ctx.cspNonce?: string`** — `PluginPublicRenderContext` の型に予約済み。今のところ常に `undefined`。runtime はこのフィールドをまだ populate しません。middleware/SSR nonce threading は将来の CSP RFP とともに landing します。
574
+
575
+ 2. **`descriptor.nonce: 'auto' | string`** — `inlineScript` と `script` の両 descriptor variant の型で受け入れられます。`'auto'` は将来の runtime スタンプ用 sentinel。その他の文字列は明示的リテラル。`undefined` は `nonce` 属性を emit しない(デフォルト、非 CSP サイトと後方互換)。Phase 1: runtime は受け入れますが伝搬しません。`nonce: 'auto'` を今日宣言することは前方互換性のヒントであり、描画 HTML を変更しません。
576
+
577
+ 3. **`'cspReady'` capability** — name-only の declarative バッジ。将来の admin UI / サニティチェックの対象になります。Phase 1 では runtime の cross-check や enforcement は一切なし。
578
+
579
+ **対応方法:**
580
+
581
+ ```ts
582
+ // src/index.ts
583
+ definePlugin({
584
+ name: 'my-plugin',
585
+ apiVersion: 1,
586
+ trust_level: 'untrusted',
587
+ capabilities: ['publicHead', 'cspReady'],
588
+ publicHead: () => [{
589
+ type: 'inlineScript',
590
+ id: 'my-snippet',
591
+ body: '...',
592
+ nonce: 'auto', // 前方互換性ヒント。Phase 1 では効果なし
593
+ }],
594
+ })
595
+ ```
596
+
597
+ npm 公開のスタンドアロンプラグインの場合は、`package.json#amplessPlugin.capabilities` も合わせて更新してください — static manifest と factory return value が一致しない場合、runtime cross-check が警告を出します:
598
+
599
+ ```json
600
+ {
601
+ "amplessPlugin": {
602
+ "apiVersion": 1,
603
+ "name": "my-plugin",
604
+ "trustLevel": "untrusted",
605
+ "capabilities": ["publicHead", "cspReady"]
606
+ }
607
+ }
608
+ ```
609
+
610
+ **`'cspReady'` の意味:**
611
+
612
+ - サイト全体の CSP 適合は middleware / レスポンスヘッダー / runtime が制御しない他の inline コンテンツにも依存します。
613
+ - middleware-driven nonce threading PR が landing した後は、`nonce: 'auto'` を持つ plugin-supplied script が runtime nonce スタンプの候補になります。
614
+ - `'cspReady'` は `create-ampless plugin --capabilities` には表示されません — reserved capability であり、scaffold はアクティブな enforcement を示唆しないよう除外しています。
615
+
566
616
  ---
567
617
 
568
618
  ## 7. 非同期イベントフック
@@ -540,8 +540,12 @@ a console warning** and never rendered.
540
540
  index numbers no one can map back to a plugin.
541
541
  - **Duplicate `id`**: the last occurrence wins. A dev warning prints
542
542
  which key was duplicated.
543
- - **CSP nonce**: not propagated in Phase 1. The `nonce` attr is
544
- declared in the type for forward-compat but discarded today.
543
+ - **CSP nonce**: `inlineScript.nonce` and `script.nonce` are accepted
544
+ by the type (`'auto'` is the sentinel for future runtime stamping;
545
+ any string is an explicit literal). Phase 1 reservation: the runtime
546
+ accepts the field but does not propagate it to the rendered element.
547
+ See [CSP nonce (Phase 1 reservation)](#csp-nonce-phase-1-reservation)
548
+ below.
545
549
  - **Strategy**: `afterInteractive` adds `async` to external scripts.
546
550
  `lazyOnload` adds `defer`. Explicit `async` / `defer` always
547
551
  wins. `beforeInteractive` is not supported.
@@ -715,6 +719,76 @@ the example above and §6's `PublicPostHtmlDescriptor`). The runtime
715
719
  emits server-side HTML at fixed slots around the post body, so
716
720
  nothing races against hydration.
717
721
 
722
+
723
+ ### CSP nonce (Phase 1 reservation)
724
+
725
+ Content Security Policy (CSP) is a near-mandatory requirement for production
726
+ sites. To avoid breaking every plugin at once when nonce propagation lands,
727
+ ampless reserves the API surface today (Phase 1 no-op) so plugins can opt in
728
+ ahead of time.
729
+
730
+ The 3-layer design:
731
+
732
+ 1. **`ctx.cspNonce?: string`** on `PluginPublicRenderContext` — type-reserved
733
+ on the interface; always `undefined` today. The runtime does not populate
734
+ this field yet; reads resolve to `undefined`. Middleware/SSR nonce threading
735
+ lands with the future CSP RFP.
736
+
737
+ 2. **`descriptor.nonce: 'auto' | string`** — accepted by the type on both
738
+ `inlineScript` and `script` descriptor variants. `'auto'` is the sentinel
739
+ for future runtime stamping; any other string is an explicit literal;
740
+ `undefined` emits no `nonce` attribute (default, backward-compatible).
741
+ Phase 1: the runtime accepts but does not propagate it. Declaring
742
+ `nonce: 'auto'` today is a forward-compatibility hint and does not change
743
+ the rendered HTML.
744
+
745
+ 3. **`'cspReady'` capability** — a name-only declarative badge. Declaring it
746
+ signals intent; future admin UI / sanity checks may surface it. No runtime
747
+ cross-check or enforcement exists in Phase 1.
748
+
749
+ **How to be ready:**
750
+
751
+ ```ts
752
+ // src/index.ts
753
+ definePlugin({
754
+ name: 'my-plugin',
755
+ apiVersion: 1,
756
+ trust_level: 'untrusted',
757
+ capabilities: ['publicHead', 'cspReady'],
758
+ publicHead: () => [{
759
+ type: 'inlineScript',
760
+ id: 'my-snippet',
761
+ body: '...',
762
+ nonce: 'auto', // forward-compat hint; no effect in Phase 1
763
+ }],
764
+ })
765
+ ```
766
+
767
+ For standalone npm-published plugins, also update `package.json#amplessPlugin.capabilities`
768
+ to match — the runtime cross-check warns on disagreement between the static
769
+ manifest and the factory return value:
770
+
771
+ ```json
772
+ {
773
+ "amplessPlugin": {
774
+ "apiVersion": 1,
775
+ "name": "my-plugin",
776
+ "trustLevel": "untrusted",
777
+ "capabilities": ["publicHead", "cspReady"]
778
+ }
779
+ }
780
+ ```
781
+
782
+ **What "cspReady" means:**
783
+
784
+ - Site-level CSP compliance depends on middleware / response headers / other
785
+ inline content the runtime does not control.
786
+ - Once the middleware-driven nonce threading PR lands, plugin-supplied scripts
787
+ that carry `nonce: 'auto'` will become candidates for runtime nonce stamping.
788
+ - `'cspReady'` does **not** appear in `create-ampless plugin --capabilities`
789
+ output — it is a reserved capability and the scaffold excludes it to avoid
790
+ implying active enforcement.
791
+
718
792
  ---
719
793
 
720
794
  ## 7. Async event hooks
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ampless",
3
- "version": "1.0.0-alpha.31",
3
+ "version": "1.0.0-alpha.32",
4
4
  "description": "Serverless CMS for AWS Amplify",
5
5
  "license": "MIT",
6
6
  "type": "module",