@nextsparkjs/core 0.1.0-beta.92 → 0.1.0-beta.94

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 (341) hide show
  1. package/dist/components/dashboard/block-editor/array-field.d.ts.map +1 -1
  2. package/dist/components/dashboard/block-editor/array-field.js +55 -3
  3. package/dist/components/dashboard/block-editor/dynamic-form.d.ts.map +1 -1
  4. package/dist/components/dashboard/block-editor/dynamic-form.js +82 -2
  5. package/dist/components/dashboard/navigation/DynamicNavigation.d.ts.map +1 -1
  6. package/dist/components/dashboard/navigation/DynamicNavigation.js +7 -1
  7. package/dist/components/devtools/scheduled-actions/actions-table.d.ts +1 -0
  8. package/dist/components/devtools/scheduled-actions/actions-table.d.ts.map +1 -1
  9. package/dist/components/devtools/scheduled-actions/actions-table.js +182 -46
  10. package/dist/components/devtools/scheduled-actions/types.d.ts +1 -0
  11. package/dist/components/devtools/scheduled-actions/types.d.ts.map +1 -1
  12. package/dist/components/media/MediaCard.d.ts +23 -0
  13. package/dist/components/media/MediaCard.d.ts.map +1 -0
  14. package/dist/components/media/MediaCard.js +154 -0
  15. package/dist/components/media/MediaDetailPanel.d.ts +17 -0
  16. package/dist/components/media/MediaDetailPanel.d.ts.map +1 -0
  17. package/dist/components/media/MediaDetailPanel.js +331 -0
  18. package/dist/components/media/MediaGrid.d.ts +26 -0
  19. package/dist/components/media/MediaGrid.d.ts.map +1 -0
  20. package/dist/components/media/MediaGrid.js +77 -0
  21. package/dist/components/media/MediaLibrary.d.ts +20 -0
  22. package/dist/components/media/MediaLibrary.d.ts.map +1 -0
  23. package/dist/components/media/MediaLibrary.js +229 -0
  24. package/dist/components/media/MediaList.d.ts +24 -0
  25. package/dist/components/media/MediaList.d.ts.map +1 -0
  26. package/dist/components/media/MediaList.js +181 -0
  27. package/dist/components/media/MediaSelector.d.ts +19 -0
  28. package/dist/components/media/MediaSelector.d.ts.map +1 -0
  29. package/dist/components/media/MediaSelector.js +145 -0
  30. package/dist/components/media/MediaTagFilter.d.ts +16 -0
  31. package/dist/components/media/MediaTagFilter.d.ts.map +1 -0
  32. package/dist/components/media/MediaTagFilter.js +122 -0
  33. package/dist/components/media/MediaToolbar.d.ts +25 -0
  34. package/dist/components/media/MediaToolbar.d.ts.map +1 -0
  35. package/dist/components/media/MediaToolbar.js +136 -0
  36. package/dist/components/media/MediaUploadZone.d.ts +19 -0
  37. package/dist/components/media/MediaUploadZone.d.ts.map +1 -0
  38. package/dist/components/media/MediaUploadZone.js +248 -0
  39. package/dist/components/media/index.d.ts +15 -0
  40. package/dist/components/media/index.d.ts.map +1 -0
  41. package/dist/components/media/index.js +20 -0
  42. package/dist/contexts/TeamContext.js +1 -1
  43. package/dist/hooks/index.d.ts +2 -0
  44. package/dist/hooks/index.d.ts.map +1 -1
  45. package/dist/hooks/index.js +2 -0
  46. package/dist/hooks/useEnsureUserMetadata.d.ts +4 -0
  47. package/dist/hooks/useEnsureUserMetadata.d.ts.map +1 -1
  48. package/dist/hooks/useEnsureUserMetadata.js +85 -60
  49. package/dist/hooks/useEntityMutations.d.ts.map +1 -1
  50. package/dist/hooks/useEntityMutations.js +5 -9
  51. package/dist/hooks/useMedia.d.ts +56 -0
  52. package/dist/hooks/useMedia.d.ts.map +1 -0
  53. package/dist/hooks/useMedia.js +181 -0
  54. package/dist/hooks/useMediaUpload.d.ts +27 -0
  55. package/dist/hooks/useMediaUpload.d.ts.map +1 -0
  56. package/dist/hooks/useMediaUpload.js +36 -0
  57. package/dist/hooks/useUserSettings.d.ts +5 -4
  58. package/dist/hooks/useUserSettings.d.ts.map +1 -1
  59. package/dist/hooks/useUserSettings.js +42 -40
  60. package/dist/index.d.ts +1 -1
  61. package/dist/index.d.ts.map +1 -1
  62. package/dist/index.js +2 -3
  63. package/dist/lib/api/auth/dual-auth.d.ts +6 -2
  64. package/dist/lib/api/auth/dual-auth.d.ts.map +1 -1
  65. package/dist/lib/api/auth/dual-auth.js +5 -9
  66. package/dist/lib/api/entity/generic-handler.d.ts.map +1 -1
  67. package/dist/lib/api/entity/generic-handler.js +3 -3
  68. package/dist/lib/config/app.config.d.ts.map +1 -1
  69. package/dist/lib/config/app.config.js +37 -0
  70. package/dist/lib/config/config-sync.d.ts +1 -0
  71. package/dist/lib/config/config-sync.d.ts.map +1 -1
  72. package/dist/lib/config/config-sync.js +2 -0
  73. package/dist/lib/config/types.d.ts +29 -0
  74. package/dist/lib/config/types.d.ts.map +1 -1
  75. package/dist/lib/media/schemas.d.ts +39 -0
  76. package/dist/lib/media/schemas.d.ts.map +1 -0
  77. package/dist/lib/media/schemas.js +32 -0
  78. package/dist/lib/media/types.d.ts +69 -0
  79. package/dist/lib/media/types.d.ts.map +1 -0
  80. package/dist/lib/media/types.js +0 -0
  81. package/dist/lib/media/utils.d.ts +26 -0
  82. package/dist/lib/media/utils.d.ts.map +1 -0
  83. package/dist/lib/media/utils.js +33 -0
  84. package/dist/lib/rate-limit-redis.d.ts.map +1 -1
  85. package/dist/lib/rate-limit-redis.js +13 -4
  86. package/dist/lib/scheduled-actions/initializer.d.ts +6 -3
  87. package/dist/lib/scheduled-actions/initializer.d.ts.map +1 -1
  88. package/dist/lib/scheduled-actions/initializer.js +11 -6
  89. package/dist/lib/scheduled-actions/processor.d.ts +20 -4
  90. package/dist/lib/scheduled-actions/processor.d.ts.map +1 -1
  91. package/dist/lib/scheduled-actions/processor.js +128 -34
  92. package/dist/lib/scheduled-actions/registry.d.ts +3 -0
  93. package/dist/lib/scheduled-actions/registry.d.ts.map +1 -1
  94. package/dist/lib/scheduled-actions/registry.js +2 -1
  95. package/dist/lib/scheduled-actions/scheduler.d.ts +1 -1
  96. package/dist/lib/scheduled-actions/scheduler.d.ts.map +1 -1
  97. package/dist/lib/scheduled-actions/scheduler.js +76 -38
  98. package/dist/lib/scheduled-actions/types.d.ts +73 -0
  99. package/dist/lib/scheduled-actions/types.d.ts.map +1 -1
  100. package/dist/lib/selectors/core-selectors.d.ts +102 -0
  101. package/dist/lib/selectors/core-selectors.d.ts.map +1 -1
  102. package/dist/lib/selectors/core-selectors.js +3 -1
  103. package/dist/lib/selectors/domains/block-editor.selectors.d.ts +8 -0
  104. package/dist/lib/selectors/domains/block-editor.selectors.d.ts.map +1 -1
  105. package/dist/lib/selectors/domains/block-editor.selectors.js +9 -0
  106. package/dist/lib/selectors/domains/devtools.selectors.d.ts +6 -0
  107. package/dist/lib/selectors/domains/devtools.selectors.d.ts.map +1 -1
  108. package/dist/lib/selectors/domains/devtools.selectors.js +6 -0
  109. package/dist/lib/selectors/domains/index.d.ts +1 -0
  110. package/dist/lib/selectors/domains/index.d.ts.map +1 -1
  111. package/dist/lib/selectors/domains/index.js +2 -0
  112. package/dist/lib/selectors/domains/media.selectors.d.ts +96 -0
  113. package/dist/lib/selectors/domains/media.selectors.d.ts.map +1 -0
  114. package/dist/lib/selectors/domains/media.selectors.js +103 -0
  115. package/dist/lib/selectors/selectors.d.ts +204 -0
  116. package/dist/lib/selectors/selectors.d.ts.map +1 -1
  117. package/dist/lib/services/index.d.ts +2 -0
  118. package/dist/lib/services/index.d.ts.map +1 -1
  119. package/dist/lib/services/index.js +2 -0
  120. package/dist/lib/services/media.service.d.ts +158 -0
  121. package/dist/lib/services/media.service.d.ts.map +1 -0
  122. package/dist/lib/services/media.service.js +410 -0
  123. package/dist/messages/de/devtools.json +16 -0
  124. package/dist/messages/de/index.d.ts +16 -0
  125. package/dist/messages/de/index.d.ts.map +1 -1
  126. package/dist/messages/en/admin.json +4 -1
  127. package/dist/messages/en/devtools.json +16 -0
  128. package/dist/messages/en/index.d.ts +167 -0
  129. package/dist/messages/en/index.d.ts.map +1 -1
  130. package/dist/messages/en/index.js +2 -0
  131. package/dist/messages/en/index.ts +2 -0
  132. package/dist/messages/en/media.json +147 -0
  133. package/dist/messages/en/navigation.json +1 -0
  134. package/dist/messages/es/admin.json +4 -1
  135. package/dist/messages/es/devtools.json +16 -0
  136. package/dist/messages/es/index.d.ts +167 -0
  137. package/dist/messages/es/index.d.ts.map +1 -1
  138. package/dist/messages/es/index.js +2 -0
  139. package/dist/messages/es/index.ts +2 -0
  140. package/dist/messages/es/media.json +147 -0
  141. package/dist/messages/es/navigation.json +1 -0
  142. package/dist/messages/fr/devtools.json +16 -0
  143. package/dist/messages/fr/index.d.ts +16 -0
  144. package/dist/messages/fr/index.d.ts.map +1 -1
  145. package/dist/messages/it/devtools.json +16 -0
  146. package/dist/messages/it/index.d.ts +16 -0
  147. package/dist/messages/it/index.d.ts.map +1 -1
  148. package/dist/messages/pt/devtools.json +16 -0
  149. package/dist/messages/pt/index.d.ts +16 -0
  150. package/dist/messages/pt/index.d.ts.map +1 -1
  151. package/dist/migrations/017_scheduled_actions_table.sql +21 -0
  152. package/dist/migrations/021_media.sql +154 -0
  153. package/dist/migrations/090_sample_data.sql +53 -0
  154. package/dist/styles/classes.json +36 -3
  155. package/dist/styles/ui.css +1 -1
  156. package/dist/templates/app/api/devtools/config/entities/route.ts +18 -11
  157. package/dist/templates/app/api/devtools/config/theme/route.ts +5 -4
  158. package/dist/templates/app/api/devtools/tests/[...path]/route.ts +6 -5
  159. package/dist/templates/app/api/devtools/tests/route.ts +5 -4
  160. package/dist/templates/app/api/health/route.ts +6 -4
  161. package/dist/templates/app/api/internal/user-metadata/route.ts +3 -2
  162. package/dist/templates/app/api/superadmin/subscriptions/route.ts +5 -6
  163. package/dist/templates/app/api/superadmin/teams/[teamId]/route.ts +6 -7
  164. package/dist/templates/app/api/superadmin/teams/route.ts +5 -6
  165. package/dist/templates/app/api/superadmin/users/[userId]/route.ts +11 -16
  166. package/dist/templates/app/api/superadmin/users/route.ts +9 -10
  167. package/dist/templates/app/api/user/delete-account/route.ts +3 -2
  168. package/dist/templates/app/api/user/plan-flags/route.ts +11 -24
  169. package/dist/templates/app/api/user/profile/route.ts +7 -6
  170. package/dist/templates/app/api/v1/[entity]/[id]/child/[childType]/[childId]/route.ts +16 -18
  171. package/dist/templates/app/api/v1/[entity]/[id]/child/[childType]/route.ts +17 -19
  172. package/dist/templates/app/api/v1/[entity]/[id]/route.ts +10 -12
  173. package/dist/templates/app/api/v1/[entity]/route.ts +9 -11
  174. package/dist/templates/app/api/v1/api-keys/[id]/route.ts +9 -8
  175. package/dist/templates/app/api/v1/api-keys/route.ts +7 -6
  176. package/dist/templates/app/api/v1/auth/signup-with-invite/route.ts +3 -2
  177. package/dist/templates/app/api/v1/billing/cancel/route.ts +15 -14
  178. package/dist/templates/app/api/v1/billing/change-plan/route.ts +10 -9
  179. package/dist/templates/app/api/v1/billing/check-action/route.ts +8 -7
  180. package/dist/templates/app/api/v1/billing/checkout/route.ts +10 -9
  181. package/dist/templates/app/api/v1/billing/plans/route.ts +5 -4
  182. package/dist/templates/app/api/v1/billing/portal/route.ts +9 -8
  183. package/dist/templates/app/api/v1/blocks/[slug]/route.ts +4 -3
  184. package/dist/templates/app/api/v1/blocks/route.ts +3 -2
  185. package/dist/templates/app/api/v1/blocks/validate/route.ts +5 -3
  186. package/dist/templates/app/api/v1/cron/process/route.ts +4 -6
  187. package/dist/templates/app/api/v1/devtools/blocks/route.ts +3 -2
  188. package/dist/templates/app/api/v1/devtools/docs/route.ts +3 -2
  189. package/dist/templates/app/api/v1/devtools/features/route.ts +3 -2
  190. package/dist/templates/app/api/v1/devtools/flows/route.ts +3 -2
  191. package/dist/templates/app/api/v1/devtools/scheduled-actions/route.ts +125 -3
  192. package/dist/templates/app/api/v1/devtools/scheduled-actions/run/route.ts +110 -0
  193. package/dist/templates/app/api/v1/devtools/testing/route.ts +3 -2
  194. package/dist/templates/app/api/v1/media/[id]/route.ts +144 -0
  195. package/dist/templates/app/api/v1/media/[id]/tags/route.ts +154 -0
  196. package/dist/templates/app/api/v1/media/check-duplicates/route.ts +56 -0
  197. package/dist/templates/app/api/v1/media/route.ts +56 -0
  198. package/dist/templates/app/api/v1/media/upload/route.ts +157 -33
  199. package/dist/templates/app/api/v1/media-tags/route.ts +65 -0
  200. package/dist/templates/app/api/v1/plugin/[...path]/route.ts +16 -15
  201. package/dist/templates/app/api/v1/plugin/route.ts +3 -2
  202. package/dist/templates/app/api/v1/post-categories/[id]/route.ts +10 -9
  203. package/dist/templates/app/api/v1/post-categories/route.ts +5 -4
  204. package/dist/templates/app/api/v1/team-invitations/[token]/accept/route.ts +3 -3
  205. package/dist/templates/app/api/v1/team-invitations/[token]/decline/route.ts +3 -3
  206. package/dist/templates/app/api/v1/team-invitations/[token]/route.ts +3 -2
  207. package/dist/templates/app/api/v1/team-invitations/route.ts +3 -2
  208. package/dist/templates/app/api/v1/teams/[teamId]/invitations/route.ts +5 -4
  209. package/dist/templates/app/api/v1/teams/[teamId]/invoices/[invoiceNumber]/route.ts +3 -2
  210. package/dist/templates/app/api/v1/teams/[teamId]/invoices/route.ts +3 -2
  211. package/dist/templates/app/api/v1/teams/[teamId]/members/[memberId]/route.ts +5 -4
  212. package/dist/templates/app/api/v1/teams/[teamId]/members/route.ts +5 -5
  213. package/dist/templates/app/api/v1/teams/[teamId]/route.ts +31 -58
  214. package/dist/templates/app/api/v1/teams/[teamId]/subscription/route.ts +3 -2
  215. package/dist/templates/app/api/v1/teams/[teamId]/usage/[limitSlug]/route.ts +5 -4
  216. package/dist/templates/app/api/v1/teams/route.ts +18 -17
  217. package/dist/templates/app/api/v1/teams/switch/route.ts +3 -2
  218. package/dist/templates/app/api/v1/theme/[...path]/route.ts +16 -15
  219. package/dist/templates/app/api/v1/theme/route.ts +3 -2
  220. package/dist/templates/app/api/v1/users/[id]/meta/[key]/route.ts +7 -6
  221. package/dist/templates/app/api/v1/users/[id]/route.ts +9 -8
  222. package/dist/templates/app/api/v1/users/route.ts +7 -6
  223. package/dist/templates/app/dashboard/(main)/media/page.tsx +607 -0
  224. package/dist/templates/contents/themes/starter/messages/de/dev.json +106 -0
  225. package/dist/templates/contents/themes/starter/messages/de/index.ts +2 -0
  226. package/dist/templates/contents/themes/starter/messages/en/dev.json +106 -0
  227. package/dist/templates/contents/themes/starter/messages/en/index.ts +2 -0
  228. package/dist/templates/contents/themes/starter/messages/es/dev.json +106 -0
  229. package/dist/templates/contents/themes/starter/messages/es/index.ts +2 -0
  230. package/dist/templates/contents/themes/starter/messages/fr/dev.json +106 -0
  231. package/dist/templates/contents/themes/starter/messages/fr/index.ts +2 -0
  232. package/dist/templates/contents/themes/starter/messages/it/dev.json +106 -0
  233. package/dist/templates/contents/themes/starter/messages/it/index.ts +2 -0
  234. package/dist/templates/contents/themes/starter/messages/pt/dev.json +106 -0
  235. package/dist/templates/contents/themes/starter/messages/pt/index.ts +2 -0
  236. package/dist/templates/contents/themes/starter/styles/globals.css +14 -0
  237. package/dist/templates/instrumentation.ts +33 -0
  238. package/dist/types/blocks.d.ts +1 -1
  239. package/dist/types/blocks.d.ts.map +1 -1
  240. package/migrations/017_scheduled_actions_table.sql +21 -0
  241. package/migrations/021_media.sql +154 -0
  242. package/migrations/090_sample_data.sql +53 -0
  243. package/package.json +3 -2
  244. package/scripts/build/registry/config.mjs +41 -0
  245. package/scripts/build/registry/discovery/templates.mjs +0 -1
  246. package/scripts/build/registry/generators/entity-registry.mjs +16 -6
  247. package/scripts/build/registry/generators/route-handlers.mjs +8 -2
  248. package/scripts/build/registry/generators/template-registry.mjs +16 -4
  249. package/scripts/build/registry/post-build/route-cleanup.mjs +0 -1
  250. package/scripts/build/registry/validate-env.test.mjs +92 -0
  251. package/scripts/build/registry.mjs +18 -1
  252. package/scripts/deploy/vercel-deploy.mjs +1 -1
  253. package/templates/app/api/devtools/config/entities/route.ts +18 -11
  254. package/templates/app/api/devtools/config/theme/route.ts +5 -4
  255. package/templates/app/api/devtools/tests/[...path]/route.ts +6 -5
  256. package/templates/app/api/devtools/tests/route.ts +5 -4
  257. package/templates/app/api/health/route.ts +6 -4
  258. package/templates/app/api/internal/user-metadata/route.ts +3 -2
  259. package/templates/app/api/superadmin/subscriptions/route.ts +5 -6
  260. package/templates/app/api/superadmin/teams/[teamId]/route.ts +6 -7
  261. package/templates/app/api/superadmin/teams/route.ts +5 -6
  262. package/templates/app/api/superadmin/users/[userId]/route.ts +11 -16
  263. package/templates/app/api/superadmin/users/route.ts +9 -10
  264. package/templates/app/api/user/delete-account/route.ts +3 -2
  265. package/templates/app/api/user/plan-flags/route.ts +11 -24
  266. package/templates/app/api/user/profile/route.ts +7 -6
  267. package/templates/app/api/v1/[entity]/[id]/child/[childType]/[childId]/route.ts +16 -18
  268. package/templates/app/api/v1/[entity]/[id]/child/[childType]/route.ts +17 -19
  269. package/templates/app/api/v1/[entity]/[id]/route.ts +10 -12
  270. package/templates/app/api/v1/[entity]/route.ts +9 -11
  271. package/templates/app/api/v1/api-keys/[id]/route.ts +9 -8
  272. package/templates/app/api/v1/api-keys/route.ts +7 -6
  273. package/templates/app/api/v1/auth/signup-with-invite/route.ts +3 -2
  274. package/templates/app/api/v1/billing/cancel/route.ts +15 -14
  275. package/templates/app/api/v1/billing/change-plan/route.ts +10 -9
  276. package/templates/app/api/v1/billing/check-action/route.ts +8 -7
  277. package/templates/app/api/v1/billing/checkout/route.ts +10 -9
  278. package/templates/app/api/v1/billing/plans/route.ts +5 -4
  279. package/templates/app/api/v1/billing/portal/route.ts +9 -8
  280. package/templates/app/api/v1/blocks/[slug]/route.ts +4 -3
  281. package/templates/app/api/v1/blocks/route.ts +3 -2
  282. package/templates/app/api/v1/blocks/validate/route.ts +5 -3
  283. package/templates/app/api/v1/cron/process/route.ts +4 -6
  284. package/templates/app/api/v1/devtools/blocks/route.ts +3 -2
  285. package/templates/app/api/v1/devtools/docs/route.ts +3 -2
  286. package/templates/app/api/v1/devtools/features/route.ts +3 -2
  287. package/templates/app/api/v1/devtools/flows/route.ts +3 -2
  288. package/templates/app/api/v1/devtools/scheduled-actions/route.ts +125 -3
  289. package/templates/app/api/v1/devtools/scheduled-actions/run/route.ts +110 -0
  290. package/templates/app/api/v1/devtools/testing/route.ts +3 -2
  291. package/templates/app/api/v1/media/[id]/route.ts +144 -0
  292. package/templates/app/api/v1/media/[id]/tags/route.ts +154 -0
  293. package/templates/app/api/v1/media/check-duplicates/route.ts +56 -0
  294. package/templates/app/api/v1/media/route.ts +56 -0
  295. package/templates/app/api/v1/media/upload/route.ts +157 -33
  296. package/templates/app/api/v1/media-tags/route.ts +65 -0
  297. package/templates/app/api/v1/plugin/[...path]/route.ts +16 -15
  298. package/templates/app/api/v1/plugin/route.ts +3 -2
  299. package/templates/app/api/v1/post-categories/[id]/route.ts +10 -9
  300. package/templates/app/api/v1/post-categories/route.ts +5 -4
  301. package/templates/app/api/v1/team-invitations/[token]/accept/route.ts +3 -3
  302. package/templates/app/api/v1/team-invitations/[token]/decline/route.ts +3 -3
  303. package/templates/app/api/v1/team-invitations/[token]/route.ts +3 -2
  304. package/templates/app/api/v1/team-invitations/route.ts +3 -2
  305. package/templates/app/api/v1/teams/[teamId]/invitations/route.ts +5 -4
  306. package/templates/app/api/v1/teams/[teamId]/invoices/[invoiceNumber]/route.ts +3 -2
  307. package/templates/app/api/v1/teams/[teamId]/invoices/route.ts +3 -2
  308. package/templates/app/api/v1/teams/[teamId]/members/[memberId]/route.ts +5 -4
  309. package/templates/app/api/v1/teams/[teamId]/members/route.ts +5 -5
  310. package/templates/app/api/v1/teams/[teamId]/route.ts +31 -58
  311. package/templates/app/api/v1/teams/[teamId]/subscription/route.ts +3 -2
  312. package/templates/app/api/v1/teams/[teamId]/usage/[limitSlug]/route.ts +5 -4
  313. package/templates/app/api/v1/teams/route.ts +18 -17
  314. package/templates/app/api/v1/teams/switch/route.ts +3 -2
  315. package/templates/app/api/v1/theme/[...path]/route.ts +16 -15
  316. package/templates/app/api/v1/theme/route.ts +3 -2
  317. package/templates/app/api/v1/users/[id]/meta/[key]/route.ts +7 -6
  318. package/templates/app/api/v1/users/[id]/route.ts +9 -8
  319. package/templates/app/api/v1/users/route.ts +7 -6
  320. package/templates/app/dashboard/(main)/media/page.tsx +607 -0
  321. package/templates/contents/themes/starter/messages/de/dev.json +106 -0
  322. package/templates/contents/themes/starter/messages/de/index.ts +2 -0
  323. package/templates/contents/themes/starter/messages/en/dev.json +106 -0
  324. package/templates/contents/themes/starter/messages/en/index.ts +2 -0
  325. package/templates/contents/themes/starter/messages/es/dev.json +106 -0
  326. package/templates/contents/themes/starter/messages/es/index.ts +2 -0
  327. package/templates/contents/themes/starter/messages/fr/dev.json +106 -0
  328. package/templates/contents/themes/starter/messages/fr/index.ts +2 -0
  329. package/templates/contents/themes/starter/messages/it/dev.json +106 -0
  330. package/templates/contents/themes/starter/messages/it/index.ts +2 -0
  331. package/templates/contents/themes/starter/messages/pt/dev.json +106 -0
  332. package/templates/contents/themes/starter/messages/pt/index.ts +2 -0
  333. package/templates/contents/themes/starter/styles/globals.css +14 -0
  334. package/templates/instrumentation.ts +33 -0
  335. package/dist/presets/plugin/.env.example.template +0 -19
  336. package/dist/presets/plugin/entities/.gitkeep +0 -18
  337. package/dist/presets/theme/blocks/.gitkeep +0 -17
  338. package/dist/presets/theme/public/brand/.gitkeep +0 -8
  339. package/dist/presets/theme/tests/cypress/.gitkeep +0 -10
  340. package/dist/templates/contents/plugins/starter/plugin/.env.example.template +0 -19
  341. package/templates/contents/plugins/starter/plugin/.env.example.template +0 -19
