@sonicjs-cms/core 3.0.0-beta.15 → 3.0.0-beta.17

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 (55) hide show
  1. package/dist/{chunk-PTTFLUEX.cjs → chunk-3RNDJAZ5.cjs} +4 -4
  2. package/dist/{chunk-PTTFLUEX.cjs.map → chunk-3RNDJAZ5.cjs.map} +1 -1
  3. package/dist/{chunk-VOAP3KFU.js → chunk-73KSHGOT.js} +2 -2
  4. package/dist/{chunk-VOAP3KFU.js.map → chunk-73KSHGOT.js.map} +1 -1
  5. package/dist/{chunk-4AB3PQHF.cjs → chunk-7YMMCIWY.cjs} +2 -2
  6. package/dist/{chunk-4AB3PQHF.cjs.map → chunk-7YMMCIWY.cjs.map} +1 -1
  7. package/dist/{chunk-FXZSZ7C7.cjs → chunk-C3KSTUEA.cjs} +2 -2
  8. package/dist/{chunk-FXZSZ7C7.cjs.map → chunk-C3KSTUEA.cjs.map} +1 -1
  9. package/dist/{chunk-L3VIH6U4.js → chunk-CYDEM6SY.js} +98 -33
  10. package/dist/chunk-CYDEM6SY.js.map +1 -0
  11. package/dist/{chunk-PK3ODTAL.cjs → chunk-KDRHGEUF.cjs} +3 -3
  12. package/dist/{chunk-PK3ODTAL.cjs.map → chunk-KDRHGEUF.cjs.map} +1 -1
  13. package/dist/{chunk-75WXXLAU.js → chunk-KXTGLSFY.js} +6 -5
  14. package/dist/chunk-KXTGLSFY.js.map +1 -0
  15. package/dist/{chunk-FVI3H6RG.cjs → chunk-MJZI3NHR.cjs} +12 -11
  16. package/dist/chunk-MJZI3NHR.cjs.map +1 -0
  17. package/dist/{chunk-BDQOPRA3.cjs → chunk-NOBU34HS.cjs} +291 -226
  18. package/dist/chunk-NOBU34HS.cjs.map +1 -0
  19. package/dist/{chunk-GQXVDFIG.js → chunk-OSMPF3PU.js} +5 -5
  20. package/dist/{chunk-GQXVDFIG.js.map → chunk-OSMPF3PU.js.map} +1 -1
  21. package/dist/{chunk-CE6POA7A.js → chunk-RIFCRZYC.js} +3 -3
  22. package/dist/{chunk-CE6POA7A.js.map → chunk-RIFCRZYC.js.map} +1 -1
  23. package/dist/{chunk-JRLADH5B.js → chunk-Y34TG4TF.js} +3 -3
  24. package/dist/{chunk-JRLADH5B.js.map → chunk-Y34TG4TF.js.map} +1 -1
  25. package/dist/{chunk-4ENXIP4M.js → chunk-YA4V4Y5U.js} +2 -2
  26. package/dist/{chunk-4ENXIP4M.js.map → chunk-YA4V4Y5U.js.map} +1 -1
  27. package/dist/{chunk-ZBDDZYA3.cjs → chunk-ZHQP75SR.cjs} +15 -15
  28. package/dist/{chunk-ZBDDZYA3.cjs.map → chunk-ZHQP75SR.cjs.map} +1 -1
  29. package/dist/index.cjs +277 -257
  30. package/dist/index.cjs.map +1 -1
  31. package/dist/index.d.cts +178 -2
  32. package/dist/index.d.ts +178 -2
  33. package/dist/index.js +28 -16
  34. package/dist/index.js.map +1 -1
  35. package/dist/middleware.cjs +33 -33
  36. package/dist/middleware.js +4 -4
  37. package/dist/migrations-7G6QBDSM.js +4 -0
  38. package/dist/{migrations-6R2N6G2P.js.map → migrations-7G6QBDSM.js.map} +1 -1
  39. package/dist/migrations-QIRBSVJJ.cjs +13 -0
  40. package/dist/{migrations-X3UX24QG.cjs.map → migrations-QIRBSVJJ.cjs.map} +1 -1
  41. package/dist/plugins.cjs +40 -40
  42. package/dist/plugins.js +3 -3
  43. package/dist/routes.cjs +26 -26
  44. package/dist/routes.js +6 -6
  45. package/dist/services.cjs +18 -18
  46. package/dist/services.js +2 -2
  47. package/dist/utils.cjs +3 -3
  48. package/dist/utils.js +1 -1
  49. package/package.json +1 -1
  50. package/dist/chunk-75WXXLAU.js.map +0 -1
  51. package/dist/chunk-BDQOPRA3.cjs.map +0 -1
  52. package/dist/chunk-FVI3H6RG.cjs.map +0 -1
  53. package/dist/chunk-L3VIH6U4.js.map +0 -1
  54. package/dist/migrations-6R2N6G2P.js +0 -4
  55. package/dist/migrations-X3UX24QG.cjs +0 -13
