@actuate-media/cms-core 0.2.2 → 0.3.0

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 (81) hide show
  1. package/LICENSE +21 -21
  2. package/dist/__tests__/auth/session.test.js +1 -1
  3. package/dist/__tests__/auth/session.test.js.map +1 -1
  4. package/dist/api/handler-factory.d.ts.map +1 -1
  5. package/dist/api/handler-factory.js +85 -68
  6. package/dist/api/handler-factory.js.map +1 -1
  7. package/dist/api/handlers.d.ts +1 -1
  8. package/dist/api/handlers.d.ts.map +1 -1
  9. package/dist/api/handlers.js +180 -32
  10. package/dist/api/handlers.js.map +1 -1
  11. package/dist/api/index.d.ts +2 -19
  12. package/dist/api/index.d.ts.map +1 -1
  13. package/dist/api/index.js +1 -54
  14. package/dist/api/index.js.map +1 -1
  15. package/dist/api/router.d.ts +20 -0
  16. package/dist/api/router.d.ts.map +1 -0
  17. package/dist/api/router.js +55 -0
  18. package/dist/api/router.js.map +1 -0
  19. package/dist/config/index.d.ts.map +1 -1
  20. package/dist/config/index.js +2 -0
  21. package/dist/config/index.js.map +1 -1
  22. package/dist/i18n/index.js +8 -8
  23. package/dist/media/optimize.d.ts +2 -3
  24. package/dist/media/optimize.d.ts.map +1 -1
  25. package/dist/media/optimize.js +10 -1
  26. package/dist/media/optimize.js.map +1 -1
  27. package/dist/next.d.ts +3 -3
  28. package/dist/next.d.ts.map +1 -1
  29. package/dist/next.js +8 -8
  30. package/dist/next.js.map +1 -1
  31. package/dist/search/index.js +22 -22
  32. package/dist/security/anomaly-detection.d.ts +1 -1
  33. package/dist/security/anomaly-detection.d.ts.map +1 -1
  34. package/dist/security/anomaly-detection.js +27 -5
  35. package/dist/security/anomaly-detection.js.map +1 -1
  36. package/dist/security/reauth.d.ts +1 -1
  37. package/dist/security/reauth.d.ts.map +1 -1
  38. package/dist/security/reauth.js +12 -4
  39. package/dist/security/reauth.js.map +1 -1
  40. package/dist/security/sanitize.d.ts +1 -1
  41. package/dist/security/sanitize.d.ts.map +1 -1
  42. package/dist/security/sanitize.js +9 -11
  43. package/dist/security/sanitize.js.map +1 -1
  44. package/dist/security/webhook.d.ts +1 -1
  45. package/dist/security/webhook.d.ts.map +1 -1
  46. package/dist/security/webhook.js +24 -3
  47. package/dist/security/webhook.js.map +1 -1
  48. package/package.json +3 -2
  49. package/prisma/cms-schema.prisma +237 -237
  50. package/prisma/migrations/0001_init/migration.sql +384 -384
  51. package/prisma/migrations/0002_folders/migration.sql +39 -39
  52. package/prisma/migrations/0003_search_and_webhooks/migration.sql +50 -50
  53. package/prisma/migrations/migration_lock.toml +3 -3
  54. package/prisma/schema.prisma +485 -485
  55. package/prisma/seed.ts +82 -82
  56. package/generated/browser.ts +0 -109
  57. package/generated/client.ts +0 -133
  58. package/generated/commonInputTypes.ts +0 -709
  59. package/generated/enums.ts +0 -125
  60. package/generated/internal/class.ts +0 -376
  61. package/generated/internal/prismaNamespace.ts +0 -2617
  62. package/generated/internal/prismaNamespaceBrowser.ts +0 -611
  63. package/generated/models/ApiKey.ts +0 -1550
  64. package/generated/models/AuditLog.ts +0 -1206
  65. package/generated/models/BackupRecord.ts +0 -1250
  66. package/generated/models/ContentLock.ts +0 -1472
  67. package/generated/models/ContentTemplate.ts +0 -1416
  68. package/generated/models/Document.ts +0 -3005
  69. package/generated/models/Folder.ts +0 -1904
  70. package/generated/models/FormSubmission.ts +0 -1200
  71. package/generated/models/InAppNotification.ts +0 -1457
  72. package/generated/models/Media.ts +0 -2340
  73. package/generated/models/MediaUsage.ts +0 -1472
  74. package/generated/models/OAuthAccount.ts +0 -1463
  75. package/generated/models/Redirect.ts +0 -1284
  76. package/generated/models/Session.ts +0 -1492
  77. package/generated/models/Site.ts +0 -1206
  78. package/generated/models/User.ts +0 -3513
  79. package/generated/models/Version.ts +0 -1511
  80. package/generated/models/WorkflowState.ts +0 -1514
  81. package/generated/models.ts +0 -29
