@plitzi/sdk-server 0.33.2 → 0.34.1

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 (274) hide show
  1. package/CHANGELOG.md +54 -0
  2. package/README.md +283 -8
  3. package/dist/actions.d.ts +62 -0
  4. package/dist/actions.js +12 -0
  5. package/dist/adapters/cloudAdapters.d.ts +72 -0
  6. package/dist/adapters/cloudAdapters.js +303 -0
  7. package/dist/adapters/space/index.d.ts +93 -0
  8. package/dist/adapters/space/index.js +122 -0
  9. package/dist/adapters/space/resolvers.d.ts +69 -0
  10. package/dist/adapters/space/resolvers.js +79 -0
  11. package/dist/adapters/space/space.test.d.ts +1 -0
  12. package/dist/adapters/space/types.d.ts +64 -0
  13. package/dist/adapters/space/types.js +41 -0
  14. package/dist/auth.d.ts +50 -0
  15. package/dist/auth.js +19 -0
  16. package/dist/core/auth/api.d.ts +400 -11
  17. package/dist/core/auth/api.js +1044 -50
  18. package/dist/core/auth/createAuth.d.ts +135 -30
  19. package/dist/core/auth/createAuth.js +96 -24
  20. package/dist/core/auth/credentials.d.ts +9 -3
  21. package/dist/core/auth/credentials.js +10 -4
  22. package/dist/core/auth/csrf.d.ts +89 -0
  23. package/dist/core/auth/csrf.js +234 -0
  24. package/dist/core/auth/csrf.test.d.ts +1 -0
  25. package/dist/core/auth/identity.d.ts +6 -0
  26. package/dist/core/auth/identity.js +37 -8
  27. package/dist/core/auth/lifecycle.test.d.ts +1 -0
  28. package/dist/core/auth/oauth/index.d.ts +8 -0
  29. package/dist/core/auth/oauth/index.js +13 -15
  30. package/dist/core/auth/passwords.d.ts +15 -0
  31. package/dist/core/auth/passwords.js +32 -0
  32. package/dist/core/auth/redirects.d.ts +18 -0
  33. package/dist/core/auth/redirects.js +31 -0
  34. package/dist/core/auth/redirects.test.d.ts +1 -0
  35. package/dist/core/auth/routes.d.ts +4 -2
  36. package/dist/core/auth/routes.js +234 -9
  37. package/dist/core/auth/session.d.ts +11 -0
  38. package/dist/core/auth/session.js +1 -1
  39. package/dist/core/auth/spaceTokens.d.ts +38 -2
  40. package/dist/core/auth/spaceTokens.js +54 -2
  41. package/dist/core/auth/throttle.d.ts +5 -0
  42. package/dist/core/auth/throttle.js +81 -0
  43. package/dist/core/auth/throttle.test.d.ts +1 -0
  44. package/dist/core/auth/tokens.d.ts +83 -12
  45. package/dist/core/auth/tokens.js +51 -9
  46. package/dist/core/auth/totp.d.ts +48 -0
  47. package/dist/core/auth/totp.js +118 -0
  48. package/dist/core/auth/totp.test.d.ts +1 -0
  49. package/dist/core/createServer.d.ts +0 -6
  50. package/dist/core/createServer.js +35 -3
  51. package/dist/core/fontStore.d.ts +33 -0
  52. package/dist/core/fontStore.js +53 -0
  53. package/dist/core/fontStore.test.d.ts +1 -0
  54. package/dist/core/handlers/authMiddleware.js +1 -1
  55. package/dist/core/handlers/authRouteHandlers.d.ts +9 -1
  56. package/dist/core/handlers/authRouteHandlers.js +4 -3
  57. package/dist/core/handlers/csrfMiddleware.d.ts +20 -0
  58. package/dist/core/handlers/csrfMiddleware.js +32 -0
  59. package/dist/core/handlers/oauthRouteHandlers.d.ts +46 -0
  60. package/dist/core/handlers/oauthRouteHandlers.js +159 -0
  61. package/dist/core/handlers/socialRouteHandlers.d.ts +40 -0
  62. package/dist/core/handlers/socialRouteHandlers.js +129 -0
  63. package/dist/core/handlers/socialRouteHandlers.test.d.ts +1 -0
  64. package/dist/core/handlers/types.d.ts +22 -5
  65. package/dist/core/health.d.ts +11 -1
  66. package/dist/core/health.js +27 -3
  67. package/dist/core/http/dispatcher.d.ts +1 -1
  68. package/dist/core/http/dispatcher.js +20 -1
  69. package/dist/core/http/stages/authApi.js +1 -1
  70. package/dist/core/http/stages/fontAssets.d.ts +9 -0
  71. package/dist/core/http/stages/fontAssets.js +27 -0
  72. package/dist/core/http/stages/oauth.d.ts +19 -0
  73. package/dist/core/http/stages/oauth.js +118 -0
  74. package/dist/core/http/types.d.ts +12 -0
  75. package/dist/core/oauth/authorize.d.ts +22 -0
  76. package/dist/core/oauth/authorize.js +254 -0
  77. package/dist/core/oauth/authorize.test.d.ts +1 -0
  78. package/dist/core/oauth/challenge.d.ts +11 -0
  79. package/dist/core/oauth/challenge.js +33 -0
  80. package/dist/core/oauth/consentPage.d.ts +12 -0
  81. package/dist/core/oauth/consentPage.js +131 -0
  82. package/dist/core/oauth/metadata.d.ts +41 -0
  83. package/dist/core/oauth/metadata.js +71 -0
  84. package/dist/core/oauth/params.d.ts +5 -0
  85. package/dist/core/oauth/params.js +5 -0
  86. package/dist/core/oauth/pkce.d.ts +6 -0
  87. package/dist/core/oauth/pkce.js +15 -0
  88. package/dist/core/oauth/records.d.ts +72 -0
  89. package/dist/core/oauth/records.js +49 -0
  90. package/dist/core/oauth/register.d.ts +5 -0
  91. package/dist/core/oauth/register.js +55 -0
  92. package/dist/core/oauth/respond.d.ts +21 -0
  93. package/dist/core/oauth/respond.js +59 -0
  94. package/dist/core/oauth/token.d.ts +14 -0
  95. package/dist/core/oauth/token.js +130 -0
  96. package/dist/core/previewToken.d.ts +20 -0
  97. package/dist/core/previewToken.js +29 -1
  98. package/dist/core/server/pageServer.js +4 -1
  99. package/dist/core/services/action.d.ts +6 -4
  100. package/dist/core/services/action.js +103 -10
  101. package/dist/core/services/registry.js +2 -0
  102. package/dist/core/services/resolve.d.ts +8 -0
  103. package/dist/core/services/resolve.js +12 -1
  104. package/dist/core/staticFiles.js +1 -2
  105. package/dist/handlers.d.ts +7 -1
  106. package/dist/handlers.js +4 -1
  107. package/dist/helpers/buildResponseHelpers.d.ts +8 -0
  108. package/dist/helpers/buildResponseHelpers.js +9 -1
  109. package/dist/helpers/buildServerInfo.d.ts +8 -3
  110. package/dist/helpers/buildServerInfo.js +18 -14
  111. package/dist/helpers/cache/keys.d.ts +13 -0
  112. package/dist/helpers/cache/keys.js +12 -1
  113. package/dist/helpers/onAbort.d.ts +12 -0
  114. package/dist/helpers/onAbort.js +22 -0
  115. package/dist/helpers/onAbort.test.d.ts +1 -0
  116. package/dist/helpers/outboundGuard.d.ts +27 -0
  117. package/dist/helpers/outboundGuard.js +49 -0
  118. package/dist/helpers/outboundGuard.test.d.ts +1 -0
  119. package/dist/helpers/serverLog.d.ts +6 -3
  120. package/dist/helpers/serverLog.js +20 -3
  121. package/dist/index.d.ts +6 -0
  122. package/dist/index.js +9 -4
  123. package/dist/kernel.d.ts +5 -22
  124. package/dist/kernel.js +1 -14
  125. package/dist/modules/actions/{handler.js → connectorWrite.js} +5 -2
  126. package/dist/modules/actions/connectorWrite.test.d.ts +1 -0
  127. package/dist/modules/actions/index.d.ts +40 -0
  128. package/dist/modules/actions/index.js +46 -0
  129. package/dist/modules/actions/moduleFor.d.ts +3 -0
  130. package/dist/modules/actions/moduleFor.js +35 -0
  131. package/dist/modules/actions/moduleFor.test.d.ts +1 -0
  132. package/dist/modules/actions/runtime/check.d.ts +24 -0
  133. package/dist/modules/actions/runtime/check.js +111 -0
  134. package/dist/modules/actions/runtime/check.test.d.ts +1 -0
  135. package/dist/modules/actions/runtime/errors.d.ts +11 -0
  136. package/dist/modules/actions/runtime/errors.js +17 -0
  137. package/dist/modules/actions/runtime/guards.d.ts +126 -0
  138. package/dist/modules/actions/runtime/guards.js +246 -0
  139. package/dist/modules/actions/runtime/guards.test.d.ts +1 -0
  140. package/dist/modules/actions/runtime/kvStore.d.ts +27 -0
  141. package/dist/modules/actions/runtime/kvStore.js +41 -0
  142. package/dist/modules/actions/runtime/kvStore.test.d.ts +1 -0
  143. package/dist/modules/actions/runtime/limits.d.ts +11 -0
  144. package/dist/modules/actions/runtime/limits.js +35 -0
  145. package/dist/modules/actions/runtime/memoryKv.d.ts +2 -0
  146. package/dist/modules/actions/runtime/memoryKv.js +77 -0
  147. package/dist/modules/actions/runtime/namespaceKv.d.ts +9 -0
  148. package/dist/modules/actions/runtime/namespaceKv.js +19 -0
  149. package/dist/modules/actions/runtime/precheck.d.ts +27 -0
  150. package/dist/modules/actions/runtime/precheck.js +45 -0
  151. package/dist/modules/actions/runtime/renderResolver.d.ts +15 -0
  152. package/dist/modules/actions/runtime/renderResolver.js +130 -0
  153. package/dist/modules/actions/runtime/renderResolver.test.d.ts +1 -0
  154. package/dist/modules/actions/runtime/renderShare.d.ts +29 -0
  155. package/dist/modules/actions/runtime/renderShare.js +36 -0
  156. package/dist/modules/actions/runtime/renderShare.test.d.ts +1 -0
  157. package/dist/modules/actions/runtime/report.d.ts +14 -0
  158. package/dist/modules/actions/runtime/report.js +22 -0
  159. package/dist/modules/actions/runtime/runAction.d.ts +12 -0
  160. package/dist/modules/actions/runtime/runAction.js +405 -0
  161. package/dist/modules/actions/runtime/runAction.test.d.ts +1 -0
  162. package/dist/modules/actions/runtime/runLogger.d.ts +31 -0
  163. package/dist/modules/actions/runtime/runLogger.js +66 -0
  164. package/dist/modules/actions/runtime/runLogger.test.d.ts +1 -0
  165. package/dist/modules/actions/runtime/schedule.d.ts +35 -0
  166. package/dist/modules/actions/runtime/schedule.js +76 -0
  167. package/dist/modules/actions/runtime/schedule.test.d.ts +1 -0
  168. package/dist/modules/actions/runtime/scope.d.ts +40 -0
  169. package/dist/modules/actions/runtime/scope.js +103 -0
  170. package/dist/modules/actions/runtime/triggers.d.ts +12 -0
  171. package/dist/modules/actions/runtime/triggers.js +14 -0
  172. package/dist/modules/actions/taskCatalog.d.ts +26 -0
  173. package/dist/modules/actions/taskCatalog.js +24 -0
  174. package/dist/modules/actions/taskCatalog.test.d.ts +1 -0
  175. package/dist/modules/actions/tasks/auth.d.ts +2 -0
  176. package/dist/modules/actions/tasks/auth.js +40 -0
  177. package/dist/modules/actions/tasks/builtins.d.ts +8 -0
  178. package/dist/modules/actions/tasks/builtins.js +24 -0
  179. package/dist/modules/actions/tasks/connector.d.ts +2 -0
  180. package/dist/modules/actions/tasks/connector.js +141 -0
  181. package/dist/modules/actions/tasks/db.d.ts +2 -0
  182. package/dist/modules/actions/tasks/db.js +59 -0
  183. package/dist/modules/actions/tasks/db.test.d.ts +1 -0
  184. package/dist/modules/actions/tasks/flow.d.ts +3 -0
  185. package/dist/modules/actions/tasks/flow.js +109 -0
  186. package/dist/modules/actions/tasks/helpers.d.ts +16 -0
  187. package/dist/modules/actions/tasks/helpers.js +30 -0
  188. package/dist/modules/actions/tasks/http.d.ts +2 -0
  189. package/dist/modules/actions/tasks/http.js +111 -0
  190. package/dist/modules/actions/tasks/http.test.d.ts +1 -0
  191. package/dist/modules/actions/tasks/kv.d.ts +2 -0
  192. package/dist/modules/actions/tasks/kv.js +102 -0
  193. package/dist/modules/actions/tasks/kv.test.d.ts +1 -0
  194. package/dist/modules/actions/tasks/registry.d.ts +10 -0
  195. package/dist/modules/actions/tasks/registry.js +36 -0
  196. package/dist/modules/actions/tasks/transform.d.ts +2 -0
  197. package/dist/modules/actions/tasks/transform.js +34 -0
  198. package/dist/modules/actions/transport/callHandler.d.ts +24 -0
  199. package/dist/modules/actions/transport/callHandler.js +233 -0
  200. package/dist/modules/actions/transport/callHandler.test.d.ts +1 -0
  201. package/dist/modules/actions/transport/cancelHandler.d.ts +23 -0
  202. package/dist/modules/actions/transport/cancelHandler.js +23 -0
  203. package/dist/modules/actions/transport/catalogHandler.d.ts +18 -0
  204. package/dist/modules/actions/transport/catalogHandler.js +21 -0
  205. package/dist/modules/actions/transport/stream.d.ts +23 -0
  206. package/dist/modules/actions/transport/stream.js +100 -0
  207. package/dist/modules/actions/transport/verifySignature.d.ts +16 -0
  208. package/dist/modules/actions/transport/verifySignature.js +72 -0
  209. package/dist/modules/actions/transport/webhookHandler.d.ts +25 -0
  210. package/dist/modules/actions/transport/webhookHandler.js +206 -0
  211. package/dist/modules/actions/transport/webhookHandler.test.d.ts +1 -0
  212. package/dist/modules/actions/types.d.ts +234 -0
  213. package/dist/modules/connectors/engine.js +4 -1
  214. package/dist/modules/connectors/resolver.d.ts +10 -2
  215. package/dist/modules/connectors/resolver.js +8 -3
  216. package/dist/modules/mysql/accounts.d.ts +5 -0
  217. package/dist/modules/mysql/accounts.js +365 -0
  218. package/dist/modules/mysql/accounts.test.d.ts +1 -0
  219. package/dist/modules/mysql/admin.d.ts +58 -0
  220. package/dist/modules/mysql/admin.js +133 -0
  221. package/dist/modules/mysql/config.d.ts +82 -0
  222. package/dist/modules/mysql/config.js +30 -0
  223. package/dist/modules/mysql/identities.d.ts +35 -0
  224. package/dist/modules/mysql/identities.js +43 -0
  225. package/dist/modules/mysql/index.d.ts +67 -0
  226. package/dist/modules/mysql/index.js +62 -0
  227. package/dist/modules/mysql/pool.d.ts +3 -0
  228. package/dist/modules/mysql/pool.js +88 -0
  229. package/dist/modules/mysql/query.d.ts +12 -0
  230. package/dist/modules/mysql/query.js +21 -0
  231. package/dist/modules/mysql/schema.d.ts +43 -0
  232. package/dist/modules/mysql/schema.js +340 -0
  233. package/dist/modules/mysql/schema.test.d.ts +1 -0
  234. package/dist/modules/mysql/sessions.d.ts +33 -0
  235. package/dist/modules/mysql/sessions.js +46 -0
  236. package/dist/modules/mysql/spaceTokens.d.ts +11 -0
  237. package/dist/modules/mysql/spaceTokens.js +59 -0
  238. package/dist/modules/mysql/store.integration.test.d.ts +1 -0
  239. package/dist/modules/rsc/connectorRscData.d.ts +25 -0
  240. package/dist/modules/rsc/connectorRscData.js +51 -0
  241. package/dist/modules/rsc/connectorRscData.test.d.ts +1 -0
  242. package/dist/modules/rsc/handler.js +16 -3
  243. package/dist/modules/rsc/matchRscPage.d.ts +14 -0
  244. package/dist/modules/rsc/matchRscPage.js +26 -0
  245. package/dist/modules/rsc/resolveRscData.d.ts +14 -1
  246. package/dist/modules/rsc/resolveRscData.js +23 -34
  247. package/dist/modules/ssr/Component.d.ts +6 -2
  248. package/dist/modules/ssr/Component.js +3 -1
  249. package/dist/modules/ssr/draftSession.test.d.ts +1 -0
  250. package/dist/modules/ssr/handler.js +15 -2
  251. package/dist/modules/ssr/loadPluginComponents.js +22 -5
  252. package/dist/modules/ssr/prepareRender.js +87 -8
  253. package/dist/modules/ssr/prepareRender.test.d.ts +1 -0
  254. package/dist/modules/ssr/preview.d.ts +21 -8
  255. package/dist/modules/ssr/preview.js +38 -14
  256. package/dist/modules/ssr/registerExternalPlugins.js +2 -2
  257. package/dist/modules/ssr/resolvePageSeo.d.ts +18 -0
  258. package/dist/modules/ssr/resolvePageSeo.js +26 -0
  259. package/dist/modules/ssr/resolvePageSeo.test.d.ts +1 -0
  260. package/dist/modules/ssr/template.test.d.ts +1 -0
  261. package/dist/modules/ssr/views/template.ejs +71 -5
  262. package/dist/mysql.d.ts +26 -0
  263. package/dist/mysql.js +4 -0
  264. package/dist/oauth.d.ts +24 -0
  265. package/dist/oauth.js +10 -0
  266. package/dist/plugins/compile.d.ts +1 -0
  267. package/dist/plugins/compile.js +37 -3
  268. package/dist/plugins/manager.d.ts +40 -0
  269. package/dist/plugins/manager.js +113 -13
  270. package/dist/plugins/manager.test.d.ts +1 -0
  271. package/package.json +43 -14
  272. package/skills/plitzi-authoring/SKILL.md +259 -0
  273. /package/dist/{modules/actions/handler.test.d.ts → adapters/cloudAdapters.test.d.ts} +0 -0
  274. /package/dist/modules/actions/{handler.d.ts → connectorWrite.d.ts} +0 -0
