@plitzi/sdk-server 0.37.1 → 0.37.3

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 (386) hide show
  1. package/CHANGELOG.md +1296 -0
  2. package/README.md +126 -7
  3. package/dist/actions.d.ts +20 -8
  4. package/dist/actions.js +11 -4
  5. package/dist/adapters/cloudAdapters.js +4 -3
  6. package/dist/adapters/jsonAdapters.js +28 -6
  7. package/dist/auth.d.ts +7 -4
  8. package/dist/auth.js +8 -6
  9. package/dist/core/auth/api.d.ts +29 -1
  10. package/dist/core/auth/api.js +47 -13
  11. package/dist/core/auth/createAuth.d.ts +4 -0
  12. package/dist/core/auth/createAuth.js +3 -3
  13. package/dist/core/auth/credentials.d.ts +3 -0
  14. package/dist/core/auth/credentials.js +1 -1
  15. package/dist/core/auth/csrf.d.ts +25 -1
  16. package/dist/core/auth/csrf.js +29 -4
  17. package/dist/core/auth/renewal.d.ts +26 -0
  18. package/dist/core/auth/renewal.js +24 -0
  19. package/dist/core/auth/routes.js +8 -6
  20. package/dist/core/auth/session.d.ts +45 -0
  21. package/dist/core/auth/session.js +47 -1
  22. package/dist/core/auth/sessionActivity.d.ts +11 -0
  23. package/dist/core/auth/sessionActivity.js +14 -0
  24. package/dist/core/auth/throttle.d.ts +15 -0
  25. package/dist/core/auth/throttle.js +29 -1
  26. package/dist/core/auth/totp.d.ts +9 -1
  27. package/dist/core/auth/totp.js +11 -6
  28. package/dist/core/createServer.actions.test.d.ts +1 -0
  29. package/dist/core/createServer.d.ts +14 -1
  30. package/dist/core/createServer.functions.test.d.ts +1 -0
  31. package/dist/core/createServer.js +22 -12
  32. package/dist/core/fontStore.js +1 -1
  33. package/dist/core/handlers/authRouteHandlers.d.ts +1 -1
  34. package/dist/core/handlers/authRouteHandlers.js +57 -21
  35. package/dist/core/handlers/csrfMiddleware.d.ts +23 -0
  36. package/dist/core/handlers/csrfMiddleware.js +31 -7
  37. package/dist/core/handlers/csrfMiddleware.test.d.ts +1 -0
  38. package/dist/core/handlers/oauthRouteHandlers.js +5 -3
  39. package/dist/core/handlers/socialRouteHandlers.d.ts +1 -1
  40. package/dist/core/handlers/socialRouteHandlers.js +2 -1
  41. package/dist/core/http/dispatcher.d.ts +9 -1
  42. package/dist/core/http/dispatcher.js +38 -11
  43. package/dist/core/http/navigation.d.ts +5 -2
  44. package/dist/core/http/navigation.js +7 -4
  45. package/dist/core/http/socketResponse.d.ts +18 -0
  46. package/dist/core/http/socketResponse.js +59 -0
  47. package/dist/core/http/sse.d.ts +26 -0
  48. package/dist/core/http/sse.js +78 -0
  49. package/dist/core/http/stages/authRoutes.js +3 -1
  50. package/dist/core/http/stages/exchangeRoute.test.d.ts +1 -0
  51. package/dist/core/http/stages/middlewares.d.ts +1 -1
  52. package/dist/core/http/stages/middlewares.js +16 -10
  53. package/dist/core/http/stages/middlewares.test.d.ts +1 -0
  54. package/dist/core/http/stages/oauth.js +2 -2
  55. package/dist/core/http/stages/sessionRenewal.d.ts +16 -0
  56. package/dist/core/http/stages/sessionRenewal.js +81 -0
  57. package/dist/core/http/stages/sessionRenewal.test.d.ts +1 -0
  58. package/dist/core/http/stages/signInRoute.d.ts +2 -0
  59. package/dist/core/http/stages/signInRoute.js +139 -0
  60. package/dist/core/http/stages/signInRoute.test.d.ts +1 -0
  61. package/dist/core/http/types.d.ts +9 -0
  62. package/dist/core/http/webExchange.d.ts +18 -0
  63. package/dist/core/http/webExchange.js +53 -0
  64. package/dist/core/oauth/authorize.js +37 -13
  65. package/dist/core/oauth/consentPage.js +11 -0
  66. package/dist/core/oauth/issueContext.d.ts +14 -0
  67. package/dist/core/oauth/issueContext.js +32 -0
  68. package/dist/core/oauth/records.d.ts +7 -0
  69. package/dist/core/oauth/register.d.ts +2 -0
  70. package/dist/core/oauth/register.js +32 -11
  71. package/dist/core/oauth/register.test.d.ts +1 -0
  72. package/dist/core/oauth/token.js +21 -6
  73. package/dist/core/oauth/token.test.d.ts +1 -0
  74. package/dist/core/requestParser.d.ts +4 -0
  75. package/dist/core/requestParser.js +14 -7
  76. package/dist/core/sdkAssets.js +1 -1
  77. package/dist/core/server/baseServer.d.ts +14 -1
  78. package/dist/core/server/baseServer.js +43 -11
  79. package/dist/core/server/closeOnSignals.d.ts +28 -0
  80. package/dist/core/server/closeOnSignals.js +47 -0
  81. package/dist/core/server/closeOnSignals.test.d.ts +1 -0
  82. package/dist/core/server/drain.d.ts +18 -0
  83. package/dist/core/server/drain.js +62 -0
  84. package/dist/core/server/drain.test.d.ts +1 -0
  85. package/dist/core/server/fleet/channel.d.ts +103 -0
  86. package/dist/core/server/fleet/channel.js +191 -0
  87. package/dist/core/server/fleet/channel.test.d.ts +1 -0
  88. package/dist/core/server/fleet/fixtures/fleetServer.d.ts +1 -0
  89. package/dist/core/server/fleet/fleet.integration.test.d.ts +1 -0
  90. package/dist/core/server/fleet/link.d.ts +23 -0
  91. package/dist/core/server/fleet/link.js +70 -0
  92. package/dist/core/server/fleet/relay.d.ts +11 -0
  93. package/dist/core/server/fleet/relay.js +104 -0
  94. package/dist/core/server/fleet/relay.test.d.ts +1 -0
  95. package/dist/core/server/fleet/role.d.ts +46 -0
  96. package/dist/core/server/fleet/role.js +59 -0
  97. package/dist/core/server/fleet/role.test.d.ts +1 -0
  98. package/dist/core/server/fleet/stores.d.ts +7 -0
  99. package/dist/core/server/fleet/stores.js +19 -0
  100. package/dist/core/server/fleet/supervisor.d.ts +26 -0
  101. package/dist/core/server/fleet/supervisor.js +108 -0
  102. package/dist/core/server/fleet/supervisor.test.d.ts +1 -0
  103. package/dist/core/server/pageServer.js +36 -5
  104. package/dist/core/services/action.js +10 -2
  105. package/dist/core/services/functionRoutes.d.ts +9 -0
  106. package/dist/core/services/functionRoutes.js +47 -0
  107. package/dist/core/services/realtime.d.ts +8 -0
  108. package/dist/core/services/realtime.js +57 -0
  109. package/dist/core/services/registry.js +6 -2
  110. package/dist/core/staticFiles.js +12 -4
  111. package/dist/core/staticFiles.test.d.ts +1 -0
  112. package/dist/core/transports.d.ts +13 -3
  113. package/dist/core/transports.js +14 -5
  114. package/dist/functions-api.d.ts +281 -0
  115. package/dist/functions.d.ts +19 -0
  116. package/dist/functions.js +5 -0
  117. package/dist/functionsRunner.d.ts +15 -0
  118. package/dist/functionsRunner.js +6 -0
  119. package/dist/handlers.d.ts +2 -2
  120. package/dist/handlers.js +2 -2
  121. package/dist/helpers/atomicFile.d.ts +10 -0
  122. package/dist/helpers/atomicFile.js +33 -0
  123. package/dist/helpers/atomicFile.test.d.ts +1 -0
  124. package/dist/helpers/buildResponseHelpers.js +35 -11
  125. package/dist/helpers/buildServerInfo.js +4 -2
  126. package/dist/helpers/buildServerInfo.test.d.ts +1 -0
  127. package/dist/helpers/cache/CompressedFileCache.d.ts +18 -0
  128. package/dist/helpers/cache/CompressedFileCache.js +44 -0
  129. package/dist/helpers/cache/CompressedFileCache.test.d.ts +1 -0
  130. package/dist/helpers/cache/cacheManager.d.ts +1 -1
  131. package/dist/helpers/cache/cacheManager.js +2 -1
  132. package/dist/helpers/cache/cacheManager.test.d.ts +1 -0
  133. package/dist/helpers/cache/index.d.ts +1 -1
  134. package/dist/helpers/cache/keys.d.ts +15 -1
  135. package/dist/helpers/cache/keys.js +47 -5
  136. package/dist/helpers/cache/serverCaches.d.ts +7 -1
  137. package/dist/helpers/compress.d.ts +3 -1
  138. package/dist/helpers/compress.js +11 -3
  139. package/dist/helpers/hydrationPayload.d.ts +11 -0
  140. package/dist/helpers/hydrationPayload.js +51 -0
  141. package/dist/helpers/hydrationPayload.test.d.ts +1 -0
  142. package/dist/helpers/metrics.d.ts +1 -1
  143. package/dist/helpers/metrics.js +3 -2
  144. package/dist/helpers/outboundGuard.d.ts +14 -6
  145. package/dist/helpers/outboundGuard.js +132 -8
  146. package/dist/helpers/paintedCookie.d.ts +8 -0
  147. package/dist/helpers/paintedCookie.js +13 -0
  148. package/dist/helpers/reportReactBuild.d.ts +9 -0
  149. package/dist/helpers/reportReactBuild.js +18 -0
  150. package/dist/helpers/reportReactBuild.test.d.ts +1 -0
  151. package/dist/helpers/serverLog.d.ts +25 -1
  152. package/dist/helpers/serverLog.js +68 -3
  153. package/dist/helpers/serverLog.test.d.ts +1 -0
  154. package/dist/helpers/wsFrame.d.ts +3 -0
  155. package/dist/helpers/wsFrame.js +5 -0
  156. package/dist/index.d.ts +8 -1
  157. package/dist/index.js +6 -2
  158. package/dist/kernel.d.ts +2 -1
  159. package/dist/kernel.js +3 -2
  160. package/dist/modules/actions/connectorWrite.js +2 -1
  161. package/dist/modules/actions/index.d.ts +41 -13
  162. package/dist/modules/actions/index.js +52 -9
  163. package/dist/modules/actions/jobs/failureStreak.d.ts +17 -0
  164. package/dist/modules/actions/jobs/failureStreak.js +47 -0
  165. package/dist/modules/actions/jobs/failureStreak.test.d.ts +1 -0
  166. package/dist/modules/actions/jobs/index.d.ts +33 -0
  167. package/dist/modules/actions/jobs/index.js +59 -0
  168. package/dist/modules/actions/jobs/memoryQueue.d.ts +33 -0
  169. package/dist/modules/actions/jobs/memoryQueue.js +194 -0
  170. package/dist/modules/actions/jobs/memoryStores.test.d.ts +1 -0
  171. package/dist/modules/actions/jobs/scheduler.d.ts +64 -0
  172. package/dist/modules/actions/jobs/scheduler.js +130 -0
  173. package/dist/modules/actions/jobs/scheduler.test.d.ts +1 -0
  174. package/dist/modules/actions/jobs/schedules.d.ts +23 -0
  175. package/dist/modules/actions/jobs/schedules.js +47 -0
  176. package/dist/modules/actions/jobs/storeClock.d.ts +16 -0
  177. package/dist/modules/actions/jobs/storeClock.js +32 -0
  178. package/dist/modules/actions/jobs/testing/jobQueueContract.d.ts +25 -0
  179. package/dist/modules/actions/jobs/worker.d.ts +64 -0
  180. package/dist/modules/actions/jobs/worker.js +267 -0
  181. package/dist/modules/actions/jobs/worker.test.d.ts +1 -0
  182. package/dist/modules/actions/moduleFor.js +6 -2
  183. package/dist/modules/actions/runtime/errors.d.ts +12 -0
  184. package/dist/modules/actions/runtime/errors.js +16 -1
  185. package/dist/modules/actions/runtime/kvChange.d.ts +27 -0
  186. package/dist/modules/actions/runtime/kvChange.js +23 -0
  187. package/dist/modules/actions/runtime/kvList.d.ts +51 -0
  188. package/dist/modules/actions/runtime/kvList.js +52 -0
  189. package/dist/modules/actions/runtime/kvStore.d.ts +8 -0
  190. package/dist/modules/actions/runtime/kvStore.js +46 -20
  191. package/dist/modules/actions/runtime/memoryKv.d.ts +3 -0
  192. package/dist/modules/actions/runtime/memoryKv.js +19 -1
  193. package/dist/modules/actions/runtime/namespaceKv.d.ts +4 -6
  194. package/dist/modules/actions/runtime/namespaceKv.js +15 -3
  195. package/dist/modules/actions/runtime/namespaceKv.test.d.ts +1 -0
  196. package/dist/modules/actions/runtime/precheck.js +5 -9
  197. package/dist/modules/actions/runtime/rateLimit.d.ts +19 -0
  198. package/dist/modules/actions/runtime/rateLimit.js +19 -0
  199. package/dist/modules/actions/runtime/redisKv.d.ts +27 -0
  200. package/dist/modules/actions/runtime/redisKv.integration.test.d.ts +1 -0
  201. package/dist/modules/actions/runtime/redisKv.js +46 -0
  202. package/dist/modules/actions/runtime/renderResolver.js +2 -2
  203. package/dist/modules/actions/runtime/report.js +2 -1
  204. package/dist/modules/actions/runtime/runAction.d.ts +10 -2
  205. package/dist/modules/actions/runtime/runAction.js +52 -116
  206. package/dist/modules/actions/runtime/runLogger.d.ts +5 -0
  207. package/dist/modules/actions/runtime/runLogger.js +8 -2
  208. package/dist/modules/actions/runtime/signing.d.ts +20 -0
  209. package/dist/modules/actions/runtime/signing.js +25 -0
  210. package/dist/modules/actions/runtime/signing.test.d.ts +1 -0
  211. package/dist/modules/actions/runtime/taskContext.d.ts +33 -0
  212. package/dist/modules/actions/runtime/taskContext.js +124 -0
  213. package/dist/modules/actions/tasks/builtins.js +5 -1
  214. package/dist/modules/actions/tasks/flow.js +81 -10
  215. package/dist/modules/actions/tasks/helpers.js +2 -2
  216. package/dist/modules/actions/tasks/http.js +2 -3
  217. package/dist/modules/actions/tasks/kv.js +39 -0
  218. package/dist/modules/actions/tasks/list.d.ts +2 -0
  219. package/dist/modules/actions/tasks/list.js +145 -0
  220. package/dist/modules/actions/tasks/realtime.d.ts +2 -0
  221. package/dist/modules/actions/tasks/realtime.js +104 -0
  222. package/dist/modules/actions/tasks/registry.d.ts +10 -1
  223. package/dist/modules/actions/tasks/registry.js +17 -6
  224. package/dist/modules/actions/transport/callHandler.js +6 -3
  225. package/dist/modules/actions/transport/catalogHandler.d.ts +5 -2
  226. package/dist/modules/actions/transport/catalogHandler.js +3 -2
  227. package/dist/modules/actions/transport/stream.d.ts +4 -5
  228. package/dist/modules/actions/transport/stream.js +12 -76
  229. package/dist/modules/actions/transport/webhookHandler.js +5 -4
  230. package/dist/modules/actions/types.d.ts +162 -4
  231. package/dist/modules/connectors/engine.js +3 -5
  232. package/dist/modules/functions/build.d.ts +22 -0
  233. package/dist/modules/functions/build.js +122 -0
  234. package/dist/modules/functions/build.test.d.ts +1 -0
  235. package/dist/modules/functions/capabilities.d.ts +22 -0
  236. package/dist/modules/functions/capabilities.js +228 -0
  237. package/dist/modules/functions/config.d.ts +34 -0
  238. package/dist/modules/functions/config.js +24 -0
  239. package/dist/modules/functions/context.d.ts +17 -0
  240. package/dist/modules/functions/context.js +88 -0
  241. package/dist/modules/functions/contract.d.ts +121 -0
  242. package/dist/modules/functions/contract.js +9 -0
  243. package/dist/modules/functions/driver.d.ts +36 -0
  244. package/dist/modules/functions/driver.js +150 -0
  245. package/dist/modules/functions/load.d.ts +15 -0
  246. package/dist/modules/functions/load.js +45 -0
  247. package/dist/modules/functions/load.test.d.ts +1 -0
  248. package/dist/modules/functions/local.d.ts +29 -0
  249. package/dist/modules/functions/local.js +61 -0
  250. package/dist/modules/functions/local.test.d.ts +1 -0
  251. package/dist/modules/functions/manifest.d.ts +24 -0
  252. package/dist/modules/functions/manifest.js +163 -0
  253. package/dist/modules/functions/manifest.test.d.ts +1 -0
  254. package/dist/modules/functions/native.d.ts +8 -0
  255. package/dist/modules/functions/native.js +21 -0
  256. package/dist/modules/functions/native.test.d.ts +1 -0
  257. package/dist/modules/functions/protocol.d.ts +216 -0
  258. package/dist/modules/functions/protocol.js +18 -0
  259. package/dist/modules/functions/routes.d.ts +36 -0
  260. package/dist/modules/functions/routes.js +181 -0
  261. package/dist/modules/functions/routes.test.d.ts +1 -0
  262. package/dist/modules/functions/runner/messages.d.ts +5 -0
  263. package/dist/modules/functions/runner/messages.js +188 -0
  264. package/dist/modules/functions/runner/remote.d.ts +19 -0
  265. package/dist/modules/functions/runner/remote.js +116 -0
  266. package/dist/modules/functions/runner/remote.test.d.ts +1 -0
  267. package/dist/modules/functions/runner/service.d.ts +32 -0
  268. package/dist/modules/functions/runner/service.js +209 -0
  269. package/dist/modules/functions/sandbox/guest.d.ts +45 -0
  270. package/dist/modules/functions/sandbox/guest.js +660 -0
  271. package/dist/modules/functions/sandbox/isolate.d.ts +37 -0
  272. package/dist/modules/functions/sandbox/isolate.js +347 -0
  273. package/dist/modules/functions/sandbox/isolate.test.d.ts +1 -0
  274. package/dist/modules/functions/sandbox/prelude.d.ts +2 -0
  275. package/dist/modules/functions/sandbox/prelude.js +49 -0
  276. package/dist/modules/functions/space.d.ts +40 -0
  277. package/dist/modules/functions/space.js +162 -0
  278. package/dist/modules/functions/testing/tasksOf.d.ts +4 -0
  279. package/dist/modules/functions/tryEntry.d.ts +9 -0
  280. package/dist/modules/functions/tryEntry.js +49 -0
  281. package/dist/modules/mongo/index.d.ts +4 -0
  282. package/dist/modules/mongo/jobQueue.d.ts +38 -0
  283. package/dist/modules/mongo/jobQueue.js +335 -0
  284. package/dist/modules/mongo/kv.d.ts +15 -0
  285. package/dist/modules/mongo/kv.js +129 -0
  286. package/dist/modules/mongo/stores.integration.test.d.ts +1 -0
  287. package/dist/modules/mysql/accounts.js +19 -9
  288. package/dist/modules/mysql/index.d.ts +2 -1
  289. package/dist/modules/mysql/jobs/index.d.ts +5 -0
  290. package/dist/modules/mysql/jobs/jobQueue.d.ts +40 -0
  291. package/dist/modules/mysql/jobs/jobQueue.js +375 -0
  292. package/dist/modules/mysql/jobs/kv.d.ts +18 -0
  293. package/dist/modules/mysql/jobs/kv.js +108 -0
  294. package/dist/modules/mysql/jobs/schema.d.ts +33 -0
  295. package/dist/modules/mysql/jobs/schema.js +113 -0
  296. package/dist/modules/mysql/jobs/stores.integration.test.d.ts +1 -0
  297. package/dist/modules/mysql/schema.js +25 -0
  298. package/dist/modules/mysql/sessions.d.ts +1 -11
  299. package/dist/modules/mysql/sessions.js +6 -1
  300. package/dist/modules/realtime/declarations.d.ts +11 -0
  301. package/dist/modules/realtime/declarations.js +26 -0
  302. package/dist/modules/realtime/grants.d.ts +23 -0
  303. package/dist/modules/realtime/grants.js +61 -0
  304. package/dist/modules/realtime/handlers.d.ts +74 -0
  305. package/dist/modules/realtime/handlers.js +224 -0
  306. package/dist/modules/realtime/hub.d.ts +62 -0
  307. package/dist/modules/realtime/hub.js +141 -0
  308. package/dist/modules/realtime/index.d.ts +51 -0
  309. package/dist/modules/realtime/index.js +62 -0
  310. package/dist/modules/realtime/memoryPubSub.d.ts +10 -0
  311. package/dist/modules/realtime/memoryPubSub.js +43 -0
  312. package/dist/modules/realtime/realtime.test.d.ts +1 -0
  313. package/dist/modules/realtime/redisPubSub.d.ts +24 -0
  314. package/dist/modules/realtime/redisPubSub.js +36 -0
  315. package/dist/modules/realtime/redisPubSub.test.d.ts +1 -0
  316. package/dist/modules/realtime/socket.d.ts +25 -0
  317. package/dist/modules/realtime/socket.js +122 -0
  318. package/dist/modules/realtime/socket.test.d.ts +1 -0
  319. package/dist/modules/rsc/handler.d.ts +16 -0
  320. package/dist/modules/rsc/handler.js +17 -10
  321. package/dist/modules/rsc/handler.test.d.ts +1 -0
  322. package/dist/modules/rsc/resolveRscData.js +2 -1
  323. package/dist/modules/runtime/bundle.d.ts +24 -0
  324. package/dist/modules/runtime/bundle.js +102 -0
  325. package/dist/modules/runtime/contract.d.ts +37 -0
  326. package/dist/modules/runtime/contract.js +21 -0
  327. package/dist/modules/runtime/entry.test.d.ts +1 -0
  328. package/dist/modules/runtime/host.d.ts +38 -0
  329. package/dist/modules/runtime/host.js +68 -0
  330. package/dist/modules/runtime/inside.d.ts +15 -0
  331. package/dist/modules/runtime/inside.js +47 -0
  332. package/dist/modules/runtime/inside.test.d.ts +1 -0
  333. package/dist/modules/runtime/runner.d.ts +11 -0
  334. package/dist/modules/runtime/runner.js +38 -0
  335. package/dist/modules/runtime/runtime.test.d.ts +1 -0
  336. package/dist/modules/runtime/stages.d.ts +50 -0
  337. package/dist/modules/runtime/stages.js +117 -0
  338. package/dist/modules/ssr/Component.d.ts +4 -5
  339. package/dist/modules/ssr/Component.js +2 -2
  340. package/dist/modules/ssr/handler.js +10 -2
  341. package/dist/modules/ssr/loadPluginComponents.js +2 -1
  342. package/dist/modules/ssr/prepareRender.js +39 -13
  343. package/dist/modules/ssr/preview.d.ts +3 -0
  344. package/dist/modules/ssr/preview.js +17 -7
  345. package/dist/modules/ssr/redirect.test.d.ts +1 -0
  346. package/dist/modules/ssr/registerExternalPlugins.d.ts +6 -1
  347. package/dist/modules/ssr/registerExternalPlugins.js +19 -16
  348. package/dist/modules/ssr/registerExternalPlugins.test.d.ts +1 -0
  349. package/dist/modules/ssr/reportMissingPlugins.d.ts +9 -0
  350. package/dist/modules/ssr/reportMissingPlugins.js +24 -0
  351. package/dist/modules/ssr/reportMissingPlugins.test.d.ts +1 -0
  352. package/dist/modules/ssr/streamBody.d.ts +2 -2
  353. package/dist/modules/ssr/streamBody.js +4 -1
  354. package/dist/modules/ssr/template.js +1 -1
  355. package/dist/modules/ssr/views/template.ejs +8 -5
  356. package/dist/mongo.d.ts +25 -0
  357. package/dist/mongo.js +3 -0
  358. package/dist/mysql.d.ts +11 -0
  359. package/dist/mysql.js +4 -1
  360. package/dist/oauth.js +2 -2
  361. package/dist/plugins/compile.js +9 -4
  362. package/dist/plugins/copy.js +3 -3
  363. package/dist/plugins/manager.d.ts +35 -3
  364. package/dist/plugins/manager.js +109 -38
  365. package/dist/runtime.d.ts +15 -0
  366. package/dist/runtime.js +7 -0
  367. package/package.json +52 -11
  368. package/skills/plitzi-authoring/SKILL.md +153 -263
  369. package/skills/plitzi-authoring/reference/accessibility.md +111 -0
  370. package/skills/plitzi-authoring/reference/authoring-errors.md +70 -0
  371. package/skills/plitzi-authoring/reference/data-and-visibility.md +180 -0
  372. package/skills/plitzi-authoring/reference/elements-and-styles.md +161 -0
  373. package/skills/plitzi-authoring/reference/flows.md +171 -0
  374. package/skills/plitzi-authoring/reference/layouts.md +140 -0
  375. package/skills/plitzi-authoring/reference/lists.md +74 -0
  376. package/skills/plitzi-authoring/reference/performance.md +67 -0
  377. package/skills/plitzi-authoring/reference/plugins.md +167 -0
  378. package/skills/plitzi-authoring/reference/review-checklist.md +67 -0
  379. package/skills/plitzi-authoring/reference/structure.md +83 -0
  380. package/skills/plitzi-authoring/reference/templates-and-export.md +54 -0
  381. package/skills/plitzi-authoring/reference/templates.md +109 -0
  382. package/skills/plitzi-authoring/reference/testing.md +119 -0
  383. package/skills/plitzi-authoring/reference/validation.md +73 -0
  384. package/dist/modules/actions/runtime/schedule.d.ts +0 -35
  385. package/dist/modules/actions/runtime/schedule.js +0 -76
  386. /package/dist/{modules/actions/runtime/schedule.test.d.ts → adapters/jsonAdapters.test.d.ts} +0 -0
