@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
@@ -1,5 +1,7 @@
1
1
  import { authorizesDebugging } from "../../helpers/debugAuthorization.js";
2
+ import { realtimeModuleFor } from "../realtime/index.js";
2
3
  import { matchRscPage } from "../rsc/matchRscPage.js";
4
+ import { ssrPaintedCookieName } from "../../helpers/paintedCookie.js";
3
5
  import { readCookie } from "../../helpers/readCookie.js";
4
6
  import { buildOfflineDataCacheKey } from "../../helpers/cache/keys.js";
5
7
  import { loadPluginComponents } from "./loadPluginComponents.js";
@@ -7,18 +9,30 @@ import "../../core/previewToken.js";
7
9
  import { resolveActionEndpoint, resolveRscEndpoint } from "../../core/services/resolve.js";
8
10
  import { createOfflineDataLoader } from "../../helpers/offlineDataLoader.js";
9
11
  import { registerExternalPlugins } from "./registerExternalPlugins.js";
12
+ import { reportMissingPlugins } from "./reportMissingPlugins.js";
10
13
  import { resolvePageSeo } from "./resolvePageSeo.js";
11
14
  import { sdkAssetVersion } from "../../core/sdkAssets.js";
12
15
  import { buildServerInfo } from "../../helpers/buildServerInfo.js";
13
- import { escapeJson } from "../../helpers/escapeJson.js";
16
+ import { hydrationPayload } from "../../helpers/hydrationPayload.js";
14
17
  import { resolveDebugMode } from "../../helpers/resolveDebugMode.js";
15
18
  import { hasServerElements } from "@plitzi/sdk-shared/schema/serverElements";
16
19
  import { debugCookieName } from "@plitzi/sdk-shared/devTools";
17
20
  import { themeFromCookies } from "@plitzi/sdk-shared/theme";
21
+ import { paintedKeys, paintedStateFor } from "@plitzi/sdk-shared/state/paintedState";
18
22
  import { fontUrlResolver, fontsToHead } from "@plitzi/sdk-shared/style";
19
23
  //#region src/modules/ssr/prepareRender.tsx
20
24
  /** Last resort only: used for a page that declares no SEO title and a deployment that supplies none either. */
21
25
  var DEFAULT_TITLE = "Plitzi App";
