@plitzi/sdk-server 0.37.2 → 0.37.4

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 (359) hide show
  1. package/CHANGELOG.md +1170 -0
  2. package/README.md +100 -7
  3. package/dist/actions.d.ts +6 -2
  4. package/dist/actions.js +5 -2
  5. package/dist/adapters/cloudAdapters.js +4 -3
  6. package/dist/adapters/jsonAdapters.js +28 -6
  7. package/dist/adapters/jsonAdapters.test.d.ts +1 -0
  8. package/dist/auth.d.ts +7 -4
  9. package/dist/auth.js +8 -6
  10. package/dist/core/auth/api.d.ts +29 -1
  11. package/dist/core/auth/api.js +47 -13
  12. package/dist/core/auth/createAuth.d.ts +4 -0
  13. package/dist/core/auth/createAuth.js +3 -3
  14. package/dist/core/auth/credentials.d.ts +3 -0
  15. package/dist/core/auth/credentials.js +1 -1
  16. package/dist/core/auth/csrf.d.ts +25 -1
  17. package/dist/core/auth/csrf.js +29 -4
  18. package/dist/core/auth/renewal.d.ts +26 -0
  19. package/dist/core/auth/renewal.js +24 -0
  20. package/dist/core/auth/routes.js +8 -6
  21. package/dist/core/auth/session.d.ts +45 -0
  22. package/dist/core/auth/session.js +47 -1
  23. package/dist/core/auth/sessionActivity.d.ts +11 -0
  24. package/dist/core/auth/sessionActivity.js +14 -0
  25. package/dist/core/auth/throttle.d.ts +15 -0
  26. package/dist/core/auth/throttle.js +29 -1
  27. package/dist/core/auth/totp.d.ts +9 -1
  28. package/dist/core/auth/totp.js +11 -6
  29. package/dist/core/createServer.actions.test.d.ts +1 -0
  30. package/dist/core/createServer.d.ts +14 -1
  31. package/dist/core/createServer.functions.test.d.ts +1 -0
  32. package/dist/core/createServer.js +22 -12
  33. package/dist/core/fontStore.js +1 -1
  34. package/dist/core/handlers/authRouteHandlers.d.ts +1 -1
  35. package/dist/core/handlers/authRouteHandlers.js +57 -21
  36. package/dist/core/handlers/csrfMiddleware.d.ts +23 -0
  37. package/dist/core/handlers/csrfMiddleware.js +31 -7
  38. package/dist/core/handlers/csrfMiddleware.test.d.ts +1 -0
  39. package/dist/core/handlers/oauthRouteHandlers.js +5 -3
  40. package/dist/core/handlers/socialRouteHandlers.d.ts +1 -1
  41. package/dist/core/handlers/socialRouteHandlers.js +2 -1
  42. package/dist/core/http/dispatcher.d.ts +9 -1
  43. package/dist/core/http/dispatcher.js +38 -11
  44. package/dist/core/http/navigation.d.ts +5 -2
  45. package/dist/core/http/navigation.js +7 -4
  46. package/dist/core/http/socketResponse.d.ts +18 -0
  47. package/dist/core/http/socketResponse.js +59 -0
  48. package/dist/core/http/sse.d.ts +26 -0
  49. package/dist/core/http/sse.js +78 -0
  50. package/dist/core/http/stages/authRoutes.js +3 -1
  51. package/dist/core/http/stages/exchangeRoute.test.d.ts +1 -0
  52. package/dist/core/http/stages/middlewares.d.ts +1 -1
  53. package/dist/core/http/stages/middlewares.js +16 -10
  54. package/dist/core/http/stages/middlewares.test.d.ts +1 -0
  55. package/dist/core/http/stages/oauth.js +2 -2
  56. package/dist/core/http/stages/sessionRenewal.d.ts +16 -0
  57. package/dist/core/http/stages/sessionRenewal.js +81 -0
  58. package/dist/core/http/stages/sessionRenewal.test.d.ts +1 -0
  59. package/dist/core/http/stages/signInRoute.d.ts +2 -0
  60. package/dist/core/http/stages/signInRoute.js +139 -0
  61. package/dist/core/http/stages/signInRoute.test.d.ts +1 -0
  62. package/dist/core/http/types.d.ts +9 -0
  63. package/dist/core/http/webExchange.d.ts +18 -0
  64. package/dist/core/http/webExchange.js +53 -0
  65. package/dist/core/oauth/authorize.js +37 -13
  66. package/dist/core/oauth/consentPage.js +11 -0
  67. package/dist/core/oauth/issueContext.d.ts +14 -0
  68. package/dist/core/oauth/issueContext.js +32 -0
  69. package/dist/core/oauth/records.d.ts +7 -0
  70. package/dist/core/oauth/register.d.ts +2 -0
  71. package/dist/core/oauth/register.js +32 -11
  72. package/dist/core/oauth/register.test.d.ts +1 -0
  73. package/dist/core/oauth/token.js +21 -6
  74. package/dist/core/oauth/token.test.d.ts +1 -0
  75. package/dist/core/requestParser.d.ts +4 -0
  76. package/dist/core/requestParser.js +14 -7
  77. package/dist/core/sdkAssets.js +1 -1
  78. package/dist/core/server/baseServer.d.ts +10 -0
  79. package/dist/core/server/baseServer.js +42 -11
  80. package/dist/core/server/closeOnSignals.js +4 -3
  81. package/dist/core/server/drain.d.ts +18 -0
  82. package/dist/core/server/drain.js +62 -0
  83. package/dist/core/server/drain.test.d.ts +1 -0
  84. package/dist/core/server/fleet/channel.d.ts +103 -0
  85. package/dist/core/server/fleet/channel.js +191 -0
  86. package/dist/core/server/fleet/channel.test.d.ts +1 -0
  87. package/dist/core/server/fleet/fixtures/fleetServer.d.ts +1 -0
  88. package/dist/core/server/fleet/fleet.integration.test.d.ts +1 -0
  89. package/dist/core/server/fleet/link.d.ts +23 -0
  90. package/dist/core/server/fleet/link.js +70 -0
  91. package/dist/core/server/fleet/relay.d.ts +11 -0
  92. package/dist/core/server/fleet/relay.js +104 -0
  93. package/dist/core/server/fleet/relay.test.d.ts +1 -0
  94. package/dist/core/server/fleet/role.d.ts +46 -0
  95. package/dist/core/server/fleet/role.js +59 -0
  96. package/dist/core/server/fleet/role.test.d.ts +1 -0
  97. package/dist/core/server/fleet/stores.d.ts +7 -0
  98. package/dist/core/server/fleet/stores.js +19 -0
  99. package/dist/core/server/fleet/supervisor.d.ts +26 -0
  100. package/dist/core/server/fleet/supervisor.js +108 -0
  101. package/dist/core/server/fleet/supervisor.test.d.ts +1 -0
  102. package/dist/core/server/pageServer.js +34 -5
  103. package/dist/core/services/action.js +10 -2
  104. package/dist/core/services/functionRoutes.d.ts +9 -0
  105. package/dist/core/services/functionRoutes.js +47 -0
  106. package/dist/core/services/realtime.d.ts +8 -0
  107. package/dist/core/services/realtime.js +57 -0
  108. package/dist/core/services/registry.js +6 -2
  109. package/dist/core/staticFiles.js +12 -4
  110. package/dist/core/staticFiles.test.d.ts +1 -0
  111. package/dist/core/transports.d.ts +13 -3
  112. package/dist/core/transports.js +14 -5
  113. package/dist/functions-api.d.ts +281 -0
  114. package/dist/functions.d.ts +19 -0
  115. package/dist/functions.js +5 -0
  116. package/dist/functionsRunner.d.ts +15 -0
  117. package/dist/functionsRunner.js +6 -0
  118. package/dist/handlers.d.ts +2 -2
  119. package/dist/handlers.js +2 -2
  120. package/dist/helpers/atomicFile.d.ts +10 -0
  121. package/dist/helpers/atomicFile.js +33 -0
  122. package/dist/helpers/atomicFile.test.d.ts +1 -0
  123. package/dist/helpers/buildResponseHelpers.js +35 -11
  124. package/dist/helpers/buildServerInfo.js +4 -2
  125. package/dist/helpers/buildServerInfo.test.d.ts +1 -0
  126. package/dist/helpers/cache/CompressedFileCache.d.ts +18 -0
  127. package/dist/helpers/cache/CompressedFileCache.js +44 -0
  128. package/dist/helpers/cache/CompressedFileCache.test.d.ts +1 -0
  129. package/dist/helpers/cache/cacheManager.d.ts +1 -1
  130. package/dist/helpers/cache/cacheManager.js +2 -1
  131. package/dist/helpers/cache/cacheManager.test.d.ts +1 -0
  132. package/dist/helpers/cache/index.d.ts +1 -1
  133. package/dist/helpers/cache/keys.d.ts +15 -1
  134. package/dist/helpers/cache/keys.js +47 -5
  135. package/dist/helpers/cache/serverCaches.d.ts +7 -1
  136. package/dist/helpers/compress.d.ts +3 -1
  137. package/dist/helpers/compress.js +11 -3
  138. package/dist/helpers/hydrationPayload.d.ts +11 -0
  139. package/dist/helpers/hydrationPayload.js +51 -0
  140. package/dist/helpers/hydrationPayload.test.d.ts +1 -0
  141. package/dist/helpers/metrics.d.ts +1 -1
  142. package/dist/helpers/metrics.js +3 -2
  143. package/dist/helpers/outboundGuard.d.ts +14 -6
  144. package/dist/helpers/outboundGuard.js +132 -8
  145. package/dist/helpers/paintedCookie.d.ts +8 -0
  146. package/dist/helpers/paintedCookie.js +13 -0
  147. package/dist/helpers/reportReactBuild.d.ts +9 -0
  148. package/dist/helpers/reportReactBuild.js +18 -0
  149. package/dist/helpers/reportReactBuild.test.d.ts +1 -0
  150. package/dist/helpers/serverLog.d.ts +25 -1
  151. package/dist/helpers/serverLog.js +68 -3
  152. package/dist/helpers/serverLog.test.d.ts +1 -0
  153. package/dist/helpers/wsFrame.d.ts +3 -0
  154. package/dist/helpers/wsFrame.js +5 -0
  155. package/dist/index.d.ts +6 -1
  156. package/dist/index.js +5 -2
  157. package/dist/kernel.d.ts +2 -1
  158. package/dist/kernel.js +3 -2
  159. package/dist/modules/actions/connectorWrite.js +2 -1
  160. package/dist/modules/actions/index.d.ts +29 -10
  161. package/dist/modules/actions/index.js +43 -6
  162. package/dist/modules/actions/jobs/failureStreak.d.ts +17 -0
  163. package/dist/modules/actions/jobs/failureStreak.js +47 -0
  164. package/dist/modules/actions/jobs/failureStreak.test.d.ts +1 -0
  165. package/dist/modules/actions/jobs/index.d.ts +2 -1
  166. package/dist/modules/actions/jobs/index.js +5 -3
  167. package/dist/modules/actions/jobs/memoryQueue.d.ts +3 -0
  168. package/dist/modules/actions/jobs/memoryQueue.js +17 -1
  169. package/dist/modules/actions/jobs/scheduler.d.ts +2 -0
  170. package/dist/modules/actions/jobs/scheduler.js +12 -7
  171. package/dist/modules/actions/jobs/worker.d.ts +3 -1
  172. package/dist/modules/actions/jobs/worker.js +9 -4
  173. package/dist/modules/actions/moduleFor.js +5 -2
  174. package/dist/modules/actions/runtime/errors.d.ts +12 -0
  175. package/dist/modules/actions/runtime/errors.js +16 -1
  176. package/dist/modules/actions/runtime/kvChange.d.ts +27 -0
  177. package/dist/modules/actions/runtime/kvChange.js +23 -0
  178. package/dist/modules/actions/runtime/kvList.d.ts +51 -0
  179. package/dist/modules/actions/runtime/kvList.js +52 -0
  180. package/dist/modules/actions/runtime/kvStore.d.ts +8 -0
  181. package/dist/modules/actions/runtime/kvStore.js +46 -20
  182. package/dist/modules/actions/runtime/memoryKv.d.ts +3 -0
  183. package/dist/modules/actions/runtime/memoryKv.js +19 -1
  184. package/dist/modules/actions/runtime/namespaceKv.d.ts +4 -6
  185. package/dist/modules/actions/runtime/namespaceKv.js +15 -3
  186. package/dist/modules/actions/runtime/namespaceKv.test.d.ts +1 -0
  187. package/dist/modules/actions/runtime/precheck.js +4 -8
  188. package/dist/modules/actions/runtime/rateLimit.d.ts +19 -0
  189. package/dist/modules/actions/runtime/rateLimit.js +19 -0
  190. package/dist/modules/actions/runtime/redisKv.d.ts +27 -0
  191. package/dist/modules/actions/runtime/redisKv.integration.test.d.ts +1 -0
  192. package/dist/modules/actions/runtime/redisKv.js +46 -0
  193. package/dist/modules/actions/runtime/report.js +2 -1
  194. package/dist/modules/actions/runtime/runAction.d.ts +10 -2
  195. package/dist/modules/actions/runtime/runAction.js +52 -116
  196. package/dist/modules/actions/runtime/runLogger.d.ts +5 -0
  197. package/dist/modules/actions/runtime/runLogger.js +8 -2
  198. package/dist/modules/actions/runtime/signing.d.ts +20 -0
  199. package/dist/modules/actions/runtime/signing.js +25 -0
  200. package/dist/modules/actions/runtime/signing.test.d.ts +1 -0
  201. package/dist/modules/actions/runtime/taskContext.d.ts +33 -0
  202. package/dist/modules/actions/runtime/taskContext.js +124 -0
  203. package/dist/modules/actions/tasks/builtins.js +5 -1
  204. package/dist/modules/actions/tasks/flow.js +81 -10
  205. package/dist/modules/actions/tasks/helpers.js +2 -2
  206. package/dist/modules/actions/tasks/http.js +2 -3
  207. package/dist/modules/actions/tasks/kv.js +39 -0
  208. package/dist/modules/actions/tasks/list.d.ts +2 -0
  209. package/dist/modules/actions/tasks/list.js +145 -0
  210. package/dist/modules/actions/tasks/realtime.d.ts +2 -0
  211. package/dist/modules/actions/tasks/realtime.js +104 -0
  212. package/dist/modules/actions/tasks/registry.d.ts +10 -1
  213. package/dist/modules/actions/tasks/registry.js +17 -6
  214. package/dist/modules/actions/transport/callHandler.js +5 -2
  215. package/dist/modules/actions/transport/catalogHandler.d.ts +5 -2
  216. package/dist/modules/actions/transport/catalogHandler.js +3 -2
  217. package/dist/modules/actions/transport/stream.d.ts +4 -5
  218. package/dist/modules/actions/transport/stream.js +12 -76
  219. package/dist/modules/actions/transport/webhookHandler.js +4 -3
  220. package/dist/modules/actions/types.d.ts +86 -3
  221. package/dist/modules/connectors/engine.js +3 -5
  222. package/dist/modules/functions/build.d.ts +22 -0
  223. package/dist/modules/functions/build.js +122 -0
  224. package/dist/modules/functions/build.test.d.ts +1 -0
  225. package/dist/modules/functions/capabilities.d.ts +22 -0
  226. package/dist/modules/functions/capabilities.js +228 -0
  227. package/dist/modules/functions/config.d.ts +34 -0
  228. package/dist/modules/functions/config.js +24 -0
  229. package/dist/modules/functions/context.d.ts +17 -0
  230. package/dist/modules/functions/context.js +88 -0
  231. package/dist/modules/functions/contract.d.ts +121 -0
  232. package/dist/modules/functions/contract.js +9 -0
  233. package/dist/modules/functions/driver.d.ts +36 -0
  234. package/dist/modules/functions/driver.js +150 -0
  235. package/dist/modules/functions/load.d.ts +15 -0
  236. package/dist/modules/functions/load.js +45 -0
  237. package/dist/modules/functions/load.test.d.ts +1 -0
  238. package/dist/modules/functions/local.d.ts +29 -0
  239. package/dist/modules/functions/local.js +61 -0
  240. package/dist/modules/functions/local.test.d.ts +1 -0
  241. package/dist/modules/functions/manifest.d.ts +24 -0
  242. package/dist/modules/functions/manifest.js +163 -0
  243. package/dist/modules/functions/manifest.test.d.ts +1 -0
  244. package/dist/modules/functions/native.d.ts +8 -0
  245. package/dist/modules/functions/native.js +21 -0
  246. package/dist/modules/functions/native.test.d.ts +1 -0
  247. package/dist/modules/functions/protocol.d.ts +216 -0
  248. package/dist/modules/functions/protocol.js +18 -0
  249. package/dist/modules/functions/routes.d.ts +36 -0
  250. package/dist/modules/functions/routes.js +181 -0
  251. package/dist/modules/functions/routes.test.d.ts +1 -0
  252. package/dist/modules/functions/runner/messages.d.ts +5 -0
  253. package/dist/modules/functions/runner/messages.js +188 -0
  254. package/dist/modules/functions/runner/remote.d.ts +19 -0
  255. package/dist/modules/functions/runner/remote.js +116 -0
  256. package/dist/modules/functions/runner/remote.test.d.ts +1 -0
  257. package/dist/modules/functions/runner/service.d.ts +32 -0
  258. package/dist/modules/functions/runner/service.js +209 -0
  259. package/dist/modules/functions/sandbox/guest.d.ts +45 -0
  260. package/dist/modules/functions/sandbox/guest.js +660 -0
  261. package/dist/modules/functions/sandbox/isolate.d.ts +37 -0
  262. package/dist/modules/functions/sandbox/isolate.js +347 -0
  263. package/dist/modules/functions/sandbox/isolate.test.d.ts +1 -0
  264. package/dist/modules/functions/sandbox/prelude.d.ts +2 -0
  265. package/dist/modules/functions/sandbox/prelude.js +49 -0
  266. package/dist/modules/functions/space.d.ts +40 -0
  267. package/dist/modules/functions/space.js +162 -0
  268. package/dist/modules/functions/testing/tasksOf.d.ts +4 -0
  269. package/dist/modules/functions/tryEntry.d.ts +9 -0
  270. package/dist/modules/functions/tryEntry.js +49 -0
  271. package/dist/modules/mongo/kv.js +31 -0
  272. package/dist/modules/mysql/accounts.js +19 -9
  273. package/dist/modules/mysql/index.d.ts +2 -1
  274. package/dist/modules/mysql/jobs/index.d.ts +1 -1
  275. package/dist/modules/mysql/jobs/kv.js +30 -0
  276. package/dist/modules/mysql/jobs/schema.d.ts +9 -0
  277. package/dist/modules/mysql/jobs/schema.js +21 -4
  278. package/dist/modules/mysql/schema.js +25 -0
  279. package/dist/modules/mysql/sessions.d.ts +1 -11
  280. package/dist/modules/mysql/sessions.js +6 -1
  281. package/dist/modules/realtime/declarations.d.ts +11 -0
  282. package/dist/modules/realtime/declarations.js +26 -0
  283. package/dist/modules/realtime/grants.d.ts +23 -0
  284. package/dist/modules/realtime/grants.js +61 -0
  285. package/dist/modules/realtime/handlers.d.ts +74 -0
  286. package/dist/modules/realtime/handlers.js +224 -0
  287. package/dist/modules/realtime/hub.d.ts +62 -0
  288. package/dist/modules/realtime/hub.js +141 -0
  289. package/dist/modules/realtime/index.d.ts +51 -0
  290. package/dist/modules/realtime/index.js +62 -0
  291. package/dist/modules/realtime/memoryPubSub.d.ts +10 -0
  292. package/dist/modules/realtime/memoryPubSub.js +43 -0
  293. package/dist/modules/realtime/realtime.test.d.ts +1 -0
  294. package/dist/modules/realtime/redisPubSub.d.ts +24 -0
  295. package/dist/modules/realtime/redisPubSub.js +36 -0
  296. package/dist/modules/realtime/redisPubSub.test.d.ts +1 -0
  297. package/dist/modules/realtime/socket.d.ts +25 -0
  298. package/dist/modules/realtime/socket.js +122 -0
  299. package/dist/modules/realtime/socket.test.d.ts +1 -0
  300. package/dist/modules/rsc/handler.d.ts +16 -0
  301. package/dist/modules/rsc/handler.js +17 -10
  302. package/dist/modules/rsc/handler.test.d.ts +1 -0
  303. package/dist/modules/rsc/resolveRscData.js +2 -1
  304. package/dist/modules/runtime/bundle.d.ts +24 -0
  305. package/dist/modules/runtime/bundle.js +102 -0
  306. package/dist/modules/runtime/contract.d.ts +37 -0
  307. package/dist/modules/runtime/contract.js +21 -0
  308. package/dist/modules/runtime/entry.test.d.ts +1 -0
  309. package/dist/modules/runtime/host.d.ts +38 -0
  310. package/dist/modules/runtime/host.js +68 -0
  311. package/dist/modules/runtime/inside.d.ts +15 -0
  312. package/dist/modules/runtime/inside.js +47 -0
  313. package/dist/modules/runtime/inside.test.d.ts +1 -0
  314. package/dist/modules/runtime/runner.d.ts +11 -0
  315. package/dist/modules/runtime/runner.js +38 -0
  316. package/dist/modules/runtime/runtime.test.d.ts +1 -0
  317. package/dist/modules/runtime/stages.d.ts +50 -0
  318. package/dist/modules/runtime/stages.js +117 -0
  319. package/dist/modules/ssr/Component.d.ts +3 -1
  320. package/dist/modules/ssr/Component.js +2 -1
  321. package/dist/modules/ssr/handler.js +10 -2
  322. package/dist/modules/ssr/loadPluginComponents.js +2 -1
  323. package/dist/modules/ssr/prepareRender.js +39 -10
  324. package/dist/modules/ssr/preview.d.ts +3 -0
  325. package/dist/modules/ssr/preview.js +17 -7
  326. package/dist/modules/ssr/redirect.test.d.ts +1 -0
  327. package/dist/modules/ssr/registerExternalPlugins.d.ts +6 -1
  328. package/dist/modules/ssr/registerExternalPlugins.js +19 -16
  329. package/dist/modules/ssr/registerExternalPlugins.test.d.ts +1 -0
  330. package/dist/modules/ssr/reportMissingPlugins.d.ts +9 -0
  331. package/dist/modules/ssr/reportMissingPlugins.js +24 -0
  332. package/dist/modules/ssr/reportMissingPlugins.test.d.ts +1 -0
  333. package/dist/modules/ssr/streamBody.d.ts +2 -2
  334. package/dist/modules/ssr/streamBody.js +4 -1
  335. package/dist/modules/ssr/template.js +1 -1
  336. package/dist/modules/ssr/views/template.ejs +8 -5
  337. package/dist/mysql.d.ts +1 -1
  338. package/dist/mysql.js +2 -2
  339. package/dist/oauth.js +2 -2
  340. package/dist/plugins/compile.js +9 -4
  341. package/dist/plugins/copy.js +3 -3
  342. package/dist/plugins/manager.d.ts +35 -3
  343. package/dist/plugins/manager.js +109 -38
  344. package/dist/runtime.d.ts +15 -0
  345. package/dist/runtime.js +7 -0
  346. package/package.json +39 -8
  347. package/skills/plitzi-authoring/SKILL.md +98 -14
  348. package/skills/plitzi-authoring/reference/accessibility.md +111 -0
  349. package/skills/plitzi-authoring/reference/authoring-errors.md +70 -0
  350. package/skills/plitzi-authoring/reference/data-and-visibility.md +84 -18
  351. package/skills/plitzi-authoring/reference/elements-and-styles.md +61 -7
  352. package/skills/plitzi-authoring/reference/flows.md +108 -17
  353. package/skills/plitzi-authoring/reference/lists.md +74 -0
  354. package/skills/plitzi-authoring/reference/performance.md +67 -0
  355. package/skills/plitzi-authoring/reference/plugins.md +167 -0
  356. package/skills/plitzi-authoring/reference/review-checklist.md +19 -2
  357. package/skills/plitzi-authoring/reference/templates.md +67 -27
  358. package/skills/plitzi-authoring/reference/testing.md +72 -5
  359. package/skills/plitzi-authoring/reference/validation.md +73 -0
