nextly 0.0.1 → 0.0.2-alpha.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 (268) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +122 -0
  3. package/dist/_dts-chunks/collections-handler.d-DjgO74Wt.d.ts +20540 -0
  4. package/dist/_dts-chunks/config.d-DNwsDnjs.d.ts +2589 -0
  5. package/dist/_dts-chunks/define-component.d-BUgTHmt3.d.ts +1149 -0
  6. package/dist/_dts-chunks/image-processor.d-OO1PmMrv.d.ts +335 -0
  7. package/dist/_dts-chunks/index.d-axCAzZ7m.d.ts +17842 -0
  8. package/dist/_dts-chunks/media.d-DjDOZo4B.d.ts +117 -0
  9. package/dist/_dts-chunks/on-error.d-CHIKWNxd.d.ts +38 -0
  10. package/dist/_dts-chunks/storage.d-BUhQ2we_.d.ts +404 -0
  11. package/dist/actions/index.d.ts +239 -0
  12. package/dist/actions/index.mjs +281 -0
  13. package/dist/api/auth-state.d.ts +5 -0
  14. package/dist/api/auth-state.mjs +131 -0
  15. package/dist/api/collections-schema-detail.d.ts +56 -0
  16. package/dist/api/collections-schema-detail.mjs +244 -0
  17. package/dist/api/collections-schema-export.d.ts +56 -0
  18. package/dist/api/collections-schema-export.mjs +129 -0
  19. package/dist/api/collections-schema.d.ts +59 -0
  20. package/dist/api/collections-schema.mjs +207 -0
  21. package/dist/api/components-detail.d.ts +50 -0
  22. package/dist/api/components-detail.mjs +132 -0
  23. package/dist/api/components.d.ts +69 -0
  24. package/dist/api/components.mjs +144 -0
  25. package/dist/api/email-providers-default.d.ts +40 -0
  26. package/dist/api/email-providers-default.mjs +75 -0
  27. package/dist/api/email-providers-detail.d.ts +81 -0
  28. package/dist/api/email-providers-detail.mjs +109 -0
  29. package/dist/api/email-providers-test.d.ts +43 -0
  30. package/dist/api/email-providers-test.mjs +114 -0
  31. package/dist/api/email-providers.d.ts +69 -0
  32. package/dist/api/email-providers.mjs +110 -0
  33. package/dist/api/email-send-template.d.ts +41 -0
  34. package/dist/api/email-send-template.mjs +58 -0
  35. package/dist/api/email-send.d.ts +42 -0
  36. package/dist/api/email-send.mjs +58 -0
  37. package/dist/api/email-templates-detail.d.ts +74 -0
  38. package/dist/api/email-templates-detail.mjs +112 -0
  39. package/dist/api/email-templates-layout.d.ts +55 -0
  40. package/dist/api/email-templates-layout.mjs +92 -0
  41. package/dist/api/email-templates-preview.d.ts +48 -0
  42. package/dist/api/email-templates-preview.mjs +93 -0
  43. package/dist/api/email-templates.d.ts +61 -0
  44. package/dist/api/email-templates.mjs +118 -0
  45. package/dist/api/health.d.ts +68 -0
  46. package/dist/api/health.mjs +67 -0
  47. package/dist/api/index.d.ts +54 -0
  48. package/dist/api/index.mjs +16 -0
  49. package/dist/api/media-bulk.d.ts +74 -0
  50. package/dist/api/media-bulk.mjs +196 -0
  51. package/dist/api/media-folders.d.ts +112 -0
  52. package/dist/api/media-folders.mjs +187 -0
  53. package/dist/api/media-handlers.d.ts +102 -0
  54. package/dist/api/media-handlers.mjs +437 -0
  55. package/dist/api/media.d.ts +117 -0
  56. package/dist/api/media.mjs +242 -0
  57. package/dist/api/singles-detail.d.ts +87 -0
  58. package/dist/api/singles-detail.mjs +170 -0
  59. package/dist/api/singles-schema-detail.d.ts +54 -0
  60. package/dist/api/singles-schema-detail.mjs +182 -0
  61. package/dist/api/singles.d.ts +34 -0
  62. package/dist/api/singles.mjs +94 -0
  63. package/dist/api/storage-upload-url.d.ts +48 -0
  64. package/dist/api/storage-upload-url.mjs +202 -0
  65. package/dist/api/uploads.d.ts +109 -0
  66. package/dist/api/uploads.mjs +359 -0
  67. package/dist/auth/index.d.ts +425 -0
  68. package/dist/auth/index.mjs +199 -0
  69. package/dist/boot-apply-PQSYLDIN.mjs +7 -0
  70. package/dist/chunk-2OALJTK6.mjs +489 -0
  71. package/dist/chunk-2Q2SX2CS.mjs +365 -0
  72. package/dist/chunk-2TFX4ND3.mjs +13 -0
  73. package/dist/chunk-2TWPDSYD.mjs +87 -0
  74. package/dist/chunk-2W3DVD7S.mjs +647 -0
  75. package/dist/chunk-2ZFKXPQM.mjs +88 -0
  76. package/dist/chunk-3FA7FKAV.mjs +832 -0
  77. package/dist/chunk-3NZ2KMBL.mjs +58 -0
  78. package/dist/chunk-4MJLT6PZ.mjs +0 -0
  79. package/dist/chunk-56WO4WX7.mjs +0 -0
  80. package/dist/chunk-5APFUGAD.mjs +89 -0
  81. package/dist/chunk-5HMZ644B.mjs +108 -0
  82. package/dist/chunk-67GXH6PR.mjs +32 -0
  83. package/dist/chunk-6JNEPWRW.mjs +14368 -0
  84. package/dist/chunk-6NFHQIJD.mjs +45 -0
  85. package/dist/chunk-7P6ASYW6.mjs +9 -0
  86. package/dist/chunk-A3WPLSDT.mjs +1364 -0
  87. package/dist/chunk-AGJ6F2T3.mjs +144 -0
  88. package/dist/chunk-AK6Z23OX.mjs +1464 -0
  89. package/dist/chunk-APKKRD2G.mjs +102 -0
  90. package/dist/chunk-B2GV2BWH.mjs +73 -0
  91. package/dist/chunk-D5HQBNUB.mjs +74 -0
  92. package/dist/chunk-DNNG377Z.mjs +204 -0
  93. package/dist/chunk-DP3G27G5.mjs +135 -0
  94. package/dist/chunk-DV6WVX2Q.mjs +0 -0
  95. package/dist/chunk-DXGGXIUZ.mjs +57 -0
  96. package/dist/chunk-EGXBZCGC.mjs +943 -0
  97. package/dist/chunk-ERCNLX3V.mjs +176 -0
  98. package/dist/chunk-FQULBZ53.mjs +850 -0
  99. package/dist/chunk-G2AA4QLC.mjs +262 -0
  100. package/dist/chunk-GDBJ5JCU.mjs +488 -0
  101. package/dist/chunk-GJNSJU4S.mjs +19 -0
  102. package/dist/chunk-GZ6DCQKC.mjs +69 -0
  103. package/dist/chunk-H26B4FYG.mjs +167 -0
  104. package/dist/chunk-I4JMR3UR.mjs +21 -0
  105. package/dist/chunk-INV7QKLG.mjs +508 -0
  106. package/dist/chunk-IUDOC7N7.mjs +46 -0
  107. package/dist/chunk-IZWPRDC3.mjs +206 -0
  108. package/dist/chunk-KIMNCZGV.mjs +15 -0
  109. package/dist/chunk-L6HW2DA7.mjs +15 -0
  110. package/dist/chunk-LAZXX4HR.mjs +100 -0
  111. package/dist/chunk-LDKCUMHK.mjs +95 -0
  112. package/dist/chunk-LRXMECUA.mjs +0 -0
  113. package/dist/chunk-M52VMPGA.mjs +119 -0
  114. package/dist/chunk-MGUWEEI6.mjs +160 -0
  115. package/dist/chunk-NRUWQ5Z7.mjs +419 -0
  116. package/dist/chunk-NSEFNNU4.mjs +25360 -0
  117. package/dist/chunk-NTHVDFGO.mjs +138 -0
  118. package/dist/chunk-O3QHXMOX.mjs +3166 -0
  119. package/dist/chunk-P7NH2OSC.mjs +2605 -0
  120. package/dist/chunk-PKMABBB5.mjs +184 -0
  121. package/dist/chunk-PWS6XGJK.mjs +76 -0
  122. package/dist/chunk-R6JJQHFC.mjs +20 -0
  123. package/dist/chunk-RJLLGGPG.mjs +0 -0
  124. package/dist/chunk-SBACDPNX.mjs +689 -0
  125. package/dist/chunk-TO5AFLVQ.mjs +124 -0
  126. package/dist/chunk-TS7GHTG2.mjs +5436 -0
  127. package/dist/chunk-UJ2IMJ4W.mjs +133 -0
  128. package/dist/chunk-UOP63Q54.mjs +102 -0
  129. package/dist/chunk-UUOFWCM6.mjs +78 -0
  130. package/dist/chunk-V4EQTOA4.mjs +893 -0
  131. package/dist/chunk-VJ66NCL4.mjs +193 -0
  132. package/dist/chunk-VQJQHVEV.mjs +29 -0
  133. package/dist/chunk-VTJADRO3.mjs +141 -0
  134. package/dist/chunk-VWF3JO32.mjs +0 -0
  135. package/dist/chunk-W4MGXIRR.mjs +27 -0
  136. package/dist/chunk-W5KKPZT5.mjs +1204 -0
  137. package/dist/chunk-WD34YQ6T.mjs +381 -0
  138. package/dist/chunk-WZBYMYVW.mjs +14 -0
  139. package/dist/chunk-X23WKS3Z.mjs +50 -0
  140. package/dist/chunk-X7TXCYYN.mjs +6496 -0
  141. package/dist/chunk-XGI4EMS3.mjs +140 -0
  142. package/dist/chunk-XZKLBMN6.mjs +1153 -0
  143. package/dist/chunk-YB7INWPY.mjs +0 -0
  144. package/dist/chunk-YV4Y7SDL.mjs +83 -0
  145. package/dist/chunk-YZNBLFIW.mjs +1688 -0
  146. package/dist/chunk-YZZCTONM.mjs +263 -0
  147. package/dist/chunk-ZE6A3FYH.mjs +289 -0
  148. package/dist/cli/nextly.mjs +68 -0
  149. package/dist/cli/utils/index.d.ts +449 -0
  150. package/dist/cli/utils/index.mjs +49 -0
  151. package/dist/component-schema-service-5577KVW6.mjs +11 -0
  152. package/dist/config-loader-23YEMC3Z.mjs +23 -0
  153. package/dist/config.d.ts +44 -0
  154. package/dist/config.mjs +109 -0
  155. package/dist/container-ORGFGYSZ.mjs +9 -0
  156. package/dist/database/index.d.ts +12 -0
  157. package/dist/database/index.mjs +40 -0
  158. package/dist/database/seeders/index.d.ts +93 -0
  159. package/dist/database/seeders/index.mjs +47 -0
  160. package/dist/db-sync-demote-LJGKLB3S.mjs +117 -0
  161. package/dist/db-sync-promote-B26VSYQF.mjs +113 -0
  162. package/dist/dev-reload-broadcaster-B73IQ53V.mjs +25 -0
  163. package/dist/dist-M2NOU37V.mjs +19 -0
  164. package/dist/drizzle-kit-lazy-D2M2PXR2.mjs +13 -0
  165. package/dist/dynamic-collection-schema-service-IEXTPIZ7.mjs +8 -0
  166. package/dist/errors/index.d.ts +159 -0
  167. package/dist/errors/index.mjs +10 -0
  168. package/dist/factory-IWMBKUJM.mjs +15 -0
  169. package/dist/first-run-QIVKWJIF.mjs +63 -0
  170. package/dist/fresh-push-NR67DC3R.mjs +8 -0
  171. package/dist/index.d.ts +4175 -0
  172. package/dist/index.mjs +1336 -0
  173. package/dist/local-plugin-PTET4NAT.mjs +7 -0
  174. package/dist/logger-NU46DXNY.mjs +15 -0
  175. package/dist/logger-YE4TC7ZN.mjs +9 -0
  176. package/dist/migration-journal-EP532Y4L.mjs +139 -0
  177. package/dist/migrations/mysql/0000_eager_sentry.sql +174 -0
  178. package/dist/migrations/mysql/0001_soft_giant_girl.sql +27 -0
  179. package/dist/migrations/mysql/0002_media_table.sql +24 -0
  180. package/dist/migrations/mysql/0003_dynamic_singles.sql +37 -0
  181. package/dist/migrations/mysql/0004_dynamic_components.sql +35 -0
  182. package/dist/migrations/mysql/0005_user_management_tables.sql +92 -0
  183. package/dist/migrations/mysql/0006_api_keys.sql +36 -0
  184. package/dist/migrations/mysql/0007_general_settings.sql +20 -0
  185. package/dist/migrations/mysql/0008_site_settings_logo_url.sql +9 -0
  186. package/dist/migrations/mysql/0009_activity_log.sql +30 -0
  187. package/dist/migrations/mysql/0010_site_settings_sidebar.sql +13 -0
  188. package/dist/migrations/mysql/0011_missing_tables_and_columns.sql +54 -0
  189. package/dist/migrations/mysql/0012_image_sizes_and_focal_point.sql +30 -0
  190. package/dist/migrations/mysql/0012_media_folders.sql +43 -0
  191. package/dist/migrations/mysql/0013_user_brute_force_protection.sql +31 -0
  192. package/dist/migrations/mysql/0014_email_template_attachments.sql +12 -0
  193. package/dist/migrations/mysql/0015_media_uploaded_by_nullable.sql +15 -0
  194. package/dist/migrations/mysql/20260429_000000_000_initial_journal.sql +22 -0
  195. package/dist/migrations/mysql/20260501_000000_journal_batch.sql +17 -0
  196. package/dist/migrations/mysql/20260501_000001_audit_log.sql +24 -0
  197. package/dist/migrations/mysql/20260504_000000_nextly_meta.sql +21 -0
  198. package/dist/migrations/mysql/meta/0000_snapshot.json +1005 -0
  199. package/dist/migrations/mysql/meta/0001_snapshot.json +1099 -0
  200. package/dist/migrations/mysql/meta/_journal.json +41 -0
  201. package/dist/migrations/postgresql/0000_misty_king_bedlam.sql +169 -0
  202. package/dist/migrations/postgresql/0001_perpetual_captain_marvel.sql +8 -0
  203. package/dist/migrations/postgresql/0002_sad_spectrum.sql +16 -0
  204. package/dist/migrations/postgresql/0003_hesitant_ultron.sql +17 -0
  205. package/dist/migrations/postgresql/0004_media_table.sql +24 -0
  206. package/dist/migrations/postgresql/0005_media_folders.sql +36 -0
  207. package/dist/migrations/postgresql/0006_dynamic_collections_update.sql +50 -0
  208. package/dist/migrations/postgresql/0007_dynamic_singles.sql +38 -0
  209. package/dist/migrations/postgresql/0008_dynamic_components.sql +37 -0
  210. package/dist/migrations/postgresql/0009_user_management_tables.sql +95 -0
  211. package/dist/migrations/postgresql/0010_api_keys.sql +34 -0
  212. package/dist/migrations/postgresql/0011_general_settings.sql +20 -0
  213. package/dist/migrations/postgresql/0012_site_settings_logo_url.sql +9 -0
  214. package/dist/migrations/postgresql/0013_activity_log.sql +29 -0
  215. package/dist/migrations/postgresql/0014_image_sizes_and_focal_point.sql +33 -0
  216. package/dist/migrations/postgresql/0014_site_settings_sidebar.sql +13 -0
  217. package/dist/migrations/postgresql/0015_user_brute_force_protection.sql +29 -0
  218. package/dist/migrations/postgresql/0016_email_template_attachments.sql +12 -0
  219. package/dist/migrations/postgresql/0017_media_uploaded_by_nullable.sql +15 -0
  220. package/dist/migrations/postgresql/20260429_000000_000_initial_journal.sql +24 -0
  221. package/dist/migrations/postgresql/20260501_000000_journal_batch.sql +17 -0
  222. package/dist/migrations/postgresql/20260501_000001_audit_log.sql +24 -0
  223. package/dist/migrations/postgresql/20260504_000000_nextly_meta.sql +22 -0
  224. package/dist/migrations/postgresql/meta/0000_snapshot.json +1286 -0
  225. package/dist/migrations/postgresql/meta/0001_snapshot.json +1407 -0
  226. package/dist/migrations/postgresql/meta/0002_snapshot.json +1552 -0
  227. package/dist/migrations/postgresql/meta/0003_snapshot.json +1695 -0
  228. package/dist/migrations/postgresql/meta/0010_snapshot.json +2345 -0
  229. package/dist/migrations/postgresql/meta/_journal.json +90 -0
  230. package/dist/migrations/sqlite/0000_api_keys.sql +34 -0
  231. package/dist/migrations/sqlite/0001_general_settings.sql +20 -0
  232. package/dist/migrations/sqlite/0002_site_settings_logo_url.sql +9 -0
  233. package/dist/migrations/sqlite/0003_activity_log.sql +29 -0
  234. package/dist/migrations/sqlite/0004_image_sizes_and_focal_point.sql +29 -0
  235. package/dist/migrations/sqlite/0004_site_settings_sidebar.sql +11 -0
  236. package/dist/migrations/sqlite/0005_user_brute_force_protection.sql +29 -0
  237. package/dist/migrations/sqlite/0006_email_template_attachments.sql +12 -0
  238. package/dist/migrations/sqlite/0007_media_uploaded_by_nullable.sql +111 -0
  239. package/dist/migrations/sqlite/20260429_000000_000_initial_journal.sql +24 -0
  240. package/dist/migrations/sqlite/20260501_000000_journal_batch.sql +19 -0
  241. package/dist/migrations/sqlite/20260501_000001_audit_log.sql +24 -0
  242. package/dist/migrations/sqlite/20260504_000000_nextly_meta.sql +21 -0
  243. package/dist/migrations/sqlite/20260505_000000_user_management_tables.sql +77 -0
  244. package/dist/next.d.ts +57 -0
  245. package/dist/next.mjs +55 -0
  246. package/dist/observability/index.d.ts +87 -0
  247. package/dist/observability/index.mjs +57 -0
  248. package/dist/permissions-3DZZQZMI.mjs +39 -0
  249. package/dist/pipeline-YOML7SWF.mjs +29 -0
  250. package/dist/preview-ZZTR3QGS.mjs +9 -0
  251. package/dist/program-PW6UB2ZC.mjs +5934 -0
  252. package/dist/reconcile-single-tables-7ENVXJGB.mjs +7 -0
  253. package/dist/register-SF6E6FVU.mjs +49 -0
  254. package/dist/reload-config-HWQ4G5MM.mjs +23 -0
  255. package/dist/resolve-single-table-name-JSOMUB3R.mjs +7 -0
  256. package/dist/routeHandler-UNMMJIBM.mjs +77 -0
  257. package/dist/runtime-schema-generator-NRA6A6Z6.mjs +8 -0
  258. package/dist/runtime.d.ts +120 -0
  259. package/dist/runtime.mjs +73 -0
  260. package/dist/schema-hash-FMMG6VPJ.mjs +13 -0
  261. package/dist/schema-registry-EQ36FZDP.mjs +7 -0
  262. package/dist/scripts/load-env.mjs +42 -0
  263. package/dist/storage/index.d.ts +566 -0
  264. package/dist/storage/index.mjs +45 -0
  265. package/dist/super-admin-G5ZK5F4T.mjs +39 -0
  266. package/dist/system-table-service-WGSRVEGT.mjs +17 -0
  267. package/dist/users-7KELGRYJ.mjs +38 -0
  268. package/package.json +308 -9
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Health Check Route Handlers for Next.js
3
+ *
4
+ * These route handlers can be re-exported in your Next.js application to provide
5
+ * a production-ready health check endpoint at /api/health.
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * // In your Next.js app: app/api/health/route.ts
10
+ * export { GET, HEAD } from 'nextly/api/health';
11
+ * ```
12
+ *
13
+ * @module api/health
14
+ */
15
+ /**
16
+ * GET handler for health check endpoint.
17
+ *
18
+ * Returns the current database/runtime health as a bare object body via
19
+ * `respondData`. The body merges the database probe with the package
20
+ * version and process uptime so monitoring dashboards have a
21
+ * non-Boolean-only payload to assert against (spec §5.1 rule 3 / §7.7).
22
+ * When the underlying check reports `ok: false`, the handler throws a 503
23
+ * `SERVICE_UNAVAILABLE` `NextlyError` so the route boundary serializes it
24
+ * as `application/problem+json`. The unhealthy detail (latency, dialect,
25
+ * error string) is logged via `logContext` rather than echoed to the
26
+ * public response; anonymous monitoring scrapers should not learn
27
+ * implementation specifics.
28
+ *
29
+ * Response Codes:
30
+ * - 200 OK: Database is healthy. Body:
31
+ * `{ ok, version, uptime, timestamp, database }`.
32
+ * - 503 Service Unavailable: Database is unreachable or unhealthy. Body:
33
+ * `{ error: { code: "SERVICE_UNAVAILABLE", message, requestId } }`.
34
+ *
35
+ * @example
36
+ * ```bash
37
+ * curl http://localhost:3000/api/health
38
+ * # => {"ok":true,"version":"0.0.142","uptime":123,"timestamp":"...","database":{...}}
39
+ * ```
40
+ */
41
+ declare const GET: (_request: Request) => Promise<Response>;
42
+ /**
43
+ * HEAD handler for lightweight health check.
44
+ *
45
+ * Returns only the HTTP status code and headers without body content. Useful
46
+ * for monitoring systems that only need to verify the endpoint is responding.
47
+ * HEAD is intentionally not wrapped in `withErrorHandler` because the wrapper
48
+ * always emits a JSON body on the error path, which violates HEAD semantics
49
+ * (per RFC 9110 HEAD responses must not include a body). Unexpected throws
50
+ * propagate to Next.js's runtime; in production this surfaces as a 500 with
51
+ * no body, matching the pre-migration behavior.
52
+ *
53
+ * `X-Request-Id` is set so log lines emitted by `healthCheck()` can be
54
+ * correlated to a probe even though HEAD bypasses the route boundary.
55
+ *
56
+ * Response Codes:
57
+ * - 200 OK: Database is healthy
58
+ * - 503 Service Unavailable: Database is unhealthy
59
+ *
60
+ * @example
61
+ * ```bash
62
+ * curl -I http://localhost:3000/api/health
63
+ * # => HTTP/1.1 200 OK
64
+ * ```
65
+ */
66
+ declare function HEAD(request: Request): Promise<Response>;
67
+
68
+ export { GET, HEAD };
@@ -0,0 +1,67 @@
1
+ import {
2
+ withErrorHandler
3
+ } from "../chunk-TO5AFLVQ.mjs";
4
+ import {
5
+ readOrGenerateRequestId
6
+ } from "../chunk-67GXH6PR.mjs";
7
+ import "../chunk-2TFX4ND3.mjs";
8
+ import "../chunk-W4MGXIRR.mjs";
9
+ import {
10
+ respondData
11
+ } from "../chunk-IUDOC7N7.mjs";
12
+ import {
13
+ healthCheck
14
+ } from "../chunk-LAZXX4HR.mjs";
15
+ import "../chunk-D5HQBNUB.mjs";
16
+ import {
17
+ NextlyError
18
+ } from "../chunk-NRUWQ5Z7.mjs";
19
+ import "../chunk-7P6ASYW6.mjs";
20
+
21
+ // src/api/health.ts
22
+ var PACKAGE_VERSION = (
23
+ // eslint-disable-next-line turbo/no-undeclared-env-vars
24
+ typeof process !== "undefined" && process.env?.npm_package_version || "unknown"
25
+ );
26
+ function readUptimeSeconds() {
27
+ if (typeof process === "undefined" || typeof process.uptime !== "function") {
28
+ return 0;
29
+ }
30
+ return Math.floor(process.uptime());
31
+ }
32
+ var HEALTH_CHECK_CACHE_SECONDS = typeof process !== "undefined" && process.env?.HEALTH_CHECK_CACHE_SECONDS ? Number(process.env.HEALTH_CHECK_CACHE_SECONDS) : 60;
33
+ var HEALTH_CACHE_CONTROL = `public, max-age=${HEALTH_CHECK_CACHE_SECONDS}, stale-while-revalidate=30`;
34
+ var GET = withErrorHandler(async (_request) => {
35
+ const health = await healthCheck();
36
+ if (!health.ok) {
37
+ throw NextlyError.serviceUnavailable({
38
+ logMessage: "Health check failed",
39
+ logContext: { health }
40
+ });
41
+ }
42
+ return respondData(
43
+ {
44
+ ...health,
45
+ version: PACKAGE_VERSION,
46
+ uptime: readUptimeSeconds()
47
+ },
48
+ {
49
+ headers: { "Cache-Control": HEALTH_CACHE_CONTROL }
50
+ }
51
+ );
52
+ });
53
+ async function HEAD(request) {
54
+ const requestId = readOrGenerateRequestId(request);
55
+ const health = await healthCheck();
56
+ return new Response(null, {
57
+ status: health.ok ? 200 : 503,
58
+ headers: {
59
+ "Cache-Control": HEALTH_CACHE_CONTROL,
60
+ "X-Request-Id": requestId
61
+ }
62
+ });
63
+ }
64
+ export {
65
+ GET,
66
+ HEAD
67
+ };
@@ -0,0 +1,54 @@
1
+ import { O as OnErrorHook } from '../_dts-chunks/on-error.d-CHIKWNxd.d.ts';
2
+ import '../errors/index.d.ts';
3
+
4
+ type WithErrorHandlerOptions = {
5
+ /** Per-call observability hook. Fired before the global hook. */
6
+ onError?: OnErrorHook;
7
+ /** Public message used when wrapping unknown errors. Default: generic. */
8
+ internalErrorMessage?: string;
9
+ };
10
+ /**
11
+ * HTTP boundary wrapper for Next.js App Router Route Handlers.
12
+ *
13
+ * Responsibilities (in order, per spec §11.2):
14
+ * 1. Read or generate a Stripe-style `requestId` for this request.
15
+ * 2. Run the handler.
16
+ * 3. On thrown values: pass Next.js sentinel errors (`redirect`, `notFound`,
17
+ * dynamic-API bailouts) through `unstable_rethrow` first.
18
+ * 4. Otherwise classify: `NextlyError` directly, `DbError` via the safety
19
+ * net, anything else wrapped as `NextlyError.internal`.
20
+ * 5. Log the classified error.
21
+ * 6. Fire the per-call `onError` hook, then the global one. Hook failures
22
+ * are logged but never poison the response.
23
+ * 7. Serialize via `toResponseJSON(requestId)` with `application/problem+json`
24
+ * content type, the response status, and `X-Request-Id`. `Retry-After`
25
+ * is set for `RATE_LIMITED`.
26
+ *
27
+ * Generic over `TArgs` so it transparently supports both static handlers
28
+ * (`(req)`) and dynamic-segment handlers (`(req, { params })`).
29
+ */
30
+ declare function withErrorHandler<TArgs extends unknown[]>(handler: (...args: TArgs) => Promise<Response>, options?: WithErrorHandlerOptions): (...args: TArgs) => Promise<Response>;
31
+
32
+ /**
33
+ * Stripe-style request IDs (`req_<16 base32 chars>`) for the unified error
34
+ * system. Generated at the boundary by withErrorHandler / withAction unless
35
+ * an upstream proxy already set `x-request-id` (or one of the cloud-provider
36
+ * variants Vercel and Cloudflare emit), in which case we honor it so a
37
+ * single user request shares one id across all hops.
38
+ *
39
+ * Format: `req_` prefix + 16 chars of RFC 4648 base32-lowercase. 10 random
40
+ * bytes provide 80 bits of entropy — uniquely identifying every request at
41
+ * any reasonable scale.
42
+ *
43
+ * Works in both Node and Edge runtimes (uses Web Crypto's
44
+ * `crypto.getRandomValues`).
45
+ */
46
+ declare function generateRequestId(): string;
47
+ /**
48
+ * Read an upstream-set request id, falling back to a freshly generated one.
49
+ * Header precedence (most-specific first): `x-request-id` (our convention) >
50
+ * `x-vercel-id` (Vercel) > `cf-ray` (Cloudflare).
51
+ */
52
+ declare function readOrGenerateRequestId(req: Request): string;
53
+
54
+ export { generateRequestId, readOrGenerateRequestId, withErrorHandler };
@@ -0,0 +1,16 @@
1
+ import {
2
+ withErrorHandler
3
+ } from "../chunk-TO5AFLVQ.mjs";
4
+ import {
5
+ generateRequestId,
6
+ readOrGenerateRequestId
7
+ } from "../chunk-67GXH6PR.mjs";
8
+ import "../chunk-2TFX4ND3.mjs";
9
+ import "../chunk-W4MGXIRR.mjs";
10
+ import "../chunk-NRUWQ5Z7.mjs";
11
+ import "../chunk-7P6ASYW6.mjs";
12
+ export {
13
+ generateRequestId,
14
+ readOrGenerateRequestId,
15
+ withErrorHandler
16
+ };
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Bulk Media API Route Handlers for Next.js
3
+ *
4
+ * These route handlers provide bulk operations for media management.
5
+ * Supports bulk upload and bulk delete with parallel processing.
6
+ *
7
+ * IMPORTANT: Before using these routes, you must initialize the service layer by calling
8
+ * `registerServices()` during your application startup.
9
+ *
10
+ * Wire shape:
11
+ * - DELETE returns the canonical respondBulk envelope:
12
+ * `{ message, items, errors }` where items are minimal `{id}` records
13
+ * for deleted files and errors are id-keyed PerItemError entries.
14
+ * - POST returns the canonical respondBulkUpload envelope:
15
+ * `{ message, items, errors }` where items are full MediaFile records
16
+ * for newly-uploaded files and errors are positional BulkUploadError
17
+ * entries (`{ index, filename, code, message }`).
18
+ *
19
+ * Per-item failures are first-class data in the body's `errors` array
20
+ * (HTTP 200). 4xx is reserved for malformed requests (e.g. empty input,
21
+ * all entries failed input validation before the service was reached).
22
+ *
23
+ * @example
24
+ * ```typescript
25
+ * // In your Next.js app: app/api/media/bulk/route.ts
26
+ * export { POST, DELETE } from 'nextly/api/media-bulk';
27
+ * ```
28
+ *
29
+ * @module api/media-bulk
30
+ */
31
+ /**
32
+ * POST handler for bulk media upload.
33
+ *
34
+ * Uploads multiple files. Provides detailed per-file results, positional
35
+ * (index + filename) for failures since uploads have no client-supplied id.
36
+ *
37
+ * Request Body (JSON):
38
+ * {
39
+ * files: Array<{
40
+ * file: string (base64),
41
+ * filename: string,
42
+ * mimeType: string,
43
+ * size: number,
44
+ * uploadedBy: string
45
+ * }>,
46
+ * uploadedBy?: string,
47
+ * }
48
+ *
49
+ * Response: canonical respondBulkUpload envelope `{ message, items, errors }`.
50
+ * Items are full MediaFile records for newly-uploaded files; errors are
51
+ * positional BulkUploadError entries. Pre-upload validation failures fold
52
+ * into the same `errors` array (no parallel `validationErrors` field;
53
+ * unified failure list). Status 200 for partial-success.
54
+ *
55
+ * 4xx applies only to fully-malformed requests: empty `files` array, or
56
+ * every entry failed input validation (no useful service work to do).
57
+ */
58
+ declare const POST: (request: Request) => Promise<Response>;
59
+ /**
60
+ * DELETE handler for bulk media deletion.
61
+ *
62
+ * Response: canonical respondBulk envelope `{ message, items, errors }`.
63
+ * Items are minimal `{id}` records (the files are gone); errors are
64
+ * id-keyed PerItemError entries. Status 200 for partial-success; 400
65
+ * only for an empty/malformed `mediaIds` array.
66
+ *
67
+ * Request Body (JSON):
68
+ * {
69
+ * mediaIds: string[]
70
+ * }
71
+ */
72
+ declare const DELETE: (request: Request) => Promise<Response>;
73
+
74
+ export { DELETE, POST };
@@ -0,0 +1,196 @@
1
+ import {
2
+ readJsonBody
3
+ } from "../chunk-VQJQHVEV.mjs";
4
+ import "../chunk-VWF3JO32.mjs";
5
+ import {
6
+ withErrorHandler
7
+ } from "../chunk-TO5AFLVQ.mjs";
8
+ import {
9
+ getService,
10
+ isServicesRegistered
11
+ } from "../chunk-X7TXCYYN.mjs";
12
+ import "../chunk-YZNBLFIW.mjs";
13
+ import "../chunk-FQULBZ53.mjs";
14
+ import "../chunk-67GXH6PR.mjs";
15
+ import "../chunk-2TFX4ND3.mjs";
16
+ import "../chunk-W4MGXIRR.mjs";
17
+ import {
18
+ UploadMediaInputSchema
19
+ } from "../chunk-NSEFNNU4.mjs";
20
+ import "../chunk-3FA7FKAV.mjs";
21
+ import "../chunk-AGJ6F2T3.mjs";
22
+ import "../chunk-KIMNCZGV.mjs";
23
+ import "../chunk-AK6Z23OX.mjs";
24
+ import "../chunk-INV7QKLG.mjs";
25
+ import "../chunk-GZ6DCQKC.mjs";
26
+ import "../chunk-SBACDPNX.mjs";
27
+ import "../chunk-RJLLGGPG.mjs";
28
+ import "../chunk-V4EQTOA4.mjs";
29
+ import "../chunk-I4JMR3UR.mjs";
30
+ import "../chunk-XZKLBMN6.mjs";
31
+ import "../chunk-IZWPRDC3.mjs";
32
+ import "../chunk-DNNG377Z.mjs";
33
+ import "../chunk-5HMZ644B.mjs";
34
+ import "../chunk-W5KKPZT5.mjs";
35
+ import "../chunk-56WO4WX7.mjs";
36
+ import "../chunk-2W3DVD7S.mjs";
37
+ import "../chunk-TS7GHTG2.mjs";
38
+ import "../chunk-H26B4FYG.mjs";
39
+ import "../chunk-DP3G27G5.mjs";
40
+ import "../chunk-DV6WVX2Q.mjs";
41
+ import "../chunk-UJ2IMJ4W.mjs";
42
+ import "../chunk-EGXBZCGC.mjs";
43
+ import "../chunk-G2AA4QLC.mjs";
44
+ import "../chunk-4MJLT6PZ.mjs";
45
+ import {
46
+ respondBulk,
47
+ respondBulkUpload
48
+ } from "../chunk-IUDOC7N7.mjs";
49
+ import "../chunk-LAZXX4HR.mjs";
50
+ import "../chunk-D5HQBNUB.mjs";
51
+ import {
52
+ NextlyError
53
+ } from "../chunk-NRUWQ5Z7.mjs";
54
+ import "../chunk-VTJADRO3.mjs";
55
+ import "../chunk-5APFUGAD.mjs";
56
+ import "../chunk-7P6ASYW6.mjs";
57
+
58
+ // src/api/media-bulk.ts
59
+ function getMediaService() {
60
+ if (!isServicesRegistered()) {
61
+ throw NextlyError.serviceUnavailable({
62
+ logMessage: "Media bulk handler called before registerServices()",
63
+ logContext: {
64
+ hint: "Call registerServices() before mounting media-bulk routes. See https://nextlyhq.com/docs/initialization"
65
+ }
66
+ });
67
+ }
68
+ return getService("mediaService");
69
+ }
70
+ function createAuthenticatedContext(userId) {
71
+ if (!userId) return {};
72
+ return {
73
+ user: {
74
+ id: userId,
75
+ email: `${userId}@api.local`,
76
+ role: "user",
77
+ permissions: []
78
+ }
79
+ };
80
+ }
81
+ var POST = withErrorHandler(
82
+ async (request) => {
83
+ const mediaService = getMediaService();
84
+ const body = await readJsonBody(request);
85
+ const filesInput = body.files;
86
+ const uploadedBy = typeof body.uploadedBy === "string" ? body.uploadedBy : void 0;
87
+ if (!Array.isArray(filesInput) || filesInput.length === 0) {
88
+ throw NextlyError.validation({
89
+ errors: [
90
+ {
91
+ path: "files",
92
+ code: "required_array",
93
+ message: "files must be a non-empty array."
94
+ }
95
+ ]
96
+ });
97
+ }
98
+ const validatedFiles = [];
99
+ const failures = [];
100
+ for (let i = 0; i < filesInput.length; i++) {
101
+ const file = filesInput[i];
102
+ const filename = file.filename || `file-${i}`;
103
+ let buffer;
104
+ if (typeof file.file === "string") {
105
+ buffer = Buffer.from(file.file, "base64");
106
+ } else if (Buffer.isBuffer(file.file)) {
107
+ buffer = file.file;
108
+ } else {
109
+ failures.push({
110
+ index: i,
111
+ filename,
112
+ code: "VALIDATION_ERROR",
113
+ message: "Invalid file format."
114
+ });
115
+ continue;
116
+ }
117
+ const parseResult = UploadMediaInputSchema.safeParse({
118
+ file: buffer,
119
+ filename: file.filename,
120
+ mimeType: file.mimeType,
121
+ size: file.size || buffer.length,
122
+ uploadedBy: file.uploadedBy || uploadedBy
123
+ });
124
+ if (!parseResult.success) {
125
+ failures.push({
126
+ index: i,
127
+ filename,
128
+ code: "VALIDATION_ERROR",
129
+ message: "Validation failed."
130
+ });
131
+ } else {
132
+ validatedFiles.push({
133
+ buffer,
134
+ filename: file.filename,
135
+ mimeType: file.mimeType,
136
+ size: file.size || buffer.length,
137
+ originalIndex: i
138
+ });
139
+ }
140
+ }
141
+ if (validatedFiles.length === 0) {
142
+ throw NextlyError.validation({
143
+ errors: failures.map((f) => ({
144
+ path: `files[${f.index}]`,
145
+ code: "INVALID_FILE",
146
+ message: f.message
147
+ })),
148
+ logContext: { totalFiles: filesInput.length }
149
+ });
150
+ }
151
+ const firstFile = filesInput[0];
152
+ const userId = firstFile.uploadedBy || uploadedBy || null;
153
+ const context = createAuthenticatedContext(userId);
154
+ const serviceInputs = validatedFiles.map(({ originalIndex: _, ...rest }) => rest);
155
+ const result = await mediaService.bulkUpload(serviceInputs, context);
156
+ for (const f of result.failures) {
157
+ const original = validatedFiles[f.index];
158
+ failures.push({
159
+ index: original?.originalIndex ?? f.index,
160
+ filename: f.filename,
161
+ code: f.code,
162
+ message: f.message
163
+ });
164
+ }
165
+ const totalRequested = filesInput.length;
166
+ const successCount = result.successCount;
167
+ const message = failures.length === 0 ? `Uploaded ${successCount} ${successCount === 1 ? "file" : "files"}.` : `Uploaded ${successCount} of ${totalRequested} files.`;
168
+ return respondBulkUpload(message, result.successes, failures);
169
+ }
170
+ );
171
+ var DELETE = withErrorHandler(
172
+ async (request) => {
173
+ const mediaService = getMediaService();
174
+ const body = await readJsonBody(request);
175
+ const mediaIds = body.mediaIds;
176
+ if (!Array.isArray(mediaIds) || mediaIds.length === 0) {
177
+ throw NextlyError.validation({
178
+ errors: [
179
+ {
180
+ path: "mediaIds",
181
+ code: "required_array",
182
+ message: "mediaIds must be a non-empty array."
183
+ }
184
+ ]
185
+ });
186
+ }
187
+ const context = {};
188
+ const result = await mediaService.bulkDelete(mediaIds, context);
189
+ const message = result.failures.length === 0 ? `Deleted ${result.successCount} ${result.successCount === 1 ? "file" : "files"}.` : `Deleted ${result.successCount} of ${result.total} files.`;
190
+ return respondBulk(message, result.successes, result.failures);
191
+ }
192
+ );
193
+ export {
194
+ DELETE,
195
+ POST
196
+ };
@@ -0,0 +1,112 @@
1
+ import { NextRequest } from 'next/server';
2
+
3
+ /**
4
+ * Media Folders API Route Handlers
5
+ *
6
+ * Next.js App Router compatible handlers for folder management operations.
7
+ * Re-export these handlers in your app's API routes.
8
+ *
9
+ * **IMPORTANT:** For storage plugins to work, initialize Nextly with your config
10
+ * via instrumentation.ts before these routes are called.
11
+ *
12
+ * @example
13
+ * ```typescript
14
+ * // app/api/media/folders/route.ts
15
+ * export { GET, POST } from 'nextly/api/media-folders';
16
+ *
17
+ * // app/api/media/folders/[id]/route.ts
18
+ * export { getFolderById as GET, updateFolder as PATCH, deleteFolder as DELETE } from 'nextly/api/media-folders';
19
+ *
20
+ * // app/api/media/folders/[id]/contents/route.ts
21
+ * export { getFolderContents as GET } from 'nextly/api/media-folders';
22
+ *
23
+ * // app/api/media/folders/root/contents/route.ts
24
+ * export { getRootFolderContents as GET } from 'nextly/api/media-folders';
25
+ * ```
26
+ */
27
+
28
+ /**
29
+ * GET /api/media/folders
30
+ *
31
+ * List folders with optional filtering:
32
+ * - ?root=true - List only root folders (no parent)
33
+ * - ?parentId=xxx - List subfolders of a specific parent
34
+ *
35
+ * Response: `{ "folders": Folder[] }` (non-paginated; respondData with a
36
+ * named field).
37
+ */
38
+ declare const GET: (request: NextRequest) => Promise<Response>;
39
+ /**
40
+ * POST /api/media/folders
41
+ *
42
+ * Create a new folder
43
+ *
44
+ * Request Body:
45
+ * - name: string (required)
46
+ * - description?: string
47
+ * - color?: string
48
+ * - icon?: string
49
+ * - parentId?: string | null
50
+ * - createdBy: string (required)
51
+ *
52
+ * Response: `{ "message", "item": Folder }` (status 201).
53
+ */
54
+ declare const POST: (request: NextRequest) => Promise<Response>;
55
+ /**
56
+ * GET /api/media/folders/[id]
57
+ *
58
+ * Get folder by ID
59
+ */
60
+ declare function getFolderById(request: NextRequest, routeContext: {
61
+ params: Promise<{
62
+ id: string;
63
+ }>;
64
+ }): Promise<Response>;
65
+ /**
66
+ * PATCH /api/media/folders/[id]
67
+ *
68
+ * Update folder metadata
69
+ *
70
+ * Request Body:
71
+ * - name?: string
72
+ * - description?: string
73
+ * - color?: string
74
+ * - icon?: string
75
+ * - parentId?: string | null
76
+ */
77
+ declare function updateFolder(request: NextRequest, routeContext: {
78
+ params: Promise<{
79
+ id: string;
80
+ }>;
81
+ }): Promise<Response>;
82
+ /**
83
+ * DELETE /api/media/folders/[id]
84
+ *
85
+ * Delete folder
86
+ * Query params: ?deleteContents=true/false
87
+ *
88
+ * Response: `{ "message", "id" }` (respondAction; service returns void).
89
+ */
90
+ declare function deleteFolder(request: NextRequest, routeContext: {
91
+ params: Promise<{
92
+ id: string;
93
+ }>;
94
+ }): Promise<Response>;
95
+ /**
96
+ * GET /api/media/folders/[id]/contents
97
+ *
98
+ * Get folder contents (subfolders + media files)
99
+ */
100
+ declare function getFolderContents(request: NextRequest, routeContext: {
101
+ params: Promise<{
102
+ id: string;
103
+ }>;
104
+ }): Promise<Response>;
105
+ /**
106
+ * GET /api/media/folders/root/contents
107
+ *
108
+ * Get root folder contents (folders + media without a folder)
109
+ */
110
+ declare const getRootFolderContents: (_request: NextRequest) => Promise<Response>;
111
+
112
+ export { GET, POST, deleteFolder, getFolderById, getFolderContents, getRootFolderContents, updateFolder };