ampless 1.0.0-beta.54 → 1.0.0-beta.56

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
@@ -1360,6 +1360,12 @@ interface AmplessPlugin {
1360
1360
  * capability.
1361
1361
  */
1362
1362
  publicPostScript?(post: Post, ctx: PluginPublicRenderContext): readonly PublicPostScriptDescriptor[];
1363
+ /**
1364
+ * Server-safe map of TipTap nodeType -> markdown serialiser, used by the
1365
+ * public runtime (postToMarkdown) — same shape the admin registry consumes.
1366
+ * Keep implementations free of '@tiptap/*' imports and 'use client'.
1367
+ */
1368
+ tiptapNodeToMarkdown?: TiptapNodeMarkdownAdapters;
1363
1369
  /**
1364
1370
  * Dynamic OG image renderer. The dispatcher route (e.g.
1365
1371
  * `app/og/[slug]/route.ts`) reads this and feeds the element into
@@ -1581,6 +1587,12 @@ interface Config {
1581
1587
  * those snapshots are retained.
1582
1588
  */
1583
1589
  history?: HistoryConfig;
1590
+ /**
1591
+ * AI-readable publishing switches (`/<slug>.md`, and future
1592
+ * `llms.txt` / public MCP surfaces). Each field defaults to its
1593
+ * documented value when the section is omitted.
1594
+ */
1595
+ ai?: AiConfig;
1584
1596
  }
1585
1597
  /**
1586
1598
  * Tunables for middleware-computed `Cache-Control`. See
@@ -1619,6 +1631,14 @@ interface HistoryConfig {
1619
1631
  */
1620
1632
  retentionDays?: number;
1621
1633
  }
1634
+ /**
1635
+ * AI-readable publishing switches. All features default to their
1636
+ * documented value when the section is omitted.
1637
+ */
1638
+ interface AiConfig {
1639
+ /** Serve the per-post markdown projection at `/<slug>.md`. Default: true. */
1640
+ markdownRoutes?: boolean;
1641
+ }
1622
1642
  type Role = 'reader' | 'editor' | 'admin';
