ampless 1.0.0-alpha.18 → 1.0.0-alpha.19

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
@@ -283,9 +283,11 @@ type TrustLevel = 'untrusted' | 'trusted' | 'privileged';
283
283
  * declaration-vs-implementation reconciliation warnings and (in later
284
284
  * phases) for `allowCapabilities` gating in `cms.config.ts`.
285
285
  *
286
- * Phase 1 active capabilities:
286
+ * Active capabilities:
287
287
  * - `publicHead` / `publicBody`: descriptor-based head/body injection.
288
288
  * - `metadata` / `eventHooks`: name-only declaration for existing surfaces.
289
+ * - `adminSettings`: admin-managed public settings manifest.
290
+ * - `writePublicAsset`: trusted hook context can write namespaced public assets.
289
291
  *
290
292
  * Reserved capabilities are accepted by the type so that plugins can
291
293
  * declare future intent, but the runtime does nothing with them yet —
@@ -293,7 +295,7 @@ type TrustLevel = 'untrusted' | 'trusted' | 'privileged';
293
295
  * capability today is harmless, but the runtime won't expose any new
294
296
  * surface for it until the matching phase ships.
295
297
  */
296
- type PluginCapability = 'publicHead' | 'publicBody' | 'metadata' | 'eventHooks' | 'adminSettings' | 'schema' | 'writePublicAsset' | 'contentFields' | 'adminPage' | 'serverRoute' | 'secretSettings' | 'network' | 'scheduler' | 'storageWrite' | 'privilegedSystem';
298
+ type PluginCapability = 'publicHead' | 'publicBody' | 'metadata' | 'eventHooks' | 'adminSettings' | 'writePublicAsset' | 'schema' | 'contentFields' | 'adminPage' | 'serverRoute' | 'secretSettings' | 'network' | 'scheduler' | 'storageWrite' | 'privilegedSystem';
297
299
  /**
298
300
  * Loading strategy for `script` / `inlineScript` descriptors.
299
301
  *
@@ -1026,6 +1028,15 @@ declare function decodeAwsJson(value: unknown): unknown;
1026
1028
  */
1027
1029
  declare function formatPublicAssetUrl(bucket: string, region: string, key: string): string;
1028
1030
 
1031
+ /**
1032
+ * Validate the user-supplied key for ctx.writePublicAsset.
1033
+ *
1034
+ * The trusted Lambda still has a processor-wide S3 grant, so path safety is
1035
+ * enforced at the runtime context boundary before the key is joined under the
1036
+ * plugin namespace.
1037
+ */
1038
+ declare function validatePublicAssetKey(key: string): string | null;
1039
+
1029
1040
  declare const PLUGIN_KEY_PATTERN: RegExp;
1030
1041
  declare function isValidPluginKey(key: string): boolean;