@@ -0,0 +1,38 @@
1
+ import { ActionJobQueue } from '@plitzi/sdk-shared';
2
+ import { Db } from 'mongodb';
3
+ /** The database, or how to reach it — a getter for a deployment whose client is replaced when it reconnects. */
4
+ export type MongoDbSource = Db | (() => Db);
5
+ export declare const resolveDb: (source: MongoDbSource) => Db;
6
+ export type MongoJobQueueOptions = {
7
+ db: MongoDbSource;
8
+ /** Collection names, for a deployment with a naming scheme of its own. */
9
+ collections?: {
10
+ jobs?: string;
11
+ schedules?: string;
12
+ };
13
+ /** How long a finished job stays readable. A waiting or running one never expires. Default 90 days. */
14
+ retentionDays?: number;
15
+ };
16
+ export type MongoJobQueue = ActionJobQueue & {
17
+ /** Takes the store's clock again on the next call — after a failover to another primary. */
18
+ resyncClock: () => void;
19
+ };
20
+ /**
21
+ * An {@link ActionJobQueue} over two collections of a Mongo database the deployment owns.
22
+ *
23
+ * The helper for a deployment that already runs Mongo: it holds no connection of its own and creates nothing but the
24
+ * indexes its queries need, on first use. Every replica pointed at the same database shares the jobs and the
25
+ * schedules, which is what running more than one needs.
26
+ *
27
+ * ```ts
28
+ * import { createMongoJobQueue } from '@plitzi/sdk-server/mongo';
29
+ *
30
+ * const queue = createMongoJobQueue({ db: client.db('app') });
31
+ * createServer({ action: { lookups, kv, jobs: { queue } } });
32
+ * ```
33
+ *
34
+ * The contract's rules, as Mongo keeps them: every instant is the SERVER's (`hello.localTime`), `enqueue` is idempotent
35
+ * by the job's `_id`, `claim` takes one document per `findOneAndUpdate` — the atomic unit — and reaps a lapsed lease in
36
+ * the same operation, and a schedule advances by compare-and-set on the instant that was read.
37
+ */
38
+ export declare const createMongoJobQueue: ({ db, collections: names, retentionDays }: MongoJobQueueOptions) => MongoJobQueue;
@@ -0,0 +1,335 @@
1
+ import { createStoreClock } from "../actions/jobs/storeClock.js";
2
+ //#region src/modules/mongo/jobQueue.ts
3
+ /** Mongo's code for a unique index that refused a second document with the same key. */
4
+ var DUPLICATE_KEY = 11e3;
5
+ var TERMINAL = [
6
+ "succeeded",
7
+ "failed",
8
+ "dead",
9
+ "cancelled"
10
+ ];
11
+ var DAY_MS = 864e5;
12
+ var resolveDb = (source) => typeof source === "function" ? source() : source;
13
+ var scheduleId = (spaceId, actionId) => `${spaceId}:${actionId}`;
14
+ /**
15
+ * A stored document as the contract shapes it: an optional field is absent, never `null`.
16
+ *
17
+ * Mongo keeps what a `$set` wrote, and clearing a field in an update pipeline writes `null` — so a released job would
18
+ * otherwise come back with `workerId: null`, which every reader typed as `string | undefined` gets wrong.
19
+ */
20
+ var withoutNulls = (document) => Object.fromEntries(Object.entries(document).filter(([, value]) => value !== null));
21
+ var toJob = ({ _id, expiresAt: _expiresAt, ...rest }) => withoutNulls({
22
+ ...rest,
23
+ id: _id
24
+ });
25
+ var toSchedule = ({ _id: _unused, ...rest }) => withoutNulls(rest);
26
+ /** The history entry a reclaim writes on behalf of a worker that never came back. */
27
+ var lostAttempt = (at) => ({ $concatArrays: ["$history", [{
28
+ attempt: { $add: [{ $size: "$history" }, 1] },
29
+ status: "lost",
30
+ startedAt: "$updatedAt",
31
+ endedAt: at,
32
+ workerId: { $ifNull: ["$workerId", "unknown"] },
33
+ error: "the worker holding this job stopped reporting"
34
+ }]] });
35
+ /**
36
+ * An {@link ActionJobQueue} over two collections of a Mongo database the deployment owns.
37
+ *
38
+ * The helper for a deployment that already runs Mongo: it holds no connection of its own and creates nothing but the
39
+ * indexes its queries need, on first use. Every replica pointed at the same database shares the jobs and the
40
+ * schedules, which is what running more than one needs.
41
+ *
42
+ * ```ts
43
+ * import { createMongoJobQueue } from '@plitzi/sdk-server/mongo';
44
+ *
45
+ * const queue = createMongoJobQueue({ db: client.db('app') });
46
+ * createServer({ action: { lookups, kv, jobs: { queue } } });
47
+ * ```
48
+ *
49
+ * The contract's rules, as Mongo keeps them: every instant is the SERVER's (`hello.localTime`), `enqueue` is idempotent
50
+ * by the job's `_id`, `claim` takes one document per `findOneAndUpdate` — the atomic unit — and reaps a lapsed lease in
51
+ * the same operation, and a schedule advances by compare-and-set on the instant that was read.
52
+ */
53
+ var createMongoJobQueue = ({ db, collections: names = {}, retentionDays = 90 }) => {
54
+ const jobsName = names.jobs ?? "action_jobs";
55
+ const schedulesName = names.schedules ?? "action_schedules";
56
+ const jobsOf = () => resolveDb(db).collection(jobsName);
57
+ const schedulesOf = () => resolveDb(db).collection(schedulesName);
58
+ const clock = createStoreClock(async () => {
59
+ const { localTime } = await resolveDb(db).command({ hello: 1 });
60
+ return localTime ? localTime.getTime() : Date.now();
61
+ });
62
+ let ready;
63
+ /**
64
+ * The indexes the queue cannot work without, built once on first use.
65
+ *
66
+ * `claim` is the one that matters: it runs on every poll of every replica, and without an index over status and the
67
+ * two time fields it is a collection scan several times a second. The two branches of its `$or` are answered by one
68
+ * index each and merged already sorted.
69
+ */
70
+ const build = async () => {
71
+ await Promise.all([
72
+ jobsOf().createIndex({
73
+ status: 1,
74
+ runAt: 1
75
+ }),
76
+ jobsOf().createIndex({
77
+ status: 1,
78
+ leaseUntil: 1
79
+ }),
80
+ jobsOf().createIndex({
81
+ spaceId: 1,
82
+ updatedAt: -1
83
+ }),
84
+ jobsOf().createIndex({
85
+ spaceId: 1,
86
+ actionId: 1,
87
+ updatedAt: -1
88
+ }),
89
+ jobsOf().createIndex({ expiresAt: 1 }, { expireAfterSeconds: 0 }),
90
+ schedulesOf().createIndex({
91
+ enabled: 1,
92
+ nextRunAt: 1
93
+ }),
94
+ schedulesOf().createIndex({ spaceId: 1 })
95
+ ]);
96
+ };
97
+ const collections = async () => {
98
+ ready ??= build().catch((error) => {
99
+ ready = void 0;
100
+ throw error;
101
+ });
102
+ await ready;
103
+ return {
104
+ jobs: jobsOf(),
105
+ schedules: schedulesOf()
106
+ };
107
+ };
108
+ const expiryOf = (at) => new Date(at + retentionDays * DAY_MS);
109
+ return {
110
+ resyncClock: clock.resync,
111
+ now: async () => new Date(await clock.now()),
112
+ enqueue: async (job) => {
113
+ const { jobs } = await collections();
114
+ const at = await clock.now();
115
+ const { id, ...fields } = job;
116
+ const document = {
117
+ ...fields,
118
+ _id: id,
119
+ status: "pending",
120
+ runAt: job.dueAt,
121
+ attempts: 0,
122
+ createdAt: at,
123
+ updatedAt: at,
124
+ history: []
125
+ };
126
+ try {
127
+ await jobs.insertOne(document);
128
+ return true;
129
+ } catch (error) {
130
+ if (error.code === DUPLICATE_KEY) return false;
131
+ throw error;
132
+ }
133
+ },
134
+ claim: async ({ workerId, leaseMs, limit }) => {
135
+ const { jobs } = await collections();
136
+ const at = await clock.now();
137
+ const taken = [];
138
+ for (let slot = 0; slot < limit; slot += 1) {
139
+ const claimed = await jobs.findOneAndUpdate({ $or: [{
140
+ status: "pending",
141
+ runAt: { $lte: at }
142
+ }, {
143
+ status: "running",
144
+ leaseUntil: { $lt: at }
145
+ }] }, [{ $set: { history: { $cond: [
146
+ { $eq: ["$status", "running"] },
147
+ lostAttempt(at),
148
+ "$history"
149
+ ] } } }, { $set: {
150
+ status: "running",
151
+ workerId,
152
+ leaseUntil: at + leaseMs,
153
+ updatedAt: at,
154
+ attempts: { $add: ["$attempts", 1] }
155
+ } }], {
156
+ sort: { runAt: 1 },
157
+ returnDocument: "after"
158
+ });
159
+ if (!claimed) break;
160
+ taken.push(toJob(claimed));
161
+ }
162
+ return taken;
163
+ },
164
+ heartbeat: async ({ jobIds, workerId, leaseMs }) => {
165
+ const { jobs } = await collections();
166
+ const at = await clock.now();
167
+ await jobs.updateMany({
168
+ _id: { $in: jobIds },
169
+ workerId,
170
+ status: "running"
171
+ }, { $set: { leaseUntil: at + leaseMs } });
172
+ return (await jobs.find({
173
+ _id: { $in: jobIds },
174
+ workerId,
175
+ status: "running",
176
+ cancelRequested: true
177
+ }).project({ _id: 1 }).toArray()).map((job) => job._id);
178
+ },
179
+ settle: async ({ jobId, workerId, status, delayMs, runId, error, attempt }) => {
180
+ const { jobs } = await collections();
181
+ const at = await clock.now();
182
+ const entry = {
183
+ attempt: { $add: [{ $size: "$history" }, 1] },
184
+ startedAt: "$updatedAt",
185
+ endedAt: at,
186
+ ...attempt
187
+ };
188
+ await jobs.updateOne({
189
+ _id: jobId,
190
+ workerId
191
+ }, [{ $set: {
192
+ ...attempt ? { history: { $concatArrays: ["$history", [entry]] } } : {},
193
+ status,
194
+ updatedAt: at,
195
+ leaseUntil: null,
196
+ error: error ?? null,
197
+ ...runId ? { runId } : {},
198
+ ...status === "pending" ? {
199
+ runAt: at + (delayMs ?? 0),
200
+ workerId: null,
201
+ ...attempt ? {} : { attempts: { $max: [0, { $subtract: ["$attempts", 1] }] } }
202
+ } : {},
203
+ expiresAt: TERMINAL.includes(status) ? expiryOf(at) : null
204
+ } }]);
205
+ },
206
+ dueSchedules: async (limit) => {
207
+ const { schedules } = await collections();
208
+ const at = await clock.now();
209
+ return (await schedules.find({
210
+ enabled: true,
211
+ nextRunAt: { $lte: at }
212
+ }).sort({ nextRunAt: 1 }).limit(limit).toArray()).map(toSchedule);
213
+ },
214
+ advanceSchedule: async ({ spaceId, actionId, from, to, missed }) => {
215
+ const { schedules } = await collections();
216
+ const at = await clock.now();
217
+ return (await schedules.updateOne({
218
+ _id: scheduleId(spaceId, actionId),
219
+ nextRunAt: from
220
+ }, {
221
+ $set: {
222
+ nextRunAt: to,
223
+ lastFireAt: from,
224
+ updatedAt: at
225
+ },
226
+ $inc: { missed }
227
+ })).matchedCount === 1;
228
+ },
229
+ putSchedules: async ({ spaceId, schedules: incoming }) => {
230
+ const { schedules } = await collections();
231
+ const at = await clock.now();
232
+ if (incoming.length > 0) await schedules.bulkWrite(incoming.map((schedule) => ({ updateOne: {
233
+ filter: { _id: scheduleId(spaceId, schedule.actionId) },
234
+ update: [{ $set: {
235
+ ...schedule,
236
+ timezone: schedule.timezone ?? null,
237
+ updatedAt: at,
238
+ missed: { $ifNull: ["$missed", 0] },
239
+ nextRunAt: { $cond: [
240
+ { $and: [
241
+ { $eq: ["$cron", schedule.cron] },
242
+ { $eq: [{ $ifNull: ["$timezone", null] }, schedule.timezone ?? null] },
243
+ { $eq: ["$environment", schedule.environment] },
244
+ { $ne: [{ $ifNull: ["$nextRunAt", null] }, null] }
245
+ ] },
246
+ "$nextRunAt",
247
+ schedule.nextRunAt
248
+ ] }
249
+ } }],
250
+ upsert: true
251
+ } })));
252
+ await schedules.deleteMany({
253
+ spaceId,
254
+ actionId: { $nin: incoming.map((schedule) => schedule.actionId) }
255
+ });
256
+ },
257
+ listJobs: async ({ spaceIds, actionId, status, limit, offset }) => {
258
+ const { jobs } = await collections();
259
+ const filter = {
260
+ spaceId: { $in: spaceIds },
261
+ ...actionId ? { actionId } : {},
262
+ ...status ? { status } : {}
263
+ };
264
+ const [found, total] = await Promise.all([jobs.find(filter).sort({
265
+ updatedAt: -1,
266
+ _id: -1
267
+ }).skip(offset).limit(limit).toArray(), jobs.countDocuments(filter)]);
268
+ return {
269
+ jobs: found.map(toJob),
270
+ total
271
+ };
272
+ },
273
+ getJob: async (spaceIds, jobId) => {
274
+ const { jobs } = await collections();
275
+ const job = await jobs.findOne({
276
+ _id: jobId,
277
+ spaceId: { $in: spaceIds }
278
+ });
279
+ return job ? toJob(job) : void 0;
280
+ },
281
+ listSchedules: async (spaceIds) => {
282
+ const { schedules } = await collections();
283
+ return (await schedules.find({ spaceId: { $in: spaceIds } }).sort({ nextRunAt: 1 }).toArray()).map(toSchedule);
284
+ },
285
+ requeue: async (spaceIds, jobId) => {
286
+ const { jobs } = await collections();
287
+ const at = await clock.now();
288
+ return (await jobs.updateOne({
289
+ _id: jobId,
290
+ spaceId: { $in: spaceIds },
291
+ status: { $in: TERMINAL }
292
+ }, {
293
+ $set: {
294
+ status: "pending",
295
+ runAt: at,
296
+ attempts: 0,
297
+ updatedAt: at,
298
+ cancelRequested: false
299
+ },
300
+ $unset: {
301
+ workerId: "",
302
+ leaseUntil: "",
303
+ error: "",
304
+ expiresAt: ""
305
+ }
306
+ })).matchedCount === 1;
307
+ },
308
+ cancel: async (spaceIds, jobId) => {
309
+ const { jobs } = await collections();
310
+ const at = await clock.now();
311
+ if ((await jobs.updateOne({
312
+ _id: jobId,
313
+ spaceId: { $in: spaceIds },
314
+ status: "pending"
315
+ }, {
316
+ $set: {
317
+ status: "cancelled",
318
+ updatedAt: at,
319
+ expiresAt: expiryOf(at)
320
+ },
321
+ $unset: { workerId: "" }
322
+ })).matchedCount === 1) return true;
323
+ return (await jobs.updateOne({
324
+ _id: jobId,
325
+ spaceId: { $in: spaceIds },
326
+ status: "running"
327
+ }, { $set: {
328
+ cancelRequested: true,
329
+ updatedAt: at
330
+ } })).matchedCount === 1;
331
+ }
332
+ };
333
+ };
334
+ //#endregion
335
+ export { createMongoJobQueue, resolveDb };
@@ -0,0 +1,15 @@
1
+ import { MongoDbSource } from './jobQueue';
2
+ import { ActionKvAdapter } from '../actions/types';
3
+ export type MongoKvOptions = {
4
+ db: MongoDbSource;
5
+ /** Default `action_kv`. */
6
+ collection?: string;
7
+ };
8
+ /**
9
+ * An {@link ActionKvAdapter} over a collection of a Mongo database the deployment owns.
10
+ *
11
+ * What the run guards' single-flight keys and the `kv` tasks' counters need from a store the replicas share: a TTL the
12
+ * store enforces and an increment nobody can race. Each operation is ONE document update, which Mongo applies
13
+ * atomically — so two replicas incrementing the same counter at once both count.
14
+ */
15
+ export declare const createMongoKv: ({ db, collection }: MongoKvOptions) => ActionKvAdapter;
@@ -0,0 +1,129 @@
1
+ import { resolveDb } from "./jobQueue.js";
2
+ //#region src/modules/mongo/kv.ts
3
+ /** Mongo's code for a unique index that refused a second document with the same key. */
4
+ var DUPLICATE_KEY = 11e3;
5
+ /**
6
+ * Whether a key is still alive, by the SERVER's clock.
7
+ *
8
+ * Mongo's TTL monitor sweeps once a minute, so a document past its lifetime can still be there to read. Expiry is
9
+ * decided here, against `$$NOW`, rather than by whether the sweeper has been round yet — the same answer Redis gives
10
+ * the instant a key lapses.
11
+ */
12
+ var LIVE = { $or: [{ $eq: [{ $ifNull: ["$expiresAt", null] }, null] }, { $gt: ["$expiresAt", "$$NOW"] }] };
13
+ var expiryIn = (ttlSeconds) => ({ $add: ["$$NOW", ttlSeconds * 1e3] });
14
+ /**
15
+ * An {@link ActionKvAdapter} over a collection of a Mongo database the deployment owns.
16
+ *
17
+ * What the run guards' single-flight keys and the `kv` tasks' counters need from a store the replicas share: a TTL the
18
+ * store enforces and an increment nobody can race. Each operation is ONE document update, which Mongo applies
19
+ * atomically — so two replicas incrementing the same counter at once both count.
20
+ */
21
+ var createMongoKv = ({ db, collection = "action_kv" }) => {
22
+ const keys = () => resolveDb(db).collection(collection);
23
+ let ready;
24
+ const store = async () => {
25
+ ready ??= keys().createIndex({ expiresAt: 1 }, { expireAfterSeconds: 0 }).then(() => void 0).catch((error) => {
26
+ ready = void 0;
27
+ throw error;
28
+ });
29
+ await ready;
30
+ return keys();
31
+ };
32
+ /**
33
+ * An upsert two replicas race for can collide on `_id` before either has written; the server retries that itself
34
+ * from 4.2 on, and this covers the rest. Once is enough: the second attempt finds the document the first one made.
35
+ */
36
+ const upserting = async (write) => {
37
+ try {
38
+ return await write();
39
+ } catch (error) {
40
+ if (error.code !== DUPLICATE_KEY) throw error;
41
+ return write();
42
+ }
43
+ };
44
+ return {
45
+ get: async (key) => {
46
+ return (await (await store()).findOne({
47
+ _id: key,
48
+ $expr: LIVE
49
+ }))?.value;
50
+ },
51
+ set: async (key, value, ttlSeconds) => {
52
+ const keysNow = await store();
53
+ await upserting(() => keysNow.updateOne({ _id: key }, [{ $set: {
54
+ value,
55
+ expiresAt: ttlSeconds === void 0 ? null : expiryIn(ttlSeconds)
56
+ } }], { upsert: true }));
57
+ },
58
+ delete: async (key) => {
59
+ await (await store()).deleteOne({ _id: key });
60
+ },
61
+ increment: async (key, amount) => {
62
+ const keysNow = await store();
63
+ const updated = await upserting(() => keysNow.findOneAndUpdate({ _id: key }, [
64
+ { $set: { live: LIVE } },
65
+ { $set: {
66
+ value: { $toString: { $add: [{ $cond: [
67
+ "$live",
68
+ { $convert: {
69
+ input: "$value",
70
+ to: "double",
71
+ onError: 0,
72
+ onNull: 0
73
+ } },
74
+ 0
75
+ ] }, amount] } },
76
+ expiresAt: { $cond: [
77
+ "$live",
78
+ { $ifNull: ["$expiresAt", null] },
79
+ null
80
+ ] }
81
+ } },
82
+ { $unset: "live" }
83
+ ], {
84
+ upsert: true,
85
+ returnDocument: "after"
86
+ }));
87
+ return Number(updated?.value ?? amount);
88
+ },
89
+ expire: async (key, ttlSeconds) => {
90
+ await (await store()).updateOne({
91
+ _id: key,
92
+ $expr: LIVE
93
+ }, [{ $set: { expiresAt: expiryIn(ttlSeconds) } }]);
94
+ },
95
+ /**
96
+ * Each branch is one update Mongo applies to the document atomically. Expecting a value, the filter names it.
97
+ * Expecting nothing is two cases: a lapsed document, taken over by a filter that matches only a lapsed one; and no
98
+ * document, inserted by an upsert whose filter no stored document satisfies — so a live one makes it collide on
99
+ * `_id`, which is the refusal, not an error. (An upsert may not filter with `$expr`, or this would be one step.)
100
+ */
101
+ swap: async (key, expected, next, ttlSeconds) => {
102
+ const keysNow = await store();
103
+ const write = [{ $set: {
104
+ value: next,
105
+ expiresAt: ttlSeconds === void 0 ? null : expiryIn(ttlSeconds)
106
+ } }];
107
+ if (expected !== void 0) return (await keysNow.updateOne({
108
+ _id: key,
109
+ value: expected,
110
+ $expr: LIVE
111
+ }, write)).matchedCount === 1;
112
+ if ((await keysNow.updateOne({
113
+ _id: key,
114
+ $expr: { $not: [LIVE] }
115
+ }, write)).matchedCount === 1) return true;
116
+ try {
117
+ return (await keysNow.updateOne({
118
+ _id: key,
119
+ value: { $exists: false }
120
+ }, write, { upsert: true })).upsertedCount === 1;
121
+ } catch (error) {
122
+ if (error.code === DUPLICATE_KEY) return false;
123
+ throw error;
124
+ }
125
+ }
126
+ };
127
+ };
128
+ //#endregion
129
+ export { createMongoKv };
@@ -0,0 +1 @@
1
+ export {};
@@ -1,3 +1,4 @@
1
+ import { activityDue } from "../../core/auth/sessionActivity.js";
1
2
  import { execute, selectOne, selectRows } from "./query.js";