1623
1643
  interface AuthContext {
1624
1644
  userId: string;
@@ -2060,4 +2080,4 @@ declare function pickDefaultEntrypoint(files: readonly {
2060
2080
 
2061
2081
  declare const VERSION = "0.0.1";
2062
2082
 
2063
- export { type AmplessEvent, type AmplessPlugin, type AuthContext, type BundleExtractResult, type CacheConfig, type CacheStrategy, type Config, type ContentEventPayload, type ContentEventType, type ContentFieldRenderer, 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 MarkdownEmbedMatch, 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 PostListFilterOptions, type PostListSort, type PostListStatusFilter, type PostMetadata, type PostRevision, type PostRevisionConnection, type PostStatus, type PostSummary, type PostsProvider, type PublicBodyDescriptor, type PublicHeadDescriptor, type PublicPostBodyDescriptor, type PublicPostHtmlDescriptor, type PublicPostHtmlPosition, type PublicPostScriptDescriptor, type Role, SITE_CONFIG_PK, type ScriptStrategy, type SiteSettingsEventPayload, type SiteSettingsEventType, type StaticPostBody, type StaticPostFileMeta, type StreamEventName, type SummaryListOptions, 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 TiptapNodeHtmlAdapters, type TiptapNodeMarkdownAdapters, type TiptapNodeToHtml, type TiptapNodeToMarkdown, type TiptapRenderNode, type TrustLevel, type TrustedPluginRuntimeContext, VERSION, type ValidationIssue, bundlePrefix, collectTags, createPost, decodeAwsJson, defineConfig, definePlugin, defineSchema, defineTheme, defineThemeModule, deletePost, deleteSiteSetting, detectContentEvents, encodeAwsJson, escapeXml, extractFirstImageUrl, filterSortPostSummaries, findAbsolutePathRefs, flattenSettings, formatColorPair, formatDate, formatPublicAssetUrl, getKvStore, getPost, getPostById, getSiteSetting, hasKvStore, hasPostsProvider, isTagListUrl, isValidPluginKey, listPostHistory, listPostSummaries, listPosts, listSiteSettings, mimeTypeFor, parseColorPair, parseLinkList, pickDefaultEntrypoint, resolveLocalized, resolvePluginSettings, resolveThemeValues, setKvStore, setPostsProvider, setSiteSetting, stringifyLinkList, stripCommonPrefix, themeSettingKey, unflattenSettings, updatePost, validateBundle, validateBundlePath, validatePluginSettingValue, validatePublicAssetKey, validateThemeValue };
2083
+ export { type AiConfig, type AmplessEvent, type AmplessPlugin, type AuthContext, type BundleExtractResult, type CacheConfig, type CacheStrategy, type Config, type ContentEventPayload, type ContentEventType, type ContentFieldRenderer, 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 MarkdownEmbedMatch, 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 PostListFilterOptions, type PostListSort, type PostListStatusFilter, type PostMetadata, type PostRevision, type PostRevisionConnection, type PostStatus, type PostSummary, type PostsProvider, type PublicBodyDescriptor, type PublicHeadDescriptor, type PublicPostBodyDescriptor, type PublicPostHtmlDescriptor, type PublicPostHtmlPosition, type PublicPostScriptDescriptor, type Role, SITE_CONFIG_PK, type ScriptStrategy, type SiteSettingsEventPayload, type SiteSettingsEventType, type StaticPostBody, type StaticPostFileMeta, type StreamEventName, type SummaryListOptions, 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 TiptapNodeHtmlAdapters, type TiptapNodeMarkdownAdapters, type TiptapNodeToHtml, type TiptapNodeToMarkdown, type TiptapRenderNode, type TrustLevel, type TrustedPluginRuntimeContext, VERSION, type ValidationIssue, bundlePrefix, collectTags, createPost, decodeAwsJson, defineConfig, definePlugin, defineSchema, defineTheme, defineThemeModule, deletePost, deleteSiteSetting, detectContentEvents, encodeAwsJson, escapeXml, extractFirstImageUrl, filterSortPostSummaries, findAbsolutePathRefs, flattenSettings, formatColorPair, formatDate, formatPublicAssetUrl, getKvStore, getPost, getPostById, getSiteSetting, hasKvStore, hasPostsProvider, isTagListUrl, isValidPluginKey, listPostHistory, listPostSummaries, 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
@@ -258,6 +258,16 @@ function definePlugin(p) {
258
258
  );
259
259
  }
260
260
  }
261
+ if (p.contentFields) {
262
+ for (const field of p.contentFields) {
263
+ if (field.kind !== "tiptap") continue;
264
+ if (typeof p.tiptapNodeToMarkdown?.[field.nodeType] !== "function") {
265
+ console.warn(
266
+ `[ampless] Plugin "${p.name}": contentFields declares tiptap nodeType "${field.nodeType}" but tiptapNodeToMarkdown has no adapter for it. The public runtime's markdown export will fall back to the default switch for this node. Add an adapter to tiptapNodeToMarkdown or ignore this if the fallback output is acceptable.`
267
+ );
268
+ }
269
+ }
270
+ }
261
271
  if (p.trust_level === "privileged") {
262
272
  const hasHooks = p.hooks && Object.keys(p.hooks).length > 0 || (p.capabilities?.includes("eventHooks") ?? false);
263
273
  if (hasHooks) {
@@ -186,6 +186,7 @@ interface AmplessPlugin {
186
186
  publicBodyEnd?(ctx): readonly PublicBodyDescriptor[]
187
187
  publicBodyForPost?(post: Post, ctx): readonly PublicPostBodyDescriptor[]
188
188
  publicHtmlForPost?(post: Post, ctx): readonly PublicPostHtmlDescriptor[]
189
+ tiptapNodeToMarkdown?: TiptapNodeMarkdownAdapters // server-safe markdown export adapters
189
190
  ogImage?: OgImageConfig
190
191
  settings?: {
191
192
  public?: readonly PluginSettingField[]
@@ -884,6 +885,48 @@ export function EditorBootstrap({ children }: { children: React.ReactNode }) {
884
885
  }
885
886
  ```
886
887
 
888
+ ### アダプターの置き場所: `./editor.tsx` ではなく `./adapters.ts`
889
+
890
+ `./editor.tsx` は `'use client'` かつ `@tiptap/core` を import している —
891
+ admin バンドルには問題ないが、server コード(や将来の `postToMarkdown`
892
+ public runtime)からこれを import すると両方を巻き込んでしまう。アダプター
893
+ (および `Node.renderHTML` と共有する `placeholderAttrs` のような plain
894
+ object ヘルパ)は、tiptap 非依存の別モジュール `./adapters.ts` に置き、
895
+ `./editor.tsx` からは 2 つの named symbol を **re-export** する:
896
+
897
+ ```ts
898
+ // packages/plugin-youtube/src/adapters.ts — 'use client' なし、@tiptap/* import なし
899
+ export const tiptapNodeToMarkdown: TiptapNodeMarkdownAdapters = { /* ... */ }
900
+ export const tiptapNodeToHtml: TiptapNodeHtmlAdapters = { /* ... */ }
901
+ ```
902
+
903
+ ```ts
904
+ // packages/plugin-youtube/src/editor.tsx
905
+ export { tiptapNodeToMarkdown, tiptapNodeToHtml } from './adapters.js'
906
+ ```
907
+
908
+ この re-export により `update-ampless` の codegen 契約は無改修で維持される
909
+ (下記「配線」の通り、`./editor` の namespace import から `ns.tiptapNodeToMarkdown ?? {}` /
910
+ `ns.tiptapNodeToHtml ?? {}` を読む挙動は変わらない)。同時に server 側
911
+ entry(`./index.tsx`)も同じアダプターを `./adapters.js` から import して
912
+ manifest に設定できる:
913
+
914
+ ```ts
915
+ // packages/plugin-youtube/src/index.tsx
916
+ import { tiptapNodeToMarkdown } from './adapters.js'
917
+
918
+ export default function youtubePlugin(opts = {}) {
919
+ return definePlugin({
920
+ // ...
921
+ tiptapNodeToMarkdown, // AmplessPlugin.tiptapNodeToMarkdown — server 側 canonical
922
+ })
923
+ }
924
+ ```
925
+
926
+ `definePlugin()` は `contentFields` の `kind: 'tiptap'` エントリの
927
+ `nodeType` に対応する `tiptapNodeToMarkdown` のキーが無い場合に warn する
928
+ — 両方をセットで宣言し、warning が出ない状態を保つ。
929
+
887
930
  ### フォーマット切り替えの可逆アダプター(`tiptapNodeToMarkdown` + `tiptapNodeToHtml`)
888
931
 
889
932
  operator が admin UI でポストのフォーマットを切り替える場合(例: `tiptap → markdown`、`tiptap → html`)、admin はボディコンテンツを変換する必要がある。通常の prose node は tiptap の built-in レンダラーで処理されるが、**atom node**(`amplessYoutube` のような embed ブロック)は子要素を持たず、children が空のまま fallthrough し、embed が無音で消えてしまう。
@@ -920,7 +963,7 @@ embed node を持つが `htmlPlaceholder` を**宣言しない** plugin は従
920
963
  **文字列**(空文字 `''` も含む)を返すと、その出力を使う。**`null`** を返すとデフォルトの switch へ fallthrough する(対応しない node や video id が欠損している場合などに使う)。
921
964
 
922
965
  ```ts
923
- // packages/plugin-youtube/src/editor.tsx
966
+ // packages/plugin-youtube/src/adapters.ts
924
967
  import type { TiptapNodeMarkdownAdapters, TiptapNodeHtmlAdapters } from 'ampless'
925
968
 
926
969
  export const tiptapNodeToMarkdown: TiptapNodeMarkdownAdapters = {
@@ -951,7 +994,7 @@ export const tiptapNodeToHtml: TiptapNodeHtmlAdapters = {
951
994
 
952
995
  #### 配線
953
996
 
954
- `update-ampless` が各プラグインの `./editor` モジュールから `tiptapNodeToMarkdown` と `tiptapNodeToHtml` の named export を読み取り(namespace import `* as` 経由)、両方の install に自動で配線する。**手動での配線は不要。** プラグインがいずれかのマップを export しない場合、生成ファイルの `?? {}` fallback が no-op になる。
997
+ `update-ampless` が各プラグインの `./editor` モジュールから `tiptapNodeToMarkdown` と `tiptapNodeToHtml` の named export を読み取り(namespace import `* as` 経由)、両方の install に自動で配線する。**手動での配線は不要。** プラグインがいずれかのマップを export しない場合、生成ファイルの `?? {}` fallback が no-op になる。上記の通り、`./editor` が re-export するこれらの export は通常 `./adapters.ts` に実装されている — codegen は `./editor` の namespace から到達可能であることだけを見ており、定義場所は問わない。
955
998
 
956
999
  #### `markdown → html` 2-hop
957
1000
 
@@ -214,6 +214,7 @@ interface AmplessPlugin {
214
214
  publicBodyEnd?(ctx): readonly PublicBodyDescriptor[]
215
215
  publicBodyForPost?(post: Post, ctx): readonly PublicPostBodyDescriptor[]
216
216
  publicHtmlForPost?(post: Post, ctx): readonly PublicPostHtmlDescriptor[]
217
+ tiptapNodeToMarkdown?: TiptapNodeMarkdownAdapters // server-safe markdown export adapters
217
218
  ogImage?: OgImageConfig
218
219
  settings?: {
219
220
  public?: readonly PluginSettingField[]
@@ -1142,6 +1143,48 @@ export function EditorBootstrap({ children }: { children: React.ReactNode }) {
1142
1143
  }
1143
1144
  ```
1144
1145
 
1146
+ ### Where the adapters live: `./adapters.ts`, not `./editor.tsx`
1147
+
1148
+ `./editor.tsx` carries `'use client'` and imports `@tiptap/core` — fine for
1149
+ the admin bundle, but importing it from server code (or the future
1150
+ `postToMarkdown` public runtime) would drag both along. Put the adapters
1151
+ (and any plain-object helpers they share with `Node.renderHTML`, like
1152
+ `placeholderAttrs`) in a separate, tiptap-free module — `./adapters.ts` —
1153
+ and have `./editor.tsx` **re-export** the two named symbols:
1154
+
1155
+ ```ts
1156
+ // packages/plugin-youtube/src/adapters.ts — no 'use client', no @tiptap/* import
1157
+ export const tiptapNodeToMarkdown: TiptapNodeMarkdownAdapters = { /* ... */ }
1158
+ export const tiptapNodeToHtml: TiptapNodeHtmlAdapters = { /* ... */ }
1159
+ ```
1160
+
1161
+ ```ts
1162
+ // packages/plugin-youtube/src/editor.tsx
1163
+ export { tiptapNodeToMarkdown, tiptapNodeToHtml } from './adapters.js'
1164
+ ```
1165
+
1166
+ The re-export keeps `update-ampless`'s codegen contract intact (it still
1167
+ reads `ns.tiptapNodeToMarkdown ?? {}` / `ns.tiptapNodeToHtml ?? {}` from a
1168
+ namespace import of `./editor` — see Wiring below) while also letting your
1169
+ server entry (`./index.tsx`) import the same adapter from `./adapters.js`
1170
+ and set it on the manifest:
1171
+
1172
+ ```ts
1173
+ // packages/plugin-youtube/src/index.tsx
1174
+ import { tiptapNodeToMarkdown } from './adapters.js'
1175
+
1176
+ export default function youtubePlugin(opts = {}) {
1177
+ return definePlugin({
1178
+ // ...
1179
+ tiptapNodeToMarkdown, // AmplessPlugin.tiptapNodeToMarkdown — server-side canonical
1180
+ })
1181
+ }
1182
+ ```
1183
+
1184
+ `definePlugin()` warns if a `contentFields` `kind: 'tiptap'` entry's
1185
+ `nodeType` has no matching key in `tiptapNodeToMarkdown` — declare both
1186
+ together so the warning stays silent.
1187
+
1145
1188
  ### Lossless format-switch adapters (`tiptapNodeToMarkdown` + `tiptapNodeToHtml`)
1146
1189
 
1147
1190
  When the operator switches the post format in the admin UI (e.g. `tiptap →
@@ -1206,7 +1249,7 @@ Return **`null`** to fall through to the default switch (useful for nodes
1206
1249
  you don't handle or for degenerate inputs like a missing video id).
1207
1250
 
1208
1251
  ```ts
1209
- // packages/plugin-youtube/src/editor.tsx
1252
+ // packages/plugin-youtube/src/adapters.ts
1210
1253
  import type { TiptapNodeMarkdownAdapters, TiptapNodeHtmlAdapters } from 'ampless'
1211
1254
 
1212
1255
  export const tiptapNodeToMarkdown: TiptapNodeMarkdownAdapters = {
@@ -1244,7 +1287,10 @@ export const tiptapNodeToHtml: TiptapNodeHtmlAdapters = {
1244
1287
  named exports from each plugin's `./editor` module (via namespace import `*
1245
1288
  as`) and wires them into both installs automatically — **no hand-wiring
1246
1289
  required**. If your plugin does not export one of the maps, the `?? {}`
1247
- fallback in the generated file is a no-op.
1290
+ fallback in the generated file is a no-op. As noted above, the exports
1291
+ `./editor` re-exports normally live in `./adapters.ts` — the codegen only
1292
+ cares that they're reachable from the `./editor` namespace, not where
1293
+ they're defined.
1248
1294
 
1249
1295
  #### `markdown → html` 2-hop
1250
1296
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ampless",
3
- "version": "1.0.0-beta.54",
3
+ "version": "1.0.0-beta.56",
4
4
  "description": "Serverless CMS for AWS Amplify",
5
5
  "license": "MIT",
6
6
  "type": "module",