@@ -0,0 +1,281 @@
1
+ /**
2
+ * The `kv` tasks' own view: values rather than strings, and a TTL that means what a caller expects.
3
+ *
4
+ * Built by `createKvStore` over an {@link ActionKvAdapter}, and then narrowed to one space by `namespaceKv`. A
5
+ * task never sees an adapter.
6
+ */
7
+ declare type ActionKvStore = {
8
+ get: (key: string) => Promise<unknown>;
9
+ set: (key: string, value: unknown, ttlSeconds?: number) => Promise<void>;
10
+ delete: (key: string) => Promise<void>;
11
+ increment: (key: string, amount: number, ttlSeconds?: number) => Promise<number>;
12
+ /**
13
+ * Writes `next` only if the key still holds `expected` — the value `get` answered — or, with `expected` undefined,
14
+ * only if it holds nothing. Answers whether it wrote: read, change, and write back with this, and a writer that
15
+ * lost the race is told so instead of undoing the other.
16
+ */
17
+ swap: (key: string, expected: unknown, next: unknown, ttlSeconds?: number) => Promise<boolean>;
18
+ /**
19
+ * Puts `entry` in the list — replacing the one with its id — keeping the highest `keep` by score, and answers what
20
+ * that dropped, for whatever it named to be let go of too. A list has no lifetime: it lives until its entries are
21
+ * removed.
22
+ */
23
+ listPut: (list: string, entry: KvListEntry, options?: KvListPutOptions) => Promise<KvListPut>;
24
+ listRange: (list: string, range?: KvListRange) => Promise<KvListEntry[]>;
25
+ /** Takes the entry with `id` out of the list, and answers whether it was there. */
26
+ listRemove: (list: string, id: string) => Promise<boolean>;
27
+ /**
28
+ * Reads the key, hands its value to `change` and writes back what that answers — reading and asking again when
29
+ * somebody wrote in between, so no writer undoes another. `change` answering `undefined` writes nothing. Answers what
30
+ * was written. `lifetime` is seconds, or worked out from the value written.
31
+ */
32
+ change: <T>(key: string, change: (current: unknown) => T | undefined | Promise<T | undefined>, lifetime?: KvChangeLifetime<T>) => Promise<T | undefined>;
33
+ };
34
+
35
+ /**
36
+ * A step refusing to go on, with a reason written for whoever called — a password too easy to guess, a board that is
37
+ * read-only, a quota reached.
38
+ *
39
+ * What any other step throws stays in the run's record and never reaches the caller: an error can carry a query, a
40
+ * URL, a credential's name, and a page is shown to anybody. This one says, by its type, that its message was written
41
+ * to be read. A run that ends on it answers `status: 'failed'` with the message as `error`, which a page's flow reads
42
+ * as `{{ step.error }}` — the same place a refusal before the run began puts its own.
43
+ */
44
+ export declare class ActionRefusal extends Error {
45
+ constructor(message: string);
46
+ }
47
+
48
+ /**
49
+ * Declares a space's functions. An identity at run time: it is here for the types, and so the same file is valid
50
+ * wherever it is loaded — natively in a self-hosted server, or built by the platform and run in its sandbox.
51
+ */
52
+ export declare const defineFunctions: (definition: FunctionsDefinition) => FunctionsDefinition;
53
+
54
+ declare type Environment = 'production' | 'staging' | 'development' | 'main';
55
+
56
+ /**
57
+ * Everything a space's code can do besides computing — one object, the same wherever it runs. In a self-hosted server
58
+ * it is built from the run's own context; in the sandbox each method is a call back to the platform, which scopes it
59
+ * to the space and the run before doing it.
60
+ */
61
+ export declare type FunctionContext = {
62
+ spaceId: number;
63
+ environment: Environment;
64
+ runId: string;
65
+ /** How the run was started: `call`, `render`, `schedule`, `webhook`… */
66
+ trigger: string;
67
+ /** `user:<id>` for a session, `ip:<address>` for everyone else — what a limit per person keys on. */
68
+ callerId: string;
69
+ user?: FunctionUser;
70
+ /**
71
+ * The space's own key/value store: `get`, `set`, `swap`, `increment`, lists — and `change`, to read, change and write
72
+ * a value back without undoing a writer that got there first.
73
+ */
74
+ kv: ActionKvStore;
75
+ /**
76
+ * Counts one more of `bucket` — per caller unless `per: 'everyone'` — and says whether it was within `most` in every
77
+ * `perSeconds`. The same count as a flow's `flow.rateLimit` step on that bucket. What to answer when it is not is the
78
+ * code's.
79
+ */
80
+ rateLimit: (bucket: string, limit: RateLimit) => Promise<RateCount>;
81
+ /**
82
+ * Signs `value` with a key of the space's own that the platform keeps and the code never sees: HMAC-SHA-256,
83
+ * base64url. What a link, an invitation or a key handed to a page is made of. Refused on a server with no signing
84
+ * secret.
85
+ */
86
+ sign: (value: string) => Promise<string>;
87
+ /** Whether `signature` is what `sign` answered for `value`, compared in constant time. */
88
+ verify: (value: string, signature: string) => Promise<boolean>;
89
+ /** To the hosts the space declared (`allow.hosts`) — and, with `credential`, with one of its secrets written in. */
90
+ fetch: FunctionFetch;
91
+ /** Says something on one of the space's realtime channels, as the server. */
92
+ publish: (topic: string, type: string, data: unknown) => Promise<void>;
93
+ /** Lets the visitor into one topic of a private (`grant: true`) channel. */
94
+ grant: (topic: string, ttlSeconds?: number) => Promise<string>;
95
+ /** Takes a grant back — or every grant for the topic, naming none. */
96
+ revoke: (topic: string, grant?: string) => Promise<void>;
97
+ /** A line for whoever reads the run: the builder's Try, and the deployment's logs. */
98
+ log: (...values: unknown[]) => void;
99
+ /** Progress for a caller that asked for a stream — a no-op when nobody did. */
100
+ emit: (chunk: unknown) => void;
101
+ /** Aborted when the run is: cancelled, or out of time. Hand it to what can stop early. */
102
+ signal: AbortSignal;
103
+ };
104
+
105
+ /** What a function's `fetch` answers: a web `Response`, whichever runner it is in. */
106
+ export declare type FunctionFetch = (url: string | URL, init?: FunctionFetchInit) => Promise<Response>;
107
+
108
+ /**
109
+ * A request a function makes: `fetch`'s own init, and `credential` — the id of one of the space's credentials, whose
110
+ * values the platform writes into the request where it says `{{credential.<key>}}` (in the URL, a header or the
111
+ * body). The code never holds the value; it names it.
112
+ */
113
+ export declare type FunctionFetchInit = {
114
+ method?: string;
115
+ headers?: Record<string, string>;
116
+ body?: string;
117
+ credential?: string;
118
+ };
119
+
120
+ /**
121
+ * An HTTP endpoint of the space, under `/api/`: a web-standard handler, the shape every edge runtime runs. The request
122
+ * carries no credentials — `ctx.user` says who is asking — and the response sets no cookies: the host's are the
123
+ * platform's.
124
+ */
125
+ export declare type FunctionRoute = (request: Request, ctx: FunctionRouteContext) => Response | Promise<Response>;
126
+
127
+ /** What a route's handler gets besides the request: the context, and the `:params` its key named, by name. */
128
+ export declare type FunctionRouteContext = FunctionContext & {
129
+ params: Record<string, string>;
130
+ };
131
+
132
+ /** What a space's `functions/index.ts` exports: its tasks, its routes, and where its code may reach. */
133
+ export declare type FunctionsDefinition = {
134
+ /** The hosts `ctx.fetch` may reach. Anything else is refused before it leaves. */
135
+ allow?: {
136
+ hosts?: string[];
137
+ };
138
+ tasks?: FunctionTask<never>[];
139
+ /** `'GET /board-assets/:board/:asset'` → a handler, served at `/api/board-assets/…`. */
140
+ routes?: Record<string, FunctionRoute>;
141
+ };
142
+
143
+ /**
144
+ * One step a server action can take, written by the space. The shape of the platform's own tasks — addressed as
145
+ * `<namespace>.<action>`, drawn in the builder from `params` — run with a {@link FunctionContext} rather than the
146
+ * platform's full one.
147
+ */
148
+ export declare type FunctionTask<T extends Record<string, unknown> = Record<string, unknown>> = {
149
+ namespace: string;
150
+ action: string;
151
+ title: string;
152
+ description?: string;
153
+ params: Record<keyof T, InteractionCallbackParam<T>>;
154
+ run: (params: T, ctx: FunctionContext) => unknown;
155
+ };
156
+
157
+ /**
158
+ * Who started the run, as a space's own code may know them: everything a function decides by — who, their roles and
159
+ * permissions — and never their session. A token inside the sandbox is a token a function could send anywhere.
160
+ */
161
+ export declare type FunctionUser = {
162
+ id: number;
163
+ username: string;
164
+ email: string;
165
+ verified: boolean;
166
+ permissions: string[];
167
+ roles: string[];
168
+ };
169
+
170
+ declare type InteractionCallbackParam<T extends Record<string, unknown> = Record<string, unknown>> = {
171
+ canBind?: boolean;
172
+ label?: string;
173
+ when?: boolean | ((params: InteractionCallbackParamValues<T>) => boolean);
174
+ /**
175
+ * This param names one of the space's credentials, of this provider. Serializable on purpose: an editor offers the
176
+ * space's credentials of that kind to pick from, rather than a text box somebody has to type an identifier into.
177
+ */
178
+ credentialProvider?: SpaceCredentialProvider;
179
+ } & ({
180
+ type: 'text';
181
+ defaultValue?: string | number;
182
+ } | {
183
+ type: 'textarea';
184
+ defaultValue?: string | number;
185
+ } | {
186
+ type: 'codemirror-text';
187
+ defaultValue?: string;
188
+ } | {
189
+ type: 'codemirror-json';
190
+ defaultValue?: string;
191
+ } | {
192
+ type: 'boolean';
193
+ defaultValue?: boolean;
194
+ } | {
195
+ /**
196
+ * Several elements of the space, stored as their ids. The editor offers the elements of `elementType` to pick
197
+ * from — it is the one that knows the page — so a step never asks for ids typed by hand.
198
+ */
199
+ type: 'elements';
200
+ defaultValue?: string[];
201
+ elementType?: string;
202
+ } | {
203
+ type: 'select';
204
+ defaultValue?: string;
205
+ options: {
206
+ label: string;
207
+ value: string;
208
+ }[] | ((params: InteractionCallbackParamValues<T>) => {
209
+ label: string;
210
+ value: string;
211
+ }[]);
212
+ } | {
213
+ type: (params: InteractionCallbackParamValues<T>) => InteractionParamType;
214
+ defaultValue?: string | number | boolean | string[];
215
+ options?: {
216
+ label: string;
217
+ value: string;
218
+ }[] | ((params: InteractionCallbackParamValues<T>) => {
219
+ label: string;
220
+ value: string;
221
+ }[]);
222
+ });
223
+
224
+ declare type InteractionCallbackParamValues<T extends Record<string, unknown> = Record<string, unknown>> = T;
225
+
226
+ declare type InteractionParamType = 'boolean' | 'select' | 'text' | 'textarea' | 'codemirror-text' | 'codemirror-json' | 'elements';
227
+
228
+ /**
229
+ * The lifetime a change writes with: a number of seconds, one worked out from the value written, or none.
230
+ */
231
+ declare type KvChangeLifetime<T> = number | ((next: T) => number | undefined);
232
+
233
+ /** One entry of a list: what it is called, where it sorts, and what it carries. */
234
+ declare type KvListEntry = {
235
+ id: string;
236
+ score: number;
237
+ value: unknown;
238
+ };
239
+
240
+ /** What a put did: whether the entry went in, and what `keep` dropped to make room. */
241
+ declare type KvListPut = {
242
+ stored: boolean;
243
+ dropped: KvListEntry[];
244
+ };
245
+
246
+ declare type KvListPutOptions = {
247
+ /** How many to keep, the highest scores; what falls past it is dropped. {@link MAX_LIST_ENTRIES} at most. */
248
+ keep?: number;
249
+ /**
250
+ * Replace an entry already there only with a score at least as high — a player's best, or the latest of two writes
251
+ * that arrived out of order. Otherwise the one there stays and nothing is written.
252
+ */
253
+ higherOnly?: boolean;
254
+ };
255
+
256
+ declare type KvListRange = {
257
+ /** How many entries to skip first. 0 when absent. */
258
+ offset?: number;
259
+ /** How many to answer. All of them when absent. */
260
+ limit?: number;
261
+ /** `desc` — the highest score first — when absent. */
262
+ order?: 'asc' | 'desc';
263
+ };
264
+
265
+ /** Where a limit stands after counting one more: whether that one was within it, and how many are left. */
266
+ declare type RateCount = {
267
+ allowed: boolean;
268
+ count: number;
269
+ remaining: number;
270
+ };
271
+
272
+ /** How much of something is allowed: `most` in every `perSeconds`, for each caller or for everyone together. */
273
+ declare type RateLimit = {
274
+ most: number;
275
+ perSeconds: number;
276
+ per?: 'caller' | 'everyone';
277
+ };
278
+
279
+ declare type SpaceCredentialProvider = 's3' | 'r2' | 'ssr' | 'custom' | 'smtp';
280
+
281
+ export { }
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Functions: a server's own code, and the contract a space's code is written against — the same file whether a
3
+ * self-hosted server loads it natively or the platform runs it in its sandbox. Its own entry so a space's code imports
4
+ * the contract alone, and nothing that runs it.
5
+ */
6
+ export { ActionRefusal, defineFunctions } from './modules/functions/contract';
7
+ export type { FunctionContext, FunctionFetch, FunctionFetchInit, FunctionRoute, FunctionRouteContext, FunctionsDefinition, FunctionTask, FunctionUser } from './modules/functions/contract';
8
+ export type { FunctionsConfig, FunctionUsageRecord } from './modules/functions/config';
9
+ export { DEFAULT_FUNCTION_LIMITS } from './modules/functions/config';
10
+ /**
11
+ * What the platform keeps of a space's functions, and what it hands a runner: the built bundle and what it declared
12
+ * when it was saved (`prepareFunctions` on the actions module is the one way to make one).
13
+ */
14
+ export type { FunctionsSource } from './modules/functions/build';
15
+ export type { FunctionsManifest, FunctionTaskManifest, FunctionsProblem } from '@plitzi/sdk-shared';
16
+ export type { FunctionInvocation, FunctionInvokeRequest, FunctionLimits, FunctionRunner, FunctionsBundle, FunctionStopReason, FunctionUsage, SpaceFunctions } from './modules/functions/protocol';
17
+ export type { PreparedFunctions } from './modules/functions/space';
18
+ export type { ManifestReading } from './modules/functions/manifest';
19
+ export { functionTryEntry, TRY_STEP } from './modules/functions/tryEntry';
@@ -0,0 +1,5 @@
1
+ import { ActionRefusal } from "./modules/actions/runtime/errors.js";
2
+ import { DEFAULT_FUNCTION_LIMITS } from "./modules/functions/config.js";
3
+ import { defineFunctions } from "./modules/functions/contract.js";
4
+ import { TRY_STEP, functionTryEntry } from "./modules/functions/tryEntry.js";
5
+ export { ActionRefusal, DEFAULT_FUNCTION_LIMITS, TRY_STEP, defineFunctions, functionTryEntry };
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Running the spaces' functions: the runner service (its own process, holding nothing), the platform's client to it,
3
+ * and the isolates both are made of. Its own entry, apart from the contract, so a space's code and a self-hosted
4
+ * server's native functions never load a line of it — nor need `isolated-vm` or `core-js`, which only the process
5
+ * that runs isolates installs.
6
+ */
7
+ export { startFunctionsRunnerService } from './modules/functions/runner/service';
8
+ export type { FunctionsRunnerService, FunctionsRunnerServiceOptions } from './modules/functions/runner/service';
9
+ export { createRemoteRunner } from './modules/functions/runner/remote';
10
+ export type { RemoteRunnerOptions } from './modules/functions/runner/remote';
11
+ export { createIsolateRunner } from './modules/functions/sandbox/isolate';
12
+ export type { IsolateRunnerOptions } from './modules/functions/sandbox/isolate';
13
+ export { FUNCTIONS_PROTOCOL, FunctionFailure } from './modules/functions/protocol';
14
+ export { createLocalFunctions } from './modules/functions/local';
15
+ export type { LocalFunctions, LocalFunctionsOptions } from './modules/functions/local';
@@ -0,0 +1,6 @@
1
+ import { FUNCTIONS_PROTOCOL, FunctionFailure } from "./modules/functions/protocol.js";
2
+ import { createIsolateRunner } from "./modules/functions/sandbox/isolate.js";
3
+ import { startFunctionsRunnerService } from "./modules/functions/runner/service.js";
4
+ import { createRemoteRunner } from "./modules/functions/runner/remote.js";
5
+ import { createLocalFunctions } from "./modules/functions/local.js";
6
+ export { FUNCTIONS_PROTOCOL, FunctionFailure, createIsolateRunner, createLocalFunctions, createRemoteRunner, startFunctionsRunnerService };
@@ -55,10 +55,10 @@ export { createAuthRouteHandlers, mountAuthRoutes } from './core/handlers/authRo
55
55
  export { createSocialAuthRouteHandlers, mountSocialAuthRoutes } from './core/handlers/socialRouteHandlers';
