dineway 0.1.3

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.
Files changed (96) hide show
  1. package/LICENSE +9 -0
  2. package/README.md +89 -0
  3. package/dist/adapters-BlzWJG82.d.mts +106 -0
  4. package/dist/apply-CAPvMfoU.mjs +1339 -0
  5. package/dist/astro/index.d.mts +50 -0
  6. package/dist/astro/index.mjs +1326 -0
  7. package/dist/astro/middleware/auth.d.mts +30 -0
  8. package/dist/astro/middleware/auth.mjs +708 -0
  9. package/dist/astro/middleware/redirect.d.mts +21 -0
  10. package/dist/astro/middleware/redirect.mjs +62 -0
  11. package/dist/astro/middleware/request-context.d.mts +17 -0
  12. package/dist/astro/middleware/request-context.mjs +1371 -0
  13. package/dist/astro/middleware/setup.d.mts +19 -0
  14. package/dist/astro/middleware/setup.mjs +46 -0
  15. package/dist/astro/middleware.d.mts +12 -0
  16. package/dist/astro/middleware.mjs +1716 -0
  17. package/dist/astro/types.d.mts +269 -0
  18. package/dist/astro/types.mjs +1 -0
  19. package/dist/base64-F8-DUraK.mjs +58 -0
  20. package/dist/byline-DeWCMU_i.mjs +234 -0
  21. package/dist/bylines-DyqBV9EQ.mjs +137 -0
  22. package/dist/chunk-ClPoSABd.mjs +21 -0
  23. package/dist/cli/index.d.mts +1 -0
  24. package/dist/cli/index.mjs +3987 -0
  25. package/dist/client/external-auth-headers.d.mts +38 -0
  26. package/dist/client/external-auth-headers.mjs +101 -0
  27. package/dist/client/index.d.mts +397 -0
  28. package/dist/client/index.mjs +345 -0
  29. package/dist/config-Cq8H0SfX.mjs +46 -0
  30. package/dist/connection-C9pxzuag.mjs +52 -0
  31. package/dist/content-zSgdNmnt.mjs +836 -0
  32. package/dist/db/index.d.mts +4 -0
  33. package/dist/db/index.mjs +62 -0
  34. package/dist/db/libsql.d.mts +10 -0
  35. package/dist/db/libsql.mjs +21 -0
  36. package/dist/db/postgres.d.mts +10 -0
  37. package/dist/db/postgres.mjs +29 -0
  38. package/dist/db/sqlite.d.mts +10 -0
  39. package/dist/db/sqlite.mjs +15 -0
  40. package/dist/default-WYlzADZL.mjs +80 -0
  41. package/dist/dialect-helpers-B9uSp2GJ.mjs +89 -0
  42. package/dist/error-DrxtnGPg.mjs +26 -0
  43. package/dist/index-C-jx21qs.d.mts +4771 -0
  44. package/dist/index.d.mts +16 -0
  45. package/dist/index.mjs +30 -0
  46. package/dist/load-C6FCD1FU.mjs +27 -0
  47. package/dist/loader-qKmo0wAY.mjs +446 -0
  48. package/dist/manifest-schema-CTSEyIJ3.mjs +186 -0
  49. package/dist/media/index.d.mts +25 -0
  50. package/dist/media/index.mjs +54 -0
  51. package/dist/media/local-runtime.d.mts +38 -0
  52. package/dist/media/local-runtime.mjs +132 -0
  53. package/dist/media-DMTr80Gv.mjs +199 -0
  54. package/dist/mode-BlyYtIFO.mjs +22 -0
  55. package/dist/page/index.d.mts +148 -0
  56. package/dist/page/index.mjs +419 -0
  57. package/dist/placeholder-B3knXwNc.mjs +267 -0
  58. package/dist/placeholder-bOx1xCTY.d.mts +283 -0
  59. package/dist/plugin-utils.d.mts +57 -0
  60. package/dist/plugin-utils.mjs +77 -0
  61. package/dist/plugins/adapt-sandbox-entry.d.mts +21 -0
  62. package/dist/plugins/adapt-sandbox-entry.mjs +112 -0
  63. package/dist/query-BiaPl_g2.mjs +459 -0
  64. package/dist/redirect-JPqLAbxa.mjs +328 -0
  65. package/dist/registry-DSd1GWB8.mjs +851 -0
  66. package/dist/request-context.d.mts +49 -0
  67. package/dist/request-context.mjs +42 -0
  68. package/dist/runner-B5l1JfOj.d.mts +26 -0
  69. package/dist/runner-BGUGywgG.mjs +1529 -0
  70. package/dist/runtime.d.mts +25 -0
  71. package/dist/runtime.mjs +41 -0
  72. package/dist/search-BNruJHDL.mjs +11054 -0
  73. package/dist/seed/index.d.mts +3 -0
  74. package/dist/seed/index.mjs +15 -0
  75. package/dist/seo/index.d.mts +69 -0
  76. package/dist/seo/index.mjs +69 -0
  77. package/dist/storage/local.d.mts +38 -0
  78. package/dist/storage/local.mjs +165 -0
  79. package/dist/storage/s3.d.mts +31 -0
  80. package/dist/storage/s3.mjs +174 -0
  81. package/dist/tokens-4vgYuXsZ.mjs +170 -0
  82. package/dist/transport-C5FYnid7.mjs +417 -0
  83. package/dist/transport-gIL-e43D.d.mts +41 -0
  84. package/dist/types-BawVha09.mjs +30 -0
  85. package/dist/types-BgQeVaPj.d.mts +192 -0
  86. package/dist/types-CLLdsG3g.d.mts +103 -0
  87. package/dist/types-D38djUXv.d.mts +1196 -0
  88. package/dist/types-DShnjzb6.mjs +15 -0
  89. package/dist/types-DkvMXalq.d.mts +425 -0
  90. package/dist/types-DuNbGKjF.mjs +74 -0
  91. package/dist/types-ju-_ORz7.d.mts +182 -0
  92. package/dist/validate-CXnRKfJK.mjs +327 -0
  93. package/dist/validate-CqRJb_xU.mjs +96 -0
  94. package/dist/validate-DVKJJ-M_.d.mts +377 -0
  95. package/locals.d.ts +47 -0
  96. package/package.json +313 -0
