ampless 1.0.0-alpha.48 → 1.0.0-alpha.50

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
@@ -1681,6 +1681,34 @@ interface PostRevisionConnection {
1681
1681
  items: PostRevision[];
1682
1682
  nextToken?: string;
1683
1683
  }
1684
+ /**
1685
+ * Lightweight row for admin list views — excludes body / metadata.
1686
+ * Body fields (tiptap JSON, markdown source, etc.) can be tens of KB per post;
1687
+ * projecting them out cuts per-post transfer size by 90%+ at scale.
1688
+ *
1689
+ * For list views that only need title / slug / status / dates / tags,
1690
+ * use `listPostSummaries` instead of `listPosts`.
1691
+ *
1692
+ * Scale note: for single-site blogs (hundreds to low thousands of posts),
1693
+ * full client-side fetch + sort/search is fast and eliminates GSI complexity.
1694
+ * If a site grows to many thousands of posts, revisit with a
1695
+ * (status, updatedAt) GSI + server-side pagination.
1696
+ */
1697
+ interface PostSummary {
1698
+ postId: string;
1699
+ slug: string;
1700
+ title: string;
1701
+ excerpt?: string;
1702
+ status: 'draft' | 'published';
1703
+ publishedAt?: string;
1704
+ updatedAt?: string;
1705
+ tags: string[];
1706
+ }
1707
+ /** Options for `listPostSummaries`. */
1708
+ interface SummaryListOptions {
1709
+ /** default 'all' */
1710
+ status?: 'draft' | 'published' | 'all';
1711
+ }
1684
1712
  interface PostsProvider {
1685
1713
  list(opts?: ListOptions): Promise<Post[]>;
1686
1714
  get(slug: string): Promise<Post | null>;
@@ -1689,6 +1717,17 @@ interface PostsProvider {
1689
1717
  update(postId: string, data: Partial<Post>): Promise<Post>;
1690
1718
  remove(postId: string): Promise<void>;
1691
1719
  listPostHistory(postId: string, options?: ListPostHistoryOptions): Promise<PostRevisionConnection>;
1720
+ /**
1721
+ * Return lightweight summaries for all posts (no body / metadata).
1722
+ * Implementations MUST page through all nextToken values to return the
1723
+ * complete list — the admin list view depends on this for accurate search
1724
+ * and sort.
1725
+ *
1726
+ * Optional: providers that do not implement this fall back to a best-effort
1727
+ * single-page result via `list()` (see `listPostSummaries` fallback path).
1728
+ * The admin provider always implements this.
1729
+ */
1730
+ listSummaries?(opts?: SummaryListOptions): Promise<PostSummary[]>;
1692
1731
  }
1693
1732
  declare function setPostsProvider(p: PostsProvider): void;
1694
1733
  declare function hasPostsProvider(): boolean;
@@ -1705,6 +1744,23 @@ declare function deletePost(postId: string): Promise<void>;
1705
1744
  * callers (e.g. the admin history panel) degrade gracefully.
1706
1745
  */
1707
1746
  declare function listPostHistory(postId: string, options?: ListPostHistoryOptions): Promise<PostRevisionConnection>;
1747
+ /**
1748
+ * Return lightweight summaries for all posts (no body / metadata).
1749
+ *
1750
+ * Delegates to `provider.listSummaries()` when available — the admin
1751
+ * provider implements this with a full nextToken loop and selectionSet
1752
+ * projection, ensuring all posts are returned without fetching large body
1753
+ * fields.
1754
+ *
1755
+ * **Fallback**: if the configured provider does not implement `listSummaries`,
1756
+ * falls back to a single page from `provider.list({ status })`. This is
1757
+ * best-effort only — it returns at most one page of results (no pagination).
1758
+ * Providers that need complete summary lists MUST implement `listSummaries`.
1759
+ * A `console.warn` is emitted once to make this visible.
1760
+ *
1761
+ * If no provider is configured, maps DUMMY_POSTS to summaries.
1762
+ */
1763
+ declare function listPostSummaries(opts?: SummaryListOptions): Promise<PostSummary[]>;
1708
1764
 
1709
1765
  interface KvItem<T = unknown> {
1710
1766
  pk: string;
@@ -1877,6 +1933,17 @@ declare function resolvePluginSettings(manifest: PluginSettingsManifest | undefi
1877
1933
  */
1878
1934
  declare function extractFirstImageUrl(post: Post): string | null;
1879
1935
 
1936
+ type PostListStatusFilter = 'all' | 'draft' | 'published';
1937
+ type PostListSort = 'updated-desc' | 'updated-asc' | 'published-desc' | 'published-asc' | 'title-asc' | 'title-desc';
1938
+ interface PostListFilterOptions {
1939
+ query?: string;
1940
+ status?: PostListStatusFilter;
1941
+ tag?: string;
1942
+ sort?: PostListSort;
1943
+ }
1944
+ declare function filterSortPostSummaries<T extends PostSummary>(rows: readonly T[], options?: PostListFilterOptions): T[];
1945
+ declare function collectTags(rows: readonly PostSummary[]): Map<string, number>;
1946
+
1880
1947
  /**
1881
1948
  * Pure helpers for `format: 'static'` post bundles. Kept platform-free
1882
1949
  * (no `File`, no Amplify Storage, no AWS SDK) so both the browser admin
@@ -1967,4 +2034,4 @@ declare function pickDefaultEntrypoint(files: readonly {
1967
2034
 
1968
2035
  declare const VERSION = "0.0.1";
1969
2036
 
1970
- 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 PostMetadata, type PostRevision, type PostRevisionConnection, type PostStatus, 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, 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, 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 };
2037
+ 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 };
package/dist/index.js CHANGED
@@ -47,6 +47,7 @@ var DUMMY_POSTS = [
47
47
 
48
48
  // src/core.ts
49
49
  var provider = null;
50
+ var warnedSummaryFallback = false;
50
51
  function setPostsProvider(p) {
51
52
  provider = p;
52
53
  }
@@ -87,6 +88,35 @@ async function listPostHistory(postId, options) {
87
88
  if (!provider) return { items: [] };
88
89
  return provider.listPostHistory(postId, options);
89
90
  }
91
+ async function listPostSummaries(opts) {
92
+ const status = opts?.status ?? "all";
93
+ if (!provider) {
94
+ return dummyList({ status }).map(postToSummary);
95
+ }
96
+ if (provider.listSummaries) {
97
+ return provider.listSummaries(opts);
98
+ }
99
+ if (!warnedSummaryFallback) {
100
+ warnedSummaryFallback = true;
101
+ console.warn(
102
+ "[ampless] listPostSummaries: provider does not implement listSummaries; falling back to a single-page best-effort via list(). Complete listings require the provider to implement listSummaries."
103
+ );
104
+ }
105
+ const posts = await provider.list({ status });
106
+ return posts.map(postToSummary);
107
+ }
108
+ function postToSummary(p) {
109
+ return {
110
+ postId: p.postId,
111
+ slug: p.slug,
112
+ title: p.title,
113
+ excerpt: p.excerpt,
114
+ status: p.status,
115
+ publishedAt: p.publishedAt,
116
+ updatedAt: p.updatedAt,
117
+ tags: p.tags ?? []
118
+ };
119
+ }
90
120
 
91
121
  // src/kv.ts
92
122
  var store = null;
@@ -461,6 +491,53 @@ function findHtmlImage(body) {
461
491
  return m ? m[1] : null;
462
492
  }
463
493
 
494
+ // src/post-list-filter.ts
495
+ function filterSortPostSummaries(rows, options = {}) {
496
+ const query = options.query?.trim().toLowerCase() ?? "";
497
+ const status = options.status ?? "all";
498
+ const tag = options.tag ?? "";
499
+ const sort = options.sort ?? "updated-desc";
500
+ return rows.filter((row) => {
501
+ if (status !== "all" && row.status !== status) return false;
502
+ if (tag && !row.tags.includes(tag)) return false;
503
+ if (!query) return true;
504
+ return row.title.toLowerCase().includes(query) || row.slug.toLowerCase().includes(query) || row.tags.some((t) => t.toLowerCase().includes(query));
505
+ }).sort((a, b) => compareRows(a, b, sort));
506
+ }
507
+ function collectTags(rows) {
508
+ const counts = /* @__PURE__ */ new Map();
509
+ for (const row of rows) {
510
+ for (const tag of row.tags) {
511
+ const trimmed = tag.trim();
512
+ if (!trimmed) continue;
513
+ counts.set(trimmed, (counts.get(trimmed) ?? 0) + 1);
514
+ }
515
+ }
516
+ return new Map([...counts.entries()].sort(([a], [b]) => a.localeCompare(b)));
517
+ }
518
+ function compareRows(a, b, sort) {
519
+ switch (sort) {
520
+ case "updated-asc":
521
+ return compareOptionalIso(a.updatedAt, b.updatedAt, "asc");
522
+ case "updated-desc":
523
+ return compareOptionalIso(a.updatedAt, b.updatedAt, "desc");
524
+ case "published-asc":
525
+ return compareOptionalIso(a.publishedAt, b.publishedAt, "asc");
526
+ case "published-desc":
527
+ return compareOptionalIso(a.publishedAt, b.publishedAt, "desc");
528
+ case "title-desc":
529
+ return b.title.localeCompare(a.title);
530
+ case "title-asc":
531
+ return a.title.localeCompare(b.title);
532
+ }
533
+ }
534
+ function compareOptionalIso(a, b, direction) {
535
+ if (!a && !b) return 0;
536
+ if (!a) return 1;
537
+ if (!b) return -1;
538
+ return direction === "asc" ? a.localeCompare(b) : b.localeCompare(a);
539
+ }
540
+
464
541
  // src/static-bundle.ts
465
542
  var DEFAULT_ENTRYPOINT = "index.html";
466
543
  var MAX_BUNDLE_BYTES = 50 * 1024 * 1024;
@@ -772,6 +849,7 @@ export {
772
849
  TEXT_EXTENSIONS,
773
850
  VERSION,
774
851
  bundlePrefix,
852
+ collectTags,
775
853
  createPost,
776
854
  decodeAwsJson,
777
855
  defineConfig,
@@ -785,6 +863,7 @@ export {
785
863
  encodeAwsJson,
786
864
  escapeXml,
787
865
  extractFirstImageUrl,
866
+ filterSortPostSummaries,
788
867
  findAbsolutePathRefs,
789
868
  flattenSettings,
790
869
  formatColorPair,
@@ -799,6 +878,7 @@ export {
799
878
  isTagListUrl,
800
879
  isValidPluginKey,
801
880
  listPostHistory,
881
+ listPostSummaries,
802
882
  listPosts,
803
883
  listSiteSettings,
804
884
  mimeTypeFor,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ampless",
3
- "version": "1.0.0-alpha.48",
3
+ "version": "1.0.0-alpha.50",
4
4
  "description": "Serverless CMS for AWS Amplify",
5
5
  "license": "MIT",
6
6
  "type": "module",