ampless 1.0.0-alpha.37 → 1.0.0-alpha.39

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
@@ -973,7 +973,13 @@ interface PluginSettingsManifest {
973
973
  }
974
974
  interface AmplessPlugin {
975
975
  name: string;
976
- /** Plugin API version. Currently 1; future versions will be additive. */
976
+ /**
977
+ * Plugin API version. Currently `1` is the only supported value.
978
+ * `apiVersion` is the breaking-change marker on the plugin contract;
979
+ * additive changes (new optional fields, new reserved capabilities)
980
+ * stay within `apiVersion: 1`. See the apiVersion bump policy in
981
+ * `docs/architecture/08-plugin-architecture.md` for the full criteria.
982
+ */
977
983
  apiVersion: 1;
978
984
  /**
979
985
  * Optional npm package name (e.g. `'@scope/ampless-plugin-foo'` or
@@ -1361,6 +1367,12 @@ interface Config {
1361
1367
  * field is absent.
1362
1368
  */
1363
1369
  cache?: CacheConfig;
1370
+ /**
1371
+ * Post revision-history knobs. The event-dispatcher Lambda snapshots
1372
+ * each post save into the `PostHistory` table; this controls how long
1373
+ * those snapshots are retained.
1374
+ */
1375
+ history?: HistoryConfig;
1364
1376
  }
1365
1377
  /**
1366
1378
  * Tunables for middleware-computed `Cache-Control`. See
@@ -1385,6 +1397,20 @@ interface CacheConfig {
1385
1397
  */
1386
1398
  deepTtlSeconds?: number;
1387
1399
  }
1400
+ /**
1401
+ * Post revision-history tunables, read by the event-dispatcher Lambda
1402
+ * (via the template shell) when snapshotting each post save.
1403
+ */
1404
+ interface HistoryConfig {
1405
+ /**
1406
+ * Days to retain each post revision before DynamoDB TTL deletes it.
1407
+ * Default 0 = keep forever (no `ttl` attribute is written). DynamoDB TTL
1408
+ * deletes within ~48h after expiry, so effective retention is
1409
+ * retentionDays + up to ~2 days. Changing this only affects revisions
1410
+ * written afterward — existing rows keep their original expiry.
1411
+ */
1412
+ retentionDays?: number;
1413
+ }
1388
1414
  type Role = 'reader' | 'editor' | 'admin';