26
+ /**
27
+ * The theme a space declares a first visit starts in, when it declares one other than `system`.
28
+ *
29
+ * `Partial`, because a style document written before themes existed has no `theme` at all, and a published space
30
+ * is rendered from whatever document it was published with.
31
+ */
32
+ var declaredTheme = (style) => {
33
+ const declared = style?.theme?.default;
34
+ return declared && declared !== "system" ? declared : void 0;
35
+ };
22
36
  var prepareRender = async (req, config, spaceId, environment, revision, pluginManager, offlineDataCache, metrics, offlineDataOverride) => {
23
37
  const m = (name, fn) => metrics ? metrics.measure(name, fn) : Promise.resolve(fn());
24
38
  const offlineCacheKey = environment !== "main" ? buildOfflineDataCacheKey(spaceId, environment, revision) : void 0;
@@ -44,7 +58,9 @@ var prepareRender = async (req, config, spaceId, environment, revision, pluginMa
44
58
  const server = buildServerInfo(req, config, {
45
59
  rscPath,
46
60
  rscData,
47
- actionPath: resolveActionEndpoint(config)
61
+ actionPath: resolveActionEndpoint(config),
62
+ realtimePath: realtimeModuleFor(config)?.path,
63
+ realtimeTransport: realtimeModuleFor(config)?.transport
48
64
  });
49
65
  if (offlineDataOverride === void 0 && !cachedOfflineStr && offlineCacheKey && offlineData !== void 0) offlineDataCache?.set(offlineCacheKey, JSON.stringify(offlineData));
50
66
  const version = config.assetVersion ?? sdkAssetVersion();
@@ -80,7 +96,6 @@ var prepareRender = async (req, config, spaceId, environment, revision, pluginMa
80
96
  ...analytics,
81
97
  firstViewCounted: true
82
98
  } : void 0;
83
- const branding = degrade ? true : void 0;
84
99
  const overQuota = degrade ? true : void 0;
85
100
  /**
86
101
  * The visitor's theme, from the cookie the SDK writes it to.
@@ -93,23 +108,33 @@ var prepareRender = async (req, config, spaceId, environment, revision, pluginMa
93
108
  * `{{ theme.resolved }}` or gate a rule on the scheme, and a client that started at `system` while the server
94
109
  * rendered `dark` would hydrate different markup and throw away the tree.
95
110
  *
96
- * Absent — a first visit — is not a problem to solve: nothing is stamped, `system` is what the provider starts
97
- * at, and the stylesheet's media queries answer, which is exactly right.
111
+ * Absent — a first visit — the space's own default applies (`style.theme.default`), painted by the server like a
112
+ * choice would be. A default of `system` stamps nothing and the stylesheet's media queries answer, which is exactly
113
+ * right for a space that did not pick.
114
+ */
115
+ const theme = themeFromCookies(req.headers.cookie) ?? declaredTheme(offlineData?.style);
116
+ /**
117
+ * The kept state the first paint depends on, from the cookie the SDK writes the space's `settings.paintedState` to.
118
+ *
119
+ * The theme's reasoning, for the space's own state: web storage is the browser's alone, so what a visitor chose — the
120
+ * tool a toolbar shows, their name in an avatar — would reach the page only after hydration, and be swapped in over
121
+ * the defaults the server drew. Read here, the server draws with it, and the page starts from the same values: it
122
+ * travels as the SDK's `state`, the starting `runtime.state`, in the render and in the payload alike, or the client
123
+ * would hydrate other markup. Only the keys the space declares, and only with `keepState` on.
98
124
  */
99
- const theme = themeFromCookies(req.headers.cookie);
100
- const offlineDataStr = escapeJson(JSON.stringify({
101
- offlineData,
125
+ const paintedState = schema?.settings.keepState ? paintedStateFor(req.headers.cookie, ssrPaintedCookieName(req.headers.host), paintedKeys(schema.settings)) : void 0;
126
+ const offlineDataStr = hydrationPayload(offlineData, {
102
127
  offlineMode: true,
103
128
  environment,
104
129
  renderMode: "raw",
105
130
  server,
106
131
  sdkDevToolsStylePath,
107
132
  ...theme ? { theme } : {},
133
+ ...paintedState ? { state: paintedState } : {},
108
134
  ...clientAnalytics ? { analytics: clientAnalytics } : {},
109
- ...branding ? { branding } : {},
110
135
  ...overQuota ? { overQuota } : {},
111
136
  ...actionRuns ? { actionRuns } : {}
112
- }));
137
+ });
113
138
  const pluginNames = req.ctx.spaceDeployment?.pluginNames ?? [];
114
139
  const pluginSources = req.ctx.spaceDeployment?.pluginSources;
115
140
  const pluginBaseNames = new Set(pluginNames.map((n) => n.replace(/@[^@]*$/, "")));
@@ -118,7 +143,7 @@ var prepareRender = async (req, config, spaceId, environment, revision, pluginMa
118
143
  const key = pluginManager.ensure(pluginName, pluginSource);
119
144
  if (!pluginBaseNames.has(pluginName)) dynamicNames.push(key);
120
145
  }
121
- const externalNamesFiltered = (config.autoLoadSchemaPlugins !== false ? await m("extPlugins", () => registerExternalPlugins(pluginManager, offlineData)) : []).filter((k) => !pluginBaseNames.has(k.replace(/@[^@]*$/, "")));
146
+ const externalNamesFiltered = (config.autoLoadSchemaPlugins !== false ? await m("extPlugins", () => registerExternalPlugins(pluginManager, offlineData, { allowPrivateHosts: config.allowPrivatePluginHosts === true })) : []).filter((k) => !pluginBaseNames.has(k.replace(/@[^@]*$/, "")));
122
147
  const allPluginNames = [
123
148
  ...pluginNames,
124
149
  ...dynamicNames,
@@ -126,6 +151,7 @@ var prepareRender = async (req, config, spaceId, environment, revision, pluginMa
126
151
  ];
127
152
  const entries = allPluginNames.length > 0 ? await pluginManager.getEntries(allPluginNames) : [];
128
153
  const pluginComponents = await m("plugins", () => loadPluginComponents(entries, pluginManager.getComponents()));
154
+ reportMissingPlugins(spaceId, schema, /* @__PURE__ */ new Set([...Object.keys(pluginComponents), ...entries.map((entry) => entry.keyName)]));
129
155
  const templatePlugins = (entries.length > 0 ? entries : req.ctx.spaceDeployment?.templateProps?.plugins)?.map((entry) => ({
130
156
  ...entry,
131
157
  ssr: entry.keyName in pluginComponents
@@ -139,9 +165,9 @@ var prepareRender = async (req, config, spaceId, environment, revision, pluginMa
139
165
  environment: req.ctx.spaceDeployment?.environment ?? environment,
140
166
  debugMode: debugRendered,
141
167
  sdkDevToolsStylePath,
142
- branding,
143
168
  overQuota,
144
- theme
169
+ theme,
170
+ ...paintedState ? { state: paintedState } : {}
145
171
  },
146
172
  entries,
147
173
  templateParams: {
@@ -1,7 +1,10 @@
1
+ import { StoreMethods } from '../../core/server/fleet/channel';
1
2
  import { DraftStore, OfflineDataRaw, SSRRequest, SSRServerConfig } from '@plitzi/sdk-shared';
2
3
  /** The READ side of draft-preview: a render resolving a stashed draft from its token. The write side — applying
3
4
  * unsaved operations and rendering the result — lives in `@plitzi/sdk-mcp`, which is what knows how to interpret an
4
5
  * operation; a page-only deployment keeps this much and never loads that. */
6
+ /** Every method of the store, for the copy a server's workers share (see `fleet/stores.ts`). */
7
+ export declare const DRAFT_STORE_METHODS: StoreMethods<DraftStore>;
5
8
  /** In-memory draft store — the default when the consumer injects none. Fine for a single replica; a multi-replica
6
9
  * deployment must inject a shared store so a preview URL resolves on any replica. */
7
10
  export declare const createMemoryDraftStore: () => DraftStore;
@@ -3,16 +3,23 @@ import { PREVIEW_COOKIE, readDraftToken } from "../../core/previewToken.js";
3
3
  /** The READ side of draft-preview: a render resolving a stashed draft from its token. The write side — applying
4
4
  * unsaved operations and rendering the result — lives in `@plitzi/sdk-mcp`, which is what knows how to interpret an
5
5
  * operation; a page-only deployment keeps this much and never loads that. */
6
+ /** Every method of the store, for the copy a server's workers share (see `fleet/stores.ts`). */
7
+ var DRAFT_STORE_METHODS = {
8
+ put: true,
9
+ take: true,
10
+ drop: true
11
+ };
6
12
  /** In-memory draft store — the default when the consumer injects none. Fine for a single replica; a multi-replica
7
13
  * deployment must inject a shared store so a preview URL resolves on any replica. */
8
14
  var createMemoryDraftStore = () => {
9
15
  const store = /* @__PURE__ */ new Map();
10
16
  return {
11
- put(token, data, { ttlMs, reusable = false }) {
17
+ put(token, data, { ttlMs, reusable = false, spaceId }) {
12
18
  store.set(token, {
13
19
  data,
14
20
  expiresAt: Date.now() + ttlMs,
15
- reusable
21
+ reusable,
22
+ spaceId
16
23
  });
17
24
  },
18
25
  take(token) {
@@ -21,7 +28,8 @@ var createMemoryDraftStore = () => {
21
28
  if (!hit.reusable || hit.expiresAt <= Date.now()) store.delete(token);
22
29
  return hit.expiresAt > Date.now() ? {
23
30
  data: hit.data,
24
- reusable: hit.reusable
31
+ reusable: hit.reusable,
32
+ spaceId: hit.spaceId
25
33
  } : void 0;
26
34
  },
27
35
  drop(token) {
@@ -39,10 +47,12 @@ var takeDraftOverride = async (req, config) => {
39
47
  const token = readDraftToken(req);
40
48
  if (!token || !config.draftStore) return;
41
49
  const entry = await config.draftStore.take(token);
42
- return entry ? {
43
- ...entry,
50
+ if (!entry || entry.spaceId !== req.ctx.spaceDeployment?.spaceId) return;
51
+ return {
52
+ data: entry.data,
53
+ reusable: entry.reusable,
44
54
  token
45
- } : void 0;
55
+ };
46
56
  };
47
57
  /** The `Set-Cookie` that carries a draft session through the rest of the visit. */
48
58
  var draftSessionCookie = (req, token, ttlMs) => [
@@ -54,4 +64,4 @@ var draftSessionCookie = (req, token, ttlMs) => [
54
64
  ...req.protocol === "https" ? ["Secure"] : []
55
65
  ].join("; ");
56
66
  //#endregion
57
- export { createMemoryDraftStore, draftSessionCookie, takeDraftOverride };
67
+ export { DRAFT_STORE_METHODS, createMemoryDraftStore, draftSessionCookie, takeDraftOverride };
@@ -0,0 +1 @@
1
+ export {};
@@ -1,7 +1,12 @@
1
1
  import { PluginManager } from '../../plugins/manager';
2
2
  import { OfflineDataRaw } from '@plitzi/sdk-shared';
3
+ /** Where a plugin may be read from: anywhere public, and — on a development machine only — a private address too. */
4
+ type ManifestReach = {
5
+ allowPrivateHosts: boolean;
6
+ };
3
7
  /**
4
8
  * Reads plugins listed in offlineData.plugins, fetches their manifests, downloads and caches
5
9
  * JS/CSS via the PluginManager, and returns the effective plugin keys to pass to getEntries().
6
10
  */
7
- export declare const registerExternalPlugins: (pluginManager: PluginManager, offlineData: OfflineDataRaw | undefined) => Promise<string[]>;
11
+ export declare const registerExternalPlugins: (pluginManager: PluginManager, offlineData: OfflineDataRaw | undefined, reach?: ManifestReach) => Promise<string[]>;
12
+ export {};
@@ -1,3 +1,6 @@
1
+ import { serverLog } from "../../helpers/serverLog.js";
2
+ import { fetchOutbound } from "../../helpers/outboundGuard.js";
3
+ import { writeFileAtomic } from "../../helpers/atomicFile.js";
1
4
  import crypto from "node:crypto";
2
5
  import path from "node:path";
3
6
  import fs from "node:fs/promises";
@@ -22,17 +25,17 @@ var readDiskEntry = async (dir, resource) => {
22
25
  var writeDiskEntry = async (dir, resource, entry) => {
23
26
  try {
24
27
  await fs.mkdir(dir, { recursive: true });
25
- await fs.writeFile(cacheFilePath(dir, resource), JSON.stringify(entry), "utf-8");
28
+ await writeFileAtomic(cacheFilePath(dir, resource), JSON.stringify(entry));
26
29
  } catch (err) {
27
- console.warn(`[SSR] Failed to persist plugin manifest cache for ${resource}:`, err);
30
+ serverLog.warn("SSR", `Failed to persist plugin manifest cache for ${resource}`, err);
28
31
  }
29
32
  };
30
- var fetchAndStore = async (dir, resource) => {
33
+ var fetchAndStore = async (dir, resource, reach) => {
31
34
  try {
32
35
  const url = `${resource}/plugin-manifest.json`;
33
- const res = await fetch(url);
36
+ const res = reach.allowPrivateHosts ? await fetch(url) : await fetchOutbound(fetch, new URL(url));
34
37
  if (!res.ok) {
35
- console.warn(`[SSR] Failed to fetch plugin manifest from ${url}: HTTP ${res.status}`);
38
+ serverLog.warn("SSR", `Failed to fetch plugin manifest from ${url}: HTTP ${res.status}`);
36
39
  return null;
37
40
  }
38
41
  const manifest = await res.json();
@@ -44,24 +47,24 @@ var fetchAndStore = async (dir, resource) => {
44
47
  await writeDiskEntry(dir, resource, entry);
45
48
  return manifest;
46
49
  } catch (err) {
47
- console.warn(`[SSR] Error fetching plugin manifest from ${resource}:`, err);
50
+ serverLog.warn("SSR", `Error fetching plugin manifest from ${resource}`, err);
48
51
  return null;
49
52
  }
50
53
  };
51
- var revalidate = (dir, resource) => {
54
+ var revalidate = (dir, resource, reach) => {
52
55
  if (refreshing.has(resource)) return;
53
56
  refreshing.add(resource);
54
- fetchAndStore(dir, resource).finally(() => refreshing.delete(resource));
57
+ fetchAndStore(dir, resource, reach).finally(() => refreshing.delete(resource));
55
58
  };
56
- var fetchManifest = async (pluginManager, resource) => {
59
+ var fetchManifest = async (pluginManager, resource, reach) => {
57
60
  const dir = manifestCacheDir(pluginManager);
58
61
  const cached = manifestCache.get(resource) ?? await readDiskEntry(dir, resource) ?? void 0;
59
62
  if (cached) {
60
63
  manifestCache.set(resource, cached);
61
- if (cached.expiresAt <= Date.now()) revalidate(dir, resource);
64
+ if (cached.expiresAt <= Date.now()) revalidate(dir, resource, reach);
62
65
  return cached.manifest;
63
66
  }
64
- return fetchAndStore(dir, resource);
67
+ return fetchAndStore(dir, resource, reach);
65
68
  };
66
69
  var resolveAssetUrl = (resource, asset) => {
67
70
  if (asset.url) return asset.url;
@@ -74,13 +77,13 @@ var findAsset = (manifest, type, resource) => {
74
77
  return main ? resolveAssetUrl(resource, main) ?? void 0 : void 0;
75
78
  };
76
79
  var isAbsoluteUrl = (url) => url.startsWith("http://") || url.startsWith("https://");
77
- var registerPlugin = async (pluginManager, plugin) => {
80
+ var registerPlugin = async (pluginManager, plugin, reach) => {
78
81
  if (!plugin.resource || !isAbsoluteUrl(plugin.resource)) return null;
79
- const manifest = await fetchManifest(pluginManager, plugin.resource);
82
+ const manifest = await fetchManifest(pluginManager, plugin.resource, reach);
80
83
  if (!manifest) return null;
81
84
  const jsUrl = findAsset(manifest, "script", plugin.resource);
82
85
  if (!jsUrl) {
83
- console.warn(`[SSR] Plugin "${plugin.type}" has no JS asset in manifest, skipping`);
86
+ serverLog.warn("SSR", `Plugin "${plugin.type}" has no JS asset in manifest, skipping`);
84
87
  return null;
85
88
  }
86
89
  const source = {
@@ -95,10 +98,10 @@ var registerPlugin = async (pluginManager, plugin) => {
95
98
  * Reads plugins listed in offlineData.plugins, fetches their manifests, downloads and caches
96
99
  * JS/CSS via the PluginManager, and returns the effective plugin keys to pass to getEntries().
97
100
  */
98
- var registerExternalPlugins = async (pluginManager, offlineData) => {
101
+ var registerExternalPlugins = async (pluginManager, offlineData, reach = { allowPrivateHosts: false }) => {
99
102
  const plugins = offlineData?.plugins;
100
103
  if (!plugins || plugins.length === 0) return [];
101
- return (await Promise.all(plugins.map((p) => registerPlugin(pluginManager, p)))).filter((k) => k !== null);
104
+ return (await Promise.all(plugins.map((p) => registerPlugin(pluginManager, p, reach)))).filter((k) => k !== null);
102
105
  };
103
106
  //#endregion
104
107
  export { registerExternalPlugins };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,9 @@
1
+ import { Schema } from '@plitzi/sdk-shared';
2
+ /**
3
+ * The plugin types a space renders that this server has nothing for — neither a component in the render nor a bundle
4
+ * for the browser. Each prints "Custom Component … Not Found" where the plugin should be, and nothing else anywhere
5
+ * says why, so it is said here: once per space and type, at `error`, because a visitor is looking at the placeholder.
6
+ *
7
+ * A `custom` element carrying its own `scriptUrl` loads itself in the browser and is not this server's to supply.
8
+ */
9
+ export declare const reportMissingPlugins: (spaceId: number, schema: Schema | undefined, available: ReadonlySet<string>) => void;
@@ -0,0 +1,24 @@
1
+ import { serverLog } from "../../helpers/serverLog.js";
2
+ //#region src/modules/ssr/reportMissingPlugins.ts
3
+ var reported = /* @__PURE__ */ new Set();
4
+ /**
5
+ * The plugin types a space renders that this server has nothing for — neither a component in the render nor a bundle
6
+ * for the browser. Each prints "Custom Component … Not Found" where the plugin should be, and nothing else anywhere
7
+ * says why, so it is said here: once per space and type, at `error`, because a visitor is looking at the placeholder.
8
+ *
9
+ * A `custom` element carrying its own `scriptUrl` loads itself in the browser and is not this server's to supply.
10
+ */
11
+ var reportMissingPlugins = (spaceId, schema, available) => {
12
+ if (!schema || !serverLog.enabled("error")) return;
13
+ for (const element of Object.values(schema.flat)) {
14
+ const { renderType, isPlugin, scriptUrl } = element.attributes;
15
+ const loadsItself = isPlugin === true && typeof scriptUrl === "string" && scriptUrl !== "";
16
+ if (element.definition.type !== "custom" || typeof renderType !== "string" || renderType === "" || loadsItself) continue;
17
+ const key = `${spaceId}:${renderType}`;
18
+ if (available.has(renderType) || reported.has(key)) continue;
19
+ reported.add(key);
20
+ serverLog.error("SSR", `Space ${String(spaceId)} renders the plugin "${renderType}" (element "${element.id}"), and this server has none by that name, so the page shows "Custom Component ${renderType} Not Found". Register it in \`plugins\` and name it in the deployment's \`pluginNames\`.`);
21
+ }
22
+ };
23
+ //#endregion
24
+ export { reportMissingPlugins };
@@ -0,0 +1 @@
1
+ export {};
@@ -1,5 +1,5 @@
1
- import { TtlCache } from '../../helpers/cache';
1
+ import { CachedPage, TtlCache } from '../../helpers/cache';
2
2
  import { RequestMetrics } from '../../helpers/metrics';
3
3
  import { PluginManager } from '../../plugins/manager';
4
4
  import { Environment, OfflineDataRaw, SSRPageServerConfig, SSRRequest, SSRResponseHelpers, SSRTemplateFn } from '@plitzi/sdk-shared';
5
- export declare const streamBody: (req: SSRRequest, res: SSRResponseHelpers, config: SSRPageServerConfig, spaceId: number, environment: Environment, revision: number, renderFn: SSRTemplateFn, pluginManager: PluginManager, offlineDataCache?: TtlCache<string>, htmlCache?: TtlCache<string>, cacheKey?: string, metrics?: RequestMetrics, offlineDataOverride?: OfflineDataRaw) => Promise<void>;
5
+ export declare const streamBody: (req: SSRRequest, res: SSRResponseHelpers, config: SSRPageServerConfig, spaceId: number, environment: Environment, revision: number, renderFn: SSRTemplateFn, pluginManager: PluginManager, offlineDataCache?: TtlCache<string>, htmlCache?: TtlCache<CachedPage>, cacheKey?: string, metrics?: RequestMetrics, offlineDataOverride?: OfflineDataRaw) => Promise<void>;
@@ -30,7 +30,10 @@ var streamBody = async (req, res, config, spaceId, environment, revision, render
30
30
  const tailBuf = Buffer.from(tail, "utf-8");
31
31
  res.write(tailBuf);
32
32
  res.end();
33
- if (chunks && cacheKey && htmlCache) htmlCache.set(cacheKey, head + Buffer.concat(chunks).toString("utf-8") + tail);
33
+ if (chunks && cacheKey && htmlCache) htmlCache.set(cacheKey, {
34
+ html: head + Buffer.concat(chunks).toString("utf-8") + tail,
35
+ compressed: {}
36
+ });
34
37
  resolve();
35
38
  cb();
36
39
  }
@@ -1,6 +1,6 @@
1
+ import path from "node:path";
1
2
  import { fileURLToPath } from "node:url";
2
3
  import fs from "node:fs";
3
- import path from "node:path";
4
4
  import ejs from "ejs";
5
5
  //#region src/modules/ssr/template.ts
6
6
  var __dirname = path.dirname(fileURLToPath(import.meta.url));
@@ -122,18 +122,21 @@
122
122
  <noscript>You need to enable JavaScript to run this app.</noscript>
123
123
  <div id="plitzi" class="plitzi-root-container"><%- locals.html || '' %></div>
124
124
  <% if (!locals.ssrOnly) { %>
125
+ <%# The payload is data, so it travels as JSON: parsing it as a JavaScript literal cost the browser several times
126
+ what JSON.parse does, on megabytes of it. Escaped by the server — no `<` reaches this block. %>
127
+ <script type="application/json" id="plitzi-ssr-data"><%- locals.offlineData || '{}' %></script>
125
128
  <script type="module">
126
129
  import { render } from '<%= locals.jsPath || '' %>';
127
130
  <% const activePlugins = (locals.plugins || []).filter(p => p.js); %>
128
- <% if (activePlugins.length > 0) { %>
129
131
  <% for (const plugin of activePlugins) { %>
130
132
  import { default as <%= plugin.varName %> } from '<%= plugin.js %>';
131
133
  <% } %>
132
134
  const __plitziPlugins = { <%- activePlugins.map(p => `'${p.keyName}': {component: ${p.varName}, props: ${JSON.stringify(p.props)}, clientOnly: ${p.ssr === false}}`).join(', ') %> };
133
- render('plitzi', <%- locals.offlineData || '{}' %>, __plitziPlugins, <%= locals.debugMode ? true : false %>, true);
134
- <% } else { %>
135
- render('plitzi', <%- locals.offlineData || '{}' %>, {}, <%= locals.debugMode ? true : false %>, true);
136
- <% } %>
135
+ const __plitziData = document.getElementById('plitzi-ssr-data');
136
+ const __plitziParams = JSON.parse(__plitziData.textContent);
137
+ // Read once: the page would otherwise hold the space twice, as this text and as what it was parsed into.
138
+ __plitziData.remove();
139
+ render('plitzi', __plitziParams, __plitziPlugins, <%= locals.debugMode ? true : false %>, true);
137
140
  </script>
138
141
  <% } %>
139
142
  </body>
@@ -0,0 +1,25 @@
1
+ /** Job queue and key/value helpers for a deployment that runs Mongo. Import them as `@plitzi/sdk-server/mongo`.
2
+ *
3
+ * The scheduler and the workers are the package's; WHERE the jobs wait is the deployment's — `action.jobs.queue`
4
+ * and `action.kv` are adapters, and the defaults keep everything in one process's memory. That is right for one
5
+ * replica and wrong for two: each gets its own copy of every schedule, and the jobs a replica was holding go with it
6
+ * when it stops. These are those adapters, already written for Mongo, over a database the deployment connects to
7
+ * and owns:
8
+ *
9
+ * ```ts
10
+ * import { MongoClient } from 'mongodb';
11
+ * import { createServer } from '@plitzi/sdk-server';
12
+ * import { createMongoJobQueue, createMongoKv } from '@plitzi/sdk-server/mongo';
13
+ *
14
+ * const db = new MongoClient(process.env.MONGO_URL).db('app');
15
+ *
16
+ * createServer({
17
+ * adapters,
18
+ * action: { lookups, kv: createMongoKv({ db }), jobs: { queue: createMongoJobQueue({ db }) } }
19
+ * });
20
+ * ```
21
+ *
22
+ * The package holds no connection and keeps no data of its own: it creates the indexes its queries need, in the
23
+ * collections it is told to use. `mongodb` is an optional peer dependency, used for its types alone. */
24
+ export { createMongoJobQueue, createMongoKv } from './modules/mongo';
25
+ export type { MongoDbSource, MongoJobQueue, MongoJobQueueOptions, MongoKvOptions } from './modules/mongo';
package/dist/mongo.js ADDED
@@ -0,0 +1,3 @@
1
+ import { createMongoJobQueue } from "./modules/mongo/jobQueue.js";
2
+ import { createMongoKv } from "./modules/mongo/kv.js";
3
+ export { createMongoJobQueue, createMongoKv };
package/dist/mysql.d.ts CHANGED
@@ -22,5 +22,16 @@
22
22
  * The tables are documented in `docs/auth/mysql-schema.md` — what each one is for, and what a deployment mapping
23
23
  * its existing schema onto the adapters has to be able to answer. */
24
24
  export { createMysqlStore, mysqlSchemaStatements } from './modules/mysql';
25
+ /**
26
+ * The job queue and the key/value store server actions run on, for a deployment that keeps them in MySQL rather than
27
+ * in one process's memory — which is what running more than one replica needs. They borrow connections from a pool
28
+ * the deployment opened (`store.pool` works) and create their three tables on first use:
29
+ *
30
+ * ```ts
31
+ * createServer({ action: { lookups, kv: createMysqlKv({ pool }), jobs: { queue: createMysqlJobQueue({ pool }) } } });
32
+ * ```
33
+ */
34
+ export { createMysqlJobQueue, createMysqlKv, mysqlJobSchemaStatements, mysqlJobSchemaUpgrades } from './modules/mysql/jobs';
35
+ export type { MysqlJobQueue, MysqlJobQueueOptions, MysqlKvOptions } from './modules/mysql/jobs';
25
36
  export { SCHEMA_VERSION, TABLE_NAMES, tableNames } from './modules/mysql';
26
37
  export type { AccountSeed, MysqlAdmin, MysqlConfig, IdentityStore, LinkedIdentity, MysqlStore, SessionStore, SessionSummary, SpaceTokenSeed, TableKey, Tables } from './modules/mysql';
package/dist/mysql.js CHANGED
@@ -1,4 +1,7 @@
1
1
  import { TABLE_NAMES, tableNames } from "./modules/mysql/config.js";
2
2
  import { SCHEMA_VERSION } from "./modules/mysql/schema.js";
3
3
  import { createMysqlStore, mysqlSchemaStatements } from "./modules/mysql/index.js";
4
- export { SCHEMA_VERSION, TABLE_NAMES, createMysqlStore, mysqlSchemaStatements, tableNames };
4
+ import { mysqlJobSchemaStatements, mysqlJobSchemaUpgrades } from "./modules/mysql/jobs/schema.js";
5
+ import { createMysqlJobQueue } from "./modules/mysql/jobs/jobQueue.js";
6
+ import { createMysqlKv } from "./modules/mysql/jobs/kv.js";
7
+ export { SCHEMA_VERSION, TABLE_NAMES, createMysqlJobQueue, createMysqlKv, createMysqlStore, mysqlJobSchemaStatements, mysqlJobSchemaUpgrades, mysqlSchemaStatements, tableNames };
package/dist/oauth.js CHANGED
@@ -1,10 +1,10 @@
1
+ import { dropPending, getAccess, getClient, getPending, putCode, putPending } from "./core/oauth/records.js";
1
2
  import { AUTHORIZATION_SERVER_PATH, AUTHORIZE_PATH, PROTECTED_RESOURCE_PATH, REGISTER_PATH, TOKEN_PATH, authorizationServerMetadata, protectedResourceMetadata } from "./core/oauth/metadata.js";
2
3
  import { randomId, verifyChallenge } from "./core/oauth/pkce.js";
3
- import { dropPending, getAccess, getClient, getPending, putCode, putPending } from "./core/oauth/records.js";
4
4
  import { redirectToSignIn, redirectWithCode, redirectWithError, sendErrorJson, sendJson } from "./core/oauth/respond.js";
5
+ import { handleRegister } from "./core/oauth/register.js";
5
6
  import { handleAuthorizeStart, handleAuthorizeSubmit } from "./core/oauth/authorize.js";
6
7
  import { bearerOf, sendChallenge } from "./core/oauth/challenge.js";
7
- import { handleRegister } from "./core/oauth/register.js";
8
8
  import { handleRevoke, handleToken } from "./core/oauth/token.js";
9
9
  import { createOAuthGuardStage, createOAuthStage } from "./core/http/stages/oauth.js";
10
10
  export { AUTHORIZATION_SERVER_PATH, AUTHORIZE_PATH, PROTECTED_RESOURCE_PATH, REGISTER_PATH, TOKEN_PATH, authorizationServerMetadata, bearerOf, createOAuthGuardStage, createOAuthStage, dropPending, getAccess, getClient, getPending, handleAuthorizeStart, handleAuthorizeSubmit, handleRegister, handleRevoke, handleToken, protectedResourceMetadata, putCode, putPending, randomId, redirectToSignIn, redirectWithCode, redirectWithError, sendChallenge, sendErrorJson, sendJson, verifyChallenge };
@@ -1,6 +1,7 @@
1
+ import { writeFileAtomic } from "../helpers/atomicFile.js";
1
2
  import path from "node:path";
2
- import fs from "node:fs/promises";
3
3
  import esbuild from "esbuild";
4
+ import fs from "node:fs/promises";
4
5
  //#region src/plugins/compile.ts
5
6
  var EXTERNAL = [
6
7
  "react",
@@ -29,7 +30,8 @@ var ASSET_LOADERS = {
29
30
  ".woff2": "dataurl"
30
31
  };
31
32
  /**
32
- * Everything that went into the bundle, so a dev server can tell when any of it has moved on.
33
+ * Everything that went into the bundle, so a server can tell when any of it has moved on: a dev server as it is
34
+ * edited, and any server — a deployment — when it finds a bundle built from something else (its content digest).
33
35
  *
34
36
  * The entry file is one file and a plugin is a directory: a component edited beside its `index.ts` leaves the entry's
35
37
  * timestamp exactly where it was, and a watcher looking only at that never rebuilds. esbuild already knows the answer
@@ -52,10 +54,13 @@ var compilePlugin = async (jsPath, outDir, devMode = false) => {
52
54
  minify: !devMode,
53
55
  splitting: false,
54
56
  logLevel: "warning",
55
- metafile: devMode
57
+ metafile: true,
58
+ write: false
56
59
  });
60
+ await fs.mkdir(outDir, { recursive: true });
61
+ await Promise.all(result.outputFiles.map((output) => writeFileAtomic(output.path, output.contents)));
57
62
  return {
58
- hasCSS: await fs.access(path.join(outDir, "index.css")).then(() => true).catch(() => false),
63
+ hasCSS: result.outputFiles.some((output) => path.basename(output.path) === "index.css"),
59
64
  inputs: sourceInputs(result.metafile)
60
65
  };
61
66
  };
@@ -1,13 +1,13 @@
1
+ import { copyFileAtomic, writeFileAtomic } from "../helpers/atomicFile.js";
1
2
  import path from "node:path";
2
- import fs from "node:fs/promises";
3
3
  //#region src/plugins/copy.ts
4
4
  var copyPlugin = async (src, destDir, filename) => {
5
5
  const dest = path.join(destDir, filename);
6
6
  if (src.startsWith("http://") || src.startsWith("https://")) {
7
7
  const res = await fetch(src);
8
8
  if (!res.ok) throw new Error(`[SSR] Plugin fetch failed ${src}: ${res.status}`);
9
- await fs.writeFile(dest, await res.text(), "utf-8");
10
- } else await fs.copyFile(src, dest);
9
+ await writeFileAtomic(dest, await res.text());
10
+ } else await copyFileAtomic(src, dest);
11
11
  };
12
12
  //#endregion
13
13
  export { copyPlugin };
@@ -14,9 +14,18 @@ export declare class PluginManager {
14
14
  hasPlugin(name: string): boolean;
15
15
  register(name: string, source: PluginSource): void;
16
16
  /**
17
- * Registers a plugin only if it is not yet known under its effective key.
18
- * Returns the effective key (`name@version` when version is set, `name` otherwise)
19
- * so the caller can pass it directly to getEntries().
17
+ * Keeps a source a render names, and returns the key to pass to getEntries(): `name@version+<identity>`, or
18
+ * `name@<identity>` without a version.
19
+ *
20
+ * The identity is what the source IS — where its files are, how they are served, the props it carries — because a
21
+ * name and a version are only what its author said about it. Keyed on those alone, the first source to arrive held
22
+ * the key for as long as the process ran: a plugin published again under the same version kept its old, now missing
23
+ * URLs, and two spaces each with a `board@1.0.0` of their own were served whichever this process had met first.
24
+ * Worked out from the source rather than handed out in order of arrival, so every worker names one source the same
25
+ * way — the key is also the folder a built bundle is written to, and all of them share it.
26
+ *
27
+ * Never taken as what a bare name means: {@link resolveKey} answers for the plugins this server was set up with, not
28
+ * for whichever space rendered last.
20
29
  */
21
30
  ensure(name: string, source: PluginSource): string;
22
31
  /**
@@ -46,6 +55,18 @@ export declare class PluginManager {
46
55
  * `checkedAt` is stamped on the cached entry rather than kept in a second map, so it cannot outlive what it is about.
47
56
  */
48
57
  private isStaleInMemory;
58
+ /**
59
+ * Whether what a bundle on disk was built from reads differently now — asked once, when a process first finds the
60
+ * bundle, in production as much as in development.
61
+ *
62
+ * A version names a release, and a release is only as good as whoever bumps it: a deployment rebuilt from new source
63
+ * under the same version found last deployment's bundle in its cache folder and served it, with nothing anywhere
64
+ * saying so. The content decides instead. A bundle written before digests were recorded has none, and is built again
65
+ * once. What this server does not build from files — a download, a CDN, a component — is its version's business.
66
+ */
67
+ private contentChanged;
68
+ /** The local files a bundle is built from: what the compiler reported, or the files it was copied from. */
69
+ private inputsOf;
49
70
  private isStale;
50
71
  /**
51
72
  * The bundle's URL, stamped with when it was built.
@@ -68,10 +89,21 @@ export declare class PluginManager {
68
89
  */
69
90
  private toRemoteEntry;
70
91
  private isWebUrl;
92
+ /**
93
+ * Builds every registered plugin now rather than on first use. A primary does it before starting its workers, so
94
+ * the workers find each one built — instead of all of them compiling the same plugin into the same folder at once.
95
+ */
96
+ prepareAll(): Promise<void>;
71
97
  prepare(name: string): Promise<PluginEntry | null>;
72
98
  private build;
73
99
  getEntries(names: string[]): Promise<PluginEntry[]>;
74
100
  getComponents(): Record<string, unknown>;
101
+ /**
102
+ * Drops what this process remembers of a plugin — its entry, its failure, which version its name means — and
103
+ * leaves the disk alone. What an invalidation elsewhere in the fleet does here: that process removes the files,
104
+ * and each of the others only has to stop pointing at them.
105
+ */
106
+ forget(name?: string, version?: string): void;
75
107
  invalidate(name?: string, version?: string): Promise<void>;
76
108
  destroy(): void;
77
109
  private readMeta;