@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.
- package/CHANGELOG.md +1170 -0
- package/README.md +100 -7
- package/dist/actions.d.ts +6 -2
- package/dist/actions.js +5 -2
- package/dist/adapters/cloudAdapters.js +4 -3
- package/dist/adapters/jsonAdapters.js +28 -6
- package/dist/adapters/jsonAdapters.test.d.ts +1 -0
- package/dist/auth.d.ts +7 -4
- package/dist/auth.js +8 -6
- package/dist/core/auth/api.d.ts +29 -1
- package/dist/core/auth/api.js +47 -13
- package/dist/core/auth/createAuth.d.ts +4 -0
- package/dist/core/auth/createAuth.js +3 -3
- package/dist/core/auth/credentials.d.ts +3 -0
- package/dist/core/auth/credentials.js +1 -1
- package/dist/core/auth/csrf.d.ts +25 -1
- package/dist/core/auth/csrf.js +29 -4
- package/dist/core/auth/renewal.d.ts +26 -0
- package/dist/core/auth/renewal.js +24 -0
- package/dist/core/auth/routes.js +8 -6
- package/dist/core/auth/session.d.ts +45 -0
- package/dist/core/auth/session.js +47 -1
- package/dist/core/auth/sessionActivity.d.ts +11 -0
- package/dist/core/auth/sessionActivity.js +14 -0
- package/dist/core/auth/throttle.d.ts +15 -0
- package/dist/core/auth/throttle.js +29 -1
- package/dist/core/auth/totp.d.ts +9 -1
- package/dist/core/auth/totp.js +11 -6
- package/dist/core/createServer.actions.test.d.ts +1 -0
- package/dist/core/createServer.d.ts +14 -1
- package/dist/core/createServer.functions.test.d.ts +1 -0
- package/dist/core/createServer.js +22 -12
- package/dist/core/fontStore.js +1 -1
- package/dist/core/handlers/authRouteHandlers.d.ts +1 -1
- package/dist/core/handlers/authRouteHandlers.js +57 -21
- package/dist/core/handlers/csrfMiddleware.d.ts +23 -0
- package/dist/core/handlers/csrfMiddleware.js +31 -7
- package/dist/core/handlers/csrfMiddleware.test.d.ts +1 -0
- package/dist/core/handlers/oauthRouteHandlers.js +5 -3
- package/dist/core/handlers/socialRouteHandlers.d.ts +1 -1
- package/dist/core/handlers/socialRouteHandlers.js +2 -1
- package/dist/core/http/dispatcher.d.ts +9 -1
- package/dist/core/http/dispatcher.js +38 -11
- package/dist/core/http/navigation.d.ts +5 -2
- package/dist/core/http/navigation.js +7 -4
- package/dist/core/http/socketResponse.d.ts +18 -0
- package/dist/core/http/socketResponse.js +59 -0
- package/dist/core/http/sse.d.ts +26 -0
- package/dist/core/http/sse.js +78 -0
- package/dist/core/http/stages/authRoutes.js +3 -1
- package/dist/core/http/stages/exchangeRoute.test.d.ts +1 -0
- package/dist/core/http/stages/middlewares.d.ts +1 -1
- package/dist/core/http/stages/middlewares.js +16 -10
- package/dist/core/http/stages/middlewares.test.d.ts +1 -0
- package/dist/core/http/stages/oauth.js +2 -2
- package/dist/core/http/stages/sessionRenewal.d.ts +16 -0
- package/dist/core/http/stages/sessionRenewal.js +81 -0
- package/dist/core/http/stages/sessionRenewal.test.d.ts +1 -0
- package/dist/core/http/stages/signInRoute.d.ts +2 -0
- package/dist/core/http/stages/signInRoute.js +139 -0
- package/dist/core/http/stages/signInRoute.test.d.ts +1 -0
- package/dist/core/http/types.d.ts +9 -0
- package/dist/core/http/webExchange.d.ts +18 -0
- package/dist/core/http/webExchange.js +53 -0
- package/dist/core/oauth/authorize.js +37 -13
- package/dist/core/oauth/consentPage.js +11 -0
- package/dist/core/oauth/issueContext.d.ts +14 -0
- package/dist/core/oauth/issueContext.js +32 -0
- package/dist/core/oauth/records.d.ts +7 -0
- package/dist/core/oauth/register.d.ts +2 -0
- package/dist/core/oauth/register.js +32 -11
- package/dist/core/oauth/register.test.d.ts +1 -0
- package/dist/core/oauth/token.js +21 -6
- package/dist/core/oauth/token.test.d.ts +1 -0
- package/dist/core/requestParser.d.ts +4 -0
- package/dist/core/requestParser.js +14 -7
- package/dist/core/sdkAssets.js +1 -1
- package/dist/core/server/baseServer.d.ts +10 -0
- package/dist/core/server/baseServer.js +42 -11
- package/dist/core/server/closeOnSignals.js +4 -3
- package/dist/core/server/drain.d.ts +18 -0
- package/dist/core/server/drain.js +62 -0
- package/dist/core/server/drain.test.d.ts +1 -0
- package/dist/core/server/fleet/channel.d.ts +103 -0
- package/dist/core/server/fleet/channel.js +191 -0
- package/dist/core/server/fleet/channel.test.d.ts +1 -0
- package/dist/core/server/fleet/fixtures/fleetServer.d.ts +1 -0
- package/dist/core/server/fleet/fleet.integration.test.d.ts +1 -0
- package/dist/core/server/fleet/link.d.ts +23 -0
- package/dist/core/server/fleet/link.js +70 -0
- package/dist/core/server/fleet/relay.d.ts +11 -0
- package/dist/core/server/fleet/relay.js +104 -0
- package/dist/core/server/fleet/relay.test.d.ts +1 -0
- package/dist/core/server/fleet/role.d.ts +46 -0
- package/dist/core/server/fleet/role.js +59 -0
- package/dist/core/server/fleet/role.test.d.ts +1 -0
- package/dist/core/server/fleet/stores.d.ts +7 -0
- package/dist/core/server/fleet/stores.js +19 -0
- package/dist/core/server/fleet/supervisor.d.ts +26 -0
- package/dist/core/server/fleet/supervisor.js +108 -0
- package/dist/core/server/fleet/supervisor.test.d.ts +1 -0
- package/dist/core/server/pageServer.js +34 -5
- package/dist/core/services/action.js +10 -2
- package/dist/core/services/functionRoutes.d.ts +9 -0
- package/dist/core/services/functionRoutes.js +47 -0
- package/dist/core/services/realtime.d.ts +8 -0
- package/dist/core/services/realtime.js +57 -0
- package/dist/core/services/registry.js +6 -2
- package/dist/core/staticFiles.js +12 -4
- package/dist/core/staticFiles.test.d.ts +1 -0
- package/dist/core/transports.d.ts +13 -3
- package/dist/core/transports.js +14 -5
- package/dist/functions-api.d.ts +281 -0
- package/dist/functions.d.ts +19 -0
- package/dist/functions.js +5 -0
- package/dist/functionsRunner.d.ts +15 -0
- package/dist/functionsRunner.js +6 -0
- package/dist/handlers.d.ts +2 -2
- package/dist/handlers.js +2 -2
- package/dist/helpers/atomicFile.d.ts +10 -0
- package/dist/helpers/atomicFile.js +33 -0
- package/dist/helpers/atomicFile.test.d.ts +1 -0
- package/dist/helpers/buildResponseHelpers.js +35 -11
- package/dist/helpers/buildServerInfo.js +4 -2
- package/dist/helpers/buildServerInfo.test.d.ts +1 -0
- package/dist/helpers/cache/CompressedFileCache.d.ts +18 -0
- package/dist/helpers/cache/CompressedFileCache.js +44 -0
- package/dist/helpers/cache/CompressedFileCache.test.d.ts +1 -0
- package/dist/helpers/cache/cacheManager.d.ts +1 -1
- package/dist/helpers/cache/cacheManager.js +2 -1
- package/dist/helpers/cache/cacheManager.test.d.ts +1 -0
- package/dist/helpers/cache/index.d.ts +1 -1
- package/dist/helpers/cache/keys.d.ts +15 -1
- package/dist/helpers/cache/keys.js +47 -5
- package/dist/helpers/cache/serverCaches.d.ts +7 -1
- package/dist/helpers/compress.d.ts +3 -1
- package/dist/helpers/compress.js +11 -3
- package/dist/helpers/hydrationPayload.d.ts +11 -0
- package/dist/helpers/hydrationPayload.js +51 -0
- package/dist/helpers/hydrationPayload.test.d.ts +1 -0
- package/dist/helpers/metrics.d.ts +1 -1
- package/dist/helpers/metrics.js +3 -2
- package/dist/helpers/outboundGuard.d.ts +14 -6
- package/dist/helpers/outboundGuard.js +132 -8
- package/dist/helpers/paintedCookie.d.ts +8 -0
- package/dist/helpers/paintedCookie.js +13 -0
- package/dist/helpers/reportReactBuild.d.ts +9 -0
- package/dist/helpers/reportReactBuild.js +18 -0
- package/dist/helpers/reportReactBuild.test.d.ts +1 -0
- package/dist/helpers/serverLog.d.ts +25 -1
- package/dist/helpers/serverLog.js +68 -3
- package/dist/helpers/serverLog.test.d.ts +1 -0
- package/dist/helpers/wsFrame.d.ts +3 -0
- package/dist/helpers/wsFrame.js +5 -0
- package/dist/index.d.ts +6 -1
- package/dist/index.js +5 -2
- package/dist/kernel.d.ts +2 -1
- package/dist/kernel.js +3 -2
- package/dist/modules/actions/connectorWrite.js +2 -1
- package/dist/modules/actions/index.d.ts +29 -10
- package/dist/modules/actions/index.js +43 -6
- package/dist/modules/actions/jobs/failureStreak.d.ts +17 -0
- package/dist/modules/actions/jobs/failureStreak.js +47 -0
- package/dist/modules/actions/jobs/failureStreak.test.d.ts +1 -0
- package/dist/modules/actions/jobs/index.d.ts +2 -1
- package/dist/modules/actions/jobs/index.js +5 -3
- package/dist/modules/actions/jobs/memoryQueue.d.ts +3 -0
- package/dist/modules/actions/jobs/memoryQueue.js +17 -1
- package/dist/modules/actions/jobs/scheduler.d.ts +2 -0
- package/dist/modules/actions/jobs/scheduler.js +12 -7
- package/dist/modules/actions/jobs/worker.d.ts +3 -1
- package/dist/modules/actions/jobs/worker.js +9 -4
- package/dist/modules/actions/moduleFor.js +5 -2
- package/dist/modules/actions/runtime/errors.d.ts +12 -0
- package/dist/modules/actions/runtime/errors.js +16 -1
- package/dist/modules/actions/runtime/kvChange.d.ts +27 -0
- package/dist/modules/actions/runtime/kvChange.js +23 -0
- package/dist/modules/actions/runtime/kvList.d.ts +51 -0
- package/dist/modules/actions/runtime/kvList.js +52 -0
- package/dist/modules/actions/runtime/kvStore.d.ts +8 -0
- package/dist/modules/actions/runtime/kvStore.js +46 -20
- package/dist/modules/actions/runtime/memoryKv.d.ts +3 -0
- package/dist/modules/actions/runtime/memoryKv.js +19 -1
- package/dist/modules/actions/runtime/namespaceKv.d.ts +4 -6
- package/dist/modules/actions/runtime/namespaceKv.js +15 -3
- package/dist/modules/actions/runtime/namespaceKv.test.d.ts +1 -0
- package/dist/modules/actions/runtime/precheck.js +4 -8
- package/dist/modules/actions/runtime/rateLimit.d.ts +19 -0
- package/dist/modules/actions/runtime/rateLimit.js +19 -0
- package/dist/modules/actions/runtime/redisKv.d.ts +27 -0
- package/dist/modules/actions/runtime/redisKv.integration.test.d.ts +1 -0
- package/dist/modules/actions/runtime/redisKv.js +46 -0
- package/dist/modules/actions/runtime/report.js +2 -1
- package/dist/modules/actions/runtime/runAction.d.ts +10 -2
- package/dist/modules/actions/runtime/runAction.js +52 -116
- package/dist/modules/actions/runtime/runLogger.d.ts +5 -0
- package/dist/modules/actions/runtime/runLogger.js +8 -2
- package/dist/modules/actions/runtime/signing.d.ts +20 -0
- package/dist/modules/actions/runtime/signing.js +25 -0
- package/dist/modules/actions/runtime/signing.test.d.ts +1 -0
- package/dist/modules/actions/runtime/taskContext.d.ts +33 -0
- package/dist/modules/actions/runtime/taskContext.js +124 -0
- package/dist/modules/actions/tasks/builtins.js +5 -1
- package/dist/modules/actions/tasks/flow.js +81 -10
- package/dist/modules/actions/tasks/helpers.js +2 -2
- package/dist/modules/actions/tasks/http.js +2 -3
- package/dist/modules/actions/tasks/kv.js +39 -0
- package/dist/modules/actions/tasks/list.d.ts +2 -0
- package/dist/modules/actions/tasks/list.js +145 -0
- package/dist/modules/actions/tasks/realtime.d.ts +2 -0
- package/dist/modules/actions/tasks/realtime.js +104 -0
- package/dist/modules/actions/tasks/registry.d.ts +10 -1
- package/dist/modules/actions/tasks/registry.js +17 -6
- package/dist/modules/actions/transport/callHandler.js +5 -2
- package/dist/modules/actions/transport/catalogHandler.d.ts +5 -2
- package/dist/modules/actions/transport/catalogHandler.js +3 -2
- package/dist/modules/actions/transport/stream.d.ts +4 -5
- package/dist/modules/actions/transport/stream.js +12 -76
- package/dist/modules/actions/transport/webhookHandler.js +4 -3
- package/dist/modules/actions/types.d.ts +86 -3
- package/dist/modules/connectors/engine.js +3 -5
- package/dist/modules/functions/build.d.ts +22 -0
- package/dist/modules/functions/build.js +122 -0
- package/dist/modules/functions/build.test.d.ts +1 -0
- package/dist/modules/functions/capabilities.d.ts +22 -0
- package/dist/modules/functions/capabilities.js +228 -0
- package/dist/modules/functions/config.d.ts +34 -0
- package/dist/modules/functions/config.js +24 -0
- package/dist/modules/functions/context.d.ts +17 -0
- package/dist/modules/functions/context.js +88 -0
- package/dist/modules/functions/contract.d.ts +121 -0
- package/dist/modules/functions/contract.js +9 -0
- package/dist/modules/functions/driver.d.ts +36 -0
- package/dist/modules/functions/driver.js +150 -0
- package/dist/modules/functions/load.d.ts +15 -0
- package/dist/modules/functions/load.js +45 -0
- package/dist/modules/functions/load.test.d.ts +1 -0
- package/dist/modules/functions/local.d.ts +29 -0
- package/dist/modules/functions/local.js +61 -0
- package/dist/modules/functions/local.test.d.ts +1 -0
- package/dist/modules/functions/manifest.d.ts +24 -0
- package/dist/modules/functions/manifest.js +163 -0
- package/dist/modules/functions/manifest.test.d.ts +1 -0
- package/dist/modules/functions/native.d.ts +8 -0
- package/dist/modules/functions/native.js +21 -0
- package/dist/modules/functions/native.test.d.ts +1 -0
- package/dist/modules/functions/protocol.d.ts +216 -0
- package/dist/modules/functions/protocol.js +18 -0
- package/dist/modules/functions/routes.d.ts +36 -0
- package/dist/modules/functions/routes.js +181 -0
- package/dist/modules/functions/routes.test.d.ts +1 -0
- package/dist/modules/functions/runner/messages.d.ts +5 -0
- package/dist/modules/functions/runner/messages.js +188 -0
- package/dist/modules/functions/runner/remote.d.ts +19 -0
- package/dist/modules/functions/runner/remote.js +116 -0
- package/dist/modules/functions/runner/remote.test.d.ts +1 -0
- package/dist/modules/functions/runner/service.d.ts +32 -0
- package/dist/modules/functions/runner/service.js +209 -0
- package/dist/modules/functions/sandbox/guest.d.ts +45 -0
- package/dist/modules/functions/sandbox/guest.js +660 -0
- package/dist/modules/functions/sandbox/isolate.d.ts +37 -0
- package/dist/modules/functions/sandbox/isolate.js +347 -0
- package/dist/modules/functions/sandbox/isolate.test.d.ts +1 -0
- package/dist/modules/functions/sandbox/prelude.d.ts +2 -0
- package/dist/modules/functions/sandbox/prelude.js +49 -0
- package/dist/modules/functions/space.d.ts +40 -0
- package/dist/modules/functions/space.js +162 -0
- package/dist/modules/functions/testing/tasksOf.d.ts +4 -0
- package/dist/modules/functions/tryEntry.d.ts +9 -0
- package/dist/modules/functions/tryEntry.js +49 -0
- package/dist/modules/mongo/kv.js +31 -0
- package/dist/modules/mysql/accounts.js +19 -9
- package/dist/modules/mysql/index.d.ts +2 -1
- package/dist/modules/mysql/jobs/index.d.ts +1 -1
- package/dist/modules/mysql/jobs/kv.js +30 -0
- package/dist/modules/mysql/jobs/schema.d.ts +9 -0
- package/dist/modules/mysql/jobs/schema.js +21 -4
- package/dist/modules/mysql/schema.js +25 -0
- package/dist/modules/mysql/sessions.d.ts +1 -11
- package/dist/modules/mysql/sessions.js +6 -1
- package/dist/modules/realtime/declarations.d.ts +11 -0
- package/dist/modules/realtime/declarations.js +26 -0
- package/dist/modules/realtime/grants.d.ts +23 -0
- package/dist/modules/realtime/grants.js +61 -0
- package/dist/modules/realtime/handlers.d.ts +74 -0
- package/dist/modules/realtime/handlers.js +224 -0
- package/dist/modules/realtime/hub.d.ts +62 -0
- package/dist/modules/realtime/hub.js +141 -0
- package/dist/modules/realtime/index.d.ts +51 -0
- package/dist/modules/realtime/index.js +62 -0
- package/dist/modules/realtime/memoryPubSub.d.ts +10 -0
- package/dist/modules/realtime/memoryPubSub.js +43 -0
- package/dist/modules/realtime/realtime.test.d.ts +1 -0
- package/dist/modules/realtime/redisPubSub.d.ts +24 -0
- package/dist/modules/realtime/redisPubSub.js +36 -0
- package/dist/modules/realtime/redisPubSub.test.d.ts +1 -0
- package/dist/modules/realtime/socket.d.ts +25 -0
- package/dist/modules/realtime/socket.js +122 -0
- package/dist/modules/realtime/socket.test.d.ts +1 -0
- package/dist/modules/rsc/handler.d.ts +16 -0
- package/dist/modules/rsc/handler.js +17 -10
- package/dist/modules/rsc/handler.test.d.ts +1 -0
- package/dist/modules/rsc/resolveRscData.js +2 -1
- package/dist/modules/runtime/bundle.d.ts +24 -0
- package/dist/modules/runtime/bundle.js +102 -0
- package/dist/modules/runtime/contract.d.ts +37 -0
- package/dist/modules/runtime/contract.js +21 -0
- package/dist/modules/runtime/entry.test.d.ts +1 -0
- package/dist/modules/runtime/host.d.ts +38 -0
- package/dist/modules/runtime/host.js +68 -0
- package/dist/modules/runtime/inside.d.ts +15 -0
- package/dist/modules/runtime/inside.js +47 -0
- package/dist/modules/runtime/inside.test.d.ts +1 -0
- package/dist/modules/runtime/runner.d.ts +11 -0
- package/dist/modules/runtime/runner.js +38 -0
- package/dist/modules/runtime/runtime.test.d.ts +1 -0
- package/dist/modules/runtime/stages.d.ts +50 -0
- package/dist/modules/runtime/stages.js +117 -0
- package/dist/modules/ssr/Component.d.ts +3 -1
- package/dist/modules/ssr/Component.js +2 -1
- package/dist/modules/ssr/handler.js +10 -2
- package/dist/modules/ssr/loadPluginComponents.js +2 -1
- package/dist/modules/ssr/prepareRender.js +39 -10
- package/dist/modules/ssr/preview.d.ts +3 -0
- package/dist/modules/ssr/preview.js +17 -7
- package/dist/modules/ssr/redirect.test.d.ts +1 -0
- package/dist/modules/ssr/registerExternalPlugins.d.ts +6 -1
- package/dist/modules/ssr/registerExternalPlugins.js +19 -16
- package/dist/modules/ssr/registerExternalPlugins.test.d.ts +1 -0
- package/dist/modules/ssr/reportMissingPlugins.d.ts +9 -0
- package/dist/modules/ssr/reportMissingPlugins.js +24 -0
- package/dist/modules/ssr/reportMissingPlugins.test.d.ts +1 -0
- package/dist/modules/ssr/streamBody.d.ts +2 -2
- package/dist/modules/ssr/streamBody.js +4 -1
- package/dist/modules/ssr/template.js +1 -1
- package/dist/modules/ssr/views/template.ejs +8 -5
- package/dist/mysql.d.ts +1 -1
- package/dist/mysql.js +2 -2
- package/dist/oauth.js +2 -2
- package/dist/plugins/compile.js +9 -4
- package/dist/plugins/copy.js +3 -3
- package/dist/plugins/manager.d.ts +35 -3
- package/dist/plugins/manager.js +109 -38
- package/dist/runtime.d.ts +15 -0
- package/dist/runtime.js +7 -0
- package/package.json +39 -8
- package/skills/plitzi-authoring/SKILL.md +98 -14
- package/skills/plitzi-authoring/reference/accessibility.md +111 -0
- package/skills/plitzi-authoring/reference/authoring-errors.md +70 -0
- package/skills/plitzi-authoring/reference/data-and-visibility.md +84 -18
- package/skills/plitzi-authoring/reference/elements-and-styles.md +61 -7
- package/skills/plitzi-authoring/reference/flows.md +108 -17
- package/skills/plitzi-authoring/reference/lists.md +74 -0
- package/skills/plitzi-authoring/reference/performance.md +67 -0
- package/skills/plitzi-authoring/reference/plugins.md +167 -0
- package/skills/plitzi-authoring/reference/review-checklist.md +19 -2
- package/skills/plitzi-authoring/reference/templates.md +67 -27
- package/skills/plitzi-authoring/reference/testing.md +72 -5
- package/skills/plitzi-authoring/reference/validation.md +73 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { ActionRefusal } from "../actions/runtime/errors.js";
|
|
2
|
+
import { changeKv } from "../actions/runtime/kvChange.js";
|
|
3
|
+
import { requestFromWire, responseOf, wireResponseFrom, wireResponseOf } from "../functions/capabilities.js";
|
|
4
|
+
import { FunctionFailure } from "../functions/protocol.js";
|
|
5
|
+
import { createFunctionsDriver, describeFunctions } from "../functions/driver.js";
|
|
6
|
+
//#region src/modules/runtime/runner.ts
|
|
7
|
+
/** A refusal, however it was made: the platform's class, or a bundle's own copy of it — known by its name. */
|
|
8
|
+
var isRefusal = (error) => error instanceof Error && error.name === "ActionRefusal";
|
|
9
|
+
/**
|
|
10
|
+
* A runtime's functions as a runner: the same protocol as the sandbox's, answered by code loaded in this process. The
|
|
11
|
+
* driver is the sandbox's own (`createFunctionsDriver`), so a task behaves the same in both — its `ctx` is calls to the
|
|
12
|
+
* platform, `ctx.kv.change` the same loop, a refusal the same answer. What it does not share is the isolate: there are
|
|
13
|
+
* no limits here but the platform's clock, since this process is the space's alone.
|
|
14
|
+
*
|
|
15
|
+
* The bundle a request names is not asked for: the code is the one this runtime was started with.
|
|
16
|
+
*/
|
|
17
|
+
var createRuntimeRunner = (definition = {}) => ({
|
|
18
|
+
describe: () => Promise.resolve(describeFunctions(definition)),
|
|
19
|
+
invoke: async ({ invocation, answer, signal }) => {
|
|
20
|
+
const driver = createFunctionsDriver({
|
|
21
|
+
call: answer,
|
|
22
|
+
signal,
|
|
23
|
+
responseOf: (wire) => responseOf(wireResponseFrom(wire)),
|
|
24
|
+
requestOf: requestFromWire,
|
|
25
|
+
wireOfResponse: async (response) => response instanceof Response ? wireResponseOf(response) : void 0,
|
|
26
|
+
changeKv,
|
|
27
|
+
refusal: (message) => new ActionRefusal(message)
|
|
28
|
+
});
|
|
29
|
+
try {
|
|
30
|
+
return await driver.invoke(definition, invocation);
|
|
31
|
+
} catch (error) {
|
|
32
|
+
if (isRefusal(error)) throw new FunctionFailure("refused", error.message);
|
|
33
|
+
throw error;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
//#endregion
|
|
38
|
+
export { createRuntimeRunner };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { SpaceRuntime, SpaceRuntimeContext, SpaceRuntimeEndpoint } from './contract';
|
|
2
|
+
import { SSRContext, Stage } from '../../core/http/types';
|
|
3
|
+
import { FunctionsDefinition } from '../functions/contract';
|
|
4
|
+
/** A runtime's endpoints answered in this process — self-hosting — exactly as the platform forwards them to its own. */
|
|
5
|
+
export declare const runtimeEndpointsStage: (endpoints: Record<string, SpaceRuntimeEndpoint>) => Stage<SSRContext>;
|
|
6
|
+
/** A runtime on a server of its own: what `createServer` is handed of it, and how to stop it. */
|
|
7
|
+
export type ServedRuntime = {
|
|
8
|
+
/** Its tasks and routes, for `functions.native`. */
|
|
9
|
+
native: FunctionsDefinition[];
|
|
10
|
+
/** Its endpoints, for `preAuth` — they gate themselves, as the platform's forwarding does. */
|
|
11
|
+
stage: Stage<SSRContext>;
|
|
12
|
+
close: () => Promise<void>;
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* A space runtime served by a self-hosted server instead of the platform: started here, its functions loaded natively
|
|
16
|
+
* and its endpoints answered by a stage — the same module the platform runs as a runtime of the space.
|
|
17
|
+
*/
|
|
18
|
+
export declare const serveRuntime: (runtime: SpaceRuntime, context: SpaceRuntimeContext) => Promise<ServedRuntime>;
|
|
19
|
+
/** Where a space's runtime is, for the page server to forward its endpoints to. */
|
|
20
|
+
export type RuntimeTarget = {
|
|
21
|
+
/** Its base URL — `http://10.0.4.7:8791`. */
|
|
22
|
+
url: string;
|
|
23
|
+
/** What it is presented, as `Authorization: Bearer <secret>`. */
|
|
24
|
+
secret: string;
|
|
25
|
+
/** The paths it answers — what it described when it started. */
|
|
26
|
+
endpoints: readonly string[];
|
|
27
|
+
};
|
|
28
|
+
export type RuntimeProxyConfig = {
|
|
29
|
+
/** The runtime serving a space and environment — or none, for a space the platform serves alone. */
|
|
30
|
+
lookup: (space: {
|
|
31
|
+
spaceId: number;
|
|
32
|
+
environment: string;
|
|
33
|
+
}) => Promise<RuntimeTarget | undefined>;
|
|
34
|
+
/**
|
|
35
|
+
* Told each time a request is forwarded to a space's runtime — not for every request of the space, most of which are
|
|
36
|
+
* its pages: what counts as a runtime being used, for a deployment that stops the ones nobody uses.
|
|
37
|
+
*/
|
|
38
|
+
onForward?: (space: {
|
|
39
|
+
spaceId: number;
|
|
40
|
+
environment: string;
|
|
41
|
+
endpoint: string;
|
|
42
|
+
}) => void;
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* The page server forwarding a space's endpoints to its runtime: the request as it came, streamed both ways — an agent's
|
|
46
|
+
* event stream included — without the visitor's cookies or `Authorization`, and with who asked in `X-Forwarded-*`.
|
|
47
|
+
*
|
|
48
|
+
* A data stage: after the auth chain, so the space is known, and before the space's `/api/` routes and its pages.
|
|
49
|
+
*/
|
|
50
|
+
export declare const createRuntimeProxyStage: ({ lookup, onForward }: RuntimeProxyConfig) => Stage<SSRContext>;
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { clientIp, requestOrigin } from "../../core/requestParser.js";
|
|
2
|
+
import { endpointFor, endpointProblem } from "./contract.js";
|
|
3
|
+
import { webRequestOf, writeWebResponse } from "../../core/http/webExchange.js";
|
|
4
|
+
import { PLATFORM_HEADERS } from "./host.js";
|
|
5
|
+
import http from "node:http";
|
|
6
|
+
import https from "node:https";
|
|
7
|
+
//#region src/modules/runtime/stages.ts
|
|
8
|
+
var originOf = (ctx) => requestOrigin(ctx.req) || `${ctx.req.protocol}://${ctx.req.hostname}`;
|
|
9
|
+
/** A runtime's endpoints answered in this process — self-hosting — exactly as the platform forwards them to its own. */
|
|
10
|
+
var runtimeEndpointsStage = (endpoints) => {
|
|
11
|
+
const paths = Object.keys(endpoints);
|
|
12
|
+
const problems = paths.flatMap((path) => endpointProblem(path) ?? []);
|
|
13
|
+
if (problems.length > 0) throw new Error(problems.join("; "));
|
|
14
|
+
return async (ctx) => {
|
|
15
|
+
const endpoint = endpointFor(paths, ctx.req.path);
|
|
16
|
+
const answer = endpoint ? endpoints[endpoint] : void 0;
|
|
17
|
+
if (!endpoint || !answer) return false;
|
|
18
|
+
ctx.operation = `endpoint ${endpoint}`;
|
|
19
|
+
const request = await webRequestOf(ctx.raw, `${originOf(ctx)}${ctx.raw.url ?? ctx.req.path}`, PLATFORM_HEADERS);
|
|
20
|
+
await writeWebResponse(ctx.rawRes, await answer(request), ctx.signal);
|
|
21
|
+
return true;
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* A space runtime served by a self-hosted server instead of the platform: started here, its functions loaded natively
|
|
26
|
+
* and its endpoints answered by a stage — the same module the platform runs as a runtime of the space.
|
|
27
|
+
*/
|
|
28
|
+
var serveRuntime = async (runtime, context) => {
|
|
29
|
+
const parts = await runtime.start(context);
|
|
30
|
+
return {
|
|
31
|
+
native: parts.functions ? [parts.functions] : [],
|
|
32
|
+
stage: runtimeEndpointsStage(parts.endpoints ?? {}),
|
|
33
|
+
close: async () => {
|
|
34
|
+
await parts.close?.();
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
};
|
|
38
|
+
var HOP_BY_HOP = [
|
|
39
|
+
"connection",
|
|
40
|
+
"keep-alive",
|
|
41
|
+
"transfer-encoding",
|
|
42
|
+
"upgrade"
|
|
43
|
+
];
|
|
44
|
+
/** The query parameter a platform credential rides in (`credentials.ts`): never forwarded either. */
|
|
45
|
+
var PLATFORM_QUERY_CREDENTIAL = "access-token";
|
|
46
|
+
/** Never forwarded to a runtime: one hop's, and the platform's — the visitor's session is not the runtime's to hold. */
|
|
47
|
+
var NOT_FORWARDED = /* @__PURE__ */ new Set([
|
|
48
|
+
...HOP_BY_HOP,
|
|
49
|
+
...PLATFORM_HEADERS,
|
|
50
|
+
"host"
|
|
51
|
+
]);
|
|
52
|
+
/** Never answered from one: the host's cookies are the platform's, as a function route's are. */
|
|
53
|
+
var NOT_ANSWERED = /* @__PURE__ */ new Set([...HOP_BY_HOP, "set-cookie"]);
|
|
54
|
+
/**
|
|
55
|
+
* The page server forwarding a space's endpoints to its runtime: the request as it came, streamed both ways — an agent's
|
|
56
|
+
* event stream included — without the visitor's cookies or `Authorization`, and with who asked in `X-Forwarded-*`.
|
|
57
|
+
*
|
|
58
|
+
* A data stage: after the auth chain, so the space is known, and before the space's `/api/` routes and its pages.
|
|
59
|
+
*/
|
|
60
|
+
var createRuntimeProxyStage = ({ lookup, onForward }) => async (ctx) => {
|
|
61
|
+
const { spaceId, environment = "main" } = ctx.req.ctx.spaceDeployment ?? {};
|
|
62
|
+
if (typeof spaceId !== "number") return false;
|
|
63
|
+
const target = await lookup({
|
|
64
|
+
spaceId,
|
|
65
|
+
environment
|
|
66
|
+
});
|
|
67
|
+
const endpoint = target ? endpointFor(target.endpoints, ctx.req.path) : void 0;
|
|
68
|
+
if (!target || !endpoint) return false;
|
|
69
|
+
ctx.operation = `runtime ${endpoint}`;
|
|
70
|
+
onForward?.({
|
|
71
|
+
spaceId,
|
|
72
|
+
environment,
|
|
73
|
+
endpoint
|
|
74
|
+
});
|
|
75
|
+
const headers = {};
|
|
76
|
+
Object.entries(ctx.raw.headers).forEach(([name, value]) => {
|
|
77
|
+
if (!name.startsWith(":") && !NOT_FORWARDED.has(name) && value !== void 0) headers[name] = value;
|
|
78
|
+
});
|
|
79
|
+
headers.authorization = `Bearer ${target.secret}`;
|
|
80
|
+
headers["x-forwarded-host"] = ctx.req.hostname;
|
|
81
|
+
headers["x-forwarded-proto"] = ctx.req.protocol;
|
|
82
|
+
headers["x-forwarded-for"] = clientIp(ctx.raw, ctx.req);
|
|
83
|
+
const url = new URL(ctx.raw.url ?? ctx.req.path, target.url);
|
|
84
|
+
url.searchParams.delete(PLATFORM_QUERY_CREDENTIAL);
|
|
85
|
+
await new Promise((resolve) => {
|
|
86
|
+
const upstream = (url.protocol === "https:" ? https : http).request(url, {
|
|
87
|
+
method: ctx.raw.method,
|
|
88
|
+
headers
|
|
89
|
+
});
|
|
90
|
+
const unreachable = () => {
|
|
91
|
+
if (!ctx.rawRes.headersSent) {
|
|
92
|
+
ctx.rawRes.writeHead(502, { "content-type": "application/json" });
|
|
93
|
+
ctx.rawRes.end(JSON.stringify({ error: "This space’s runtime is not answering" }));
|
|
94
|
+
} else ctx.rawRes.end();
|
|
95
|
+
resolve();
|
|
96
|
+
};
|
|
97
|
+
ctx.signal.addEventListener("abort", () => upstream.destroy(), { once: true });
|
|
98
|
+
upstream.on("error", unreachable);
|
|
99
|
+
upstream.on("response", (answer) => {
|
|
100
|
+
const answered = {};
|
|
101
|
+
Object.entries(answer.headers).forEach(([name, value]) => {
|
|
102
|
+
if (!NOT_ANSWERED.has(name) && value !== void 0) answered[name] = value;
|
|
103
|
+
});
|
|
104
|
+
ctx.rawRes.writeHead(answer.statusCode ?? 502, answered);
|
|
105
|
+
answer.on("data", (chunk) => ctx.rawRes.write(chunk));
|
|
106
|
+
answer.on("end", () => {
|
|
107
|
+
ctx.rawRes.end();
|
|
108
|
+
resolve();
|
|
109
|
+
});
|
|
110
|
+
answer.on("error", unreachable);
|
|
111
|
+
});
|
|
112
|
+
ctx.raw.pipe(upstream);
|
|
113
|
+
});
|
|
114
|
+
return true;
|
|
115
|
+
};
|
|
116
|
+
//#endregion
|
|
117
|
+
export { createRuntimeProxyStage, runtimeEndpointsStage, serveRuntime };
|
|
@@ -13,6 +13,8 @@ export type ComponentProps = {
|
|
|
13
13
|
overQuota?: boolean;
|
|
14
14
|
/** The theme this document was rendered with, from the visitor's cookie. See `prepareRender`. */
|
|
15
15
|
theme?: Theme;
|
|
16
|
+
/** The kept state the first paint depends on (`settings.paintedState`), from the visitor's cookie. */
|
|
17
|
+
state?: Record<string, unknown>;
|
|
16
18
|
};
|
|
17
|
-
declare const Component: ({ server, renderMode, previewMode, offlineData, environment, plugins, ssrResult, sdkDevToolsStylePath, debugMode, overQuota, theme }: ComponentProps) => import('react').JSX.Element;
|
|
19
|
+
declare const Component: ({ server, renderMode, previewMode, offlineData, environment, plugins, ssrResult, sdkDevToolsStylePath, debugMode, overQuota, theme, state }: ComponentProps) => import('react').JSX.Element;
|
|
18
20
|
export default Component;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import PlitziSdk from "@plitzi/plitzi-sdk";
|
|
2
2
|
import { jsx } from "react/jsx-runtime";
|
|
3
3
|
//#region src/modules/ssr/Component.tsx
|
|
4
|
-
var Component = ({ server, renderMode = "raw", previewMode = true, offlineData, environment = "main", plugins, ssrResult, sdkDevToolsStylePath, debugMode = false, overQuota, theme }) => {
|
|
4
|
+
var Component = ({ server, renderMode = "raw", previewMode = true, offlineData, environment = "main", plugins, ssrResult, sdkDevToolsStylePath, debugMode = false, overQuota, theme, state }) => {
|
|
5
5
|
const serverWithResult = {
|
|
6
6
|
...server,
|
|
7
7
|
ssr: {
|
|
@@ -20,6 +20,7 @@ var Component = ({ server, renderMode = "raw", previewMode = true, offlineData,
|
|
|
20
20
|
debugMode,
|
|
21
21
|
...overQuota === void 0 ? {} : { overQuota },
|
|
22
22
|
...theme === void 0 ? {} : { theme },
|
|
23
|
+
...state === void 0 ? {} : { state },
|
|
23
24
|
children: plugins && Object.keys(plugins).map((key) => /* @__PURE__ */ jsx(PlitziSdk.Plugin, {
|
|
24
25
|
renderType: key,
|
|
25
26
|
component: plugins[key].component,
|
|
@@ -46,7 +46,7 @@ var renderSSR = async (req, res, config, renderFn, pluginManager, caches) => {
|
|
|
46
46
|
res.setHeader("X-Cache", "HIT");
|
|
47
47
|
if (devMode) res.setHeader("Server-Timing", "html;desc=\"cache-hit\";dur=0");
|
|
48
48
|
await meterPage(req, config, spaceId, environment, revision, true);
|
|
49
|
-
res.send(cached);
|
|
49
|
+
res.send(cached.html, { compressed: cached.compressed });
|
|
50
50
|
return;
|
|
51
51
|
}
|
|
52
52
|
}
|
|
@@ -63,7 +63,15 @@ var renderSSR = async (req, res, config, renderFn, pluginManager, caches) => {
|
|
|
63
63
|
metrics.log(`${req.method} ${req.path}`);
|
|
64
64
|
}
|
|
65
65
|
if (applySSRResult(res, result)) return;
|
|
66
|
-
if (htmlCache && cacheKey && body !== void 0 && cacheable)
|
|
66
|
+
if (htmlCache && cacheKey && body !== void 0 && cacheable) {
|
|
67
|
+
const page = {
|
|
68
|
+
html: body,
|
|
69
|
+
compressed: {}
|
|
70
|
+
};
|
|
71
|
+
htmlCache.set(cacheKey, page);
|
|
72
|
+
res.send(body, { compressed: page.compressed });
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
67
75
|
res.send(body ?? "");
|
|
68
76
|
};
|
|
69
77
|
//#endregion
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { serverLog } from "../../helpers/serverLog.js";
|
|
1
2
|
import { pathToFileURL } from "node:url";
|
|
2
3
|
//#region src/modules/ssr/loadPluginComponents.ts
|
|
3
4
|
/** Module-level cache: the bundle's stamped identity → loaded React component. */
|
|
@@ -56,7 +57,7 @@ var loadPluginComponents = async (entries, inlineComponents) => {
|
|
|
56
57
|
component = mod.default ?? mod;
|
|
57
58
|
componentCache.set(cacheKey, component);
|
|
58
59
|
} catch (err) {
|
|
59
|
-
|
|
60
|
+
serverLog.warn("SSR", `Plugin "${e.keyName}" cannot be imported server-side, falling back to client rendering`, err);
|
|
60
61
|
failedImports.add(filePath);
|
|
61
62
|
return;
|
|
62
63
|
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { authorizesDebugging } from "../../helpers/debugAuthorization.js";
|
|
2
|
+
import { realtimeModuleFor } from "../realtime/index.js";
|
|
2
3
|
import { matchRscPage } from "../rsc/matchRscPage.js";
|
|
4
|
+
import { ssrPaintedCookieName } from "../../helpers/paintedCookie.js";
|
|
3
5
|
import { readCookie } from "../../helpers/readCookie.js";
|
|
4
6
|
import { buildOfflineDataCacheKey } from "../../helpers/cache/keys.js";
|
|
5
7
|
import { loadPluginComponents } from "./loadPluginComponents.js";
|
|
@@ -7,18 +9,30 @@ import "../../core/previewToken.js";
|
|
|
7
9
|
import { resolveActionEndpoint, resolveRscEndpoint } from "../../core/services/resolve.js";
|
|
8
10
|
import { createOfflineDataLoader } from "../../helpers/offlineDataLoader.js";
|
|
9
11
|
import { registerExternalPlugins } from "./registerExternalPlugins.js";
|
|
12
|
+
import { reportMissingPlugins } from "./reportMissingPlugins.js";
|
|
10
13
|
import { resolvePageSeo } from "./resolvePageSeo.js";
|
|
11
14
|
import { sdkAssetVersion } from "../../core/sdkAssets.js";
|
|
12
15
|
import { buildServerInfo } from "../../helpers/buildServerInfo.js";
|
|
13
|
-
import {
|
|
16
|
+
import { hydrationPayload } from "../../helpers/hydrationPayload.js";
|
|
14
17
|
import { resolveDebugMode } from "../../helpers/resolveDebugMode.js";
|
|
15
18
|
import { hasServerElements } from "@plitzi/sdk-shared/schema/serverElements";
|
|
16
19
|
import { debugCookieName } from "@plitzi/sdk-shared/devTools";
|
|
17
20
|
import { themeFromCookies } from "@plitzi/sdk-shared/theme";
|
|
21
|
+
import { paintedKeys, paintedStateFor } from "@plitzi/sdk-shared/state/paintedState";
|
|
18
22
|
import { fontUrlResolver, fontsToHead } from "@plitzi/sdk-shared/style";
|
|
19
23
|
//#region src/modules/ssr/prepareRender.tsx
|
|
20
24
|
/** Last resort only: used for a page that declares no SEO title and a deployment that supplies none either. */
|
|
21
25
|
var DEFAULT_TITLE = "Plitzi App";
|
|
26
|
+
/**
|
|
27
|
+
* The theme a space declares a first visit starts in, when it declares one other than `system`.
|
|
28
|
+
*
|
|
29
|
+
* `Partial`, because a style document written before themes existed has no `theme` at all, and a published space
|
|
30
|
+
* is rendered from whatever document it was published with.
|
|
31
|
+
*/
|
|
32
|
+
var declaredTheme = (style) => {
|
|
33
|
+
const declared = style?.theme?.default;
|
|
34
|
+
return declared && declared !== "system" ? declared : void 0;
|
|
35
|
+
};
|
|
22
36
|
var prepareRender = async (req, config, spaceId, environment, revision, pluginManager, offlineDataCache, metrics, offlineDataOverride) => {
|
|
23
37
|
const m = (name, fn) => metrics ? metrics.measure(name, fn) : Promise.resolve(fn());
|
|
24
38
|
const offlineCacheKey = environment !== "main" ? buildOfflineDataCacheKey(spaceId, environment, revision) : void 0;
|
|
@@ -44,7 +58,9 @@ var prepareRender = async (req, config, spaceId, environment, revision, pluginMa
|
|
|
44
58
|
const server = buildServerInfo(req, config, {
|
|
45
59
|
rscPath,
|
|
46
60
|
rscData,
|
|
47
|
-
actionPath: resolveActionEndpoint(config)
|
|
61
|
+
actionPath: resolveActionEndpoint(config),
|
|
62
|
+
realtimePath: realtimeModuleFor(config)?.path,
|
|
63
|
+
realtimeTransport: realtimeModuleFor(config)?.transport
|
|
48
64
|
});
|
|
49
65
|
if (offlineDataOverride === void 0 && !cachedOfflineStr && offlineCacheKey && offlineData !== void 0) offlineDataCache?.set(offlineCacheKey, JSON.stringify(offlineData));
|
|
50
66
|
const version = config.assetVersion ?? sdkAssetVersion();
|
|
@@ -92,22 +108,33 @@ var prepareRender = async (req, config, spaceId, environment, revision, pluginMa
|
|
|
92
108
|
* `{{ theme.resolved }}` or gate a rule on the scheme, and a client that started at `system` while the server
|
|
93
109
|
* rendered `dark` would hydrate different markup and throw away the tree.
|
|
94
110
|
*
|
|
95
|
-
* Absent — a first visit —
|
|
96
|
-
*
|
|
111
|
+
* Absent — a first visit — the space's own default applies (`style.theme.default`), painted by the server like a
|
|
112
|
+
* choice would be. A default of `system` stamps nothing and the stylesheet's media queries answer, which is exactly
|
|
113
|
+
* right for a space that did not pick.
|
|
114
|
+
*/
|
|
115
|
+
const theme = themeFromCookies(req.headers.cookie) ?? declaredTheme(offlineData?.style);
|
|
116
|
+
/**
|
|
117
|
+
* The kept state the first paint depends on, from the cookie the SDK writes the space's `settings.paintedState` to.
|
|
118
|
+
*
|
|
119
|
+
* The theme's reasoning, for the space's own state: web storage is the browser's alone, so what a visitor chose — the
|
|
120
|
+
* tool a toolbar shows, their name in an avatar — would reach the page only after hydration, and be swapped in over
|
|
121
|
+
* the defaults the server drew. Read here, the server draws with it, and the page starts from the same values: it
|
|
122
|
+
* travels as the SDK's `state`, the starting `runtime.state`, in the render and in the payload alike, or the client
|
|
123
|
+
* would hydrate other markup. Only the keys the space declares, and only with `keepState` on.
|
|
97
124
|
*/
|
|
98
|
-
const
|
|
99
|
-
const offlineDataStr =
|
|
100
|
-
offlineData,
|
|
125
|
+
const paintedState = schema?.settings.keepState ? paintedStateFor(req.headers.cookie, ssrPaintedCookieName(req.headers.host), paintedKeys(schema.settings)) : void 0;
|
|
126
|
+
const offlineDataStr = hydrationPayload(offlineData, {
|
|
101
127
|
offlineMode: true,
|
|
102
128
|
environment,
|
|
103
129
|
renderMode: "raw",
|
|
104
130
|
server,
|
|
105
131
|
sdkDevToolsStylePath,
|
|
106
132
|
...theme ? { theme } : {},
|
|
133
|
+
...paintedState ? { state: paintedState } : {},
|
|
107
134
|
...clientAnalytics ? { analytics: clientAnalytics } : {},
|
|
108
135
|
...overQuota ? { overQuota } : {},
|
|
109
136
|
...actionRuns ? { actionRuns } : {}
|
|
110
|
-
})
|
|
137
|
+
});
|
|
111
138
|
const pluginNames = req.ctx.spaceDeployment?.pluginNames ?? [];
|
|
112
139
|
const pluginSources = req.ctx.spaceDeployment?.pluginSources;
|
|
113
140
|
const pluginBaseNames = new Set(pluginNames.map((n) => n.replace(/@[^@]*$/, "")));
|
|
@@ -116,7 +143,7 @@ var prepareRender = async (req, config, spaceId, environment, revision, pluginMa
|
|
|
116
143
|
const key = pluginManager.ensure(pluginName, pluginSource);
|
|
117
144
|
if (!pluginBaseNames.has(pluginName)) dynamicNames.push(key);
|
|
118
145
|
}
|
|
119
|
-
const externalNamesFiltered = (config.autoLoadSchemaPlugins !== false ? await m("extPlugins", () => registerExternalPlugins(pluginManager, offlineData)) : []).filter((k) => !pluginBaseNames.has(k.replace(/@[^@]*$/, "")));
|
|
146
|
+
const externalNamesFiltered = (config.autoLoadSchemaPlugins !== false ? await m("extPlugins", () => registerExternalPlugins(pluginManager, offlineData, { allowPrivateHosts: config.allowPrivatePluginHosts === true })) : []).filter((k) => !pluginBaseNames.has(k.replace(/@[^@]*$/, "")));
|
|
120
147
|
const allPluginNames = [
|
|
121
148
|
...pluginNames,
|
|
122
149
|
...dynamicNames,
|
|
@@ -124,6 +151,7 @@ var prepareRender = async (req, config, spaceId, environment, revision, pluginMa
|
|
|
124
151
|
];
|
|
125
152
|
const entries = allPluginNames.length > 0 ? await pluginManager.getEntries(allPluginNames) : [];
|
|
126
153
|
const pluginComponents = await m("plugins", () => loadPluginComponents(entries, pluginManager.getComponents()));
|
|
154
|
+
reportMissingPlugins(spaceId, schema, /* @__PURE__ */ new Set([...Object.keys(pluginComponents), ...entries.map((entry) => entry.keyName)]));
|
|
127
155
|
const templatePlugins = (entries.length > 0 ? entries : req.ctx.spaceDeployment?.templateProps?.plugins)?.map((entry) => ({
|
|
128
156
|
...entry,
|
|
129
157
|
ssr: entry.keyName in pluginComponents
|
|
@@ -138,7 +166,8 @@ var prepareRender = async (req, config, spaceId, environment, revision, pluginMa
|
|
|
138
166
|
debugMode: debugRendered,
|
|
139
167
|
sdkDevToolsStylePath,
|
|
140
168
|
overQuota,
|
|
141
|
-
theme
|
|
169
|
+
theme,
|
|
170
|
+
...paintedState ? { state: paintedState } : {}
|
|
142
171
|
},
|
|
143
172
|
entries,
|
|
144
173
|
templateParams: {
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
+
import { StoreMethods } from '../../core/server/fleet/channel';
|
|
1
2
|
import { DraftStore, OfflineDataRaw, SSRRequest, SSRServerConfig } from '@plitzi/sdk-shared';
|
|
2
3
|
/** The READ side of draft-preview: a render resolving a stashed draft from its token. The write side — applying
|
|
3
4
|
* unsaved operations and rendering the result — lives in `@plitzi/sdk-mcp`, which is what knows how to interpret an
|
|
4
5
|
* operation; a page-only deployment keeps this much and never loads that. */
|
|
6
|
+
/** Every method of the store, for the copy a server's workers share (see `fleet/stores.ts`). */
|
|
7
|
+
export declare const DRAFT_STORE_METHODS: StoreMethods<DraftStore>;
|
|
5
8
|
/** In-memory draft store — the default when the consumer injects none. Fine for a single replica; a multi-replica
|
|
6
9
|
* deployment must inject a shared store so a preview URL resolves on any replica. */
|
|
7
10
|
export declare const createMemoryDraftStore: () => DraftStore;
|
|
@@ -3,16 +3,23 @@ import { PREVIEW_COOKIE, readDraftToken } from "../../core/previewToken.js";
|
|
|
3
3
|
/** The READ side of draft-preview: a render resolving a stashed draft from its token. The write side — applying
|
|
4
4
|
* unsaved operations and rendering the result — lives in `@plitzi/sdk-mcp`, which is what knows how to interpret an
|
|
5
5
|
* operation; a page-only deployment keeps this much and never loads that. */
|
|
6
|
+
/** Every method of the store, for the copy a server's workers share (see `fleet/stores.ts`). */
|
|
7
|
+
var DRAFT_STORE_METHODS = {
|
|
8
|
+
put: true,
|
|
9
|
+
take: true,
|
|
10
|
+
drop: true
|
|
11
|
+
};
|
|
6
12
|
/** In-memory draft store — the default when the consumer injects none. Fine for a single replica; a multi-replica
|
|
7
13
|
* deployment must inject a shared store so a preview URL resolves on any replica. */
|
|
8
14
|
var createMemoryDraftStore = () => {
|
|
9
15
|
const store = /* @__PURE__ */ new Map();
|
|
10
16
|
return {
|
|
11
|
-
put(token, data, { ttlMs, reusable = false }) {
|
|
17
|
+
put(token, data, { ttlMs, reusable = false, spaceId }) {
|
|
12
18
|
store.set(token, {
|
|
13
19
|
data,
|
|
14
20
|
expiresAt: Date.now() + ttlMs,
|
|
15
|
-
reusable
|
|
21
|
+
reusable,
|
|
22
|
+
spaceId
|
|
16
23
|
});
|
|
17
24
|
},
|
|
18
25
|
take(token) {
|
|
@@ -21,7 +28,8 @@ var createMemoryDraftStore = () => {
|
|
|
21
28
|
if (!hit.reusable || hit.expiresAt <= Date.now()) store.delete(token);
|
|
22
29
|
return hit.expiresAt > Date.now() ? {
|
|
23
30
|
data: hit.data,
|
|
24
|
-
reusable: hit.reusable
|
|
31
|
+
reusable: hit.reusable,
|
|
32
|
+
spaceId: hit.spaceId
|
|
25
33
|
} : void 0;
|
|
26
34
|
},
|
|
27
35
|
drop(token) {
|
|
@@ -39,10 +47,12 @@ var takeDraftOverride = async (req, config) => {
|
|
|
39
47
|
const token = readDraftToken(req);
|
|
40
48
|
if (!token || !config.draftStore) return;
|
|
41
49
|
const entry = await config.draftStore.take(token);
|
|
42
|
-
|
|
43
|
-
|
|
50
|
+
if (!entry || entry.spaceId !== req.ctx.spaceDeployment?.spaceId) return;
|
|
51
|
+
return {
|
|
52
|
+
data: entry.data,
|
|
53
|
+
reusable: entry.reusable,
|
|
44
54
|
token
|
|
45
|
-
}
|
|
55
|
+
};
|
|
46
56
|
};
|
|
47
57
|
/** The `Set-Cookie` that carries a draft session through the rest of the visit. */
|
|
48
58
|
var draftSessionCookie = (req, token, ttlMs) => [
|
|
@@ -54,4 +64,4 @@ var draftSessionCookie = (req, token, ttlMs) => [
|
|
|
54
64
|
...req.protocol === "https" ? ["Secure"] : []
|
|
55
65
|
].join("; ");
|
|
56
66
|
//#endregion
|
|
57
|
-
export { createMemoryDraftStore, draftSessionCookie, takeDraftOverride };
|
|
67
|
+
export { DRAFT_STORE_METHODS, createMemoryDraftStore, draftSessionCookie, takeDraftOverride };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
import { PluginManager } from '../../plugins/manager';
|
|
2
2
|
import { OfflineDataRaw } from '@plitzi/sdk-shared';
|
|
3
|
+
/** Where a plugin may be read from: anywhere public, and — on a development machine only — a private address too. */
|
|
4
|
+
type ManifestReach = {
|
|
5
|
+
allowPrivateHosts: boolean;
|
|
6
|
+
};
|
|
3
7
|
/**
|
|
4
8
|
* Reads plugins listed in offlineData.plugins, fetches their manifests, downloads and caches
|
|
5
9
|
* JS/CSS via the PluginManager, and returns the effective plugin keys to pass to getEntries().
|
|
6
10
|
*/
|
|
7
|
-
export declare const registerExternalPlugins: (pluginManager: PluginManager, offlineData: OfflineDataRaw | undefined) => Promise<string[]>;
|
|
11
|
+
export declare const registerExternalPlugins: (pluginManager: PluginManager, offlineData: OfflineDataRaw | undefined, reach?: ManifestReach) => Promise<string[]>;
|
|
12
|
+
export {};
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { serverLog } from "../../helpers/serverLog.js";
|
|
2
|
+
import { fetchOutbound } from "../../helpers/outboundGuard.js";
|
|
3
|
+
import { writeFileAtomic } from "../../helpers/atomicFile.js";
|
|
1
4
|
import crypto from "node:crypto";
|
|
2
5
|
import path from "node:path";
|
|
3
6
|
import fs from "node:fs/promises";
|
|
@@ -22,17 +25,17 @@ var readDiskEntry = async (dir, resource) => {
|
|
|
22
25
|
var writeDiskEntry = async (dir, resource, entry) => {
|
|
23
26
|
try {
|
|
24
27
|
await fs.mkdir(dir, { recursive: true });
|
|
25
|
-
await
|
|
28
|
+
await writeFileAtomic(cacheFilePath(dir, resource), JSON.stringify(entry));
|
|
26
29
|
} catch (err) {
|
|
27
|
-
|
|
30
|
+
serverLog.warn("SSR", `Failed to persist plugin manifest cache for ${resource}`, err);
|
|
28
31
|
}
|
|
29
32
|
};
|
|
30
|
-
var fetchAndStore = async (dir, resource) => {
|
|
33
|
+
var fetchAndStore = async (dir, resource, reach) => {
|
|
31
34
|
try {
|
|
32
35
|
const url = `${resource}/plugin-manifest.json`;
|
|
33
|
-
const res = await fetch(url);
|
|
36
|
+
const res = reach.allowPrivateHosts ? await fetch(url) : await fetchOutbound(fetch, new URL(url));
|
|
34
37
|
if (!res.ok) {
|
|
35
|
-
|
|
38
|
+
serverLog.warn("SSR", `Failed to fetch plugin manifest from ${url}: HTTP ${res.status}`);
|
|
36
39
|
return null;
|
|
37
40
|
}
|
|
38
41
|
const manifest = await res.json();
|
|
@@ -44,24 +47,24 @@ var fetchAndStore = async (dir, resource) => {
|
|
|
44
47
|
await writeDiskEntry(dir, resource, entry);
|
|
45
48
|
return manifest;
|
|
46
49
|
} catch (err) {
|
|
47
|
-
|
|
50
|
+
serverLog.warn("SSR", `Error fetching plugin manifest from ${resource}`, err);
|
|
48
51
|
return null;
|
|
49
52
|
}
|
|
50
53
|
};
|
|
51
|
-
var revalidate = (dir, resource) => {
|
|
54
|
+
var revalidate = (dir, resource, reach) => {
|
|
52
55
|
if (refreshing.has(resource)) return;
|
|
53
56
|
refreshing.add(resource);
|
|
54
|
-
fetchAndStore(dir, resource).finally(() => refreshing.delete(resource));
|
|
57
|
+
fetchAndStore(dir, resource, reach).finally(() => refreshing.delete(resource));
|
|
55
58
|
};
|
|
56
|
-
var fetchManifest = async (pluginManager, resource) => {
|
|
59
|
+
var fetchManifest = async (pluginManager, resource, reach) => {
|
|
57
60
|
const dir = manifestCacheDir(pluginManager);
|
|
58
61
|
const cached = manifestCache.get(resource) ?? await readDiskEntry(dir, resource) ?? void 0;
|
|
59
62
|
if (cached) {
|
|
60
63
|
manifestCache.set(resource, cached);
|
|
61
|
-
if (cached.expiresAt <= Date.now()) revalidate(dir, resource);
|
|
64
|
+
if (cached.expiresAt <= Date.now()) revalidate(dir, resource, reach);
|
|
62
65
|
return cached.manifest;
|
|
63
66
|
}
|
|
64
|
-
return fetchAndStore(dir, resource);
|
|
67
|
+
return fetchAndStore(dir, resource, reach);
|
|
65
68
|
};
|
|
66
69
|
var resolveAssetUrl = (resource, asset) => {
|
|
67
70
|
if (asset.url) return asset.url;
|
|
@@ -74,13 +77,13 @@ var findAsset = (manifest, type, resource) => {
|
|
|
74
77
|
return main ? resolveAssetUrl(resource, main) ?? void 0 : void 0;
|
|
75
78
|
};
|
|
76
79
|
var isAbsoluteUrl = (url) => url.startsWith("http://") || url.startsWith("https://");
|
|
77
|
-
var registerPlugin = async (pluginManager, plugin) => {
|
|
80
|
+
var registerPlugin = async (pluginManager, plugin, reach) => {
|
|
78
81
|
if (!plugin.resource || !isAbsoluteUrl(plugin.resource)) return null;
|
|
79
|
-
const manifest = await fetchManifest(pluginManager, plugin.resource);
|
|
82
|
+
const manifest = await fetchManifest(pluginManager, plugin.resource, reach);
|
|
80
83
|
if (!manifest) return null;
|
|
81
84
|
const jsUrl = findAsset(manifest, "script", plugin.resource);
|
|
82
85
|
if (!jsUrl) {
|
|
83
|
-
|
|
86
|
+
serverLog.warn("SSR", `Plugin "${plugin.type}" has no JS asset in manifest, skipping`);
|
|
84
87
|
return null;
|
|
85
88
|
}
|
|
86
89
|
const source = {
|
|
@@ -95,10 +98,10 @@ var registerPlugin = async (pluginManager, plugin) => {
|
|
|
95
98
|
* Reads plugins listed in offlineData.plugins, fetches their manifests, downloads and caches
|
|
96
99
|
* JS/CSS via the PluginManager, and returns the effective plugin keys to pass to getEntries().
|
|
97
100
|
*/
|
|
98
|
-
var registerExternalPlugins = async (pluginManager, offlineData) => {
|
|
101
|
+
var registerExternalPlugins = async (pluginManager, offlineData, reach = { allowPrivateHosts: false }) => {
|
|
99
102
|
const plugins = offlineData?.plugins;
|
|
100
103
|
if (!plugins || plugins.length === 0) return [];
|
|
101
|
-
return (await Promise.all(plugins.map((p) => registerPlugin(pluginManager, p)))).filter((k) => k !== null);
|
|
104
|
+
return (await Promise.all(plugins.map((p) => registerPlugin(pluginManager, p, reach)))).filter((k) => k !== null);
|
|
102
105
|
};
|
|
103
106
|
//#endregion
|
|
104
107
|
export { registerExternalPlugins };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Schema } from '@plitzi/sdk-shared';
|
|
2
|
+
/**
|
|
3
|
+
* The plugin types a space renders that this server has nothing for — neither a component in the render nor a bundle
|
|
4
|
+
* for the browser. Each prints "Custom Component … Not Found" where the plugin should be, and nothing else anywhere
|
|
5
|
+
* says why, so it is said here: once per space and type, at `error`, because a visitor is looking at the placeholder.
|
|
6
|
+
*
|
|
7
|
+
* A `custom` element carrying its own `scriptUrl` loads itself in the browser and is not this server's to supply.
|
|
8
|
+
*/
|
|
9
|
+
export declare const reportMissingPlugins: (spaceId: number, schema: Schema | undefined, available: ReadonlySet<string>) => void;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { serverLog } from "../../helpers/serverLog.js";
|
|
2
|
+
//#region src/modules/ssr/reportMissingPlugins.ts
|
|
3
|
+
var reported = /* @__PURE__ */ new Set();
|
|
4
|
+
/**
|
|
5
|
+
* The plugin types a space renders that this server has nothing for — neither a component in the render nor a bundle
|
|
6
|
+
* for the browser. Each prints "Custom Component … Not Found" where the plugin should be, and nothing else anywhere
|
|
7
|
+
* says why, so it is said here: once per space and type, at `error`, because a visitor is looking at the placeholder.
|
|
8
|
+
*
|
|
9
|
+
* A `custom` element carrying its own `scriptUrl` loads itself in the browser and is not this server's to supply.
|
|
10
|
+
*/
|
|
11
|
+
var reportMissingPlugins = (spaceId, schema, available) => {
|
|
12
|
+
if (!schema || !serverLog.enabled("error")) return;
|
|
13
|
+
for (const element of Object.values(schema.flat)) {
|
|
14
|
+
const { renderType, isPlugin, scriptUrl } = element.attributes;
|
|
15
|
+
const loadsItself = isPlugin === true && typeof scriptUrl === "string" && scriptUrl !== "";
|
|
16
|
+
if (element.definition.type !== "custom" || typeof renderType !== "string" || renderType === "" || loadsItself) continue;
|
|
17
|
+
const key = `${spaceId}:${renderType}`;
|
|
18
|
+
if (available.has(renderType) || reported.has(key)) continue;
|
|
19
|
+
reported.add(key);
|
|
20
|
+
serverLog.error("SSR", `Space ${String(spaceId)} renders the plugin "${renderType}" (element "${element.id}"), and this server has none by that name, so the page shows "Custom Component ${renderType} Not Found". Register it in \`plugins\` and name it in the deployment's \`pluginNames\`.`);
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
//#endregion
|
|
24
|
+
export { reportMissingPlugins };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { TtlCache } from '../../helpers/cache';
|
|
1
|
+
import { CachedPage, TtlCache } from '../../helpers/cache';
|
|
2
2
|
import { RequestMetrics } from '../../helpers/metrics';
|
|
3
3
|
import { PluginManager } from '../../plugins/manager';
|
|
4
4
|
import { Environment, OfflineDataRaw, SSRPageServerConfig, SSRRequest, SSRResponseHelpers, SSRTemplateFn } from '@plitzi/sdk-shared';
|
|
5
|
-
export declare const streamBody: (req: SSRRequest, res: SSRResponseHelpers, config: SSRPageServerConfig, spaceId: number, environment: Environment, revision: number, renderFn: SSRTemplateFn, pluginManager: PluginManager, offlineDataCache?: TtlCache<string>, htmlCache?: TtlCache<
|
|
5
|
+
export declare const streamBody: (req: SSRRequest, res: SSRResponseHelpers, config: SSRPageServerConfig, spaceId: number, environment: Environment, revision: number, renderFn: SSRTemplateFn, pluginManager: PluginManager, offlineDataCache?: TtlCache<string>, htmlCache?: TtlCache<CachedPage>, cacheKey?: string, metrics?: RequestMetrics, offlineDataOverride?: OfflineDataRaw) => Promise<void>;
|
|
@@ -30,7 +30,10 @@ var streamBody = async (req, res, config, spaceId, environment, revision, render
|
|
|
30
30
|
const tailBuf = Buffer.from(tail, "utf-8");
|
|
31
31
|
res.write(tailBuf);
|
|
32
32
|
res.end();
|
|
33
|
-
if (chunks && cacheKey && htmlCache) htmlCache.set(cacheKey,
|
|
33
|
+
if (chunks && cacheKey && htmlCache) htmlCache.set(cacheKey, {
|
|
34
|
+
html: head + Buffer.concat(chunks).toString("utf-8") + tail,
|
|
35
|
+
compressed: {}
|
|
36
|
+
});
|
|
34
37
|
resolve();
|
|
35
38
|
cb();
|
|
36
39
|
}
|