@@ -1,20 +1,113 @@
1
- import { readRawBody } from "../requestParser.js";
2
- import { handleAction } from "../../modules/actions/handler.js";
1
+ import { handleActionCall } from "../../modules/actions/transport/callHandler.js";
2
+ import { handleActionCatalog } from "../../modules/actions/transport/catalogHandler.js";
3
+ import { handleActionWebhook } from "../../modules/actions/transport/webhookHandler.js";
4
+ import { handleActionCancel } from "../../modules/actions/transport/cancelHandler.js";
5
+ import { clientIp, readRawBody } from "../requestParser.js";
6
+ import { handleAction } from "../../modules/actions/connectorWrite.js";
3
7
  //#region src/core/services/action.ts
8
+ var LINEAGE_HEADER = "x-plitzi-action-lineage";
9
+ var safeParse = (body) => {
10
+ try {
11
+ return JSON.parse(body);
12
+ } catch {
13
+ return;
14
+ }
15
+ };
4
16
  /**
5
- * Write endpoint for server-driven providers. RSC is read-only, so this is the only path a page has to mutate a
6
- * connected backend — and it answers POST on its own path alone, never falling through to SSR.
17
+ * Who is asking, for the single-flight key and for cancellation ownership.
7
18
  *
8
- * Inert unless the consumer supplied the connector lookups: without them there is no manifest to authorize a
9
- * write against, and guessing would be the whole vulnerability.
19
+ * A signed-in visitor is themselves; anyone else is their address. The address is a coarse identity a shared
20
+ * NAT makes two visitors look like one, which single-flight would read as a duplicate — so it is only ever used
21
+ * for a `public` action, and the derived key also folds in the input: two people submitting different forms do
22
+ * not collide.
23
+ */
24
+ var callerIdOf = (ctx, req) => req.ctx.user ? `user:${req.ctx.user.id}` : `ip:${clientIp(ctx.raw, req)}`;
25
+ var lineageOf = (req) => {
26
+ const raw = req.headers[LINEAGE_HEADER];
27
+ return (Array.isArray(raw) ? raw.join(",") : raw ?? "").split(",").map((entry) => entry.trim()).filter(Boolean);
28
+ };
29
+ /**
30
+ * The action endpoint: server-driven provider writes, and server actions.
31
+ *
32
+ * Two addressing modes on one path, because both are "the browser asks the server to change something, naming it
33
+ * rather than addressing it". An element-addressed body reaches a connector's declared write; an action-addressed
34
+ * one runs a stored flow. Each mode is inert unless its own half of the config is present, so a deployment that
35
+ * configures neither has no endpoint at all — and guessing what an unconfigured one should do would be the whole
36
+ * vulnerability.
10
37
  */