1031
1042
  /**
@@ -1178,4 +1189,4 @@ declare function pickDefaultEntrypoint(files: readonly {
1178
1189
 
1179
1190
  declare const VERSION = "0.0.1";
1180
1191
 
1181
- export { type AmplessEvent, type AmplessPlugin, type AuthContext, type BundleExtractResult, type CacheConfig, type CacheStrategy, type Config, type ContentEventPayload, type ContentEventType, type ContentFormat, type ContentTypeDefinition, type CreatePostInput, DEFAULT_ENTRYPOINT, type DateFormat, type EventPayloadOf, type EventType, type ExtractedFile, type FieldDefinition, type FieldType, type ImageDisplay, type KvItem, type KvStore, type LinkListItem, type ListOptions, type LocalizedString, MAX_BUNDLE_BYTES, type Media, type MediaEventPayload, type MediaEventType, type MediaMetadata, type MediaProcessingDefaults, type OgImageConfig, type OgImageFont, type OgImageRenderContext, PLUGIN_KEY_PATTERN, type Page, type PluginBooleanField, type PluginCapability, type PluginCodeField, type PluginEventHandler, type PluginJsonField, type PluginMetadata, type PluginNumberField, type PluginPublicRenderContext, type PluginRuntimeContext, type PluginSelectField, type PluginSettingField, type PluginSettingsManifest, type PluginTextField, type PluginTextareaField, type PluginUrlField, type Post, type PostIndexEventPayload, type PostIndexEventType, type PostMetadata, type PostStatus, type PostsProvider, type PublicBodyDescriptor, type PublicHeadDescriptor, type Role, SITE_CONFIG_PK, type ScriptStrategy, type SiteSettingsEventPayload, type SiteSettingsEventType, type StaticPostBody, type StaticPostFileMeta, type StreamEventName, TEXT_EXTENSIONS, type ThemeColorField, type ThemeField, type ThemeFieldType, type ThemeFontFamilyField, type ThemeImageField, type ThemeLengthField, type ThemeLinkListField, type ThemeManifest, type ThemeModule, type ThemeRouteContext, type ThemeSelectField, type ThemeTextField, type TrustLevel, VERSION, type ValidationIssue, bundlePrefix, createPost, decodeAwsJson, defineConfig, definePlugin, defineSchema, defineTheme, defineThemeModule, deletePost, deleteSiteSetting, detectContentEvents, encodeAwsJson, escapeXml, extractFirstImageUrl, findAbsolutePathRefs, flattenSettings, formatColorPair, formatDate, formatPublicAssetUrl, getKvStore, getPost, getPostById, getSiteSetting, hasKvStore, hasPostsProvider, isTagListUrl, isValidPluginKey, listPosts, listSiteSettings, mimeTypeFor, parseColorPair, parseLinkList, pickDefaultEntrypoint, resolveLocalized, resolvePluginSettings, resolveThemeValues, setKvStore, setPostsProvider, setSiteSetting, stringifyLinkList, stripCommonPrefix, themeSettingKey, unflattenSettings, updatePost, validateBundle, validateBundlePath, validatePluginSettingValue, validateThemeValue };
1192
+ export { type AmplessEvent, type AmplessPlugin, type AuthContext, type BundleExtractResult, type CacheConfig, type CacheStrategy, type Config, type ContentEventPayload, type ContentEventType, type ContentFormat, type ContentTypeDefinition, type CreatePostInput, DEFAULT_ENTRYPOINT, type DateFormat, type EventPayloadOf, type EventType, type ExtractedFile, type FieldDefinition, type FieldType, type ImageDisplay, type KvItem, type KvStore, type LinkListItem, type ListOptions, type LocalizedString, MAX_BUNDLE_BYTES, type Media, type MediaEventPayload, type MediaEventType, type MediaMetadata, type MediaProcessingDefaults, type OgImageConfig, type OgImageFont, type OgImageRenderContext, PLUGIN_KEY_PATTERN, type Page, type PluginBooleanField, type PluginCapability, type PluginCodeField, type PluginEventHandler, type PluginJsonField, type PluginMetadata, type PluginNumberField, type PluginPublicRenderContext, type PluginRuntimeContext, type PluginSelectField, type PluginSettingField, type PluginSettingsManifest, type PluginTextField, type PluginTextareaField, type PluginUrlField, type Post, type PostIndexEventPayload, type PostIndexEventType, type PostMetadata, type PostStatus, type PostsProvider, type PublicBodyDescriptor, type PublicHeadDescriptor, type Role, SITE_CONFIG_PK, type ScriptStrategy, type SiteSettingsEventPayload, type SiteSettingsEventType, type StaticPostBody, type StaticPostFileMeta, type StreamEventName, TEXT_EXTENSIONS, type ThemeColorField, type ThemeField, type ThemeFieldType, type ThemeFontFamilyField, type ThemeImageField, type ThemeLengthField, type ThemeLinkListField, type ThemeManifest, type ThemeModule, type ThemeRouteContext, type ThemeSelectField, type ThemeTextField, type TrustLevel, VERSION, type ValidationIssue, bundlePrefix, createPost, decodeAwsJson, defineConfig, definePlugin, defineSchema, defineTheme, defineThemeModule, deletePost, deleteSiteSetting, detectContentEvents, encodeAwsJson, escapeXml, extractFirstImageUrl, findAbsolutePathRefs, flattenSettings, formatColorPair, formatDate, formatPublicAssetUrl, getKvStore, getPost, getPostById, getSiteSetting, hasKvStore, hasPostsProvider, isTagListUrl, isValidPluginKey, listPosts, listSiteSettings, mimeTypeFor, parseColorPair, parseLinkList, pickDefaultEntrypoint, resolveLocalized, resolvePluginSettings, resolveThemeValues, setKvStore, setPostsProvider, setSiteSetting, stringifyLinkList, stripCommonPrefix, themeSettingKey, unflattenSettings, updatePost, validateBundle, validateBundlePath, validatePluginSettingValue, validatePublicAssetKey, validateThemeValue };
package/dist/index.js CHANGED
@@ -215,6 +215,22 @@ function definePlugin(p) {
215
215
  return p;
216
216
  }
217
217
 
218
+ // src/plugin-asset-key.ts
219
+ function validatePublicAssetKey(key) {
220
+ if (key.length === 0) return "key must not be empty";
221
+ if (key.length > 256) return "key must be 256 characters or less";
222
+ if (key.startsWith("/")) return 'key must be relative and must not start with "/"';
223
+ if (key.includes("\\")) return "key must not contain backslashes";
224
+ if (/[\u0000-\u001f\u007f]/.test(key)) {
225
+ return "key must not contain control characters";
226
+ }
227
+ const segments = key.split("/");
228
+ if (segments.some((segment) => segment === "." || segment === "..")) {
229
+ return 'key must not contain "." or ".." path segments';
230
+ }
231
+ return null;
232
+ }
233
+
218
234
  // src/plugin-settings.ts
219
235
  var PLUGIN_KEY_PATTERN = /^[a-zA-Z0-9_-]+$/;
220
236
  function isValidPluginKey(key) {
@@ -721,5 +737,6 @@ export {
721
737
  validateBundle,
722
738
  validateBundlePath,
723
739
  validatePluginSettingValue,
740
+ validatePublicAssetKey,
724
741
  validateThemeValue
725
742
  };
@@ -139,7 +139,7 @@ analyticsGa4Plugin({ instanceId: 'product' })
139
139
  | 階層 | IAM | 用途 |
140
140
  |---|---|---|
141
141
  | `untrusted` | なし (SQS consume のみ) | head/body descriptor、webhook 配送、コンテンツ変換 |
142
- | `trusted` | 投稿読み出し、`public/plugins/<name>/...` への書き込み | RSS フィード、sitemap、計算済み JSON インデックス |
142
+ | `trusted` | 投稿読み出し、`public/plugins/<instanceId ?? name>/...` への書き込み | RSS フィード、sitemap、計算済み JSON インデックス |
143
143
  | `privileged` | 予約 | 将来: SES、secret、private S3 |
144
144
 
145
145
  決め方の目安:
@@ -273,6 +273,26 @@ hooks: {
273
273
  }
274
274
  ```
275
275
 
276
+ ### `writePublicAsset`
277
+
278
+ 公開生成ファイルを書き出す trusted plugin は capability を宣言してください:
279
+
280
+ ```ts
281
+ capabilities: ['eventHooks', 'writePublicAsset']
282
+ ```
283
+
284
+ 同じ plugin が `metadata()` または `siteMetadata()` も実装する場合は、`metadata` も宣言します。この capability 名は両方の metadata 関数をまとめて表し、別個の `siteMetadata` capability はありません。
285
+
286
+ trusted processor は次の場所に書き込みます:
287
+
288
+ ```txt
289
+ public/plugins/<instanceId ?? name>/<key>
290
+ ```
291
+
292
+ `key` は相対 asset key である必要があります。空文字、絶対パス、`.` / `..` path segment、backslash、制御文字、256 文字超の key は S3 呼び出し前に拒否されます。`indexes/posts.json` のような nested path は許可されます。戻り値は書き込まれた object の public URL です。
293
+
294
+ 移行期間中、`capabilities` フィールドが無い plugin はそのまま動きます。`capabilities` を宣言しているのに `writePublicAsset` を省いた plugin は、実際に `ctx.writePublicAsset()` を呼んだ時に 1 回だけ warn します。
295
+
276
296
  ### ベストプラクティス
277
297
 
278
298
  - **冪等にする**。SQS は at-least-once 配送 — 同じイベントが 2 回 fire する可能性があります。同じ入力で同じ出力 (決定論的なフィード等) を生成するようにしてください
@@ -467,6 +487,8 @@ it('admin が空文字保存した場合は空配列', () => {
467
487
  参考実装:
468
488
 
469
489
  - [`packages/plugin-analytics-ga4`](https://github.com/heavymoons/ampless/tree/main/packages/plugin-analytics-ga4) — descriptor ベース、Phase 2 settings
490
+ - [`packages/plugin-gtm`](https://github.com/heavymoons/ampless/tree/main/packages/plugin-gtm) — `publicHead`(ローダーインラインスクリプト)+ `publicBodyEnd`(`<noscript>` iframe フォールバック)を両方使用、コンテナ ID は admin 編集可能
491
+ - [`packages/plugin-plausible`](https://github.com/heavymoons/ampless/tree/main/packages/plugin-plausible) — `data-*` attrs 付きの単一 `<script>` descriptor、`required` な URL field(self-hosted Plausible 上書き対応)
470
492
  - [`packages/plugin-rss`](https://github.com/heavymoons/ampless/tree/main/packages/plugin-rss) — trusted、非同期 hooks + `writePublicAsset`
471
493
  - [`packages/plugin-seo`](https://github.com/heavymoons/ampless/tree/main/packages/plugin-seo) — `metadata()` + `siteMetadata()`
472
494
  - [`packages/plugin-webhook`](https://github.com/heavymoons/ampless/tree/main/packages/plugin-webhook) — untrusted hook + 外向き HTTP
@@ -168,7 +168,7 @@ touch IAM):
168
168
  | Tier | IAM | Used by |
169
169
  |---|---|---|
170
170
  | `untrusted` | none (SQS consume only) | head/body descriptors, webhook delivery, content transforms |
171
- | `trusted` | read posts, write `public/plugins/<name>/...` | RSS feed, sitemap, computed JSON indexes |
171
+ | `trusted` | read posts, write `public/plugins/<instanceId ?? name>/...` | RSS feed, sitemap, computed JSON indexes |
172
172
  | `privileged` | reserved | future: SES, secrets, private S3 |
173
173
 
174
174
  Rule of thumb:
@@ -332,6 +332,36 @@ hooks: {
332
332
  }
333
333
  ```
334
334
 
335
+ ### `writePublicAsset`
336
+
337
+ Trusted plugins that write public generated files should declare the
338
+ capability:
339
+
340
+ ```ts
341
+ capabilities: ['eventHooks', 'writePublicAsset']
342
+ ```
343
+
344
+ If the same plugin implements `metadata()` or `siteMetadata()`, also
345
+ declare `metadata`. That capability name covers both metadata
346
+ functions; there is no separate `siteMetadata` capability.
347
+
348
+ The trusted processor writes under:
349
+
350
+ ```txt
351
+ public/plugins/<instanceId ?? name>/<key>
352
+ ```
353
+
354
+ `key` must be a relative asset key. Empty strings, absolute paths,
355
+ `.` / `..` path segments, backslashes, control characters, and keys
356
+ over 256 characters are rejected before S3 is called. Nested paths
357
+ such as `indexes/posts.json` are allowed. The return value is the
358
+ public URL for the written object.
359
+
360
+ During the migration period, plugins with no `capabilities` field
361
+ keep working. Plugins that do declare `capabilities` but omit
362
+ `writePublicAsset` warn once when they actually call
363
+ `ctx.writePublicAsset()`.
364
+
335
365
  ### Best practices
336
366
 
337
367
  - **Be idempotent.** SQS delivery is at-least-once: the same event
@@ -575,6 +605,8 @@ a normal npm package:
575
605
  Worked examples to crib from:
576
606
 
577
607
  - [`packages/plugin-analytics-ga4`](https://github.com/heavymoons/ampless/tree/main/packages/plugin-analytics-ga4) — descriptor-based, Phase 2 settings.
608
+ - [`packages/plugin-gtm`](https://github.com/heavymoons/ampless/tree/main/packages/plugin-gtm) — uses both `publicHead` (loader inline script) and `publicBodyEnd` (`<noscript>` iframe fallback) with the container ID admin-edited.
609
+ - [`packages/plugin-plausible`](https://github.com/heavymoons/ampless/tree/main/packages/plugin-plausible) — single `<script>` descriptor with `data-*` attrs and a required URL field (self-hosted Plausible override).
578
610
  - [`packages/plugin-rss`](https://github.com/heavymoons/ampless/tree/main/packages/plugin-rss) — trusted, async event hooks + `writePublicAsset`.
579
611
  - [`packages/plugin-seo`](https://github.com/heavymoons/ampless/tree/main/packages/plugin-seo) — `metadata()` + `siteMetadata()`.
580
612
  - [`packages/plugin-webhook`](https://github.com/heavymoons/ampless/tree/main/packages/plugin-webhook) — untrusted hook with outbound HTTP.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ampless",
3
- "version": "1.0.0-alpha.18",
3
+ "version": "1.0.0-alpha.19",
4
4
  "description": "Serverless CMS for AWS Amplify",
5
5
  "license": "MIT",
6
6
  "type": "module",