ampless 0.2.0-alpha.7 → 1.0.0-alpha.10
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 +184 -133
- package/dist/index.js +160 -65
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -4,7 +4,6 @@ type SiteSettingsEventType = 'site.settings.updated';
|
|
|
4
4
|
type EventType = ContentEventType | MediaEventType | SiteSettingsEventType;
|
|
5
5
|
/** Minimal projection of a Post item carried in events (no body, to keep payloads small). */
|
|
6
6
|
interface ContentEventPayload {
|
|
7
|
-
siteId: string;
|
|
8
7
|
postId: string;
|
|
9
8
|
slug: string;
|
|
10
9
|
title: string;
|
|
@@ -13,18 +12,16 @@ interface ContentEventPayload {
|
|
|
13
12
|
tags?: string[];
|
|
14
13
|
}
|
|
15
14
|
interface MediaEventPayload {
|
|
16
|
-
siteId: string;
|
|
17
15
|
mediaId: string;
|
|
18
16
|
src: string;
|
|
19
17
|
mimeType: string;
|
|
20
18
|
}
|
|
21
19
|
/**
|
|
22
|
-
* Emitted whenever any setting under `siteconfig
|
|
23
|
-
*
|
|
24
|
-
*
|
|
20
|
+
* Emitted whenever any setting under the `siteconfig:` PK in KvStore is
|
|
21
|
+
* created, updated, or removed. Subscribers (built-in or user plugins)
|
|
22
|
+
* can rebuild caches, theme assets, etc.
|
|
25
23
|
*/
|
|
26
24
|
interface SiteSettingsEventPayload {
|
|
27
|
-
siteId: string;
|
|
28
25
|
}
|
|
29
26
|
type EventPayloadOf<T extends EventType> = T extends ContentEventType ? ContentEventPayload : T extends MediaEventType ? MediaEventPayload : T extends SiteSettingsEventType ? SiteSettingsEventPayload : never;
|
|
30
27
|
interface AmplessEvent<T extends EventType = EventType> {
|
|
@@ -89,13 +86,12 @@ type PluginEventHandler<T extends EventType = EventType> = (event: AmplessEvent<
|
|
|
89
86
|
* (sandbox, tests) without touching plugin code.
|
|
90
87
|
*/
|
|
91
88
|
interface PluginRuntimeContext {
|
|
92
|
-
siteId: string;
|
|
93
89
|
/** Read-only view of the cms.config site block (name, url, description). */
|
|
94
90
|
site: Config['site'];
|
|
95
|
-
/** Read all published posts
|
|
91
|
+
/** Read all published posts (used by sitemap/RSS). */
|
|
96
92
|
listPublishedPosts(): Promise<Post[]>;
|
|
97
93
|
/**
|
|
98
|
-
* Persist a file under `public/plugins/{pluginName}/{key}` in the
|
|
94
|
+
* Persist a file under `public/plugins/{pluginName}/{key}` in the
|
|
99
95
|
* S3 bucket. Returns the public URL.
|
|
100
96
|
*/
|
|
101
97
|
writePublicAsset(key: string, body: string | Uint8Array, contentType: string): Promise<string>;
|
|
@@ -157,9 +153,9 @@ interface AmplessPlugin {
|
|
|
157
153
|
siteMetadata?(site: Config['site']): PluginMetadata;
|
|
158
154
|
/**
|
|
159
155
|
* Dynamic OG image renderer. The dispatcher route (e.g.
|
|
160
|
-
* `app/
|
|
161
|
-
*
|
|
162
|
-
*
|
|
156
|
+
* `app/og/[slug]/route.ts`) reads this and feeds the element into
|
|
157
|
+
* Next.js `ImageResponse`. Only one plugin should set this — the
|
|
158
|
+
* route resolves the first plugin in `cms.config.plugins` that
|
|
163
159
|
* declares `ogImage`.
|
|
164
160
|
*/
|
|
165
161
|
ogImage?: OgImageConfig;
|
|
@@ -169,9 +165,9 @@ declare function definePlugin(p: AmplessPlugin): AmplessPlugin;
|
|
|
169
165
|
type ContentFormat = 'tiptap' | 'markdown' | 'html' | 'static';
|
|
170
166
|
/**
|
|
171
167
|
* Body shape for `format: 'static'` posts. The actual asset bytes
|
|
172
|
-
* live under S3 at `public/static/<
|
|
173
|
-
*
|
|
174
|
-
*
|
|
168
|
+
* live under S3 at `public/static/<slug>/<files...>` — the body here
|
|
169
|
+
* is the manifest describing which entrypoint to serve and which files
|
|
170
|
+
* are part of the bundle.
|
|
175
171
|
*
|
|
176
172
|
* Stored as JSON in the `body` column (same encoding pattern as the
|
|
177
173
|
* tiptap doc / html string / markdown string for the other formats).
|
|
@@ -192,6 +188,22 @@ interface StaticPostBody {
|
|
|
192
188
|
uploadedAt: string;
|
|
193
189
|
}
|
|
194
190
|
type PostStatus = 'draft' | 'published';
|
|
191
|
+
/**
|
|
192
|
+
* Per-post cache strategy. Middleware computes the response's
|
|
193
|
+
* Cache-Control header from this value (plus `post.updatedAt` for the
|
|
194
|
+
* `auto` case and the project's `cms.config.cache.*` knobs).
|
|
195
|
+
*
|
|
196
|
+
* - `'auto'` (default): cooldown by edit time. Posts updated within
|
|
197
|
+
* the cooldown window (`cms.config.cache.cooldownMs`, default 1h)
|
|
198
|
+
* emit a no-store header so editors see fresh content immediately.
|
|
199
|
+
* Older posts emit a long s-maxage so the CDN serves them cheaply.
|
|
200
|
+
* - `'deep'`: always long-cache (`cms.config.cache.deepTtlSeconds`,
|
|
201
|
+
* default 1h). Use for posts whose content is fixed for the
|
|
202
|
+
* foreseeable future.
|
|
203
|
+
* - `'hot'`: always no-store. Use for posts whose content is rapidly
|
|
204
|
+
* evolving or computed per request.
|
|
205
|
+
*/
|
|
206
|
+
type CacheStrategy = 'auto' | 'deep' | 'hot';
|
|
195
207
|
/**
|
|
196
208
|
* Free-form per-post metadata. The `metadata` JSON column carries
|
|
197
209
|
* arbitrary key/value pairs; the runtime / themes / plugins each pick
|
|
@@ -200,8 +212,13 @@ type PostStatus = 'draft' | 'published';
|
|
|
200
212
|
*
|
|
201
213
|
* Well-known keys:
|
|
202
214
|
* - `no_layout`: when true, the public page is served as bare HTML
|
|
203
|
-
* (no theme chrome).
|
|
204
|
-
*
|
|
215
|
+
* (no theme chrome). Middleware rewrites the request to the
|
|
216
|
+
* unified internal route handler (`/r/<slug>`) for such posts
|
|
217
|
+
* and renders the body verbatim — no Next.js root layout, no
|
|
218
|
+
* theme chrome.
|
|
219
|
+
* - `cache`: see `CacheStrategy`. Overrides the default 'auto'
|
|
220
|
+
* cache strategy for this post. Independent of `no_layout` —
|
|
221
|
+
* applies uniformly to themed, no_layout, and static posts.
|
|
205
222
|
*
|
|
206
223
|
* Additional keys are passed through unchanged — themes and plugins
|
|
207
224
|
* are free to store their own per-post state here (e.g. SEO overrides,
|
|
@@ -209,11 +226,11 @@ type PostStatus = 'draft' | 'published';
|
|
|
209
226
|
*/
|
|
210
227
|
interface PostMetadata {
|
|
211
228
|
no_layout?: boolean;
|
|
229
|
+
cache?: CacheStrategy;
|
|
212
230
|
[key: string]: unknown;
|
|
213
231
|
}
|
|
214
232
|
interface Post {
|
|
215
233
|
postId: string;
|
|
216
|
-
siteId: string;
|
|
217
234
|
slug: string;
|
|
218
235
|
title: string;
|
|
219
236
|
excerpt?: string;
|
|
@@ -223,10 +240,18 @@ interface Post {
|
|
|
223
240
|
publishedAt?: string;
|
|
224
241
|
tags?: string[];
|
|
225
242
|
metadata?: PostMetadata;
|
|
243
|
+
/**
|
|
244
|
+
* DynamoDB auto-managed timestamp (ISO 8601). Surfaced through the
|
|
245
|
+
* `PublicPost` projection so middleware can compute the
|
|
246
|
+
* `metadata.cache='auto'` cooldown without re-fetching the model
|
|
247
|
+
* row. Absent on optimistically-constructed posts (e.g. test
|
|
248
|
+
* fixtures); the cache strategy treats absent values as "very old"
|
|
249
|
+
* and emits a long s-maxage.
|
|
250
|
+
*/
|
|
251
|
+
updatedAt?: string;
|
|
226
252
|
}
|
|
227
253
|
interface Page {
|
|
228
254
|
pageId: string;
|
|
229
|
-
siteId: string;
|
|
230
255
|
slug: string;
|
|
231
256
|
title: string;
|
|
232
257
|
format: ContentFormat;
|
|
@@ -236,7 +261,6 @@ interface Page {
|
|
|
236
261
|
}
|
|
237
262
|
interface Media {
|
|
238
263
|
mediaId: string;
|
|
239
|
-
siteId: string;
|
|
240
264
|
src: string;
|
|
241
265
|
mimeType: string;
|
|
242
266
|
size: number;
|
|
@@ -261,21 +285,6 @@ interface MediaProcessingDefaults {
|
|
|
261
285
|
/** Use lossless WebP for PNG inputs (default true). */
|
|
262
286
|
losslessForPng?: boolean;
|
|
263
287
|
}
|
|
264
|
-
/**
|
|
265
|
-
* Per-site override. The top-level `Config.site` provides defaults that
|
|
266
|
-
* fall through when these are unset. `domains` is required because it's
|
|
267
|
-
* how the middleware maps incoming requests to a siteId.
|
|
268
|
-
*/
|
|
269
|
-
interface SiteConfig {
|
|
270
|
-
/** Hostnames this site responds to (subdomains, separate apex domains, both fine). */
|
|
271
|
-
domains: string[];
|
|
272
|
-
/** Override `Config.site.name` for this site. */
|
|
273
|
-
name?: string;
|
|
274
|
-
/** Override `Config.site.url` (canonical) for this site. */
|
|
275
|
-
url?: string;
|
|
276
|
-
/** Override `Config.site.description` for this site. */
|
|
277
|
-
description?: string;
|
|
278
|
-
}
|
|
279
288
|
interface Config {
|
|
280
289
|
site: {
|
|
281
290
|
name: string;
|
|
@@ -304,16 +313,9 @@ interface Config {
|
|
|
304
313
|
* UI locale for the admin app. The scaffolded project ships
|
|
305
314
|
* `locales/<code>.json` dictionaries; defaults are `en` and `ja`.
|
|
306
315
|
* Add a new language by dropping `locales/<code>.json` in and
|
|
307
|
-
* updating the dictionary map in `lib/i18n.ts`.
|
|
308
|
-
* possible via the `locale` site setting.
|
|
316
|
+
* updating the dictionary map in `lib/i18n.ts`.
|
|
309
317
|
*/
|
|
310
318
|
locale?: string;
|
|
311
|
-
/**
|
|
312
|
-
* Multi-site configuration. When 2+ entries are declared, the runtime
|
|
313
|
-
* switches to multi-site mode (host-based routing + Cache-Control:
|
|
314
|
-
* private). When 0 or 1 entries, single-site mode is used.
|
|
315
|
-
*/
|
|
316
|
-
sites?: Record<string, SiteConfig>;
|
|
317
319
|
/**
|
|
318
320
|
* Active plugins. Each entry is the result of a plugin factory call
|
|
319
321
|
* (e.g. `seoPlugin({ ... })`) or a raw AmplessPlugin object. Strings are
|
|
@@ -321,6 +323,36 @@ interface Config {
|
|
|
321
323
|
* ignored by the runtime.
|
|
322
324
|
*/
|
|
323
325
|
plugins?: Array<AmplessPlugin | string>;
|
|
326
|
+
/**
|
|
327
|
+
* Cache strategy knobs read by the runtime's middleware when
|
|
328
|
+
* computing `Cache-Control` for post responses. Each field is
|
|
329
|
+
* optional — middleware applies the documented defaults when a
|
|
330
|
+
* field is absent.
|
|
331
|
+
*/
|
|
332
|
+
cache?: CacheConfig;
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* Tunables for middleware-computed `Cache-Control`. See
|
|
336
|
+
* `PostMetadata.cache` / `CacheStrategy` for how the per-post override
|
|
337
|
+
* interacts with these defaults.
|
|
338
|
+
*/
|
|
339
|
+
interface CacheConfig {
|
|
340
|
+
/**
|
|
341
|
+
* `cache: 'auto'` cooldown. Posts whose `updatedAt` is younger than
|
|
342
|
+
* this many milliseconds emit a no-store header so editors see
|
|
343
|
+
* fresh content immediately after a save. Default 3,600,000 (1h).
|
|
344
|
+
*/
|
|
345
|
+
cooldownMs?: number;
|
|
346
|
+
/**
|
|
347
|
+
* `cache: 'auto'` post-cooldown TTL, in seconds. Applied as both
|
|
348
|
+
* `max-age` and `s-maxage` on the response. Default 300 (5 minutes).
|
|
349
|
+
*/
|
|
350
|
+
freshTtlSeconds?: number;
|
|
351
|
+
/**
|
|
352
|
+
* `cache: 'deep'` TTL, in seconds. Applied as both `max-age` and
|
|
353
|
+
* `s-maxage`. Default 3600 (1 hour).
|
|
354
|
+
*/
|
|
355
|
+
deepTtlSeconds?: number;
|
|
324
356
|
}
|
|
325
357
|
type Role = 'reader' | 'editor' | 'admin';
|
|
326
358
|
interface AuthContext {
|
|
@@ -346,7 +378,6 @@ interface ContentTypeDefinition {
|
|
|
346
378
|
declare function defineSchema<T extends Record<string, ContentTypeDefinition>>(schema: T): T;
|
|
347
379
|
|
|
348
380
|
interface ListOptions {
|
|
349
|
-
siteId?: string;
|
|
350
381
|
limit?: number;
|
|
351
382
|
status?: 'draft' | 'published' | 'all';
|
|
352
383
|
}
|
|
@@ -355,85 +386,20 @@ type CreatePostInput = Omit<Post, 'postId'> & {
|
|
|
355
386
|
};
|
|
356
387
|
interface PostsProvider {
|
|
357
388
|
list(opts?: ListOptions): Promise<Post[]>;
|
|
358
|
-
get(slug: string
|
|
359
|
-
|
|
360
|
-
}): Promise<Post | null>;
|
|
361
|
-
getById(postId: string, opts?: {
|
|
362
|
-
siteId?: string;
|
|
363
|
-
}): Promise<Post | null>;
|
|
389
|
+
get(slug: string): Promise<Post | null>;
|
|
390
|
+
getById(postId: string): Promise<Post | null>;
|
|
364
391
|
create(data: CreatePostInput): Promise<Post>;
|
|
365
|
-
update(postId: string, data: Partial<Post
|
|
366
|
-
|
|
367
|
-
}): Promise<Post>;
|
|
368
|
-
remove(postId: string, opts?: {
|
|
369
|
-
siteId?: string;
|
|
370
|
-
}): Promise<void>;
|
|
392
|
+
update(postId: string, data: Partial<Post>): Promise<Post>;
|
|
393
|
+
remove(postId: string): Promise<void>;
|
|
371
394
|
}
|
|
372
395
|
declare function setPostsProvider(p: PostsProvider): void;
|
|
373
396
|
declare function hasPostsProvider(): boolean;
|
|
374
397
|
declare function listPosts(opts?: ListOptions): Promise<Post[]>;
|
|
375
|
-
declare function getPost(slug: string
|
|
376
|
-
|
|
377
|
-
}): Promise<Post | null>;
|
|
378
|
-
declare function getPostById(postId: string, opts?: {
|
|
379
|
-
siteId?: string;
|
|
380
|
-
}): Promise<Post | null>;
|
|
398
|
+
declare function getPost(slug: string): Promise<Post | null>;
|
|
399
|
+
declare function getPostById(postId: string): Promise<Post | null>;
|
|
381
400
|
declare function createPost(data: CreatePostInput): Promise<Post>;
|
|
382
|
-
declare function updatePost(postId: string, data: Partial<Post
|
|
383
|
-
|
|
384
|
-
}): Promise<Post>;
|
|
385
|
-
declare function deletePost(postId: string, opts?: {
|
|
386
|
-
siteId?: string;
|
|
387
|
-
}): Promise<void>;
|
|
388
|
-
|
|
389
|
-
/**
|
|
390
|
-
* Single-site fallback identifier. Used when `cms.config.sites` is unset
|
|
391
|
-
* or empty — keeps existing single-site code paths working without
|
|
392
|
-
* special-casing.
|
|
393
|
-
*/
|
|
394
|
-
declare const DEFAULT_SITE_ID = "default";
|
|
395
|
-
/**
|
|
396
|
-
* Resolve a hostname to a configured siteId.
|
|
397
|
-
*
|
|
398
|
-
* - Single-site mode (no `sites` defined / empty / exactly one entry):
|
|
399
|
-
* returns that site's id regardless of host. The single site catches
|
|
400
|
-
* every request. Matches `isMultiSite` (≥2 entries = multi).
|
|
401
|
-
* - Multi-site mode (2+ entries): looks up the host in each site's
|
|
402
|
-
* `domains` list. Returns `null` if the host is not registered
|
|
403
|
-
* (caller should 404).
|
|
404
|
-
*
|
|
405
|
-
* The host comparison is case-insensitive; ports are not stripped here
|
|
406
|
-
* — pass the bare hostname (e.g. `'site-a.example.com'`).
|
|
407
|
-
*/
|
|
408
|
-
declare function resolveSiteId(host: string, config: Config): string | null;
|
|
409
|
-
/**
|
|
410
|
-
* Multi-site mode iff two or more sites are declared. A single declared
|
|
411
|
-
* site is treated as single-site mode (the explicit declaration just lets
|
|
412
|
-
* the operator name the site, but no host disambiguation is needed).
|
|
413
|
-
*/
|
|
414
|
-
declare function isMultiSite(config: Config): boolean;
|
|
415
|
-
/**
|
|
416
|
-
* Site-effective name / url / description for a given siteId. Per-site
|
|
417
|
-
* `sites.{id}.{name|url|description}` overrides the top-level `site.*`
|
|
418
|
-
* defaults; otherwise falls through.
|
|
419
|
-
*/
|
|
420
|
-
declare function siteFor(siteId: string, config: Config): {
|
|
421
|
-
name: string;
|
|
422
|
-
url: string;
|
|
423
|
-
description?: string;
|
|
424
|
-
};
|
|
425
|
-
/**
|
|
426
|
-
* Build the denormalized GSI key for `bySiteIdStatus`. All Post writes
|
|
427
|
-
* (admin client, MCP tools) must set this so the public-read resolvers
|
|
428
|
-
* can do a single Query without table-level filtering.
|
|
429
|
-
*/
|
|
430
|
-
declare function composeSiteIdStatus(siteId: string, status: PostStatus): string;
|
|
431
|
-
/**
|
|
432
|
-
* Build the denormalized GSI key for `bySiteIdSlug`. The public
|
|
433
|
-
* `getPublishedPost(slug)` resolver does an O(1) PK lookup against
|
|
434
|
-
* this index, so every Post write must set it alongside the slug.
|
|
435
|
-
*/
|
|
436
|
-
declare function composeSiteIdSlug(siteId: string, slug: string): string;
|
|
401
|
+
declare function updatePost(postId: string, data: Partial<Post>): Promise<Post>;
|
|
402
|
+
declare function deletePost(postId: string): Promise<void>;
|
|
437
403
|
|
|
438
404
|
interface KvItem<T = unknown> {
|
|
439
405
|
pk: string;
|
|
@@ -459,15 +425,15 @@ declare function hasKvStore(): boolean;
|
|
|
459
425
|
* namespace (e.g. `mcp-tokens`).
|
|
460
426
|
*/
|
|
461
427
|
declare function getKvStore(): KvStore;
|
|
462
|
-
declare const SITE_CONFIG_PK
|
|
463
|
-
declare function getSiteSetting<T = unknown>(
|
|
464
|
-
declare function setSiteSetting(
|
|
465
|
-
declare function deleteSiteSetting(
|
|
428
|
+
declare const SITE_CONFIG_PK = "siteconfig";
|
|
429
|
+
declare function getSiteSetting<T = unknown>(key: string): Promise<T | null>;
|
|
430
|
+
declare function setSiteSetting(key: string, value: unknown): Promise<void>;
|
|
431
|
+
declare function deleteSiteSetting(key: string): Promise<void>;
|
|
466
432
|
/**
|
|
467
|
-
* Fetch every setting
|
|
433
|
+
* Fetch every site setting as a flat map (`{ 'site.name': 'My Blog', ... }`).
|
|
468
434
|
* Use `unflattenSettings` to convert to the nested shape if needed.
|
|
469
435
|
*/
|
|
470
|
-
declare function listSiteSettings(
|
|
436
|
+
declare function listSiteSettings(): Promise<Record<string, unknown>>;
|
|
471
437
|
declare function flattenSettings(obj: Record<string, unknown>, prefix?: string): Record<string, unknown>;
|
|
472
438
|
declare function unflattenSettings(flat: Record<string, unknown>): Record<string, unknown>;
|
|
473
439
|
|
|
@@ -551,6 +517,94 @@ declare function formatPublicAssetUrl(bucket: string, region: string, key: strin
|
|
|
551
517
|
*/
|
|
552
518
|
declare function extractFirstImageUrl(post: Post): string | null;
|
|
553
519
|
|
|
520
|
+
/**
|
|
521
|
+
* Pure helpers for `format: 'static'` post bundles. Kept platform-free
|
|
522
|
+
* (no `File`, no Amplify Storage, no AWS SDK) so both the browser admin
|
|
523
|
+
* uploader and the MCP tools (running in stdio CLI + Lambda HTTP
|
|
524
|
+
* transport) can share the validation / picker / mime logic.
|
|
525
|
+
*
|
|
526
|
+
* The `extractZip(File)` / `uploadBundle` / `deleteBundle` browser
|
|
527
|
+
* helpers stay in `@ampless/admin/lib/static-bundle.js` — they pull in
|
|
528
|
+
* JSZip and `aws-amplify/storage`, neither of which we want in Lambda.
|
|
529
|
+
* The MCP Lambda implements its own zip extractor (`fflate`) on top of
|
|
530
|
+
* the helpers here.
|
|
531
|
+
*/
|
|
532
|
+
declare const DEFAULT_ENTRYPOINT = "index.html";
|
|
533
|
+
/**
|
|
534
|
+
* Maximum bundle size (uncompressed) for the browser-side admin
|
|
535
|
+
* pipeline. Above this the in-tab extract / multi-PUT pipeline gets
|
|
536
|
+
* sluggish. The Lambda / MCP side enforces its own limit (Function URL
|
|
537
|
+
* payload cap, around 6 MB base64-inflated per call) — this constant
|
|
538
|
+
* is exported as a reasonable upper bound for any caller that wants
|
|
539
|
+
* a sanity check, not a hard contract for non-browser paths.
|
|
540
|
+
*/
|
|
541
|
+
declare const MAX_BUNDLE_BYTES: number;
|
|
542
|
+
declare const TEXT_EXTENSIONS: ReadonlySet<string>;
|
|
543
|
+
declare function mimeTypeFor(path: string): string;
|
|
544
|
+
interface ValidationIssue {
|
|
545
|
+
path: string;
|
|
546
|
+
line?: number;
|
|
547
|
+
reason: string;
|
|
548
|
+
}
|
|
549
|
+
/**
|
|
550
|
+
* Reject paths that would either escape the bundle root (`..`), confuse
|
|
551
|
+
* S3 (`null bytes`), or carry OS-specific cruft from zip tools
|
|
552
|
+
* (`__MACOSX/`, `.DS_Store`). Returns `null` when the path is OK,
|
|
553
|
+
* otherwise the reason to surface to the user.
|
|
554
|
+
*/
|
|
555
|
+
declare function validateBundlePath(path: string): string | null;
|
|
556
|
+
/**
|
|
557
|
+
* Scan text files for **absolute** path references. The static-bundle
|
|
558
|
+
* contract is that every reference resolves inside the bundle via
|
|
559
|
+
* relative paths, so any `href="/foo"` would either escape to the
|
|
560
|
+
* Next.js root or break under arbitrary URL prefixes. Protocol-prefixed
|
|
561
|
+
* URLs (`https://…`) and `mailto:` / `tel:` are fine.
|
|
562
|
+
*
|
|
563
|
+
* `data:` and `blob:` URIs also pass (they don't traverse the network).
|
|
564
|
+
* Hash-only (`#anchor`) and empty values pass too.
|
|
565
|
+
*/
|
|
566
|
+
declare function findAbsolutePathRefs(path: string, content: string): ValidationIssue[];
|
|
567
|
+
interface ExtractedFile {
|
|
568
|
+
/** Relative path inside the bundle (slash-separated). */
|
|
569
|
+
path: string;
|
|
570
|
+
data: Uint8Array;
|
|
571
|
+
}
|
|
572
|
+
interface BundleExtractResult {
|
|
573
|
+
files: ExtractedFile[];
|
|
574
|
+
issues: ValidationIssue[];
|
|
575
|
+
totalBytes: number;
|
|
576
|
+
}
|
|
577
|
+
/**
|
|
578
|
+
* Scan every text file in the bundle for absolute URL refs. Returns
|
|
579
|
+
* the union of issues across files so the admin UI / MCP tool can
|
|
580
|
+
* render a single list of problems before saving.
|
|
581
|
+
*/
|
|
582
|
+
declare function validateBundle(files: ExtractedFile[]): ValidationIssue[];
|
|
583
|
+
declare function bundlePrefix(slug: string): string;
|
|
584
|
+
/**
|
|
585
|
+
* If every file shares the same top-level directory (e.g. macOS Finder
|
|
586
|
+
* zipping wraps the contents in a `MyBundle/` folder), strip that
|
|
587
|
+
* prefix so the bundle's logical root is the entrypoint's parent.
|
|
588
|
+
* Bundles already at root pass through unchanged.
|
|
589
|
+
*/
|
|
590
|
+
declare function stripCommonPrefix(files: ExtractedFile[]): ExtractedFile[];
|
|
591
|
+
/**
|
|
592
|
+
* Heuristic for the default entrypoint when the caller didn't override:
|
|
593
|
+
* 1. exact `index.html` at root
|
|
594
|
+
* 2. exact `index.htm` at root
|
|
595
|
+
* 3. the first .html / .htm file at root (alphabetical)
|
|
596
|
+
* 4. the first .html / .htm anywhere
|
|
597
|
+
* 5. fall back to the literal 'index.html' so the validator surfaces
|
|
598
|
+
* a meaningful error to the user ("entrypoint not in bundle")
|
|
599
|
+
*
|
|
600
|
+
* Accepts either extracted files (with `data`) or a plain list of
|
|
601
|
+
* relative paths — the MCP `commit_static_post` flow only has the
|
|
602
|
+
* S3 ListObjects result to work with, no bytes.
|
|
603
|
+
*/
|
|
604
|
+
declare function pickDefaultEntrypoint(files: readonly {
|
|
605
|
+
path: string;
|
|
606
|
+
}[]): string;
|
|
607
|
+
|
|
554
608
|
type ThemeFieldType = 'color' | 'text' | 'select' | 'image' | 'length' | 'fontFamily' | 'linkList';
|
|
555
609
|
/**
|
|
556
610
|
* Single entry in a `linkList` field. Stored as part of a JSON array
|
|
@@ -653,9 +707,7 @@ declare function defineTheme(m: ThemeManifest): ThemeManifest;
|
|
|
653
707
|
*/
|
|
654
708
|
declare function resolveLocalized(value: LocalizedString | undefined, locale: string, fallback?: string): string;
|
|
655
709
|
interface ThemeRouteContext<P = Record<string, string>> {
|
|
656
|
-
params: Promise<P
|
|
657
|
-
siteId: string;
|
|
658
|
-
}>;
|
|
710
|
+
params: Promise<P>;
|
|
659
711
|
}
|
|
660
712
|
interface ThemeModule {
|
|
661
713
|
/** Stable identifier — must match the directory name and the value
|
|
@@ -663,9 +715,10 @@ interface ThemeModule {
|
|
|
663
715
|
name: string;
|
|
664
716
|
manifest: ThemeManifest;
|
|
665
717
|
/**
|
|
666
|
-
* Server components rendered by the dispatcher routes
|
|
667
|
-
* `app/
|
|
668
|
-
*
|
|
718
|
+
* Server components rendered by the dispatcher routes
|
|
719
|
+
* (`app/page.tsx`, `app/[slug]/page.tsx`, `app/tag/[tag]/page.tsx`).
|
|
720
|
+
* Each theme MUST provide Home; Post / Tag are recommended but
|
|
721
|
+
* optional (dispatcher 404s when missing).
|
|
669
722
|
*/
|
|
670
723
|
components: {
|
|
671
724
|
Home: (ctx: ThemeRouteContext) => Promise<unknown> | unknown;
|
|
@@ -695,11 +748,9 @@ interface ThemeModule {
|
|
|
695
748
|
*/
|
|
696
749
|
routes?: {
|
|
697
750
|
feed?: (ctx: {
|
|
698
|
-
siteId: string;
|
|
699
751
|
request: Request;
|
|
700
752
|
}) => Promise<Response>;
|
|
701
753
|
sitemap?: (ctx: {
|
|
702
|
-
siteId: string;
|
|
703
754
|
request: Request;
|
|
704
755
|
}) => Promise<Response>;
|
|
705
756
|
};
|
|
@@ -757,11 +808,11 @@ declare function isTagListUrl(url: string): {
|
|
|
757
808
|
/**
|
|
758
809
|
* Resolve effective values for every manifest field, merging stored
|
|
759
810
|
* overrides on top of defaults. `stored` is the flat settings map keyed
|
|
760
|
-
* by `theme.{key}` — typically the output of `listSiteSettings(
|
|
811
|
+
* by `theme.{key}` — typically the output of `listSiteSettings()`
|
|
761
812
|
* filtered to theme entries.
|
|
762
813
|
*/
|
|
763
814
|
declare function resolveThemeValues(manifest: ThemeManifest, stored: Record<string, unknown>): Record<string, string>;
|
|
764
815
|
|
|
765
816
|
declare const VERSION = "0.0.1";
|
|
766
817
|
|
|
767
|
-
export { type AmplessEvent, type AmplessPlugin, type AuthContext, type Config, type ContentEventPayload, type ContentEventType, type ContentFormat, type ContentTypeDefinition, type CreatePostInput,
|
|
818
|
+
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 MediaProcessingDefaults, type OgImageConfig, type OgImageFont, type OgImageRenderContext, type Page, type PluginEventHandler, type PluginMetadata, type PluginRuntimeContext, type Post, type PostMetadata, type PostStatus, type PostsProvider, type Role, SITE_CONFIG_PK, type SiteSettingsEventPayload, type SiteSettingsEventType, type StaticPostBody, 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, listPosts, listSiteSettings, mimeTypeFor, parseColorPair, parseLinkList, pickDefaultEntrypoint, resolveLocalized, resolveThemeValues, setKvStore, setPostsProvider, setSiteSetting, stringifyLinkList, stripCommonPrefix, themeSettingKey, unflattenSettings, updatePost, validateBundle, validateBundlePath, validateThemeValue };
|
package/dist/index.js
CHANGED
|
@@ -12,7 +12,6 @@ function defineSchema(schema) {
|
|
|
12
12
|
var DUMMY_POSTS = [
|
|
13
13
|
{
|
|
14
14
|
postId: "post-001",
|
|
15
|
-
siteId: "default",
|
|
16
15
|
slug: "hello-world",
|
|
17
16
|
title: "Hello, ampless",
|
|
18
17
|
excerpt: "Welcome to your new ampless-powered blog. This is the first post.",
|
|
@@ -24,7 +23,6 @@ var DUMMY_POSTS = [
|
|
|
24
23
|
},
|
|
25
24
|
{
|
|
26
25
|
postId: "post-002",
|
|
27
|
-
siteId: "default",
|
|
28
26
|
slug: "about-ampless",
|
|
29
27
|
title: "About ampless",
|
|
30
28
|
excerpt: "Why ampless exists, and what makes it different from other CMS options.",
|
|
@@ -36,7 +34,6 @@ var DUMMY_POSTS = [
|
|
|
36
34
|
},
|
|
37
35
|
{
|
|
38
36
|
postId: "post-003",
|
|
39
|
-
siteId: "default",
|
|
40
37
|
slug: "getting-started",
|
|
41
38
|
title: "Getting started",
|
|
42
39
|
excerpt: "How to set up your ampless site and deploy it to AWS.",
|
|
@@ -57,8 +54,8 @@ function hasPostsProvider() {
|
|
|
57
54
|
return provider !== null;
|
|
58
55
|
}
|
|
59
56
|
function dummyList(opts = {}) {
|
|
60
|
-
const {
|
|
61
|
-
let posts = DUMMY_POSTS
|
|
57
|
+
const { limit, status = "published" } = opts;
|
|
58
|
+
let posts = DUMMY_POSTS;
|
|
62
59
|
if (status !== "all") posts = posts.filter((p) => p.status === status);
|
|
63
60
|
return limit ? posts.slice(0, limit) : posts;
|
|
64
61
|
}
|
|
@@ -66,60 +63,25 @@ async function listPosts(opts = {}) {
|
|
|
66
63
|
if (provider) return provider.list(opts);
|
|
67
64
|
return dummyList(opts);
|
|
68
65
|
}
|
|
69
|
-
async function getPost(slug
|
|
70
|
-
if (provider) return provider.get(slug
|
|
71
|
-
|
|
72
|
-
return DUMMY_POSTS.find((p) => p.siteId === siteId && p.slug === slug) ?? null;
|
|
66
|
+
async function getPost(slug) {
|
|
67
|
+
if (provider) return provider.get(slug);
|
|
68
|
+
return DUMMY_POSTS.find((p) => p.slug === slug) ?? null;
|
|
73
69
|
}
|
|
74
|
-
async function getPostById(postId
|
|
75
|
-
if (provider) return provider.getById(postId
|
|
76
|
-
|
|
77
|
-
return DUMMY_POSTS.find((p) => p.siteId === siteId && p.postId === postId) ?? null;
|
|
70
|
+
async function getPostById(postId) {
|
|
71
|
+
if (provider) return provider.getById(postId);
|
|
72
|
+
return DUMMY_POSTS.find((p) => p.postId === postId) ?? null;
|
|
78
73
|
}
|
|
79
74
|
async function createPost(data) {
|
|
80
75
|
if (!provider) throw new Error("No posts provider configured. Call setPostsProvider() first.");
|
|
81
76
|
return provider.create(data);
|
|
82
77
|
}
|
|
83
|
-
async function updatePost(postId, data
|
|
78
|
+
async function updatePost(postId, data) {
|
|
84
79
|
if (!provider) throw new Error("No posts provider configured. Call setPostsProvider() first.");
|
|
85
|
-
return provider.update(postId, data
|
|
80
|
+
return provider.update(postId, data);
|
|
86
81
|
}
|
|
87
|
-
async function deletePost(postId
|
|
82
|
+
async function deletePost(postId) {
|
|
88
83
|
if (!provider) throw new Error("No posts provider configured. Call setPostsProvider() first.");
|
|
89
|
-
return provider.remove(postId
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
// src/sites.ts
|
|
93
|
-
var DEFAULT_SITE_ID = "default";
|
|
94
|
-
function resolveSiteId(host, config) {
|
|
95
|
-
const sites = config.sites;
|
|
96
|
-
if (!sites || Object.keys(sites).length === 0) {
|
|
97
|
-
return DEFAULT_SITE_ID;
|
|
98
|
-
}
|
|
99
|
-
const ids = Object.keys(sites);
|
|
100
|
-
if (ids.length === 1) return ids[0];
|
|
101
|
-
const lower = host.toLowerCase();
|
|
102
|
-
for (const [id, site] of Object.entries(sites)) {
|
|
103
|
-
if (site.domains.some((d) => d.toLowerCase() === lower)) return id;
|
|
104
|
-
}
|
|
105
|
-
return null;
|
|
106
|
-
}
|
|
107
|
-
function isMultiSite(config) {
|
|
108
|
-
return !!config.sites && Object.keys(config.sites).length >= 2;
|
|
109
|
-
}
|
|
110
|
-
function siteFor(siteId, config) {
|
|
111
|
-
const override = config.sites?.[siteId];
|
|
112
|
-
return {
|
|
113
|
-
name: override?.name ?? config.site.name,
|
|
114
|
-
url: override?.url ?? config.site.url,
|
|
115
|
-
description: override?.description ?? config.site.description
|
|
116
|
-
};
|
|
117
|
-
}
|
|
118
|
-
function composeSiteIdStatus(siteId, status) {
|
|
119
|
-
return `${siteId}#${status}`;
|
|
120
|
-
}
|
|
121
|
-
function composeSiteIdSlug(siteId, slug) {
|
|
122
|
-
return `${siteId}#${slug}`;
|
|
84
|
+
return provider.remove(postId);
|
|
123
85
|
}
|
|
124
86
|
|
|
125
87
|
// src/kv.ts
|
|
@@ -139,18 +101,18 @@ function requireStore() {
|
|
|
139
101
|
function getKvStore() {
|
|
140
102
|
return requireStore();
|
|
141
103
|
}
|
|
142
|
-
var SITE_CONFIG_PK =
|
|
143
|
-
async function getSiteSetting(
|
|
144
|
-
return requireStore().get(SITE_CONFIG_PK
|
|
104
|
+
var SITE_CONFIG_PK = "siteconfig";
|
|
105
|
+
async function getSiteSetting(key) {
|
|
106
|
+
return requireStore().get(SITE_CONFIG_PK, key);
|
|
145
107
|
}
|
|
146
|
-
async function setSiteSetting(
|
|
147
|
-
return requireStore().put(SITE_CONFIG_PK
|
|
108
|
+
async function setSiteSetting(key, value) {
|
|
109
|
+
return requireStore().put(SITE_CONFIG_PK, key, value);
|
|
148
110
|
}
|
|
149
|
-
async function deleteSiteSetting(
|
|
150
|
-
return requireStore().remove(SITE_CONFIG_PK
|
|
111
|
+
async function deleteSiteSetting(key) {
|
|
112
|
+
return requireStore().remove(SITE_CONFIG_PK, key);
|
|
151
113
|
}
|
|
152
|
-
async function listSiteSettings(
|
|
153
|
-
const items = await requireStore().query(SITE_CONFIG_PK
|
|
114
|
+
async function listSiteSettings() {
|
|
115
|
+
const items = await requireStore().query(SITE_CONFIG_PK);
|
|
154
116
|
const out = {};
|
|
155
117
|
for (const item of items) {
|
|
156
118
|
out[item.sk] = item.value;
|
|
@@ -296,6 +258,135 @@ function findHtmlImage(body) {
|
|
|
296
258
|
return m ? m[1] : null;
|
|
297
259
|
}
|
|
298
260
|
|
|
261
|
+
// src/static-bundle.ts
|
|
262
|
+
var DEFAULT_ENTRYPOINT = "index.html";
|
|
263
|
+
var MAX_BUNDLE_BYTES = 50 * 1024 * 1024;
|
|
264
|
+
var TEXT_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
265
|
+
".html",
|
|
266
|
+
".htm",
|
|
267
|
+
".css",
|
|
268
|
+
".svg"
|
|
269
|
+
]);
|
|
270
|
+
var MIME_TYPES = {
|
|
271
|
+
".html": "text/html; charset=utf-8",
|
|
272
|
+
".htm": "text/html; charset=utf-8",
|
|
273
|
+
".css": "text/css; charset=utf-8",
|
|
274
|
+
".js": "application/javascript; charset=utf-8",
|
|
275
|
+
".mjs": "application/javascript; charset=utf-8",
|
|
276
|
+
".json": "application/json; charset=utf-8",
|
|
277
|
+
".svg": "image/svg+xml",
|
|
278
|
+
".png": "image/png",
|
|
279
|
+
".jpg": "image/jpeg",
|
|
280
|
+
".jpeg": "image/jpeg",
|
|
281
|
+
".gif": "image/gif",
|
|
282
|
+
".webp": "image/webp",
|
|
283
|
+
".avif": "image/avif",
|
|
284
|
+
".ico": "image/x-icon",
|
|
285
|
+
".woff": "font/woff",
|
|
286
|
+
".woff2": "font/woff2",
|
|
287
|
+
".ttf": "font/ttf",
|
|
288
|
+
".otf": "font/otf",
|
|
289
|
+
".eot": "application/vnd.ms-fontobject",
|
|
290
|
+
".txt": "text/plain; charset=utf-8",
|
|
291
|
+
".xml": "application/xml; charset=utf-8",
|
|
292
|
+
".map": "application/json; charset=utf-8",
|
|
293
|
+
".pdf": "application/pdf"
|
|
294
|
+
};
|
|
295
|
+
function mimeTypeFor(path) {
|
|
296
|
+
const lower = path.toLowerCase();
|
|
297
|
+
const dot = lower.lastIndexOf(".");
|
|
298
|
+
if (dot < 0) return "application/octet-stream";
|
|
299
|
+
return MIME_TYPES[lower.slice(dot)] ?? "application/octet-stream";
|
|
300
|
+
}
|
|
301
|
+
function validateBundlePath(path) {
|
|
302
|
+
if (path === "" || path.endsWith("/")) return "directory entry";
|
|
303
|
+
if (path.includes("\0")) return "contains null byte";
|
|
304
|
+
if (path.startsWith("/") || path.startsWith("\\")) return "absolute path";
|
|
305
|
+
if (path.split(/[/\\]/).some((seg) => seg === "..")) return "parent-directory traversal";
|
|
306
|
+
if (path.startsWith("__MACOSX/") || /(^|\/)\._/.test(path)) return "macOS resource fork";
|
|
307
|
+
if (/(^|\/)\.DS_Store$/.test(path)) return ".DS_Store junk";
|
|
308
|
+
if (/(^|\/)Thumbs\.db$/i.test(path)) return "Thumbs.db junk";
|
|
309
|
+
return null;
|
|
310
|
+
}
|
|
311
|
+
var HTML_URL_ATTR_RE = /\b(?:href|src|action|data|poster|cite|formaction|manifest|srcset)\s*=\s*["']([^"']+)["']/gi;
|
|
312
|
+
var CSS_URL_RE = /url\(\s*["']?([^"')\s]+)["']?\s*\)|@import\s+["']([^"']+)["']/gi;
|
|
313
|
+
function findAbsolutePathRefs(path, content) {
|
|
314
|
+
const ext = path.toLowerCase().slice(path.lastIndexOf("."));
|
|
315
|
+
if (!TEXT_EXTENSIONS.has(ext)) return [];
|
|
316
|
+
const issues = [];
|
|
317
|
+
function check(url, lineHint) {
|
|
318
|
+
const trimmed = url.trim();
|
|
319
|
+
if (!trimmed) return;
|
|
320
|
+
if (trimmed.startsWith("#")) return;
|
|
321
|
+
if (/^[a-z][a-z0-9+.-]*:/i.test(trimmed)) return;
|
|
322
|
+
if (trimmed.startsWith("//")) {
|
|
323
|
+
issues.push({ path, reason: `protocol-relative URL: ${lineHint}` });
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
if (trimmed.startsWith("/")) {
|
|
327
|
+
issues.push({ path, reason: `absolute path: ${lineHint}` });
|
|
328
|
+
return;
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
if (ext === ".html" || ext === ".htm" || ext === ".svg") {
|
|
332
|
+
HTML_URL_ATTR_RE.lastIndex = 0;
|
|
333
|
+
let m;
|
|
334
|
+
while ((m = HTML_URL_ATTR_RE.exec(content)) !== null) {
|
|
335
|
+
const val = m[1] ?? "";
|
|
336
|
+
if (/\bsrcset\s*=/i.test(m[0])) {
|
|
337
|
+
for (const candidate of val.split(",")) {
|
|
338
|
+
const urlPart = candidate.trim().split(/\s+/)[0];
|
|
339
|
+
if (urlPart) check(urlPart, candidate.trim());
|
|
340
|
+
}
|
|
341
|
+
} else {
|
|
342
|
+
check(val, m[0]);
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
if (ext === ".css" || ext === ".svg") {
|
|
347
|
+
CSS_URL_RE.lastIndex = 0;
|
|
348
|
+
let m;
|
|
349
|
+
while ((m = CSS_URL_RE.exec(content)) !== null) {
|
|
350
|
+
const val = (m[1] ?? m[2] ?? "").trim();
|
|
351
|
+
check(val, m[0]);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
return issues;
|
|
355
|
+
}
|
|
356
|
+
function validateBundle(files) {
|
|
357
|
+
const issues = [];
|
|
358
|
+
const decoder = new TextDecoder("utf-8", { fatal: false });
|
|
359
|
+
for (const f of files) {
|
|
360
|
+
const ext = f.path.toLowerCase().slice(f.path.lastIndexOf("."));
|
|
361
|
+
if (!TEXT_EXTENSIONS.has(ext)) continue;
|
|
362
|
+
const text = decoder.decode(f.data);
|
|
363
|
+
issues.push(...findAbsolutePathRefs(f.path, text));
|
|
364
|
+
}
|
|
365
|
+
return issues;
|
|
366
|
+
}
|
|
367
|
+
function bundlePrefix(slug) {
|
|
368
|
+
return `public/static/${slug}/`;
|
|
369
|
+
}
|
|
370
|
+
function stripCommonPrefix(files) {
|
|
371
|
+
if (files.length === 0) return files;
|
|
372
|
+
const firstSlash = files[0].path.indexOf("/");
|
|
373
|
+
if (firstSlash < 0) return files;
|
|
374
|
+
const prefix = files[0].path.slice(0, firstSlash + 1);
|
|
375
|
+
if (!files.every((f) => f.path.startsWith(prefix))) return files;
|
|
376
|
+
return files.map((f) => ({ ...f, path: f.path.slice(prefix.length) }));
|
|
377
|
+
}
|
|
378
|
+
function pickDefaultEntrypoint(files) {
|
|
379
|
+
const exact = files.find((f) => f.path === DEFAULT_ENTRYPOINT);
|
|
380
|
+
if (exact) return exact.path;
|
|
381
|
+
const altRoot = files.find((f) => f.path === "index.htm");
|
|
382
|
+
if (altRoot) return altRoot.path;
|
|
383
|
+
const htmlRoot = files.filter((f) => /^[^/]+\.html?$/.test(f.path)).sort((a, b) => a.path.localeCompare(b.path));
|
|
384
|
+
if (htmlRoot.length > 0) return htmlRoot[0].path;
|
|
385
|
+
const htmlAny = files.filter((f) => /\.html?$/.test(f.path)).sort((a, b) => a.path.localeCompare(b.path));
|
|
386
|
+
if (htmlAny.length > 0) return htmlAny[0].path;
|
|
387
|
+
return DEFAULT_ENTRYPOINT;
|
|
388
|
+
}
|
|
389
|
+
|
|
299
390
|
// src/events.ts
|
|
300
391
|
function detectContentEvents(input) {
|
|
301
392
|
switch (input.eventName) {
|
|
@@ -471,11 +562,12 @@ function defaultValueAsString(field) {
|
|
|
471
562
|
// src/index.ts
|
|
472
563
|
var VERSION = "0.0.1";
|
|
473
564
|
export {
|
|
474
|
-
|
|
565
|
+
DEFAULT_ENTRYPOINT,
|
|
566
|
+
MAX_BUNDLE_BYTES,
|
|
475
567
|
SITE_CONFIG_PK,
|
|
568
|
+
TEXT_EXTENSIONS,
|
|
476
569
|
VERSION,
|
|
477
|
-
|
|
478
|
-
composeSiteIdStatus,
|
|
570
|
+
bundlePrefix,
|
|
479
571
|
createPost,
|
|
480
572
|
decodeAwsJson,
|
|
481
573
|
defineConfig,
|
|
@@ -489,6 +581,7 @@ export {
|
|
|
489
581
|
encodeAwsJson,
|
|
490
582
|
escapeXml,
|
|
491
583
|
extractFirstImageUrl,
|
|
584
|
+
findAbsolutePathRefs,
|
|
492
585
|
flattenSettings,
|
|
493
586
|
formatColorPair,
|
|
494
587
|
formatDate,
|
|
@@ -499,22 +592,24 @@ export {
|
|
|
499
592
|
getSiteSetting,
|
|
500
593
|
hasKvStore,
|
|
501
594
|
hasPostsProvider,
|
|
502
|
-
isMultiSite,
|
|
503
595
|
isTagListUrl,
|
|
504
596
|
listPosts,
|
|
505
597
|
listSiteSettings,
|
|
598
|
+
mimeTypeFor,
|
|
506
599
|
parseColorPair,
|
|
507
600
|
parseLinkList,
|
|
601
|
+
pickDefaultEntrypoint,
|
|
508
602
|
resolveLocalized,
|
|
509
|
-
resolveSiteId,
|
|
510
603
|
resolveThemeValues,
|
|
511
604
|
setKvStore,
|
|
512
605
|
setPostsProvider,
|
|
513
606
|
setSiteSetting,
|
|
514
|
-
siteFor,
|
|
515
607
|
stringifyLinkList,
|
|
608
|
+
stripCommonPrefix,
|
|
516
609
|
themeSettingKey,
|
|
517
610
|
unflattenSettings,
|
|
518
611
|
updatePost,
|
|
612
|
+
validateBundle,
|
|
613
|
+
validateBundlePath,
|
|
519
614
|
validateThemeValue
|
|
520
615
|
};
|