2
3
  import { createSessionStore } from "./sessions.js";
3
4
  //#region src/modules/mysql/accounts.ts
@@ -50,12 +51,15 @@ var createAccountStore = (db, t) => {
50
51
  * check — deactivating somebody has to end the session they are already holding, not just the next login.
51
52
  */
52
53
  findAccountByToken: async (token) => {
53
- const row = await selectOne(db, `SELECT ${ACCOUNT_COLUMNS}, s.expires_at AS session_expires_at
54
+ const row = await selectOne(db, `SELECT ${ACCOUNT_COLUMNS}, s.id AS session_id, s.expires_at AS session_expires_at,
55
+ s.last_active_at AS session_last_active_at
54
56
  FROM ${t.session} s
55
57
  JOIN ${t.account} a ON a.id = s.account_id
56
58
  WHERE s.token = ? AND a.status = 'active'
57
59
  LIMIT 1`, [token]);
58
60
  if (!row) return;
61
+ const now = Math.floor(Date.now() / 1e3);
62
+ if (row.session_id !== void 0 && activityDue(row.session_last_active_at, now)) execute(db, `UPDATE ${t.session} SET last_active_at = ? WHERE id = ?`, [now, row.session_id]).catch(() => void 0);
59
63
  const { roles, permissions } = await loadAccess(row.id);
60
64
  return {
61
65
  id: row.id,
@@ -120,15 +124,18 @@ var createAccountStore = (db, t) => {
120
124
  ]);
121
125
  return;
122
126
  }
123
- await execute(db, `INSERT INTO ${t.session} (account_id, token, expires_at, refresh_token, refresh_expires_at, user_agent, ip)
124
- VALUES (?, ?, ?, ?, ?, ?, ?)`, [
127
+ await execute(db, `INSERT INTO ${t.session}
128
+ (account_id, token, expires_at, refresh_token, refresh_expires_at, user_agent, ip, app_name, app_id)
129
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`, [
125
130
  userId,
126
131
  session.token,
127
132
  session.expiresAt,
128
133
  session.refreshToken ?? null,
129
134
  session.refreshExpiresAt ?? null,
130
135
  context?.client?.userAgent?.slice(0, 255) ?? null,
131
- context?.client?.ip ?? null
136
+ context?.client?.ip ?? null,
137
+ context?.client?.app?.name.slice(0, 120) ?? null,
138
+ context?.client?.app?.softwareId?.slice(0, 64) ?? null
132
139
  ]);
133
140
  },
134
141
  /**
@@ -335,22 +342,25 @@ var createAccountStore = (db, t) => {
335
342
  * read whole and written whole, and a text column that a human can read in a crisis beats one they cannot.
336
343
  */
337
344
  loadMfa: async (userId) => {
338
- const row = await selectOne(db, `SELECT secret, confirmed_at, recovery_codes FROM ${t.mfa} WHERE account_id = ? LIMIT 1`, [userId]);
345
+ const row = await selectOne(db, `SELECT secret, confirmed_at, recovery_codes, last_used_step FROM ${t.mfa} WHERE account_id = ? LIMIT 1`, [userId]);
339
346
  if (!row) return;
340
347
  return {
341
348
  secret: row.secret,
342
349
  ...row.confirmed_at !== null ? { confirmedAt: row.confirmed_at } : {},
343
- recoveryCodes: (row.recovery_codes ?? "").split("\n").filter(Boolean)
350
+ recoveryCodes: (row.recovery_codes ?? "").split("\n").filter(Boolean),
351
+ ...row.last_used_step !== null ? { lastUsedStep: row.last_used_step } : {}
344
352
  };
345
353
  },
346
354
  saveMfa: async (userId, mfaRecord) => {
347
- await execute(db, `INSERT INTO ${t.mfa} (account_id, secret, confirmed_at, recovery_codes) VALUES (?, ?, ?, ?)
355
+ await execute(db, `INSERT INTO ${t.mfa} (account_id, secret, confirmed_at, recovery_codes, last_used_step) VALUES (?, ?, ?, ?, ?)
348
356
  ON DUPLICATE KEY UPDATE
349
- secret = VALUES(secret), confirmed_at = VALUES(confirmed_at), recovery_codes = VALUES(recovery_codes)`, [
357
+ secret = VALUES(secret), confirmed_at = VALUES(confirmed_at), recovery_codes = VALUES(recovery_codes),
358
+ last_used_step = VALUES(last_used_step)`, [
350
359
  userId,
351
360
  mfaRecord.secret,
352
361
  mfaRecord.confirmedAt ?? null,
353
- (mfaRecord.recoveryCodes ?? []).join("\n")
362
+ (mfaRecord.recoveryCodes ?? []).join("\n"),
363
+ mfaRecord.lastUsedStep ?? null
354
364
  ]);
355
365
  },
356
366
  deleteMfa: async (userId) => {
@@ -63,5 +63,6 @@ export { TABLE_NAMES, tableNames } from './config';
63
63
  export { SCHEMA_VERSION } from './schema';
64
64
  export type { MysqlConfig, TableKey, Tables } from './config';
65
65
  export type { AccountSeed, MysqlAdmin, SpaceTokenSeed } from './admin';
66
- export type { SessionStore, SessionSummary } from './sessions';
66
+ export type { SessionStore } from './sessions';
67
+ export type { SessionSummary } from '../../core/auth/api';
67
68
  export type { IdentityStore, LinkedIdentity } from './identities';
@@ -0,0 +1,5 @@
1
+ export { createMysqlJobQueue } from './jobQueue';
2
+ export { createMysqlKv } from './kv';
3
+ export { mysqlJobSchemaStatements, mysqlJobSchemaUpgrades } from './schema';
4
+ export type { MysqlJobQueue, MysqlJobQueueOptions } from './jobQueue';
5
+ export type { MysqlKvOptions } from './kv';
@@ -0,0 +1,40 @@
1
+ import { ActionJobQueue } from '@plitzi/sdk-shared';
2
+ import { Pool } from 'mysql2/promise';
3
+ export type MysqlJobQueueOptions = {
4
+ /** A pool the deployment opened. The helper borrows connections from it and never ends it. */
5
+ pool: Pool;
6
+ /** Prefix for the three tables — `action_jobs`, `action_schedules`, `action_kv`. Default none. */
7
+ tablePrefix?: string;
8
+ /**
9
+ * Create the tables on first use (`CREATE TABLE IF NOT EXISTS`). Default true; false for a deployment that runs
10
+ * {@link mysqlJobSchemaStatements} through its own migrations.
11
+ */
12
+ createTables?: boolean;
13
+ /** How long a finished job stays readable. A waiting or running one never expires. Default 90 days. */
14
+ retentionDays?: number;
15
+ };
16
+ export type MysqlJobQueue = ActionJobQueue & {
17
+ /** Takes the store's clock again on the next call — after a failover to another primary. */
18
+ resyncClock: () => void;
19
+ };
20
+ /**
21
+ * An {@link ActionJobQueue} over tables in a MySQL database the deployment owns. Tested on MySQL 8; nothing in it
22
+ * needs more than 5.7.
23
+ *
24
+ * The helper for a deployment that already runs MySQL: it borrows connections from the pool it is handed, and creates
25
+ * its three tables on first use unless told not to. Every replica pointed at the same database shares the jobs and the
26
+ * schedules.
27
+ *
28
+ * ```ts
29
+ * import mysql from 'mysql2/promise';
30
+ * import { createMysqlJobQueue, createMysqlKv } from '@plitzi/sdk-server/mysql';
31
+ *
32
+ * const pool = mysql.createPool(process.env.DATABASE_URL);
33
+ * createServer({ action: { lookups, kv: createMysqlKv({ pool }), jobs: { queue: createMysqlJobQueue({ pool }) } } });
34
+ * ```
35
+ *
36
+ * The contract's rules, as MySQL keeps them: every instant is the SERVER's (`NOW(3)`), `enqueue` is idempotent by the
37
+ * primary key, `claim` takes each job with a single-row compare-and-set — so two workers never take the same one —
38
+ * and reaps a lapsed lease in the same write, and a schedule advances by compare-and-set too.
39
+ */
40
+ export declare const createMysqlJobQueue: ({ pool, tablePrefix, createTables, retentionDays }: MysqlJobQueueOptions) => MysqlJobQueue;