56
56
  export { createOAuthRouteHandlers, mountOAuthRoutes, OAUTH_ROUTE_PATHS } from './core/handlers/oauthRouteHandlers';
57
57
  export { createAuthMiddleware } from './core/handlers/authMiddleware';
58
- export { createCsrfMiddleware } from './core/handlers/csrfMiddleware';
58
+ export { createCsrfMiddleware, createOriginGuardMiddleware } from './core/handlers/csrfMiddleware';
59
59
  export type { AuthRouteHandlersOptions } from './core/handlers/authRouteHandlers';
60
60
  export type { SocialRouteHandlersOptions } from './core/handlers/socialRouteHandlers';
61
61
  export type { OAuthResponse, OAuthRouteHandler, OAuthRouteHandlersOptions } from './core/handlers/oauthRouteHandlers';
62
62
  export type { AuthMiddlewareOptions } from './core/handlers/authMiddleware';
63
- export type { CsrfMiddlewareOptions } from './core/handlers/csrfMiddleware';
63
+ export type { CsrfMiddlewareOptions, OriginGuardOptions } from './core/handlers/csrfMiddleware';
64
64
  export type { AuthedRequest, HttpRoute, JsonResponse, RedirectResponse, RouteHandler, RouterLike, SocialRouteHandler } from './core/handlers/types';
