@sonicjs-cms/core 3.0.0-beta.23 → 3.0.0-beta.24

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 (57) hide show
  1. package/dist/{chunk-IS54FPB7.cjs → chunk-37V3RET3.cjs} +18 -34
  2. package/dist/chunk-37V3RET3.cjs.map +1 -0
  3. package/dist/{chunk-VGHEKIJL.cjs → chunk-A2SN3RVL.cjs} +2 -2
  4. package/dist/{chunk-VGHEKIJL.cjs.map → chunk-A2SN3RVL.cjs.map} +1 -1
  5. package/dist/{chunk-4WMZGHIC.cjs → chunk-BP52BFIV.cjs} +4 -4
  6. package/dist/{chunk-4WMZGHIC.cjs.map → chunk-BP52BFIV.cjs.map} +1 -1
  7. package/dist/{chunk-DIBCKCUE.js → chunk-FHPEM77Y.js} +8 -24
  8. package/dist/chunk-FHPEM77Y.js.map +1 -0
  9. package/dist/{chunk-CTYLCWMO.cjs → chunk-I767LVN7.cjs} +252 -217
  10. package/dist/chunk-I767LVN7.cjs.map +1 -0
  11. package/dist/{chunk-C3ZQP5NW.cjs → chunk-KKNEYIZJ.cjs} +3 -3
  12. package/dist/{chunk-C3ZQP5NW.cjs.map → chunk-KKNEYIZJ.cjs.map} +1 -1
  13. package/dist/{chunk-DPLJYTHE.js → chunk-LNI3FYSI.js} +3 -3
  14. package/dist/{chunk-DPLJYTHE.js.map → chunk-LNI3FYSI.js.map} +1 -1
  15. package/dist/{chunk-AT4ZQGEZ.cjs → chunk-QCJHCSOK.cjs} +21 -2
  16. package/dist/chunk-QCJHCSOK.cjs.map +1 -0
  17. package/dist/{chunk-RFBW5RRH.cjs → chunk-QJUJNTIU.cjs} +11 -11
  18. package/dist/{chunk-RFBW5RRH.cjs.map → chunk-QJUJNTIU.cjs.map} +1 -1
  19. package/dist/{chunk-KS24NPPL.js → chunk-RJ2O5IIE.js} +21 -2
  20. package/dist/chunk-RJ2O5IIE.js.map +1 -0
  21. package/dist/{chunk-A46IRC5A.js → chunk-UIHIXTIS.js} +2 -2
  22. package/dist/{chunk-A46IRC5A.js.map → chunk-UIHIXTIS.js.map} +1 -1
  23. package/dist/{chunk-SK5CHFJP.js → chunk-VC5XVPLM.js} +52 -20
  24. package/dist/chunk-VC5XVPLM.js.map +1 -0
  25. package/dist/{chunk-2MIYYAO4.js → chunk-VGEZNFWH.js} +3 -3
  26. package/dist/{chunk-2MIYYAO4.js.map → chunk-VGEZNFWH.js.map} +1 -1
  27. package/dist/{chunk-XXRR54AB.js → chunk-VYQVDL2M.js} +4 -4
  28. package/dist/{chunk-XXRR54AB.js.map → chunk-VYQVDL2M.js.map} +1 -1
  29. package/dist/index.cjs +1093 -264
  30. package/dist/index.cjs.map +1 -1
  31. package/dist/index.d.cts +28 -1
  32. package/dist/index.d.ts +28 -1
  33. package/dist/index.js +841 -14
  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-FGXZPKDC.cjs +13 -0
  38. package/dist/{migrations-ZD7Y5NUC.cjs.map → migrations-FGXZPKDC.cjs.map} +1 -1
  39. package/dist/migrations-Z6D27NAW.js +4 -0
  40. package/dist/{migrations-XQ6EX6HX.js.map → migrations-Z6D27NAW.js.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-AT4ZQGEZ.cjs.map +0 -1
  51. package/dist/chunk-CTYLCWMO.cjs.map +0 -1
  52. package/dist/chunk-DIBCKCUE.js.map +0 -1
  53. package/dist/chunk-IS54FPB7.cjs.map +0 -1
  54. package/dist/chunk-KS24NPPL.js.map +0 -1
  55. package/dist/chunk-SK5CHFJP.js.map +0 -1
  56. package/dist/migrations-XQ6EX6HX.js +0 -4
  57. package/dist/migrations-ZD7Y5NUC.cjs +0 -13
@@ -1,18 +1,18 @@
1
1
  import { isFirstUserRegistration, isRegistrationEnabled, authValidationService } from './chunk-VVYVFCML.js';
2
2
  import { renderDocumentFormPage, renderAlert } from './chunk-BHND5PEV.js';
3
3
  import { getCacheService, CACHE_CONFIGS, SettingsService, getLogger, getAppInstance, buildRouteList, CATEGORY_INFO } from './chunk-2XAQTPAE.js';
4
- import { DocumentTypeRegistry, requireAuth, requireRole, optionalAuth, isPluginActive, rateLimit, AuthManager, getJwtExpirySecondsFromDb, getJwtRefreshGraceSecondsFromDb, logActivity, generateCsrfToken } from './chunk-DIBCKCUE.js';
4
+ import { DocumentTypeRegistry, requireAuth, requireRole, optionalAuth, isPluginActive, rateLimit, AuthManager, getJwtExpirySecondsFromDb, getJwtRefreshGraceSecondsFromDb, logActivity, generateCsrfToken } from './chunk-FHPEM77Y.js';
5
5
  import { DocumentsService, documentSecondsToMs, RbacService } from './chunk-3TMTYJAJ.js';
6
6
  import { nanoid } from './chunk-UWUP2VMT.js';
7
- import { getCollectionRegistry, collectionRecordToRow, loadCollectionConfigs, getVisibleCollections, PluginService, PLUGIN_REGISTRY, findPluginByCodeName, isCodeCollectionInternal, isDbDocTypeInternal, invalidateTenantCache } from './chunk-KS24NPPL.js';
8
- import { MigrationService } from './chunk-A46IRC5A.js';
7
+ import { getCollectionRegistry, collectionRecordToRow, loadCollectionConfigs, getVisibleCollections, PluginService, PLUGIN_REGISTRY, findPluginByCodeName, isCodeCollectionInternal, isDbDocTypeInternal, invalidateTenantCache } from './chunk-RJ2O5IIE.js';
8
+ import { MigrationService } from './chunk-UIHIXTIS.js';
9
9
  import { renderCheckboxPage, renderAlert as renderAlert$1, renderTable, renderPagination, renderConfirmationDialog, getConfirmationDialogScript, renderAdminLayout, adminLayoutV2, renderForm } from './chunk-BJROXF4N.js';
10
10
  import { init_admin_layout_catalyst_template, renderAdminLayoutCatalyst } from './chunk-THFZSDIU.js';
11
- import { createServiceSingleton, definePlugin, getPluginDefinition, applySchemaDefaults, renderSchemaFields, parseFormDataToSettings, getPluginMenu } from './chunk-2MIYYAO4.js';
11
+ import { createServiceSingleton, definePlugin, getPluginDefinition, applySchemaDefaults, renderSchemaFields, parseFormDataToSettings, getPluginMenu } from './chunk-VGEZNFWH.js';
12
12
  import { hasHookSystem, getTypedHooks } from './chunk-RNZFGN4R.js';
13
13
  import { QueryFilterBuilder, getBlocksFieldConfig, parseBlocksValue } from './chunk-QZGABF2M.js';
14
14
  import { metricsTracker } from './chunk-FICTAGD4.js';
15
- import { getCoreVersion } from './chunk-DPLJYTHE.js';
15
+ import { getCoreVersion } from './chunk-LNI3FYSI.js';
16
16
  import { escapeHtml, sanitizeRichText, sanitizeInput } from './chunk-TQABQWOP.js';
17
17
  import { Hono } from 'hono';
18
18
  import { z } from 'zod';
@@ -149,6 +149,18 @@ var DocumentRepository = class {
149
149
  const row = await this.db.prepare("SELECT * FROM documents WHERE root_id = ? AND tenant_id = ? AND is_published = 1").bind(rootId, this.tenantId).first();
150
150
  return row ? rowToDocument(row) : null;
151
151
  }
152
+ // Slug lookup for a single doc. Prefer the published row; fall back to the current
153
+ // draft so a never-published doc is still reachable by slug (matches getById, which
154
+ // resolves drafts too). ORDER BY makes the preference deterministic when both exist.
155
+ async getBySlug(typeId, slug) {
156
+ const row = await this.db.prepare(
157
+ `SELECT * FROM documents
158
+ WHERE tenant_id = ? AND type_id = ? AND slug = ? AND deleted_at IS NULL
159
+ AND (is_published = 1 OR is_current_draft = 1)
160
+ ORDER BY is_published DESC LIMIT 1`
161
+ ).bind(this.tenantId, typeId, slug).first();
162
+ return row ? rowToDocument(row) : null;
163
+ }
152
164
  // Unified, tenant-scoped list with optional generated-column / facet filters and sort. This is the
153
165
  // single place document list SQL is built — route handlers must call this, never inline SQL (R4).
154
166
  async list(opts = {}) {
@@ -3399,7 +3411,7 @@ adminApiRoutes.patch("/collections/:id", collectionsReadOnly);
3399
3411
  adminApiRoutes.delete("/collections/:id", collectionsReadOnly);
3400
3412
  adminApiRoutes.get("/migrations/status", async (c) => {
3401
3413
  try {
3402
- const { MigrationService: MigrationService2 } = await import('./migrations-XQ6EX6HX.js');
3414
+ const { MigrationService: MigrationService2 } = await import('./migrations-Z6D27NAW.js');
3403
3415
  const db = c.env.DB;
3404
3416
  const migrationService = new MigrationService2(db);
3405
3417
  const status = await migrationService.getMigrationStatus();
@@ -3442,7 +3454,7 @@ adminApiRoutes.post("/migrations/run", async (c) => {
3442
3454
  });
3443
3455
  adminApiRoutes.get("/migrations/validate", async (c) => {
3444
3456
  try {
3445
- const { MigrationService: MigrationService2 } = await import('./migrations-XQ6EX6HX.js');
3457
+ const { MigrationService: MigrationService2 } = await import('./migrations-Z6D27NAW.js');
3446
3458
  const db = c.env.DB;
3447
3459
  const migrationService = new MigrationService2(db);
3448
3460
  const validation = await migrationService.validateSchema();
@@ -9008,20 +9020,20 @@ function renderContentFormPage(data, opts) {
9008
9020
  <dl class="space-y-3 text-sm">
9009
9021
  <div>
9010
9022
  <dt class="text-zinc-500 dark:text-zinc-400">Created</dt>
9011
- <dd class="mt-1 text-zinc-950 dark:text-white">${data.created_at ? new Date(data.created_at).toLocaleDateString() : "Unknown"}</dd>
9023
+ <dd class="mt-1 text-zinc-950 dark:text-white">${data.created_at ? new Date(data.created_at * 1e3).toLocaleDateString() : "Unknown"}</dd>
9012
9024
  </div>
9013
9025
  <div>
9014
9026
  <dt class="text-zinc-500 dark:text-zinc-400">Last Modified</dt>
9015
- <dd class="mt-1 text-zinc-950 dark:text-white">${data.updated_at ? new Date(data.updated_at).toLocaleDateString() : "Unknown"}</dd>
9027
+ <dd class="mt-1 text-zinc-950 dark:text-white">${data.updated_at ? new Date(data.updated_at * 1e3).toLocaleDateString() : "Unknown"}</dd>
9016
9028
  </div>
9017
9029
  <div>
9018
9030
  <dt class="text-zinc-500 dark:text-zinc-400">Author</dt>
9019
- <dd class="mt-1 text-zinc-950 dark:text-white">${data.data?.author || "Unknown"}</dd>
9031
+ <dd class="mt-1 text-zinc-950 dark:text-white">${escapeHtml(String(data.data?.author || data.author_name || "Unknown"))}</dd>
9020
9032
  </div>
9021
9033
  ${data.published_at ? `
9022
9034
  <div>
9023
9035
  <dt class="text-zinc-500 dark:text-zinc-400">Published</dt>
9024
- <dd class="mt-1 text-zinc-950 dark:text-white">${new Date(data.published_at).toLocaleDateString()}</dd>
9036
+ <dd class="mt-1 text-zinc-950 dark:text-white">${new Date(data.published_at * 1e3).toLocaleDateString()}</dd>
9025
9037
  </div>
9026
9038
  ` : ""}
9027
9039
  </dl>
@@ -11623,6 +11635,14 @@ adminContentRoutes.get("/", async (c) => {
11623
11635
  docSql += " ORDER BY updated_at DESC LIMIT ? OFFSET ?";
11624
11636
  docParams.push(limit, offset);
11625
11637
  const { results: docRows } = await db.prepare(docSql).bind(...docParams).all();
11638
+ const docUserIds = [...new Set((docRows ?? []).map((r) => r.created_by).filter(Boolean))];
11639
+ const docAuthorMap = {};
11640
+ for (let i = 0; i < docUserIds.length; i += 99) {
11641
+ const chunk = docUserIds.slice(i, i + 99);
11642
+ const ph = chunk.map(() => "?").join(",");
11643
+ const { results: uRows } = await db.prepare(`SELECT id, email FROM auth_user WHERE id IN (${ph})`).bind(...chunk).all();
11644
+ for (const u of uRows ?? []) docAuthorMap[u.id] = u.email;
11645
+ }
11626
11646
  const statusBadgeCss = {
11627
11647
  published: "bg-green-50 dark:bg-green-500/10 text-green-700 dark:text-green-400 ring-1 ring-inset ring-green-600/20 dark:ring-green-500/20",
11628
11648
  draft: "bg-zinc-50 dark:bg-zinc-500/10 text-zinc-700 dark:text-zinc-400 ring-1 ring-inset ring-zinc-600/20 dark:ring-zinc-500/20"
@@ -11639,7 +11659,7 @@ adminContentRoutes.get("/", async (c) => {
11639
11659
  slug: row.slug || "",
11640
11660
  modelName: docType?.displayName ?? typeId,
11641
11661
  statusBadge: `<span class="inline-flex items-center rounded-md px-2 py-1 text-xs font-medium ${css}">${label}</span>`,
11642
- authorName: row.created_by || "System",
11662
+ authorName: (row.created_by ? docAuthorMap[row.created_by] ?? row.created_by : null) || "System",
11643
11663
  // Document timestamps are stored in SECONDS (documents.ts), unlike legacy content rows which
11644
11664
  // store MILLISECONDS — hence the *1000 here (D23).
11645
11665
  formattedDate: new Date((row.updated_at ?? 0) * 1e3).toLocaleDateString(),
@@ -11687,8 +11707,8 @@ adminContentRoutes.get("/", async (c) => {
11687
11707
  SELECT d.root_id AS id, d.title AS title, d.slug AS slug,
11688
11708
  CASE WHEN d.is_published = 1 THEN 'published' ELSE 'draft' END AS status,
11689
11709
  d.updated_at * 1000 AS updated_at,
11690
- dt.display_name AS cdisplay, COALESCE(d.created_by, 'System') AS author_label
11691
- FROM documents d JOIN document_types dt ON dt.id = d.type_id
11710
+ dt.display_name AS cdisplay, COALESCE(u.email, d.created_by, 'System') AS author_label
11711
+ FROM documents d JOIN document_types dt ON dt.id = d.type_id LEFT JOIN auth_user u ON u.id = d.created_by
11692
11712
  WHERE ${docConds.join(" AND ")}
11693
11713
  ORDER BY updated_at DESC LIMIT ? OFFSET ?`;
11694
11714
  const { results: unionRows } = await db.prepare(unionSql).bind(...docParams, limit, offset).all();
@@ -12029,6 +12049,13 @@ adminContentRoutes.get("/:id/edit", async (c) => {
12029
12049
  if (docType && dcoll) {
12030
12050
  const fields2 = await getCollectionFields(db, dcoll.id);
12031
12051
  const flags = await loadContentEditorFlags(db);
12052
+ let authorName;
12053
+ if (docRow.created_by) {
12054
+ const authorRow = await db.prepare("SELECT name, first_name, last_name, email FROM auth_user WHERE id = ?").bind(docRow.created_by).first();
12055
+ if (authorRow) {
12056
+ authorName = authorRow.name || [authorRow.first_name, authorRow.last_name].filter(Boolean).join(" ") || authorRow.email;
12057
+ }
12058
+ }
12032
12059
  const formData2 = {
12033
12060
  id: docRow.root_id,
12034
12061
  title: docRow.title,
@@ -12043,6 +12070,7 @@ adminContentRoutes.get("/:id/edit", async (c) => {
12043
12070
  isEdit: true,
12044
12071
  referrerParams,
12045
12072
  versioningEnabled: docType?.settings?.versioning === true,
12073
+ author_name: authorName,
12046
12074
  user: user ? { name: user.email, email: user.email, role: user.role } : void 0,
12047
12075
  version: c.get("appVersion"),
12048
12076
  ...flags
@@ -12202,6 +12230,7 @@ adminContentRoutes.post("/", async (c) => {
12202
12230
  const fields = await getCollectionFields(db, collectionId);
12203
12231
  const { data, errors } = extractFieldData(fields, formData);
12204
12232
  if (Object.keys(errors).length > 0) {
12233
+ const flags = await loadContentEditorFlags(db);
12205
12234
  const formDataWithErrors = {
12206
12235
  collection,
12207
12236
  fields,
@@ -12212,7 +12241,8 @@ adminContentRoutes.post("/", async (c) => {
12212
12241
  name: user.email,
12213
12242
  email: user.email,
12214
12243
  role: user.role
12215
- } : void 0
12244
+ } : void 0,
12245
+ ...flags
12216
12246
  };
12217
12247
  if (c.req.header("HX-Request") === "true") {
12218
12248
  c.header("HX-Retarget", "#content-form-page");
@@ -12393,6 +12423,7 @@ adminContentRoutes.put("/:id", async (c) => {
12393
12423
  const fields = await getCollectionFields(db, existingContent.collection_id);
12394
12424
  const { data, errors } = extractFieldData(fields, formData);
12395
12425
  if (Object.keys(errors).length > 0) {
12426
+ const flags = await loadContentEditorFlags(db);
12396
12427
  const formDataWithErrors = {
12397
12428
  id,
12398
12429
  collection,
@@ -12405,7 +12436,8 @@ adminContentRoutes.put("/:id", async (c) => {
12405
12436
  name: user.email,
12406
12437
  email: user.email,
12407
12438
  role: user.role
12408
- } : void 0
12439
+ } : void 0,
12440
+ ...flags
12409
12441
  };
12410
12442
  if (c.req.header("HX-Request") === "true") {
12411
12443
  c.header("HX-Retarget", "#content-form-page");
@@ -13076,7 +13108,7 @@ adminContentRoutes.get("/documents/:typeId/:rootId/versions", async (c) => {
13076
13108
  const docType = await registry.findById(typeId);
13077
13109
  if (!docType) return c.html("<div>Unknown type.</div>", 404);
13078
13110
  const result = await db.prepare(
13079
- "SELECT id, version_number, is_current_draft, is_published, status, updated_at, created_by FROM documents WHERE root_id = ? AND tenant_id = ? ORDER BY version_number DESC LIMIT 50"
13111
+ "SELECT d.id, d.version_number, d.is_current_draft, d.is_published, d.status, d.updated_at, COALESCE(u.email, d.created_by) AS created_by FROM documents d LEFT JOIN auth_user u ON u.id = d.created_by WHERE d.root_id = ? AND d.tenant_id = ? ORDER BY d.version_number DESC LIMIT 50"
13080
13112
  ).bind(rootId, reqTenant(c)).all();
13081
13113
  const versions = (result.results ?? []).map((r) => ({
13082
13114
  id: r.id,
@@ -27084,6 +27116,6 @@ var ROUTES_INFO = {
27084
27116
  reference: "https://github.com/sonicjs/sonicjs"
27085
27117
  };
27086
27118
 
27087
- export { DocumentRepository, ROUTES_INFO, TenantService, VALID_MEMBER_ROLES, adminCheckboxRoutes, adminCollectionsRoutes, adminDocumentsRoutes, adminLogsRoutes, adminMediaRoutes, adminPluginRoutes, adminSettingsRoutes, admin_api_default, admin_content_default, apiDocumentsRoutes, api_content_crud_default, api_default, api_media_default, api_system_default, auth_default, createDocumentSchema, createUserProfilesPlugin, defineUserProfile, denyIfNotAllowed, dispatchHookEvent, getConfirmationDialogScript2 as getConfirmationDialogScript, getCustomData, getEmailService, getUserProfileConfig, getVariablesCached, hasEmailService, invalidateVariablesCache, isValidMemberRole, lexicalEditorPlugin, reconcileMenuFromPlugins, renderConfirmationDialog2 as renderConfirmationDialog, renderTable2 as renderTable, resolveDocScope, resolveVariablesInObject, router, router2, setEmailService, setVariablesCache, test_cleanup_default, userProfilesPlugin, userRoutes };
27088
- //# sourceMappingURL=chunk-SK5CHFJP.js.map
27089
- //# sourceMappingURL=chunk-SK5CHFJP.js.map
27119
+ export { DocumentRepository, ROUTES_INFO, TenantService, VALID_MEMBER_ROLES, adminCheckboxRoutes, adminCollectionsRoutes, adminDocumentsRoutes, adminLogsRoutes, adminMediaRoutes, adminPluginRoutes, adminSettingsRoutes, admin_api_default, admin_content_default, apiDocumentsRoutes, api_content_crud_default, api_default, api_media_default, api_system_default, auth_default, createDocumentSchema, createUserProfilesPlugin, defineUserProfile, denyIfNotAllowed, dispatchHookEvent, effectiveTenantForType, getConfirmationDialogScript2 as getConfirmationDialogScript, getCustomData, getDocumentRequestContext, getEmailService, getUserProfileConfig, getVariablesCached, hasEmailService, invalidateVariablesCache, isValidMemberRole, lexicalEditorPlugin, reconcileMenuFromPlugins, renderConfirmationDialog2 as renderConfirmationDialog, renderTable2 as renderTable, resolveDocScope, resolveVariablesInObject, router, router2, setEmailService, setVariablesCache, test_cleanup_default, updateDocumentSchema, userProfilesPlugin, userRoutes };
27120
+ //# sourceMappingURL=chunk-VC5XVPLM.js.map
27121
+ //# sourceMappingURL=chunk-VC5XVPLM.js.map