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 +39 -4
- package/docs/plugin-author-guide.ja.md +51 -1
- package/docs/plugin-author-guide.md +76 -2
- package/package.json +1 -1
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
|
-
*
|
|
395
|
-
*
|
|
396
|
-
*
|
|
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
|
|
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**:
|
|
544
|
-
|
|
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
|