11
38
  var actionStage = async (ctx) => {
12
- const { config, req } = ctx;
39
+ const { config, req, actions } = ctx;
13
40
  const actionPath = config.action?.path ?? "/_action";
14
- if (!config.action?.lookups || req.method !== "POST" || req.path !== actionPath) return false;
15
- ctx.operation = "action";
41
+ const hasConnectors = !!config.connectors;
42
+ if (!hasConnectors && !actions) return false;
43
+ if (actions && req.method === "GET" && req.path === `${actionPath}/catalog`) {
44
+ ctx.operation = "action:catalog";
45
+ if (!req.ctx.user) {
46
+ ctx.res.setStatus(401);
47
+ ctx.res.send("");
48
+ return true;
49
+ }
50
+ handleActionCatalog({
51
+ res: ctx.res,
52
+ module: actions
53
+ });
54
+ return true;
55
+ }
56
+ if (actions && req.method === "POST" && req.path.startsWith(`${actionPath}/hook/`)) {
57
+ ctx.operation = "action:webhook";
58
+ req.body = await readRawBody(ctx.raw);
59
+ await handleActionWebhook({
60
+ req,
61
+ res: ctx.res,
62
+ config,
63
+ module: actions,
64
+ signal: ctx.signal,
65
+ actionId: req.path.slice(`${actionPath}/hook/`.length),
66
+ callerId: `ip:${clientIp(ctx.raw, req)}`,
67
+ lineage: lineageOf(req)
68
+ });
69
+ return true;
70
+ }
71
+ if (actions && req.method === "DELETE" && req.path.startsWith(`${actionPath}/run/`)) {
72
+ ctx.operation = "action:cancel";
73
+ await handleActionCancel({
74
+ res: ctx.res,
75
+ module: actions,
76
+ runId: req.path.slice(`${actionPath}/run/`.length),
77
+ callerId: callerIdOf(ctx, req)
78
+ });
79
+ return true;
80
+ }
81
+ if (req.method !== "POST" || req.path !== actionPath) return false;
16
82
  req.body = await readRawBody(ctx.raw);
17
- await handleAction(req, ctx.res, config, config.action.lookups);
83
+ const body = req.body ? safeParse(req.body) : void 0;
84
+ const addressesAction = body !== void 0 && typeof body === "object" && body !== null && "actionId" in body;
85
+ if (addressesAction && actions) {
86
+ ctx.operation = "action:run";
87
+ await handleActionCall({
88
+ req,
89
+ res: ctx.res,
90
+ raw: ctx.rawRes,
91
+ config,
92
+ module: actions,
93
+ signal: ctx.signal,
94
+ callerId: callerIdOf(ctx, req),
95
+ lineage: lineageOf(req)
96
+ });
97
+ return true;
98
+ }
99
+ if (addressesAction || !hasConnectors) {
100
+ ctx.operation = "action";
101
+ ctx.res.setStatus(404);
102
+ ctx.res.setHeader("Content-Type", "application/json; charset=utf-8");
103
+ ctx.res.send(JSON.stringify({
104
+ error: "This server runs no actions",
105
+ reason: "not_found"
106
+ }));
107
+ return true;
108
+ }
109
+ ctx.operation = "action";
110
+ await handleAction(req, ctx.res, config, config.connectors);
18
111
  return true;
19
112
  };