@@ -9,18 +9,19 @@
9
9
  * P2: Stripe Integration
10
10
  */
11
11
 
12
- import { NextRequest } from 'next/server'
12
+ import { NextRequest, NextResponse } from 'next/server'
13
13
  import { authenticateRequest, createAuthError } from '@nextsparkjs/core/lib/api/auth/dual-auth'
14
14
  import { createCheckoutSession } from '@nextsparkjs/core/lib/billing/gateways/stripe'
15
15
  import { SubscriptionService, MembershipService } from '@nextsparkjs/core/lib/services'
16
16
  import { z } from 'zod'
17
+ import { withRateLimitTier } from '@nextsparkjs/core/lib/api/rate-limit'
17
18
 
18
19
  const checkoutSchema = z.object({
19
20
  planSlug: z.string().min(1, 'Plan slug is required'),
20
21
  billingPeriod: z.enum(['monthly', 'yearly']).default('monthly')
21
22
  })
22
23
 
23
- export async function POST(request: NextRequest) {
24
+ export const POST = withRateLimitTier(async (request: NextRequest) => {
24
25
  // 1. Dual authentication
25
26
  const authResult = await authenticateRequest(request)
26
27
 
@@ -33,7 +34,7 @@ export async function POST(request: NextRequest) {
33
34
  try {
34
35
  body = await request.json()
35
36
  } catch {
36
- return Response.json(
37
+ return NextResponse.json(
37
38
  { success: false, error: 'Invalid JSON body' },
38
39
  { status: 400 }
39
40
  )
@@ -41,7 +42,7 @@ export async function POST(request: NextRequest) {
41
42
 
42
43
  const parseResult = checkoutSchema.safeParse(body)
43
44
  if (!parseResult.success) {
44
- return Response.json(
45
+ return NextResponse.json(
45
46
  {
46
47
  success: false,
47
48
  error: 'Validation failed',
@@ -59,7 +60,7 @@ export async function POST(request: NextRequest) {
59
60
  authResult.user.defaultTeamId
60
61
 
61
62
  if (!teamId) {
62
- return Response.json(
63
+ return NextResponse.json(
63
64
  {
64
65
  success: false,
65
66
  error: 'No team context available. Please provide x-team-id header.'
@@ -73,7 +74,7 @@ export async function POST(request: NextRequest) {
73
74
  const actionResult = membership.canPerformAction('billing.checkout')
74
75
 
75
76
  if (!actionResult.allowed) {
76
- return Response.json(
77
+ return NextResponse.json(
77
78
  {
78
79
  success: false,
79
80
  error: actionResult.message,
@@ -104,7 +105,7 @@ export async function POST(request: NextRequest) {
104
105
  customerId: subscription?.externalCustomerId || undefined
105
106
  })
106
107
 
107
- return Response.json({
108
+ return NextResponse.json({
108
109
  success: true,
109
110
  data: {
110
111
  url: session.url,
@@ -113,7 +114,7 @@ export async function POST(request: NextRequest) {
113
114
  })
114
115
  } catch (error) {
115
116
  console.error('[checkout] Error creating checkout session:', error)
116
- return Response.json(
117
+ return NextResponse.json(
117
118
  {
118
119
  success: false,
119
120
  error: error instanceof Error ? error.message : 'Failed to create checkout session'
@@ -121,4 +122,4 @@ export async function POST(request: NextRequest) {
121
122
  { status: 500 }
122
123
  )
123
124
  }
124
- }
125
+ }, 'write');
@@ -10,8 +10,9 @@ import { validateAndAuthenticateRequest, createApiResponse, createApiError } fro
10
10
  import { PlanService } from '@nextsparkjs/core/lib/services'
11
11
  import { createPlanSchema } from '@nextsparkjs/core/lib/billing/schema'
12
12
  import { mutateWithRLS } from '@nextsparkjs/core/lib/db'
13
+ import { withRateLimitTier } from '@nextsparkjs/core/lib/api/rate-limit'
13
14
 
14
- export async function GET(request: NextRequest) {
15
+ export const GET = withRateLimitTier(async (request: NextRequest) => {
15
16
  // Plans list is partially public (public plans visible to all, hidden plans only to superadmin)
16
17
  let includeHidden = false
17
18
 
@@ -31,9 +32,9 @@ export async function GET(request: NextRequest) {
31
32
  console.error('[Billing API] Error fetching plans:', error)
32
33
  return createApiError('Failed to fetch plans', 500)
33
34
  }
34
- }
35
+ }, 'read');
35
36
 
36
- export async function POST(request: NextRequest) {
37
+ export const POST = withRateLimitTier(async (request: NextRequest) => {
37
38
  // Authenticate request
38
39
  const { auth, rateLimitResponse } = await validateAndAuthenticateRequest(request)
39
40
  if (rateLimitResponse) return rateLimitResponse
@@ -82,4 +83,4 @@ export async function POST(request: NextRequest) {
82
83
  console.error('[Billing API] Error creating plan:', error)
83
84
  return createApiError('Failed to create plan', 500)
84
85
  }
85
- }
86
+ }, 'strict');
@@ -7,12 +7,13 @@
7
7
  * P6: Customer Portal
8
8
  */
9
9
 
10
- import { NextRequest } from 'next/server'
10
+ import { NextRequest, NextResponse } from 'next/server'
11
11
  import { authenticateRequest, createAuthError } from '@nextsparkjs/core/lib/api/auth/dual-auth'
12
12
  import { createPortalSession } from '@nextsparkjs/core/lib/billing/gateways/stripe'
13
13
  import { SubscriptionService, MembershipService } from '@nextsparkjs/core/lib/services'
14
+ import { withRateLimitTier } from '@nextsparkjs/core/lib/api/rate-limit'
14
15
 
15
- export async function POST(request: NextRequest) {
16
+ export const POST = withRateLimitTier(async (request: NextRequest) => {
16
17
  // 1. Dual authentication
17
18
  const authResult = await authenticateRequest(request)
18
19
 
@@ -26,7 +27,7 @@ export async function POST(request: NextRequest) {
26
27
  authResult.user.defaultTeamId
27
28
 
28
29
  if (!teamId) {
29
- return Response.json(
30
+ return NextResponse.json(
30
31
  {
31
32
  success: false,
32
33
  error: 'No team context available. Please provide x-team-id header.'
@@ -40,7 +41,7 @@ export async function POST(request: NextRequest) {
40
41
  const actionResult = membership.canPerformAction('billing.portal')
41
42
 
42
43
  if (!actionResult.allowed) {
43
- return Response.json(
44
+ return NextResponse.json(
44
45
  {
45
46
  success: false,
46
47
  error: actionResult.message,
@@ -56,7 +57,7 @@ export async function POST(request: NextRequest) {
56
57
  const subscription = await SubscriptionService.getActive(teamId)
57
58
 
58
59
  if (!subscription?.externalCustomerId) {
59
- return Response.json(
60
+ return NextResponse.json(
60
61
  {
61
62
  success: false,
62
63
  error: 'No billing account found. Please upgrade to a paid plan first.'
@@ -73,13 +74,13 @@ export async function POST(request: NextRequest) {
73
74
  returnUrl
74
75
  })
75
76
 
76
- return Response.json({
77
+ return NextResponse.json({
77
78
  success: true,
78
79
  data: { url: session.url }
79
80
  })
80
81
  } catch (error) {
81
82
  console.error('[portal] Error creating portal session:', error)
82
- return Response.json(
83
+ return NextResponse.json(
83
84
  {
84
85
  success: false,
85
86
  error: error instanceof Error ? error.message : 'Failed to create portal session'
@@ -87,4 +88,4 @@ export async function POST(request: NextRequest) {
87
88
  { status: 500 }
88
89
  )
89
90
  }
90
- }
91
+ }, 'write');
@@ -1,10 +1,11 @@
1
1
  import { NextRequest, NextResponse } from 'next/server'
2
2
  import { BLOCK_REGISTRY } from '@nextsparkjs/registries/block-registry'
3
+ import { withRateLimitTier } from '@nextsparkjs/core/lib/api/rate-limit'
3
4
 
4
- export async function GET(
5
+ export const GET = withRateLimitTier(async (
5
6
  request: NextRequest,
6
7
  { params }: { params: Promise<{ slug: string }> }
7
- ): Promise<NextResponse> {
8
+ ): Promise<NextResponse> => {
8
9
  try {
9
10
  const { slug } = await params
10
11
  const block = BLOCK_REGISTRY[slug]
@@ -26,4 +27,4 @@ export async function GET(
26
27
  console.error('Error fetching block:', err)
27
28
  return NextResponse.json({ error: 'Internal server error' }, { status: 500 })
28
29
  }
29
- }
30
+ }, 'read');
@@ -1,7 +1,8 @@
1
1
  import { NextRequest, NextResponse } from 'next/server'
2
2
  import { BLOCK_REGISTRY, BLOCK_CATEGORIES } from '@nextsparkjs/registries/block-registry'
3
+ import { withRateLimitTier } from '@nextsparkjs/core/lib/api/rate-limit'
3
4
 
4
- export async function GET(request: NextRequest) {
5
+ export const GET = withRateLimitTier(async (request: NextRequest) => {
5
6
  try {
6
7
  const { searchParams } = new URL(request.url)
7
8
  const category = searchParams.get('category')
@@ -42,4 +43,4 @@ export async function GET(request: NextRequest) {
42
43
  console.error('Error listing blocks:', err)
43
44
  return NextResponse.json({ success: false, error: 'Internal server error' }, { status: 500 })
44
45
  }
45
- }
46
+ }, 'read');
@@ -1,13 +1,14 @@
1
1
  import { NextRequest, NextResponse } from 'next/server'
2
2
  import { BLOCK_REGISTRY } from '@nextsparkjs/registries/block-registry'
3
3
  import { z } from 'zod'
4
+ import { withRateLimitTier } from '@nextsparkjs/core/lib/api/rate-limit'
4
5
 
5
6
  const requestSchema = z.object({
6
7
  blockSlug: z.string(),
7
8
  props: z.record(z.string(), z.unknown())
8
9
  })
9
10
 
10
- export async function POST(request: NextRequest) {
11
+ export const POST = withRateLimitTier(async (request: NextRequest) => {
11
12
  try {
12
13
  const body = await request.json()
13
14
  const { blockSlug, props } = requestSchema.parse(body)
@@ -24,7 +25,8 @@ export async function POST(request: NextRequest) {
24
25
 
25
26
  try {
26
27
  // Dynamic import is allowed here (server-side validation, not registry loading)
27
- const schemaModule = await import(block.schemaPath)
28
+ // webpackIgnore tells webpack to skip static analysis for this intentional dynamic import
29
+ const schemaModule = await import(/* webpackIgnore: true */ block.schemaPath)
28
30
  const schema = schemaModule.schema
29
31
 
30
32
  schema.parse(props)
@@ -42,4 +44,4 @@ export async function POST(request: NextRequest) {
42
44
  console.error('Error validating block:', err)
43
45
  return NextResponse.json({ error: 'Internal server error' }, { status: 500 })
44
46
  }
45
- }
47
+ }, 'write');
@@ -12,22 +12,20 @@
12
12
  import { NextRequest, NextResponse } from 'next/server'
13
13
  import {
14
14
  processPendingActions,
15
- cleanupOldActions,
16
- initializeScheduledActions
15
+ cleanupOldActions
17
16
  } from '@nextsparkjs/core/lib/scheduled-actions'
18
17
  import type { ProcessResult } from '@nextsparkjs/core/lib/scheduled-actions'
19
18
 
20
19
  /**
21
20
  * Process pending scheduled actions
22
21
  * Protected by CRON_SECRET for security
22
+ *
23
+ * Note: Handler initialization is handled by instrumentation.ts at server startup.
24
+ * This endpoint only processes actions, not initialization.
23
25
  */
24
26
  export async function GET(request: NextRequest): Promise<NextResponse> {
25
27
  const startTime = Date.now()
26
28
 
27
- // Ensure action handlers are registered in this context
28
- // (initializeScheduledActions has its own guard against duplicates)
29
- initializeScheduledActions()
30
-
31
29
  try {
32
30
  // Validate CRON_SECRET
33
31
  const cronSecret = request.headers.get('x-cron-secret')
@@ -16,8 +16,9 @@ import {
16
16
  } from '@nextsparkjs/core/lib/api/auth/devtools-auth'
17
17
  import { BLOCK_REGISTRY } from '@nextsparkjs/registries/block-registry'
18
18
  import { TAGS_REGISTRY, COVERAGE_SUMMARY } from '@nextsparkjs/registries/testing-registry'
19
+ import { withRateLimitTier } from '@nextsparkjs/core/lib/api/rate-limit'
19
20
 
20
- export async function GET(request: NextRequest) {
21
+ export const GET = withRateLimitTier(async (request: NextRequest) => {
21
22
  // Authenticate request
22
23
  const authResult = await authenticateRequest(request)
23
24
 
@@ -69,7 +70,7 @@ export async function GET(request: NextRequest) {
69
70
  },
70
71
  },
71
72
  })
72
- }
73
+ }, 'read');
73
74
 
74
75
  export async function OPTIONS() {
75
76
  return new NextResponse(null, {
@@ -15,6 +15,7 @@ import { NextRequest, NextResponse } from 'next/server'
15
15
  import { readFile } from 'fs/promises'
16
16
  import { join, dirname } from 'path'
17
17
  import { existsSync } from 'fs'
18
+ import { withRateLimitTier } from '@nextsparkjs/core/lib/api/rate-limit'
18
19
 
19
20
  /**
20
21
  * Valid path patterns for documentation files
@@ -80,7 +81,7 @@ function getBasePaths(): string[] {
80
81
  return paths
81
82
  }
82
83
 
83
- export async function GET(request: NextRequest) {
84
+ export const GET = withRateLimitTier(async (request: NextRequest) => {
84
85
  const searchParams = request.nextUrl.searchParams
85
86
  const docPath = searchParams.get('path')
86
87
 
@@ -147,4 +148,4 @@ export async function GET(request: NextRequest) {
147
148
  { status: 500 }
148
149
  )
149
150
  }
150
- }
151
+ }, 'read');
@@ -18,8 +18,9 @@ import {
18
18
  FEATURE_REGISTRY,
19
19
  COVERAGE_SUMMARY,
20
20
  } from '@nextsparkjs/registries/testing-registry'
21
+ import { withRateLimitTier } from '@nextsparkjs/core/lib/api/rate-limit'
21
22
 
22
- export async function GET(request: NextRequest) {
23
+ export const GET = withRateLimitTier(async (request: NextRequest) => {
23
24
  // Authenticate request
24
25
  const authResult = await authenticateRequest(request)
25
26
 
@@ -48,7 +49,7 @@ export async function GET(request: NextRequest) {
48
49
  },
49
50
  },
50
51
  })
51
- }
52
+ }, 'read');
52
53
 
53
54
  export async function OPTIONS() {
54
55
  return new NextResponse(null, {
@@ -18,8 +18,9 @@ import {
18
18
  FLOW_REGISTRY,
19
19
  COVERAGE_SUMMARY,
20
20
  } from '@nextsparkjs/registries/testing-registry'
21
+ import { withRateLimitTier } from '@nextsparkjs/core/lib/api/rate-limit'
21
22
 
22
- export async function GET(request: NextRequest) {
23
+ export const GET = withRateLimitTier(async (request: NextRequest) => {
23
24
  // Authenticate request
24
25
  const authResult = await authenticateRequest(request)
25
26
 
@@ -48,7 +49,7 @@ export async function GET(request: NextRequest) {
48
49
  },
49
50
  },
50
51
  })
51
- }
52
+ }, 'read');
52
53
 
53
54
  export async function OPTIONS() {
54
55
  return new NextResponse(null, {
@@ -17,8 +17,10 @@ import {
17
17
  import { queryWithRLS } from '@nextsparkjs/core/lib/db'
18
18
  import type { ScheduledAction, ScheduledActionStatus } from '@nextsparkjs/core/lib/scheduled-actions/types'
19
19
  import { getAllRegisteredActions } from '@nextsparkjs/core/lib/scheduled-actions/registry'
20
+ import { withRateLimitTier } from '@nextsparkjs/core/lib/api/rate-limit'
21
+ import { scheduleAction } from '@nextsparkjs/core/lib/scheduled-actions/scheduler'
20
22
 
21
- export async function GET(request: NextRequest) {
23
+ export const GET = withRateLimitTier(async (request: NextRequest) => {
22
24
  // Authenticate request
23
25
  const authResult = await authenticateRequest(request)
24
26
 
@@ -78,6 +80,7 @@ export async function GET(request: NextRequest) {
78
80
  "completedAt",
79
81
  "errorMessage",
80
82
  attempts,
83
+ "maxRetries",
81
84
  "recurringInterval",
82
85
  "createdAt",
83
86
  "updatedAt"
@@ -92,6 +95,16 @@ export async function GET(request: NextRequest) {
92
95
  // Get all registered action types
93
96
  const registeredActions = getAllRegisteredActions()
94
97
 
98
+ // Count failed actions (last 24 hours)
99
+ const failedCountQuery = `
100
+ SELECT COUNT(*) as count
101
+ FROM "scheduled_actions"
102
+ WHERE status = 'failed'
103
+ AND "completedAt" > NOW() - INTERVAL '24 hours'
104
+ `
105
+ const failedCountResult = await queryWithRLS<{ count: string }>(failedCountQuery, [], null)
106
+ const failedCount = parseInt(failedCountResult[0]?.count || '0', 10)
107
+
95
108
  return NextResponse.json({
96
109
  success: true,
97
110
  data: {
@@ -104,16 +117,125 @@ export async function GET(request: NextRequest) {
104
117
  },
105
118
  meta: {
106
119
  registeredActionTypes: registeredActions,
120
+ failedCount,
107
121
  },
108
122
  },
109
123
  })
110
- }
124
+ }, 'read');
125
+
126
+ /**
127
+ * POST /api/v1/devtools/scheduled-actions
128
+ *
129
+ * Retry a failed action by creating a new action with the same payload.
130
+ * Requires superadmin or developer user role.
131
+ *
132
+ * Body:
133
+ * {
134
+ * "actionId": "uuid-of-failed-action"
135
+ * }
136
+ */
137
+ export const POST = withRateLimitTier(async (request: NextRequest) => {
138
+ // Authenticate request
139
+ const authResult = await authenticateRequest(request)
140
+
141
+ if (!authResult.success) {
142
+ return createDevtoolsUnauthorizedResponse()
143
+ }
144
+
145
+ // Check DevTools access permission
146
+ if (!canAccessDevtoolsApi(authResult)) {
147
+ return createDevtoolsAccessDeniedResponse()
148
+ }
149
+
150
+ // Parse request body
151
+ const body = await request.json()
152
+ const { actionId } = body
153
+
154
+ if (!actionId) {
155
+ return NextResponse.json({
156
+ success: false,
157
+ error: 'actionId is required'
158
+ }, { status: 400 })
159
+ }
160
+
161
+ // Fetch the failed action
162
+ const actions = await queryWithRLS<ScheduledAction>(
163
+ `SELECT
164
+ id,
165
+ "actionType",
166
+ status,
167
+ payload,
168
+ "teamId",
169
+ "lockGroup"
170
+ FROM "scheduled_actions"
171
+ WHERE id = $1`,
172
+ [actionId],
173
+ null
174
+ )
175
+
176
+ if (actions.length === 0) {
177
+ return NextResponse.json({
178
+ success: false,
179
+ error: 'Action not found'
180
+ }, { status: 404 })
181
+ }
182
+
183
+ const failedAction = actions[0]
184
+
185
+ // Only allow retrying failed actions
186
+ if (failedAction.status !== 'failed') {
187
+ return NextResponse.json({
188
+ success: false,
189
+ error: 'Only failed actions can be retried'
190
+ }, { status: 400 })
191
+ }
192
+
193
+ // Check if there's already a pending action with the same actionType and payload
194
+ // Use JSONB containment operator for reliable comparison
195
+ const existingPending = await queryWithRLS<{ id: string }>(
196
+ `SELECT id
197
+ FROM "scheduled_actions"
198
+ WHERE "actionType" = $1
199
+ AND payload @> $2::jsonb
200
+ AND $2::jsonb @> payload
201
+ AND status = 'pending'
202
+ LIMIT 1`,
203
+ [failedAction.actionType, JSON.stringify(failedAction.payload)],
204
+ null
205
+ )
206
+
207
+ if (existingPending.length > 0) {
208
+ return NextResponse.json({
209
+ success: false,
210
+ error: 'A pending action with the same payload already exists',
211
+ existingActionId: existingPending[0].id
212
+ }, { status: 409 })
213
+ }
214
+
215
+ // Create a new action with the same payload
216
+ const newActionId = await scheduleAction(
217
+ failedAction.actionType,
218
+ failedAction.payload,
219
+ {
220
+ scheduledAt: new Date(), // Schedule immediately
221
+ teamId: failedAction.teamId ?? undefined,
222
+ lockGroup: failedAction.lockGroup ?? undefined
223
+ }
224
+ )
225
+
226
+ return NextResponse.json({
227
+ success: true,
228
+ data: {
229
+ newActionId
230
+ }
231
+ })
232
+ }, 'write');
111
233
 
112
234
  export async function OPTIONS() {
113
235
  return new NextResponse(null, {
114
236
  status: 204,
115
237
  headers: {
116
- 'Access-Control-Allow-Methods': 'GET, OPTIONS',
238
+ 'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
117
239
  'Access-Control-Allow-Headers': 'Content-Type, Authorization, x-api-key',
118
240
  },
119
241
  })
@@ -0,0 +1,110 @@
1
+ /**
2
+ * DevTools Scheduled Actions Run API
3
+ *
4
+ * POST /api/v1/devtools/scheduled-actions/run
5
+ *
6
+ * Executes a pending action immediately.
7
+ * Requires superadmin or developer user role.
8
+ */
9
+
10
+ import { NextRequest, NextResponse } from 'next/server'
11
+ import { authenticateRequest } from '@nextsparkjs/core/lib/api/auth/dual-auth'
12
+ import {
13
+ canAccessDevtoolsApi,
14
+ createDevtoolsAccessDeniedResponse,
15
+ createDevtoolsUnauthorizedResponse,
16
+ } from '@nextsparkjs/core/lib/api/auth/devtools-auth'
17
+ import { queryWithRLS } from '@nextsparkjs/core/lib/db'
18
+ import type { ScheduledAction } from '@nextsparkjs/core/lib/scheduled-actions/types'
19
+ import { withRateLimitTier } from '@nextsparkjs/core/lib/api/rate-limit'
20
+ import { executeAction } from '@nextsparkjs/core/lib/scheduled-actions/processor'
21
+
22
+ export const POST = withRateLimitTier(async (request: NextRequest) => {
23
+ // Authenticate request
24
+ const authResult = await authenticateRequest(request)
25
+
26
+ if (!authResult.success) {
27
+ return createDevtoolsUnauthorizedResponse()
28
+ }
29
+
30
+ // Check DevTools access permission
31
+ if (!canAccessDevtoolsApi(authResult)) {
32
+ return createDevtoolsAccessDeniedResponse()
33
+ }
34
+
35
+ // Parse request body
36
+ const body = await request.json()
37
+ const { actionId } = body
38
+
39
+ if (!actionId) {
40
+ return NextResponse.json({
41
+ success: false,
42
+ error: 'actionId is required'
43
+ }, { status: 400 })
44
+ }
45
+
46
+ // Fetch the pending action
47
+ const actions = await queryWithRLS<ScheduledAction>(
48
+ `SELECT
49
+ id,
50
+ "actionType",
51
+ status,
52
+ payload,
53
+ "teamId",
54
+ "scheduledAt",
55
+ attempts,
56
+ "maxRetries",
57
+ "recurringInterval",
58
+ "recurrenceType",
59
+ "lockGroup"
60
+ FROM "scheduled_actions"
61
+ WHERE id = $1`,
62
+ [actionId],
63
+ null
64
+ )
65
+
66
+ if (actions.length === 0) {
67
+ return NextResponse.json({
68
+ success: false,
69
+ error: 'Action not found'
70
+ }, { status: 404 })
71
+ }
72
+
73
+ const action = actions[0]
74
+
75
+ // Only allow running pending actions
76
+ if (action.status !== 'pending') {
77
+ return NextResponse.json({
78
+ success: false,
79
+ error: 'Only pending actions can be executed'
80
+ }, { status: 400 })
81
+ }
82
+
83
+ try {
84
+ // Execute the action immediately
85
+ await executeAction(action)
86
+
87
+ return NextResponse.json({
88
+ success: true,
89
+ data: {
90
+ executed: true
91
+ }
92
+ })
93
+ } catch (error) {
94
+ console.error('[DevTools] Failed to execute action:', error)
95
+ return NextResponse.json({
96
+ success: false,
97
+ error: error instanceof Error ? error.message : 'Failed to execute action'
98
+ }, { status: 500 })
99
+ }
100
+ }, 'write');
101
+
102
+ export async function OPTIONS() {
103
+ return new NextResponse(null, {
104
+ status: 204,
105
+ headers: {
106
+ 'Access-Control-Allow-Methods': 'POST, OPTIONS',
107
+ 'Access-Control-Allow-Headers': 'Content-Type, Authorization, x-api-key',
108
+ },
109
+ })
110
+ }
@@ -20,8 +20,9 @@ import {
20
20
  FEATURE_REGISTRY,
21
21
  FLOW_REGISTRY,
22
22
  } from '@nextsparkjs/registries/testing-registry'
23
+ import { withRateLimitTier } from '@nextsparkjs/core/lib/api/rate-limit'
23
24
 
24
- export async function GET(request: NextRequest) {
25
+ export const GET = withRateLimitTier(async (request: NextRequest) => {
25
26
  // Authenticate request
26
27
  const authResult = await authenticateRequest(request)
27
28
 
@@ -69,7 +70,7 @@ export async function GET(request: NextRequest) {
69
70
  },
70
71
  },
71
72
  })
72
- }
73
+ }, 'read');
73
74
 
74
75
  export async function OPTIONS() {
75
76
  return new NextResponse(null, {