package/dist/handlers.js CHANGED
@@ -2,5 +2,5 @@ import { createAuthRouteHandlers, mountAuthRoutes } from "./core/handlers/authRo
2
2
  import { createSocialAuthRouteHandlers, mountSocialAuthRoutes } from "./core/handlers/socialRouteHandlers.js";
3
3
  import { OAUTH_ROUTE_PATHS, createOAuthRouteHandlers, mountOAuthRoutes } from "./core/handlers/oauthRouteHandlers.js";
4
4
  import { createAuthMiddleware } from "./core/handlers/authMiddleware.js";
5
- import { createCsrfMiddleware } from "./core/handlers/csrfMiddleware.js";
6
- export { OAUTH_ROUTE_PATHS, createAuthMiddleware, createAuthRouteHandlers, createCsrfMiddleware, createOAuthRouteHandlers, createSocialAuthRouteHandlers, mountAuthRoutes, mountOAuthRoutes, mountSocialAuthRoutes };
5
+ import { createCsrfMiddleware, createOriginGuardMiddleware } from "./core/handlers/csrfMiddleware.js";
6
+ export { OAUTH_ROUTE_PATHS, createAuthMiddleware, createAuthRouteHandlers, createCsrfMiddleware, createOAuthRouteHandlers, createOriginGuardMiddleware, createSocialAuthRouteHandlers, mountAuthRoutes, mountOAuthRoutes, mountSocialAuthRoutes };
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Writes a file whole or not at all: to a temporary name beside it, then renamed over it.
3
+ *
4
+ * Several workers can build or download the same plugin into the same folder at once, and a reader can open a file
5
+ * while another process is writing it. A rename replaces the file in one step, so whoever reads it sees the old
6
+ * version or the new one — never half of either. Same-folder temporary, so the rename never crosses a filesystem.
7
+ */
8
+ export declare const writeFileAtomic: (file: string, data: string | Uint8Array) => Promise<void>;
9
+ /** `copyFile`, with the same whole-or-nothing guarantee. */
10
+ export declare const copyFileAtomic: (source: string, file: string) => Promise<void>;
@@ -0,0 +1,33 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import fs from "node:fs/promises";
3
+ //#region src/helpers/atomicFile.ts
4
+ /**
5
+ * Writes a file whole or not at all: to a temporary name beside it, then renamed over it.
6
+ *
7
+ * Several workers can build or download the same plugin into the same folder at once, and a reader can open a file
8
+ * while another process is writing it. A rename replaces the file in one step, so whoever reads it sees the old
9
+ * version or the new one — never half of either. Same-folder temporary, so the rename never crosses a filesystem.
10
+ */
11
+ var writeFileAtomic = async (file, data) => {
12
+ const temporary = `${file}.${process.pid}.${randomUUID()}.tmp`;
13
+ try {
14
+ await fs.writeFile(temporary, data);
15
+ await fs.rename(temporary, file);
16
+ } catch (error) {
17
+ await fs.rm(temporary, { force: true });
18
+ throw error;
19
+ }
20
+ };
21
+ /** `copyFile`, with the same whole-or-nothing guarantee. */
22
+ var copyFileAtomic = async (source, file) => {
23
+ const temporary = `${file}.${process.pid}.${randomUUID()}.tmp`;
24
+ try {
25
+ await fs.copyFile(source, temporary);
26
+ await fs.rename(temporary, file);
27
+ } catch (error) {
28
+ await fs.rm(temporary, { force: true });
29
+ throw error;
30
+ }
31
+ };
32
+ //#endregion
33
+ export { copyFileAtomic, writeFileAtomic };
@@ -0,0 +1 @@
1
+ export {};
@@ -1,5 +1,18 @@
1
1
  import { DEFAULT_COMPRESSION, compressBody, selectEncoding } from "./compress.js";