20
113
  //#endregion
@@ -2,6 +2,7 @@ import { actionStage } from "./action.js";
2
2
  import { rscStage } from "./rsc.js";
3
3
  import { notFoundStage, ssrStage } from "./ssr.js";
4
4
  import { authRoutesStages } from "../http/stages/authRoutes.js";
5
+ import { fontAssetsStage } from "../http/stages/fontAssets.js";
5
6
  import { healthStage } from "../http/stages/health.js";
6
7
  import { middlewaresStage } from "../http/stages/middlewares.js";
7
8
  import { pluginAssetsStage } from "../http/stages/pluginAssets.js";
@@ -13,6 +14,7 @@ var buildPagePipeline = (services, extensions = {}) => {
13
14
  publicDirStage,
14
15
  wellKnownStage,
15
16
  pluginAssetsStage,
17
+ fontAssetsStage,
16
18
  ...authRoutesStages,
17
19
  configStaticStage,
18
20
  sdkAssetsStage
@@ -2,3 +2,11 @@ import { ServerServices, SSRServerConfig } from '@plitzi/sdk-shared';
2
2
  export type ResolvedServices = Required<ServerServices>;
3
3
  export declare const resolveServices: (config: SSRServerConfig) => ResolvedServices;
4
4
  export declare const resolveRscEndpoint: (config: SSRServerConfig) => string | undefined;
5
+ /**
6
+ * Where this server runs actions, or undefined when it runs none.
7
+ *
8
+ * Published to the client as `server.ssr.actionPath` for the same reason `rscPath` is: absence is how a page
9
+ * learns, once, that a `serverAction` step has nowhere to run — instead of every click discovering it through a
10
+ * 404. A static export or an embed with no server tier publishes nothing here.
11
+ */
12
+ export declare const resolveActionEndpoint: (config: SSRServerConfig) => string | undefined;
@@ -10,5 +10,16 @@ var resolveRscEndpoint = (config) => {
10
10
  if (!resolveServices(config).rsc || !(config.rsc?.enabled ?? true) || !config.adapters.getRscData) return;
11
11
  return config.rsc?.path ?? "/_rsc";
12
12
  };
13
+ /**
14
+ * Where this server runs actions, or undefined when it runs none.
15
+ *
16
+ * Published to the client as `server.ssr.actionPath` for the same reason `rscPath` is: absence is how a page
17
+ * learns, once, that a `serverAction` step has nowhere to run — instead of every click discovering it through a
18
+ * 404. A static export or an embed with no server tier publishes nothing here.
19
+ */
20
+ var resolveActionEndpoint = (config) => {
21
+ if (!config.action?.lookups) return;
22
+ return config.action.path ?? "/_action";
23
+ };
13
24
  //#endregion
14
- export { resolveRscEndpoint, resolveServices };
25
+ export { resolveActionEndpoint, resolveRscEndpoint, resolveServices };
@@ -16,8 +16,7 @@ var serveFile = (req, res, filePath, stat) => {
16
16
  }
17
17
  const content = fs.readFileSync(filePath);
18
18
  res.setHeader("Content-Type", getMimeType(filePath));
19
- res.setHeader("Content-Length", content.byteLength.toString());
20
- res.send(content.toString("utf-8"));
19
+ res.send(content);
21
20
  return true;
22
21
  };