@@ -0,0 +1,4771 @@
1
+ import { _ as MediaValue, m as MediaProviderDescriptor } from "./placeholder-bOx1xCTY.mjs";
2
+ import { t as Database } from "./types-DkvMXalq.mjs";
3
+ import { a as ContentSeoInput, c as FindManyOptions, l as FindManyResult, o as CreateContentInput, r as ContentItem, t as BylineSummary, u as UpdateContentInput } from "./types-CLLdsG3g.mjs";
4
+ import { $ as StandardPluginDefinition, B as PluginManifest, E as PageFragmentEvent, H as PluginStorageConfig, J as ResolvedPlugin, K as RequestMeta, O as PageMetadataContribution, R as PluginDefinition, S as MediaItem$1, T as PageFragmentContribution, a as CommentAfterModerateEvent, k as PageMetadataEvent, m as EmailMessage, p as CronEvent, r as CommentAfterCreateEvent, s as CommentBeforeCreateEvent } from "./types-D38djUXv.mjs";
5
+ import { g as UpdateFieldInput, h as UpdateCollectionInput, i as CollectionWithFields, l as Field, o as CreateCollectionInput, s as CreateFieldInput, t as Collection } from "./types-BgQeVaPj.mjs";
6
+ import { C as SiteSettingKey, w as SiteSettings } from "./validate-DVKJJ-M_.mjs";
7
+ import { d as Storage } from "./types-ju-_ORz7.mjs";
8
+ import { t as DatabaseDescriptor } from "./adapters-BlzWJG82.mjs";
9
+ import { Kysely } from "kysely";
10
+ import { z } from "astro/zod";
11
+ import { z as z$1 } from "zod";
12
+ import { PortableTextBlock } from "@dineway-ai/gutenberg-to-portable-text";
13
+ import { Readable } from "node:stream";
14
+ import { MiddlewareHandler } from "astro";
15
+ import { LiveLoader } from "astro/loaders";
16
+
17
+ //#region src/database/connection.d.ts
18
+ interface DatabaseConfig {
19
+ url: string;
20
+ authToken?: string;
21
+ }
22
+ declare class DinewayDatabaseError extends Error {
23
+ cause?: unknown | undefined;
24
+ constructor(message: string, cause?: unknown | undefined);
25
+ }
26
+ //#endregion
27
+ //#region src/database/repositories/content.d.ts
28
+ /**
29
+ * Repository for content CRUD operations
30
+ *
31
+ * Content is stored in per-collection tables (ec_posts, ec_pages, etc.)
32
+ * Each field becomes a real column in the table.
33
+ */
34
+ declare class ContentRepository {
35
+ private db;
36
+ constructor(db: Kysely<Database>);
37
+ /**
38
+ * Create a new content item
39
+ */
40
+ create(input: CreateContentInput): Promise<ContentItem>;
41
+ /**
42
+ * Generate a unique slug for a content item within a collection.
43
+ *
44
+ * Checks the collection table for existing slugs that match `baseSlug`
45
+ * (optionally scoped to a locale) and appends a numeric suffix (`-1`,
46
+ * `-2`, etc.) on collision to guarantee uniqueness.
47
+ *
48
+ * Returns `null` if `baseSlug` is empty after slugification.
49
+ */
50
+ generateUniqueSlug(type: string, text: string, locale?: string): Promise<string | null>;
51
+ /**
52
+ * Duplicate a content item
53
+ * Creates a new draft copy with "(Copy)" appended to the title.
54
+ * A slug is auto-generated from the new title by the handler layer.
55
+ */
56
+ duplicate(type: string, id: string, authorId?: string): Promise<ContentItem>;
57
+ /**
58
+ * Find content by ID
59
+ */
60
+ findById(type: string, id: string): Promise<ContentItem | null>;
61
+ /**
62
+ * Find content by id, including trashed (soft-deleted) items.
63
+ * Used by restore endpoint for ownership checks.
64
+ */
65
+ findByIdIncludingTrashed(type: string, id: string): Promise<ContentItem | null>;
66
+ /**
67
+ * Find content by ID or slug. Tries ID first if it looks like a ULID,
68
+ * otherwise tries slug. Falls back to the other if the first lookup misses.
69
+ */
70
+ findByIdOrSlug(type: string, identifier: string, locale?: string): Promise<ContentItem | null>;
71
+ /**
72
+ * Find content by ID or slug, including trashed (soft-deleted) items.
73
+ * Used by restore/permanent-delete endpoints.
74
+ */
75
+ findByIdOrSlugIncludingTrashed(type: string, identifier: string, locale?: string): Promise<ContentItem | null>;
76
+ private _findByIdOrSlug;
77
+ /**
78
+ * Find content by slug
79
+ */
80
+ findBySlug(type: string, slug: string, locale?: string): Promise<ContentItem | null>;
81
+ /**
82
+ * Find content by slug, including trashed (soft-deleted) items.
83
+ * Used by restore/permanent-delete endpoints.
84
+ */
85
+ findBySlugIncludingTrashed(type: string, slug: string, locale?: string): Promise<ContentItem | null>;
86
+ /**
87
+ * Find many content items with filtering and pagination
88
+ */
89
+ findMany(type: string, options?: FindManyOptions): Promise<FindManyResult<ContentItem>>;
90
+ /**
91
+ * Update content
92
+ */
93
+ update(type: string, id: string, input: UpdateContentInput): Promise<ContentItem>;
94
+ /**
95
+ * Delete content (soft delete - moves to trash)
96
+ */
97
+ delete(type: string, id: string): Promise<boolean>;
98
+ /**
99
+ * Restore content from trash
100
+ */
101
+ restore(type: string, id: string): Promise<boolean>;
102
+ /**
103
+ * Permanently delete content (cannot be undone)
104
+ */
105
+ permanentDelete(type: string, id: string): Promise<boolean>;
106
+ /**
107
+ * Find trashed content items
108
+ */
109
+ findTrashed(type: string, options?: Omit<FindManyOptions, "where">): Promise<FindManyResult<ContentItem & {
110
+ deletedAt: string;
111
+ }>>;
112
+ /**
113
+ * Count trashed content items
114
+ */
115
+ countTrashed(type: string): Promise<number>;
116
+ /**
117
+ * Count content items
118
+ */
119
+ count(type: string, where?: {
120
+ status?: string;
121
+ authorId?: string;
122
+ locale?: string;
123
+ }): Promise<number>;
124
+ getStats(type: string): Promise<{
125
+ total: number;
126
+ published: number;
127
+ draft: number;
128
+ }>;
129
+ /**
130
+ * Schedule content for future publishing
131
+ *
132
+ * Sets status to 'scheduled' and stores the scheduled publish time.
133
+ * The content will be auto-published when the scheduled time is reached.
134
+ */
135
+ schedule(type: string, id: string, scheduledAt: string): Promise<ContentItem>;
136
+ /**
137
+ * Unschedule content
138
+ *
139
+ * Clears the scheduled time. Published posts stay published;
140
+ * draft/scheduled posts revert to 'draft'.
141
+ */
142
+ unschedule(type: string, id: string): Promise<ContentItem>;
143
+ /**
144
+ * Find content that is ready to be published
145
+ *
146
+ * Returns all content where scheduled_at <= now, regardless of status.
147
+ * This covers both draft-scheduled posts (status='scheduled') and
148
+ * published posts with scheduled draft changes (status='published').
149
+ */
150
+ findReadyToPublish(type: string): Promise<ContentItem[]>;
151
+ /**
152
+ * Find all translations in a translation group
153
+ */
154
+ findTranslations(type: string, translationGroup: string): Promise<ContentItem[]>;
155
+ /**
156
+ * Publish the current draft
157
+ *
158
+ * Promotes draft_revision_id to live_revision_id and clears draft pointer.
159
+ * Syncs the draft revision's data into the content table columns so the
160
+ * content table always reflects the published version.
161
+ * If no draft revision exists, creates one from current data and publishes it.
162
+ */
163
+ publish(type: string, id: string): Promise<ContentItem>;
164
+ /**
165
+ * Unpublish content
166
+ *
167
+ * Removes live pointer but preserves draft. If no draft exists,
168
+ * creates one from the live version so the content isn't lost.
169
+ */
170
+ unpublish(type: string, id: string): Promise<ContentItem>;
171
+ /**
172
+ * Discard pending draft changes
173
+ *
174
+ * Clears draft_revision_id. The content table columns already hold the
175
+ * published version, so no data sync is needed.
176
+ */
177
+ discardDraft(type: string, id: string): Promise<ContentItem>;
178
+ /**
179
+ * Sync data columns in the content table from a data object.
180
+ * Used to promote revision data into the content table on publish.
181
+ * Keys starting with _ are revision metadata (e.g. _slug) and are skipped.
182
+ */
183
+ private syncDataColumns;
184
+ /**
185
+ * Count content items with a pending schedule.
186
+ * Includes both draft-scheduled (status='scheduled') and published
187
+ * posts with scheduled draft changes (status='published', scheduled_at set).
188
+ */
189
+ countScheduled(type: string): Promise<number>;
190
+ /**
191
+ * Map database row to ContentItem
192
+ * Extracts system columns and puts content fields in data
193
+ * Excludes null values from data to match input semantics
194
+ */
195
+ private mapRow;
196
+ /**
197
+ * Map order field names to database columns.
198
+ * Only allows known fields to prevent column enumeration via crafted orderBy values.
199
+ */
200
+ private mapOrderField;
201
+ }
202
+ //#endregion
203
+ //#region src/database/repositories/media.d.ts
204
+ type MediaStatus = "pending" | "ready" | "failed";
205
+ interface MediaItem {
206
+ id: string;
207
+ filename: string;
208
+ mimeType: string;
209
+ size: number | null;
210
+ width: number | null;
211
+ height: number | null;
212
+ alt: string | null;
213
+ caption: string | null;
214
+ storageKey: string;
215
+ status: MediaStatus;
216
+ contentHash: string | null;
217
+ blurhash: string | null;
218
+ dominantColor: string | null;
219
+ createdAt: string;
220
+ authorId: string | null;
221
+ }
222
+ interface CreateMediaInput {
223
+ filename: string;
224
+ mimeType: string;
225
+ size?: number;
226
+ width?: number;
227
+ height?: number;
228
+ alt?: string;
229
+ caption?: string;
230
+ storageKey: string;
231
+ contentHash?: string;
232
+ blurhash?: string;
233
+ dominantColor?: string;
234
+ status?: MediaStatus;
235
+ authorId?: string;
236
+ }
237
+ interface FindManyMediaOptions {
238
+ limit?: number;
239
+ cursor?: string;
240
+ mimeType?: string;
241
+ status?: MediaStatus | "all";
242
+ }
243
+ /**
244
+ * Media repository for database operations
245
+ */
246
+ declare class MediaRepository {
247
+ private db;
248
+ constructor(db: Kysely<Database>);
249
+ /**
250
+ * Create a new media item
251
+ */
252
+ create(input: CreateMediaInput): Promise<MediaItem>;
253
+ /**
254
+ * Create a pending media item (for signed URL upload flow)
255
+ */
256
+ createPending(input: {
257
+ filename: string;
258
+ mimeType: string;
259
+ size?: number;
260
+ storageKey: string;
261
+ contentHash?: string;
262
+ authorId?: string;
263
+ }): Promise<MediaItem>;
264
+ /**
265
+ * Confirm upload (mark as ready)
266
+ */
267
+ confirmUpload(id: string, metadata?: {
268
+ width?: number;
269
+ height?: number;
270
+ size?: number;
271
+ }): Promise<MediaItem | null>;
272
+ /**
273
+ * Mark upload as failed
274
+ */
275
+ markFailed(id: string): Promise<MediaItem | null>;
276
+ /**
277
+ * Find media by ID
278
+ */
279
+ findById(id: string): Promise<MediaItem | null>;
280
+ /**
281
+ * Find media by filename
282
+ * Useful for idempotent imports
283
+ */
284
+ findByFilename(filename: string): Promise<MediaItem | null>;
285
+ /**
286
+ * Find media by content hash
287
+ * Used for deduplication - same content = same hash
288
+ */
289
+ findByContentHash(contentHash: string): Promise<MediaItem | null>;
290
+ /**
291
+ * Find many media items with cursor pagination
292
+ *
293
+ * Uses keyset pagination (cursor-based) for consistent results.
294
+ * The cursor encodes the created_at and id of the last item.
295
+ */
296
+ findMany(options?: FindManyMediaOptions): Promise<FindManyResult<MediaItem>>;
297
+ /**
298
+ * Update media metadata
299
+ */
300
+ update(id: string, input: Partial<Pick<CreateMediaInput, "alt" | "caption" | "width" | "height">>): Promise<MediaItem | null>;
301
+ /**
302
+ * Delete media item
303
+ */
304
+ delete(id: string): Promise<boolean>;
305
+ /**
306
+ * Count media items
307
+ */
308
+ count(mimeType?: string): Promise<number>;
309
+ /**
310
+ * Delete pending uploads older than the given age.
311
+ * Pending uploads that were never confirmed indicate abandoned upload flows.
312
+ *
313
+ * Returns the storage keys of deleted rows so callers can remove the
314
+ * corresponding files from object storage.
315
+ */
316
+ cleanupPendingUploads(maxAgeMs?: number): Promise<string[]>;
317
+ /**
318
+ * Convert database row to MediaItem
319
+ */
320
+ private rowToItem;
321
+ }
322
+ //#endregion
323
+ //#region src/database/repositories/revision.d.ts
324
+ interface Revision {
325
+ id: string;
326
+ collection: string;
327
+ entryId: string;
328
+ data: Record<string, unknown>;
329
+ authorId: string | null;
330
+ createdAt: string;
331
+ }
332
+ //#endregion
333
+ //#region src/database/repositories/comment.d.ts
334
+ /** Public-facing comment shape — no private fields */
335
+ interface PublicComment {
336
+ id: string;
337
+ parentId: string | null;
338
+ authorName: string;
339
+ isRegisteredUser: boolean;
340
+ body: string;
341
+ createdAt: string;
342
+ replies?: PublicComment[];
343
+ }
344
+ //#endregion
345
+ //#region src/database/repositories/byline.d.ts
346
+ interface ContentBylineInput {
347
+ bylineId: string;
348
+ roleLabel?: string | null;
349
+ }
350
+ //#endregion
351
+ //#region src/fields/types.d.ts
352
+ /**
353
+ * SQLite column types that map from field types
354
+ */
355
+ type ColumnType = "TEXT" | "REAL" | "INTEGER" | "JSON";
356
+ /**
357
+ * Base field definition
358
+ *
359
+ * Note: schema uses z.ZodTypeAny to accommodate optional/default wrappers
360
+ */
361
+ interface FieldDefinition<_T = unknown> {
362
+ type: string;
363
+ /**
364
+ * The SQLite column type to use when storing this field
365
+ */
366
+ columnType: ColumnType;
367
+ schema: z.ZodTypeAny;
368
+ options?: unknown;
369
+ ui?: FieldUIHints;
370
+ }
371
+ /**
372
+ * UI hints for admin rendering
373
+ */
374
+ interface FieldUIHints {
375
+ widget?: string;
376
+ placeholder?: string;
377
+ helpText?: string;
378
+ rows?: number;
379
+ min?: number | string;
380
+ max?: number | string;
381
+ [key: string]: unknown;
382
+ }
383
+ /**
384
+ * Portable Text block structure
385
+ */
386
+ interface PortableTextBlock$2 {
387
+ _type: string;
388
+ _key: string;
389
+ [key: string]: unknown;
390
+ }
391
+ /**
392
+ * @deprecated Use MediaValue instead. ImageValue is an alias for backwards compatibility.
393
+ */
394
+ type ImageValue = MediaValue;
395
+ /**
396
+ * File field value
397
+ */
398
+ interface FileValue {
399
+ id: string;
400
+ url: string;
401
+ filename: string;
402
+ mimeType: string;
403
+ size: number;
404
+ }
405
+ //#endregion
406
+ //#region src/fields/image.d.ts
407
+ /**
408
+ * Image field
409
+ * References media items from the media library
410
+ */
411
+ declare function image(options?: {
412
+ required?: boolean;
413
+ maxSize?: number;
414
+ allowedTypes?: string[];
415
+ }): FieldDefinition<ImageValue | undefined>;
416
+ //#endregion
417
+ //#region src/fields/reference.d.ts
418
+ /**
419
+ * Reference field
420
+ * References another content item by ID
421
+ */
422
+ declare function reference(collection: string, options?: {
423
+ required?: boolean;
424
+ }): FieldDefinition<string | undefined>;
425
+ //#endregion
426
+ //#region src/fields/portable-text.d.ts
427
+ /**
428
+ * Portable Text field
429
+ * Stores structured content in Portable Text format
430
+ */
431
+ declare function portableText(options?: {
432
+ required?: boolean;
433
+ }): FieldDefinition<PortableTextBlock$2[] | undefined>;
434
+ //#endregion
435
+ //#region src/api/types.d.ts
436
+ /**
437
+ * List response with cursor pagination
438
+ */
439
+ interface ListResponse<T> {
440
+ items: T[];
441
+ nextCursor?: string;
442
+ }
443
+ /**
444
+ * Content API responses
445
+ */
446
+ interface ContentListResponse extends ListResponse<ContentItem> {}
447
+ interface ContentResponse {
448
+ item: ContentItem;
449
+ /** Opaque revision token for optimistic concurrency */
450
+ _rev?: string;
451
+ }
452
+ /**
453
+ * Manifest API response
454
+ */
455
+ interface ManifestResponse {
456
+ version: string;
457
+ hash: string;
458
+ collections: Record<string, {
459
+ label: string;
460
+ labelSingular: string;
461
+ supports: string[];
462
+ fields: Record<string, FieldDescriptor>;
463
+ }>;
464
+ plugins: Record<string, {
465
+ adminPages?: Array<{
466
+ path: string;
467
+ component: string;
468
+ }>;
469
+ widgets?: string[];
470
+ }>;
471
+ }
472
+ interface FieldDescriptor {
473
+ kind: string;
474
+ label?: string;
475
+ required?: boolean;
476
+ options?: Array<{
477
+ value: string;
478
+ label: string;
479
+ }>;
480
+ }
481
+ /**
482
+ * Discriminated union for handler results.
483
+ *
484
+ * Handlers return `ApiResult<T>` -- either `{ success: true, data: T }` or
485
+ * `{ success: false, error: { code, message } }`. The `success` literal
486
+ * enables TypeScript narrowing on `.data`.
487
+ *
488
+ * The generic `E` parameter defaults to `ErrorCode` but can be narrowed to
489
+ * `OAuthErrorCode` for OAuth token-endpoint handlers.
490
+ *
491
+ * Use `unwrapResult()` from `error.ts` to convert to an HTTP Response.
492
+ */
493
+ type ApiResult<T, E extends string = string> = {
494
+ success: true;
495
+ data: T;
496
+ } | {
497
+ success: false;
498
+ error: {
499
+ code: E;
500
+ message: string;
501
+ details?: Record<string, unknown>;
502
+ };
503
+ };
504
+ /**
505
+ * API request context
506
+ */
507
+ interface ApiContext {
508
+ userId?: string;
509
+ userRole?: string;
510
+ }
511
+ //#endregion
512
+ //#region src/api/handlers/content.d.ts
513
+ /**
514
+ * Trashed content item with deletion timestamp
515
+ */
516
+ interface TrashedContentItem {
517
+ id: string;
518
+ type: string;
519
+ slug: string | null;
520
+ status: string;
521
+ data: Record<string, unknown>;
522
+ authorId: string | null;
523
+ createdAt: string;
524
+ updatedAt: string;
525
+ publishedAt: string | null;
526
+ deletedAt: string;
527
+ }
528
+ /**
529
+ * Create content list handler
530
+ */
531
+ declare function handleContentList(db: Kysely<Database>, collection: string, params: {
532
+ cursor?: string;
533
+ limit?: number;
534
+ status?: string;
535
+ orderBy?: string;
536
+ order?: "asc" | "desc";
537
+ locale?: string;
538
+ }): Promise<ApiResult<ContentListResponse>>;
539
+ /**
540
+ * Get single content item
541
+ */
542
+ declare function handleContentGet(db: Kysely<Database>, collection: string, id: string, locale?: string): Promise<ApiResult<ContentResponse>>;
543
+ /**
544
+ * Get a content item by id, including trashed items.
545
+ * Used by restore endpoint for ownership checks on soft-deleted items.
546
+ */
547
+ declare function handleContentGetIncludingTrashed(db: Kysely<Database>, collection: string, id: string, locale?: string): Promise<ApiResult<ContentResponse>>;
548
+ /**
549
+ * Create content item.
550
+ *
551
+ * Content + SEO writes are wrapped in a transaction so either both succeed
552
+ * or neither does. If `body.seo` is provided for a non-SEO collection, the
553
+ * API returns a validation error rather than silently dropping it.
554
+ */
555
+ declare function handleContentCreate(db: Kysely<Database>, collection: string, body: {
556
+ data: Record<string, unknown>;
557
+ slug?: string;
558
+ status?: string;
559
+ authorId?: string;
560
+ bylines?: ContentBylineInput[];
561
+ locale?: string;
562
+ translationOf?: string;
563
+ seo?: ContentSeoInput;
564
+ createdAt?: string | null;
565
+ publishedAt?: string | null;
566
+ }): Promise<ApiResult<ContentResponse>>;
567
+ /**
568
+ * Update content item.
569
+ * If `_rev` is provided, validates it against the current version before writing.
570
+ * No `_rev` = blind write (backwards-compatible for admin UI).
571
+ *
572
+ * Content + SEO writes are wrapped in a transaction for atomicity.
573
+ */
574
+ declare function handleContentUpdate(db: Kysely<Database>, collection: string, id: string, body: {
575
+ data?: Record<string, unknown>;
576
+ slug?: string;
577
+ status?: string;
578
+ authorId?: string | null;
579
+ bylines?: ContentBylineInput[];
580
+ _rev?: string;
581
+ seo?: ContentSeoInput;
582
+ }): Promise<ApiResult<ContentResponse>>;
583
+ /**
584
+ * Duplicate content item.
585
+ *
586
+ * Only copies SEO data if the collection has SEO enabled.
587
+ * Always returns consistent `seo` shape for SEO-enabled collections.
588
+ */
589
+ declare function handleContentDuplicate(db: Kysely<Database>, collection: string, id: string, authorId?: string): Promise<ApiResult<{
590
+ item: ContentItem;
591
+ }>>;
592
+ /**
593
+ * Delete content item (soft delete - moves to trash)
594
+ */
595
+ declare function handleContentDelete(db: Kysely<Database>, collection: string, id: string): Promise<ApiResult<{
596
+ deleted: true;
597
+ }>>;
598
+ /**
599
+ * Restore content item from trash
600
+ */
601
+ declare function handleContentRestore(db: Kysely<Database>, collection: string, id: string): Promise<ApiResult<{
602
+ restored: true;
603
+ }>>;
604
+ /**
605
+ * Permanently delete content item (cannot be undone).
606
+ * Also cleans up associated SEO data.
607
+ */
608
+ declare function handleContentPermanentDelete(db: Kysely<Database>, collection: string, id: string): Promise<ApiResult<{
609
+ deleted: true;
610
+ }>>;
611
+ /**
612
+ * List trashed content items
613
+ */
614
+ declare function handleContentListTrashed(db: Kysely<Database>, collection: string, options?: {
615
+ limit?: number;
616
+ cursor?: string;
617
+ }): Promise<ApiResult<{
618
+ items: TrashedContentItem[];
619
+ nextCursor?: string;
620
+ }>>;
621
+ /**
622
+ * Count trashed content items
623
+ */
624
+ declare function handleContentCountTrashed(db: Kysely<Database>, collection: string): Promise<ApiResult<{
625
+ count: number;
626
+ }>>;
627
+ /**
628
+ * Schedule content for future publishing
629
+ */
630
+ declare function handleContentSchedule(db: Kysely<Database>, collection: string, id: string, scheduledAt: string): Promise<ApiResult<ContentResponse>>;
631
+ /**
632
+ * Unschedule content (revert to draft)
633
+ */
634
+ declare function handleContentUnschedule(db: Kysely<Database>, collection: string, id: string): Promise<ApiResult<ContentResponse>>;
635
+ /**
636
+ * Publish content immediately.
637
+ *
638
+ * Wrapped in a transaction because publish performs multiple writes
639
+ * (syncDataColumns, slug sync, status/revision update) that must
640
+ * be atomic to prevent FTS shadow table corruption on crash.
641
+ */
642
+ declare function handleContentPublish(db: Kysely<Database>, collection: string, id: string): Promise<ApiResult<ContentResponse>>;
643
+ /**
644
+ * Unpublish content (revert to draft).
645
+ *
646
+ * Wrapped in a transaction — unpublish may create a draft revision
647
+ * from the live version then update the status, which is multi-step.
648
+ */
649
+ declare function handleContentUnpublish(db: Kysely<Database>, collection: string, id: string): Promise<ApiResult<ContentResponse>>;
650
+ /**
651
+ * Count scheduled content items
652
+ */
653
+ declare function handleContentCountScheduled(db: Kysely<Database>, collection: string): Promise<ApiResult<{
654
+ count: number;
655
+ }>>;
656
+ /**
657
+ * Discard draft changes (revert to live version)
658
+ */
659
+ declare function handleContentDiscardDraft(db: Kysely<Database>, collection: string, id: string): Promise<ApiResult<ContentResponse>>;
660
+ /**
661
+ * Compare live and draft revisions
662
+ */
663
+ declare function handleContentCompare(db: Kysely<Database>, collection: string, id: string): Promise<ApiResult<{
664
+ hasChanges: boolean;
665
+ live: Record<string, unknown> | null;
666
+ draft: Record<string, unknown> | null;
667
+ }>>;
668
+ /**
669
+ * Get all translations for a content item.
670
+ * Returns the item's translation group members with locale and status info.
671
+ */
672
+ declare function handleContentTranslations(db: Kysely<Database>, collection: string, id: string): Promise<ApiResult<{
673
+ translationGroup: string;
674
+ translations: Array<{
675
+ id: string;
676
+ locale: string | null;
677
+ slug: string | null;
678
+ status: string;
679
+ updatedAt: string;
680
+ }>;
681
+ }>>;
682
+ //#endregion
683
+ //#region src/api/handlers/manifest.d.ts
684
+ interface CollectionDefinition {
685
+ schema: {
686
+ _def?: {
687
+ shape?: () => Record<string, unknown>;
688
+ };
689
+ shape?: Record<string, unknown>;
690
+ };
691
+ admin: {
692
+ label: string;
693
+ labelSingular?: string;
694
+ supports?: string[];
695
+ };
696
+ }
697
+ type CollectionMap = Record<string, CollectionDefinition>;
698
+ /**
699
+ * Generate admin manifest from collections
700
+ */
701
+ declare function generateManifest(collections: CollectionMap, plugins?: Record<string, {
702
+ adminPages?: Array<{
703
+ path: string;
704
+ component: string;
705
+ }>;
706
+ widgets?: string[];
707
+ }>): Promise<ManifestResponse>;
708
+ //#endregion
709
+ //#region src/api/handlers/revision.d.ts
710
+ interface RevisionListResponse {
711
+ items: Revision[];
712
+ total: number;
713
+ }
714
+ interface RevisionResponse {
715
+ item: Revision;
716
+ }
717
+ /**
718
+ * List revisions for a content entry
719
+ */
720
+ declare function handleRevisionList(db: Kysely<Database>, collection: string, entryId: string, params?: {
721
+ limit?: number;
722
+ }): Promise<ApiResult<RevisionListResponse>>;
723
+ /**
724
+ * Get a specific revision
725
+ */
726
+ declare function handleRevisionGet(db: Kysely<Database>, revisionId: string): Promise<ApiResult<RevisionResponse>>;
727
+ /**
728
+ * Restore a revision (updates content to this revision's data and creates new revision)
729
+ */
730
+ declare function handleRevisionRestore(db: Kysely<Database>, revisionId: string, callerUserId: string): Promise<ApiResult<ContentResponse>>;
731
+ //#endregion
732
+ //#region src/api/handlers/media.d.ts
733
+ interface MediaListResponse {
734
+ items: MediaItem[];
735
+ nextCursor?: string;
736
+ }
737
+ interface MediaResponse {
738
+ item: MediaItem;
739
+ }
740
+ /**
741
+ * List media items
742
+ */
743
+ declare function handleMediaList(db: Kysely<Database>, params: {
744
+ cursor?: string;
745
+ limit?: number;
746
+ mimeType?: string;
747
+ }): Promise<ApiResult<MediaListResponse>>;
748
+ /**
749
+ * Get single media item
750
+ */
751
+ declare function handleMediaGet(db: Kysely<Database>, id: string): Promise<ApiResult<MediaResponse>>;
752
+ /**
753
+ * Create media item (after file upload)
754
+ */
755
+ declare function handleMediaCreate(db: Kysely<Database>, input: {
756
+ filename: string;
757
+ mimeType: string;
758
+ size?: number;
759
+ width?: number;
760
+ height?: number;
761
+ alt?: string;
762
+ storageKey: string;
763
+ contentHash?: string;
764
+ blurhash?: string;
765
+ dominantColor?: string;
766
+ authorId?: string;
767
+ }): Promise<ApiResult<MediaResponse>>;
768
+ /**
769
+ * Update media metadata
770
+ */
771
+ declare function handleMediaUpdate(db: Kysely<Database>, id: string, input: {
772
+ alt?: string;
773
+ caption?: string;
774
+ width?: number;
775
+ height?: number;
776
+ }): Promise<ApiResult<MediaResponse>>;
777
+ /**
778
+ * Delete media item
779
+ */
780
+ declare function handleMediaDelete(db: Kysely<Database>, id: string): Promise<ApiResult<{
781
+ deleted: true;
782
+ }>>;
783
+ //#endregion
784
+ //#region src/schema/registry.d.ts
785
+ /**
786
+ * Error thrown when a schema operation fails
787
+ */
788
+ declare class SchemaError extends Error {
789
+ code: string;
790
+ details?: Record<string, unknown> | undefined;
791
+ constructor(message: string, code: string, details?: Record<string, unknown> | undefined);
792
+ }
793
+ /**
794
+ * Schema Registry
795
+ *
796
+ * Manages collection and field definitions stored in the database.
797
+ * Handles runtime DDL operations (CREATE TABLE, ALTER TABLE).
798
+ */
799
+ declare class SchemaRegistry {
800
+ private db;
801
+ constructor(db: Kysely<Database>);
802
+ /**
803
+ * List all collections
804
+ */
805
+ listCollections(): Promise<Collection[]>;
806
+ /**
807
+ * Get a collection by slug
808
+ */
809
+ getCollection(slug: string): Promise<Collection | null>;
810
+ /**
811
+ * Get a collection with all its fields
812
+ */
813
+ getCollectionWithFields(slug: string): Promise<CollectionWithFields | null>;
814
+ /**
815
+ * Create a new collection
816
+ */
817
+ createCollection(input: CreateCollectionInput): Promise<Collection>;
818
+ /**
819
+ * Update a collection
820
+ */
821
+ updateCollection(slug: string, input: UpdateCollectionInput): Promise<Collection>;
822
+ /**
823
+ * Delete a collection
824
+ */
825
+ deleteCollection(slug: string, options?: {
826
+ force?: boolean;
827
+ }): Promise<void>;
828
+ /**
829
+ * List fields for a collection
830
+ */
831
+ listFields(collectionId: string): Promise<Field[]>;
832
+ /**
833
+ * Get a field by slug within a collection
834
+ */
835
+ getField(collectionSlug: string, fieldSlug: string): Promise<Field | null>;
836
+ /**
837
+ * Create a new field
838
+ */
839
+ createField(collectionSlug: string, input: CreateFieldInput): Promise<Field>;
840
+ /**
841
+ * Update a field
842
+ */
843
+ updateField(collectionSlug: string, fieldSlug: string, input: UpdateFieldInput): Promise<Field>;
844
+ /**
845
+ * Rebuild the search index for a collection
846
+ *
847
+ * Called when searchable fields change. If search is enabled for the collection,
848
+ * this will rebuild the FTS table with the updated field list.
849
+ */
850
+ private rebuildSearchIndex;
851
+ /**
852
+ * Delete a field
853
+ */
854
+ deleteField(collectionSlug: string, fieldSlug: string): Promise<void>;
855
+ /**
856
+ * Reorder fields
857
+ */
858
+ reorderFields(collectionSlug: string, fieldSlugs: string[]): Promise<void>;
859
+ /**
860
+ * Create a content table for a collection
861
+ */
862
+ private createContentTable;
863
+ /**
864
+ * Drop a content table
865
+ */
866
+ private dropContentTable;
867
+ /**
868
+ * Add a column to a content table
869
+ */
870
+ private addColumn;
871
+ /**
872
+ * Drop a column from a content table
873
+ */
874
+ private dropColumn;
875
+ /**
876
+ * Check if a collection has any content
877
+ */
878
+ private collectionHasContent;
879
+ /**
880
+ * Get table name for a collection
881
+ */
882
+ private getTableName;
883
+ /**
884
+ * Get column name for a field
885
+ */
886
+ private getColumnName;
887
+ /**
888
+ * Validate a slug
889
+ */
890
+ private validateSlug;
891
+ /**
892
+ * Format a default value for SQL.
893
+ *
894
+ * SQLite `ALTER TABLE ADD COLUMN ... DEFAULT` requires a literal constant
895
+ * expression — parameterized values cannot be used here. We manually escape
896
+ * single quotes and coerce types to ensure the output is safe.
897
+ *
898
+ * INTEGER/REAL values are coerced through `Number()` which can only produce
899
+ * digits, `.`, `-`, `e`, `Infinity`, or `NaN` — all safe in SQL.
900
+ * TEXT/JSON values have single quotes escaped via SQL standard doubling (`''`).
901
+ */
902
+ private formatDefaultValue;
903
+ /**
904
+ * Get empty default for a field type
905
+ */
906
+ private getEmptyDefault;
907
+ /**
908
+ * Map a collection row to a Collection object
909
+ */
910
+ private mapCollectionRow;
911
+ /**
912
+ * Map a field row to a Field object
913
+ */
914
+ private mapFieldRow;
915
+ /**
916
+ * Discover orphaned content tables
917
+ *
918
+ * Finds ec_* tables that exist in the database but don't have a
919
+ * corresponding entry in _dineway_collections.
920
+ */
921
+ discoverOrphanedTables(): Promise<Array<{
922
+ slug: string;
923
+ tableName: string;
924
+ rowCount: number;
925
+ }>>;
926
+ /**
927
+ * Register an orphaned table as a collection
928
+ *
929
+ * Creates a _dineway_collections entry for an existing ec_* table.
930
+ */
931
+ registerOrphanedTable(slug: string, options?: {
932
+ label?: string;
933
+ labelSingular?: string;
934
+ description?: string;
935
+ }): Promise<Collection>;
936
+ /**
937
+ * Convert slug to human-readable label
938
+ */
939
+ private slugToLabel;
940
+ }
941
+ //#endregion
942
+ //#region src/schema/query.d.ts
943
+ /**
944
+ * Get collection metadata by slug.
945
+ *
946
+ * @example
947
+ * ```ts
948
+ * import { getCollectionInfo } from "dineway";
949
+ *
950
+ * const info = await getCollectionInfo("posts");
951
+ * if (info?.commentsEnabled) {
952
+ * // render comment UI
953
+ * }
954
+ * ```
955
+ */
956
+ declare function getCollectionInfo(slug: string): Promise<Collection | null>;
957
+ //#endregion
958
+ //#region src/sections/types.d.ts
959
+ /**
960
+ * Section source types
961
+ */
962
+ type SectionSource = "theme" | "user" | "import";
963
+ /**
964
+ * Section as returned to templates/admin
965
+ */
966
+ interface Section {
967
+ id: string;
968
+ slug: string;
969
+ title: string;
970
+ description?: string;
971
+ keywords: string[];
972
+ content: PortableTextBlock$2[];
973
+ previewUrl?: string;
974
+ source: SectionSource;
975
+ themeId?: string;
976
+ createdAt: string;
977
+ updatedAt: string;
978
+ }
979
+ /**
980
+ * Input for creating a section
981
+ */
982
+ interface CreateSectionInput {
983
+ slug: string;
984
+ title: string;
985
+ description?: string;
986
+ keywords?: string[];
987
+ content: PortableTextBlock$2[];
988
+ previewMediaId?: string;
989
+ source?: SectionSource;
990
+ themeId?: string;
991
+ }
992
+ /**
993
+ * Input for updating a section
994
+ */
995
+ interface UpdateSectionInput {
996
+ slug?: string;
997
+ title?: string;
998
+ description?: string;
999
+ keywords?: string[];
1000
+ content?: PortableTextBlock$2[];
1001
+ previewMediaId?: string | null;
1002
+ }
1003
+ /**
1004
+ * Options for querying sections
1005
+ */
1006
+ interface GetSectionsOptions {
1007
+ /** Filter by source */
1008
+ source?: SectionSource;
1009
+ /** Search title, description, keywords */
1010
+ search?: string;
1011
+ /** Limit results */
1012
+ limit?: number;
1013
+ /** Cursor for pagination */
1014
+ cursor?: string;
1015
+ }
1016
+ //#endregion
1017
+ //#region src/sections/index.d.ts
1018
+ /**
1019
+ * Get a section by slug
1020
+ *
1021
+ * @example
1022
+ * ```ts
1023
+ * import { getSection } from "dineway";
1024
+ *
1025
+ * const section = await getSection("hero-centered");
1026
+ * if (section) {
1027
+ * console.log(section.content); // Portable Text array
1028
+ * }
1029
+ * ```
1030
+ */
1031
+ declare function getSection(slug: string): Promise<Section | null>;
1032
+ /**
1033
+ * Get all sections with optional filtering
1034
+ *
1035
+ * @example
1036
+ * ```ts
1037
+ * import { getSections } from "dineway";
1038
+ *
1039
+ * // Get all theme-provided sections
1040
+ * const themeSections = await getSections({ source: "theme" });
1041
+ *
1042
+ * // Search sections
1043
+ * const results = await getSections({ search: "pricing" });
1044
+ * ```
1045
+ */
1046
+ declare function getSections(options?: GetSectionsOptions): Promise<FindManyResult<Section>>;
1047
+ //#endregion
1048
+ //#region src/plugins/sandbox/types.d.ts
1049
+ /**
1050
+ * Resource limits for sandboxed plugins.
1051
+ * Enforced by the sandbox runtime.
1052
+ */
1053
+ interface ResourceLimits {
1054
+ /** CPU time per invocation in milliseconds (default: 50ms) */
1055
+ cpuMs?: number;
1056
+ /** Memory limit in MB (default: 128MB) */
1057
+ memoryMb?: number;
1058
+ /** Maximum subrequests per invocation (default: 10) */
1059
+ subrequests?: number;
1060
+ /** Wall-clock time limit in milliseconds (default: 30000ms) */
1061
+ wallTimeMs?: number;
1062
+ }
1063
+ /**
1064
+ * Storage interface for loading plugin code.
1065
+ * Could be R2, local filesystem, or any other storage backend.
1066
+ */
1067
+ interface PluginCodeStorage {
1068
+ /** Get plugin bundle code by path */
1069
+ get(path: string): Promise<string | null>;
1070
+ /** Check if a bundle exists */
1071
+ exists(path: string): Promise<boolean>;
1072
+ }
1073
+ /**
1074
+ * Serialized email message for sandbox RPC transport.
1075
+ * Matches the core EmailMessage type but uses only serializable fields.
1076
+ */
1077
+ interface SandboxEmailMessage {
1078
+ to: string;
1079
+ subject: string;
1080
+ text: string;
1081
+ html?: string;
1082
+ }
1083
+ /**
1084
+ * Callback for sending email from a sandboxed plugin.
1085
+ * The sandbox runner wires this up from the EmailPipeline.
1086
+ *
1087
+ * @param message - The email message to send
1088
+ * @param pluginId - The sending plugin's ID (used as source)
1089
+ */
1090
+ type SandboxEmailSendCallback = (message: SandboxEmailMessage, pluginId: string) => Promise<void>;
1091
+ /**
1092
+ * Options for creating a sandbox runner
1093
+ */
1094
+ interface SandboxOptions {
1095
+ /** Storage interface for loading plugin code */
1096
+ storage?: PluginCodeStorage;
1097
+ /** Database for bridge operations */
1098
+ db: Kysely<Database>;
1099
+ /** Default resource limits */
1100
+ limits?: ResourceLimits;
1101
+ /** Site info for plugin context (injected into wrapper at generation time) */
1102
+ siteInfo?: {
1103
+ name: string;
1104
+ url: string;
1105
+ locale: string;
1106
+ };
1107
+ /** Email send callback, wired from the EmailPipeline by the runtime */
1108
+ emailSend?: SandboxEmailSendCallback;
1109
+ }
1110
+ /**
1111
+ * A sandboxed plugin instance.
1112
+ * Provides methods to invoke hooks and routes in the isolated environment.
1113
+ */
1114
+ interface SandboxedPlugin {
1115
+ /** Unique identifier: `${manifest.id}:${manifest.version}` */
1116
+ readonly id: string;
1117
+ /**
1118
+ * Invoke a hook in the sandboxed plugin.
1119
+ *
1120
+ * @param hookName - Name of the hook (e.g., "content:beforeSave")
1121
+ * @param event - Event data to pass to the hook
1122
+ * @returns Hook result (transformed content, void, etc.)
1123
+ */
1124
+ invokeHook(hookName: string, event: unknown): Promise<unknown>;
1125
+ /**
1126
+ * Invoke an API route in the sandboxed plugin.
1127
+ *
1128
+ * @param routeName - Name of the route
1129
+ * @param input - Validated input data
1130
+ * @param request - Serialized request info for context
1131
+ * @returns Route response data
1132
+ */
1133
+ invokeRoute(routeName: string, input: unknown, request: SerializedRequest): Promise<unknown>;
1134
+ /**
1135
+ * Terminate the sandboxed plugin.
1136
+ * Releases resources and prevents further invocations.
1137
+ */
1138
+ terminate(): Promise<void>;
1139
+ }
1140
+ /**
1141
+ * Serialized request for RPC transport.
1142
+ * Sandbox RPC layers can't pass Request objects directly.
1143
+ */
1144
+ interface SerializedRequest {
1145
+ url: string;
1146
+ method: string;
1147
+ headers: Record<string, string>;
1148
+ /** Normalized request metadata extracted before RPC serialization */
1149
+ meta: RequestMeta;
1150
+ }
1151
+ /**
1152
+ * Sandbox runner interface.
1153
+ * Platform adapters implement this to provide plugin isolation.
1154
+ */
1155
+ interface SandboxRunner {
1156
+ /**
1157
+ * Check if sandboxing is available on this platform.
1158
+ * Returns false for platforms that don't support isolation.
1159
+ */
1160
+ isAvailable(): boolean;
1161
+ /**
1162
+ * Load a sandboxed plugin from code.
1163
+ *
1164
+ * @param manifest - Plugin manifest with metadata and capabilities
1165
+ * @param code - The bundled plugin JavaScript code
1166
+ * @returns A sandboxed plugin instance
1167
+ * @throws If sandboxing is not available or plugin can't be loaded
1168
+ */
1169
+ load(manifest: PluginManifest, code: string): Promise<SandboxedPlugin>;
1170
+ /**
1171
+ * Set the email send callback for sandboxed plugins.
1172
+ * Called after the EmailPipeline is created, since the pipeline
1173
+ * doesn't exist when the sandbox runner is constructed.
1174
+ */
1175
+ setEmailSend(callback: SandboxEmailSendCallback | null): void;
1176
+ /**
1177
+ * Terminate all loaded sandboxed plugins.
1178
+ * Called during shutdown or when reconfiguring.
1179
+ */
1180
+ terminateAll(): Promise<void>;
1181
+ }
1182
+ /**
1183
+ * Factory function type for creating sandbox runners.
1184
+ * Exported by platform adapters.
1185
+ *
1186
+ * @example
1187
+ * ```typescript
1188
+ * // In a platform adapter module
1189
+ * export const createSandboxRunner: SandboxRunnerFactory = (options) => {
1190
+ * return new NodeSandboxRunner(options);
1191
+ * };
1192
+ * ```
1193
+ */
1194
+ type SandboxRunnerFactory = (options: SandboxOptions) => SandboxRunner;
1195
+ //#endregion
1196
+ //#region src/content/converters/types.d.ts
1197
+ /**
1198
+ * Portable Text Types
1199
+ *
1200
+ * Defines the structure of Portable Text blocks used in Dineway.
1201
+ */
1202
+ /**
1203
+ * Base span (inline text)
1204
+ */
1205
+ interface PortableTextSpan {
1206
+ _type: "span";
1207
+ _key: string;
1208
+ text: string;
1209
+ marks?: string[];
1210
+ }
1211
+ /**
1212
+ * Mark definition (bold, italic, link, etc.)
1213
+ */
1214
+ interface PortableTextMarkDef {
1215
+ _type: string;
1216
+ _key: string;
1217
+ [key: string]: unknown;
1218
+ }
1219
+ /**
1220
+ * Link mark definition
1221
+ */
1222
+ interface PortableTextLinkMark extends PortableTextMarkDef {
1223
+ _type: "link";
1224
+ href: string;
1225
+ blank?: boolean;
1226
+ }
1227
+ /**
1228
+ * Text block (paragraph, heading, etc.)
1229
+ */
1230
+ interface PortableTextTextBlock {
1231
+ _type: "block";
1232
+ _key: string;
1233
+ style?: "normal" | "h1" | "h2" | "h3" | "h4" | "h5" | "h6" | "blockquote";
1234
+ listItem?: "bullet" | "number";
1235
+ level?: number;
1236
+ children: PortableTextSpan[];
1237
+ markDefs?: PortableTextMarkDef[];
1238
+ }
1239
+ /**
1240
+ * Image block
1241
+ */
1242
+ interface PortableTextImageBlock {
1243
+ _type: "image";
1244
+ _key: string;
1245
+ asset: {
1246
+ _ref: string;
1247
+ url?: string; /** Provider ID for external media (e.g., "image-cdn") */
1248
+ provider?: string;
1249
+ };
1250
+ alt?: string;
1251
+ caption?: string;
1252
+ /** Original image width */
1253
+ width?: number;
1254
+ /** Original image height */
1255
+ height?: number;
1256
+ /** Display width for this instance (overrides original) */
1257
+ displayWidth?: number;
1258
+ /** Display height for this instance (overrides original) */
1259
+ displayHeight?: number;
1260
+ }
1261
+ /**
1262
+ * Code block
1263
+ */
1264
+ interface PortableTextCodeBlock {
1265
+ _type: "code";
1266
+ _key: string;
1267
+ code: string;
1268
+ language?: string;
1269
+ filename?: string;
1270
+ }
1271
+ /**
1272
+ * Unknown/custom block (preserved for plugin compatibility)
1273
+ */
1274
+ interface PortableTextUnknownBlock {
1275
+ _type: string;
1276
+ _key: string;
1277
+ [key: string]: unknown;
1278
+ }
1279
+ /**
1280
+ * Any Portable Text block
1281
+ */
1282
+ type PortableTextBlock$1 = PortableTextTextBlock | PortableTextImageBlock | PortableTextCodeBlock | PortableTextUnknownBlock;
1283
+ /**
1284
+ * ProseMirror JSON types (simplified for TipTap)
1285
+ */
1286
+ interface ProseMirrorMark {
1287
+ type: string;
1288
+ attrs?: Record<string, unknown>;
1289
+ }
1290
+ interface ProseMirrorNode {
1291
+ type: string;
1292
+ attrs?: Record<string, unknown>;
1293
+ content?: ProseMirrorNode[];
1294
+ marks?: ProseMirrorMark[];
1295
+ text?: string;
1296
+ }
1297
+ interface ProseMirrorDocument {
1298
+ type: "doc";
1299
+ content: ProseMirrorNode[];
1300
+ }
1301
+ //#endregion
1302
+ //#region src/content/converters/prosemirror-to-portable-text.d.ts
1303
+ /**
1304
+ * Convert ProseMirror document to Portable Text
1305
+ */
1306
+ declare function prosemirrorToPortableText(doc: ProseMirrorDocument): PortableTextBlock$1[];
1307
+ //#endregion
1308
+ //#region src/content/converters/portable-text-to-prosemirror.d.ts
1309
+ /**
1310
+ * Convert Portable Text to ProseMirror document
1311
+ */
1312
+ declare function portableTextToProsemirror(blocks: PortableTextBlock$1[]): ProseMirrorDocument;
1313
+ //#endregion
1314
+ //#region src/utils/hash.d.ts
1315
+ /**
1316
+ * SHA-256 hash of a string, truncated to 16 hex chars (64 bits).
1317
+ * For cache invalidation / ETags — not for security.
1318
+ */
1319
+ declare function hashString(content: string): Promise<string>;
1320
+ /**
1321
+ * Compute content hash using Web Crypto API
1322
+ *
1323
+ * Uses SHA-1 which is the fastest option in SubtleCrypto.
1324
+ * SHA-1 is cryptographically weak but fine for content deduplication
1325
+ * where we only need to detect identical files, not resist attacks.
1326
+ *
1327
+ * Returns hex string prefixed with "sha1:" for future-proofing
1328
+ */
1329
+ declare function computeContentHash(content: Uint8Array | ArrayBuffer): Promise<string>;
1330
+ //#endregion
1331
+ //#region src/utils/url.d.ts
1332
+ /**
1333
+ * URL scheme validation utilities
1334
+ *
1335
+ * Prevents XSS via dangerous URL schemes (javascript:, data:, vbscript:, etc.)
1336
+ * by allowlisting known-safe schemes before rendering into href attributes.
1337
+ */
1338
+ /**
1339
+ * Returns the URL unchanged if it uses a safe scheme, otherwise returns "#".
1340
+ *
1341
+ * Use this at the render layer as the primary defense against XSS via
1342
+ * dangerous URL schemes like `javascript:`, `data:`, or `vbscript:`.
1343
+ *
1344
+ * @example
1345
+ * ```ts
1346
+ * sanitizeHref("https://example.com") // "https://example.com"
1347
+ * sanitizeHref("/about") // "/about"
1348
+ * sanitizeHref("#section") // "#section"
1349
+ * sanitizeHref("mailto:a@b.com") // "mailto:a@b.com"
1350
+ * sanitizeHref("javascript:alert(1)") // "#"
1351
+ * sanitizeHref("data:text/html,<script>") // "#"
1352
+ * sanitizeHref("") // "#"
1353
+ * ```
1354
+ */
1355
+ declare function sanitizeHref(url: string | undefined | null): string;
1356
+ /**
1357
+ * Returns true if the URL uses a safe scheme for rendering in href attributes.
1358
+ */
1359
+ declare function isSafeHref(url: string): boolean;
1360
+ //#endregion
1361
+ //#region src/visual-editing/editable.d.ts
1362
+ /**
1363
+ * Visual editing annotation system
1364
+ *
1365
+ * Creates Proxy objects that emit data-dineway-ref attributes when spread onto elements.
1366
+ */
1367
+ interface CMSAnnotation {
1368
+ collection: string;
1369
+ id: string;
1370
+ field?: string;
1371
+ /** Entry status — only present on entry-level annotations (not field-level) */
1372
+ status?: string;
1373
+ /** Whether the entry has unpublished draft changes */
1374
+ hasDraft?: boolean;
1375
+ }
1376
+ /** The shape returned when spreading an edit annotation onto an element */
1377
+ interface FieldAnnotation {
1378
+ "data-dineway-ref": string;
1379
+ }
1380
+ interface EditableOptions {
1381
+ /** Entry status: "draft", "published", "scheduled" */
1382
+ status?: string;
1383
+ /** true when draftRevisionId exists and differs from liveRevisionId */
1384
+ hasDraft?: boolean;
1385
+ }
1386
+ /**
1387
+ * Create an editable proxy for an entry.
1388
+ *
1389
+ * Usage:
1390
+ * - `{...entry.edit}` - entry-level annotation (includes status/hasDraft)
1391
+ * - `{...entry.edit.title}` - field-level annotation
1392
+ * - `{...entry.edit['nested.field']}` - nested field (bracket notation)
1393
+ */
1394
+ declare function createEditable(collection: string, id: string, options?: EditableOptions): EditProxy;
1395
+ /**
1396
+ * Create a noop proxy for production mode.
1397
+ * Spreading this produces no attributes.
1398
+ */
1399
+ declare function createNoop(): EditProxy;
1400
+ /**
1401
+ * Visual editing proxy type.
1402
+ *
1403
+ * Spread directly onto elements for entry-level annotations: `{...entry.edit}`
1404
+ * Access a field for field-level annotations: `{...entry.edit.title}`
1405
+ *
1406
+ * In production, spreading produces no attributes (noop).
1407
+ */
1408
+ type EditProxy = {
1409
+ readonly [field: string]: Partial<FieldAnnotation>;
1410
+ };
1411
+ //#endregion
1412
+ //#region src/query.d.ts
1413
+ /**
1414
+ * Collection type registry for type-safe queries.
1415
+ *
1416
+ * This interface is extended by the generated dineway-env.d.ts file
1417
+ * to provide type inference for collection names and their data shapes.
1418
+ *
1419
+ * @example
1420
+ * ```ts
1421
+ * // In dineway-env.d.ts (generated):
1422
+ * declare module "dineway" {
1423
+ * interface DinewayCollections {
1424
+ * posts: { title: string; content: PortableTextBlock[]; };
1425
+ * pages: { title: string; body: PortableTextBlock[]; };
1426
+ * }
1427
+ * }
1428
+ *
1429
+ * // Then in your code:
1430
+ * const { entries } = await getDinewayCollection("posts");
1431
+ * // entries[0].data.title is typed as string
1432
+ * ```
1433
+ */
1434
+ interface DinewayCollections {}
1435
+ /**
1436
+ * Helper type to infer the data type for a collection.
1437
+ * Returns the registered type if known, otherwise falls back to Record<string, unknown>.
1438
+ */
1439
+ type InferCollectionData<T extends string> = T extends keyof DinewayCollections ? DinewayCollections[T] : Record<string, unknown>;
1440
+ /**
1441
+ * Sort direction
1442
+ */
1443
+ type SortDirection$1 = "asc" | "desc";
1444
+ /**
1445
+ * Order by specification - field name to direction
1446
+ * @example { created_at: "desc" } - Sort by created_at descending
1447
+ * @example { title: "asc" } - Sort by title ascending
1448
+ * @example { published_at: "desc", title: "asc" } - Multi-field sort
1449
+ */
1450
+ type OrderBySpec$1 = Record<string, SortDirection$1>;
1451
+ interface CollectionFilter$1 {
1452
+ status?: "draft" | "published" | "archived";
1453
+ limit?: number;
1454
+ /**
1455
+ * Opaque cursor for keyset pagination.
1456
+ * Pass the `nextCursor` value from a previous result to fetch the next page.
1457
+ * @example
1458
+ * ```ts
1459
+ * const cursor = Astro.url.searchParams.get("cursor") ?? undefined;
1460
+ * const { entries, nextCursor } = await getDinewayCollection("posts", {
1461
+ * limit: 10,
1462
+ * cursor,
1463
+ * });
1464
+ * ```
1465
+ */
1466
+ cursor?: string;
1467
+ /**
1468
+ * Filter by field values or taxonomy terms
1469
+ * @example { category: 'news' } - Filter by taxonomy term
1470
+ * @example { category: ['news', 'featured'] } - Filter by multiple terms (OR)
1471
+ */
1472
+ where?: Record<string, string | string[]>;
1473
+ /**
1474
+ * Order results by field(s)
1475
+ * @default { created_at: "desc" }
1476
+ * @example { created_at: "desc" } - Sort by created_at descending (default)
1477
+ * @example { title: "asc" } - Sort by title ascending
1478
+ * @example { published_at: "desc", title: "asc" } - Multi-field sort
1479
+ */
1480
+ orderBy?: OrderBySpec$1;
1481
+ /**
1482
+ * Filter by locale. When set, only returns entries in this locale.
1483
+ * Only relevant when i18n is configured.
1484
+ * @example "en" — English entries only
1485
+ * @example "fr" — French entries only
1486
+ */
1487
+ locale?: string;
1488
+ }
1489
+ interface ContentEntry<T = Record<string, unknown>> {
1490
+ id: string;
1491
+ data: T;
1492
+ /** Visual editing annotations. Spread onto elements: {...entry.edit.title} */
1493
+ edit: EditProxy;
1494
+ }
1495
+ /** Cache hint returned by the content loader for route caching */
1496
+ interface CacheHint {
1497
+ tags?: string[];
1498
+ lastModified?: Date;
1499
+ }
1500
+ /**
1501
+ * Result from getDinewayCollection
1502
+ */
1503
+ interface CollectionResult<T> {
1504
+ /** The entries (empty array if error or none found) */
1505
+ entries: ContentEntry<T>[];
1506
+ /** Error if the query failed */
1507
+ error?: Error;
1508
+ /** Cache hint for route caching (pass to Astro.cache.set()) */
1509
+ cacheHint: CacheHint;
1510
+ /**
1511
+ * Opaque cursor for the next page.
1512
+ * Undefined when there are no more results.
1513
+ * Pass this as `cursor` in the next query to get the next page.
1514
+ */
1515
+ nextCursor?: string;
1516
+ }
1517
+ /**
1518
+ * Result from getDinewayEntry
1519
+ */
1520
+ interface EntryResult<T> {
1521
+ /** The entry, or null if not found */
1522
+ entry: ContentEntry<T> | null;
1523
+ /** Error if the query failed (not set for "not found", only for actual errors) */
1524
+ error?: Error;
1525
+ /** Whether we're in preview mode (valid token was provided) */
1526
+ isPreview: boolean;
1527
+ /** Set when a fallback locale was used instead of the requested locale */
1528
+ fallbackLocale?: string;
1529
+ /** Cache hint for route caching (pass to Astro.cache.set()) */
1530
+ cacheHint: CacheHint;
1531
+ }
1532
+ /** Edit metadata attached to PT arrays in edit mode */
1533
+ interface EditFieldMeta {
1534
+ collection: string;
1535
+ id: string;
1536
+ field: string;
1537
+ }
1538
+ /**
1539
+ * Read edit metadata from a value (returns undefined if not tagged).
1540
+ * Uses Object.getOwnPropertyDescriptor to access Symbol-keyed property
1541
+ * without an unsafe type assertion.
1542
+ */
1543
+ declare function getEditMeta(value: unknown): EditFieldMeta | undefined;
1544
+ /**
1545
+ * Get all entries of a content type
1546
+ *
1547
+ * Returns { entries, error } for graceful error handling.
1548
+ *
1549
+ * When dineway-env.d.ts is generated, the collection name will be
1550
+ * type-checked and the return type will be inferred automatically.
1551
+ *
1552
+ * @example
1553
+ * ```ts
1554
+ * import { getDinewayCollection } from "dineway";
1555
+ *
1556
+ * const { entries: posts, error } = await getDinewayCollection("posts");
1557
+ * if (error) {
1558
+ * console.error("Failed to load posts:", error);
1559
+ * return;
1560
+ * }
1561
+ * // posts[0].data.title is typed (if dineway-env.d.ts exists)
1562
+ *
1563
+ * // With filters
1564
+ * const { entries: drafts } = await getDinewayCollection("posts", { status: "draft" });
1565
+ * ```
1566
+ */
1567
+ declare function getDinewayCollection<T extends string, D = InferCollectionData<T>>(type: T, filter?: CollectionFilter$1): Promise<CollectionResult<D>>;
1568
+ /**
1569
+ * Get a single entry by type and ID/slug
1570
+ *
1571
+ * Returns { entry, error, isPreview } for graceful error handling.
1572
+ * - entry is null if not found (not an error)
1573
+ * - error is set only for actual errors (db issues, etc.)
1574
+ *
1575
+ * Preview mode is detected automatically from request context (ALS).
1576
+ * When the URL has a valid `_preview` token, the middleware sets preview
1577
+ * context and this function serves draft revision data if available.
1578
+ *
1579
+ * @example
1580
+ * ```ts
1581
+ * import { getDinewayEntry } from "dineway";
1582
+ *
1583
+ * // Simple usage — preview just works via middleware
1584
+ * const { entry: post, isPreview, error } = await getDinewayEntry("posts", "my-slug");
1585
+ * if (!post) return Astro.redirect("/404");
1586
+ * ```
1587
+ */
1588
+ declare function getDinewayEntry<T extends string, D = InferCollectionData<T>>(type: T, id: string, options?: {
1589
+ locale?: string;
1590
+ }): Promise<EntryResult<D>>;
1591
+ /**
1592
+ * Translation summary for a single locale variant
1593
+ */
1594
+ interface TranslationSummary {
1595
+ /** Content item ID */
1596
+ id: string;
1597
+ /** Locale code (e.g. "en", "fr") */
1598
+ locale: string;
1599
+ /** URL slug */
1600
+ slug: string | null;
1601
+ /** Current status */
1602
+ status: string;
1603
+ }
1604
+ /**
1605
+ * Result from getTranslations
1606
+ */
1607
+ interface TranslationsResult {
1608
+ /** The translation group ID (shared across locales) */
1609
+ translationGroup: string;
1610
+ /** All locale variants in this group */
1611
+ translations: TranslationSummary[];
1612
+ /** Error if the query failed */
1613
+ error?: Error;
1614
+ }
1615
+ /**
1616
+ * Get all translations of a content item.
1617
+ *
1618
+ * Given a content entry, returns all locale variants that share the same
1619
+ * translation group. This is useful for building language switcher UI.
1620
+ *
1621
+ * @example
1622
+ * ```ts
1623
+ * import { getDinewayEntry, getTranslations } from "dineway";
1624
+ *
1625
+ * const { entry: post } = await getDinewayEntry("posts", "hello-world", { locale: "en" });
1626
+ * const { translations } = await getTranslations("posts", post.data.id);
1627
+ * // translations = [{ id: "...", locale: "en", slug: "hello-world", status: "published" }, ...]
1628
+ * ```
1629
+ */
1630
+ declare function getTranslations(type: string, id: string): Promise<TranslationsResult>;
1631
+ /**
1632
+ * Result from resolveDinewayPath
1633
+ */
1634
+ interface ResolvePathResult<T = Record<string, unknown>> {
1635
+ /** The matched entry */
1636
+ entry: ContentEntry<T>;
1637
+ /** The collection slug that matched */
1638
+ collection: string;
1639
+ /** Extracted parameters from the URL pattern (e.g. { slug: "my-post" }) */
1640
+ params: Record<string, string>;
1641
+ }
1642
+ /**
1643
+ * Resolve a URL path to a content entry by matching against collection URL patterns.
1644
+ *
1645
+ * Loads all collections with a `urlPattern` set, converts each pattern to a regex,
1646
+ * and tests the given path. On match, extracts the slug and fetches the entry.
1647
+ *
1648
+ * @example
1649
+ * ```ts
1650
+ * import { resolveDinewayPath } from "dineway";
1651
+ *
1652
+ * // Given pages with urlPattern "/{slug}" and posts with "/blog/{slug}":
1653
+ * const result = await resolveDinewayPath("/blog/hello-world");
1654
+ * if (result) {
1655
+ * console.log(result.collection); // "posts"
1656
+ * console.log(result.params.slug); // "hello-world"
1657
+ * console.log(result.entry.data); // post data
1658
+ * }
1659
+ * ```
1660
+ */
1661
+ declare function resolveDinewayPath<T = Record<string, unknown>>(path: string): Promise<ResolvePathResult<T> | null>;
1662
+ //#endregion
1663
+ //#region src/i18n/config.d.ts
1664
+ /**
1665
+ * Dineway i18n Configuration
1666
+ *
1667
+ * Reads locale configuration from the virtual module (sourced from Astro config).
1668
+ * Initialized during runtime startup, then available via getI18nConfig().
1669
+ */
1670
+ interface I18nConfig {
1671
+ defaultLocale: string;
1672
+ locales: string[];
1673
+ fallback?: Record<string, string>;
1674
+ prefixDefaultLocale?: boolean;
1675
+ }
1676
+ /**
1677
+ * Get the current i18n config.
1678
+ * Returns null if i18n is not configured.
1679
+ */
1680
+ declare function getI18nConfig(): I18nConfig | null;
1681
+ /**
1682
+ * Check if i18n is enabled.
1683
+ * Returns true when multiple locales are configured.
1684
+ */
1685
+ declare function isI18nEnabled(): boolean;
1686
+ /**
1687
+ * Resolve fallback locale chain for a given locale.
1688
+ * Returns array of locales to try, from most preferred to least.
1689
+ * Always ends with defaultLocale.
1690
+ */
1691
+ declare function getFallbackChain(locale: string): string[];
1692
+ //#endregion
1693
+ //#region src/preview/sidecar-client.d.ts
1694
+ /**
1695
+ * Preview sidecar protocol helpers.
1696
+ *
1697
+ * These utilities define the signed URL and snapshot-auth contract shared
1698
+ * by preview sidecars and the source site serving snapshot exports.
1699
+ */
1700
+ interface PreviewSidecarSignature {
1701
+ source: string;
1702
+ exp: number;
1703
+ sig: string;
1704
+ }
1705
+ interface PreviewSidecarClient {
1706
+ signPreviewUrl(previewBase: string, source: string, secret: string, ttl?: number): Promise<string>;
1707
+ buildSnapshotSignatureHeader(signature: PreviewSidecarSignature): string;
1708
+ }
1709
+ declare function signPreviewUrl(previewBase: string, source: string, secret: string, ttl?: number): Promise<string>;
1710
+ declare function buildPreviewSignatureHeader(signature: PreviewSidecarSignature): string;
1711
+ declare function parsePreviewSignatureHeader(header: string): PreviewSidecarSignature | null;
1712
+ declare function verifyPreviewSignature(source: string, exp: number, sig: string, secret: string): Promise<boolean>;
1713
+ declare const defaultPreviewSidecarClient: PreviewSidecarClient;
1714
+ //#endregion
1715
+ //#region src/preview/session-database-factory.d.ts
1716
+ interface SessionDatabaseInfo {
1717
+ id: string;
1718
+ dbPath: string;
1719
+ createdAt: number;
1720
+ expiresAt: number;
1721
+ lastTouchedAt: number;
1722
+ }
1723
+ interface SessionDatabaseHandle {
1724
+ created: boolean;
1725
+ session: SessionDatabaseInfo;
1726
+ db: Kysely<Database>;
1727
+ close(): Promise<void>;
1728
+ }
1729
+ interface SessionCleanupResult {
1730
+ removedSessionIds: string[];
1731
+ removedPaths: string[];
1732
+ }
1733
+ interface SessionOpenOptions {
1734
+ id: string;
1735
+ now?: number;
1736
+ }
1737
+ interface SessionOpenOrCreateOptions extends SessionOpenOptions {
1738
+ ttlMs: number;
1739
+ }
1740
+ interface SessionDatabaseFactory {
1741
+ open(input: SessionOpenOptions): Promise<SessionDatabaseHandle | null>;
1742
+ openOrCreate(input: SessionOpenOrCreateOptions): Promise<SessionDatabaseHandle>;
1743
+ destroy(id: string): Promise<boolean>;
1744
+ cleanup(now?: number): Promise<SessionCleanupResult>;
1745
+ close(): Promise<void>;
1746
+ }
1747
+ interface FileSessionDatabaseFactoryOptions {
1748
+ rootDir: string;
1749
+ maxDiskBytes?: number;
1750
+ registryFileName?: string;
1751
+ sessionsDirName?: string;
1752
+ }
1753
+ declare class SessionDatabaseLimitError extends Error {
1754
+ constructor(message?: string);
1755
+ }
1756
+ declare class FileSessionDatabaseFactory implements SessionDatabaseFactory {
1757
+ private readonly options;
1758
+ private readonly registry;
1759
+ private readonly sessionsDir;
1760
+ private readonly maxDiskBytes;
1761
+ constructor(options: FileSessionDatabaseFactoryOptions);
1762
+ open(input: SessionOpenOptions): Promise<SessionDatabaseHandle | null>;
1763
+ openOrCreate(input: SessionOpenOrCreateOptions): Promise<SessionDatabaseHandle>;
1764
+ destroy(id: string): Promise<boolean>;
1765
+ cleanup(now?: number): Promise<SessionCleanupResult>;
1766
+ close(): Promise<void>;
1767
+ private createHandle;
1768
+ private getSessionRow;
1769
+ private toSessionInfo;
1770
+ private deleteSession;
1771
+ private getActiveDiskBytes;
1772
+ private getDbPath;
1773
+ private getManagedPaths;
1774
+ private listSessionRows;
1775
+ private listDbPathRows;
1776
+ }
1777
+ //#endregion
1778
+ //#region src/preview/middleware.d.ts
1779
+ interface FilePreviewMiddlewareConfig {
1780
+ rootDir?: string;
1781
+ secret: string;
1782
+ ttlSeconds?: number;
1783
+ cookieName?: string;
1784
+ snapshotPath?: string;
1785
+ maxSessionDiskBytes?: number;
1786
+ sessionFactory?: SessionDatabaseFactory;
1787
+ fetch?: typeof globalThis.fetch;
1788
+ }
1789
+ declare function createFilePreviewMiddleware(config: FilePreviewMiddlewareConfig): MiddlewareHandler;
1790
+ //#endregion
1791
+ //#region src/loader.d.ts
1792
+ /**
1793
+ * Entry data type - generic object
1794
+ */
1795
+ type EntryData = Record<string, unknown>;
1796
+ /**
1797
+ * Sort direction
1798
+ */
1799
+ type SortDirection = "asc" | "desc";
1800
+ /**
1801
+ * Order by specification - field name to direction
1802
+ * @example { created_at: "desc" } - Sort by created_at descending
1803
+ * @example { title: "asc" } - Sort by title ascending
1804
+ */
1805
+ type OrderBySpec = Record<string, SortDirection>;
1806
+ /**
1807
+ * Filter for loadCollection - type is required
1808
+ */
1809
+ interface CollectionFilter {
1810
+ type: string;
1811
+ status?: "draft" | "published" | "archived";
1812
+ limit?: number;
1813
+ /**
1814
+ * Opaque cursor for keyset pagination.
1815
+ * Pass the `nextCursor` value from a previous result to fetch the next page.
1816
+ */
1817
+ cursor?: string;
1818
+ /**
1819
+ * Filter by field values or taxonomy terms
1820
+ */
1821
+ where?: Record<string, string | string[]>;
1822
+ /**
1823
+ * Order results by field(s)
1824
+ * @default { created_at: "desc" }
1825
+ */
1826
+ orderBy?: OrderBySpec;
1827
+ /**
1828
+ * Filter by locale (e.g. 'en', 'fr').
1829
+ * When set, only returns content in this locale.
1830
+ */
1831
+ locale?: string;
1832
+ }
1833
+ /**
1834
+ * Filter for loadEntry - type and id are required
1835
+ */
1836
+ interface EntryFilter {
1837
+ type: string;
1838
+ id: string;
1839
+ /**
1840
+ * When set, fetch content data from this revision instead of the content table.
1841
+ * Used by preview mode to serve draft revision data.
1842
+ */
1843
+ revisionId?: string;
1844
+ /**
1845
+ * Locale to scope slug lookup. Only affects slug resolution;
1846
+ * IDs are globally unique and always resolve regardless of locale.
1847
+ */
1848
+ locale?: string;
1849
+ }
1850
+ /**
1851
+ * Get the database instance. Used by query wrapper functions and middleware.
1852
+ *
1853
+ * Checks the ALS request context first — if a per-request DB override is set
1854
+ * (e.g. by preview or playground middleware), it takes precedence over the
1855
+ * module-level cached instance. This allows preview flows to route queries
1856
+ * to an isolated session database without modifying any calling code.
1857
+ *
1858
+ * Initializes the default database on first call using config from virtual module.
1859
+ */
1860
+ declare function getDb(): Promise<Kysely<Database>>;
1861
+ /**
1862
+ * Create a Dineway Live Collections loader
1863
+ *
1864
+ * This loader handles ALL content types in a single Astro collection.
1865
+ * Use `getDinewayCollection()` and `getDinewayEntry()` to query
1866
+ * specific content types.
1867
+ *
1868
+ * Database is configured in astro.config.mjs via the dineway() integration.
1869
+ *
1870
+ * @example
1871
+ * ```ts
1872
+ * // src/live.config.ts
1873
+ * import { defineLiveCollection } from "astro:content";
1874
+ * import { dinewayLoader } from "dineway";
1875
+ *
1876
+ * export const collections = {
1877
+ * dineway: defineLiveCollection({
1878
+ * loader: dinewayLoader(),
1879
+ * }),
1880
+ * };
1881
+ * ```
1882
+ */
1883
+ declare function dinewayLoader(): LiveLoader<EntryData, EntryFilter, CollectionFilter>;
1884
+ //#endregion
1885
+ //#region src/cli/wxr/parser.d.ts
1886
+ /**
1887
+ * Parsed WordPress export data
1888
+ */
1889
+ interface WxrData {
1890
+ /** Site metadata */
1891
+ site: WxrSite;
1892
+ /** Posts (including custom post types) */
1893
+ posts: WxrPost[];
1894
+ /** Media attachments */
1895
+ attachments: WxrAttachment[];
1896
+ /** Categories */
1897
+ categories: WxrCategory[];
1898
+ /** Tags */
1899
+ tags: WxrTag[];
1900
+ /** Authors */
1901
+ authors: WxrAuthor[];
1902
+ /** All taxonomy terms (including custom taxonomies and nav_menu) */
1903
+ terms: WxrTerm[];
1904
+ /** Parsed navigation menus */
1905
+ navMenus: WxrNavMenu[];
1906
+ }
1907
+ interface WxrSite {
1908
+ title?: string;
1909
+ link?: string;
1910
+ description?: string;
1911
+ language?: string;
1912
+ baseSiteUrl?: string;
1913
+ baseBlogUrl?: string;
1914
+ }
1915
+ interface WxrPost {
1916
+ id?: number;
1917
+ title?: string;
1918
+ link?: string;
1919
+ pubDate?: string;
1920
+ creator?: string;
1921
+ guid?: string;
1922
+ description?: string;
1923
+ content?: string;
1924
+ excerpt?: string;
1925
+ postDate?: string;
1926
+ postDateGmt?: string;
1927
+ postModified?: string;
1928
+ postModifiedGmt?: string;
1929
+ commentStatus?: string;
1930
+ pingStatus?: string;
1931
+ status?: string;
1932
+ postType?: string;
1933
+ postName?: string;
1934
+ postPassword?: string;
1935
+ isSticky?: boolean;
1936
+ /** Parent post ID for hierarchical content (pages) */
1937
+ postParent?: number;
1938
+ /** Menu order for sorting */
1939
+ menuOrder?: number;
1940
+ categories: string[];
1941
+ tags: string[];
1942
+ /** Custom taxonomy assignments beyond categories/tags */
1943
+ customTaxonomies?: Map<string, string[]>;
1944
+ meta: Map<string, string>;
1945
+ }
1946
+ interface WxrAttachment {
1947
+ id?: number;
1948
+ title?: string;
1949
+ url?: string;
1950
+ postDate?: string;
1951
+ meta: Map<string, string>;
1952
+ }
1953
+ interface WxrCategory {
1954
+ id?: number;
1955
+ nicename?: string;
1956
+ name?: string;
1957
+ parent?: string;
1958
+ description?: string;
1959
+ }
1960
+ interface WxrTag {
1961
+ id?: number;
1962
+ slug?: string;
1963
+ name?: string;
1964
+ description?: string;
1965
+ }
1966
+ /**
1967
+ * Generic taxonomy term (categories, tags, nav_menu, custom taxonomies)
1968
+ */
1969
+ interface WxrTerm {
1970
+ id: number;
1971
+ taxonomy: string;
1972
+ slug: string;
1973
+ name: string;
1974
+ parent?: string;
1975
+ description?: string;
1976
+ }
1977
+ /**
1978
+ * Navigation menu structure
1979
+ */
1980
+ interface WxrNavMenu {
1981
+ id: number;
1982
+ name: string;
1983
+ label: string;
1984
+ items: WxrNavMenuItem[];
1985
+ }
1986
+ /**
1987
+ * Navigation menu item
1988
+ */
1989
+ interface WxrNavMenuItem {
1990
+ id: number;
1991
+ menuId: number;
1992
+ parentId?: number;
1993
+ sortOrder: number;
1994
+ type: "custom" | "post_type" | "taxonomy";
1995
+ objectType?: string;
1996
+ objectId?: number;
1997
+ url?: string;
1998
+ title: string;
1999
+ target?: string;
2000
+ classes?: string;
2001
+ }
2002
+ interface WxrAuthor {
2003
+ id?: number;
2004
+ login?: string;
2005
+ email?: string;
2006
+ displayName?: string;
2007
+ firstName?: string;
2008
+ lastName?: string;
2009
+ }
2010
+ /**
2011
+ * Parse a WordPress WXR export file
2012
+ */
2013
+ declare function parseWxr(stream: Readable): Promise<WxrData>;
2014
+ /**
2015
+ * Parse a WordPress WXR export from a string
2016
+ *
2017
+ * Uses the non-streaming SAX parser API for compatibility with
2018
+ * environments that don't expose Node.js streams.
2019
+ */
2020
+ declare function parseWxrString(xml: string): Promise<WxrData>;
2021
+ //#endregion
2022
+ //#region src/plugins/define-plugin.d.ts
2023
+ /**
2024
+ * Define a Dineway plugin.
2025
+ *
2026
+ * **Standard format** -- the canonical format for plugins that work in both
2027
+ * trusted and sandboxed modes. No id/version -- those come from the descriptor.
2028
+ *
2029
+ * @example
2030
+ * ```typescript
2031
+ * import { definePlugin } from "dineway";
2032
+ *
2033
+ * export default definePlugin({
2034
+ * hooks: {
2035
+ * "content:afterSave": {
2036
+ * handler: async (event, ctx) => {
2037
+ * await ctx.kv.set("lastSave", Date.now());
2038
+ * },
2039
+ * },
2040
+ * },
2041
+ * routes: {
2042
+ * status: {
2043
+ * handler: async (routeCtx, ctx) => ({ ok: true }),
2044
+ * },
2045
+ * },
2046
+ * });
2047
+ * ```
2048
+ *
2049
+ * **Native format** -- for plugins that need React admin, direct DB access,
2050
+ * or other capabilities not available in the sandbox.
2051
+ *
2052
+ * @example
2053
+ * ```typescript
2054
+ * import { definePlugin } from "dineway";
2055
+ *
2056
+ * export default definePlugin({
2057
+ * id: "my-plugin",
2058
+ * version: "1.0.0",
2059
+ * capabilities: ["read:content"],
2060
+ * hooks: {
2061
+ * "content:beforeSave": async (event, ctx) => {
2062
+ * ctx.log.info("Saving content", { collection: event.collection });
2063
+ * return event.content;
2064
+ * }
2065
+ * },
2066
+ * routes: {
2067
+ * "sync": {
2068
+ * handler: async (ctx) => {
2069
+ * return { status: "ok" };
2070
+ * }
2071
+ * }
2072
+ * }
2073
+ * });
2074
+ * ```
2075
+ */
2076
+ declare function definePlugin<TStorage extends PluginStorageConfig>(definition: PluginDefinition<TStorage>): ResolvedPlugin<TStorage>;
2077
+ declare function definePlugin(definition: StandardPluginDefinition): StandardPluginDefinition;
2078
+ //#endregion
2079
+ //#region src/auth/types.d.ts
2080
+ /**
2081
+ * Auth Provider Types
2082
+ *
2083
+ * Defines the interfaces for pluggable authentication providers.
2084
+ * External auth adapters implement these interfaces.
2085
+ */
2086
+ /**
2087
+ * Result of authenticating a request via an external auth provider
2088
+ */
2089
+ interface AuthResult {
2090
+ /** User's email address */
2091
+ email: string;
2092
+ /** User's display name */
2093
+ name: string;
2094
+ /** Resolved role level (e.g., 50 for Admin, 30 for Editor) */
2095
+ role: number;
2096
+ /** Provider-specific subject ID */
2097
+ subject?: string;
2098
+ /** Additional provider-specific data */
2099
+ metadata?: Record<string, unknown>;
2100
+ }
2101
+ /**
2102
+ * Auth descriptor - returned by auth adapter functions (e.g., access())
2103
+ *
2104
+ * Similar to DatabaseDescriptor and StorageDescriptor, this allows
2105
+ * auth providers to be configured at build time and loaded at runtime.
2106
+ */
2107
+ interface AuthDescriptor {
2108
+ /**
2109
+ * Auth provider type identifier
2110
+ * @example "header-auth", "okta", "auth0"
2111
+ */
2112
+ type: string;
2113
+ /**
2114
+ * Module specifier to import at runtime
2115
+ * The module must export an `authenticate` function.
2116
+ * @example "@acme/dineway-header-auth"
2117
+ */
2118
+ entrypoint: string;
2119
+ /**
2120
+ * Provider-specific configuration (JSON-serializable)
2121
+ */
2122
+ config: unknown;
2123
+ }
2124
+ /**
2125
+ * Auth provider module interface
2126
+ *
2127
+ * Modules specified by AuthDescriptor.entrypoint must export
2128
+ * an `authenticate` function matching this signature.
2129
+ */
2130
+ interface AuthProviderModule {
2131
+ /**
2132
+ * Authenticate a request using the provider
2133
+ *
2134
+ * @param request - The incoming HTTP request
2135
+ * @param config - Provider-specific configuration from AuthDescriptor
2136
+ * @returns Authentication result if valid, throws if invalid
2137
+ */
2138
+ authenticate(request: Request, config: unknown): Promise<AuthResult>;
2139
+ }
2140
+ /**
2141
+ * Configuration options common to external auth providers
2142
+ */
2143
+ interface ExternalAuthConfig {
2144
+ /**
2145
+ * Automatically create Dineway users on first login
2146
+ * @default true
2147
+ */
2148
+ autoProvision?: boolean;
2149
+ /**
2150
+ * Role level for users not matching any group in roleMapping
2151
+ * @default 30 (Editor)
2152
+ */
2153
+ defaultRole?: number;
2154
+ /**
2155
+ * Update user's role on each login based on current IdP groups
2156
+ * When false, role is only set on first provisioning
2157
+ * @default false
2158
+ */
2159
+ syncRoles?: boolean;
2160
+ /**
2161
+ * Map IdP group names to Dineway role levels
2162
+ * First match wins if user is in multiple groups
2163
+ *
2164
+ * @example
2165
+ * ```ts
2166
+ * roleMapping: {
2167
+ * "Admins": 50, // Admin
2168
+ * "Developers": 40, // Developer
2169
+ * "Content Team": 30, // Editor
2170
+ * }
2171
+ * ```
2172
+ */
2173
+ roleMapping?: Record<string, number>;
2174
+ }
2175
+ //#endregion
2176
+ //#region src/astro/storage/types.d.ts
2177
+ /**
2178
+ * Serializable storage configuration descriptor
2179
+ */
2180
+ interface StorageDescriptor {
2181
+ /** Module path exporting createStorage function */
2182
+ entrypoint: string;
2183
+ /** Serializable config passed to createStorage at runtime */
2184
+ config: unknown;
2185
+ }
2186
+ /**
2187
+ * S3-compatible storage configuration
2188
+ */
2189
+ interface S3StorageConfig {
2190
+ /** S3 endpoint URL */
2191
+ endpoint: string;
2192
+ /** Bucket name */
2193
+ bucket: string;
2194
+ /** Access key ID */
2195
+ accessKeyId: string;
2196
+ /** Secret access key */
2197
+ secretAccessKey: string;
2198
+ /** Optional region (defaults to "auto") */
2199
+ region?: string;
2200
+ /** Optional public URL prefix for CDN */
2201
+ publicUrl?: string;
2202
+ }
2203
+ /**
2204
+ * Local filesystem storage configuration
2205
+ */
2206
+ interface LocalStorageConfig {
2207
+ /** Directory path for storing files */
2208
+ directory: string;
2209
+ /** Base URL for serving files */
2210
+ baseUrl: string;
2211
+ }
2212
+ //#endregion
2213
+ //#region src/astro/integration/runtime.d.ts
2214
+ /**
2215
+ * Admin page definition (copied from plugins/types to avoid circular deps)
2216
+ */
2217
+ interface PluginAdminPage {
2218
+ path: string;
2219
+ label: string;
2220
+ icon?: string;
2221
+ }
2222
+ /**
2223
+ * Dashboard widget definition (copied from plugins/types to avoid circular deps)
2224
+ */
2225
+ interface PluginDashboardWidget {
2226
+ id: string;
2227
+ size?: "full" | "half" | "third";
2228
+ title?: string;
2229
+ }
2230
+ /**
2231
+ * Plugin descriptor - returned by plugin factory functions
2232
+ *
2233
+ * Contains all static metadata needed for manifest and admin UI,
2234
+ * plus the entrypoint for runtime instantiation.
2235
+ *
2236
+ * @example
2237
+ * ```ts
2238
+ * export function myPlugin(options?: MyPluginOptions): PluginDescriptor {
2239
+ * return {
2240
+ * id: "my-plugin",
2241
+ * version: "1.0.0",
2242
+ * entrypoint: "@my-org/dineway-plugin-foo",
2243
+ * options: options ?? {},
2244
+ * adminEntry: "@my-org/dineway-plugin-foo/admin",
2245
+ * adminPages: [{ path: "/settings", label: "Settings" }],
2246
+ * };
2247
+ * }
2248
+ * ```
2249
+ */
2250
+ /**
2251
+ * Storage collection declaration for sandboxed plugins
2252
+ */
2253
+ interface StorageCollectionDeclaration {
2254
+ indexes?: string[];
2255
+ uniqueIndexes?: string[];
2256
+ }
2257
+ interface PluginDescriptor<TOptions = Record<string, unknown>> {
2258
+ /** Unique plugin identifier */
2259
+ id: string;
2260
+ /** Plugin version (semver) */
2261
+ version: string;
2262
+ /** Module specifier to import (e.g., "@dineway-ai/plugin-api-test") */
2263
+ entrypoint: string;
2264
+ /**
2265
+ * Options to pass to createPlugin(). Native format only.
2266
+ * Standard-format plugins configure themselves via KV settings
2267
+ * and Block Kit admin pages -- not constructor options.
2268
+ */
2269
+ options?: TOptions;
2270
+ /**
2271
+ * Plugin format. Determines how the entrypoint is loaded:
2272
+ * - `"standard"` -- exports `definePlugin({ hooks, routes })` as default.
2273
+ * Wrapped with `adaptSandboxEntry` for in-process execution. Can run in both
2274
+ * `plugins: []` (in-process) and `sandboxed: []` (isolate).
2275
+ * - `"native"` -- exports `createPlugin(options)` returning a `ResolvedPlugin`.
2276
+ * Can only run in `plugins: []`. Cannot be sandboxed or published to marketplace.
2277
+ *
2278
+ * Defaults to `"native"` when unset.
2279
+ *
2280
+ */
2281
+ format?: "standard" | "native";
2282
+ /** Admin UI module specifier (e.g., "@dineway-ai/plugin-audit-log/admin") */
2283
+ adminEntry?: string;
2284
+ /** Module specifier for site-side Astro rendering components (must export `blockComponents`) */
2285
+ componentsEntry?: string;
2286
+ /** Admin pages for navigation */
2287
+ adminPages?: PluginAdminPage[];
2288
+ /** Dashboard widgets */
2289
+ adminWidgets?: PluginDashboardWidget[];
2290
+ /**
2291
+ * Capabilities the plugin requests.
2292
+ * For standard-format plugins, capabilities are enforced in both trusted and
2293
+ * sandboxed modes via the PluginContextFactory.
2294
+ */
2295
+ capabilities?: string[];
2296
+ /**
2297
+ * Allowed hosts for network:fetch capability
2298
+ * Supports wildcards like "*.example.com"
2299
+ */
2300
+ allowedHosts?: string[];
2301
+ /**
2302
+ * Storage collections the plugin declares
2303
+ * Sandboxed plugins can only access declared collections.
2304
+ */
2305
+ storage?: Record<string, StorageCollectionDeclaration>;
2306
+ }
2307
+ /**
2308
+ * Sandboxed plugin descriptor - same format as PluginDescriptor
2309
+ *
2310
+ * These run in isolated environments provided by the configured sandbox runner.
2311
+ * The `entrypoint` is resolved to a file and bundled at build time.
2312
+ */
2313
+ type SandboxedPluginDescriptor<TOptions = Record<string, unknown>> = PluginDescriptor<TOptions>;
2314
+ interface DinewayConfig {
2315
+ /**
2316
+ * Database configuration
2317
+ *
2318
+ * Use one of the adapter functions:
2319
+ * - `libsql({ url: process.env.DINEWAY_DATABASE_URL || "file:./data.db" })` - Default Node/libSQL path
2320
+ * - `sqlite({ url: "file:./data.db" })` - Local SQLite only
2321
+ * - `postgres({ connectionString: process.env.DATABASE_URL! })` - PostgreSQL deployments
2322
+ *
2323
+ * @example
2324
+ * ```ts
2325
+ * import { libsql } from "dineway/db";
2326
+ *
2327
+ * dineway({
2328
+ * database: libsql({ url: process.env.DINEWAY_DATABASE_URL || "file:./data.db" }),
2329
+ * })
2330
+ * ```
2331
+ */
2332
+ database?: DatabaseDescriptor;
2333
+ /**
2334
+ * Storage configuration (for media)
2335
+ */
2336
+ storage?: StorageDescriptor;
2337
+ /**
2338
+ * Trusted plugins to load (run in main isolate)
2339
+ *
2340
+ * @example
2341
+ * ```ts
2342
+ * import { auditLogPlugin } from "@dineway-ai/plugin-audit-log";
2343
+ * import { webhookNotifierPlugin } from "@dineway-ai/plugin-webhook-notifier";
2344
+ *
2345
+ * dineway({
2346
+ * plugins: [
2347
+ * auditLogPlugin(),
2348
+ * webhookNotifierPlugin({ url: "https://example.com/webhook" }),
2349
+ * ],
2350
+ * })
2351
+ * ```
2352
+ */
2353
+ plugins?: PluginDescriptor[];
2354
+ /**
2355
+ * Sandboxed plugins to load (run behind the configured `SandboxRunner`)
2356
+ *
2357
+ * Uses the same format as `plugins`; the configured sandbox runner decides
2358
+ * how isolation is enforced for the current runtime.
2359
+ *
2360
+ * @example
2361
+ * ```ts
2362
+ * import { untrustedPlugin } from "some-third-party-plugin";
2363
+ *
2364
+ * dineway({
2365
+ * plugins: [trustedPlugin()], // runs in host
2366
+ * sandboxed: [untrustedPlugin()], // runs in the default Node sandbox
2367
+ * })
2368
+ * ```
2369
+ */
2370
+ sandboxed?: SandboxedPluginDescriptor[];
2371
+ /**
2372
+ * Optional module that exports a custom sandbox runner factory.
2373
+ * When omitted, Dineway uses its built-in Node sandbox runner.
2374
+ *
2375
+ * @example
2376
+ * ```ts
2377
+ * import { createNodeSandboxRunner } from "dineway";
2378
+ *
2379
+ * export const createSandboxRunner = createNodeSandboxRunner;
2380
+ * ```
2381
+ *
2382
+ * @example
2383
+ * ```ts
2384
+ * dineway({
2385
+ * sandboxRunner: "./src/sandbox-runner.ts",
2386
+ * })
2387
+ * ```
2388
+ */
2389
+ sandboxRunner?: string;
2390
+ /**
2391
+ * Authentication configuration
2392
+ *
2393
+ * Use an auth descriptor or an adapter function from a provider package.
2394
+ *
2395
+ * When an external auth provider is configured, passkey auth is disabled.
2396
+ *
2397
+ * @example
2398
+ * ```ts
2399
+ * dineway({
2400
+ * auth: {
2401
+ * type: "header-auth",
2402
+ * entrypoint: "./src/header-auth.ts",
2403
+ * config: {
2404
+ * userHeader: "x-forwarded-user-email",
2405
+ * roleHeader: "x-forwarded-user-role",
2406
+ * },
2407
+ * },
2408
+ * })
2409
+ * ```
2410
+ */
2411
+ auth?: AuthDescriptor;
2412
+ /**
2413
+ * Enable the MCP (Model Context Protocol) server endpoint.
2414
+ *
2415
+ * When enabled, exposes an MCP Streamable HTTP server at
2416
+ * `/_dineway/api/mcp` that allows AI agents and tools to interact
2417
+ * with the CMS using the standardized MCP protocol.
2418
+ *
2419
+ * Authentication is handled by the existing Dineway auth middleware —
2420
+ * agents must authenticate with an API token or session cookie.
2421
+ *
2422
+ * @default false
2423
+ *
2424
+ * @example
2425
+ * ```ts
2426
+ * dineway({
2427
+ * mcp: true,
2428
+ * })
2429
+ * ```
2430
+ */
2431
+ mcp?: boolean;
2432
+ /**
2433
+ * Plugin marketplace URL
2434
+ *
2435
+ * When set, enables the marketplace features: browse, install, update,
2436
+ * and uninstall plugins from a remote marketplace.
2437
+ *
2438
+ * Must be an HTTPS URL in production, or localhost/127.0.0.1 in dev.
2439
+ * Marketplace plugins run in the built-in Node sandbox runner unless
2440
+ * `sandboxRunner` is set to override it.
2441
+ *
2442
+ * @example
2443
+ * ```ts
2444
+ * dineway({
2445
+ * marketplace: "https://marketplace.example.com",
2446
+ * })
2447
+ * ```
2448
+ */
2449
+ marketplace?: string;
2450
+ /**
2451
+ * Public browser-facing origin for the site.
2452
+ *
2453
+ * Use when `Astro.url` / `request.url` do not match what users open — common with a
2454
+ * **TLS-terminating reverse proxy**: the app often sees `http://` on the internal hop
2455
+ * while the browser uses `https://`, which breaks WebAuthn, CSRF, OAuth, and redirect URLs.
2456
+ *
2457
+ * Set to the full origin users type in the address bar (no path), e.g.
2458
+ * `https://mysite.example.com`. When not set, falls back to environment variables
2459
+ * `DINEWAY_SITE_URL` > `SITE_URL`, then to the request URL's origin.
2460
+ *
2461
+ * Replaces `passkeyPublicOrigin` (which only fixed passkeys).
2462
+ */
2463
+ siteUrl?: string;
2464
+ /**
2465
+ * Enable playground mode for ephemeral "try Dineway" sites.
2466
+ *
2467
+ * When set, the integration injects a playground middleware (order: "pre")
2468
+ * that runs BEFORE the normal Dineway middleware chain. It creates an
2469
+ * isolated session database per visitor, runs migrations, applies the
2470
+ * seed, creates an anonymous admin user, and stashes the request-scoped
2471
+ * database on locals so the runtime and request-context middleware can
2472
+ * pick it up.
2473
+ *
2474
+ * Setup and auth middleware are skipped because the playground middleware
2475
+ * handles bootstrap and user injection.
2476
+ *
2477
+ * For the first portable release, playground sidecars are explicitly
2478
+ * single-instance only.
2479
+ *
2480
+ * @example
2481
+ * ```ts
2482
+ * import { fileURLToPath } from "node:url";
2483
+ * import { libsql } from "dineway/db";
2484
+ *
2485
+ * dineway({
2486
+ * database: libsql({ url: process.env.DINEWAY_DATABASE_URL || "file:./playground.db" }),
2487
+ * playground: {
2488
+ * middlewareEntrypoint: fileURLToPath(
2489
+ * new URL("./src/playground-middleware.ts", import.meta.url)
2490
+ * ),
2491
+ * },
2492
+ * })
2493
+ * ```
2494
+ */
2495
+ playground?: {
2496
+ /** Module path for the playground middleware. */middlewareEntrypoint: string;
2497
+ };
2498
+ /**
2499
+ * Media providers for browsing and uploading media
2500
+ *
2501
+ * The local media provider (using storage adapter) is available by default.
2502
+ * Additional providers can be added for external services like Unsplash,
2503
+ * Cloudinary, Mux, and other provider packages.
2504
+ *
2505
+ * @example
2506
+ * ```ts
2507
+ * import { unsplash } from "@dineway-ai/provider-unsplash";
2508
+ *
2509
+ * dineway({
2510
+ * mediaProviders: [
2511
+ * unsplash({ accessKey: "..." }),
2512
+ * ],
2513
+ * })
2514
+ * ```
2515
+ */
2516
+ mediaProviders?: MediaProviderDescriptor[];
2517
+ }
2518
+ /**
2519
+ * Get stored config from global
2520
+ * This is set by the virtual module at build time
2521
+ */
2522
+ declare function getStoredConfig(): DinewayConfig | null;
2523
+ declare global {
2524
+ var __dinewayConfig: DinewayConfig | undefined;
2525
+ }
2526
+ //#endregion
2527
+ //#region src/plugins/manifest-schema.d.ts
2528
+ /**
2529
+ * Zod schema matching the PluginManifest interface from types.ts.
2530
+ *
2531
+ * Every JSON.parse of a manifest.json should validate through this.
2532
+ */
2533
+ declare const pluginManifestSchema: z$1.ZodObject<{
2534
+ id: z$1.ZodString;
2535
+ version: z$1.ZodString;
2536
+ capabilities: z$1.ZodArray<z$1.ZodEnum<{
2537
+ "network:fetch": "network:fetch";
2538
+ "network:fetch:any": "network:fetch:any";
2539
+ "read:content": "read:content";
2540
+ "write:content": "write:content";
2541
+ "read:media": "read:media";
2542
+ "write:media": "write:media";
2543
+ "read:users": "read:users";
2544
+ "email:send": "email:send";
2545
+ "email:provide": "email:provide";
2546
+ "email:intercept": "email:intercept";
2547
+ "page:inject": "page:inject";
2548
+ }>>;
2549
+ allowedHosts: z$1.ZodArray<z$1.ZodString>;
2550
+ storage: z$1.ZodRecord<z$1.ZodString, z$1.ZodObject<{
2551
+ indexes: z$1.ZodArray<z$1.ZodUnion<readonly [z$1.ZodString, z$1.ZodArray<z$1.ZodString>]>>;
2552
+ uniqueIndexes: z$1.ZodOptional<z$1.ZodArray<z$1.ZodUnion<readonly [z$1.ZodString, z$1.ZodArray<z$1.ZodString>]>>>;
2553
+ }, z$1.core.$strip>>;
2554
+ hooks: z$1.ZodArray<z$1.ZodUnion<readonly [z$1.ZodEnum<{
2555
+ "plugin:install": "plugin:install";
2556
+ "plugin:activate": "plugin:activate";
2557
+ "plugin:deactivate": "plugin:deactivate";
2558
+ "plugin:uninstall": "plugin:uninstall";
2559
+ "content:beforeSave": "content:beforeSave";
2560
+ "content:afterSave": "content:afterSave";
2561
+ "content:beforeDelete": "content:beforeDelete";
2562
+ "content:afterDelete": "content:afterDelete";
2563
+ "content:afterPublish": "content:afterPublish";
2564
+ "content:afterUnpublish": "content:afterUnpublish";
2565
+ "media:beforeUpload": "media:beforeUpload";
2566
+ "media:afterUpload": "media:afterUpload";
2567
+ cron: "cron";
2568
+ "email:beforeSend": "email:beforeSend";
2569
+ "email:deliver": "email:deliver";
2570
+ "email:afterSend": "email:afterSend";
2571
+ "comment:beforeCreate": "comment:beforeCreate";
2572
+ "comment:moderate": "comment:moderate";
2573
+ "comment:afterCreate": "comment:afterCreate";
2574
+ "comment:afterModerate": "comment:afterModerate";
2575
+ "page:metadata": "page:metadata";
2576
+ "page:fragments": "page:fragments";
2577
+ }>, z$1.ZodObject<{
2578
+ name: z$1.ZodEnum<{
2579
+ "plugin:install": "plugin:install";
2580
+ "plugin:activate": "plugin:activate";
2581
+ "plugin:deactivate": "plugin:deactivate";
2582
+ "plugin:uninstall": "plugin:uninstall";
2583
+ "content:beforeSave": "content:beforeSave";
2584
+ "content:afterSave": "content:afterSave";
2585
+ "content:beforeDelete": "content:beforeDelete";
2586
+ "content:afterDelete": "content:afterDelete";
2587
+ "content:afterPublish": "content:afterPublish";
2588
+ "content:afterUnpublish": "content:afterUnpublish";
2589
+ "media:beforeUpload": "media:beforeUpload";
2590
+ "media:afterUpload": "media:afterUpload";
2591
+ cron: "cron";
2592
+ "email:beforeSend": "email:beforeSend";
2593
+ "email:deliver": "email:deliver";
2594
+ "email:afterSend": "email:afterSend";
2595
+ "comment:beforeCreate": "comment:beforeCreate";
2596
+ "comment:moderate": "comment:moderate";
2597
+ "comment:afterCreate": "comment:afterCreate";
2598
+ "comment:afterModerate": "comment:afterModerate";
2599
+ "page:metadata": "page:metadata";
2600
+ "page:fragments": "page:fragments";
2601
+ }>;
2602
+ exclusive: z$1.ZodOptional<z$1.ZodBoolean>;
2603
+ priority: z$1.ZodOptional<z$1.ZodNumber>;
2604
+ timeout: z$1.ZodOptional<z$1.ZodNumber>;
2605
+ }, z$1.core.$strip>]>>;
2606
+ routes: z$1.ZodArray<z$1.ZodUnion<readonly [z$1.ZodString, z$1.ZodObject<{
2607
+ name: z$1.ZodString;
2608
+ public: z$1.ZodOptional<z$1.ZodBoolean>;
2609
+ }, z$1.core.$strip>]>>;
2610
+ admin: z$1.ZodObject<{
2611
+ entry: z$1.ZodOptional<z$1.ZodString>;
2612
+ settingsSchema: z$1.ZodOptional<z$1.ZodRecord<z$1.ZodString, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{
2613
+ type: z$1.ZodLiteral<"string">;
2614
+ default: z$1.ZodOptional<z$1.ZodString>;
2615
+ multiline: z$1.ZodOptional<z$1.ZodBoolean>;
2616
+ label: z$1.ZodString;
2617
+ description: z$1.ZodOptional<z$1.ZodString>;
2618
+ }, z$1.core.$strip>, z$1.ZodObject<{
2619
+ type: z$1.ZodLiteral<"number">;
2620
+ default: z$1.ZodOptional<z$1.ZodNumber>;
2621
+ min: z$1.ZodOptional<z$1.ZodNumber>;
2622
+ max: z$1.ZodOptional<z$1.ZodNumber>;
2623
+ label: z$1.ZodString;
2624
+ description: z$1.ZodOptional<z$1.ZodString>;
2625
+ }, z$1.core.$strip>, z$1.ZodObject<{
2626
+ type: z$1.ZodLiteral<"boolean">;
2627
+ default: z$1.ZodOptional<z$1.ZodBoolean>;
2628
+ label: z$1.ZodString;
2629
+ description: z$1.ZodOptional<z$1.ZodString>;
2630
+ }, z$1.core.$strip>, z$1.ZodObject<{
2631
+ type: z$1.ZodLiteral<"select">;
2632
+ options: z$1.ZodArray<z$1.ZodObject<{
2633
+ value: z$1.ZodString;
2634
+ label: z$1.ZodString;
2635
+ }, z$1.core.$strip>>;
2636
+ default: z$1.ZodOptional<z$1.ZodString>;
2637
+ label: z$1.ZodString;
2638
+ description: z$1.ZodOptional<z$1.ZodString>;
2639
+ }, z$1.core.$strip>, z$1.ZodObject<{
2640
+ type: z$1.ZodLiteral<"secret">;
2641
+ label: z$1.ZodString;
2642
+ description: z$1.ZodOptional<z$1.ZodString>;
2643
+ }, z$1.core.$strip>], "type">>>;
2644
+ pages: z$1.ZodOptional<z$1.ZodArray<z$1.ZodObject<{
2645
+ path: z$1.ZodString;
2646
+ label: z$1.ZodString;
2647
+ icon: z$1.ZodOptional<z$1.ZodString>;
2648
+ }, z$1.core.$strip>>>;
2649
+ widgets: z$1.ZodOptional<z$1.ZodArray<z$1.ZodObject<{
2650
+ id: z$1.ZodString;
2651
+ size: z$1.ZodOptional<z$1.ZodEnum<{
2652
+ full: "full";
2653
+ half: "half";
2654
+ third: "third";
2655
+ }>>;
2656
+ title: z$1.ZodOptional<z$1.ZodString>;
2657
+ }, z$1.core.$strip>>>;
2658
+ fieldWidgets: z$1.ZodOptional<z$1.ZodArray<z$1.ZodObject<{
2659
+ name: z$1.ZodString;
2660
+ label: z$1.ZodString;
2661
+ fieldTypes: z$1.ZodArray<z$1.ZodEnum<{
2662
+ string: "string";
2663
+ number: "number";
2664
+ boolean: "boolean";
2665
+ text: "text";
2666
+ integer: "integer";
2667
+ datetime: "datetime";
2668
+ select: "select";
2669
+ multiSelect: "multiSelect";
2670
+ portableText: "portableText";
2671
+ image: "image";
2672
+ file: "file";
2673
+ reference: "reference";
2674
+ json: "json";
2675
+ slug: "slug";
2676
+ repeater: "repeater";
2677
+ }>>;
2678
+ elements: z$1.ZodOptional<z$1.ZodArray<z$1.ZodObject<{
2679
+ type: z$1.ZodString;
2680
+ action_id: z$1.ZodString;
2681
+ label: z$1.ZodOptional<z$1.ZodString>;
2682
+ }, z$1.core.$loose>>>;
2683
+ }, z$1.core.$strip>>>;
2684
+ }, z$1.core.$strip>;
2685
+ }, z$1.core.$strip>;
2686
+ type ValidatedPluginManifest = z$1.infer<typeof pluginManifestSchema>;
2687
+ //#endregion
2688
+ //#region src/plugins/hooks.d.ts
2689
+ type HookNameV2 = "plugin:install" | "plugin:activate" | "plugin:deactivate" | "plugin:uninstall" | "content:beforeSave" | "content:afterSave" | "content:beforeDelete" | "content:afterDelete" | "content:afterPublish" | "content:afterUnpublish" | "media:beforeUpload" | "media:afterUpload" | "cron" | "email:beforeSend" | "email:deliver" | "email:afterSend" | "comment:beforeCreate" | "comment:moderate" | "comment:afterCreate" | "comment:afterModerate" | "page:metadata" | "page:fragments";
2690
+ /**
2691
+ * Hook execution result
2692
+ */
2693
+ interface HookResult<T> {
2694
+ success: boolean;
2695
+ value?: T;
2696
+ error?: Error;
2697
+ pluginId: string;
2698
+ duration: number;
2699
+ }
2700
+ /**
2701
+ * Hook pipeline for executing hooks in order
2702
+ */
2703
+ declare class HookPipeline {
2704
+ private hooks;
2705
+ private pluginMap;
2706
+ private contextFactory;
2707
+ /** Stored so setContextFactory can merge incrementally. */
2708
+ private contextFactoryOptions;
2709
+ /** Hook names where at least one handler declared exclusive: true */
2710
+ private exclusiveHookNames;
2711
+ /**
2712
+ * Selected provider plugin ID for each exclusive hook.
2713
+ * Set by the PluginManager after resolution.
2714
+ */
2715
+ private exclusiveSelections;
2716
+ constructor(plugins: ResolvedPlugin[], factoryOptions?: PluginContextFactoryOptions);
2717
+ /**
2718
+ * Set or update the context factory options.
2719
+ *
2720
+ * When called on a pipeline that already has a factory, the new options
2721
+ * are merged on top of the existing ones so that callers don't need to
2722
+ * repeat every field (e.g. adding `cronReschedule` without losing
2723
+ * `storage` / `getUploadUrl`).
2724
+ */
2725
+ setContextFactory(options: Partial<PluginContextFactoryOptions>): void;
2726
+ /**
2727
+ * Get context for a plugin
2728
+ */
2729
+ private getContext;
2730
+ /**
2731
+ * Get typed hooks for a specific hook name.
2732
+ * The internal map stores ResolvedHook<unknown>, but we know each name
2733
+ * maps to a specific handler type via HookHandlerMap.
2734
+ *
2735
+ * Exclusive hooks that have a selected provider are filtered out — they
2736
+ * should only run via invokeExclusiveHook(), not in the regular pipeline.
2737
+ */
2738
+ private getTypedHooks;
2739
+ /**
2740
+ * Register all hooks from plugins.
2741
+ *
2742
+ * Registers each hook name individually to preserve type safety. The
2743
+ * internal map stores ResolvedHook<unknown> since it's keyed by string,
2744
+ * but getTypedHooks() restores the correct handler type on retrieval.
2745
+ */
2746
+ private registerPlugins;
2747
+ /**
2748
+ * Maps hook names to the capability required to register them.
2749
+ *
2750
+ * Hooks not listed here have no capability requirement (e.g. lifecycle
2751
+ * hooks, cron). Any plugin declaring a listed hook without the required
2752
+ * capability will have that hook silently skipped at registration time.
2753
+ */
2754
+ private static readonly HOOK_REQUIRED_CAPABILITY;
2755
+ /**
2756
+ * Register a single plugin's hook by name
2757
+ */
2758
+ private registerPluginHook;
2759
+ /**
2760
+ * Register a single hook
2761
+ */
2762
+ private registerHook;
2763
+ /**
2764
+ * Sort hooks by priority and dependencies
2765
+ */
2766
+ private sortHooks;
2767
+ /**
2768
+ * Execute a hook with timeout
2769
+ */
2770
+ private executeWithTimeout;
2771
+ /**
2772
+ * Run plugin:install hooks
2773
+ */
2774
+ runPluginInstall(pluginId: string): Promise<HookResult<void>[]>;
2775
+ /**
2776
+ * Run plugin:activate hooks
2777
+ */
2778
+ runPluginActivate(pluginId: string): Promise<HookResult<void>[]>;
2779
+ /**
2780
+ * Run plugin:deactivate hooks
2781
+ */
2782
+ runPluginDeactivate(pluginId: string): Promise<HookResult<void>[]>;
2783
+ /**
2784
+ * Run plugin:uninstall hooks
2785
+ */
2786
+ runPluginUninstall(pluginId: string, deleteData: boolean): Promise<HookResult<void>[]>;
2787
+ private runLifecycleHook;
2788
+ /**
2789
+ * Run content:beforeSave hooks
2790
+ * Returns modified content from the pipeline
2791
+ */
2792
+ runContentBeforeSave(content: Record<string, unknown>, collection: string, isNew: boolean): Promise<{
2793
+ content: Record<string, unknown>;
2794
+ results: HookResult<Record<string, unknown>>[];
2795
+ }>;
2796
+ /**
2797
+ * Run content:afterSave hooks
2798
+ */
2799
+ runContentAfterSave(content: Record<string, unknown>, collection: string, isNew: boolean): Promise<HookResult<void>[]>;
2800
+ /**
2801
+ * Run content:beforeDelete hooks
2802
+ * Returns whether deletion is allowed
2803
+ */
2804
+ runContentBeforeDelete(id: string, collection: string): Promise<{
2805
+ allowed: boolean;
2806
+ results: HookResult<boolean>[];
2807
+ }>;
2808
+ /**
2809
+ * Run content:afterDelete hooks
2810
+ */
2811
+ runContentAfterDelete(id: string, collection: string): Promise<HookResult<void>[]>;
2812
+ /**
2813
+ * Run content:afterPublish hooks (fire-and-forget).
2814
+ */
2815
+ runContentAfterPublish(content: Record<string, unknown>, collection: string): Promise<HookResult<void>[]>;
2816
+ /**
2817
+ * Run content:afterUnpublish hooks (fire-and-forget).
2818
+ */
2819
+ runContentAfterUnpublish(content: Record<string, unknown>, collection: string): Promise<HookResult<void>[]>;
2820
+ /**
2821
+ * Run media:beforeUpload hooks
2822
+ */
2823
+ runMediaBeforeUpload(file: {
2824
+ name: string;
2825
+ type: string;
2826
+ size: number;
2827
+ }): Promise<{
2828
+ file: {
2829
+ name: string;
2830
+ type: string;
2831
+ size: number;
2832
+ };
2833
+ results: HookResult<{
2834
+ name: string;
2835
+ type: string;
2836
+ size: number;
2837
+ }>[];
2838
+ }>;
2839
+ /**
2840
+ * Run media:afterUpload hooks
2841
+ */
2842
+ runMediaAfterUpload(media: {
2843
+ id: string;
2844
+ filename: string;
2845
+ mimeType: string;
2846
+ size: number | null;
2847
+ url: string;
2848
+ createdAt: string;
2849
+ }): Promise<HookResult<void>[]>;
2850
+ /**
2851
+ * Invoke the cron hook for a specific plugin.
2852
+ *
2853
+ * Unlike other hooks which broadcast to all plugins, the cron hook is
2854
+ * dispatched only to the target plugin — the one that owns the task.
2855
+ */
2856
+ invokeCronHook(pluginId: string, event: CronEvent): Promise<HookResult<void>>;
2857
+ /**
2858
+ * Run email:beforeSend hooks (middleware pipeline).
2859
+ *
2860
+ * Each handler receives the message and returns a modified message or
2861
+ * `false` to cancel delivery. The pipeline chains message transformations —
2862
+ * each handler receives the output of the previous one.
2863
+ */
2864
+ runEmailBeforeSend(message: EmailMessage, source: string): Promise<{
2865
+ message: EmailMessage | false;
2866
+ results: HookResult<EmailMessage | false>[];
2867
+ }>;
2868
+ /**
2869
+ * Run email:afterSend hooks (fire-and-forget).
2870
+ *
2871
+ * Errors are logged but don't propagate — they don't affect the caller.
2872
+ */
2873
+ runEmailAfterSend(message: EmailMessage, source: string): Promise<HookResult<void>[]>;
2874
+ /**
2875
+ * Run comment:beforeCreate hooks (middleware pipeline).
2876
+ *
2877
+ * Each handler receives the event and returns a modified event or
2878
+ * `false` to reject the comment. The pipeline chains transformations —
2879
+ * each handler receives the output of the previous one.
2880
+ */
2881
+ runCommentBeforeCreate(event: CommentBeforeCreateEvent): Promise<CommentBeforeCreateEvent | false>;
2882
+ /**
2883
+ * Run comment:afterCreate hooks (fire-and-forget).
2884
+ *
2885
+ * Errors are logged but don't propagate — they don't affect the caller.
2886
+ */
2887
+ runCommentAfterCreate(event: CommentAfterCreateEvent): Promise<void>;
2888
+ /**
2889
+ * Run comment:afterModerate hooks (fire-and-forget).
2890
+ *
2891
+ * Errors are logged but don't propagate — they don't affect the caller.
2892
+ */
2893
+ runCommentAfterModerate(event: CommentAfterModerateEvent): Promise<void>;
2894
+ /**
2895
+ * Run page:metadata hooks. Each handler returns contributions that are
2896
+ * merged by the metadata collector. Errors are logged but don't propagate.
2897
+ */
2898
+ runPageMetadata(event: PageMetadataEvent): Promise<Array<{
2899
+ pluginId: string;
2900
+ contributions: PageMetadataContribution[];
2901
+ }>>;
2902
+ /**
2903
+ * Run page:fragments hooks. Only trusted plugins should be registered
2904
+ * for this hook. Errors are logged but don't propagate.
2905
+ */
2906
+ runPageFragments(event: PageFragmentEvent): Promise<Array<{
2907
+ pluginId: string;
2908
+ contributions: PageFragmentContribution[];
2909
+ }>>;
2910
+ /**
2911
+ * Check if any hooks are registered for a given name
2912
+ */
2913
+ hasHooks(name: HookNameV2): boolean;
2914
+ /**
2915
+ * Get hook count for debugging
2916
+ */
2917
+ getHookCount(name: HookNameV2): number;
2918
+ /**
2919
+ * Get all registered hook names
2920
+ */
2921
+ getRegisteredHooks(): HookNameV2[];
2922
+ /**
2923
+ * Returns hook names where at least one handler declared exclusive: true
2924
+ */
2925
+ getRegisteredExclusiveHooks(): string[];
2926
+ /**
2927
+ * Check if a hook is exclusive
2928
+ */
2929
+ isExclusiveHook(name: string): boolean;
2930
+ /**
2931
+ * Set the selected provider for an exclusive hook.
2932
+ * Called by PluginManager after resolution.
2933
+ */
2934
+ setExclusiveSelection(hookName: string, pluginId: string): void;
2935
+ /**
2936
+ * Clear the selected provider for an exclusive hook.
2937
+ */
2938
+ clearExclusiveSelection(hookName: string): void;
2939
+ /**
2940
+ * Get the selected provider for an exclusive hook (if any).
2941
+ */
2942
+ getExclusiveSelection(hookName: string): string | undefined;
2943
+ /**
2944
+ * Get all plugins that registered a handler for a given exclusive hook.
2945
+ */
2946
+ getExclusiveHookProviders(hookName: string): Array<{
2947
+ pluginId: string;
2948
+ }>;
2949
+ /**
2950
+ * Invoke an exclusive hook — dispatch only to the selected provider.
2951
+ * Returns null if no provider is selected or if the selected hook
2952
+ * is not found in the pipeline.
2953
+ *
2954
+ * This is a generic dispatch used by the email pipeline and other
2955
+ * exclusive hook consumers. The handler type is unknown — callers
2956
+ * must know the expected signature.
2957
+ *
2958
+ * Errors are isolated: a failing handler returns an error result
2959
+ * instead of propagating the exception to the caller.
2960
+ */
2961
+ invokeExclusiveHook(hookName: string, event: unknown): Promise<{
2962
+ result: unknown;
2963
+ pluginId: string;
2964
+ error?: Error;
2965
+ duration: number;
2966
+ } | null>;
2967
+ }
2968
+ /**
2969
+ * Create a hook pipeline from plugins
2970
+ */
2971
+ declare function createHookPipeline(plugins: ResolvedPlugin[], factoryOptions?: PluginContextFactoryOptions): HookPipeline;
2972
+ //#endregion
2973
+ //#region src/plugins/email.d.ts
2974
+ /**
2975
+ * EmailPipeline orchestrates email delivery through the plugin hook system.
2976
+ *
2977
+ * The pipeline runs in three stages:
2978
+ * 1. email:beforeSend — middleware hooks that can transform or cancel messages
2979
+ * 2. email:deliver — exclusive hook dispatching to the selected provider
2980
+ * 3. email:afterSend — fire-and-forget hooks for logging/analytics
2981
+ */
2982
+ declare class EmailPipeline {
2983
+ private pipeline;
2984
+ constructor(pipeline: HookPipeline);
2985
+ /**
2986
+ * Replace the underlying hook pipeline.
2987
+ *
2988
+ * Called by the runtime when rebuilding the hook pipeline after a
2989
+ * plugin is enabled or disabled, so the email pipeline dispatches
2990
+ * to the current set of active hooks.
2991
+ */
2992
+ setPipeline(pipeline: HookPipeline): void;
2993
+ /**
2994
+ * Send an email through the full pipeline.
2995
+ *
2996
+ * @param message - The email to send
2997
+ * @param source - Where the email originated ("system" for auth, plugin ID for plugins)
2998
+ * @throws EmailNotConfiguredError if no provider is selected
2999
+ * @throws EmailRecursionError if called re-entrantly from within a hook
3000
+ * @throws Error if the provider handler throws
3001
+ */
3002
+ send(message: EmailMessage, source: string): Promise<void>;
3003
+ /**
3004
+ * Inner send implementation, separated from the recursion guard.
3005
+ */
3006
+ private sendInner;
3007
+ /**
3008
+ * Check if an email provider is configured and available.
3009
+ *
3010
+ * Returns true if an email:deliver provider is selected in the exclusive
3011
+ * hook system. Plugins and auth code use this to decide whether to show
3012
+ * "send invite" vs "copy invite link" UI.
3013
+ */
3014
+ isAvailable(): boolean;
3015
+ }
3016
+ //#endregion
3017
+ //#region src/plugins/context.d.ts
3018
+ /**
3019
+ * Options for creating site info
3020
+ */
3021
+ interface SiteInfoOptions {
3022
+ /** Site name from options table */
3023
+ siteName?: string;
3024
+ /** Site URL from options table or Astro config */
3025
+ siteUrl?: string;
3026
+ /** Site locale from options table */
3027
+ locale?: string;
3028
+ }
3029
+ interface PluginContextFactoryOptions {
3030
+ db: Kysely<Database>;
3031
+ /**
3032
+ * Storage backend for direct media uploads.
3033
+ * If not provided, upload() will throw.
3034
+ */
3035
+ storage?: Storage;
3036
+ /**
3037
+ * Function to generate upload URLs for media.
3038
+ * If not provided, media write operations will throw.
3039
+ */
3040
+ getUploadUrl?: (filename: string, contentType: string) => Promise<{
3041
+ uploadUrl: string;
3042
+ mediaId: string;
3043
+ }>;
3044
+ /**
3045
+ * Site information for ctx.site and ctx.url().
3046
+ * If not provided, site info will have empty defaults.
3047
+ */
3048
+ siteInfo?: SiteInfoOptions;
3049
+ /**
3050
+ * Callback to notify the cron scheduler that the next due time may have changed.
3051
+ * If not provided, ctx.cron will not be available.
3052
+ */
3053
+ cronReschedule?: () => void;
3054
+ /**
3055
+ * Email pipeline instance for ctx.email.
3056
+ * If not provided (or no provider configured), ctx.email will be undefined.
3057
+ */
3058
+ emailPipeline?: EmailPipeline;
3059
+ }
3060
+ //#endregion
3061
+ //#region src/plugins/routes.d.ts
3062
+ /**
3063
+ * Result from a route invocation
3064
+ */
3065
+ interface RouteResult<T = unknown> {
3066
+ success: boolean;
3067
+ data?: T;
3068
+ error?: {
3069
+ code: string;
3070
+ message: string;
3071
+ details?: unknown;
3072
+ };
3073
+ status: number;
3074
+ }
3075
+ /**
3076
+ * Route invocation options
3077
+ */
3078
+ interface InvokeRouteOptions {
3079
+ /** The original request */
3080
+ request: Request;
3081
+ /** Request body (already parsed) */
3082
+ body?: unknown;
3083
+ }
3084
+ /**
3085
+ * Error class for plugin routes
3086
+ * Allows plugins to return structured errors with specific HTTP status codes
3087
+ */
3088
+ declare class PluginRouteError extends Error {
3089
+ code: string;
3090
+ status: number;
3091
+ details?: unknown | undefined;
3092
+ constructor(code: string, message: string, status?: number, details?: unknown | undefined);
3093
+ /**
3094
+ * Create a bad request error (400)
3095
+ */
3096
+ static badRequest(message: string, details?: unknown): PluginRouteError;
3097
+ /**
3098
+ * Create an unauthorized error (401)
3099
+ */
3100
+ static unauthorized(message?: string): PluginRouteError;
3101
+ /**
3102
+ * Create a forbidden error (403)
3103
+ */
3104
+ static forbidden(message?: string): PluginRouteError;
3105
+ /**
3106
+ * Create a not found error (404)
3107
+ */
3108
+ static notFound(message?: string): PluginRouteError;
3109
+ /**
3110
+ * Create a conflict error (409)
3111
+ */
3112
+ static conflict(message: string, details?: unknown): PluginRouteError;
3113
+ /**
3114
+ * Create an internal error (500)
3115
+ */
3116
+ static internal(message?: string): PluginRouteError;
3117
+ }
3118
+ //#endregion
3119
+ //#region src/plugins/manager.d.ts
3120
+ /**
3121
+ * Plugin state in the manager
3122
+ */
3123
+ type PluginState = "registered" | "installed" | "active" | "inactive";
3124
+ /**
3125
+ * Plugin manager options
3126
+ */
3127
+ interface PluginManagerOptions {
3128
+ /** Database instance */
3129
+ db: Kysely<Database>;
3130
+ /** Storage backend for direct media uploads */
3131
+ storage?: Storage;
3132
+ /** Function to generate upload URLs for media */
3133
+ getUploadUrl?: (filename: string, contentType: string) => Promise<{
3134
+ uploadUrl: string;
3135
+ mediaId: string;
3136
+ }>;
3137
+ }
3138
+ /**
3139
+ * Plugin Manager v2
3140
+ *
3141
+ * Manages the full lifecycle of plugins and coordinates hooks/routes.
3142
+ */
3143
+ declare class PluginManager {
3144
+ private options;
3145
+ private plugins;
3146
+ private hookPipeline;
3147
+ private routeRegistry;
3148
+ private factoryOptions;
3149
+ private initialized;
3150
+ constructor(options: PluginManagerOptions);
3151
+ /**
3152
+ * Set the email pipeline used when creating plugin contexts.
3153
+ * Reinitializes routes/hooks if already initialized so ctx.email is available immediately.
3154
+ */
3155
+ setEmailPipeline(pipeline: EmailPipeline): void;
3156
+ /**
3157
+ * Register a plugin definition
3158
+ * This resolves the definition and adds it to the manager, but doesn't install it
3159
+ */
3160
+ register<TStorage extends PluginStorageConfig>(definition: PluginDefinition<TStorage>): ResolvedPlugin<TStorage>;
3161
+ /**
3162
+ * Register multiple plugins
3163
+ */
3164
+ registerAll(definitions: PluginDefinition[]): void;
3165
+ /**
3166
+ * Unregister a plugin
3167
+ * Plugin must be inactive or just registered
3168
+ */
3169
+ unregister(pluginId: string): boolean;
3170
+ /**
3171
+ * Install a plugin (run install hooks, set up storage)
3172
+ */
3173
+ install(pluginId: string): Promise<HookResult<void>[]>;
3174
+ /**
3175
+ * Activate a plugin (run activate hooks, enable hooks/routes)
3176
+ */
3177
+ activate(pluginId: string): Promise<HookResult<void>[]>;
3178
+ /**
3179
+ * Deactivate a plugin (run deactivate hooks, disable hooks/routes)
3180
+ */
3181
+ deactivate(pluginId: string): Promise<HookResult<void>[]>;
3182
+ /**
3183
+ * Uninstall a plugin (run uninstall hooks, optionally delete data)
3184
+ */
3185
+ uninstall(pluginId: string, deleteData?: boolean): Promise<HookResult<void>[]>;
3186
+ /**
3187
+ * Run content:beforeSave hooks across all active plugins
3188
+ */
3189
+ runContentBeforeSave(content: Record<string, unknown>, collection: string, isNew: boolean): Promise<{
3190
+ content: Record<string, unknown>;
3191
+ results: HookResult<Record<string, unknown>>[];
3192
+ }>;
3193
+ /**
3194
+ * Run content:afterSave hooks across all active plugins
3195
+ */
3196
+ runContentAfterSave(content: Record<string, unknown>, collection: string, isNew: boolean): Promise<HookResult<void>[]>;
3197
+ /**
3198
+ * Run content:beforeDelete hooks across all active plugins
3199
+ */
3200
+ runContentBeforeDelete(id: string, collection: string): Promise<{
3201
+ allowed: boolean;
3202
+ results: HookResult<boolean>[];
3203
+ }>;
3204
+ /**
3205
+ * Run content:afterDelete hooks across all active plugins
3206
+ */
3207
+ runContentAfterDelete(id: string, collection: string): Promise<HookResult<void>[]>;
3208
+ /**
3209
+ * Run content:afterPublish hooks across all active plugins
3210
+ */
3211
+ runContentAfterPublish(content: Record<string, unknown>, collection: string): Promise<HookResult<void>[]>;
3212
+ /**
3213
+ * Run content:afterUnpublish hooks across all active plugins
3214
+ */
3215
+ runContentAfterUnpublish(content: Record<string, unknown>, collection: string): Promise<HookResult<void>[]>;
3216
+ /**
3217
+ * Run media:beforeUpload hooks across all active plugins
3218
+ */
3219
+ runMediaBeforeUpload(file: {
3220
+ name: string;
3221
+ type: string;
3222
+ size: number;
3223
+ }): Promise<{
3224
+ file: {
3225
+ name: string;
3226
+ type: string;
3227
+ size: number;
3228
+ };
3229
+ results: HookResult<{
3230
+ name: string;
3231
+ type: string;
3232
+ size: number;
3233
+ }>[];
3234
+ }>;
3235
+ /**
3236
+ * Run media:afterUpload hooks across all active plugins
3237
+ */
3238
+ runMediaAfterUpload(media: MediaItem$1): Promise<HookResult<void>[]>;
3239
+ /**
3240
+ * Invoke the cron hook for a specific plugin (per-plugin dispatch).
3241
+ * Used as the InvokeCronHookFn callback for CronExecutor.
3242
+ */
3243
+ invokeCronHook(pluginId: string, event: CronEvent): Promise<void>;
3244
+ /**
3245
+ * Invoke a plugin route
3246
+ */
3247
+ invokeRoute(pluginId: string, routeName: string, options: InvokeRouteOptions): Promise<RouteResult>;
3248
+ /**
3249
+ * Get all routes for a plugin
3250
+ */
3251
+ getPluginRoutes(pluginId: string): string[];
3252
+ /**
3253
+ * Get a plugin by ID
3254
+ */
3255
+ getPlugin(pluginId: string): ResolvedPlugin | undefined;
3256
+ /**
3257
+ * Get plugin state
3258
+ */
3259
+ getPluginState(pluginId: string): PluginState | undefined;
3260
+ /**
3261
+ * Get all registered plugins
3262
+ */
3263
+ getAllPlugins(): Array<{
3264
+ plugin: ResolvedPlugin;
3265
+ state: PluginState;
3266
+ }>;
3267
+ /**
3268
+ * Get all active plugins
3269
+ */
3270
+ getActivePlugins(): ResolvedPlugin[];
3271
+ /**
3272
+ * Check if a plugin exists
3273
+ */
3274
+ hasPlugin(pluginId: string): boolean;
3275
+ /**
3276
+ * Check if a plugin is active
3277
+ */
3278
+ isActive(pluginId: string): boolean;
3279
+ /**
3280
+ * Get all plugins that registered a handler for an exclusive hook.
3281
+ */
3282
+ getExclusiveHookProviders(hookName: string): Array<{
3283
+ pluginId: string;
3284
+ pluginName: string;
3285
+ }>;
3286
+ /**
3287
+ * Read the selected provider for an exclusive hook from the options table.
3288
+ */
3289
+ getExclusiveHookSelection(hookName: string): Promise<string | null>;
3290
+ /**
3291
+ * Set the selected provider for an exclusive hook in the options table.
3292
+ * Pass null to clear the selection.
3293
+ */
3294
+ setExclusiveHookSelection(hookName: string, pluginId: string | null): Promise<void>;
3295
+ /**
3296
+ * Resolution algorithm for exclusive hooks.
3297
+ *
3298
+ * Delegates to the shared resolveExclusiveHooks() function.
3299
+ * See hooks.ts for the full algorithm description.
3300
+ */
3301
+ resolveExclusiveHooks(preferredHints?: Map<string, string[]>): Promise<void>;
3302
+ /**
3303
+ * Get all exclusive hooks with their providers and current selections.
3304
+ * Used by the admin API.
3305
+ */
3306
+ getExclusiveHooksInfo(): Promise<Array<{
3307
+ hookName: string;
3308
+ providers: Array<{
3309
+ pluginId: string;
3310
+ }>;
3311
+ selectedPluginId: string | null;
3312
+ }>>;
3313
+ /**
3314
+ * Initialize or reinitialize the hook pipeline and route registry
3315
+ */
3316
+ private ensureInitialized;
3317
+ /**
3318
+ * Force reinitialization (useful after plugin state changes)
3319
+ */
3320
+ reinitialize(): void;
3321
+ /**
3322
+ * Delete all cron tasks for a plugin.
3323
+ * Used during uninstall.
3324
+ */
3325
+ private deleteCronTasks;
3326
+ }
3327
+ /**
3328
+ * Create a plugin manager
3329
+ */
3330
+ declare function createPluginManager(options: PluginManagerOptions): PluginManager;
3331
+ //#endregion
3332
+ //#region src/plugins/sandbox/noop.d.ts
3333
+ /**
3334
+ * Error thrown when attempting to use sandboxing on an unsupported platform.
3335
+ */
3336
+ declare class SandboxNotAvailableError extends Error {
3337
+ constructor();
3338
+ }
3339
+ /**
3340
+ * No-op sandbox runner for platforms without isolation support.
3341
+ *
3342
+ * - `isAvailable()` returns false
3343
+ * - `load()` throws SandboxNotAvailableError
3344
+ * - `terminateAll()` is a no-op
3345
+ *
3346
+ * This is the default runner when no platform adapter is configured.
3347
+ */
3348
+ declare class NoopSandboxRunner implements SandboxRunner {
3349
+ /**
3350
+ * Always returns false - sandboxing is not available.
3351
+ */
3352
+ isAvailable(): boolean;
3353
+ /**
3354
+ * Always throws - can't load sandboxed plugins without isolation.
3355
+ */
3356
+ load(_manifest: PluginManifest, _code: string): Promise<SandboxedPlugin>;
3357
+ /**
3358
+ * No-op - sandboxing not available, email callback is irrelevant.
3359
+ */
3360
+ setEmailSend(): void;
3361
+ /**
3362
+ * No-op - nothing to terminate.
3363
+ */
3364
+ terminateAll(): Promise<void>;
3365
+ }
3366
+ /**
3367
+ * Create a no-op sandbox runner.
3368
+ * This is used as the default when no platform adapter is configured.
3369
+ */
3370
+ declare function createNoopSandboxRunner(_options?: SandboxOptions): SandboxRunner;
3371
+ //#endregion
3372
+ //#region src/plugins/sandbox/runtime-options.d.ts
3373
+ interface SandboxRunnerRuntimeOptions extends SandboxOptions {
3374
+ mediaStorage?: Storage;
3375
+ cronReschedule?: () => void;
3376
+ }
3377
+ //#endregion
3378
+ //#region src/plugins/sandbox/node.d.ts
3379
+ declare class NodeSandboxRunner implements SandboxRunner {
3380
+ private readonly options;
3381
+ private readonly limits;
3382
+ private readonly activeWorkers;
3383
+ private emailSend;
3384
+ constructor(options: SandboxRunnerRuntimeOptions);
3385
+ isAvailable(): boolean;
3386
+ load(manifest: PluginManifest, code: string): Promise<SandboxedPlugin>;
3387
+ setEmailSend(callback: SandboxEmailSendCallback | null): void;
3388
+ terminateAll(): Promise<void>;
3389
+ }
3390
+ declare function createNodeSandboxRunner(options: SandboxRunnerRuntimeOptions): SandboxRunner;
3391
+ //#endregion
3392
+ //#region src/import/types.d.ts
3393
+ /** Author info from WordPress */
3394
+ interface WpAuthorInfo {
3395
+ id?: number;
3396
+ login?: string;
3397
+ email?: string;
3398
+ displayName?: string;
3399
+ postCount: number;
3400
+ }
3401
+ /** File-based input (WXR upload) */
3402
+ interface FileInput {
3403
+ type: "file";
3404
+ file: File;
3405
+ }
3406
+ /** URL-based input (REST API probe) */
3407
+ interface UrlInput {
3408
+ type: "url";
3409
+ url: string;
3410
+ /** Optional auth token for authenticated requests */
3411
+ token?: string;
3412
+ }
3413
+ /** OAuth-based input (WordPress.com) */
3414
+ interface OAuthInput {
3415
+ type: "oauth";
3416
+ url: string;
3417
+ accessToken: string;
3418
+ /** Site ID for WordPress.com */
3419
+ siteId?: string;
3420
+ }
3421
+ type SourceInput = FileInput | UrlInput | OAuthInput;
3422
+ /** Auth requirements for an import source */
3423
+ interface SourceAuth {
3424
+ type: "oauth" | "token" | "password" | "none";
3425
+ /** OAuth provider identifier */
3426
+ provider?: string;
3427
+ /** OAuth authorization URL */
3428
+ oauthUrl?: string;
3429
+ /** Human-readable instructions */
3430
+ instructions?: string;
3431
+ }
3432
+ /** What the source can provide */
3433
+ interface SourceCapabilities {
3434
+ /** Can fetch published content without auth */
3435
+ publicContent: boolean;
3436
+ /** Can fetch drafts/private (may need auth) */
3437
+ privateContent: boolean;
3438
+ /** Can fetch all custom post types */
3439
+ customPostTypes: boolean;
3440
+ /** Can fetch all meta fields */
3441
+ allMeta: boolean;
3442
+ /** Can stream media directly */
3443
+ mediaStream: boolean;
3444
+ }
3445
+ /** Suggested next action after probe */
3446
+ type SuggestedAction = {
3447
+ type: "proceed";
3448
+ } | {
3449
+ type: "oauth";
3450
+ url: string;
3451
+ provider: string;
3452
+ } | {
3453
+ type: "upload";
3454
+ instructions: string;
3455
+ } | {
3456
+ type: "install-plugin";
3457
+ instructions: string;
3458
+ };
3459
+ /** Detected i18n/multilingual plugin info */
3460
+ interface I18nDetection {
3461
+ /** Multilingual plugin name (e.g. "wpml", "polylang") */
3462
+ plugin: string;
3463
+ /** BCP 47 default locale */
3464
+ defaultLocale: string;
3465
+ /** All configured locales */
3466
+ locales: string[];
3467
+ }
3468
+ /** Result of probing a URL for a specific source */
3469
+ interface SourceProbeResult {
3470
+ /** Which source can handle this */
3471
+ sourceId: string;
3472
+ /** Confidence level */
3473
+ confidence: "definite" | "likely" | "possible";
3474
+ /** What we detected */
3475
+ detected: {
3476
+ platform: string;
3477
+ version?: string;
3478
+ siteTitle?: string;
3479
+ siteUrl?: string;
3480
+ };
3481
+ /** What capabilities are available */
3482
+ capabilities: SourceCapabilities;
3483
+ /** What auth is needed, if any */
3484
+ auth?: SourceAuth;
3485
+ /** Suggested next step */
3486
+ suggestedAction: SuggestedAction;
3487
+ /** Preview data if available (e.g., post counts from REST API) */
3488
+ preview?: {
3489
+ posts?: number;
3490
+ pages?: number;
3491
+ media?: number;
3492
+ };
3493
+ /** Detected multilingual plugin. Absent when none detected. */
3494
+ i18n?: I18nDetection;
3495
+ }
3496
+ /** Combined probe result from all sources */
3497
+ interface ProbeResult {
3498
+ url: string;
3499
+ isWordPress: boolean;
3500
+ /** Best matching source (highest confidence) */
3501
+ bestMatch: SourceProbeResult | null;
3502
+ /** All matching sources */
3503
+ allMatches: SourceProbeResult[];
3504
+ }
3505
+ /** Field definition for import */
3506
+ interface ImportFieldDef {
3507
+ slug: string;
3508
+ label: string;
3509
+ type: string;
3510
+ required: boolean;
3511
+ searchable?: boolean;
3512
+ }
3513
+ /** Field compatibility with existing schema */
3514
+ type FieldCompatibility = "compatible" | "type_mismatch" | "missing";
3515
+ /** Schema status for a collection */
3516
+ interface CollectionSchemaStatus {
3517
+ exists: boolean;
3518
+ fieldStatus: Record<string, {
3519
+ status: FieldCompatibility;
3520
+ existingType?: string;
3521
+ requiredType: string;
3522
+ }>;
3523
+ canImport: boolean;
3524
+ reason?: string;
3525
+ }
3526
+ /** Analysis of a single post type */
3527
+ interface PostTypeAnalysis {
3528
+ name: string;
3529
+ count: number;
3530
+ suggestedCollection: string;
3531
+ requiredFields: ImportFieldDef[];
3532
+ schemaStatus: CollectionSchemaStatus;
3533
+ }
3534
+ /** Attachment/media info */
3535
+ interface AttachmentInfo {
3536
+ id?: number;
3537
+ title?: string;
3538
+ url?: string;
3539
+ filename?: string;
3540
+ mimeType?: string;
3541
+ alt?: string;
3542
+ caption?: string;
3543
+ width?: number;
3544
+ height?: number;
3545
+ }
3546
+ /** Navigation menu analysis */
3547
+ interface NavMenuAnalysis {
3548
+ /** Menu name/slug */
3549
+ name: string;
3550
+ /** Menu display label */
3551
+ label: string;
3552
+ /** Number of items in this menu */
3553
+ itemCount: number;
3554
+ }
3555
+ /** Custom taxonomy analysis */
3556
+ interface TaxonomyAnalysis {
3557
+ /** Taxonomy slug (e.g., 'genre', 'portfolio_category') */
3558
+ slug: string;
3559
+ /** Number of terms in this taxonomy */
3560
+ termCount: number;
3561
+ /** Sample term names */
3562
+ sampleTerms: string[];
3563
+ }
3564
+ /** Reusable block analysis (wp_block post type) */
3565
+ interface ReusableBlockAnalysis {
3566
+ /** Original WP ID */
3567
+ id: number;
3568
+ /** Block title */
3569
+ title: string;
3570
+ /** Block slug */
3571
+ slug: string;
3572
+ }
3573
+ /** Normalized analysis result - same format for all sources */
3574
+ interface ImportAnalysis {
3575
+ /** Source that produced this analysis */
3576
+ sourceId: string;
3577
+ site: {
3578
+ title: string;
3579
+ url: string;
3580
+ };
3581
+ postTypes: PostTypeAnalysis[];
3582
+ attachments: {
3583
+ count: number;
3584
+ items: AttachmentInfo[];
3585
+ };
3586
+ categories: number;
3587
+ tags: number;
3588
+ authors: WpAuthorInfo[];
3589
+ /** Navigation menus found in the export */
3590
+ navMenus?: NavMenuAnalysis[];
3591
+ /** Custom taxonomies (beyond categories/tags) */
3592
+ customTaxonomies?: TaxonomyAnalysis[];
3593
+ /** Reusable blocks (wp_block post type) - will be imported as sections */
3594
+ reusableBlocks?: ReusableBlockAnalysis[];
3595
+ /** Source-specific custom fields analysis */
3596
+ customFields?: Array<{
3597
+ key: string;
3598
+ count: number;
3599
+ samples: string[];
3600
+ suggestedField: string;
3601
+ suggestedType: "string" | "number" | "boolean" | "date" | "json";
3602
+ isInternal: boolean;
3603
+ }>;
3604
+ /** Detected multilingual plugin. Absent when none detected. */
3605
+ i18n?: I18nDetection;
3606
+ }
3607
+ /** Normalized content item - produced by all sources */
3608
+ interface NormalizedItem {
3609
+ /** Original ID from source */
3610
+ sourceId: string | number;
3611
+ /** WordPress post type */
3612
+ postType: string;
3613
+ /** Content status */
3614
+ status: "publish" | "draft" | "pending" | "private" | "future";
3615
+ /** URL slug */
3616
+ slug: string;
3617
+ /** Title */
3618
+ title: string;
3619
+ /** Content as Portable Text (already converted) */
3620
+ content: PortableTextBlock[];
3621
+ /** Excerpt/summary */
3622
+ excerpt?: string;
3623
+ /** Publication date */
3624
+ date: Date;
3625
+ /** Last modified date */
3626
+ modified?: Date;
3627
+ /** Author identifier */
3628
+ author?: string;
3629
+ /** Category slugs */
3630
+ categories?: string[];
3631
+ /** Tag slugs */
3632
+ tags?: string[];
3633
+ /** Custom meta fields */
3634
+ meta?: Record<string, unknown>;
3635
+ /** Featured image URL */
3636
+ featuredImage?: string;
3637
+ /** Parent post ID (for hierarchical content like pages) */
3638
+ parentId?: string | number;
3639
+ /** Menu order for sorting */
3640
+ menuOrder?: number;
3641
+ /** Custom taxonomy assignments beyond categories/tags */
3642
+ customTaxonomies?: Record<string, string[]>;
3643
+ /** BCP 47 locale code. When omitted, defaults to defaultLocale. */
3644
+ locale?: string;
3645
+ /**
3646
+ * Source-side translation group ID (opaque string from the origin system).
3647
+ * Items sharing the same translationGroup are linked as translations.
3648
+ * Resolved to a Dineway translation_group ULID during execute.
3649
+ */
3650
+ translationGroup?: string;
3651
+ }
3652
+ /** Post type mapping configuration */
3653
+ interface PostTypeMapping {
3654
+ enabled: boolean;
3655
+ collection: string;
3656
+ }
3657
+ /** Import configuration */
3658
+ interface ImportConfig {
3659
+ postTypeMappings: Record<string, PostTypeMapping>;
3660
+ skipExisting?: boolean;
3661
+ }
3662
+ /** Options for fetching content */
3663
+ interface FetchOptions {
3664
+ /** Post types to fetch */
3665
+ postTypes: string[];
3666
+ /** Whether to include drafts */
3667
+ includeDrafts?: boolean;
3668
+ /** Limit number of items (for testing) */
3669
+ limit?: number;
3670
+ }
3671
+ /** Import result */
3672
+ interface ImportResult {
3673
+ success: boolean;
3674
+ imported: number;
3675
+ skipped: number;
3676
+ errors: Array<{
3677
+ title: string;
3678
+ error: string;
3679
+ }>;
3680
+ byCollection: Record<string, number>;
3681
+ }
3682
+ /**
3683
+ * An import source provides content from an external system.
3684
+ * All sources produce the same normalized analysis and content format.
3685
+ */
3686
+ interface ImportSource {
3687
+ /** Unique identifier */
3688
+ id: string;
3689
+ /** Display name */
3690
+ name: string;
3691
+ /** Description for UI */
3692
+ description: string;
3693
+ /** Icon identifier */
3694
+ icon: "upload" | "globe" | "wordpress" | "plug";
3695
+ /** Whether this source requires a file upload */
3696
+ requiresFile?: boolean;
3697
+ /** Whether this source can probe URLs */
3698
+ canProbe?: boolean;
3699
+ /**
3700
+ * Probe a URL to see if this source can handle it.
3701
+ * Returns null if not applicable.
3702
+ */
3703
+ probe?(url: string): Promise<SourceProbeResult | null>;
3704
+ /**
3705
+ * Analyze content from this source.
3706
+ * Returns normalized ImportAnalysis.
3707
+ */
3708
+ analyze(input: SourceInput, context: ImportContext): Promise<ImportAnalysis>;
3709
+ /**
3710
+ * Stream content items for import.
3711
+ * Yields normalized content items.
3712
+ */
3713
+ fetchContent(input: SourceInput, options: FetchOptions): AsyncGenerator<NormalizedItem>;
3714
+ /**
3715
+ * Fetch a media item's data.
3716
+ * Used for media import.
3717
+ */
3718
+ fetchMedia?(url: string, input: SourceInput): Promise<Blob>;
3719
+ }
3720
+ /** Context passed to import sources */
3721
+ interface ImportContext {
3722
+ /** Database connection for schema checks */
3723
+ db?: unknown;
3724
+ /** Function to check existing collections */
3725
+ getExistingCollections?: () => Promise<Map<string, {
3726
+ slug: string;
3727
+ fields: Map<string, {
3728
+ type: string;
3729
+ }>;
3730
+ }>>;
3731
+ }
3732
+ //#endregion
3733
+ //#region src/import/sections.d.ts
3734
+ /**
3735
+ * Result of sections import operation
3736
+ */
3737
+ interface SectionsImportResult {
3738
+ /** Number of sections created */
3739
+ sectionsCreated: number;
3740
+ /** Number of sections skipped (already exist) */
3741
+ sectionsSkipped: number;
3742
+ /** Errors encountered during import */
3743
+ errors: Array<{
3744
+ title: string;
3745
+ error: string;
3746
+ }>;
3747
+ }
3748
+ /**
3749
+ * Import reusable blocks (wp_block post type) from WXR as sections
3750
+ *
3751
+ * @param posts - All posts from WXR (will filter to wp_block)
3752
+ * @param db - Database connection
3753
+ * @returns Import result with counts
3754
+ */
3755
+ declare function importReusableBlocksAsSections(posts: WxrPost[], db: Kysely<Database>): Promise<SectionsImportResult>;
3756
+ //#endregion
3757
+ //#region src/import/registry.d.ts
3758
+ /**
3759
+ * Register an import source
3760
+ */
3761
+ declare function registerSource(source: ImportSource): void;
3762
+ /**
3763
+ * Get a source by ID
3764
+ */
3765
+ declare function getSource(id: string): ImportSource | undefined;
3766
+ /**
3767
+ * Get all registered sources
3768
+ */
3769
+ declare function getAllSources(): ImportSource[];
3770
+ /**
3771
+ * Get sources that can handle file uploads
3772
+ */
3773
+ declare function getFileSources(): ImportSource[];
3774
+ /**
3775
+ * Get sources that can probe URLs
3776
+ */
3777
+ declare function getUrlSources(): ImportSource[];
3778
+ /**
3779
+ * Probe a URL against all registered sources
3780
+ *
3781
+ * Returns probe results sorted by confidence (definite > likely > possible)
3782
+ */
3783
+ declare function probeUrl(url: string): Promise<ProbeResult>;
3784
+ /**
3785
+ * Clear all registered sources (useful for testing)
3786
+ */
3787
+ declare function clearSources(): void;
3788
+ //#endregion
3789
+ //#region src/import/sources/wxr.d.ts
3790
+ declare const wxrSource: ImportSource;
3791
+ /**
3792
+ * Parse a WXR date with the correct fallback chain:
3793
+ * 1. GMT date (always UTC, most reliable)
3794
+ * 2. pubDate (RFC 2822, includes timezone offset)
3795
+ * 3. Site-local date (MySQL datetime without timezone, imprecise but best available)
3796
+ *
3797
+ * Returns undefined when none of the inputs yield a valid date.
3798
+ * Callers that need a guaranteed Date should use `?? new Date()`.
3799
+ */
3800
+ declare function parseWxrDate(gmtDate: string | undefined, pubDate: string | undefined, localDate: string | undefined): Date | undefined;
3801
+ //#endregion
3802
+ //#region src/import/sources/wordpress-rest.d.ts
3803
+ declare const wordpressRestSource: ImportSource;
3804
+ //#endregion
3805
+ //#region src/preview/tokens.d.ts
3806
+ /**
3807
+ * Preview token generation and verification
3808
+ *
3809
+ * Tokens are compact, URL-safe, and HMAC-signed.
3810
+ * Format: base64url(JSON payload).base64url(HMAC signature)
3811
+ *
3812
+ * Payload: { cid: contentId, exp: expiryTimestamp, iat: issuedAt }
3813
+ */
3814
+ /**
3815
+ * Preview token payload
3816
+ */
3817
+ interface PreviewTokenPayload {
3818
+ /** Content ID in format "collection:id" (e.g., "posts:abc123") */
3819
+ cid: string;
3820
+ /** Expiry timestamp (seconds since epoch) */
3821
+ exp: number;
3822
+ /** Issued at timestamp (seconds since epoch) */
3823
+ iat: number;
3824
+ }
3825
+ /**
3826
+ * Options for generating a preview token
3827
+ */
3828
+ interface GeneratePreviewTokenOptions {
3829
+ /** Content ID in format "collection:id" */
3830
+ contentId: string;
3831
+ /** How long the token is valid. Accepts "1h", "30m", "1d", or seconds as number. Default: "1h" */
3832
+ expiresIn?: string | number;
3833
+ /** Secret key for signing. Should be from environment variable. */
3834
+ secret: string;
3835
+ }
3836
+ /**
3837
+ * Generate a preview token for content
3838
+ *
3839
+ * @example
3840
+ * ```ts
3841
+ * const token = await generatePreviewToken({
3842
+ * contentId: "posts:abc123",
3843
+ * expiresIn: "1h",
3844
+ * secret: process.env.PREVIEW_SECRET!,
3845
+ * });
3846
+ * ```
3847
+ */
3848
+ declare function generatePreviewToken(options: GeneratePreviewTokenOptions): Promise<string>;
3849
+ /**
3850
+ * Result of verifying a preview token
3851
+ */
3852
+ type VerifyPreviewTokenResult = {
3853
+ valid: true;
3854
+ payload: PreviewTokenPayload;
3855
+ } | {
3856
+ valid: false;
3857
+ error: "invalid" | "expired" | "malformed" | "none";
3858
+ };
3859
+ /**
3860
+ * Options for verifyPreviewToken
3861
+ */
3862
+ type VerifyPreviewTokenOptions = {
3863
+ /** Secret key for verifying tokens */secret: string;
3864
+ } & ({
3865
+ url: URL;
3866
+ } | {
3867
+ /** Preview token string (can be null) */token: string | null | undefined;
3868
+ });
3869
+ /**
3870
+ * Verify a preview token and return the payload
3871
+ *
3872
+ * @example
3873
+ * ```ts
3874
+ * // With URL (extracts _preview query param)
3875
+ * const result = await verifyPreviewToken({
3876
+ * url: Astro.url,
3877
+ * secret: import.meta.env.PREVIEW_SECRET,
3878
+ * });
3879
+ *
3880
+ * // With token directly
3881
+ * const result = await verifyPreviewToken({
3882
+ * token: someToken,
3883
+ * secret: import.meta.env.PREVIEW_SECRET,
3884
+ * });
3885
+ *
3886
+ * if (result.valid) {
3887
+ * console.log(result.payload.cid); // "posts:abc123"
3888
+ * }
3889
+ * ```
3890
+ */
3891
+ declare function verifyPreviewToken(options: VerifyPreviewTokenOptions): Promise<VerifyPreviewTokenResult>;
3892
+ /**
3893
+ * Parse a content ID into collection and id
3894
+ */
3895
+ declare function parseContentId(contentId: string): {
3896
+ collection: string;
3897
+ id: string;
3898
+ };
3899
+ //#endregion
3900
+ //#region src/preview/urls.d.ts
3901
+ /**
3902
+ * Preview URL generation
3903
+ *
3904
+ * Creates preview URLs that include a signed token for accessing draft content.
3905
+ */
3906
+ /**
3907
+ * Options for generating a preview URL
3908
+ */
3909
+ interface GetPreviewUrlOptions {
3910
+ /** Collection slug (e.g., "posts") */
3911
+ collection: string;
3912
+ /** Content ID or slug */
3913
+ id: string;
3914
+ /** Secret key for signing the token */
3915
+ secret: string;
3916
+ /** How long the preview URL is valid. Default: "1h" */
3917
+ expiresIn?: string | number;
3918
+ /** Base URL of the site. If not provided, returns a relative URL. */
3919
+ baseUrl?: string;
3920
+ /** Custom path pattern. Use {collection} and {id} as placeholders. Default: "/{collection}/{id}" */
3921
+ pathPattern?: string;
3922
+ }
3923
+ /**
3924
+ * Generate a preview URL for content
3925
+ *
3926
+ * The URL includes a `_preview` query parameter with a signed token.
3927
+ *
3928
+ * @example
3929
+ * ```ts
3930
+ * const url = await getPreviewUrl({
3931
+ * collection: "posts",
3932
+ * id: "hello-world",
3933
+ * secret: process.env.PREVIEW_SECRET!,
3934
+ * });
3935
+ * // Returns: /posts/hello-world?_preview=eyJj...
3936
+ *
3937
+ * // With base URL:
3938
+ * const fullUrl = await getPreviewUrl({
3939
+ * collection: "posts",
3940
+ * id: "hello-world",
3941
+ * secret: process.env.PREVIEW_SECRET!,
3942
+ * baseUrl: "https://example.com",
3943
+ * });
3944
+ * // Returns: https://example.com/posts/hello-world?_preview=eyJj...
3945
+ *
3946
+ * // Custom path pattern:
3947
+ * const customUrl = await getPreviewUrl({
3948
+ * collection: "posts",
3949
+ * id: "hello-world",
3950
+ * secret: process.env.PREVIEW_SECRET!,
3951
+ * pathPattern: "/blog/{id}",
3952
+ * });
3953
+ * // Returns: /blog/hello-world?_preview=eyJj...
3954
+ * ```
3955
+ */
3956
+ declare function getPreviewUrl(options: GetPreviewUrlOptions): Promise<string>;
3957
+ /**
3958
+ * Build a preview URL from a token (when you already have the token)
3959
+ *
3960
+ * @example
3961
+ * ```ts
3962
+ * const url = buildPreviewUrl({
3963
+ * path: "/posts/hello-world",
3964
+ * token: existingToken,
3965
+ * });
3966
+ * ```
3967
+ */
3968
+ declare function buildPreviewUrl(options: {
3969
+ path: string;
3970
+ token: string;
3971
+ baseUrl?: string;
3972
+ }): string;
3973
+ //#endregion
3974
+ //#region src/preview/helpers.d.ts
3975
+ /**
3976
+ * Preview helpers for Astro pages
3977
+ */
3978
+ /**
3979
+ * Check if a request is a preview request
3980
+ *
3981
+ * @example
3982
+ * ```ts
3983
+ * const isPreview = isPreviewRequest(Astro.url);
3984
+ * ```
3985
+ */
3986
+ declare function isPreviewRequest(url: URL): boolean;
3987
+ /**
3988
+ * Get the preview token from a URL
3989
+ *
3990
+ * @example
3991
+ * ```ts
3992
+ * const token = getPreviewToken(Astro.url);
3993
+ * ```
3994
+ */
3995
+ declare function getPreviewToken(url: URL): string | null;
3996
+ //#endregion
3997
+ //#region src/preview/routes.d.ts
3998
+ /**
3999
+ * Preview mode route gating.
4000
+ *
4001
+ * Preview is read-only with no authenticated user. All `/_dineway/`
4002
+ * routes are blocked by default. Only specific read-only API prefixes
4003
+ * are allowlisted.
4004
+ */
4005
+ declare function isBlockedInPreview(pathname: string): boolean;
4006
+ //#endregion
4007
+ //#region src/preview/loading.d.ts
4008
+ declare function renderPreviewLoadingPage(): string;
4009
+ //#endregion
4010
+ //#region src/preview/snapshot-types.d.ts
4011
+ interface Snapshot {
4012
+ tables: Record<string, Record<string, unknown>[]>;
4013
+ schema: Record<string, {
4014
+ columns: string[];
4015
+ types?: Record<string, string>;
4016
+ }>;
4017
+ generatedAt: string;
4018
+ }
4019
+ //#endregion
4020
+ //#region src/preview/snapshot-database.d.ts
4021
+ interface AppliedSnapshotMeta {
4022
+ fetchedAt: number;
4023
+ generatedAt: string;
4024
+ }
4025
+ interface ApplySnapshotToDatabaseOptions {
4026
+ fetchedAt?: number;
4027
+ reset?: boolean;
4028
+ }
4029
+ declare function dropSessionDatabaseTables(db: Kysely<Database>): Promise<void>;
4030
+ declare function applySnapshotToDatabase(db: Kysely<Database>, snapshot: Snapshot, options?: ApplySnapshotToDatabaseOptions): Promise<void>;
4031
+ declare function getAppliedSnapshotMeta(db: Kysely<Database>): Promise<AppliedSnapshotMeta | null>;
4032
+ //#endregion
4033
+ //#region src/preview/toolbar.d.ts
4034
+ /**
4035
+ * Preview toolbar injected into preview responses.
4036
+ *
4037
+ * Plain HTML with inline styles/script so sidecar middleware can use it
4038
+ * without any framework/runtime dependency.
4039
+ */
4040
+ interface PreviewToolbarConfig {
4041
+ generatedAt?: string;
4042
+ source?: string;
4043
+ error?: string;
4044
+ }
4045
+ declare function renderPreviewToolbar(config: PreviewToolbarConfig): string;
4046
+ //#endregion
4047
+ //#region src/settings/index.d.ts
4048
+ /**
4049
+ * Get a single site setting by key
4050
+ *
4051
+ * Returns `undefined` if the setting has not been configured.
4052
+ * For media settings (logo, favicon), the URL is resolved automatically.
4053
+ *
4054
+ * @param key - The setting key (e.g., "title", "logo", "social")
4055
+ * @returns The setting value, or undefined if not set
4056
+ *
4057
+ * @example
4058
+ * ```ts
4059
+ * import { getSiteSetting } from "dineway";
4060
+ *
4061
+ * const title = await getSiteSetting("title");
4062
+ * const logo = await getSiteSetting("logo");
4063
+ * console.log(logo?.url); // Resolved URL
4064
+ * ```
4065
+ */
4066
+ declare function getSiteSetting<K extends SiteSettingKey>(key: K): Promise<SiteSettings[K] | undefined>;
4067
+ /**
4068
+ * Get all site settings
4069
+ *
4070
+ * Returns all configured settings. Unset values are undefined.
4071
+ * Media references (logo/favicon) are resolved to include URLs.
4072
+ *
4073
+ * @example
4074
+ * ```ts
4075
+ * import { getSiteSettings } from "dineway";
4076
+ *
4077
+ * const settings = await getSiteSettings();
4078
+ * console.log(settings.title); // "My Site"
4079
+ * console.log(settings.logo?.url); // "/_dineway/api/media/file/abc123"
4080
+ * ```
4081
+ */
4082
+ declare function getSiteSettings(): Promise<Partial<SiteSettings>>;
4083
+ /**
4084
+ * Set site settings (internal function used by admin API)
4085
+ *
4086
+ * Merges provided settings with existing ones. Only provided fields are updated.
4087
+ * Media references should include just the mediaId; URLs are resolved on read.
4088
+ *
4089
+ * @param settings - Partial settings object with values to update
4090
+ * @param db - Kysely database instance
4091
+ * @returns Promise that resolves when settings are saved
4092
+ *
4093
+ * @internal
4094
+ *
4095
+ * @example
4096
+ * ```ts
4097
+ * // Update multiple settings at once
4098
+ * await setSiteSettings({
4099
+ * title: "My Site",
4100
+ * tagline: "Welcome",
4101
+ * logo: { mediaId: "med_123", alt: "Logo" }
4102
+ * }, db);
4103
+ * ```
4104
+ */
4105
+ declare function setSiteSettings(settings: Partial<SiteSettings>, db: Kysely<Database>): Promise<void>;
4106
+ /**
4107
+ * Get a single plugin setting by key.
4108
+ *
4109
+ * Plugin settings are stored in the options table under
4110
+ * `plugin:<pluginId>:settings:<key>`.
4111
+ */
4112
+ declare function getPluginSetting<T = unknown>(pluginId: string, key: string): Promise<T | undefined>;
4113
+ /**
4114
+ * Get all persisted plugin settings for a plugin.
4115
+ *
4116
+ * Defaults declared in `admin.settingsSchema` are not materialized
4117
+ * automatically; callers should apply their own fallback defaults.
4118
+ */
4119
+ declare function getPluginSettings(pluginId: string): Promise<Record<string, unknown>>;
4120
+ //#endregion
4121
+ //#region src/comments/query.d.ts
4122
+ interface GetCommentsOptions {
4123
+ collection: string;
4124
+ contentId: string;
4125
+ threaded?: boolean;
4126
+ }
4127
+ interface GetCommentsResult {
4128
+ items: PublicComment[];
4129
+ total: number;
4130
+ }
4131
+ /**
4132
+ * Get approved comments for a content item.
4133
+ *
4134
+ * @example
4135
+ * ```ts
4136
+ * import { getComments } from "dineway";
4137
+ *
4138
+ * const { items, total } = await getComments({
4139
+ * collection: "posts",
4140
+ * contentId: post.id,
4141
+ * threaded: true,
4142
+ * });
4143
+ * ```
4144
+ */
4145
+ declare function getComments(options: GetCommentsOptions): Promise<GetCommentsResult>;
4146
+ /**
4147
+ * Get the count of approved comments for a content item.
4148
+ *
4149
+ * @example
4150
+ * ```ts
4151
+ * import { getCommentCount } from "dineway";
4152
+ *
4153
+ * const count = await getCommentCount("posts", post.id);
4154
+ * ```
4155
+ */
4156
+ declare function getCommentCount(collection: string, contentId: string): Promise<number>;
4157
+ //#endregion
4158
+ //#region src/menus/types.d.ts
4159
+ /**
4160
+ * Menu item types
4161
+ */
4162
+ type MenuItemType = string;
4163
+ /**
4164
+ * Menu item as returned to templates (with resolved URL)
4165
+ */
4166
+ interface MenuItem {
4167
+ id: string;
4168
+ label: string;
4169
+ url: string;
4170
+ target?: string;
4171
+ titleAttr?: string;
4172
+ cssClasses?: string;
4173
+ children: MenuItem[];
4174
+ }
4175
+ /**
4176
+ * Menu as returned to templates
4177
+ */
4178
+ interface Menu {
4179
+ id: string;
4180
+ name: string;
4181
+ label: string;
4182
+ items: MenuItem[];
4183
+ }
4184
+ /**
4185
+ * Input for creating a menu item
4186
+ */
4187
+ interface CreateMenuItemInput {
4188
+ type: MenuItemType;
4189
+ label: string;
4190
+ referenceCollection?: string;
4191
+ referenceId?: string;
4192
+ customUrl?: string;
4193
+ target?: string;
4194
+ titleAttr?: string;
4195
+ cssClasses?: string;
4196
+ parentId?: string;
4197
+ sortOrder?: number;
4198
+ }
4199
+ /**
4200
+ * Input for updating a menu item
4201
+ */
4202
+ interface UpdateMenuItemInput {
4203
+ label?: string;
4204
+ customUrl?: string;
4205
+ target?: string;
4206
+ titleAttr?: string;
4207
+ cssClasses?: string;
4208
+ parentId?: string | null;
4209
+ sortOrder?: number;
4210
+ }
4211
+ /**
4212
+ * Input for creating a menu
4213
+ */
4214
+ interface CreateMenuInput {
4215
+ name: string;
4216
+ label: string;
4217
+ }
4218
+ /**
4219
+ * Input for updating a menu
4220
+ */
4221
+ interface UpdateMenuInput {
4222
+ label?: string;
4223
+ }
4224
+ /**
4225
+ * Input for reordering menu items
4226
+ */
4227
+ interface ReorderMenuItemsInput {
4228
+ items: Array<{
4229
+ id: string;
4230
+ parentId: string | null;
4231
+ sortOrder: number;
4232
+ }>;
4233
+ }
4234
+ //#endregion
4235
+ //#region src/menus/index.d.ts
4236
+ /**
4237
+ * Get menu by name with resolved URLs
4238
+ *
4239
+ * @example
4240
+ * ```ts
4241
+ * import { getMenu } from "dineway";
4242
+ *
4243
+ * const menu = await getMenu("primary");
4244
+ * if (menu) {
4245
+ * console.log(menu.items); // Array of MenuItem with resolved URLs
4246
+ * }
4247
+ * ```
4248
+ */
4249
+ declare function getMenu(name: string): Promise<Menu | null>;
4250
+ /**
4251
+ * Get all menus (without items - for admin list)
4252
+ *
4253
+ * @example
4254
+ * ```ts
4255
+ * import { getMenus } from "dineway";
4256
+ *
4257
+ * const menus = await getMenus();
4258
+ * console.log(menus); // [{ id, name, label }]
4259
+ * ```
4260
+ */
4261
+ declare function getMenus(): Promise<Array<{
4262
+ id: string;
4263
+ name: string;
4264
+ label: string;
4265
+ }>>;
4266
+ //#endregion
4267
+ //#region src/bylines/index.d.ts
4268
+ /**
4269
+ * Get a byline by ID.
4270
+ *
4271
+ * @example
4272
+ * ```ts
4273
+ * import { getByline } from "dineway";
4274
+ *
4275
+ * const byline = await getByline("01HXYZ...");
4276
+ * if (byline) {
4277
+ * console.log(byline.displayName);
4278
+ * }
4279
+ * ```
4280
+ */
4281
+ declare function getByline(id: string): Promise<BylineSummary | null>;
4282
+ /**
4283
+ * Get a byline by slug.
4284
+ *
4285
+ * @example
4286
+ * ```ts
4287
+ * import { getBylineBySlug } from "dineway";
4288
+ *
4289
+ * const byline = await getBylineBySlug("jane-doe");
4290
+ * if (byline) {
4291
+ * console.log(byline.displayName); // "Jane Doe"
4292
+ * }
4293
+ * ```
4294
+ */
4295
+ declare function getBylineBySlug(slug: string): Promise<BylineSummary | null>;
4296
+ //#endregion
4297
+ //#region src/taxonomies/types.d.ts
4298
+ /**
4299
+ * Taxonomy types for Dineway Agentic Web builder
4300
+ */
4301
+ /**
4302
+ * Taxonomy definition - describes a taxonomy like "category" or "tag"
4303
+ */
4304
+ interface TaxonomyDef {
4305
+ id: string;
4306
+ name: string;
4307
+ label: string;
4308
+ labelSingular?: string;
4309
+ hierarchical: boolean;
4310
+ collections: string[];
4311
+ }
4312
+ /**
4313
+ * Taxonomy term - a specific term within a taxonomy (e.g., "News" in "category")
4314
+ */
4315
+ interface TaxonomyTerm {
4316
+ id: string;
4317
+ name: string;
4318
+ slug: string;
4319
+ label: string;
4320
+ parentId?: string;
4321
+ description?: string;
4322
+ children: TaxonomyTerm[];
4323
+ count?: number;
4324
+ }
4325
+ /**
4326
+ * Flat version for DB row
4327
+ */
4328
+ interface TaxonomyTermRow {
4329
+ id: string;
4330
+ name: string;
4331
+ slug: string;
4332
+ label: string;
4333
+ parent_id: string | null;
4334
+ data: string | null;
4335
+ }
4336
+ /**
4337
+ * Input for creating a term
4338
+ */
4339
+ interface CreateTermInput {
4340
+ slug: string;
4341
+ label: string;
4342
+ parentId?: string;
4343
+ description?: string;
4344
+ }
4345
+ /**
4346
+ * Input for updating a term
4347
+ */
4348
+ interface UpdateTermInput {
4349
+ slug?: string;
4350
+ label?: string;
4351
+ parentId?: string | null;
4352
+ description?: string;
4353
+ }
4354
+ //#endregion
4355
+ //#region src/taxonomies/index.d.ts
4356
+ /**
4357
+ * Get all taxonomy definitions
4358
+ */
4359
+ declare function getTaxonomyDefs(): Promise<TaxonomyDef[]>;
4360
+ /**
4361
+ * Get a single taxonomy definition by name
4362
+ */
4363
+ declare function getTaxonomyDef(name: string): Promise<TaxonomyDef | null>;
4364
+ /**
4365
+ * Get all terms for a taxonomy (as tree for hierarchical, flat for tags)
4366
+ */
4367
+ declare function getTaxonomyTerms(taxonomyName: string): Promise<TaxonomyTerm[]>;
4368
+ /**
4369
+ * Get a single term by taxonomy and slug
4370
+ */
4371
+ declare function getTerm(taxonomyName: string, slug: string): Promise<TaxonomyTerm | null>;
4372
+ /**
4373
+ * Get terms assigned to an entry
4374
+ */
4375
+ declare function getEntryTerms(collection: string, entryId: string, taxonomyName?: string): Promise<TaxonomyTerm[]>;
4376
+ /**
4377
+ * Get terms for multiple entries in a single query (batched API)
4378
+ *
4379
+ * This is more efficient than calling getEntryTerms for each entry
4380
+ * when you need terms for a list of entries.
4381
+ *
4382
+ * @param collection - The collection type (e.g., "posts")
4383
+ * @param entryIds - Array of entry IDs
4384
+ * @param taxonomyName - The taxonomy name (e.g., "categories")
4385
+ * @returns Map from entry ID to array of terms
4386
+ */
4387
+ declare function getTermsForEntries(collection: string, entryIds: string[], taxonomyName: string): Promise<Map<string, TaxonomyTerm[]>>;
4388
+ /**
4389
+ * Get entries by term (wraps getDinewayCollection)
4390
+ */
4391
+ declare function getEntriesByTerm(collection: string, taxonomyName: string, termSlug: string): Promise<Array<{
4392
+ id: string;
4393
+ data: Record<string, unknown>;
4394
+ }>>;
4395
+ //#endregion
4396
+ //#region src/widgets/types.d.ts
4397
+ type WidgetType = "content" | "menu" | "component";
4398
+ interface Widget {
4399
+ id: string;
4400
+ type: WidgetType;
4401
+ title?: string;
4402
+ content?: PortableTextBlock$2[];
4403
+ menuName?: string;
4404
+ componentId?: string;
4405
+ componentProps?: Record<string, unknown>;
4406
+ }
4407
+ interface WidgetArea {
4408
+ id: string;
4409
+ name: string;
4410
+ label: string;
4411
+ description?: string;
4412
+ widgets: Widget[];
4413
+ }
4414
+ interface WidgetComponentDef {
4415
+ id: string;
4416
+ label: string;
4417
+ description?: string;
4418
+ props: Record<string, PropDef>;
4419
+ }
4420
+ interface PropDef {
4421
+ type: "string" | "number" | "boolean" | "select";
4422
+ label: string;
4423
+ default?: unknown;
4424
+ options?: Array<{
4425
+ value: string;
4426
+ label: string;
4427
+ }>;
4428
+ }
4429
+ interface CreateWidgetAreaInput {
4430
+ name: string;
4431
+ label: string;
4432
+ description?: string;
4433
+ }
4434
+ interface CreateWidgetInput {
4435
+ type: WidgetType;
4436
+ title?: string;
4437
+ content?: PortableTextBlock$2[];
4438
+ menuName?: string;
4439
+ componentId?: string;
4440
+ componentProps?: Record<string, unknown>;
4441
+ }
4442
+ interface UpdateWidgetInput extends Partial<CreateWidgetInput> {}
4443
+ interface ReorderWidgetsInput {
4444
+ widgetIds: string[];
4445
+ }
4446
+ //#endregion
4447
+ //#region src/widgets/index.d.ts
4448
+ /**
4449
+ * Get a widget area by name, with all its widgets
4450
+ */
4451
+ declare function getWidgetArea(name: string): Promise<WidgetArea | null>;
4452
+ /**
4453
+ * Get all widget areas with their widgets
4454
+ */
4455
+ declare function getWidgetAreas(): Promise<WidgetArea[]>;
4456
+ /**
4457
+ * Get available widget components (for admin UI)
4458
+ */
4459
+ declare function getWidgetComponents(): WidgetComponentDef[];
4460
+ //#endregion
4461
+ //#region src/search/types.d.ts
4462
+ /**
4463
+ * Search Types
4464
+ *
4465
+ * Type definitions for the Dineway search system.
4466
+ */
4467
+ /**
4468
+ * Search configuration for a collection
4469
+ */
4470
+ interface SearchConfig {
4471
+ /** Whether search is enabled for this collection */
4472
+ enabled: boolean;
4473
+ /** Field weights for ranking (higher = more important) */
4474
+ weights?: Record<string, number>;
4475
+ }
4476
+ /**
4477
+ * Options for search queries
4478
+ */
4479
+ interface SearchOptions {
4480
+ /** Collections to search (defaults to all searchable collections) */
4481
+ collections?: string[];
4482
+ /** Filter by content status (defaults to 'published') */
4483
+ status?: string;
4484
+ /** Filter by locale (omit to search all locales) */
4485
+ locale?: string;
4486
+ /** Maximum results to return (defaults to 20) */
4487
+ limit?: number;
4488
+ /** Pagination cursor */
4489
+ cursor?: string;
4490
+ }
4491
+ /**
4492
+ * Options for collection-specific search
4493
+ */
4494
+ interface CollectionSearchOptions {
4495
+ /** Filter by content status (defaults to 'published') */
4496
+ status?: string;
4497
+ /** Filter by locale (omit to search all locales) */
4498
+ locale?: string;
4499
+ /** Maximum results to return (defaults to 20) */
4500
+ limit?: number;
4501
+ /** Pagination cursor */
4502
+ cursor?: string;
4503
+ }
4504
+ /**
4505
+ * A single search result
4506
+ */
4507
+ interface SearchResult {
4508
+ /** Collection the result belongs to */
4509
+ collection: string;
4510
+ /** Entry ID */
4511
+ id: string;
4512
+ /** Entry slug */
4513
+ slug: string | null;
4514
+ /** Content locale */
4515
+ locale: string;
4516
+ /** Entry title (if available) */
4517
+ title?: string;
4518
+ /** Highlighted snippet showing match context */
4519
+ snippet?: string;
4520
+ /** Relevance score (higher = more relevant) */
4521
+ score: number;
4522
+ }
4523
+ /**
4524
+ * Response from a search query
4525
+ */
4526
+ interface SearchResponse {
4527
+ /** Search results */
4528
+ items: SearchResult[];
4529
+ /** Cursor for next page of results */
4530
+ nextCursor?: string;
4531
+ }
4532
+ /**
4533
+ * Options for suggestion/autocomplete queries
4534
+ */
4535
+ interface SuggestOptions {
4536
+ /** Collections to search (defaults to all searchable collections) */
4537
+ collections?: string[];
4538
+ /** Filter by locale (omit to search all locales) */
4539
+ locale?: string;
4540
+ /** Maximum suggestions to return (defaults to 5) */
4541
+ limit?: number;
4542
+ }
4543
+ /**
4544
+ * A single suggestion result
4545
+ */
4546
+ interface Suggestion {
4547
+ /** Collection the suggestion belongs to */
4548
+ collection: string;
4549
+ /** Entry ID */
4550
+ id: string;
4551
+ /** Entry title */
4552
+ title: string;
4553
+ }
4554
+ /**
4555
+ * Search index statistics
4556
+ */
4557
+ interface SearchStats {
4558
+ collections: Record<string, {
4559
+ /** Number of indexed entries */indexed: number; /** When the index was last rebuilt */
4560
+ lastRebuilt?: string;
4561
+ }>;
4562
+ }
4563
+ //#endregion
4564
+ //#region src/search/fts-manager.d.ts
4565
+ /**
4566
+ * FTS5 Manager
4567
+ *
4568
+ * Handles creation, deletion, and management of FTS5 virtual tables
4569
+ * for full-text search on content collections.
4570
+ */
4571
+ declare class FTSManager {
4572
+ private db;
4573
+ constructor(db: Kysely<Database>);
4574
+ /**
4575
+ * Validate a collection slug and its searchable field names.
4576
+ * Must be called before any raw SQL interpolation.
4577
+ */
4578
+ private validateInputs;
4579
+ /**
4580
+ * Get the FTS table name for a collection
4581
+ * Uses _dineway_ prefix to clearly mark as internal/system table
4582
+ */
4583
+ getFtsTableName(collectionSlug: string): string;
4584
+ /**
4585
+ * Get the content table name for a collection
4586
+ */
4587
+ getContentTableName(collectionSlug: string): string;
4588
+ /**
4589
+ * Check if an FTS table exists for a collection
4590
+ */
4591
+ ftsTableExists(collectionSlug: string): Promise<boolean>;
4592
+ /**
4593
+ * Create an FTS5 virtual table for a collection.
4594
+ * FTS5 is SQLite-only; on other dialects this is a no-op.
4595
+ *
4596
+ * @param collectionSlug - The collection slug
4597
+ * @param searchableFields - Array of field names to index
4598
+ * @param weights - Optional field weights for ranking
4599
+ */
4600
+ createFtsTable(collectionSlug: string, searchableFields: string[], _weights?: Record<string, number>): Promise<void>;
4601
+ /**
4602
+ * Create triggers to keep FTS table in sync with content table
4603
+ */
4604
+ private createTriggers;
4605
+ /**
4606
+ * Drop triggers for a collection
4607
+ */
4608
+ private dropTriggers;
4609
+ /**
4610
+ * Drop the FTS table and triggers for a collection
4611
+ */
4612
+ dropFtsTable(collectionSlug: string): Promise<void>;
4613
+ /**
4614
+ * Rebuild the FTS index for a collection
4615
+ *
4616
+ * This is useful after bulk imports or if the index gets out of sync.
4617
+ */
4618
+ rebuildIndex(collectionSlug: string, searchableFields: string[], weights?: Record<string, number>): Promise<void>;
4619
+ /**
4620
+ * Populate the FTS table from existing content
4621
+ */
4622
+ populateFromContent(collectionSlug: string, searchableFields: string[]): Promise<void>;
4623
+ /**
4624
+ * Get the search configuration for a collection
4625
+ */
4626
+ getSearchConfig(collectionSlug: string): Promise<SearchConfig | null>;
4627
+ /**
4628
+ * Update the search configuration for a collection
4629
+ */
4630
+ setSearchConfig(collectionSlug: string, config: SearchConfig): Promise<void>;
4631
+ /**
4632
+ * Get searchable fields for a collection
4633
+ */
4634
+ getSearchableFields(collectionSlug: string): Promise<string[]>;
4635
+ /**
4636
+ * Enable search for a collection
4637
+ *
4638
+ * Creates the FTS table and triggers, and populates from existing content.
4639
+ */
4640
+ enableSearch(collectionSlug: string, options?: {
4641
+ weights?: Record<string, number>;
4642
+ }): Promise<void>;
4643
+ /**
4644
+ * Disable search for a collection
4645
+ *
4646
+ * Drops the FTS table and triggers.
4647
+ */
4648
+ disableSearch(collectionSlug: string): Promise<void>;
4649
+ /**
4650
+ * Get index statistics for a collection
4651
+ */
4652
+ getIndexStats(collectionSlug: string): Promise<{
4653
+ indexed: number;
4654
+ lastRebuilt?: string;
4655
+ } | null>;
4656
+ /**
4657
+ * Verify FTS index integrity and rebuild if corrupted.
4658
+ *
4659
+ * Checks for row count mismatch between content table and FTS table.
4660
+ *
4661
+ * Returns true if the index was rebuilt, false if it was healthy.
4662
+ */
4663
+ verifyAndRepairIndex(collectionSlug: string): Promise<boolean>;
4664
+ /**
4665
+ * Verify and repair FTS indexes for all search-enabled collections.
4666
+ *
4667
+ * Intended to run at startup to auto-heal any corruption from
4668
+ * previous process crashes.
4669
+ */
4670
+ verifyAndRepairAll(): Promise<number>;
4671
+ }
4672
+ //#endregion
4673
+ //#region src/search/query.d.ts
4674
+ /**
4675
+ * Search across multiple collections
4676
+ *
4677
+ * Public API that auto-injects the database.
4678
+ *
4679
+ * @param query - Search query (FTS5 syntax supported)
4680
+ * @param options - Search options
4681
+ * @returns Search results with pagination
4682
+ *
4683
+ * @example
4684
+ * ```typescript
4685
+ * import { search } from "dineway";
4686
+ *
4687
+ * const results = await search("hello world", {
4688
+ * collections: ["posts", "pages"],
4689
+ * limit: 20
4690
+ * });
4691
+ * ```
4692
+ */
4693
+ declare function search(query: string, options?: SearchOptions): Promise<SearchResponse>;
4694
+ /**
4695
+ * Search across multiple collections (with explicit db)
4696
+ *
4697
+ * @internal Use `search()` in templates. This variant is for admin routes
4698
+ * that already have a database handle.
4699
+ *
4700
+ * @param db - Kysely database instance
4701
+ * @param query - Search query (FTS5 syntax supported)
4702
+ * @param options - Search options
4703
+ * @returns Search results with pagination
4704
+ */
4705
+ declare function searchWithDb(db: Kysely<Database>, query: string, options?: SearchOptions): Promise<SearchResponse>;
4706
+ /**
4707
+ * Search within a single collection
4708
+ *
4709
+ * @param db - Kysely database instance
4710
+ * @param collection - Collection slug
4711
+ * @param query - Search query (FTS5 syntax supported)
4712
+ * @param options - Search options
4713
+ * @returns Search results with pagination
4714
+ *
4715
+ * @example
4716
+ * ```typescript
4717
+ * const results = await searchCollection(db, "posts", "hello world", {
4718
+ * limit: 10
4719
+ * });
4720
+ * ```
4721
+ */
4722
+ declare function searchCollection(db: Kysely<Database>, collection: string, query: string, options?: CollectionSearchOptions): Promise<SearchResponse>;
4723
+ /**
4724
+ * Get search suggestions for autocomplete
4725
+ *
4726
+ * @param db - Kysely database instance
4727
+ * @param query - Partial search query
4728
+ * @param options - Suggestion options
4729
+ * @returns Array of suggestions
4730
+ */
4731
+ declare function getSuggestions(db: Kysely<Database>, query: string, options?: SuggestOptions): Promise<Suggestion[]>;
4732
+ /**
4733
+ * Get search statistics for all collections
4734
+ */
4735
+ declare function getSearchStats(db: Kysely<Database>): Promise<SearchStats>;
4736
+ //#endregion
4737
+ //#region src/search/text-extraction.d.ts
4738
+ /**
4739
+ * Extract plain text from Portable Text blocks
4740
+ *
4741
+ * Uses @portabletext/toolkit's toPlainText for standard blocks,
4742
+ * plus extracts text from custom block types (code, images with alt/caption).
4743
+ *
4744
+ * @param blocks - Array of Portable Text blocks (or a JSON string)
4745
+ * @returns Plain text content
4746
+ *
4747
+ * @example
4748
+ * ```typescript
4749
+ * const text = extractPlainText([
4750
+ * {
4751
+ * _type: "block",
4752
+ * _key: "abc",
4753
+ * children: [{ _type: "span", _key: "s1", text: "Hello World" }]
4754
+ * }
4755
+ * ]);
4756
+ * // Returns: "Hello World"
4757
+ * ```
4758
+ */
4759
+ declare function extractPlainText(blocks: PortableTextBlock$1[] | string | null | undefined): string;
4760
+ /**
4761
+ * Extract searchable text from a content entry
4762
+ *
4763
+ * Extracts text from specified fields, handling both plain text and Portable Text.
4764
+ *
4765
+ * @param entry - Content entry data
4766
+ * @param fields - Field names to extract text from
4767
+ * @returns Object mapping field names to extracted text
4768
+ */
4769
+ declare function extractSearchableFields(entry: Record<string, unknown>, fields: string[]): Record<string, string>;
4770
+ //#endregion
4771
+ export { GetCommentsOptions as $, ManifestResponse as $i, SessionDatabaseFactory as $n, SandboxEmailMessage as $r, OAuthInput as $t, getEntryTerms as A, handleContentCountScheduled as Ai, AuthProviderModule as An, getTranslations as Ar, wordpressRestSource as At, UpdateTermInput as B, handleContentPermanentDelete as Bi, WxrTag as Bn, hashString as Br, importReusableBlocksAsSections as Bt, ReorderWidgetsInput as C, RevisionListResponse as Ci, DinewayConfig as Cn, InferCollectionData as Cr, GeneratePreviewTokenOptions as Ct, WidgetComponentDef as D, handleRevisionRestore as Di, S3StorageConfig as Dn, getDinewayCollection as Dr, generatePreviewToken as Dt, WidgetArea as E, handleRevisionList as Ei, LocalStorageConfig as En, TranslationsResult as Er, VerifyPreviewTokenResult as Et, getTermsForEntries as F, handleContentDuplicate as Fi, WxrAuthor as Fn, createEditable as Fr, getFileSources as Ft, CreateMenuInput as G, handleContentUnpublish as Gi, EntryFilter as Gn, PortableTextLinkMark as Gr, FileInput as Gt, getBylineBySlug as H, handleContentRestore as Hi, parseWxrString as Hn, prosemirrorToPortableText as Hr, CollectionSchemaStatus as Ht, CreateTermInput as I, handleContentGet as Ii, WxrCategory as In, createNoop as Ir, getSource as It, MenuItem as J, ApiContext as Ji, FilePreviewMiddlewareConfig as Jn, PortableTextTextBlock as Jr, ImportContext as Jt, CreateMenuItemInput as K, handleContentUnschedule as Ki, dinewayLoader as Kn, PortableTextMarkDef as Kr, ImportAnalysis as Kt, TaxonomyDef as L, handleContentGetIncludingTrashed as Li, WxrData as Ln, isSafeHref as Lr, getUrlSources as Lt, getTaxonomyDefs as M, handleContentCreate as Mi, ExternalAuthConfig as Mn, CMSAnnotation as Mr, wxrSource as Mt, getTaxonomyTerms as N, handleContentDelete as Ni, definePlugin as Nn, EditProxy as Nr, clearSources as Nt, WidgetType as O, generateManifest as Oi, StorageDescriptor as On, getDinewayEntry as Or, parseContentId as Ot, getTerm as P, handleContentDiscardDraft as Pi, WxrAttachment as Pn, FieldAnnotation as Pr, getAllSources as Pt, UpdateMenuItemInput as Q, ListResponse as Qi, SessionCleanupResult as Qn, ProseMirrorNode as Qr, NormalizedItem as Qt, TaxonomyTerm as R, handleContentList as Ri, WxrPost as Rn, sanitizeHref as Rr, probeUrl as Rt, PropDef as S, handleMediaUpdate as Si, pluginManifestSchema as Sn, EntryResult as Sr, getPreviewUrl as St, Widget as T, handleRevisionGet as Ti, getStoredConfig as Tn, TranslationSummary as Tr, VerifyPreviewTokenOptions as Tt, getMenu as U, handleContentSchedule as Ui, CollectionFilter as Un, PortableTextCodeBlock as Ur, FetchOptions as Ut, getByline as V, handleContentPublish as Vi, parseWxr as Vn, portableTextToProsemirror as Vr, AttachmentInfo as Vt, getMenus as W, handleContentTranslations as Wi, EntryData as Wn, PortableTextImageBlock as Wr, FieldCompatibility as Wt, ReorderMenuItemsInput as X, ContentResponse as Xi, FileSessionDatabaseFactory as Xn, ProseMirrorDocument as Xr, ImportResult as Xt, MenuItemType as Y, ContentListResponse as Yi, createFilePreviewMiddleware as Yn, PortableTextUnknownBlock as Yr, ImportFieldDef as Yt, UpdateMenuInput as Z, FieldDescriptor as Zi, FileSessionDatabaseFactoryOptions as Zn, ProseMirrorMark as Zr, ImportSource as Zt, getWidgetArea as _, MediaResponse as _i, EmailPipeline as _n, CollectionFilter$1 as _r, isBlockedInPreview as _t, search as a, FileValue as aa, SerializedRequest as ai, SourceInput as an, PreviewSidecarClient as ar, getSiteSetting as at, CreateWidgetAreaInput as b, handleMediaGet as bi, createHookPipeline as bn, DinewayCollections as br, GetPreviewUrlOptions as bt, FTSManager as c, CreateMediaInput as ca, CreateSectionInput as ci, UrlInput as cn, defaultPreviewSidecarClient as cr, PreviewToolbarConfig as ct, SearchOptions as d, ContentRepository as da, SectionSource as di, NoopSandboxRunner as dn, verifyPreviewSignature as dr, ApplySnapshotToDatabaseOptions as dt, portableText as ea, SandboxEmailSendCallback as ei, PostTypeAnalysis as en, SessionDatabaseHandle as er, GetCommentsResult as et, SearchResponse as f, DatabaseConfig as fa, UpdateSectionInput as fi, SandboxNotAvailableError as fn, I18nConfig as fr, applySnapshotToDatabase as ft, Suggestion as g, MediaListResponse as gi, PluginRouteError as gn, CacheHint as gr, renderPreviewLoadingPage as gt, SuggestOptions as h, SchemaRegistry as hi, createPluginManager as hn, isI18nEnabled as hr, Snapshot as ht, getSuggestions as i, FieldUIHints as ia, SandboxedPlugin as ii, SourceCapabilities as in, SessionOpenOrCreateOptions as ir, getPluginSettings as it, getTaxonomyDef as j, handleContentCountTrashed as ji, AuthResult as jn, resolveDinewayPath as jr, parseWxrDate as jt, getEntriesByTerm as k, handleContentCompare as ki, AuthDescriptor as kn, getEditMeta as kr, verifyPreviewToken as kt, CollectionSearchOptions as l, MediaItem as la, GetSectionsOptions as li, NodeSandboxRunner as ln, parsePreviewSignatureHeader as lr, renderPreviewToolbar as lt, SearchStats as m, SchemaError as mi, PluginManager as mn, getI18nConfig as mr, getAppliedSnapshotMeta as mt, extractSearchableFields as n, image as na, SandboxRunner as ni, ProbeResult as nn, SessionDatabaseLimitError as nr, getComments as nt, searchCollection as o, ImageValue as oa, getSection as oi, SourceProbeResult as on, PreviewSidecarSignature as or, getSiteSettings as ot, SearchResult as p, DinewayDatabaseError as pa, getCollectionInfo as pi, createNoopSandboxRunner as pn, getFallbackChain as pr, dropSessionDatabaseTables as pt, Menu as q, handleContentUpdate as qi, getDb as qn, PortableTextSpan as qr, ImportConfig as qt, getSearchStats as r, FieldDefinition as ra, SandboxRunnerFactory as ri, SourceAuth as rn, SessionOpenOptions as rr, getPluginSetting as rt, searchWithDb as s, PortableTextBlock$2 as sa, getSections as si, SuggestedAction as sn, buildPreviewSignatureHeader as sr, setSiteSettings as st, extractPlainText as t, reference as ta, SandboxOptions as ti, PostTypeMapping as tn, SessionDatabaseInfo as tr, getCommentCount as tt, SearchConfig as u, MediaRepository as ua, Section as ui, createNodeSandboxRunner as un, signPreviewUrl as ur, AppliedSnapshotMeta as ut, getWidgetAreas as v, handleMediaCreate as vi, HookPipeline as vn, CollectionResult as vr, getPreviewToken as vt, UpdateWidgetInput as w, RevisionResponse as wi, PluginDescriptor as wn, ResolvePathResult as wr, PreviewTokenPayload as wt, CreateWidgetInput as x, handleMediaList as xi, ValidatedPluginManifest as xn, EditFieldMeta as xr, buildPreviewUrl as xt, getWidgetComponents as y, handleMediaDelete as yi, HookResult as yn, ContentEntry as yr, isPreviewRequest as yt, TaxonomyTermRow as z, handleContentListTrashed as zi, WxrSite as zn, computeContentHash as zr, registerSource as zt };