@plitzi/sdk-server 0.37.1 → 0.37.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +1296 -0
- package/README.md +126 -7
- package/dist/actions.d.ts +20 -8
- package/dist/actions.js +11 -4
- package/dist/adapters/cloudAdapters.js +4 -3
- package/dist/adapters/jsonAdapters.js +28 -6
- 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 +14 -1
- package/dist/core/server/baseServer.js +43 -11
- package/dist/core/server/closeOnSignals.d.ts +28 -0
- package/dist/core/server/closeOnSignals.js +47 -0
- package/dist/core/server/closeOnSignals.test.d.ts +1 -0
- 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 +36 -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 +8 -1
- package/dist/index.js +6 -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 +41 -13
- package/dist/modules/actions/index.js +52 -9
- 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 +33 -0
- package/dist/modules/actions/jobs/index.js +59 -0
- package/dist/modules/actions/jobs/memoryQueue.d.ts +33 -0
- package/dist/modules/actions/jobs/memoryQueue.js +194 -0
- package/dist/modules/actions/jobs/memoryStores.test.d.ts +1 -0
- package/dist/modules/actions/jobs/scheduler.d.ts +64 -0
- package/dist/modules/actions/jobs/scheduler.js +130 -0
- package/dist/modules/actions/jobs/scheduler.test.d.ts +1 -0
- package/dist/modules/actions/jobs/schedules.d.ts +23 -0
- package/dist/modules/actions/jobs/schedules.js +47 -0
- package/dist/modules/actions/jobs/storeClock.d.ts +16 -0
- package/dist/modules/actions/jobs/storeClock.js +32 -0
- package/dist/modules/actions/jobs/testing/jobQueueContract.d.ts +25 -0
- package/dist/modules/actions/jobs/worker.d.ts +64 -0
- package/dist/modules/actions/jobs/worker.js +267 -0
- package/dist/modules/actions/jobs/worker.test.d.ts +1 -0
- package/dist/modules/actions/moduleFor.js +6 -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 +5 -9
- 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/renderResolver.js +2 -2
- 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 +6 -3
- 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 +5 -4
- package/dist/modules/actions/types.d.ts +162 -4
- 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/index.d.ts +4 -0
- package/dist/modules/mongo/jobQueue.d.ts +38 -0
- package/dist/modules/mongo/jobQueue.js +335 -0
- package/dist/modules/mongo/kv.d.ts +15 -0
- package/dist/modules/mongo/kv.js +129 -0
- package/dist/modules/mongo/stores.integration.test.d.ts +1 -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 +5 -0
- package/dist/modules/mysql/jobs/jobQueue.d.ts +40 -0
- package/dist/modules/mysql/jobs/jobQueue.js +375 -0
- package/dist/modules/mysql/jobs/kv.d.ts +18 -0
- package/dist/modules/mysql/jobs/kv.js +108 -0
- package/dist/modules/mysql/jobs/schema.d.ts +33 -0
- package/dist/modules/mysql/jobs/schema.js +113 -0
- package/dist/modules/mysql/jobs/stores.integration.test.d.ts +1 -0
- 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 +4 -5
- package/dist/modules/ssr/Component.js +2 -2
- package/dist/modules/ssr/handler.js +10 -2
- package/dist/modules/ssr/loadPluginComponents.js +2 -1
- package/dist/modules/ssr/prepareRender.js +39 -13
- 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/mongo.d.ts +25 -0
- package/dist/mongo.js +3 -0
- package/dist/mysql.d.ts +11 -0
- package/dist/mysql.js +4 -1
- 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 +52 -11
- package/skills/plitzi-authoring/SKILL.md +153 -263
- 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 +180 -0
- package/skills/plitzi-authoring/reference/elements-and-styles.md +161 -0
- package/skills/plitzi-authoring/reference/flows.md +171 -0
- package/skills/plitzi-authoring/reference/layouts.md +140 -0
- 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 +67 -0
- package/skills/plitzi-authoring/reference/structure.md +83 -0
- package/skills/plitzi-authoring/reference/templates-and-export.md +54 -0
- package/skills/plitzi-authoring/reference/templates.md +109 -0
- package/skills/plitzi-authoring/reference/testing.md +119 -0
- package/skills/plitzi-authoring/reference/validation.md +73 -0
- package/dist/modules/actions/runtime/schedule.d.ts +0 -35
- package/dist/modules/actions/runtime/schedule.js +0 -76
- /package/dist/{modules/actions/runtime/schedule.test.d.ts → adapters/jsonAdapters.test.d.ts} +0 -0
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import esbuild from "esbuild";
|
|
4
|
+
import { pathToFileURL } from "node:url";
|
|
5
|
+
import fs from "node:fs/promises";
|
|
6
|
+
import { gunzipSync, gzipSync } from "node:zlib";
|
|
7
|
+
//#region src/modules/runtime/bundle.ts
|
|
8
|
+
/** What the runtime's host provides, and a bundle must not carry a copy of: the platform's packages and React. */
|
|
9
|
+
var PROVIDED = [
|
|
10
|
+
"@plitzi/*",
|
|
11
|
+
"react",
|
|
12
|
+
"react-dom",
|
|
13
|
+
"react/*",
|
|
14
|
+
"react-dom/*"
|
|
15
|
+
];
|
|
16
|
+
/** A packed runtime at most this big: its code and every dependency, not its data. */
|
|
17
|
+
var MAX_RUNTIME_BUNDLE_BYTES = 33554432;
|
|
18
|
+
var FORMAT = 1;
|
|
19
|
+
var ENTRY = "runtime.mjs";
|
|
20
|
+
/** A bundle's id: what its bytes are, so the same code packed twice is one bundle. */
|
|
21
|
+
var runtimeBundleId = (bytes) => createHash("sha256").update(bytes).digest("hex");
|
|
22
|
+
/**
|
|
23
|
+
* A runtime's module packed to travel: bundled for Node with every dependency it imports — but the platform's packages
|
|
24
|
+
* and React, which the host provides, so there is one copy of each — and gzipped. `entry` is the module whose default
|
|
25
|
+
* export is `defineRuntime(…)`.
|
|
26
|
+
*/
|
|
27
|
+
var packRuntime = async (entry) => {
|
|
28
|
+
const result = await esbuild.build({
|
|
29
|
+
entryPoints: [entry],
|
|
30
|
+
bundle: true,
|
|
31
|
+
platform: "node",
|
|
32
|
+
format: "esm",
|
|
33
|
+
target: "node22",
|
|
34
|
+
external: PROVIDED,
|
|
35
|
+
outdir: "runtime",
|
|
36
|
+
entryNames: "runtime",
|
|
37
|
+
outExtension: { ".js": ".mjs" },
|
|
38
|
+
banner: { js: "import { createRequire as __plitziRequire } from \"node:module\"; const require = __plitziRequire(import.meta.url);" },
|
|
39
|
+
splitting: false,
|
|
40
|
+
logLevel: "warning",
|
|
41
|
+
write: false
|
|
42
|
+
});
|
|
43
|
+
const files = Object.fromEntries(result.outputFiles.map((output) => [path.basename(output.path), Buffer.from(output.contents).toString("base64")]));
|
|
44
|
+
if (!(ENTRY in files)) throw new Error(`Packing ${entry} produced no ${ENTRY}`);
|
|
45
|
+
const bytes = gzipSync(JSON.stringify({
|
|
46
|
+
format: FORMAT,
|
|
47
|
+
entry: ENTRY,
|
|
48
|
+
files
|
|
49
|
+
}));
|
|
50
|
+
if (bytes.byteLength > 33554432) throw new Error(`A runtime is at most ${String(MAX_RUNTIME_BUNDLE_BYTES / 1024 / 1024)} MB packed; this one is ${(bytes.byteLength / 1024 / 1024).toFixed(1)} MB`);
|
|
51
|
+
return new Uint8Array(bytes);
|
|
52
|
+
};
|
|
53
|
+
var isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
54
|
+
/** A packed runtime read back — refused whole when it is not one. */
|
|
55
|
+
var unpack = (bytes) => {
|
|
56
|
+
let parsed;
|
|
57
|
+
try {
|
|
58
|
+
parsed = JSON.parse(gunzipSync(bytes).toString("utf8"));
|
|
59
|
+
} catch {
|
|
60
|
+
throw new Error("Not a packed runtime: it is not gzipped JSON");
|
|
61
|
+
}
|
|
62
|
+
if (!isRecord(parsed) || parsed.format !== FORMAT || typeof parsed.entry !== "string" || !isRecord(parsed.files)) throw new Error(`Not a packed runtime of format ${String(FORMAT)}`);
|
|
63
|
+
const files = {};
|
|
64
|
+
Object.entries(parsed.files).forEach(([name, content]) => {
|
|
65
|
+
if (typeof content !== "string" || name !== path.basename(name) || name.startsWith(".")) throw new Error(`"${name}" is not a file a packed runtime can hold`);
|
|
66
|
+
files[name] = content;
|
|
67
|
+
});
|
|
68
|
+
if (!(parsed.entry in files)) throw new Error(`A packed runtime's entry, ${parsed.entry}, is not among its files`);
|
|
69
|
+
return {
|
|
70
|
+
format: FORMAT,
|
|
71
|
+
entry: parsed.entry,
|
|
72
|
+
files
|
|
73
|
+
};
|
|
74
|
+
};
|
|
75
|
+
/**
|
|
76
|
+
* What a packed runtime holds, read without running any of it — what a platform checks a bundle with before keeping it.
|
|
77
|
+
* Throws, saying why, for bytes that are not one.
|
|
78
|
+
*/
|
|
79
|
+
var inspectRuntime = (bytes) => {
|
|
80
|
+
if (bytes.byteLength > 33554432) throw new Error(`A runtime is at most ${String(MAX_RUNTIME_BUNDLE_BYTES / 1024 / 1024)} MB packed`);
|
|
81
|
+
const { entry, files } = unpack(bytes);
|
|
82
|
+
return {
|
|
83
|
+
entry,
|
|
84
|
+
files: Object.keys(files)
|
|
85
|
+
};
|
|
86
|
+
};
|
|
87
|
+
var isRuntime = (value) => isRecord(value) && typeof value.start === "function";
|
|
88
|
+
/**
|
|
89
|
+
* A packed runtime written into `dir` and imported: its module's default export. `dir` must be inside the host's own
|
|
90
|
+
* project, so the packages the bundle leaves to the host resolve to the host's — one copy of each.
|
|
91
|
+
*/
|
|
92
|
+
var loadRuntime = async (bytes, dir) => {
|
|
93
|
+
const { entry, files } = unpack(bytes);
|
|
94
|
+
await fs.mkdir(dir, { recursive: true });
|
|
95
|
+
await Promise.all(Object.entries(files).map(([name, content]) => fs.writeFile(path.join(dir, name), Buffer.from(content, "base64"))));
|
|
96
|
+
const loaded = await import(pathToFileURL(path.join(dir, entry)).href);
|
|
97
|
+
const runtime = isRecord(loaded) ? loaded.default : void 0;
|
|
98
|
+
if (!isRuntime(runtime)) throw new Error("A runtime module exports its runtime by default: export default defineRuntime({ start: … })");
|
|
99
|
+
return runtime;
|
|
100
|
+
};
|
|
101
|
+
//#endregion
|
|
102
|
+
export { MAX_RUNTIME_BUNDLE_BYTES, inspectRuntime, loadRuntime, packRuntime, runtimeBundleId };
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { FunctionsDefinition } from '../functions/contract';
|
|
2
|
+
/** What a runtime starts with. */
|
|
3
|
+
export type SpaceRuntimeContext = {
|
|
4
|
+
/** Its variables: those the platform keeps for it (`REDIS_URL`…), or a self-hosted server's own environment. */
|
|
5
|
+
env: Readonly<Record<string, string | undefined>>;
|
|
6
|
+
/** Where people reach the space — what a link written for a person, or an agent, is handed. */
|
|
7
|
+
publicUrl: string;
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* A path of the space's own answered by the runtime: a web handler, streaming if it likes — an agent's endpoint, a
|
|
11
|
+
* webhook that speaks a protocol of its own. The visitor's cookies and `Authorization` never reach it: the host's are
|
|
12
|
+
* the platform's.
|
|
13
|
+
*/
|
|
14
|
+
export type SpaceRuntimeEndpoint = (request: Request) => Response | Promise<Response>;
|
|
15
|
+
/** What a started runtime is made of. */
|
|
16
|
+
export type SpaceRuntimeParts = {
|
|
17
|
+
/** Its tasks and `/api/` routes, run with a `ctx` that is the platform's — the space's `kv`, its channels, its key. */
|
|
18
|
+
functions?: FunctionsDefinition;
|
|
19
|
+
/** Paths it answers itself, each with everything beneath it (`/mcp` answers `/mcp/…`) — see {@link endpointProblem}. */
|
|
20
|
+
endpoints?: Record<string, SpaceRuntimeEndpoint>;
|
|
21
|
+
/** Called when it is stopped: close what `start` opened. */
|
|
22
|
+
close?: () => Promise<void>;
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* A space's own server code, run as code of its own — Node, its dependencies, its connections — beside the platform
|
|
26
|
+
* that serves the space: a runtime of the space, where the sandbox's functions are not enough. `start` is handed its
|
|
27
|
+
* variables and answers what it serves.
|
|
28
|
+
*/
|
|
29
|
+
export type SpaceRuntime = {
|
|
30
|
+
start: (context: SpaceRuntimeContext) => SpaceRuntimeParts | Promise<SpaceRuntimeParts>;
|
|
31
|
+
};
|
|
32
|
+
/** Declares a space runtime — an identity, for the types: `export default defineRuntime({ start: … })`. */
|
|
33
|
+
export declare const defineRuntime: (runtime: SpaceRuntime) => SpaceRuntime;
|
|
34
|
+
/** Why a path cannot be an endpoint — or nothing, for one that can. */
|
|
35
|
+
export declare const endpointProblem: (path: string) => string | undefined;
|
|
36
|
+
/** The endpoint a request's path belongs to: exactly it, or beneath it — the longest that does. */
|
|
37
|
+
export declare const endpointFor: (paths: readonly string[], path: string) => string | undefined;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { FUNCTION_ROUTES_PREFIX } from "@plitzi/sdk-shared/actions";
|
|
2
|
+
//#region src/modules/runtime/contract.ts
|
|
3
|
+
/** Declares a space runtime — an identity, for the types: `export default defineRuntime({ start: … })`. */
|
|
4
|
+
var defineRuntime = (runtime) => runtime;
|
|
5
|
+
/** The paths the server answers itself, which no endpoint may take: its routes, its own endpoints and sign-in. */
|
|
6
|
+
var RESERVED = [
|
|
7
|
+
FUNCTION_ROUTES_PREFIX,
|
|
8
|
+
"/_",
|
|
9
|
+
"/auth",
|
|
10
|
+
"/.well-known"
|
|
11
|
+
];
|
|
12
|
+
/** Why a path cannot be an endpoint — or nothing, for one that can. */
|
|
13
|
+
var endpointProblem = (path) => {
|
|
14
|
+
if (!/^\/[A-Za-z0-9._~-]+(\/[A-Za-z0-9._~-]+)*$/.test(path)) return `"${path}" is not an endpoint path: it starts with "/" and is made of plain segments`;
|
|
15
|
+
const taken = RESERVED.find((prefix) => path === prefix || path.startsWith(prefix.endsWith("_") ? prefix : `${prefix}/`));
|
|
16
|
+
if (taken) return `"${path}" is the server's own (${taken}): an endpoint takes a path of the space's`;
|
|
17
|
+
};
|
|
18
|
+
/** The endpoint a request's path belongs to: exactly it, or beneath it — the longest that does. */
|
|
19
|
+
var endpointFor = (paths, path) => paths.filter((candidate) => path === candidate || path.startsWith(`${candidate}/`)).sort((a, b) => b.length - a.length)[0];
|
|
20
|
+
//#endregion
|
|
21
|
+
export { defineRuntime, endpointFor, endpointProblem };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { SpaceRuntime } from './contract';
|
|
2
|
+
import { AddressInfo } from 'node:net';
|
|
3
|
+
/** What the platform reads of a started runtime: its functions' manifest, and the paths it answers itself. */
|
|
4
|
+
export type SpaceRuntimeDescription = {
|
|
5
|
+
functions: Record<string, unknown>;
|
|
6
|
+
endpoints: string[];
|
|
7
|
+
};
|
|
8
|
+
/** Where a started runtime says what it serves — under `/_`, which no endpoint may take. */
|
|
9
|
+
export declare const RUNTIME_DESCRIBE_PATH = "/_describe";
|
|
10
|
+
/** The headers of the platform's, which a runtime's endpoint never sees. */
|
|
11
|
+
export declare const PLATFORM_HEADERS: string[];
|
|
12
|
+
export type SpaceRuntimeHostOptions = {
|
|
13
|
+
runtime: SpaceRuntime;
|
|
14
|
+
/** What the platform presents — `Authorization: Bearer <secret>` — on its calls and on the requests it forwards. */
|
|
15
|
+
secret: string;
|
|
16
|
+
port?: number;
|
|
17
|
+
host?: string;
|
|
18
|
+
/** The runtime's variables. */
|
|
19
|
+
env: Readonly<Record<string, string | undefined>>;
|
|
20
|
+
/** Where people reach the space. */
|
|
21
|
+
publicUrl: string;
|
|
22
|
+
/**
|
|
23
|
+
* Where the space is reached from inside the network this runtime runs in — the platform's ingress, over plain HTTP.
|
|
24
|
+
* Given, the runtime's requests to its own space go there rather than out to the edge and back (`reachSpaceInside`).
|
|
25
|
+
*/
|
|
26
|
+
insideUrl?: string | undefined;
|
|
27
|
+
};
|
|
28
|
+
export type SpaceRuntimeHost = {
|
|
29
|
+
address: () => AddressInfo;
|
|
30
|
+
close: () => Promise<void>;
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* A space runtime, started and served: its tasks and routes over the functions runners' protocol (the platform invokes
|
|
34
|
+
* them and answers every `ctx` call), and its endpoints as plain HTTP the platform forwards — both behind one secret,
|
|
35
|
+
* since the only caller is the platform. The process is the space's alone: what its code can reach is this process
|
|
36
|
+
* and the network it is given, never the platform's database or keys.
|
|
37
|
+
*/
|
|
38
|
+
export declare const startSpaceRuntime: ({ runtime, secret, port, host, env, publicUrl, insideUrl }: SpaceRuntimeHostOptions) => Promise<SpaceRuntimeHost>;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { describeFunctions } from "../functions/driver.js";
|
|
2
|
+
import { startFunctionsRunnerService } from "../functions/runner/service.js";
|
|
3
|
+
import { endpointFor, endpointProblem } from "./contract.js";
|
|
4
|
+
import { reachSpaceInside } from "./inside.js";
|
|
5
|
+
import { createRuntimeRunner } from "./runner.js";
|
|
6
|
+
import { webRequestOf, writeWebResponse } from "../../core/http/webExchange.js";
|
|
7
|
+
//#region src/modules/runtime/host.ts
|
|
8
|
+
/** Where a started runtime says what it serves — under `/_`, which no endpoint may take. */
|
|
9
|
+
var RUNTIME_DESCRIBE_PATH = "/_describe";
|
|
10
|
+
/** The headers of the platform's, which a runtime's endpoint never sees. */
|
|
11
|
+
var PLATFORM_HEADERS = ["authorization", "cookie"];
|
|
12
|
+
/**
|
|
13
|
+
* A space runtime, started and served: its tasks and routes over the functions runners' protocol (the platform invokes
|
|
14
|
+
* them and answers every `ctx` call), and its endpoints as plain HTTP the platform forwards — both behind one secret,
|
|
15
|
+
* since the only caller is the platform. The process is the space's alone: what its code can reach is this process
|
|
16
|
+
* and the network it is given, never the platform's database or keys.
|
|
17
|
+
*/
|
|
18
|
+
var startSpaceRuntime = async ({ runtime, secret, port = 8791, host = "0.0.0.0", env, publicUrl, insideUrl }) => {
|
|
19
|
+
if (insideUrl) await reachSpaceInside({
|
|
20
|
+
publicUrl,
|
|
21
|
+
insideUrl
|
|
22
|
+
});
|
|
23
|
+
const parts = await runtime.start({
|
|
24
|
+
env,
|
|
25
|
+
publicUrl
|
|
26
|
+
});
|
|
27
|
+
const endpoints = parts.endpoints ?? {};
|
|
28
|
+
const paths = Object.keys(endpoints);
|
|
29
|
+
const problems = paths.flatMap((path) => endpointProblem(path) ?? []);
|
|
30
|
+
if (problems.length > 0) {
|
|
31
|
+
await parts.close?.();
|
|
32
|
+
throw new Error(problems.join("; "));
|
|
33
|
+
}
|
|
34
|
+
const description = {
|
|
35
|
+
functions: describeFunctions(parts.functions ?? {}),
|
|
36
|
+
endpoints: paths
|
|
37
|
+
};
|
|
38
|
+
const service = await startFunctionsRunnerService({
|
|
39
|
+
secret,
|
|
40
|
+
port,
|
|
41
|
+
host,
|
|
42
|
+
runner: createRuntimeRunner(parts.functions),
|
|
43
|
+
http: async (req, res) => {
|
|
44
|
+
const url = new URL(req.url ?? "/", publicUrl);
|
|
45
|
+
if (req.method === "GET" && url.pathname === "/_describe") {
|
|
46
|
+
res.writeHead(200, { "content-type": "application/json" });
|
|
47
|
+
res.end(JSON.stringify(description));
|
|
48
|
+
return true;
|
|
49
|
+
}
|
|
50
|
+
const endpoint = endpointFor(paths, url.pathname);
|
|
51
|
+
const answer = endpoint ? endpoints[endpoint] : void 0;
|
|
52
|
+
if (!answer) return false;
|
|
53
|
+
const left = new AbortController();
|
|
54
|
+
res.once("close", () => left.abort());
|
|
55
|
+
await writeWebResponse(res, await answer(await webRequestOf(req, url.href, PLATFORM_HEADERS)), left.signal);
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
return {
|
|
60
|
+
address: service.address,
|
|
61
|
+
close: async () => {
|
|
62
|
+
await service.close();
|
|
63
|
+
await parts.close?.();
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
};
|
|
67
|
+
//#endregion
|
|
68
|
+
export { PLATFORM_HEADERS, RUNTIME_DESCRIBE_PATH, startSpaceRuntime };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The space's own public address, reached from inside the network this runtime runs in: every request this process
|
|
3
|
+
* makes to the space's host — `fetch` and `WebSocket` alike, which share Node's dispatcher — connects to `insideUrl`
|
|
4
|
+
* instead, over plain HTTP, the space's host and the public protocol kept (`X-Forwarded-Proto`). It is the path a
|
|
5
|
+
* request takes once past the edge, without leaving to come back through it; the space's code keeps writing its public
|
|
6
|
+
* address, and nothing else it reaches changes.
|
|
7
|
+
*
|
|
8
|
+
* `undici` is imported here, when a runtime asks, and never with the module: loading the package installs a global
|
|
9
|
+
* dispatcher of its own, and this entry is loaded by the platform's page server too (`createRuntimeProxyStage`), whose
|
|
10
|
+
* every `fetch` must stay Node's.
|
|
11
|
+
*/
|
|
12
|
+
export declare const reachSpaceInside: ({ publicUrl, insideUrl }: {
|
|
13
|
+
publicUrl: string;
|
|
14
|
+
insideUrl: string;
|
|
15
|
+
}) => Promise<void>;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import net from "node:net";
|
|
2
|
+
//#region src/modules/runtime/inside.ts
|
|
3
|
+
/** Headers as a dispatch carries them — a record, name/value pairs flattened into one list, or pairs — plus one more. */
|
|
4
|
+
var withHeader = (headers, name, value) => {
|
|
5
|
+
const entries = [];
|
|
6
|
+
if (Array.isArray(headers)) for (let index = 0; index < headers.length; index += 2) entries.push([headers[index], headers[index + 1]]);
|
|
7
|
+
else if (headers && Symbol.iterator in headers) entries.push(...headers);
|
|
8
|
+
else if (headers) entries.push(...Object.entries(headers));
|
|
9
|
+
return {
|
|
10
|
+
...Object.fromEntries(entries),
|
|
11
|
+
[name]: value
|
|
12
|
+
};
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* The space's own public address, reached from inside the network this runtime runs in: every request this process
|
|
16
|
+
* makes to the space's host — `fetch` and `WebSocket` alike, which share Node's dispatcher — connects to `insideUrl`
|
|
17
|
+
* instead, over plain HTTP, the space's host and the public protocol kept (`X-Forwarded-Proto`). It is the path a
|
|
18
|
+
* request takes once past the edge, without leaving to come back through it; the space's code keeps writing its public
|
|
19
|
+
* address, and nothing else it reaches changes.
|
|
20
|
+
*
|
|
21
|
+
* `undici` is imported here, when a runtime asks, and never with the module: loading the package installs a global
|
|
22
|
+
* dispatcher of its own, and this entry is loaded by the platform's page server too (`createRuntimeProxyStage`), whose
|
|
23
|
+
* every `fetch` must stay Node's.
|
|
24
|
+
*/
|
|
25
|
+
var reachSpaceInside = async ({ publicUrl, insideUrl }) => {
|
|
26
|
+
const outside = new URL(publicUrl);
|
|
27
|
+
const inside = new URL(insideUrl);
|
|
28
|
+
if (inside.protocol !== "http:") throw new Error(`A space is reached from inside over plain HTTP, not ${inside.protocol} (${insideUrl})`);
|
|
29
|
+
const { Agent, buildConnector, setGlobalDispatcher } = await import("undici");
|
|
30
|
+
const port = Number(inside.port || 80);
|
|
31
|
+
const protocol = outside.protocol.replace(":", "");
|
|
32
|
+
const connect = buildConnector({});
|
|
33
|
+
setGlobalDispatcher(new Agent({ connect: (options, callback) => {
|
|
34
|
+
if (options.hostname !== outside.hostname) {
|
|
35
|
+
connect(options, callback);
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
const socket = net.connect(port, inside.hostname);
|
|
39
|
+
socket.once("connect", () => callback(null, socket));
|
|
40
|
+
socket.once("error", (error) => callback(error, null));
|
|
41
|
+
} }).compose((dispatch) => (options, handler) => dispatch(new URL(String(options.origin)).hostname === outside.hostname ? {
|
|
42
|
+
...options,
|
|
43
|
+
headers: withHeader(options.headers, "x-forwarded-proto", protocol)
|
|
44
|
+
} : options, handler)));
|
|
45
|
+
};
|
|
46
|
+
//#endregion
|
|
47
|
+
export { reachSpaceInside };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { FunctionsDefinition } from '../functions/contract';
|
|
2
|
+
import { FunctionRunner } from '../functions/protocol';
|
|
3
|
+
/**
|
|
4
|
+
* A runtime's functions as a runner: the same protocol as the sandbox's, answered by code loaded in this process. The
|
|
5
|
+
* driver is the sandbox's own (`createFunctionsDriver`), so a task behaves the same in both — its `ctx` is calls to the
|
|
6
|
+
* platform, `ctx.kv.change` the same loop, a refusal the same answer. What it does not share is the isolate: there are
|
|
7
|
+
* no limits here but the platform's clock, since this process is the space's alone.
|
|
8
|
+
*
|
|
9
|
+
* The bundle a request names is not asked for: the code is the one this runtime was started with.
|
|
10
|
+
*/
|
|
11
|
+
export declare const createRuntimeRunner: (definition?: FunctionsDefinition) => FunctionRunner;
|
|
@@ -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 };
|
|
@@ -9,13 +9,12 @@ export type ComponentProps = {
|
|
|
9
9
|
ssrResult?: SSRRenderResult;
|
|
10
10
|
sdkDevToolsStylePath?: string;
|
|
11
11
|
debugMode?: boolean;
|
|
12
|
-
/**
|
|
13
|
-
* markup here matches what the browser hydrates with. */
|
|
14
|
-
branding?: boolean;
|
|
15
|
-
/** The same degraded render, as the reason: the account behind this space is over its quota. */
|
|
12
|
+
/** Set when the metering adapter degrades this render: the account behind this space is over its quota. */
|
|
16
13
|
overQuota?: boolean;
|
|
17
14
|
/** The theme this document was rendered with, from the visitor's cookie. See `prepareRender`. */
|
|
18
15
|
theme?: Theme;
|
|
16
|
+
/** The kept state the first paint depends on (`settings.paintedState`), from the visitor's cookie. */
|
|
17
|
+
state?: Record<string, unknown>;
|
|
19
18
|
};
|
|
20
|
-
declare const Component: ({ server, renderMode, previewMode, offlineData, environment, plugins, ssrResult, sdkDevToolsStylePath, debugMode,
|
|
19
|
+
declare const Component: ({ server, renderMode, previewMode, offlineData, environment, plugins, ssrResult, sdkDevToolsStylePath, debugMode, overQuota, theme, state }: ComponentProps) => import('react').JSX.Element;
|
|
21
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,
|
|
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: {
|
|
@@ -18,9 +18,9 @@ var Component = ({ server, renderMode = "raw", previewMode = true, offlineData,
|
|
|
18
18
|
offlineData,
|
|
19
19
|
sdkDevToolsStylePath,
|
|
20
20
|
debugMode,
|
|
21
|
-
...branding === void 0 ? {} : { branding },
|
|
22
21
|
...overQuota === void 0 ? {} : { overQuota },
|
|
23
22
|
...theme === void 0 ? {} : { theme },
|
|
23
|
+
...state === void 0 ? {} : { state },
|
|
24
24
|
children: plugins && Object.keys(plugins).map((key) => /* @__PURE__ */ jsx(PlitziSdk.Plugin, {
|
|
25
25
|
renderType: key,
|
|
26
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
|
}
|