package/LICENSE CHANGED
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 Actuate Media
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Actuate Media
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -51,7 +51,7 @@ describe('refreshSession', () => {
51
51
  it('returns a new valid token with the same payload', async () => {
52
52
  const original = await createSession(TEST_PAYLOAD, {
53
53
  secret: TEST_SECRET,
54
- maxAge: 2,
54
+ maxAge: 10,
55
55
  });
56
56
  await new Promise((resolve) => setTimeout(resolve, 1100));
57
57
  const refreshed = await refreshSession(original, { secret: TEST_SECRET });
@@ -1 +1 @@
1
- {"version":3,"file":"session.test.js","sourceRoot":"","sources":["../../../src/__tests__/auth/session.test.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"session.test.js","sourceRoot":"","sources":["../../../src/__tests__/auth/session.test.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"handler-factory.d.ts","sourceRoot":"","sources":["../../src/api/handler-factory.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,uBAAuB;IACtC,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,kBAAkB,CAAC,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;CAC7C;AAMD,wBAAgB,gBAAgB,CAAC,OAAO,GAAE,uBAA4B,IA4DtC,SAAS,OAAO,KAAG,OAAO,CAAC,QAAQ,CAAC,CA0FnE"}
1
+ {"version":3,"file":"handler-factory.d.ts","sourceRoot":"","sources":["../../src/api/handler-factory.ts"],"names":[],"mappings":"AAWA,MAAM,WAAW,uBAAuB;IACtC,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,kBAAkB,CAAC,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;CAC7C;AAID,wBAAgB,gBAAgB,CAAC,OAAO,GAAE,uBAA4B,IA4DtC,SAAS,OAAO,KAAG,OAAO,CAAC,QAAQ,CAAC,CA0GnE"}
@@ -1,12 +1,13 @@
1
- import { createApiRouter } from './index.js';
1
+ import { createRequire } from 'node:module';
2
+ import { createApiRouter } from './router.js';
2
3
  import { registerCMSRoutes, parseCookieHeader } from './handlers.js';
3
4
  import { initDB, isDBInitialized } from '../db.js';
4
5
  import { validateCsrfToken } from '../security/index.js';
5
6
  import { createRateLimiter } from '../security/rate-limit.js';
6
7
  import { autoSeedAdmin } from '../setup/index.js';
7
- import { createGraphQLHandler } from '../graphql/index.js';
8
+ const _require = createRequire(import.meta.url);
9
+ const { version: CMS_CORE_VERSION } = _require('../../package.json');
8
10
  let cachedGraphQL = null;
9
- const CMS_CORE_VERSION = '0.1.0';
10
11
  export function handleActuateAPI(options = {}) {
11
12
  globalThis.__actuateCoreVersion = CMS_CORE_VERSION;
12
13
  if (options.config) {
@@ -57,83 +58,99 @@ export function handleActuateAPI(options = {}) {
57
58
  registerCMSRoutes(router);
58
59
  let dbChecked = false;
59
60
  return async function handler(request) {
60
- if (!isDBInitialized()) {
61
- const client = options.prismaClient ?? (options.prismaClientGetter ? await options.prismaClientGetter() : null);
62
- if (client) {
63
- initDB(client);
64
- autoSeedAdmin(client).catch(() => { });
65
- }
66
- }
67
- if (!dbChecked) {
68
- dbChecked = true;
69
- try {
70
- const client = options.prismaClient;
61
+ try {
62
+ if (!isDBInitialized()) {
63
+ const client = options.prismaClient ?? (options.prismaClientGetter ? await options.prismaClientGetter() : null);
71
64
  if (client) {
72
- const required = ['document', 'user', 'session', 'media'];
73
- const missing = required.filter(m => !(m in client));
74
- if (missing.length > 0) {
75
- console.warn(`[Actuate CMS] Prisma client is missing models: ${missing.join(', ')}. `
76
- + 'CMS features that depend on these models will return empty results. '
77
- + 'Add the CMS schema to your project: see @actuate-media/cms-core/prisma/schema');
78
- }
65
+ initDB(client);
66
+ autoSeedAdmin(client).catch(() => { });
79
67
  }
80
68
  }
81
- catch { }
82
- }
83
- const url = new URL(request.url);
84
- const originalPath = url.pathname;
85
- if (originalPath === '/api/cms/graphql' || originalPath.startsWith('/api/cms/graphql')) {
86
- const secret = process.env.CMS_SECRET;
87
- if (!secret || secret.length < 32) {
88
- return new Response(JSON.stringify({ error: 'Server misconfiguration' }), {
89
- status: 500,
90
- headers: { 'Content-Type': 'application/json' },
91
- });
92
- }
93
- const clientIp = request.headers.get('x-forwarded-for')?.split(',')[0]?.trim() ?? 'unknown';
94
- const rateLimitResult = await rateLimiter.check(clientIp);
95
- if (!rateLimitResult.allowed) {
96
- return new Response(JSON.stringify({ error: 'Too many requests' }), {
97
- status: 429,
98
- headers: {
99
- 'Content-Type': 'application/json',
100
- 'Retry-After': rateLimitResult.retryAfter?.toString() ?? '60',
101
- },
102
- });
69
+ if (!dbChecked) {
70
+ dbChecked = true;
71
+ try {
72
+ const client = options.prismaClient;
73
+ if (client) {
74
+ const required = ['document', 'user', 'session', 'media'];
75
+ const missing = required.filter(m => !(m in client));
76
+ if (missing.length > 0) {
77
+ console.warn(`[Actuate CMS] Prisma client is missing models: ${missing.join(', ')}. `
78
+ + 'CMS features that depend on these models will return empty results. '
79
+ + 'Add the CMS schema to your project: see @actuate-media/cms-core/prisma/schema');
80
+ }
81
+ }
82
+ }
83
+ catch { }
103
84
  }
104
- if (['POST', 'PUT', 'PATCH', 'DELETE'].includes(request.method)) {
105
- const csrfToken = request.headers.get('x-csrf-token');
106
- const csrfCookie = parseCookieHeader(request.headers.get('cookie') ?? '')['actuate_csrf'];
107
- if (!csrfToken || !csrfCookie || !validateCsrfToken(csrfToken, csrfCookie)) {
108
- return new Response(JSON.stringify({ error: 'Invalid CSRF token' }), {
109
- status: 403,
85
+ const url = new URL(request.url);
86
+ const originalPath = url.pathname;
87
+ if (originalPath === '/api/cms/graphql' || originalPath.startsWith('/api/cms/graphql')) {
88
+ const secret = process.env.CMS_SECRET;
89
+ if (!secret || secret.length < 32) {
90
+ return new Response(JSON.stringify({ error: 'Server misconfiguration' }), {
91
+ status: 500,
110
92
  headers: { 'Content-Type': 'application/json' },
111
93
  });
112
94
  }
113
- }
114
- const config = globalThis.__actuateConfig;
115
- if (config) {
116
- if (!cachedGraphQL) {
117
- cachedGraphQL = createGraphQLHandler({ config, secret });
95
+ const clientIp = request.headers.get('x-forwarded-for')?.split(',')[0]?.trim() ?? 'unknown';
96
+ const rateLimitResult = await rateLimiter.check(clientIp);
97
+ if (!rateLimitResult.allowed) {
98
+ return new Response(JSON.stringify({ error: 'Too many requests' }), {
99
+ status: 429,
100
+ headers: {
101
+ 'Content-Type': 'application/json',
102
+ 'Retry-After': rateLimitResult.retryAfter?.toString() ?? '60',
103
+ },
104
+ });
118
105
  }
119
- return cachedGraphQL.handle(request);
106
+ if (['POST', 'PUT', 'PATCH', 'DELETE'].includes(request.method)) {
107
+ const csrfToken = request.headers.get('x-csrf-token');
108
+ const csrfCookie = parseCookieHeader(request.headers.get('cookie') ?? '')['actuate_csrf'];
109
+ if (!csrfToken || !csrfCookie || !validateCsrfToken(csrfToken, csrfCookie)) {
110
+ return new Response(JSON.stringify({ error: 'Invalid CSRF token' }), {
111
+ status: 403,
112
+ headers: { 'Content-Type': 'application/json' },
113
+ });
114
+ }
115
+ }
116
+ const config = globalThis.__actuateConfig;
117
+ if (config) {
118
+ if (!cachedGraphQL) {
119
+ const { createGraphQLHandler } = await import('../graphql/index.js');
120
+ cachedGraphQL = createGraphQLHandler({ config, secret });
121
+ }
122
+ return cachedGraphQL.handle(request);
123
+ }
124
+ }
125
+ const cmsPrefix = '/api/cms';
126
+ if (originalPath.startsWith(cmsPrefix)) {
127
+ const strippedPath = originalPath.slice(cmsPrefix.length) || '/';
128
+ const rewrittenUrl = new URL(strippedPath, url.origin);
129
+ rewrittenUrl.search = url.search;
130
+ const rewrittenRequest = new Request(rewrittenUrl.toString(), {
131
+ method: request.method,
132
+ headers: request.headers,
133
+ body: request.body,
134
+ // @ts-ignore -- duplex is needed for streaming bodies
135
+ duplex: 'half',
136
+ });
137
+ return router.handle(rewrittenRequest);
120
138
  }
139
+ return router.handle(request);
121
140
  }
122
- const cmsPrefix = '/api/cms';
123
- if (originalPath.startsWith(cmsPrefix)) {
124
- const strippedPath = originalPath.slice(cmsPrefix.length) || '/';
125
- const rewrittenUrl = new URL(strippedPath, url.origin);
126
- rewrittenUrl.search = url.search;
127
- const rewrittenRequest = new Request(rewrittenUrl.toString(), {
128
- method: request.method,
129
- headers: request.headers,
130
- body: request.body,
131
- // @ts-ignore -- duplex is needed for streaming bodies
132
- duplex: 'half',
141
+ catch (err) {
142
+ const message = err instanceof Error ? err.message : String(err);
143
+ const stack = err instanceof Error ? err.stack : undefined;
144
+ console.error(`[Actuate CMS] Unhandled error in API handler: ${message}`, stack);
145
+ const isDev = process.env.NODE_ENV !== 'production';
146
+ return new Response(JSON.stringify({
147
+ error: 'Internal CMS error',
148
+ ...(isDev && { detail: message, stack }),
149
+ }), {
150
+ status: 500,
151
+ headers: { 'Content-Type': 'application/json' },
133
152
  });
134
- return router.handle(rewrittenRequest);
135
153
  }
136
- return router.handle(request);
137
154
  };
138
155
  }
139
156
  //# sourceMappingURL=handler-factory.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"handler-factory.js","sourceRoot":"","sources":["../../src/api/handler-factory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AACrE,OAAO,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AACnD,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAQ3D,IAAI,aAAa,GAAmD,IAAI,CAAC;AAEzE,MAAM,gBAAgB,GAAG,OAAO,CAAC;AAEjC,MAAM,UAAU,gBAAgB,CAAC,UAAmC,EAAE;IACnE,UAAkB,CAAC,oBAAoB,GAAG,gBAAgB,CAAC;IAE5D,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;QAClB,UAAkB,CAAC,eAAe,GAAG,OAAO,CAAC,MAAM,CAAC;QAErD,MAAM,MAAM,GAAG,OAAO,CAAC,MAAa,CAAC;QACrC,MAAM,KAAK,GAAU,EAAE,CAAC;QACxB,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC;YAClC,KAAK,MAAM,MAAM,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;gBACpC,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE,CAAC;oBACjC,KAAK,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;gBAC9B,CAAC;YACH,CAAC;QACH,CAAC;QACA,MAAc,CAAC,YAAY,GAAG,KAAK,CAAC;IACvC,CAAC;IAED,MAAM,MAAM,GAAG,eAAe,EAAE,CAAC;IAEjC,MAAM,WAAW,GAAG,iBAAiB,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,WAAW,EAAE,GAAG,EAAE,CAAC,CAAC;IAE7E,MAAM,CAAC,GAAG,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE;QACjC,MAAM,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,SAAS,CAAC;QAC5F,MAAM,eAAe,GAAG,MAAM,WAAW,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QAC1D,IAAI,CAAC,eAAe,CAAC,OAAO,EAAE,CAAC;YAC7B,OAAO,IAAI,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,mBAAmB,EAAE,CAAC,EAAE;gBAClE,MAAM,EAAE,GAAG;gBACX,OAAO,EAAE;oBACP,cAAc,EAAE,kBAAkB;oBAClC,aAAa,EAAE,eAAe,CAAC,UAAU,EAAE,QAAQ,EAAE,IAAI,IAAI;iBAC9D;aACF,CAAC,CAAC;QACL,CAAC;QAED,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;YAChE,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;YACpC,MAAM,UAAU,GAAG,CAAC,aAAa,EAAE,cAAc,EAAE,qBAAqB,EAAE,aAAa,CAAC,CAAC;YACzF,MAAM,QAAQ,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;mBAC7D,yBAAyB,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;YAErD,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACd,MAAM,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;gBACtD,MAAM,UAAU,GAAG,iBAAiB,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,cAAc,CAAC,CAAC;gBAC1F,IAAI,CAAC,SAAS,IAAI,CAAC,UAAU,IAAI,CAAC,iBAAiB,CAAC,SAAS,EAAE,UAAU,CAAC,EAAE,CAAC;oBAC3E,OAAO,IAAI,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,oBAAoB,EAAE,CAAC,EAAE;wBACnE,MAAM,EAAE,GAAG;wBACX,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;qBAChD,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;QACH,CAAC;QAED,OAAO,IAAI,EAAE,CAAC;IAChB,CAAC,CAAC,CAAC;IAEH,iBAAiB,CAAC,MAAM,CAAC,CAAC;IAE1B,IAAI,SAAS,GAAG,KAAK,CAAC;IAEtB,OAAO,KAAK,UAAU,OAAO,CAAC,OAAgB;QAC5C,IAAI,CAAC,eAAe,EAAE,EAAE,CAAC;YACvB,MAAM,MAAM,GAAG,OAAO,CAAC,YAAY,IAAI,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAC,CAAC,MAAM,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;YAChH,IAAI,MAAM,EAAE,CAAC;gBACX,MAAM,CAAC,MAAM,CAAC,CAAC;gBACf,aAAa,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;YACxC,CAAC;QACH,CAAC;QAED,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,SAAS,GAAG,IAAI,CAAC;YACjB,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,OAAO,CAAC,YAAmD,CAAC;gBAC3E,IAAI,MAAM,EAAE,CAAC;oBACX,MAAM,QAAQ,GAAG,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;oBAC1D,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC;oBACrD,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;wBACvB,OAAO,CAAC,IAAI,CACV,kDAAkD,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI;8BACtE,sEAAsE;8BACtE,+EAA+E,CAClF,CAAC;oBACJ,CAAC;gBACH,CAAC;YACH,CAAC;YAAC,MAAM,CAAC,CAAA,CAAC;QACZ,CAAC;QAED,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACjC,MAAM,YAAY,GAAG,GAAG,CAAC,QAAQ,CAAC;QAElC,IAAI,YAAY,KAAK,kBAAkB,IAAI,YAAY,CAAC,UAAU,CAAC,kBAAkB,CAAC,EAAE,CAAC;YACvF,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC;YACtC,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,GAAG,EAAE,EAAE,CAAC;gBAClC,OAAO,IAAI,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,yBAAyB,EAAE,CAAC,EAAE;oBACxE,MAAM,EAAE,GAAG;oBACX,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;iBAChD,CAAC,CAAC;YACL,CAAC;YAED,MAAM,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,SAAS,CAAC;YAC5F,MAAM,eAAe,GAAG,MAAM,WAAW,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;YAC1D,IAAI,CAAC,eAAe,CAAC,OAAO,EAAE,CAAC;gBAC7B,OAAO,IAAI,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,mBAAmB,EAAE,CAAC,EAAE;oBAClE,MAAM,EAAE,GAAG;oBACX,OAAO,EAAE;wBACP,cAAc,EAAE,kBAAkB;wBAClC,aAAa,EAAE,eAAe,CAAC,UAAU,EAAE,QAAQ,EAAE,IAAI,IAAI;qBAC9D;iBACF,CAAC,CAAC;YACL,CAAC;YAED,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;gBAChE,MAAM,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;gBACtD,MAAM,UAAU,GAAG,iBAAiB,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,cAAc,CAAC,CAAC;gBAC1F,IAAI,CAAC,SAAS,IAAI,CAAC,UAAU,IAAI,CAAC,iBAAiB,CAAC,SAAS,EAAE,UAAU,CAAC,EAAE,CAAC;oBAC3E,OAAO,IAAI,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,oBAAoB,EAAE,CAAC,EAAE;wBACnE,MAAM,EAAE,GAAG;wBACX,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;qBAChD,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;YAED,MAAM,MAAM,GAAI,UAAkB,CAAC,eAAe,CAAC;YACnD,IAAI,MAAM,EAAE,CAAC;gBACX,IAAI,CAAC,aAAa,EAAE,CAAC;oBACnB,aAAa,GAAG,oBAAoB,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;gBAC3D,CAAC;gBACD,OAAO,aAAa,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;YACvC,CAAC;QACH,CAAC;QAED,MAAM,SAAS,GAAG,UAAU,CAAC;QAC7B,IAAI,YAAY,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;YACvC,MAAM,YAAY,GAAG,YAAY,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,GAAG,CAAC;YACjE,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,YAAY,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;YACvD,YAAY,CAAC,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC;YAEjC,MAAM,gBAAgB,GAAG,IAAI,OAAO,CAAC,YAAY,CAAC,QAAQ,EAAE,EAAE;gBAC5D,MAAM,EAAE,OAAO,CAAC,MAAM;gBACtB,OAAO,EAAE,OAAO,CAAC,OAAO;gBACxB,IAAI,EAAE,OAAO,CAAC,IAAI;gBAClB,sDAAsD;gBACtD,MAAM,EAAE,MAAM;aACf,CAAC,CAAC;YAEH,OAAO,MAAM,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC;QACzC,CAAC;QAED,OAAO,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAChC,CAAC,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"handler-factory.js","sourceRoot":"","sources":["../../src/api/handler-factory.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import type { ApiRouter } from './index.js';
1
+ import type { ApiRouter } from './router.js';
2
2
  export declare function parseCookieHeader(cookieHeader: string): Record<string, string>;
3
3
  export declare function registerCMSRoutes(router: ApiRouter): void;
4
4
  //# sourceMappingURL=handlers.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"handlers.d.ts","sourceRoot":"","sources":["../../src/api/handlers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AA2L5C,wBAAgB,iBAAiB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAS9E;AAyDD,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA8zEzD"}
1
+ {"version":3,"file":"handlers.d.ts","sourceRoot":"","sources":["../../src/api/handlers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAkN7C,wBAAgB,iBAAiB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAS9E;AAiED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAi6EzD"}
@@ -64,9 +64,18 @@ function modelNotAvailable(name) {
64
64
  }
65
65
  async function safeCount(model, where) {
66
66
  try {
67
- if (!model?.count)
67
+ if (!model || typeof model !== 'object')
68
68
  return 0;
69
- return await model.count(where ? { where } : undefined);
69
+ let countFn;
70
+ try {
71
+ countFn = model.count;
72
+ }
73
+ catch {
74
+ return 0;
75
+ }
76
+ if (typeof countFn !== 'function')
77
+ return 0;
78
+ return await countFn.call(model, where ? { where } : undefined);
70
79
  }
71
80
  catch {
72
81
  return 0;
@@ -74,9 +83,18 @@ async function safeCount(model, where) {
74
83
  }
75
84
  async function safeFindMany(model, args) {
76
85
  try {
77
- if (!model?.findMany)
86
+ if (!model || typeof model !== 'object')
87
+ return [];
88
+ let findManyFn;
89
+ try {
90
+ findManyFn = model.findMany;
91
+ }
92
+ catch {
78
93
  return [];
79
- return await model.findMany(args);
94
+ }
95
+ if (typeof findManyFn !== 'function')
96
+ return [];
97
+ return await findManyFn.call(model, args);
80
98
  }
81
99
  catch {
82
100
  return [];
@@ -107,22 +125,44 @@ function isAllowedStorageUrl(url) {
107
125
  const ALLOWED_SORT_FIELDS = new Set([
108
126
  'createdAt', 'updatedAt', 'publishedAt', 'status', 'collection',
109
127
  ]);
128
+ let _secretMissing = false;
129
+ let _secretWarningLogged = false;
110
130
  function getSessionSecret() {
111
131
  const secret = process.env.CMS_SECRET
112
132
  ?? process.env.CMS_SESSION_SECRET
113
133
  ?? globalThis.__actuateConfig?.secret;
114
134
  if (!secret) {
115
- throw new Error('[Actuate CMS] Missing CMS secret. Set the CMS_SECRET environment variable (min 32 characters) '
116
- + 'or pass `secret` in your actuate.config.ts. '
117
- + 'Generate one with: node -e "console.log(require(\'crypto\').randomBytes(32).toString(\'hex\'))"');
135
+ _secretMissing = true;
136
+ if (!_secretWarningLogged) {
137
+ _secretWarningLogged = true;
138
+ console.error('[Actuate CMS] Missing CMS secret. Set the CMS_SECRET environment variable (min 32 characters) '
139
+ + 'or pass `secret` in your actuate.config.ts. '
140
+ + 'Generate one with: node -e "console.log(require(\'crypto\').randomBytes(32).toString(\'hex\'))" '
141
+ + '-- All authenticated API routes will return 503 until this is configured.');
142
+ }
143
+ throw new Error('CMS secret not configured');
118
144
  }
119
145
  if (secret.length < 32) {
120
146
  throw new Error('[Actuate CMS] CMS secret must be at least 32 characters (got ' + secret.length + '). '
121
147
  + 'Generate a secure value with: node -e "console.log(require(\'crypto\').randomBytes(32).toString(\'hex\'))"');
122
148
  }
149
+ _secretMissing = false;
123
150
  return secret;
124
151
  }
152
+ function isSecretMissing() {
153
+ if (_secretMissing)
154
+ return true;
155
+ try {
156
+ getSessionSecret();
157
+ return false;
158
+ }
159
+ catch {
160
+ return true;
161
+ }
162
+ }
125
163
  async function extractSession(request) {
164
+ if (isSecretMissing())
165
+ return null;
126
166
  let token;
127
167
  const authHeader = request.headers.get('Authorization');
128
168
  if (authHeader?.startsWith('Bearer ')) {
@@ -163,6 +203,14 @@ export function parseCookieHeader(cookieHeader) {
163
203
  return cookies;
164
204
  }
165
205
  async function requireAuth(request) {
206
+ if (isSecretMissing()) {
207
+ return {
208
+ error: json({
209
+ error: 'CMS secret not configured. Set CMS_SECRET or CMS_SESSION_SECRET environment variable (min 32 characters).',
210
+ code: 'MISSING_SECRET',
211
+ }, 503),
212
+ };
213
+ }
166
214
  const session = await extractSession(request);
167
215
  if (!session) {
168
216
  return { error: errorResponse('Unauthorized', 401) };
@@ -206,16 +254,39 @@ class ModelNotAvailableError extends Error {
206
254
  export function registerCMSRoutes(router) {
207
255
  const rawDb = () => getDB();
208
256
  const db = () => {
209
- const d = rawDb();
257
+ let d;
258
+ try {
259
+ d = rawDb();
260
+ }
261
+ catch (err) {
262
+ console.error('[actuate][db] Failed to obtain database client:', err instanceof Error ? err.message : err);
263
+ return new Proxy({}, {
264
+ get(_target, prop) {
265
+ if (typeof prop !== 'string' || prop.startsWith('$') || prop === 'then')
266
+ return undefined;
267
+ return new Proxy({}, {
268
+ get() { throw new ModelNotAvailableError(String(prop)); },
269
+ });
270
+ },
271
+ });
272
+ }
210
273
  return new Proxy(d, {
211
274
  get(target, prop) {
212
- const val = target[prop];
213
- if (val !== undefined)
275
+ if (typeof prop !== 'string')
276
+ return Reflect.get(target, prop);
277
+ if (prop.startsWith('$') || prop === 'then')
278
+ return Reflect.get(target, prop);
279
+ let val;
280
+ try {
281
+ val = target[prop];
282
+ }
283
+ catch {
284
+ val = undefined;
285
+ }
286
+ if (val !== undefined && val !== null)
214
287
  return val;
215
288
  return new Proxy({}, {
216
- get() {
217
- throw new ModelNotAvailableError(String(prop));
218
- },
289
+ get() { throw new ModelNotAvailableError(String(prop)); },
219
290
  });
220
291
  },
221
292
  });
@@ -253,17 +324,17 @@ export function registerCMSRoutes(router) {
253
324
  });
254
325
  });
255
326
  router.get('/docs', async () => {
256
- const html = `<!DOCTYPE html>
257
- <html>
258
- <head>
259
- <title>Actuate CMS API Reference</title>
260
- <meta charset="utf-8" />
261
- <meta name="viewport" content="width=device-width, initial-scale=1" />
262
- </head>
263
- <body>
264
- <script id="api-reference" data-url="/api/cms/openapi.json"></script>
265
- <script src="https://cdn.jsdelivr.net/npm/@scalar/api-reference"></script>
266
- </body>
327
+ const html = `<!DOCTYPE html>
328
+ <html>
329
+ <head>
330
+ <title>Actuate CMS API Reference</title>
331
+ <meta charset="utf-8" />
332
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
333
+ </head>
334
+ <body>
335
+ <script id="api-reference" data-url="/api/cms/openapi.json"></script>
336
+ <script src="https://cdn.jsdelivr.net/npm/@scalar/api-reference"></script>
337
+ </body>
267
338
  </html>`;
268
339
  return new Response(html, {
269
340
  status: 200,
@@ -1205,13 +1276,83 @@ export function registerCMSRoutes(router) {
1205
1276
  // ---------------------------------------------------------------------------
1206
1277
  // Stats route
1207
1278
  // ---------------------------------------------------------------------------
1279
+ // ---------------------------------------------------------------------------
1280
+ // Health endpoint -- reports available models and CMS version
1281
+ // ---------------------------------------------------------------------------
1282
+ const CMS_EXPECTED_MODELS = [
1283
+ 'document', 'media', 'user', 'session', 'version',
1284
+ 'folder', 'redirect', 'formSubmission', 'auditLog',
1285
+ 'webhookEndpoint', 'webhookDeliveryLog',
1286
+ ];
1287
+ router.get('/health', async () => {
1288
+ const cmsVersion = globalThis.__actuateCoreVersion ?? '0.0.0';
1289
+ const models = {};
1290
+ let d;
1291
+ try {
1292
+ d = db();
1293
+ }
1294
+ catch {
1295
+ for (const m of CMS_EXPECTED_MODELS)
1296
+ models[m] = false;
1297
+ return json({
1298
+ data: {
1299
+ status: 'degraded',
1300
+ version: cmsVersion,
1301
+ secretConfigured: !isSecretMissing(),
1302
+ models,
1303
+ databaseConnected: false,
1304
+ },
1305
+ });
1306
+ }
1307
+ let dbConnected = true;
1308
+ for (const modelName of CMS_EXPECTED_MODELS) {
1309
+ try {
1310
+ const model = d[modelName];
1311
+ if (model && typeof model.count === 'function') {
1312
+ await model.count({ take: 0 });
1313
+ models[modelName] = true;
1314
+ }
1315
+ else {
1316
+ models[modelName] = false;
1317
+ }
1318
+ }
1319
+ catch {
1320
+ models[modelName] = false;
1321
+ if (modelName === CMS_EXPECTED_MODELS[0]) {
1322
+ dbConnected = false;
1323
+ }
1324
+ }
1325
+ }
1326
+ const allAvailable = Object.values(models).every(Boolean);
1327
+ return json({
1328
+ data: {
1329
+ status: allAvailable ? 'healthy' : 'degraded',
1330
+ version: cmsVersion,
1331
+ secretConfigured: !isSecretMissing(),
1332
+ models,
1333
+ databaseConnected: dbConnected,
1334
+ },
1335
+ });
1336
+ });
1337
+ // ---------------------------------------------------------------------------
1338
+ // Stats route
1339
+ // ---------------------------------------------------------------------------
1340
+ const EMPTY_STATS = { totalDocuments: 0, totalMedia: 0, totalUsers: 0, recentDocuments: [] };
1208
1341
  router.get('/stats', async (request) => {
1209
1342
  try {
1210
- const auth = await requireAuth(request);
1211
- if (auth.error)
1212
- return auth.error;
1213
- const d = db();
1214
- const [totalDocuments, totalMedia, totalUsers, recentDocuments] = await Promise.all([
1343
+ if (!isSecretMissing()) {
1344
+ const auth = await requireAuth(request);
1345
+ if (auth.error)
1346
+ return auth.error;
1347
+ }
1348
+ let d;
1349
+ try {
1350
+ d = db();
1351
+ }
1352
+ catch {
1353
+ return json({ data: EMPTY_STATS });
1354
+ }
1355
+ const [docResult, mediaResult, userResult, recentResult] = await Promise.allSettled([
1215
1356
  safeCount(d.document, { deletedAt: null }),
1216
1357
  safeCount(d.media),
1217
1358
  safeCount(d.user),
@@ -1221,10 +1362,17 @@ export function registerCMSRoutes(router) {
1221
1362
  take: 10,
1222
1363
  }),
1223
1364
  ]);
1224
- return json({ data: { totalDocuments, totalMedia, totalUsers, recentDocuments } });
1365
+ return json({
1366
+ data: {
1367
+ totalDocuments: docResult.status === 'fulfilled' ? docResult.value : 0,
1368
+ totalMedia: mediaResult.status === 'fulfilled' ? mediaResult.value : 0,
1369
+ totalUsers: userResult.status === 'fulfilled' ? userResult.value : 0,
1370
+ recentDocuments: recentResult.status === 'fulfilled' ? recentResult.value : [],
1371
+ },
1372
+ });
1225
1373
  }
1226
- catch (err) {
1227
- return internalError(err);
1374
+ catch {
1375
+ return json({ data: EMPTY_STATS });
1228
1376
  }
1229
1377
  });
1230
1378
  // ---------------------------------------------------------------------------