2
2
  //#region src/helpers/buildResponseHelpers.ts
3
+ /**
4
+ * `compressBody`, remembered in `store` when the caller keeps one: the same body in the same encoding is compressed
5
+ * once. What comes back uncompressed (identity, or a body under the threshold) is never stored — there is nothing to
6
+ * reuse, and a stored copy would only be the body again.
7
+ */
8
+ var compressOnce = (body, encoding, compression, store) => {
9
+ if (!store || encoding === "identity") return compressBody(body, encoding, compression);
10
+ const kept = store[encoding];
11
+ if (kept) return kept;
12
+ const compressed = compressBody(body, encoding, compression, true);
13
+ if (typeof compressed !== "string") store[encoding] = compressed;
14
+ return compressed;
15
+ };
3
16
  var buildResponseHelpers = (raw, acceptEncoding, compression = DEFAULT_COMPRESSION) => {
4
17
  let statusCode = 200;
5
18
  const encoding = selectEncoding(acceptEncoding, compression);
@@ -12,7 +25,24 @@ var buildResponseHelpers = (raw, acceptEncoding, compression = DEFAULT_COMPRESSI
12
25
  * already said so in a header.
13
26
  */
14
27
  const transformable = () => !String(raw.getHeaders()["cache-control"]).includes("no-transform");
15
- const writeSend = (body) => {
28
+ /** A stored form this request can take as it is, without the body it was made from. */
29
+ const storedFor = (store) => encoding === "identity" || !transformable() ? void 0 : store?.[encoding];
30
+ const writeBody = (payload, encoded) => {
31
+ if (encoded) {
32
+ raw.setHeader("Content-Encoding", encoding);
33
+ raw.setHeader("Vary", "Accept-Encoding");
34
+ }
35
+ raw.setHeader("Content-Length", Buffer.byteLength(payload).toString());
36
+ if (!raw.headersSent) raw.writeHead(statusCode);
37
+ raw.end(payload);
38
+ };
39
+ const writeSend = (content, store) => {
40
+ const stored = typeof content === "function" ? storedFor(store) : void 0;
41
+ if (stored) {
42
+ writeBody(stored, true);
43
+ return;
44
+ }
45
+ const body = typeof content === "function" ? content() : content;
16
46
  /**
17
47
  * A Buffer goes out untouched.
18
48
  *
@@ -21,14 +51,8 @@ var buildResponseHelpers = (raw, acceptEncoding, compression = DEFAULT_COMPRESSI
21
51
  * corrupts any font, image or archive served through it. What a Buffer holds is also compressed already
22
52
  * (woff2, png), so re-encoding it would cost CPU to make it bigger.
23
53
  */
24
- const compressed = typeof body === "string" && transformable() ? compressBody(body, encoding, compression) : body;
25
- if (compressed !== body) {
26
- raw.setHeader("Content-Encoding", encoding);
27
- raw.setHeader("Vary", "Accept-Encoding");
28
- }
29
- raw.setHeader("Content-Length", Buffer.byteLength(compressed).toString());
30
- if (!raw.headersSent) raw.writeHead(statusCode);
31
- raw.end(compressed);
54
+ const compressed = typeof body === "string" && transformable() ? compressOnce(body, encoding, compression, store) : body;
55
+ writeBody(compressed, compressed !== body);
32
56
  };
33
57
  return {
34
58
  get status() {
@@ -43,8 +67,8 @@ var buildResponseHelpers = (raw, acceptEncoding, compression = DEFAULT_COMPRESSI
43
67
  setStatus(code) {
44
68
  statusCode = code;
45
69
  },
46
- send(body) {
47
- writeSend(body);
70
+ send(body, options) {
71
+ writeSend(body, options?.compressed);
48
72
  },
49
73
  write(chunk) {
50
74
  if (!raw.headersSent) raw.writeHead(statusCode);
@@ -1,3 +1,4 @@
1
+ import { requestOrigin } from "../core/requestParser.js";
1
2
  //#region src/helpers/buildServerInfo.ts
2
3
  var getEnvironment = (env = "production", server) => {
3
4
  switch (env) {
@@ -36,7 +37,8 @@ var getEnvironment = (env = "production", server) => {
36
37
  */
37
38
  var buildServerInfo = (req, config, ssr) => {
38
39
  const accessToken = req.query["access-token"];
39
- const origin = `${req.protocol}://${req.hostname}`;
40
+ const origin = requestOrigin(req) || `${req.protocol}://${req.hostname}`;
41
+ const host = origin.slice(`${req.protocol}://`.length);
40
42
  const user = req.ctx.user;
41
43
  return getEnvironment(config.environment, {
42
44
  basePath: "/",
@@ -52,7 +54,7 @@ var buildServerInfo = (req, config, ssr) => {
52
54
  location: {
53
55
  origin,
54
56
  protocol: `${req.protocol}:`,
55
- host: req.hostname,
57
+ host,
56
58
  hostname: req.hostname,
57
59
  pathname: req.path || "/",
58
60
  search: req.search
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,18 @@
1
+ import { CompressedBodies } from '@plitzi/sdk-shared';
2
+ /**
3
+ * The compressed forms of static files, one entry per file, within a byte budget.
4
+ *
5
+ * A file is compressed once per version and encoding instead of on every request — the SDK bundle alone is megabytes
6
+ * of JavaScript. Keyed by path with the version beside it, so a file that changed replaces its old forms rather than
7
+ * sitting next to them. Past the budget the least recently served files go first.
8
+ */
9
+ export declare class CompressedFileCache {
10
+ private readonly maxBytes;
11
+ private readonly entries;
12
+ constructor(maxBytes: number);
13
+ /** Where the compressed forms of this version of the file are kept; `send` fills it as encodings are asked for. */
14
+ storeFor(filePath: string, version: string): CompressedBodies;
15
+ /** Drops the least recently served files until the rest fit the budget. Called after a send may have grown one. */
16
+ trim(): void;
17
+ get bytes(): number;
18
+ }
@@ -0,0 +1,44 @@
1
+ //#region src/helpers/cache/CompressedFileCache.ts
2
+ var sizeOf = (bodies) => (bodies.br?.length ?? 0) + (bodies.gzip?.length ?? 0);
3
+ /**
4
+ * The compressed forms of static files, one entry per file, within a byte budget.
5
+ *
6
+ * A file is compressed once per version and encoding instead of on every request — the SDK bundle alone is megabytes
7
+ * of JavaScript. Keyed by path with the version beside it, so a file that changed replaces its old forms rather than
8
+ * sitting next to them. Past the budget the least recently served files go first.
9
+ */
10
+ var CompressedFileCache = class {
11
+ maxBytes;
12
+ entries = /* @__PURE__ */ new Map();
13
+ constructor(maxBytes) {
14
+ this.maxBytes = maxBytes;
15
+ }
16
+ /** Where the compressed forms of this version of the file are kept; `send` fills it as encodings are asked for. */
17
+ storeFor(filePath, version) {
18
+ const existing = this.entries.get(filePath);
19
+ this.entries.delete(filePath);
20
+ const entry = existing?.version === version ? existing : {
21
+ version,
22
+ bodies: {}
23
+ };
24
+ this.entries.set(filePath, entry);
25
+ return entry.bodies;
26
+ }
27
+ /** Drops the least recently served files until the rest fit the budget. Called after a send may have grown one. */
28
+ trim() {
29
+ let total = 0;
30
+ for (const entry of this.entries.values()) total += sizeOf(entry.bodies);
31
+ for (const [filePath, entry] of this.entries) {
32
+ if (total <= this.maxBytes) return;
33
+ total -= sizeOf(entry.bodies);
34
+ this.entries.delete(filePath);
35
+ }
36
+ }
37
+ get bytes() {
38
+ let total = 0;
39
+ for (const entry of this.entries.values()) total += sizeOf(entry.bodies);
40
+ return total;
41
+ }
42
+ };
43
+ //#endregion
44
+ export { CompressedFileCache };
@@ -0,0 +1 @@
1
+ export {};
@@ -1,3 +1,3 @@
1
1
  import { TtlCache } from './TtlCache';
2
2
  import { CacheManager } from '@plitzi/sdk-shared';
3
- export declare const buildCacheManager: (store: TtlCache<string>) => CacheManager;
3
+ export declare const buildCacheManager: <T>(store: TtlCache<T>) => CacheManager;
@@ -1,3 +1,4 @@
1
+ import { readHtmlCacheKey } from "./keys.js";
1
2
  //#region src/helpers/cache/cacheManager.ts
2
3
  var buildCacheManager = (store) => ({
3
4
  invalidate(filter) {
@@ -7,7 +8,7 @@ var buildCacheManager = (store) => ({
7
8
  return count;
8
9
  }
9
10
  return store.invalidateWhere((key) => {
10
- const [keySpaceId, keyEnvironment, , keyHostname] = key.split("\0");
11
+ const { spaceId: keySpaceId, environment: keyEnvironment, hostname: keyHostname } = readHtmlCacheKey(key);
11
12
  if (filter.spaceId !== void 0 && keySpaceId !== String(filter.spaceId)) return false;
12
13
  if (filter.environment !== void 0 && keyEnvironment !== filter.environment) return false;
13
14
  if (filter.hostname !== void 0 && keyHostname !== filter.hostname) return false;
@@ -0,0 +1 @@
1
+ export {};
@@ -2,5 +2,5 @@ export { DEFAULT_TTL_MS } from './defaults';
2
2
  export { TtlCache } from './TtlCache';
3
3
  export { buildHtmlCacheKey, buildOfflineDataCacheKey, buildRscCacheKey } from './keys';
4
4
  export { buildCacheManager } from './cacheManager';
5
- export type { ServerCaches } from './serverCaches';
5
+ export type { CachedPage, ServerCaches } from './serverCaches';
6
6
  export { createServerCaches, destroyServerCaches } from './serverCaches';
@@ -10,7 +10,11 @@
10
10
  * one keyed — a space that switched dev tools on for its published site would otherwise hand the first visitor's
11
11
  * choice to the rest.
12
12
  *
13
- * Read from the request here rather than handed in, so a call site cannot key the page without it. Only those two
13
+ * So is the kept state the first paint depends on (`settings.paintedState`): `prepareRender` renders with that cookie's
14
+ * values, so a page drawn with one visitor's toolbar must not be served to the next. Keyed by its raw value — this
15
+ * key does not know which keys a space declares, and a space that declares none has no such cookie to split on.
16
+ *
17
+ * Read from the request here rather than handed in, so a call site cannot key the page without it. Only those
14
18
  * cookies are read: keying the whole header would split the cache on every analytics cookie a visitor carries.
15
19
  */
16
20
  export declare const buildHtmlCacheKey: (accessToken: string | undefined, spaceId: number | string | null, environment: string, revision: number, req: {
@@ -22,6 +26,16 @@ export declare const buildHtmlCacheKey: (accessToken: string | undefined, spaceI
22
26
  host?: string;
23
27
  };
24
28
  }) => string;
29
+ /**
30
+ * What an HTML key says about the page it holds, read by the one list that also writes it. `server.cache.invalidate`
31
+ * filters on these; it used to split the key by positions of its own, and when the key grew a field in front the
32
+ * filter went on reading the wrong ones — every invalidation by space matched nothing.
33
+ */
34
+ export declare const readHtmlCacheKey: (key: string) => {
35
+ spaceId: string;
36
+ environment: string;
37
+ hostname: string;
38
+ };
25
39
  export declare const buildOfflineDataCacheKey: (spaceId: number, environment: string, revision: number) => string;
26
40
  export declare const buildRscCacheKey: (spaceId: number, environment: string, revision: number, userId: string | number | undefined, idsParam: string | undefined, req: {
27
41
  hostname: string;