1389
1415
  interface AuthContext {
1390
1416
  userId: string;
@@ -1415,6 +1441,45 @@ interface ListOptions {
1415
1441
  type CreatePostInput = Omit<Post, 'postId'> & {
1416
1442
  postId?: string;
1417
1443
  };
1444
+ /**
1445
+ * One in-memory snapshot of a Post at save time, read back from the
1446
+ * `PostHistory` table (written by the event-dispatcher Lambda on each
1447
+ * Post INSERT/MODIFY — see packages/backend/src/events/dispatcher.ts).
1448
+ *
1449
+ * `body` is already decoded from its AWSJSON wire form (the provider
1450
+ * runs `decodeAwsJson` before handing the row up), so it matches the
1451
+ * `Post['body']` shape for the declared `format`.
1452
+ */
1453
+ interface PostRevision {
1454
+ /** Deterministic id `${postId}#${revisedAt}` — unique per save. */
1455
+ postHistoryId: string;
1456
+ postId: string;
1457
+ /** ISO 8601 save time. Also the `byPost` GSI sort key (newest-first). */
1458
+ revisedAt: string;
1459
+ title?: string;
1460
+ slug?: string;
1461
+ excerpt?: string;
1462
+ format?: ContentFormat;
1463
+ body?: unknown;
1464
+ status?: PostStatus;
1465
+ publishedAt?: string;
1466
+ tags?: string[];
1467
+ metadata?: PostMetadata;
1468
+ }
1469
+ /** Pagination options for `listPostHistory`. */
1470
+ interface ListPostHistoryOptions {
1471
+ limit?: number;
1472
+ nextToken?: string;
1473
+ }
1474
+ /**
1475
+ * A page of revisions newest-first. `nextToken` feeds straight back into
1476
+ * `ListPostHistoryOptions.nextToken` for the next page; `undefined` means
1477
+ * no more rows.
1478
+ */
1479
+ interface PostRevisionConnection {
1480
+ items: PostRevision[];
1481
+ nextToken?: string;
1482
+ }
1418
1483
  interface PostsProvider {
1419
1484
  list(opts?: ListOptions): Promise<Post[]>;
1420
1485
  get(slug: string): Promise<Post | null>;
@@ -1422,6 +1487,7 @@ interface PostsProvider {
1422
1487
  create(data: CreatePostInput): Promise<Post>;
1423
1488
  update(postId: string, data: Partial<Post>): Promise<Post>;
1424
1489
  remove(postId: string): Promise<void>;
1490
+ listPostHistory(postId: string, options?: ListPostHistoryOptions): Promise<PostRevisionConnection>;
1425
1491
  }
1426
1492
  declare function setPostsProvider(p: PostsProvider): void;
1427
1493
  declare function hasPostsProvider(): boolean;
@@ -1431,6 +1497,13 @@ declare function getPostById(postId: string): Promise<Post | null>;
1431
1497
  declare function createPost(data: CreatePostInput): Promise<Post>;
1432
1498
  declare function updatePost(postId: string, data: Partial<Post>): Promise<Post>;
1433
1499
  declare function deletePost(postId: string): Promise<void>;
1500
+ /**
1501
+ * List a post's revision history, newest-first. Backed by the
1502
+ * `PostHistory` `byPost` GSI. Requires a configured provider (the dummy
1503
+ * fallback has no history) — returns an empty connection otherwise so
1504
+ * callers (e.g. the admin history panel) degrade gracefully.
1505
+ */
1506
+ declare function listPostHistory(postId: string, options?: ListPostHistoryOptions): Promise<PostRevisionConnection>;
1434
1507
 
1435
1508
  interface KvItem<T = unknown> {
1436
1509
  pk: string;
@@ -1693,4 +1766,4 @@ declare function pickDefaultEntrypoint(files: readonly {
1693
1766
 
1694
1767
  declare const VERSION = "0.0.1";
1695
1768
 
1696
- 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 PluginHookResult, type PluginJsonField, type PluginMetadata, type PluginNumberField, type PluginPackageManifest, type PluginPublicRenderContext, type PluginRepeatableField, type PluginRepeatableSubField, type PluginRuntimeContext, type PluginSecretField, type PluginSelectField, type PluginSettingField, type PluginSettingsManifest, type PluginTextField, type PluginTextareaField, type PluginUninstallContext, type PluginUrlField, type Post, type PostIndexEventPayload, type PostIndexEventType, type PostMetadata, type PostStatus, type PostsProvider, type PublicBodyDescriptor, type PublicHeadDescriptor, type PublicPostBodyDescriptor, type PublicPostHtmlDescriptor, type PublicPostHtmlPosition, 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, type TrustedPluginRuntimeContext, 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 };
1769
+ 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 HistoryConfig, type ImageDisplay, type KvItem, type KvStore, type LinkListItem, type ListOptions, type ListPostHistoryOptions, 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 PluginHookResult, type PluginJsonField, type PluginMetadata, type PluginNumberField, type PluginPackageManifest, type PluginPublicRenderContext, type PluginRepeatableField, type PluginRepeatableSubField, type PluginRuntimeContext, type PluginSecretField, type PluginSelectField, type PluginSettingField, type PluginSettingsManifest, type PluginTextField, type PluginTextareaField, type PluginUninstallContext, type PluginUrlField, type Post, type PostIndexEventPayload, type PostIndexEventType, type PostMetadata, type PostRevision, type PostRevisionConnection, type PostStatus, type PostsProvider, type PublicBodyDescriptor, type PublicHeadDescriptor, type PublicPostBodyDescriptor, type PublicPostHtmlDescriptor, type PublicPostHtmlPosition, 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, type TrustedPluginRuntimeContext, 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, listPostHistory, 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
@@ -83,6 +83,10 @@ async function deletePost(postId) {
83
83
  if (!provider) throw new Error("No posts provider configured. Call setPostsProvider() first.");
84
84
  return provider.remove(postId);
85
85
  }
86
+ async function listPostHistory(postId, options) {
87
+ if (!provider) return { items: [] };
88
+ return provider.listPostHistory(postId, options);
89
+ }
86
90
 
87
91
  // src/kv.ts
88
92
  var store = null;
@@ -794,6 +798,7 @@ export {
794
798
  hasPostsProvider,
795
799
  isTagListUrl,
796
800
  isValidPluginKey,
801
+ listPostHistory,
797
802
  listPosts,
798
803
  listSiteSettings,
799
804
  mimeTypeFor,
@@ -172,7 +172,7 @@ export default defineConfig({
172
172
  interface AmplessPlugin {
173
173
  name: string // パッケージ風の識別子。例: 'analytics-ga4'
174
174
  packageName?: string // インストール時のクロスチェック用 npm パッケージ名
175
- apiVersion: 1 // 契約が変わるときだけ bump
175
+ apiVersion: 1 // 現状唯一の有効値
176
176
  trust_level: 'untrusted' | 'trusted' | 'privileged'
177
177
  instanceId?: string // 複数インストール時の namespace
178
178
  displayName?: LocalizedString // admin UI ラベル
@@ -201,6 +201,12 @@ interface AmplessPlugin {
201
201
 
202
202
  今日は 1 のみ。将来の互換性破壊バージョンが出たらこの数字が bump され、runtime は未知の値を黙って bind せず拒否します。
203
203
 
204
+ **現状唯一の有効値は `apiVersion: 1` です。** literal type は他の値を compile-time に拒否し、`package.json#amplessPlugin.apiVersion` が `definePlugin()` の戻り値と異なる場合、または runtime の `SUPPORTED_API_VERSION` を超える場合、runtime は hard-throw します。
205
+
206
+ Phase 1 の compat-break reservation すべて(PR #220、#222、#230、#232、#234)は `apiVersion: 1` 内に収まります。これらをプラグインで declare するかどうかは契約バージョンに影響しません。
207
+
208
+ 将来 `apiVersion: 2` が導入される場合は、changeset とこのガイドおよび architecture doc のセクション更新を通じてアナウンスされます。それまでは、**`apiVersion: 1` でプラグインを publish し、唯一の有効値として扱ってください**。v2 bump の trigger となるもの(ならないもの)の全基準については、architecture doc の [apiVersion bump policy](https://github.com/heavymoons/ampless/blob/main/docs/architecture/08-plugin-architecture.md#apiversion-bump-policy) セクションを参照してください。
209
+
204
210
  ### `instanceId`
205
211
 
206
212
  optional、デフォルトは `name`。同じプラグインを 1 サイトで複数 instance 動かせる作り (例: 2 つの GA4 measurement ID、チャットプラットフォーム毎の webhook) では、ホストに `instanceId` を指定させて各々独立した namespace を持たせる:
@@ -1218,7 +1224,7 @@ it('admin が空文字保存した場合は空配列', () => {
1218
1224
 
1219
1225
  - **パッケージ名**: `@your-scope/plugin-foo`。`@ampless/plugin-*` スコープは本モノレポから ship する公式プラグイン用に予約
1220
1226
  - **エントリ**: ESM のみ、default export (factory) + 設定インターフェイス (ユーザの `cms.config.ts` から型付きで引数を渡せるように) を export
1221
- - **`apiVersion`**: 契約が変わるときだけ bump。既存フィールドの型が変わったら major、新フィールド追加なら minor (既存インストールは動き続ける)
1227
+ - **`apiVersion`**: 現状は `1` を declare してください — 唯一の有効値で、literal type が他の値を compile-time に reject します。`apiVersion` はプラグイン契約の **breaking-change marker** であって semver 風のチャンネルではありません。additive な追加 (optional field、reserved capability など) は `apiVersion: 1` 内に収まり、bump は不要です。詳細は architecture doc の [apiVersion bump policy](https://github.com/heavymoons/ampless/blob/main/docs/architecture/08-plugin-architecture.md#apiversion-bump-policy) を参照
1222
1228
  - **Dist-tag**: ampless 自体が alpha のうちは `@alpha`。`@latest` は ampless v1.0 まで予約
1223
1229
 
1224
1230
  参考実装:
@@ -200,7 +200,7 @@ That's it. Restart `npm run dev`, view source on any page, and the
200
200
  interface AmplessPlugin {
201
201
  name: string // package-like identifier, e.g. 'analytics-ga4'
202
202
  packageName?: string // npm package name for install-time cross-check
203
- apiVersion: 1 // bump only when the contract changes
203
+ apiVersion: 1 // the only valid value today
204
204
  trust_level: 'untrusted' | 'trusted' | 'privileged'
205
205
  instanceId?: string // namespace for multi-instance installs
206
206
  displayName?: LocalizedString // admin UI label
@@ -234,6 +234,23 @@ There's only one version today. Future breaking-change versions will
234
234
  bump this number; the runtime rejects unknown values rather than
235
235
  silently mis-binding.
236
236
 
237
+ **Today only `apiVersion: 1` is valid.** The literal type accepts
238
+ no other value, and the runtime hard-throws if `package.json#amplessPlugin.apiVersion`
239
+ disagrees with what `definePlugin()` returns or exceeds the runtime's
240
+ `SUPPORTED_API_VERSION`.
241
+
242
+ All Phase 1 compat-break reservations (PRs #220, #222, #230, #232,
243
+ #234) live within `apiVersion: 1` — declaring or not declaring them
244
+ in your plugin does not affect the contract version.
245
+
246
+ If a future `apiVersion: 2` is ever introduced, it will be announced
247
+ through a changeset and a section update in this guide and the
248
+ architecture doc. Until then, **publish your plugin with
249
+ `apiVersion: 1` and treat it as the only valid value**. See the
250
+ [apiVersion bump policy](https://github.com/heavymoons/ampless/blob/main/docs/architecture/08-plugin-architecture.md#apiversion-bump-policy)
251
+ section in the architecture doc for the full criteria around what
252
+ would (and would not) trigger a v2 bump.
253
+
237
254
  ### `instanceId`
238
255
 
239
256
  Optional, defaults to `name`. When you ship a plugin that can run
@@ -1641,9 +1658,14 @@ a normal npm package:
1641
1658
  monorepo.
1642
1659
  - **Entry**: ESM only, exports default (the factory) and the
1643
1660
  config interface (for typed args in user `cms.config.ts`).
1644
- - **`apiVersion`**: bump only when the contract changes. Bump
1645
- major when an existing field's type changes; bump minor when you
1646
- add a new field (existing installs keep working).
1661
+ - **`apiVersion`**: declare `1` today — it is the only valid
1662
+ value, and the literal type rejects others at compile time.
1663
+ `apiVersion` is the breaking-change marker on the plugin
1664
+ contract, not a semver-style channel: additive changes (new
1665
+ optional fields, new reserved capabilities) stay within
1666
+ `apiVersion: 1` and do NOT require a bump. See the [apiVersion
1667
+ bump policy](https://github.com/heavymoons/ampless/blob/main/docs/architecture/08-plugin-architecture.md#apiversion-bump-policy)
1668
+ in the architecture doc for the full criteria.
1647
1669
  - **Dist-tag**: `@alpha` while ampless itself is in alpha. The
1648
1670
  `@latest` tag stays reserved until ampless v1.0.
1649
1671
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ampless",
3
- "version": "1.0.0-alpha.37",
3
+ "version": "1.0.0-alpha.39",
4
4
  "description": "Serverless CMS for AWS Amplify",
5
5
  "license": "MIT",
6
6
  "type": "module",