23
22
  var serveStatic = (req, res, rootDir) => {
@@ -52,7 +52,13 @@
52
52
  * ```
53
53
  */
54
54
  export { createAuthRouteHandlers, mountAuthRoutes } from './core/handlers/authRouteHandlers';
55
+ export { createSocialAuthRouteHandlers, mountSocialAuthRoutes } from './core/handlers/socialRouteHandlers';
56
+ export { createOAuthRouteHandlers, mountOAuthRoutes, OAUTH_ROUTE_PATHS } from './core/handlers/oauthRouteHandlers';
55
57
  export { createAuthMiddleware } from './core/handlers/authMiddleware';
58
+ export { createCsrfMiddleware } from './core/handlers/csrfMiddleware';
56
59
  export type { AuthRouteHandlersOptions } from './core/handlers/authRouteHandlers';
60
+ export type { SocialRouteHandlersOptions } from './core/handlers/socialRouteHandlers';
61
+ export type { OAuthResponse, OAuthRouteHandler, OAuthRouteHandlersOptions } from './core/handlers/oauthRouteHandlers';
57
62
  export type { AuthMiddlewareOptions } from './core/handlers/authMiddleware';
58
- export type { AuthedRequest, JsonResponse, HttpRoute, RouteHandler, RouterLike } from './core/handlers/types';
63
+ export type { CsrfMiddlewareOptions } from './core/handlers/csrfMiddleware';
64
+ export type { AuthedRequest, HttpRoute, JsonResponse, RedirectResponse, RouteHandler, RouterLike, SocialRouteHandler } from './core/handlers/types';
package/dist/handlers.js CHANGED
@@ -1,3 +1,6 @@
1
1
  import { createAuthRouteHandlers, mountAuthRoutes } from "./core/handlers/authRouteHandlers.js";
2
+ import { createSocialAuthRouteHandlers, mountSocialAuthRoutes } from "./core/handlers/socialRouteHandlers.js";
3
+ import { OAUTH_ROUTE_PATHS, createOAuthRouteHandlers, mountOAuthRoutes } from "./core/handlers/oauthRouteHandlers.js";
2
4
  import { createAuthMiddleware } from "./core/handlers/authMiddleware.js";
3
- export { createAuthMiddleware, createAuthRouteHandlers, mountAuthRoutes };
5
+ import { createCsrfMiddleware } from "./core/handlers/csrfMiddleware.js";
6
+ export { OAUTH_ROUTE_PATHS, createAuthMiddleware, createAuthRouteHandlers, createCsrfMiddleware, createOAuthRouteHandlers, createSocialAuthRouteHandlers, mountAuthRoutes, mountOAuthRoutes, mountSocialAuthRoutes };
@@ -9,5 +9,13 @@ export type RawResponse = {
9
9
  writeHead(statusCode: number, headers?: Record<string, string | number | readonly string[]>): unknown;
10
10
  write(chunk: string | Buffer): unknown;
11
11
  end(chunk?: string | Buffer): unknown;
12
+ /**
13
+ * Optional, because this type is the MINIMUM a host has to provide — node's own, http2's, or a fake in a test.
14
+ *
15
+ * They are how the dispatcher tells "the caller left" from "the answer was sent": a host that exposes neither
16
+ * simply never cancels early, which is the behaviour of every host that had no such notion to begin with.
17
+ */
18
+ once?(event: 'close', listener: () => void): unknown;
19
+ writableFinished?: boolean;
12
20
  };
13
21
  export declare const buildResponseHelpers: (raw: RawResponse, acceptEncoding?: string, compression?: ResolvedCompression) => SSRResponseHelpers;
@@ -13,7 +13,15 @@ var buildResponseHelpers = (raw, acceptEncoding, compression = DEFAULT_COMPRESSI
13
13
  */
14
14
  const transformable = () => !String(raw.getHeaders()["cache-control"]).includes("no-transform");
15
15
  const writeSend = (body) => {
16
- const compressed = transformable() ? compressBody(body, encoding, compression) : body;
16
+ /**
17
+ * A Buffer goes out untouched.
18
+ *
19
+ * It is the only way a binary reaches the wire — this response object had `send(body: string)` and every
20
+ * caller went through a UTF-8 round trip, which silently replaces every byte that is not valid UTF-8 and so
21
+ * corrupts any font, image or archive served through it. What a Buffer holds is also compressed already
22
+ * (woff2, png), so re-encoding it would cost CPU to make it bigger.
23
+ */
24
+ const compressed = typeof body === "string" && transformable() ? compressBody(body, encoding, compression) : body;
17
25
  if (compressed !== body) {
18
26
  raw.setHeader("Content-Encoding", encoding);
19
27
  raw.setHeader("Vary", "Accept-Encoding");
@@ -1,3 +1,8 @@
1
- import { OfflineDataLoader } from './offlineDataLoader';
2
- import { Server, SSRRequest, SSRServerConfig } from '@plitzi/sdk-shared';
3
- export declare const buildServerInfo: (req: SSRRequest, config: SSRServerConfig, loadOfflineData: OfflineDataLoader) => Promise<Partial<Server>>;
1
+ import { Server, ServerSSR, SSRRequest, SSRServerConfig } from '@plitzi/sdk-shared';
2
+ /**
3
+ * The endpoints, the session and the location this render happens at.
4
+ *
5
+ * Synchronous, and takes the RSC bootstrap already resolved rather than resolving it: the only async thing here was
6
+ * ever the `getRscData` call, so the caller starting that read is also what decides whether it happens at all.
7
+ */
8
+ export declare const buildServerInfo: (req: SSRRequest, config: SSRServerConfig, ssr: ServerSSR) => Partial<Server>;
@@ -1,4 +1,3 @@
1
- import { resolveRscEndpoint } from "../core/services/resolve.js";
2
1
  //#region src/helpers/buildServerInfo.ts
3
2
  var getEnvironment = (env = "production", server) => {
4
3
  switch (env) {
@@ -29,16 +28,31 @@ var getEnvironment = (env = "production", server) => {
29
28
  };
30
29
  }
31
30
  };
32
- var buildServerInfo = async (req, config, loadOfflineData) => {
31
+ /**
32
+ * The endpoints, the session and the location this render happens at.
33
+ *
34
+ * Synchronous, and takes the RSC bootstrap already resolved rather than resolving it: the only async thing here was
35
+ * ever the `getRscData` call, so the caller starting that read is also what decides whether it happens at all.
36
+ */
37
+ var buildServerInfo = (req, config, ssr) => {
33
38
  const accessToken = req.query["access-token"];
34
39
  const origin = `${req.protocol}://${req.hostname}`;
35
40
  const user = req.ctx.user;
36
- const { environment = "main", spaceId, revision = 0 } = req.ctx.spaceDeployment ?? {};
37
41
  return getEnvironment(config.environment, {
38
42
  basePath: "/",
39
43
  requestUrl: req.url || "/",
40
44
  origin,
45
+ /**
46
+ * Complete enough to be the same object a browser hands the SDK, `origin` included.
47
+ *
48
+ * It used to carry the hostname and the path only, which reads as a location right up until something needs to
49
+ * name THIS page from the server: a sign-in link that sends somebody back where they were had nothing to build
50
+ * an absolute URL out of, so a space had to name its own address in a per-environment variable instead.
51
+ */
41
52
  location: {
53
+ origin,
54
+ protocol: `${req.protocol}:`,
55
+ host: req.hostname,
42
56
  hostname: req.hostname,
43
57
  pathname: req.path || "/",
44
58
  search: req.search
@@ -57,17 +71,7 @@ var buildServerInfo = async (req, config, loadOfflineData) => {
57
71
  accessToken: user.token,
58
72
  expiresAt: user.expiresAt
59
73
  } : void 0,
60
- ssr: {
61
- rscPath: resolveRscEndpoint(config),
62
- rscData: await config.adapters.getRscData?.({
63
- req,
64
- spaceId,
65
- environment,
66
- revision,
67
- user,
68
- loadOfflineData
69
- })
70
- }
74
+ ssr
71
75
  });
72
76
  };
73
77
  //#endregion
@@ -1,7 +1,20 @@
1
+ /**
2
+ * The key a rendered document is cached under.
3
+ *
4
+ * The visitor's theme is part of it because it is part of the DOCUMENT: `prepareRender` reads the `theme` cookie and
5
+ * writes it onto `<html>` and into the props the SDK hydrates with. Keyed without it, the first visitor's choice was
6
+ * served to everybody behind them — a dark page for a visitor who chose light, then corrected on hydration.
7
+ *
8
+ * Read from the request here rather than handed in, so a call site cannot key the page without it. Only the theme
9
+ * cookie is read: keying the whole header would split the cache on every analytics cookie a visitor carries.
10
+ */
1
11
  export declare const buildHtmlCacheKey: (accessToken: string | undefined, spaceId: number | string | null, environment: string, revision: number, req: {
2
12
  hostname: string;
3
13
  path: string;
4
14
  search: string;
15
+ headers: {
16
+ cookie?: string;
17
+ };
5
18
  }) => string;
6
19
  export declare const buildOfflineDataCacheKey: (spaceId: number, environment: string, revision: number) => string;
7
20
  export declare const buildRscCacheKey: (spaceId: number, environment: string, revision: number, userId: string | number | undefined, idsParam: string | undefined, req: {
@@ -1,5 +1,16 @@
1
+ import { themeFromCookies } from "@plitzi/sdk-shared/theme";
1
2
  //#region src/helpers/cache/keys.ts
2
- var buildHtmlCacheKey = (accessToken = "anonymous", spaceId, environment, revision, req) => `${accessToken}\0${spaceId ?? 1}\0${environment}\0${revision}\0${req.hostname}\0${req.path}\0${req.search}`;
3
+ /**
4
+ * The key a rendered document is cached under.
5
+ *
6
+ * The visitor's theme is part of it because it is part of the DOCUMENT: `prepareRender` reads the `theme` cookie and
7
+ * writes it onto `<html>` and into the props the SDK hydrates with. Keyed without it, the first visitor's choice was
8
+ * served to everybody behind them — a dark page for a visitor who chose light, then corrected on hydration.
9
+ *
10
+ * Read from the request here rather than handed in, so a call site cannot key the page without it. Only the theme
11
+ * cookie is read: keying the whole header would split the cache on every analytics cookie a visitor carries.
12
+ */
13
+ var buildHtmlCacheKey = (accessToken = "anonymous", spaceId, environment, revision, req) => `${accessToken}\0${spaceId ?? 1}\0${environment}\0${revision}\0${themeFromCookies(req.headers.cookie) ?? ""}\0${req.hostname}\0${req.path}\0${req.search}`;
3
14
  var buildOfflineDataCacheKey = (spaceId, environment, revision) => `${spaceId}|${environment}|${revision}`;
4
15
  var buildRscCacheKey = (spaceId, environment, revision, userId, idsParam, req) => `${spaceId}\0${environment}\0${revision}\0${userId ?? "anon"}\0${idsParam ?? ""}\0${req.hostname}\0${req.path}\0${req.search}`;
5
16
  //#endregion
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Subscribes to a signal, and covers the case every hand-rolled subscription misses: one that is ALREADY aborted.
3
+ *
4
+ * `addEventListener('abort', …)` on a signal that has already fired never calls back — the event is long gone — so
5
+ * a listener attached after any `await` is a cancellation silently dropped. That window is not theoretical: an
6
+ * action is READ before its run begins, and a page that gave up during that read left the run to carry on holding
7
+ * a slot and a connection for nobody.
8
+ *
9
+ * Returns the unsubscribe, so a caller that outlives the signal does not leak a listener onto it.
10
+ */
11
+ export declare const onAbort: (signal: AbortSignal | undefined, stop: () => void) => (() => void);
12
+ export default onAbort;
@@ -0,0 +1,22 @@
1
+ //#region src/helpers/onAbort.ts
2
+ /**
3
+ * Subscribes to a signal, and covers the case every hand-rolled subscription misses: one that is ALREADY aborted.
4
+ *
5
+ * `addEventListener('abort', …)` on a signal that has already fired never calls back — the event is long gone — so
6
+ * a listener attached after any `await` is a cancellation silently dropped. That window is not theoretical: an
7
+ * action is READ before its run begins, and a page that gave up during that read left the run to carry on holding
8
+ * a slot and a connection for nobody.
9
+ *
10
+ * Returns the unsubscribe, so a caller that outlives the signal does not leak a listener onto it.
11
+ */
12
+ var onAbort = (signal, stop) => {
13
+ if (!signal) return () => {};
14
+ if (signal.aborted) {
15
+ stop();
16
+ return () => {};
17
+ }
18
+ signal.addEventListener("abort", stop, { once: true });
19
+ return () => signal.removeEventListener("abort", stop);
20
+ };
21
+ //#endregion
22
+ export { onAbort as default, onAbort };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Where a customer-authored request may go.
3
+ *
4
+ * Two things reach the outside world on somebody else's say-so: the `http.request` task, whose URL is typed into
5
+ * a flow, and the connector engine, whose `baseUrl` is typed into a manifest. Both run inside the cluster, from a
6
+ * trusted network position, which is what turns "fetch this URL for me" into a way to read the instance's cloud
7
+ * credentials at `169.254.169.254` or talk to Redis on `localhost`. One rule, in one place, for both of them.
8
+ */
9
+ /** Literal forms an authored URL can hold, and the ones this refuses outright. */
10
+ export declare const isBlockedHost: (hostname: string) => boolean;
11
+ export type HostLookup = (hostname: string) => Promise<{
12
+ address: string;
13
+ }[]>;
14
+ /**
15
+ * Checks the URL an authored document asked for, including what its hostname RESOLVES to.
16
+ *
17
+ * The literal check alone was never enough and said so: `http://metadata.example.com/` is a public-looking name
18
+ * whose A record can be `169.254.169.254`, and nothing about the string gives that away. So the name is resolved
19
+ * and every address it answers is judged — a name that resolves to a private address is refused whatever it is
20
+ * spelled like.
21
+ *
22
+ * A name that does not resolve is ALLOWED through: there is nothing to judge, and the request is about to fail on
23
+ * its own with a better error than this could give. What remains open is DNS rebinding — an attacker's own server
24
+ * answering a public address here and a private one when the socket is opened a moment later — which is closed
25
+ * only by resolving and connecting to the same address, and that belongs in the transport rather than here.
26
+ */
27
+ export declare const assertOutboundAllowed: (url: URL, lookup?: HostLookup) => Promise<void>;
@@ -0,0 +1,49 @@
1
+ import { lookup } from "node:dns/promises";
2
+ //#region src/helpers/outboundGuard.ts
3
+ /**
4
+ * Where a customer-authored request may go.
5
+ *
6
+ * Two things reach the outside world on somebody else's say-so: the `http.request` task, whose URL is typed into
7
+ * a flow, and the connector engine, whose `baseUrl` is typed into a manifest. Both run inside the cluster, from a
8
+ * trusted network position, which is what turns "fetch this URL for me" into a way to read the instance's cloud
9
+ * credentials at `169.254.169.254` or talk to Redis on `localhost`. One rule, in one place, for both of them.
10
+ */
11
+ /** Literal forms an authored URL can hold, and the ones this refuses outright. */
12
+ var isBlockedHost = (hostname) => {
13
+ const host = hostname.toLowerCase().replace(/^\[|\]$/g, "");
14
+ if (host === "localhost" || host.endsWith(".localhost") || host.endsWith(".internal") || host === "::1") return true;
15
+ const ipv4 = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/.exec(host);
16
+ if (!ipv4) return /^f[cd]/.test(host) || host.startsWith("fe8") || host.startsWith("fe9") || /^fe[ab]/.test(host);
17
+ const [a = 0, b = 0] = ipv4.slice(1).map((part) => Number.parseInt(part, 10));
18
+ return a === 0 || a === 10 || a === 127 || a === 100 && b >= 64 && b <= 127 || a === 169 && b === 254 || a === 172 && b >= 16 && b <= 31 || a === 192 && b === 168;
19
+ };
20
+ var resolveAll = (hostname) => lookup(hostname, {
21
+ all: true,
22
+ verbatim: true
23
+ });
24
+ /**
25
+ * Checks the URL an authored document asked for, including what its hostname RESOLVES to.
26
+ *
27
+ * The literal check alone was never enough and said so: `http://metadata.example.com/` is a public-looking name
28
+ * whose A record can be `169.254.169.254`, and nothing about the string gives that away. So the name is resolved
29
+ * and every address it answers is judged — a name that resolves to a private address is refused whatever it is
30
+ * spelled like.
31
+ *
32
+ * A name that does not resolve is ALLOWED through: there is nothing to judge, and the request is about to fail on
33
+ * its own with a better error than this could give. What remains open is DNS rebinding — an attacker's own server
34
+ * answering a public address here and a private one when the socket is opened a moment later — which is closed
35
+ * only by resolving and connecting to the same address, and that belongs in the transport rather than here.
36
+ */
37
+ var assertOutboundAllowed = async (url, lookup = resolveAll) => {
38
+ if (url.protocol !== "https:" && url.protocol !== "http:") throw new Error(`Request protocol "${url.protocol}" is not allowed`);
39
+ if (isBlockedHost(url.hostname)) throw new Error("Request host is not allowed");
40
+ let addresses;
41
+ try {
42
+ addresses = await lookup(url.hostname.replace(/^\[|\]$/g, ""));
43
+ } catch {
44
+ return;
45
+ }
46
+ if (addresses.some(({ address }) => isBlockedHost(address))) throw new Error("Request host is not allowed");
47
+ };
48
+ //#endregion
49
+ export { assertOutboundAllowed, isBlockedHost };
@@ -0,0 +1 @@
1
+ export {};
@@ -1,9 +1,12 @@
1
1
  import { ServerLogEvent, ServerLogger } from '@plitzi/sdk-shared';
2
2
  /** One line for any {@link ServerLogEvent}: an HTTP request reads as an access-log line
3
3
  * (`[SSR] 203.0.113.7 GET /pricing 200 12ms ok`), the MCP events as what happened inside one
4
- * (`[MCP] tools/call plitzi_apply {operations:[3]} 41ms ok`). Rendering is a pure format the dispatcher
5
- * already stripped query values, collected no headers, cookies or tokens and summarised tool args by shape;
6
- * the client IP it does carry is personal data, so a sink that persists these lines must say so. */
4
+ * (`[MCP] tools/call plitzi_apply {operations:[3]} 41ms ok`), a server action as what its flow did
5
+ * (`[Action] shipping-quote via call space=1 completed 12ms ok`) and a refused one as what turned it away
6
+ * (`[Action] checkout via webhook space=1 REFUSED invalid_signature`). Rendering is a pure format the dispatcher
7
+ * already stripped query values, collected no headers, cookies or tokens, summarised tool args by shape and
8
+ * reduced a run to its steps; the client IP it does carry is personal data, so a sink that persists these lines
9
+ * must say so. */
7
10
  export declare const renderLogEvent: (event: ServerLogEvent) => string;
8
11
  /** A drop-in `SSRServerConfig.logger` for consumers that just want the log on the console. Consumers with their
9
12
  * own logging stack should pass their own sink instead and read the structured event. */
@@ -11,16 +11,33 @@ var renderTool = (event) => {
11
11
  return `[MCP] tools/call ${event.name}${args} ${Math.round(event.durationMs)}ms ${outcomeOf(event)}`;
12
12
  };
13
13
  var renderResource = (event) => `[MCP] resources/read ${event.name} ${Math.round(event.durationMs)}ms ${outcomeOf(event)}`;
14
+ /** The steps go on the line only when the run ended badly. On a run that worked they are noise on every single
15
+ * call; on one that did not they are the answer — which step stopped, and what the ones before it did. */
16
+ var renderRun = (event) => {
17
+ const steps = event.ok || event.steps.length === 0 ? "" : ` [${event.steps.join(" → ")}]`;
18
+ return `[Action] ${event.name} via ${event.trigger} space=${event.spaceId} ${event.status} ${Math.round(event.durationMs)}ms ${outcomeOf(event)}${steps}`;
19
+ };
20
+ /** A refusal reads as what refused it: `[Action] checkout via webhook space=1 REFUSED invalid_signature`. The
21
+ * reason is the whole point of the line — "401" is what the request log already said. */
22
+ var renderReject = (event) => {
23
+ const caller = event.callerId ? ` from ${event.callerId}` : "";
24
+ return `[Action] ${event.name} via ${event.trigger} space=${event.spaceId} REFUSED ${event.reason}${caller} ${outcomeOf(event)}`;
25
+ };
14
26
  /** One line for any {@link ServerLogEvent}: an HTTP request reads as an access-log line
15
27
  * (`[SSR] 203.0.113.7 GET /pricing 200 12ms ok`), the MCP events as what happened inside one
16
- * (`[MCP] tools/call plitzi_apply {operations:[3]} 41ms ok`). Rendering is a pure format the dispatcher
17
- * already stripped query values, collected no headers, cookies or tokens and summarised tool args by shape;
18
- * the client IP it does carry is personal data, so a sink that persists these lines must say so. */
28
+ * (`[MCP] tools/call plitzi_apply {operations:[3]} 41ms ok`), a server action as what its flow did
29
+ * (`[Action] shipping-quote via call space=1 completed 12ms ok`) and a refused one as what turned it away
30
+ * (`[Action] checkout via webhook space=1 REFUSED invalid_signature`). Rendering is a pure format the dispatcher
31
+ * already stripped query values, collected no headers, cookies or tokens, summarised tool args by shape and
32
+ * reduced a run to its steps; the client IP it does carry is personal data, so a sink that persists these lines
33
+ * must say so. */
19
34
  var renderLogEvent = (event) => {
20
35
  switch (event.kind) {
21
36
  case "request": return renderRequest(event);
22
37
  case "tool": return renderTool(event);
23
38
  case "resource": return renderResource(event);
39
+ case "run": return renderRun(event);
40
+ case "reject": return renderReject(event);
24
41
  }
25
42
  };
26
43
  /** A drop-in `SSRServerConfig.logger` for consumers that just want the log on the console. Consumers with their
package/dist/index.d.ts CHANGED
@@ -2,15 +2,21 @@ export { createServer, resolveServices } from './core/createServer';
2
2
  export { registerHealthCheck, buildHealthPayload } from './core/health';
3
3
  export { consoleLogger, renderLogEvent } from './helpers/serverLog';
4
4
  export type { HealthCheckApp, HealthIdentity } from './core/health';
5
+ export { createCloudAdapters } from './adapters/cloudAdapters';
5
6
  export { createJsonAdapters } from './adapters/jsonAdapters';
6
7
  export { createAuthAdapters } from './adapters/authAdapters';
8
+ export { authoringPreview, createMemoryCache, createSpaceAdapters, fixedSpace, presentsCredential, refuse, verifiedDomain, wildcardSubdomain } from './adapters/space';
9
+ export { createLocalFontStore, hostedPathsOf } from './core/fontStore';
7
10
  export { createMemoryDraftStore, takeDraftOverride } from './modules/ssr/preview';
8
11
  export { PREVIEW_TOKEN_PARAM } from './core/previewToken';
9
12
  export { resolveRscData } from './modules/rsc/resolveRscData';
10
13
  export { fetchConnectorRecords, rebaseMedia, writeConnectorRecord, createConnectorResolver } from './modules/connectors';
14
+ export type { CloudAdaptersConfig, CloudSpaceCache } from './adapters/cloudAdapters';
11
15
  export type { JsonAdaptersConfig } from './adapters/jsonAdapters';
12
16
  export type { AuthAdapters, AuthAdaptersConfig } from './adapters/authAdapters';
17
+ export type { AuthoringPreviewOptions, DeploymentRow, FrameAncestorsConfig, SpaceAdapters, SpaceAdaptersConfig, SpaceCache, SpaceRefusal, SpaceResolution, SpaceResolver, WildcardSubdomainOptions } from './adapters/space';
13
18
  export type { RscElementResolver, RscResolveContext, ResolveRscDataOptions } from './modules/rsc/resolveRscData';
14
19
  export type { ConnectorAuth, ConnectorCredential, ConnectorEndpoints, ConnectorFilter, ConnectorLookups, ConnectorManifest, ConnectorManifestDraft, ConnectorPageInfo, ConnectorPagination, ConnectorQuery, ConnectorReadEndpoint, ConnectorRecord, ConnectorResponseMapping, ConnectorResult, ProviderPagination } from './modules/connectors';
20
+ export type { FontStore, StoredFont } from './core/fontStore';
15
21
  export type { ResolvedServices } from './core/createServer';
16
22
  export type { BaseContext, PipelineExtensions, SSRContext, Stage } from './core/http/types';
package/dist/index.js CHANGED
@@ -1,12 +1,17 @@
1
+ import { fetchConnectorRecords, rebaseMedia, writeConnectorRecord } from "./modules/connectors/engine.js";
2
+ import { createConnectorResolver } from "./modules/connectors/resolver.js";
3
+ import { resolveRscData } from "./modules/rsc/resolveRscData.js";
1
4
  import { PREVIEW_TOKEN_PARAM } from "./core/previewToken.js";
2
5
  import { createMemoryDraftStore, takeDraftOverride } from "./modules/ssr/preview.js";
3
- import { fetchConnectorRecords, rebaseMedia, writeConnectorRecord } from "./modules/connectors/engine.js";
4
6
  import { resolveServices } from "./core/services/resolve.js";
5
7
  import { buildHealthPayload, registerHealthCheck } from "./core/health.js";
6
8
  import { createServer } from "./core/createServer.js";
7
9
  import { consoleLogger, renderLogEvent } from "./helpers/serverLog.js";
10
+ import { createCloudAdapters } from "./adapters/cloudAdapters.js";
8
11
  import { createJsonAdapters } from "./adapters/jsonAdapters.js";
9
12
  import { createAuthAdapters } from "./adapters/authAdapters.js";
10
- import { resolveRscData } from "./modules/rsc/resolveRscData.js";
11
- import { createConnectorResolver } from "./modules/connectors/resolver.js";
12
- export { PREVIEW_TOKEN_PARAM, buildHealthPayload, consoleLogger, createAuthAdapters, createConnectorResolver, createJsonAdapters, createMemoryDraftStore, createServer, fetchConnectorRecords, rebaseMedia, registerHealthCheck, renderLogEvent, resolveRscData, resolveServices, takeDraftOverride, writeConnectorRecord };
13
+ import { createMemoryCache, refuse } from "./adapters/space/types.js";
14
+ import { authoringPreview, fixedSpace, presentsCredential, verifiedDomain, wildcardSubdomain } from "./adapters/space/resolvers.js";
15
+ import { createSpaceAdapters } from "./adapters/space/index.js";
16
+ import { createLocalFontStore, hostedPathsOf } from "./core/fontStore.js";
17
+ export { PREVIEW_TOKEN_PARAM, authoringPreview, buildHealthPayload, consoleLogger, createAuthAdapters, createCloudAdapters, createConnectorResolver, createJsonAdapters, createLocalFontStore, createMemoryCache, createMemoryDraftStore, createServer, createSpaceAdapters, fetchConnectorRecords, fixedSpace, hostedPathsOf, presentsCredential, rebaseMedia, refuse, registerHealthCheck, renderLogEvent, resolveRscData, resolveServices, takeDraftOverride, verifiedDomain, wildcardSubdomain, writeConnectorRecord };
package/dist/kernel.d.ts CHANGED
@@ -5,37 +5,20 @@
5
5
  * from there would load that whole graph. This entry's closure is the dispatcher, the transports and the base
6
6
  * stages: no React, no template, no plugin manager.
7
7
  *
8
- * A server built on it supplies its own pipeline; `@plitzi/sdk-mcp` is the in-tree example. */
8
+ * A server built on it supplies its own pipeline; `@plitzi/sdk-mcp` is the in-tree example.
9
+ *
10
+ * Auth is **not** here — it is `@plitzi/sdk-server/auth`. The two shared this entry for a while and the name
11
+ * described neither: a deployment wiring up sessions loaded the dispatcher to get them, and a server that wants
12
+ * the dispatcher and no auth at all had to name the entry that carried both. */
9
13
  export { createHttpServer } from './core/server/baseServer';
10
14
  export { makeHandler } from './core/http/dispatcher';
11
15
  export { healthStage } from './core/http/stages/health';
12
16
  export { configStaticStage, publicDirStage, wellKnownStage } from './core/http/stages/static';
13
17
  export { buildHealthPayload, registerHealthCheck } from './core/health';
14
18
  export { clientIp, parseRequest, readRawBody, requestOrigin } from './core/requestParser';
15
- export { clearFlowCookie, clearSessionCookies, createSessionCookies, isLocalHost, readFlowCookie, readRefreshToken, readSessionToken, sessionCookieParams, sessionHintValue, writeFlowCookie, writeSessionCookies } from './core/auth/session';
16
- export { SCOPES, authFailureMessage, createTokens, userIdOf } from './core/auth/tokens';
17
- export { createCarriers, presentedOrigin } from './core/auth/credentials';
18
- export { ANY_DOMAIN, corsOrigins, domainAllowed, frameAncestors, hostnameOf, normalizeDomain } from './core/auth/domains';
19
- export { createIdentity } from './core/auth/identity';
20
- export { checkPermission, checkSpaceAccess, createAuthorizer, requirementFor } from './core/auth/authorize';
21
- export { createAuth } from './core/auth/createAuth';
22
- export { createAuthApi } from './core/auth/api';
23
- export { applySessionOutcome, authPolicyRules, authRoutes } from './core/auth/routes';
24
- export { createSpaceTokenApi } from './core/auth/spaceTokens';
25
- export { BUILT_IN_PROVIDERS, OAuthFailure, createSocialAuth, requestProfileJson } from './core/auth/oauth';
26
19
  export { consoleLogger, renderLogEvent } from './helpers/serverLog';
27
20
  export { PREVIEW_TOKEN_PARAM } from './core/previewToken';
28
21
  export type { HttpServerParts } from './core/server/baseServer';
29
22
  export type { BuildContext } from './core/http/dispatcher';
30
23
  export type { HealthCheckApp, HealthIdentity } from './core/health';
31
24
  export type { BaseContext, PipelineExtensions, SSRContext, Stage } from './core/http/types';
32
- export type { CookieCarrier, CookieSink, SessionCookieParams, SessionCookies } from './core/auth/session';
33
- export type { CredentialCarrier } from './core/auth/credentials';
34
- export type { Actor, ActorResult, Grant, GrantOptions, GrantResult, Identity, IdentityAdapters, IdentityConfig, SpaceMembership, StoredSpaceToken } from './core/auth/identity';
35
- export type { AuthPolicy, AuthorizeResult, Authorizer, MembershipFacts, PathMatcher, PermissionCheck, Requirement, SpaceAccessCheck } from './core/auth/authorize';
36
- export type { AuthRequest, AuthRoute } from './core/auth/routes';
37
- export type { Auth, AuthConfig } from './core/auth/createAuth';
38
- export type { CompletedFlow, OAuthFailureReason, OAuthProfile, OAuthProvider, OAuthProviderConfig, SocialAuth, SocialAuthAdapters, SocialAuthConfig, StartedFlow } from './core/auth/oauth';
39
- export type { AccountAccess, AccountAdapters, AccountRecord, AuthApi, AuthApiConfig, AuthOutcome } from './core/auth/api';
40
- export type { SpaceTokenAdapters, SpaceTokenApi, SpaceTokenContext, SpaceTokenOutcome, SpaceTokenRecord, SpaceTokenSummary } from './core/auth/spaceTokens';
41
- export type { AuthFailure, RefreshTokenPayload, SpaceScope, SpaceTokenOptions, SpaceTokenPayload, TokenConfig, TokenScope, Tokens, UserTokenPayload, VerifyResult, WidgetTokenPayload } from './core/auth/tokens';