package/dist/index.d.cts CHANGED
@@ -2,6 +2,7 @@ export { B as Bindings, a as BootIsolateFn, b as SonicJSApp, S as SonicJSConfig,
2
2
  import { o as DefinedPlugin } from './define-plugin-DsKiGu1q.cjs';
3
3
  export { B as BooleanField, e as ConfigSchema, f as ConfigSchemaField, h as CronContext, i as CronDeclaration, j as CronDispatchResult, k as CronTickEvent, l as CronablePlugin, H as HookSystemImpl, r as HookUtils, N as NumberField, P as ParsedField, v as PluginManagerClass, an as PluginMenuEntry, x as PluginRegistryImpl, y as PluginValidatorClass, z as PluginsRegistry, A as RegisterPluginsError, G as RegisterPluginsErrorReason, I as RegisterPluginsHostContext, J as RegisterablePlugin, K as RegistryEntry, ao as ResolvedPluginMenuEntry, L as ScopedHookSystemClass, O as SelectField, Q as SettingsFor, U as StringField, Y as applySchemaDefaults, _ as collectCronSchedules, $ as collectCrons, a2 as createScheduledHandler, a3 as definePlugin, a4 as dispatchCronTick, a5 as getHookSystem, ap as getPluginMenu, a6 as getTypedHooks, a8 as hasHookSystem, a9 as isDefinedPlugin, ae as parseConfigSchema, af as parseFormDataToSettings, ah as registerPlugins, ai as renderSchemaFields, aj as resetHookSystem, aq as resetPluginMenu, ar as resolvePluginMenuItems, ak as setHookSystem, as as setPluginMenu } from './define-plugin-DsKiGu1q.cjs';
4
4
  import { D1Database as D1Database$1 } from '@cloudflare/workers-types';
5
+ import { z } from 'zod';
5
6
  import { E as EmailProvider, N as NormalizedEmailMessage, t as SendResult } from './types-DT7XN5TX.cjs';
6
7
  export { q as EmailLogRow } from './types-DT7XN5TX.cjs';
7
8
  import { s as schema } from './plugin-bootstrap-BHWQ2df8.cjs';
@@ -21,7 +22,6 @@ import 'better-auth';
21
22
  import 'better-auth/plugins/magic-link';
22
23
  import 'better-call';
23
24
  import 'zod/v4/core';
24
- import 'zod';
25
25
  import 'hono';
26
26
  import 'drizzle-zod';
27
27
  import 'drizzle-orm/sqlite-core';
@@ -213,6 +213,182 @@ declare class RbacService {
213
213
 
214
214
  declare function bootstrapDocumentTypes(db: D1Database$1): Promise<void>;
215
215
 
216
+ type Permission = 'read' | 'create' | 'update' | 'delete' | 'publish' | 'manage';
217
+ type PrincipalType = 'user' | 'role' | 'group' | 'public' | 'token';
218
+ type RefStrength = 'strong' | 'weak';
219
+ type QueryableFieldKind = 'scalar' | 'facet' | 'reference';
220
+ type DocumentStatus = 'draft' | 'published' | 'archived';
221
+ interface QueryableField {
222
+ name: string;
223
+ path?: string;
224
+ kind: QueryableFieldKind;
225
+ type?: 'text' | 'number' | 'integer' | 'boolean' | 'date';
226
+ column?: string;
227
+ refStrength?: RefStrength;
228
+ }
229
+ interface DocumentTypeSettings {
230
+ baseGrants?: Record<string, Permission[]>;
231
+ maxVersionsPerRoot?: number;
232
+ pii?: boolean;
233
+ /** Hide this type from the admin content list and all-view (e.g. internal system types like 'plugin'). */
234
+ internal?: boolean;
235
+ /**
236
+ * Shared/global type: its documents are NOT tenant-scoped — they live in one shared pool and are
237
+ * visible from every tenant. Opt-in (default false). When false, the type is tenant-isolated like
238
+ * everything else. See `effectiveTenantForType` (services/document-request-context.ts).
239
+ */
240
+ global?: boolean;
241
+ /**
242
+ * Retain historical version rows for this type. Default false.
243
+ * When false: saveDraft updates the working draft row in place and publish deletes the
244
+ * superseded published row (at most ~2 rows per root, no history accumulation).
245
+ * When true: new row per saveDraft + prune to maxVersionsPerRoot (the versioning-plugin opts types in).
246
+ */
247
+ versioning?: boolean;
248
+ }
249
+ interface Document {
250
+ id: string;
251
+ rootId: string;
252
+ typeId: string;
253
+ typeVersion: number;
254
+ versionOfId: string | null;
255
+ versionNumber: number;
256
+ isCurrentDraft: boolean;
257
+ isPublished: boolean;
258
+ status: DocumentStatus;
259
+ parentRootId: string;
260
+ slug: string | null;
261
+ path: string | null;
262
+ title: string | null;
263
+ zone: string | null;
264
+ sortOrder: number;
265
+ visible: boolean;
266
+ publishedAt: number | null;
267
+ scheduledAt: number | null;
268
+ expiresAt: number | null;
269
+ deletedAt: number | null;
270
+ tenantId: string;
271
+ locale: string;
272
+ translationGroupId: string;
273
+ data: Record<string, unknown>;
274
+ metadata: Record<string, unknown>;
275
+ ownerId: string | null;
276
+ createdBy: string | null;
277
+ updatedBy: string | null;
278
+ createdAt: number;
279
+ updatedAt: number;
280
+ }
281
+ interface PrincipalRef {
282
+ type: PrincipalType;
283
+ id: string;
284
+ }
285
+ declare const createDocumentSchema: z.ZodObject<{
286
+ typeId: z.ZodString;
287
+ tenantId: z.ZodDefault<z.ZodString>;
288
+ locale: z.ZodDefault<z.ZodString>;
289
+ parentRootId: z.ZodDefault<z.ZodString>;
290
+ slug: z.ZodOptional<z.ZodNullable<z.ZodString>>;
291
+ title: z.ZodOptional<z.ZodNullable<z.ZodString>>;
292
+ zone: z.ZodOptional<z.ZodNullable<z.ZodString>>;
293
+ sortOrder: z.ZodDefault<z.ZodNumber>;
294
+ visible: z.ZodDefault<z.ZodBoolean>;
295
+ scheduledAt: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
296
+ expiresAt: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
297
+ data: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
298
+ metadata: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
299
+ ownerId: z.ZodOptional<z.ZodNullable<z.ZodString>>;
300
+ publishOnCreate: z.ZodDefault<z.ZodBoolean>;
301
+ createdAt: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
302
+ updatedAt: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
303
+ }, z.core.$strip>;
304
+ declare const updateDocumentSchema: z.ZodObject<{
305
+ title: z.ZodOptional<z.ZodNullable<z.ZodString>>;
306
+ slug: z.ZodOptional<z.ZodNullable<z.ZodString>>;
307
+ zone: z.ZodOptional<z.ZodNullable<z.ZodString>>;
308
+ sortOrder: z.ZodOptional<z.ZodNumber>;
309
+ visible: z.ZodOptional<z.ZodBoolean>;
310
+ scheduledAt: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
311
+ expiresAt: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
312
+ data: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
313
+ metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
314
+ updatedBy: z.ZodOptional<z.ZodNullable<z.ZodString>>;
315
+ }, z.core.$strip>;
316
+ type CreateDocumentInput = z.infer<typeof createDocumentSchema>;
317
+ type UpdateDocumentInput = z.infer<typeof updateDocumentSchema>;
318
+
319
+ type ListStatus = 'published' | 'draft' | 'all';
320
+ interface ListDocumentsOptions {
321
+ typeId?: string;
322
+ /** Which lifecycle axis to list: published row, current-draft row, or either. */
323
+ status?: ListStatus;
324
+ locale?: string;
325
+ parentRootId?: string;
326
+ limit?: number;
327
+ cursorUpdatedAt?: number;
328
+ cursorId?: string;
329
+ now?: number;
330
+ /** Resolved generated-column filters, e.g. { column: 'q_tst_rating', value: 4 }. Caller maps
331
+ * field→column via the type's queryableFields; column names are format-guarded here too. */
332
+ scalarFilters?: Array<{
333
+ column: string;
334
+ value: string | number;
335
+ }>;
336
+ /** Multi-valued facet filter, e.g. { field: 'tags', value: 'homepage' }. Bound as params. */
337
+ facetFilter?: {
338
+ field: string;
339
+ value: string;
340
+ };
341
+ /** Generated-column to sort by (else keyset on updated_at). Format-guarded. */
342
+ sortColumn?: string | null;
343
+ sortDir?: 'ASC' | 'DESC';
344
+ /** Apply the schedule window (scheduled_at/expires_at) — public reads only. */
345
+ timeWindow?: boolean;
346
+ }
347
+ declare class DocumentRepository {
348
+ private db;
349
+ private tenantId;
350
+ private permissions;
351
+ constructor(db: D1Database$1, tenantId: string);
352
+ getById(id: string): Promise<Document | null>;
353
+ getCurrentDraft(rootId: string): Promise<Document | null>;
354
+ getPublished(rootId: string): Promise<Document | null>;
355
+ list(opts?: ListDocumentsOptions): Promise<Document[]>;
356
+ listPublished(opts?: ListDocumentsOptions): Promise<Document[]>;
357
+ listDrafts(opts?: ListDocumentsOptions): Promise<Document[]>;
358
+ getVersionHistory(rootId: string): Promise<Document[]>;
359
+ getInboundReferences(toRootId: string): Promise<Array<{
360
+ fromDocumentId: string;
361
+ fieldName: string;
362
+ refStrength: string;
363
+ }>>;
364
+ isAllowed(principalSet: PrincipalRef[], rootId: string, permission: Permission, typeSettings: DocumentTypeSettings): Promise<boolean>;
365
+ }
366
+
367
+ interface DocumentsServiceOptions {
368
+ queryableFields?: QueryableField[];
369
+ typeSchemaVersion?: number;
370
+ maxVersionsPerRoot?: number;
371
+ /** Tenant this service operates within. Every root-keyed lookup is scoped to it (R3). POC default: 'default'. */
372
+ tenantId?: string;
373
+ /** Retain version history (new row per saveDraft, supersede-as-history). Default false (in-place). */
374
+ versioning?: boolean;
375
+ }
376
+ declare class DocumentsService {
377
+ private db;
378
+ private opts;
379
+ private projection;
380
+ private tenantId;
381
+ private versioning;
382
+ constructor(db: D1Database$1, opts?: DocumentsServiceOptions);
383
+ create(input: CreateDocumentInput, createdBy?: string): Promise<Document>;
384
+ saveDraft(rootId: string, input: UpdateDocumentInput, updatedBy?: string): Promise<Document>;
385
+ private updateInPlace;
386
+ publish(documentId: string, publishedBy?: string): Promise<Document>;
387
+ unpublish(documentId: string): Promise<Document>;
388
+ softDelete(documentId: string): Promise<void>;
389
+ erase(rootId: string, tenantId: string): Promise<void>;
390
+ }
391
+
216
392
  /**
217
393
  * Cloudflare Email binding provider (MailChannels / send_email binding)
218
394
  *
@@ -553,4 +729,4 @@ declare function createUserProfilesPlugin(): DefinedPlugin;
553
729
 
554
730
  declare const VERSION: string;
555
731
 
556
- export { BUILT_IN_PROVIDERS, type CFSendEmailBinding, CloudflareEmailProvider, type CloudflareEmailProviderOptions, FieldType, OAuthService, PluginDependencyCycleError, type ProfileFieldDefinition, RbacService, type SortablePlugin, type TopoSortOptions, type UserProfileConfig, VERSION, bootstrapDocumentTypes, createDb, createHelloWorldPlugin, createOAuthProvidersPlugin, createRedirectPlugin, createUserProfilesPlugin, defineUserProfile, emailReconciliationPlugin, generateTriggersComment, getUserProfileConfig, helloWorldPlugin, oauthProvidersPlugin, parseCronTriggers, redirectPlugin, _default as siteSettingsCollection, topoSort, updateWranglerTriggers, userProfilesPlugin };
732
+ export { BUILT_IN_PROVIDERS, type CFSendEmailBinding, CloudflareEmailProvider, type CloudflareEmailProviderOptions, DocumentRepository, DocumentsService, FieldType, OAuthService, PluginDependencyCycleError, type ProfileFieldDefinition, RbacService, type SortablePlugin, type TopoSortOptions, type UserProfileConfig, VERSION, bootstrapDocumentTypes, createDb, createHelloWorldPlugin, createOAuthProvidersPlugin, createRedirectPlugin, createUserProfilesPlugin, defineUserProfile, emailReconciliationPlugin, generateTriggersComment, getUserProfileConfig, helloWorldPlugin, oauthProvidersPlugin, parseCronTriggers, redirectPlugin, _default as siteSettingsCollection, topoSort, updateWranglerTriggers, userProfilesPlugin };
package/dist/index.d.ts CHANGED
@@ -2,6 +2,7 @@ export { B as Bindings, a as BootIsolateFn, b as SonicJSApp, S as SonicJSConfig,
2
2
  import { o as DefinedPlugin } from './define-plugin-BYIey6sp.js';
3
3
  export { B as BooleanField, e as ConfigSchema, f as ConfigSchemaField, h as CronContext, i as CronDeclaration, j as CronDispatchResult, k as CronTickEvent, l as CronablePlugin, H as HookSystemImpl, r as HookUtils, N as NumberField, P as ParsedField, v as PluginManagerClass, an as PluginMenuEntry, x as PluginRegistryImpl, y as PluginValidatorClass, z as PluginsRegistry, A as RegisterPluginsError, G as RegisterPluginsErrorReason, I as RegisterPluginsHostContext, J as RegisterablePlugin, K as RegistryEntry, ao as ResolvedPluginMenuEntry, L as ScopedHookSystemClass, O as SelectField, Q as SettingsFor, U as StringField, Y as applySchemaDefaults, _ as collectCronSchedules, $ as collectCrons, a2 as createScheduledHandler, a3 as definePlugin, a4 as dispatchCronTick, a5 as getHookSystem, ap as getPluginMenu, a6 as getTypedHooks, a8 as hasHookSystem, a9 as isDefinedPlugin, ae as parseConfigSchema, af as parseFormDataToSettings, ah as registerPlugins, ai as renderSchemaFields, aj as resetHookSystem, aq as resetPluginMenu, ar as resolvePluginMenuItems, ak as setHookSystem, as as setPluginMenu } from './define-plugin-BYIey6sp.js';
4
4
  import { D1Database as D1Database$1 } from '@cloudflare/workers-types';
5
+ import { z } from 'zod';
5
6
  import { E as EmailProvider, N as NormalizedEmailMessage, t as SendResult } from './types-DT7XN5TX.js';
6
7
  export { q as EmailLogRow } from './types-DT7XN5TX.js';
7
8
  import { s as schema } from './plugin-bootstrap-Bj4fxX1q.js';
@@ -21,7 +22,6 @@ import 'better-auth';
21
22
  import 'better-auth/plugins/magic-link';
22
23
  import 'better-call';
23
24
  import 'zod/v4/core';
24
- import 'zod';
25
25
  import 'hono';
26
26
  import 'drizzle-zod';
27
27
  import 'drizzle-orm/sqlite-core';
@@ -213,6 +213,182 @@ declare class RbacService {
213
213
 
214
214
  declare function bootstrapDocumentTypes(db: D1Database$1): Promise<void>;
215
215
 
216
+ type Permission = 'read' | 'create' | 'update' | 'delete' | 'publish' | 'manage';
217
+ type PrincipalType = 'user' | 'role' | 'group' | 'public' | 'token';
218
+ type RefStrength = 'strong' | 'weak';
219
+ type QueryableFieldKind = 'scalar' | 'facet' | 'reference';
220
+ type DocumentStatus = 'draft' | 'published' | 'archived';
221
+ interface QueryableField {
222
+ name: string;
223
+ path?: string;
224
+ kind: QueryableFieldKind;
225
+ type?: 'text' | 'number' | 'integer' | 'boolean' | 'date';
226
+ column?: string;
227
+ refStrength?: RefStrength;
228
+ }
229
+ interface DocumentTypeSettings {
230
+ baseGrants?: Record<string, Permission[]>;
231
+ maxVersionsPerRoot?: number;
232
+ pii?: boolean;
233
+ /** Hide this type from the admin content list and all-view (e.g. internal system types like 'plugin'). */
234
+ internal?: boolean;
235
+ /**
236
+ * Shared/global type: its documents are NOT tenant-scoped — they live in one shared pool and are
237
+ * visible from every tenant. Opt-in (default false). When false, the type is tenant-isolated like
238
+ * everything else. See `effectiveTenantForType` (services/document-request-context.ts).
239
+ */
240
+ global?: boolean;
241
+ /**
242
+ * Retain historical version rows for this type. Default false.
243
+ * When false: saveDraft updates the working draft row in place and publish deletes the
244
+ * superseded published row (at most ~2 rows per root, no history accumulation).
245
+ * When true: new row per saveDraft + prune to maxVersionsPerRoot (the versioning-plugin opts types in).
246
+ */
247
+ versioning?: boolean;
248
+ }
249
+ interface Document {
250
+ id: string;
251
+ rootId: string;
252
+ typeId: string;
253
+ typeVersion: number;
254
+ versionOfId: string | null;
255
+ versionNumber: number;
256
+ isCurrentDraft: boolean;
257
+ isPublished: boolean;
258
+ status: DocumentStatus;
259
+ parentRootId: string;
260
+ slug: string | null;
261
+ path: string | null;
262
+ title: string | null;
263
+ zone: string | null;
264
+ sortOrder: number;
265
+ visible: boolean;
266
+ publishedAt: number | null;
267
+ scheduledAt: number | null;
268
+ expiresAt: number | null;
269
+ deletedAt: number | null;
270
+ tenantId: string;
271
+ locale: string;
272
+ translationGroupId: string;
273
+ data: Record<string, unknown>;
274
+ metadata: Record<string, unknown>;
275
+ ownerId: string | null;
276
+ createdBy: string | null;
277
+ updatedBy: string | null;
278
+ createdAt: number;
279
+ updatedAt: number;
280
+ }
281
+ interface PrincipalRef {
282
+ type: PrincipalType;
283
+ id: string;
284
+ }
285
+ declare const createDocumentSchema: z.ZodObject<{
286
+ typeId: z.ZodString;
287
+ tenantId: z.ZodDefault<z.ZodString>;
288
+ locale: z.ZodDefault<z.ZodString>;
289
+ parentRootId: z.ZodDefault<z.ZodString>;
290
+ slug: z.ZodOptional<z.ZodNullable<z.ZodString>>;
291
+ title: z.ZodOptional<z.ZodNullable<z.ZodString>>;
292
+ zone: z.ZodOptional<z.ZodNullable<z.ZodString>>;
293
+ sortOrder: z.ZodDefault<z.ZodNumber>;
294
+ visible: z.ZodDefault<z.ZodBoolean>;
295
+ scheduledAt: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
296
+ expiresAt: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
297
+ data: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
298
+ metadata: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
299
+ ownerId: z.ZodOptional<z.ZodNullable<z.ZodString>>;
300
+ publishOnCreate: z.ZodDefault<z.ZodBoolean>;
301
+ createdAt: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
302
+ updatedAt: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
303
+ }, z.core.$strip>;
304
+ declare const updateDocumentSchema: z.ZodObject<{
305
+ title: z.ZodOptional<z.ZodNullable<z.ZodString>>;
306
+ slug: z.ZodOptional<z.ZodNullable<z.ZodString>>;
307
+ zone: z.ZodOptional<z.ZodNullable<z.ZodString>>;
308
+ sortOrder: z.ZodOptional<z.ZodNumber>;
309
+ visible: z.ZodOptional<z.ZodBoolean>;
310
+ scheduledAt: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
311
+ expiresAt: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
312
+ data: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
313
+ metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
314
+ updatedBy: z.ZodOptional<z.ZodNullable<z.ZodString>>;
315
+ }, z.core.$strip>;
316
+ type CreateDocumentInput = z.infer<typeof createDocumentSchema>;
317
+ type UpdateDocumentInput = z.infer<typeof updateDocumentSchema>;
318
+
319
+ type ListStatus = 'published' | 'draft' | 'all';
320
+ interface ListDocumentsOptions {
321
+ typeId?: string;
322
+ /** Which lifecycle axis to list: published row, current-draft row, or either. */
323
+ status?: ListStatus;
324
+ locale?: string;
325
+ parentRootId?: string;
326
+ limit?: number;
327
+ cursorUpdatedAt?: number;
328
+ cursorId?: string;
329
+ now?: number;
330
+ /** Resolved generated-column filters, e.g. { column: 'q_tst_rating', value: 4 }. Caller maps
331
+ * field→column via the type's queryableFields; column names are format-guarded here too. */
332
+ scalarFilters?: Array<{
333
+ column: string;
334
+ value: string | number;
335
+ }>;
336
+ /** Multi-valued facet filter, e.g. { field: 'tags', value: 'homepage' }. Bound as params. */
337
+ facetFilter?: {
338
+ field: string;
339
+ value: string;
340
+ };
341
+ /** Generated-column to sort by (else keyset on updated_at). Format-guarded. */
342
+ sortColumn?: string | null;
343
+ sortDir?: 'ASC' | 'DESC';
344
+ /** Apply the schedule window (scheduled_at/expires_at) — public reads only. */
345
+ timeWindow?: boolean;
346
+ }
347
+ declare class DocumentRepository {
348
+ private db;
349
+ private tenantId;
350
+ private permissions;
351
+ constructor(db: D1Database$1, tenantId: string);
352
+ getById(id: string): Promise<Document | null>;
353
+ getCurrentDraft(rootId: string): Promise<Document | null>;
354
+ getPublished(rootId: string): Promise<Document | null>;
355
+ list(opts?: ListDocumentsOptions): Promise<Document[]>;
356
+ listPublished(opts?: ListDocumentsOptions): Promise<Document[]>;
357
+ listDrafts(opts?: ListDocumentsOptions): Promise<Document[]>;
358
+ getVersionHistory(rootId: string): Promise<Document[]>;
359
+ getInboundReferences(toRootId: string): Promise<Array<{
360
+ fromDocumentId: string;
361
+ fieldName: string;
362
+ refStrength: string;
363
+ }>>;
364
+ isAllowed(principalSet: PrincipalRef[], rootId: string, permission: Permission, typeSettings: DocumentTypeSettings): Promise<boolean>;
365
+ }
366
+
367
+ interface DocumentsServiceOptions {
368
+ queryableFields?: QueryableField[];
369
+ typeSchemaVersion?: number;
370
+ maxVersionsPerRoot?: number;
371
+ /** Tenant this service operates within. Every root-keyed lookup is scoped to it (R3). POC default: 'default'. */
372
+ tenantId?: string;
373
+ /** Retain version history (new row per saveDraft, supersede-as-history). Default false (in-place). */
374
+ versioning?: boolean;
375
+ }
376
+ declare class DocumentsService {
377
+ private db;
378
+ private opts;
379
+ private projection;
380
+ private tenantId;
381
+ private versioning;
382
+ constructor(db: D1Database$1, opts?: DocumentsServiceOptions);
383
+ create(input: CreateDocumentInput, createdBy?: string): Promise<Document>;
384
+ saveDraft(rootId: string, input: UpdateDocumentInput, updatedBy?: string): Promise<Document>;
385
+ private updateInPlace;
386
+ publish(documentId: string, publishedBy?: string): Promise<Document>;
387
+ unpublish(documentId: string): Promise<Document>;
388
+ softDelete(documentId: string): Promise<void>;
389
+ erase(rootId: string, tenantId: string): Promise<void>;
390
+ }
391
+
216
392
  /**
217
393
  * Cloudflare Email binding provider (MailChannels / send_email binding)
218
394
  *
@@ -553,4 +729,4 @@ declare function createUserProfilesPlugin(): DefinedPlugin;
553
729
 
554
730
  declare const VERSION: string;
555
731
 
556
- export { BUILT_IN_PROVIDERS, type CFSendEmailBinding, CloudflareEmailProvider, type CloudflareEmailProviderOptions, FieldType, OAuthService, PluginDependencyCycleError, type ProfileFieldDefinition, RbacService, type SortablePlugin, type TopoSortOptions, type UserProfileConfig, VERSION, bootstrapDocumentTypes, createDb, createHelloWorldPlugin, createOAuthProvidersPlugin, createRedirectPlugin, createUserProfilesPlugin, defineUserProfile, emailReconciliationPlugin, generateTriggersComment, getUserProfileConfig, helloWorldPlugin, oauthProvidersPlugin, parseCronTriggers, redirectPlugin, _default as siteSettingsCollection, topoSort, updateWranglerTriggers, userProfilesPlugin };
732
+ export { BUILT_IN_PROVIDERS, type CFSendEmailBinding, CloudflareEmailProvider, type CloudflareEmailProviderOptions, DocumentRepository, DocumentsService, FieldType, OAuthService, PluginDependencyCycleError, type ProfileFieldDefinition, RbacService, type SortablePlugin, type TopoSortOptions, type UserProfileConfig, VERSION, bootstrapDocumentTypes, createDb, createHelloWorldPlugin, createOAuthProvidersPlugin, createRedirectPlugin, createUserProfilesPlugin, defineUserProfile, emailReconciliationPlugin, generateTriggersComment, getUserProfileConfig, helloWorldPlugin, oauthProvidersPlugin, parseCronTriggers, redirectPlugin, _default as siteSettingsCollection, topoSort, updateWranglerTriggers, userProfilesPlugin };
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { createAuth } from './chunk-IQZA2OY5.js';
2
- import { getEmailService, hasEmailService, setEmailService, invalidateVariablesCache, resolveVariablesInObject, resolveDocScope, denyIfNotAllowed, DocumentRepository, dispatchHookEvent, getCustomData, createDocumentSchema, renderTable, getVariablesCached, setVariablesCache, TenantService, isValidMemberRole, renderConfirmationDialog, getConfirmationDialogScript, VALID_MEMBER_ROLES, userProfilesPlugin, lexicalEditorPlugin, api_media_default, api_system_default, apiDocumentsRoutes, api_default, adminDocumentsRoutes, admin_api_default, adminCollectionsRoutes, adminSettingsRoutes, router2, admin_content_default, adminMediaRoutes, router, adminPluginRoutes, adminLogsRoutes, userRoutes, auth_default, test_cleanup_default } from './chunk-L3VIH6U4.js';
3
- export { ROUTES_INFO, admin_api_default as adminApiRoutes, adminCheckboxRoutes, adminCollectionsRoutes, admin_content_default as adminContentRoutes, router as adminDashboardRoutes, adminLogsRoutes, adminMediaRoutes, adminPluginRoutes, adminSettingsRoutes, userRoutes as adminUsersRoutes, api_content_crud_default as apiContentCrudRoutes, api_media_default as apiMediaRoutes, api_default as apiRoutes, api_system_default as apiSystemRoutes, auth_default as authRoutes, createUserProfilesPlugin, defineUserProfile, getUserProfileConfig, userProfilesPlugin } from './chunk-L3VIH6U4.js';
2
+ import { getEmailService, hasEmailService, setEmailService, invalidateVariablesCache, resolveVariablesInObject, resolveDocScope, denyIfNotAllowed, DocumentRepository, dispatchHookEvent, getCustomData, createDocumentSchema, renderTable, getVariablesCached, setVariablesCache, TenantService, isValidMemberRole, renderConfirmationDialog, getConfirmationDialogScript, VALID_MEMBER_ROLES, userProfilesPlugin, lexicalEditorPlugin, api_media_default, api_system_default, apiDocumentsRoutes, api_default, adminDocumentsRoutes, admin_api_default, adminCollectionsRoutes, adminSettingsRoutes, router2, admin_content_default, adminMediaRoutes, router, adminPluginRoutes, adminLogsRoutes, userRoutes, auth_default, test_cleanup_default } from './chunk-CYDEM6SY.js';
3
+ export { DocumentRepository, ROUTES_INFO, admin_api_default as adminApiRoutes, adminCheckboxRoutes, adminCollectionsRoutes, admin_content_default as adminContentRoutes, router as adminDashboardRoutes, adminLogsRoutes, adminMediaRoutes, adminPluginRoutes, adminSettingsRoutes, userRoutes as adminUsersRoutes, api_content_crud_default as apiContentCrudRoutes, api_media_default as apiMediaRoutes, api_default as apiRoutes, api_system_default as apiSystemRoutes, auth_default as authRoutes, createUserProfilesPlugin, defineUserProfile, getUserProfileConfig, userProfilesPlugin } from './chunk-CYDEM6SY.js';
4
4
  import './chunk-VVYVFCML.js';
5
5
  import './chunk-RMRJGMDE.js';
6
6
  import { SettingsService, setAppInstance } from './chunk-RQ6N3FTV.js';
@@ -8,30 +8,30 @@ export { Logger, getLogger, initLogger } from './chunk-RQ6N3FTV.js';
8
8
  import { getAllCacheStats, CACHE_CONFIGS, getCacheService, clearAllCaches, parseCacheKey } from './chunk-K25XHMM3.js';
9
9
  import { schema_exports } from './chunk-AI663NBO.js';
10
10
  export { apiTokens, content, contentVersions, insertContentSchema, insertLogConfigSchema, insertMediaSchema, insertPluginActivityLogSchema, insertPluginAssetSchema, insertPluginHookSchema, insertPluginRouteSchema, insertPluginSchema, insertSystemLogSchema, insertUserSchema, insertWorkflowHistorySchema, logConfig, media, pluginActivityLog, pluginAssets, pluginHooks, pluginRoutes, plugins, selectContentSchema, selectLogConfigSchema, selectMediaSchema, selectPluginActivityLogSchema, selectPluginAssetSchema, selectPluginHookSchema, selectPluginRouteSchema, selectPluginSchema, selectSystemLogSchema, selectUserSchema, selectWorkflowHistorySchema, systemLogs, users, workflowHistory } from './chunk-AI663NBO.js';
11
- import { requireAuth, DocumentTypeRegistry, requireRbac, requireRole, getJwtExpirySecondsFromDb, AuthManager, metricsMiddleware, bootstrapMiddleware, securityHeadersMiddleware, csrfProtection } from './chunk-GQXVDFIG.js';
12
- export { AuthManager, PermissionManager, bootstrapDocumentTypes, bootstrapMiddleware, cacheHeaders, compressionMiddleware, detailedLoggingMiddleware, getActivePlugins, isPluginActive, logActivity, loggingMiddleware, optionalAuth, performanceLoggingMiddleware, requireActivePlugin, requireActivePlugins, requireAnyPermission, requireAuth, requirePermission, requireRole, securityHeadersMiddleware as securityHeaders, securityLoggingMiddleware } from './chunk-GQXVDFIG.js';
11
+ import { requireAuth, DocumentTypeRegistry, requireRbac, requireRole, getJwtExpirySecondsFromDb, AuthManager, metricsMiddleware, bootstrapMiddleware, securityHeadersMiddleware, csrfProtection } from './chunk-OSMPF3PU.js';
12
+ export { AuthManager, PermissionManager, bootstrapDocumentTypes, bootstrapMiddleware, cacheHeaders, compressionMiddleware, detailedLoggingMiddleware, getActivePlugins, isPluginActive, logActivity, loggingMiddleware, optionalAuth, performanceLoggingMiddleware, requireActivePlugin, requireActivePlugins, requireAnyPermission, requireAuth, requirePermission, requireRole, securityHeadersMiddleware as securityHeaders, securityLoggingMiddleware } from './chunk-OSMPF3PU.js';
13
13
  import { RbacService, DocumentsService } from './chunk-PDC7DLOV.js';
14
- export { RbacService } from './chunk-PDC7DLOV.js';
14
+ export { DocumentsService, RbacService } from './chunk-PDC7DLOV.js';
15
15
  import { nanoid } from './chunk-GCDZZNIN.js';
16
- import { PluginService, PLUGIN_REGISTRY, invalidateTenantCache, getCollectionRegistry, TENANT_COOKIE, MULTI_TENANT_PLUGIN_ID, collectionRecordToRow, tenantMiddleware } from './chunk-4ENXIP4M.js';
17
- export { PluginBootstrapService, PluginService as PluginServiceClass, getAvailableCollectionNames, loadCollectionConfig, loadCollectionConfigs, registerCollections, validateCollectionConfig } from './chunk-4ENXIP4M.js';
18
- export { MigrationService } from './chunk-VOAP3KFU.js';
16
+ import { PluginService, PLUGIN_REGISTRY, invalidateTenantCache, getCollectionRegistry, TENANT_COOKIE, MULTI_TENANT_PLUGIN_ID, collectionRecordToRow, tenantMiddleware } from './chunk-YA4V4Y5U.js';
17
+ export { PluginBootstrapService, PluginService as PluginServiceClass, getAvailableCollectionNames, loadCollectionConfig, loadCollectionConfigs, registerCollections, validateCollectionConfig } from './chunk-YA4V4Y5U.js';
18
+ export { MigrationService } from './chunk-73KSHGOT.js';
19
19
  export { renderFilterBar } from './chunk-JQISFW6U.js';
20
20
  import { renderAdminLayout } from './chunk-OBA2RYZN.js';
21
21
  export { getConfirmationDialogScript, renderAlert, renderConfirmationDialog, renderForm, renderFormField, renderPagination, renderTable } from './chunk-OBA2RYZN.js';
22
22
  import { init_admin_layout_catalyst_template, renderAdminLayoutCatalyst } from './chunk-5V62WT6M.js';
23
23
  export { renderAdminLayoutCatalyst } from './chunk-5V62WT6M.js';
24
- import { TurnstileService, HookSystemImpl, createPluginWirer, registerPluginRoutes, setPluginMenu } from './chunk-75WXXLAU.js';
25
- export { HookSystemImpl, HookUtils, PluginDependencyCycleError, PluginManager as PluginManagerClass, PluginRegistryImpl, PluginValidator as PluginValidatorClass, RegisterPluginsError, ScopedHookSystem as ScopedHookSystemClass, collectCronSchedules, collectCrons, createScheduledHandler, dispatchCronTick, getPluginMenu, registerPlugins, resetPluginMenu, resolvePluginMenuItems, setPluginMenu, topoSort } from './chunk-75WXXLAU.js';
26
- import { definePlugin, setPluginDefinitions } from './chunk-JRLADH5B.js';
27
- export { applySchemaDefaults, definePlugin, isDefinedPlugin, parseConfigSchema, parseFormDataToSettings, renderSchemaFields } from './chunk-JRLADH5B.js';
24
+ import { TurnstileService, HookSystemImpl, createPluginWirer, registerPluginRoutes, setPluginMenu, resolvePluginMenuItems } from './chunk-KXTGLSFY.js';
25
+ export { HookSystemImpl, HookUtils, PluginDependencyCycleError, PluginManager as PluginManagerClass, PluginRegistryImpl, PluginValidator as PluginValidatorClass, RegisterPluginsError, ScopedHookSystem as ScopedHookSystemClass, collectCronSchedules, collectCrons, createScheduledHandler, dispatchCronTick, getPluginMenu, registerPlugins, resetPluginMenu, resolvePluginMenuItems, setPluginMenu, topoSort } from './chunk-KXTGLSFY.js';
26
+ import { definePlugin, setPluginDefinitions } from './chunk-Y34TG4TF.js';
27
+ export { applySchemaDefaults, definePlugin, isDefinedPlugin, parseConfigSchema, parseFormDataToSettings, renderSchemaFields } from './chunk-Y34TG4TF.js';
28
28
  import { setHookSystem } from './chunk-RNZFGN4R.js';
29
29
  export { getHookSystem, getTypedHooks, hasHookSystem, resetHookSystem, setHookSystem } from './chunk-RNZFGN4R.js';
30
30
  export { QueryFilterBuilder, TemplateRenderer, buildQuery, renderTemplate, templateRenderer } from './chunk-QZGABF2M.js';
31
31
  export { metricsTracker } from './chunk-FICTAGD4.js';
32
32
  import './chunk-X7ZAEI5S.js';
33
- import { getCoreVersion, package_default } from './chunk-CE6POA7A.js';
34
- export { SONICJS_VERSION, getCoreVersion } from './chunk-CE6POA7A.js';
33
+ import { getCoreVersion, package_default } from './chunk-RIFCRZYC.js';
34
+ export { SONICJS_VERSION, getCoreVersion } from './chunk-RIFCRZYC.js';
35
35
  import { escapeHtml, sanitizeInput } from './chunk-TQABQWOP.js';
36
36
  export { escapeHtml, sanitizeInput, sanitizeObject } from './chunk-TQABQWOP.js';
37
37
  export { HOOKS } from './chunk-QXOZI5Q2.js';
@@ -11546,7 +11546,16 @@ function pluginMenuMiddleware() {
11546
11546
  }
11547
11547
  } catch {
11548
11548
  }
11549
- c.set("pluginMenuItems", activeMenuItems.map((m) => ({ label: m.label, path: m.path, icon: resolveIcon(m.icon) || "" })));
11549
+ const user = c.get("user");
11550
+ const singletonItems = resolvePluginMenuItems(user ? { role: user.role } : void 0);
11551
+ const existingPaths = new Set(activeMenuItems.map((i) => i.path));
11552
+ for (const item of singletonItems) {
11553
+ if (!existingPaths.has(item.path)) {
11554
+ activeMenuItems.push({ label: item.label, path: item.path, icon: item.icon, order: item.order });
11555
+ }
11556
+ }
11557
+ activeMenuItems.sort((a, b) => a.order - b.order);
11558
+ c.set("pluginMenuItems", activeMenuItems.map((m) => ({ label: m.label, path: m.path, icon: resolveIcon(m.icon) || m.icon || "" })));
11550
11559
  await next();
11551
11560
  const finalItems = c.get("pluginMenuItems") ?? [];
11552
11561
  if (finalItems.length > 0 && c.res.headers.get("content-type")?.includes("text/html")) {
@@ -16774,7 +16783,10 @@ function createSonicJSApp(config = {}) {
16774
16783
  ...corePluginsAfterCatchAll,
16775
16784
  ...config.plugins?.register ?? []
16776
16785
  ];
16777
- setPluginMenu(allMountedPlugins.flatMap((p) => p.menu ?? []));
16786
+ const userPlugins = (config.plugins?.register ?? []).filter(
16787
+ (p) => !PLUGIN_REGISTRY[p.id]
16788
+ );
16789
+ setPluginMenu(userPlugins.flatMap((p) => p.menu ?? []));
16778
16790
  setPluginDefinitions(allMountedPlugins);
16779
16791
  }
16780
16792
  app2.get("/favicon.svg", (c) => {