@plitzi/sdk-server 0.32.25 → 0.33.0
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 +12 -0
- package/README.md +326 -162
- package/dist/adapters/authAdapters.d.ts +21 -0
- package/dist/adapters/authAdapters.js +12 -0
- package/dist/adapters/jsonAdapters.d.ts +15 -0
- package/dist/adapters/jsonAdapters.js +9 -4
- package/dist/core/auth/api.d.ts +148 -0
- package/dist/core/auth/api.js +286 -0
- package/dist/core/auth/authorize.d.ts +96 -0
- package/dist/core/auth/authorize.js +92 -0
- package/dist/core/auth/createAuth.d.ts +165 -0
- package/dist/core/auth/createAuth.js +105 -0
- package/dist/core/auth/credentials.d.ts +29 -0
- package/dist/core/auth/credentials.js +48 -0
- package/dist/core/auth/domains.d.ts +41 -0
- package/dist/core/auth/domains.js +78 -0
- package/dist/core/auth/identity.d.ts +108 -0
- package/dist/core/auth/identity.js +164 -0
- package/dist/core/auth/oauth/client.d.ts +5 -0
- package/dist/core/auth/oauth/client.js +47 -0
- package/dist/core/auth/oauth/index.d.ts +78 -0
- package/dist/core/auth/oauth/index.js +113 -0
- package/dist/core/auth/oauth/providers/github.d.ts +2 -0
- package/dist/core/auth/oauth/providers/github.js +48 -0
- package/dist/core/auth/oauth/providers/google.d.ts +2 -0
- package/dist/core/auth/oauth/providers/google.js +30 -0
- package/dist/core/auth/oauth/state.d.ts +23 -0
- package/dist/core/auth/oauth/state.js +55 -0
- package/dist/core/auth/oauth/types.d.ts +51 -0
- package/dist/core/auth/oauth/types.js +13 -0
- package/dist/core/auth/routes.d.ts +50 -0
- package/dist/core/auth/routes.js +129 -0
- package/dist/core/auth/session.d.ts +128 -0
- package/dist/core/auth/session.js +165 -0
- package/dist/core/auth/spaceTokens.d.ts +137 -0
- package/dist/core/auth/spaceTokens.js +212 -0
- package/dist/core/auth/tokens.d.ts +151 -0
- package/dist/core/auth/tokens.js +221 -0
- package/dist/core/createServer.d.ts +29 -0
- package/dist/core/createServer.js +28 -14
- package/dist/core/handlers/authMiddleware.d.ts +27 -0
- package/dist/core/handlers/authMiddleware.js +38 -0
- package/dist/core/handlers/authRouteHandlers.d.ts +46 -0
- package/dist/core/handlers/authRouteHandlers.js +75 -0
- package/dist/core/handlers/types.d.ts +37 -0
- package/dist/{src/core → core}/http/dispatcher.d.ts +2 -2
- package/dist/core/http/dispatcher.js +8 -6
- package/dist/core/http/navigation.d.ts +11 -0
- package/dist/core/http/navigation.js +16 -0
- package/dist/core/http/securityHeaders.js +6 -4
- package/dist/core/http/stages/authApi.d.ts +17 -0
- package/dist/core/http/stages/authApi.js +66 -0
- package/dist/core/http/stages/authRoutes.js +40 -11
- package/dist/core/http/stages/exchangeRoute.d.ts +15 -0
- package/dist/core/http/stages/exchangeRoute.js +67 -0
- package/dist/core/http/stages/health.d.ts +11 -0
- package/dist/core/http/stages/health.js +25 -3
- package/dist/core/http/stages/middlewares.d.ts +2 -0
- package/dist/core/http/stages/static.d.ts +13 -0
- package/dist/core/http/stages/static.js +21 -6
- package/dist/core/http/types.d.ts +35 -0
- package/dist/{modules/mcp/constants.js → core/previewToken.js} +1 -1
- package/dist/core/sdkAssets.d.ts +16 -0
- package/dist/core/sdkAssets.js +46 -0
- package/dist/core/server/baseServer.js +40 -5
- package/dist/core/server/pageServer.d.ts +7 -0
- package/dist/core/server/pageServer.js +13 -17
- package/dist/core/services/action.d.ts +9 -0
- package/dist/core/services/action.js +21 -0
- package/dist/core/services/registry.d.ts +3 -0
- package/dist/core/services/registry.js +9 -19
- package/dist/{src/core → core}/services/resolve.d.ts +1 -0
- package/dist/core/services/resolve.js +6 -4
- package/dist/core/services/rsc.js +3 -2
- package/dist/core/staticFiles.js +1 -1
- package/dist/{src/core → core}/transports.d.ts +3 -0
- package/dist/core/transports.js +7 -6
- package/dist/handlers.d.ts +58 -0
- package/dist/handlers.js +3 -0
- package/dist/{src/helpers → helpers}/buildResponseHelpers.d.ts +2 -1
- package/dist/helpers/buildResponseHelpers.js +13 -4
- package/dist/helpers/buildServerInfo.d.ts +3 -0
- package/dist/helpers/buildServerInfo.js +25 -3
- package/dist/{src/helpers → helpers}/cache/keys.d.ts +5 -1
- package/dist/helpers/cache/keys.js +1 -1
- package/dist/helpers/compress.d.ts +18 -0
- package/dist/helpers/compress.js +47 -11
- package/dist/helpers/offlineDataLoader.d.ts +11 -0
- package/dist/helpers/offlineDataLoader.js +15 -0
- package/dist/helpers/resolveDebugMode.d.ts +10 -0
- package/dist/helpers/resolveDebugMode.js +13 -0
- package/dist/index.d.ts +16 -2
- package/dist/index.js +9 -20
- package/dist/kernel.d.ts +41 -0
- package/dist/kernel.js +22 -0
- package/dist/middlewares/spaceDeployment.d.ts +2 -0
- package/dist/middlewares/spaceDeployment.js +2 -1
- package/dist/modules/actions/handler.d.ts +11 -0
- package/dist/modules/actions/handler.js +77 -0
- package/dist/modules/connectors/engine.d.ts +42 -0
- package/dist/modules/connectors/engine.js +221 -0
- package/dist/modules/connectors/getByPath.d.ts +8 -0
- package/dist/modules/connectors/getByPath.js +21 -0
- package/dist/modules/connectors/index.d.ts +7 -0
- package/dist/modules/connectors/projection.d.ts +18 -0
- package/dist/modules/connectors/projection.js +108 -0
- package/dist/modules/connectors/resolver.d.ts +18 -0
- package/dist/modules/connectors/resolver.js +68 -0
- package/dist/modules/connectors/types.d.ts +19 -0
- package/dist/{src/modules → modules}/rsc/handler.d.ts +2 -2
- package/dist/modules/rsc/handler.js +54 -2
- package/dist/modules/rsc/resolveRscData.d.ts +35 -0
- package/dist/modules/rsc/resolveRscData.js +74 -0
- package/dist/{src/modules → modules}/ssr/Component.d.ts +4 -1
- package/dist/modules/ssr/Component.js +10 -3
- package/dist/modules/ssr/buildBody.d.ts +9 -0
- package/dist/modules/ssr/handler.d.ts +4 -0
- package/dist/modules/ssr/handler.js +18 -1
- package/dist/{src/modules → modules}/ssr/loadPluginComponents.d.ts +5 -2
- package/dist/modules/ssr/loadPluginComponents.js +20 -2
- package/dist/{src/modules → modules}/ssr/prepareRender.d.ts +2 -2
- package/dist/modules/ssr/prepareRender.js +24 -7
- package/dist/modules/ssr/preview.d.ts +10 -0
- package/dist/modules/ssr/preview.js +5 -78
- package/dist/modules/ssr/registerExternalPlugins.js +1 -1
- package/dist/modules/ssr/streamBody.d.ts +5 -0
- package/dist/modules/ssr/streamBody.js +1 -1
- package/dist/modules/ssr/template.d.ts +2 -0
- package/dist/modules/ssr/template.js +1 -1
- package/dist/plugins/compile.js +1 -1
- package/dist/plugins/manager.js +12 -8
- package/dist/ssr.d.ts +15 -0
- package/dist/ssr.js +4 -0
- package/package.json +29 -25
- package/dist/.gitkeep +0 -0
- package/dist/core/server/mcpServer.js +0 -29
- package/dist/core/services/mcp.js +0 -27
- package/dist/core/services/oauth.js +0 -116
- package/dist/core/services/preview.js +0 -37
- package/dist/core/services/proxy.js +0 -12
- package/dist/mcp.d.ts +0 -2
- package/dist/mcp.js +0 -7
- package/dist/modules/ai/AIEngine.js +0 -120
- package/dist/modules/ai/toolkit.js +0 -59
- package/dist/modules/mcp/apps/example/view/index.tsx +0 -70
- package/dist/modules/mcp/apps/index.js +0 -16
- package/dist/modules/mcp/apps/render/index.js +0 -17
- package/dist/modules/mcp/apps/render/styles.js +0 -54
- package/dist/modules/mcp/apps/render/view/heldBatch.ts +0 -107
- package/dist/modules/mcp/apps/render/view/index.tsx +0 -314
- package/dist/modules/mcp/apps/render/view/streamProgress.ts +0 -137
- package/dist/modules/mcp/apps/shared/assets.js +0 -10
- package/dist/modules/mcp/apps/shared/bundle.js +0 -23
- package/dist/modules/mcp/apps/shared/page.js +0 -34
- package/dist/modules/mcp/apps/shared/registerApp.js +0 -43
- package/dist/modules/mcp/apps/shared/resolve.js +0 -5
- package/dist/modules/mcp/apps/shared/shell.ejs +0 -59
- package/dist/modules/mcp/apps/shared/zodEnglishOnly.js +0 -23
- package/dist/modules/mcp/catalogs/builtinCallbacks.js +0 -204
- package/dist/modules/mcp/catalogs/builtinComponents.js +0 -170
- package/dist/modules/mcp/catalogs/builtinElementCallbacks.js +0 -50
- package/dist/modules/mcp/catalogs/builtinTransformers.js +0 -148
- package/dist/modules/mcp/catalogs/builtinUtilities.js +0 -90
- package/dist/modules/mcp/catalogs/cssCatalog/border.js +0 -30
- package/dist/modules/mcp/catalogs/cssCatalog/box.js +0 -31
- package/dist/modules/mcp/catalogs/cssCatalog/helpers.js +0 -185
- package/dist/modules/mcp/catalogs/cssCatalog/index.js +0 -131
- package/dist/modules/mcp/catalogs/cssCatalog/layout.js +0 -98
- package/dist/modules/mcp/catalogs/cssCatalog/visual.js +0 -144
- package/dist/modules/mcp/catalogs/observed.js +0 -90
- package/dist/modules/mcp/catalogs/paramSpec.js +0 -69
- package/dist/modules/mcp/catalogs/registry.js +0 -89
- package/dist/modules/mcp/handler.js +0 -83
- package/dist/modules/mcp/helpers/agentPrompt.js +0 -104
- package/dist/modules/mcp/helpers/computeVersion.js +0 -16
- package/dist/modules/mcp/helpers/guide.js +0 -467
- package/dist/modules/mcp/helpers/interactions.js +0 -123
- package/dist/modules/mcp/helpers/log.js +0 -64
- package/dist/modules/mcp/helpers/opResult.js +0 -18
- package/dist/modules/mcp/helpers/space.js +0 -300
- package/dist/modules/mcp/helpers/uris.js +0 -44
- package/dist/modules/mcp/previewClient.js +0 -31
- package/dist/modules/mcp/proxy/config.js +0 -63
- package/dist/modules/mcp/proxy/fetch.js +0 -91
- package/dist/modules/mcp/proxy/grant.js +0 -67
- package/dist/modules/mcp/proxy/guard.js +0 -38
- package/dist/modules/mcp/proxy/handler.js +0 -99
- package/dist/modules/mcp/proxy/payload.js +0 -29
- package/dist/modules/mcp/proxy/rewrite.js +0 -138
- package/dist/modules/mcp/proxy/sign.js +0 -15
- package/dist/modules/mcp/proxy/types.js +0 -9
- package/dist/modules/mcp/resources/canonical.js +0 -30
- package/dist/modules/mcp/resources/core.js +0 -18
- package/dist/modules/mcp/resources/envelope.js +0 -14
- package/dist/modules/mcp/resources/primer.js +0 -31
- package/dist/modules/mcp/resources/register.js +0 -190
- package/dist/modules/mcp/resources/renderGuide.js +0 -451
- package/dist/modules/mcp/resources/router.js +0 -37
- package/dist/modules/mcp/resources/schema.js +0 -43
- package/dist/modules/mcp/resources/style.js +0 -34
- package/dist/modules/mcp/screenshotClient.js +0 -47
- package/dist/modules/mcp/server.js +0 -113
- package/dist/modules/mcp/tools/apply/dispatch.js +0 -105
- package/dist/modules/mcp/tools/apply/index.js +0 -150
- package/dist/modules/mcp/tools/apply/writeResult.js +0 -37
- package/dist/modules/mcp/tools/index.js +0 -24
- package/dist/modules/mcp/tools/operations/index.js +0 -45
- package/dist/modules/mcp/tools/operations/schema/bindings/deleteBinding.js +0 -32
- package/dist/modules/mcp/tools/operations/schema/bindings/patchBinding.js +0 -36
- package/dist/modules/mcp/tools/operations/schema/bindings/upsertBinding.js +0 -47
- package/dist/modules/mcp/tools/operations/schema/elements/deleteElement.js +0 -29
- package/dist/modules/mcp/tools/operations/schema/elements/moveElement.js +0 -41
- package/dist/modules/mcp/tools/operations/schema/elements/patchElement.js +0 -58
- package/dist/modules/mcp/tools/operations/schema/elements/repeatElement.js +0 -148
- package/dist/modules/mcp/tools/operations/schema/elements/upsertElement.js +0 -65
- package/dist/modules/mcp/tools/operations/schema/folders/deleteFolder.js +0 -30
- package/dist/modules/mcp/tools/operations/schema/folders/upsertFolder.js +0 -49
- package/dist/modules/mcp/tools/operations/schema/interactions/deleteInteraction.js +0 -52
- package/dist/modules/mcp/tools/operations/schema/interactions/patchInteractionNode.js +0 -47
- package/dist/modules/mcp/tools/operations/schema/interactions/upsertInteractionFlow.js +0 -44
- package/dist/modules/mcp/tools/operations/schema/operations.js +0 -41
- package/dist/modules/mcp/tools/operations/schema/pages/deletePage.js +0 -25
- package/dist/modules/mcp/tools/operations/schema/pages/upsertPage.js +0 -75
- package/dist/modules/mcp/tools/operations/schema/settings/patchSettings.js +0 -45
- package/dist/modules/mcp/tools/operations/schema/shared.js +0 -122
- package/dist/modules/mcp/tools/operations/schema/translator.js +0 -215
- package/dist/modules/mcp/tools/operations/schema/variables/deleteVariable.js +0 -18
- package/dist/modules/mcp/tools/operations/schema/variables/upsertVariable.js +0 -42
- package/dist/modules/mcp/tools/operations/schema/write.js +0 -109
- package/dist/modules/mcp/tools/operations/schemaIds.js +0 -54
- package/dist/modules/mcp/tools/operations/style/definitions/deleteDefinition.js +0 -21
- package/dist/modules/mcp/tools/operations/style/definitions/patchDefinition.js +0 -28
- package/dist/modules/mcp/tools/operations/style/definitions/upsertDefinition.js +0 -24
- package/dist/modules/mcp/tools/operations/style/definitions/upsertDefinitions.js +0 -40
- package/dist/modules/mcp/tools/operations/style/globalStyles/deleteGlobalStyle.js +0 -21
- package/dist/modules/mcp/tools/operations/style/globalStyles/patchGlobalStyle.js +0 -28
- package/dist/modules/mcp/tools/operations/style/globalStyles/upsertGlobalStyle.js +0 -24
- package/dist/modules/mcp/tools/operations/style/idStyles/deleteIdStyle.js +0 -21
- package/dist/modules/mcp/tools/operations/style/idStyles/patchIdStyle.js +0 -28
- package/dist/modules/mcp/tools/operations/style/idStyles/upsertIdStyle.js +0 -24
- package/dist/modules/mcp/tools/operations/style/operations.js +0 -29
- package/dist/modules/mcp/tools/operations/style/shared.js +0 -59
- package/dist/modules/mcp/tools/operations/style/translator.js +0 -101
- package/dist/modules/mcp/tools/operations/style/variables/deleteStyleVariable.js +0 -21
- package/dist/modules/mcp/tools/operations/style/variables/upsertStyleVariable.js +0 -22
- package/dist/modules/mcp/tools/operations/style/write.js +0 -108
- package/dist/modules/mcp/tools/preview.js +0 -37
- package/dist/modules/mcp/tools/read.js +0 -51
- package/dist/modules/mcp/tools/render.js +0 -184
- package/dist/modules/mcp/tools/screenshot.js +0 -83
- package/dist/modules/mcp/tools/search.js +0 -115
- package/dist/modules/mcp/tools/shared/expandOperations.js +0 -44
- package/dist/modules/mcp/tools/shared/tool.js +0 -33
- package/dist/modules/mcp/tools/shared/validator/audit.js +0 -124
- package/dist/modules/mcp/tools/shared/validator/batch.js +0 -39
- package/dist/modules/mcp/tools/shared/validator/bindings.js +0 -70
- package/dist/modules/mcp/tools/shared/validator/context.js +0 -35
- package/dist/modules/mcp/tools/shared/validator/css.js +0 -39
- package/dist/modules/mcp/tools/shared/validator/elements.js +0 -68
- package/dist/modules/mcp/tools/shared/validator/index.js +0 -246
- package/dist/modules/mcp/tools/shared/validator/interactions.js +0 -103
- package/dist/modules/mcp/tools/shared/validator/refs.js +0 -28
- package/dist/modules/mcp/tools/validate.js +0 -47
- package/dist/modules/oauth/authorize.js +0 -177
- package/dist/modules/oauth/challenge.js +0 -33
- package/dist/modules/oauth/consentPage.js +0 -118
- package/dist/modules/oauth/metadata.js +0 -69
- package/dist/modules/oauth/params.js +0 -5
- package/dist/modules/oauth/pkce.js +0 -15
- package/dist/modules/oauth/records.js +0 -46
- package/dist/modules/oauth/register.js +0 -55
- package/dist/modules/oauth/respond.js +0 -44
- package/dist/modules/oauth/token.js +0 -100
- package/dist/public/.gitkeep +0 -0
- package/dist/src/adapters/jsonAdapters.d.ts +0 -7
- package/dist/src/core/createServer.d.ts +0 -14
- package/dist/src/core/http/stages/health.d.ts +0 -2
- package/dist/src/core/http/stages/middlewares.d.ts +0 -2
- package/dist/src/core/http/stages/static.d.ts +0 -5
- package/dist/src/core/http/types.d.ts +0 -22
- package/dist/src/core/server/mcpServer.d.ts +0 -2
- package/dist/src/core/server/pageServer.d.ts +0 -10
- package/dist/src/core/services/mcp.d.ts +0 -3
- package/dist/src/core/services/oauth.d.ts +0 -18
- package/dist/src/core/services/preview.d.ts +0 -2
- package/dist/src/core/services/proxy.d.ts +0 -2
- package/dist/src/core/services/registry.d.ts +0 -4
- package/dist/src/helpers/buildServerInfo.d.ts +0 -2
- package/dist/src/helpers/compress.d.ts +0 -3
- package/dist/src/index.d.ts +0 -15
- package/dist/src/mcp.d.ts +0 -14
- package/dist/src/middlewares/spaceDeployment.d.ts +0 -2
- package/dist/src/modules/ai/AIEngine.d.ts +0 -20
- package/dist/src/modules/ai/index.d.ts +0 -4
- package/dist/src/modules/ai/toolkit.d.ts +0 -17
- package/dist/src/modules/mcp/apps/example/index.d.ts +0 -8
- package/dist/src/modules/mcp/apps/index.d.ts +0 -11
- package/dist/src/modules/mcp/apps/render/index.d.ts +0 -4
- package/dist/src/modules/mcp/apps/render/styles.d.ts +0 -10
- package/dist/src/modules/mcp/apps/shared/assets.d.ts +0 -10
- package/dist/src/modules/mcp/apps/shared/bundle.d.ts +0 -4
- package/dist/src/modules/mcp/apps/shared/index.d.ts +0 -3
- package/dist/src/modules/mcp/apps/shared/page.d.ts +0 -2
- package/dist/src/modules/mcp/apps/shared/registerApp.d.ts +0 -5
- package/dist/src/modules/mcp/apps/shared/resolve.d.ts +0 -1
- package/dist/src/modules/mcp/apps/shared/zodEnglishOnly.d.ts +0 -4
- package/dist/src/modules/mcp/catalogs/builtinCallbacks.d.ts +0 -23
- package/dist/src/modules/mcp/catalogs/builtinComponents.d.ts +0 -4
- package/dist/src/modules/mcp/catalogs/builtinElementCallbacks.d.ts +0 -20
- package/dist/src/modules/mcp/catalogs/builtinTransformers.d.ts +0 -28
- package/dist/src/modules/mcp/catalogs/builtinUtilities.d.ts +0 -18
- package/dist/src/modules/mcp/catalogs/cssCatalog/border.d.ts +0 -4
- package/dist/src/modules/mcp/catalogs/cssCatalog/box.d.ts +0 -4
- package/dist/src/modules/mcp/catalogs/cssCatalog/helpers.d.ts +0 -34
- package/dist/src/modules/mcp/catalogs/cssCatalog/index.d.ts +0 -19
- package/dist/src/modules/mcp/catalogs/cssCatalog/layout.d.ts +0 -9
- package/dist/src/modules/mcp/catalogs/cssCatalog/visual.d.ts +0 -8
- package/dist/src/modules/mcp/catalogs/index.d.ts +0 -9
- package/dist/src/modules/mcp/catalogs/observed.d.ts +0 -48
- package/dist/src/modules/mcp/catalogs/paramSpec.d.ts +0 -42
- package/dist/src/modules/mcp/catalogs/registry.d.ts +0 -35
- package/dist/src/modules/mcp/e2e/index.d.ts +0 -6
- package/dist/src/modules/mcp/e2e/mcpEndpoint.d.ts +0 -27
- package/dist/src/modules/mcp/e2e/postMessageChannel.d.ts +0 -22
- package/dist/src/modules/mcp/e2e/renderingHost.d.ts +0 -34
- package/dist/src/modules/mcp/handler.d.ts +0 -22
- package/dist/src/modules/mcp/helpers/agentPrompt.d.ts +0 -4
- package/dist/src/modules/mcp/helpers/computeVersion.d.ts +0 -1
- package/dist/src/modules/mcp/helpers/guide.d.ts +0 -4
- package/dist/src/modules/mcp/helpers/index.d.ts +0 -8
- package/dist/src/modules/mcp/helpers/interactions.d.ts +0 -30
- package/dist/src/modules/mcp/helpers/log.d.ts +0 -8
- package/dist/src/modules/mcp/helpers/opResult.d.ts +0 -13
- package/dist/src/modules/mcp/helpers/space.d.ts +0 -115
- package/dist/src/modules/mcp/helpers/uris.d.ts +0 -28
- package/dist/src/modules/mcp/index.d.ts +0 -13
- package/dist/src/modules/mcp/previewClient.d.ts +0 -13
- package/dist/src/modules/mcp/proxy/config.d.ts +0 -19
- package/dist/src/modules/mcp/proxy/fetch.d.ts +0 -18
- package/dist/src/modules/mcp/proxy/grant.d.ts +0 -25
- package/dist/src/modules/mcp/proxy/guard.d.ts +0 -6
- package/dist/src/modules/mcp/proxy/handler.d.ts +0 -8
- package/dist/src/modules/mcp/proxy/index.d.ts +0 -8
- package/dist/src/modules/mcp/proxy/payload.d.ts +0 -8
- package/dist/src/modules/mcp/proxy/rewrite.d.ts +0 -18
- package/dist/src/modules/mcp/proxy/sign.d.ts +0 -6
- package/dist/src/modules/mcp/proxy/types.d.ts +0 -45
- package/dist/src/modules/mcp/resources/canonical.d.ts +0 -6
- package/dist/src/modules/mcp/resources/core.d.ts +0 -5
- package/dist/src/modules/mcp/resources/envelope.d.ts +0 -10
- package/dist/src/modules/mcp/resources/index.d.ts +0 -8
- package/dist/src/modules/mcp/resources/primer.d.ts +0 -7
- package/dist/src/modules/mcp/resources/register.d.ts +0 -10
- package/dist/src/modules/mcp/resources/renderGuide.d.ts +0 -10
- package/dist/src/modules/mcp/resources/router.d.ts +0 -10
- package/dist/src/modules/mcp/resources/schema.d.ts +0 -5
- package/dist/src/modules/mcp/resources/style.d.ts +0 -5
- package/dist/src/modules/mcp/screenshotClient.d.ts +0 -13
- package/dist/src/modules/mcp/server.d.ts +0 -31
- package/dist/src/modules/mcp/tests/helpers.d.ts +0 -13
- package/dist/src/modules/mcp/tools/apply/dispatch.d.ts +0 -6
- package/dist/src/modules/mcp/tools/apply/index.d.ts +0 -470
- package/dist/src/modules/mcp/tools/apply/writeResult.d.ts +0 -8
- package/dist/src/modules/mcp/tools/index.d.ts +0 -18
- package/dist/src/modules/mcp/tools/operations/index.d.ts +0 -928
- package/dist/src/modules/mcp/tools/operations/schema/bindings/deleteBinding.d.ts +0 -17
- package/dist/src/modules/mcp/tools/operations/schema/bindings/patchBinding.d.ts +0 -25
- package/dist/src/modules/mcp/tools/operations/schema/bindings/upsertBinding.d.ts +0 -27
- package/dist/src/modules/mcp/tools/operations/schema/elements/deleteElement.d.ts +0 -10
- package/dist/src/modules/mcp/tools/operations/schema/elements/moveElement.d.ts +0 -16
- package/dist/src/modules/mcp/tools/operations/schema/elements/patchElement.d.ts +0 -22
- package/dist/src/modules/mcp/tools/operations/schema/elements/repeatElement.d.ts +0 -55
- package/dist/src/modules/mcp/tools/operations/schema/elements/upsertElement.d.ts +0 -16
- package/dist/src/modules/mcp/tools/operations/schema/folders/deleteFolder.d.ts +0 -9
- package/dist/src/modules/mcp/tools/operations/schema/folders/upsertFolder.d.ts +0 -12
- package/dist/src/modules/mcp/tools/operations/schema/index.d.ts +0 -21
- package/dist/src/modules/mcp/tools/operations/schema/interactions/deleteInteraction.d.ts +0 -12
- package/dist/src/modules/mcp/tools/operations/schema/interactions/patchInteractionNode.d.ts +0 -18
- package/dist/src/modules/mcp/tools/operations/schema/interactions/upsertInteractionFlow.d.ts +0 -27
- package/dist/src/modules/mcp/tools/operations/schema/operations.d.ts +0 -229
- package/dist/src/modules/mcp/tools/operations/schema/pages/deletePage.d.ts +0 -9
- package/dist/src/modules/mcp/tools/operations/schema/pages/upsertPage.d.ts +0 -14
- package/dist/src/modules/mcp/tools/operations/schema/settings/patchSettings.d.ts +0 -34
- package/dist/src/modules/mcp/tools/operations/schema/shared.d.ts +0 -92
- package/dist/src/modules/mcp/tools/operations/schema/translator.d.ts +0 -12
- package/dist/src/modules/mcp/tools/operations/schema/variables/deleteVariable.d.ts +0 -9
- package/dist/src/modules/mcp/tools/operations/schema/variables/upsertVariable.d.ts +0 -16
- package/dist/src/modules/mcp/tools/operations/schema/write.d.ts +0 -42
- package/dist/src/modules/mcp/tools/operations/schemaIds.d.ts +0 -6
- package/dist/src/modules/mcp/tools/operations/style/definitions/deleteDefinition.d.ts +0 -9
- package/dist/src/modules/mcp/tools/operations/style/definitions/patchDefinition.d.ts +0 -37
- package/dist/src/modules/mcp/tools/operations/style/definitions/upsertDefinition.d.ts +0 -37
- package/dist/src/modules/mcp/tools/operations/style/definitions/upsertDefinitions.d.ts +0 -41
- package/dist/src/modules/mcp/tools/operations/style/globalStyles/deleteGlobalStyle.d.ts +0 -9
- package/dist/src/modules/mcp/tools/operations/style/globalStyles/patchGlobalStyle.d.ts +0 -37
- package/dist/src/modules/mcp/tools/operations/style/globalStyles/upsertGlobalStyle.d.ts +0 -37
- package/dist/src/modules/mcp/tools/operations/style/idStyles/deleteIdStyle.d.ts +0 -9
- package/dist/src/modules/mcp/tools/operations/style/idStyles/patchIdStyle.d.ts +0 -37
- package/dist/src/modules/mcp/tools/operations/style/idStyles/upsertIdStyle.d.ts +0 -37
- package/dist/src/modules/mcp/tools/operations/style/index.d.ts +0 -15
- package/dist/src/modules/mcp/tools/operations/style/operations.d.ts +0 -264
- package/dist/src/modules/mcp/tools/operations/style/shared.d.ts +0 -116
- package/dist/src/modules/mcp/tools/operations/style/translator.d.ts +0 -12
- package/dist/src/modules/mcp/tools/operations/style/variables/deleteStyleVariable.d.ts +0 -15
- package/dist/src/modules/mcp/tools/operations/style/variables/upsertStyleVariable.d.ts +0 -20
- package/dist/src/modules/mcp/tools/operations/style/write.d.ts +0 -12
- package/dist/src/modules/mcp/tools/preview.d.ts +0 -465
- package/dist/src/modules/mcp/tools/read.d.ts +0 -9
- package/dist/src/modules/mcp/tools/render.d.ts +0 -499
- package/dist/src/modules/mcp/tools/render.test.d.ts +0 -1
- package/dist/src/modules/mcp/tools/screenshot.d.ts +0 -470
- package/dist/src/modules/mcp/tools/search.d.ts +0 -15
- package/dist/src/modules/mcp/tools/shared/expandOperations.d.ts +0 -13
- package/dist/src/modules/mcp/tools/shared/tool.d.ts +0 -72
- package/dist/src/modules/mcp/tools/shared/validator/audit.d.ts +0 -4
- package/dist/src/modules/mcp/tools/shared/validator/batch.d.ts +0 -5
- package/dist/src/modules/mcp/tools/shared/validator/bindings.d.ts +0 -6
- package/dist/src/modules/mcp/tools/shared/validator/context.d.ts +0 -38
- package/dist/src/modules/mcp/tools/shared/validator/css.d.ts +0 -4
- package/dist/src/modules/mcp/tools/shared/validator/elements.d.ts +0 -7
- package/dist/src/modules/mcp/tools/shared/validator/index.d.ts +0 -8
- package/dist/src/modules/mcp/tools/shared/validator/interactions.d.ts +0 -3
- package/dist/src/modules/mcp/tools/shared/validator/refs.d.ts +0 -4
- package/dist/src/modules/mcp/tools/validate.d.ts +0 -467
- package/dist/src/modules/mcp/types/aiSchema.d.ts +0 -218
- package/dist/src/modules/mcp/types/appTypes.d.ts +0 -26
- package/dist/src/modules/mcp/types/index.d.ts +0 -5
- package/dist/src/modules/mcp/types/previewTypes.d.ts +0 -25
- package/dist/src/modules/mcp/types/screenshotTypes.d.ts +0 -29
- package/dist/src/modules/mcp/types/toolTypes.d.ts +0 -138
- package/dist/src/modules/oauth/authorize.d.ts +0 -7
- package/dist/src/modules/oauth/challenge.d.ts +0 -11
- package/dist/src/modules/oauth/consentPage.d.ts +0 -7
- package/dist/src/modules/oauth/metadata.d.ts +0 -40
- package/dist/src/modules/oauth/params.d.ts +0 -5
- package/dist/src/modules/oauth/pkce.d.ts +0 -6
- package/dist/src/modules/oauth/records.d.ts +0 -71
- package/dist/src/modules/oauth/register.d.ts +0 -5
- package/dist/src/modules/oauth/respond.d.ts +0 -13
- package/dist/src/modules/oauth/token.d.ts +0 -5
- package/dist/src/modules/ssr/buildBody.d.ts +0 -9
- package/dist/src/modules/ssr/handler.d.ts +0 -4
- package/dist/src/modules/ssr/preview.d.ts +0 -16
- package/dist/src/modules/ssr/streamBody.d.ts +0 -5
- package/dist/src/modules/ssr/template.d.ts +0 -6
- package/dist/src/standalone/alias-loader.d.mts +0 -2
- package/dist/src/standalone/plugins/ClientInfo.d.ts +0 -2
- package/dist/src/standalone/plugins/ServerInfo.d.ts +0 -2
- package/dist/src/standalone/plugins/SharedInfo.d.ts +0 -2
- package/dist/src/standalone/plugins/styles.d.ts +0 -5
- package/dist/src/standalone/register-alias.d.mts +0 -1
- package/dist/src/standalone/server.d.ts +0 -1
- package/dist/src/standalone/stubs/react-syntax-highlighter.d.mts +0 -31
- package/skills/plitzi-render/SKILL.md +0 -174
- /package/dist/{src/core/http/dispatcher.test.d.ts → core/auth/api.test.d.ts} +0 -0
- /package/dist/{src/core/server/mcpServer.test.d.ts → core/auth/authorize.test.d.ts} +0 -0
- /package/dist/{src/modules/ai/toolkit.test.d.ts → core/auth/createAuth.test.d.ts} +0 -0
- /package/dist/{src/modules/mcp/apps/apps.test.d.ts → core/auth/domains.test.d.ts} +0 -0
- /package/dist/{src/modules/mcp/apps/render/styles.test.d.ts → core/auth/identity.test.d.ts} +0 -0
- /package/dist/{src/modules → core/auth}/oauth/oauth.test.d.ts +0 -0
- /package/dist/{src/modules/mcp/catalogs/builtinTransformers.test.d.ts → core/auth/routes.test.d.ts} +0 -0
- /package/dist/{src/modules/mcp/catalogs/cssCatalog/cssCatalog.test.d.ts → core/auth/session.test.d.ts} +0 -0
- /package/dist/{src/modules/mcp/e2e/connector.test.d.ts → core/auth/spaceTokens.test.d.ts} +0 -0
- /package/dist/{src/modules/mcp/e2e/host.test.d.ts → core/auth/tokens.test.d.ts} +0 -0
- /package/dist/{src/modules/mcp/e2e/oauthConnector.test.d.ts → core/createServer.test.d.ts} +0 -0
- /package/dist/{src/modules/mcp/helpers/log.test.d.ts → core/handlers/handlers.test.d.ts} +0 -0
- /package/dist/{src/core → core}/health.d.ts +0 -0
- /package/dist/{src/modules/mcp/mcp.bench.d.ts → core/http/dispatcher.test.d.ts} +0 -0
- /package/dist/{src/core → core}/http/securityHeaders.d.ts +0 -0
- /package/dist/{src/core → core}/http/stages/authRoutes.d.ts +0 -0
- /package/dist/{src/core → core}/http/stages/pluginAssets.d.ts +0 -0
- /package/dist/{src/core → core}/mimeTypes.d.ts +0 -0
- /package/dist/{src/modules/mcp/constants.d.ts → core/previewToken.d.ts} +0 -0
- /package/dist/{src/core → core}/requestParser.d.ts +0 -0
- /package/dist/{src/core → core}/server/baseServer.d.ts +0 -0
- /package/dist/{src/modules/mcp/proxy/endpoint.test.d.ts → core/server/baseServer.test.d.ts} +0 -0
- /package/dist/{src/modules/mcp/proxy/proxy.test.d.ts → core/services/resolve.test.d.ts} +0 -0
- /package/dist/{src/core → core}/services/rsc.d.ts +0 -0
- /package/dist/{src/core → core}/services/ssr.d.ts +0 -0
- /package/dist/{src/core → core}/staticFiles.d.ts +0 -0
- /package/dist/{src/modules/mcp/proxy/wiring.test.d.ts → helpers/buildResponseHelpers.test.d.ts} +0 -0
- /package/dist/{src/helpers → helpers}/cache/TtlCache.d.ts +0 -0
- /package/dist/{src/helpers → helpers}/cache/cacheManager.d.ts +0 -0
- /package/dist/{src/helpers → helpers}/cache/defaults.d.ts +0 -0
- /package/dist/{src/helpers → helpers}/cache/index.d.ts +0 -0
- /package/dist/{src/modules/mcp/tests/apply.test.d.ts → helpers/cache/keys.test.d.ts} +0 -0
- /package/dist/{src/helpers → helpers}/cache/serverCaches.d.ts +0 -0
- /package/dist/{src/modules/mcp/tests/bindings.test.d.ts → helpers/compress.test.d.ts} +0 -0
- /package/dist/{src/helpers → helpers}/escapeJson.d.ts +0 -0
- /package/dist/{src/helpers → helpers}/metrics.d.ts +0 -0
- /package/dist/{src/helpers → helpers}/normalizePlugins.d.ts +0 -0
- /package/dist/{src/modules/mcp/tests/css.test.d.ts → helpers/offlineDataLoader.test.d.ts} +0 -0
- /package/dist/{src/helpers → helpers}/readCookie.d.ts +0 -0
- /package/dist/{src/modules/mcp/tests/interactions.test.d.ts → helpers/resolveDebugMode.test.d.ts} +0 -0
- /package/dist/{src/helpers → helpers}/runMiddlewares.d.ts +0 -0
- /package/dist/{src/helpers → helpers}/serverLog.d.ts +0 -0
- /package/dist/{src/middlewares → middlewares}/auth.d.ts +0 -0
- /package/dist/{src/middlewares → middlewares}/basicAuth.d.ts +0 -0
- /package/dist/{src/modules/mcp/tests/pages.test.d.ts → middlewares/spaceDeployment.test.d.ts} +0 -0
- /package/dist/{src/modules/mcp/tests/reads.test.d.ts → modules/actions/handler.test.d.ts} +0 -0
- /package/dist/{src/modules/mcp/tests/schemaIds.test.d.ts → modules/connectors/engine.test.d.ts} +0 -0
- /package/dist/{src/modules/mcp/tests/search.test.d.ts → modules/connectors/projection.test.d.ts} +0 -0
- /package/dist/{src/modules/mcp/tests/skill.test.d.ts → modules/connectors/resolver.test.d.ts} +0 -0
- /package/dist/{src/modules/mcp/tests/styles.test.d.ts → modules/rsc/resolveRscData.test.d.ts} +0 -0
- /package/dist/{src/modules → modules}/ssr/applySSRResult.d.ts +0 -0
- /package/dist/{src/modules/mcp/tests/tools.test.d.ts → modules/ssr/loadPluginComponents.test.d.ts} +0 -0
- /package/dist/{src/modules/mcp/tests/validation.test.d.ts → modules/ssr/metering.test.d.ts} +0 -0
- /package/dist/{src/modules → modules}/ssr/registerExternalPlugins.d.ts +0 -0
- /package/dist/{src/plugins → plugins}/compile.d.ts +0 -0
- /package/dist/{src/plugins → plugins}/copy.d.ts +0 -0
- /package/dist/{src/plugins → plugins}/detect.d.ts +0 -0
- /package/dist/{src/plugins → plugins}/manager.d.ts +0 -0
- /package/dist/{src/plugins → plugins}/validate.d.ts +0 -0
- /package/dist/{src/plugins → plugins}/validate.test.d.ts +0 -0
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
//#region src/core/auth/authorize.ts
|
|
2
|
+
var matches = (path, matchers) => matchers.some((matcher) => {
|
|
3
|
+
if (matcher instanceof RegExp) return matcher.test(path);
|
|
4
|
+
return typeof matcher === "function" ? matcher(path) : matcher === path;
|
|
5
|
+
});
|
|
6
|
+
var requirementFor = (policy, path) => policy.rules.find((rule) => matches(path, rule.match))?.requirement ?? policy.fallback;
|
|
7
|
+
/**
|
|
8
|
+
* Decides whether a request may proceed, and with what identity — the same decision on every transport, which is
|
|
9
|
+
* the point of it living here rather than inside one framework's middleware. Callers bind it to their own: Express
|
|
10
|
+
* puts the result on `req` and answers 401 itself, this server's pipeline does the same with its own response.
|
|
11
|
+
*/
|
|
12
|
+
var createAuthorizer = (identity, policy) => async (carrier, path) => {
|
|
13
|
+
const requirement = requirementFor(policy, path);
|
|
14
|
+
if (requirement === "public") return { ok: true };
|
|
15
|
+
const [actorResult, grantResult] = await Promise.all([identity.resolveActor(carrier), identity.resolveGrant(carrier)]);
|
|
16
|
+
const actor = actorResult.ok && actorResult.actor.verified ? actorResult.actor : void 0;
|
|
17
|
+
const grant = grantResult.ok ? grantResult.grant : void 0;
|
|
18
|
+
if ((requirement === "grant" || requirement === "grant+actor") && !grant) return {
|
|
19
|
+
ok: false,
|
|
20
|
+
status: 401,
|
|
21
|
+
reason: grantResult.ok ? "missing" : grantResult.reason
|
|
22
|
+
};
|
|
23
|
+
if (requirement === "actor" || requirement === "grant+actor") {
|
|
24
|
+
if (!actorResult.ok) return {
|
|
25
|
+
ok: false,
|
|
26
|
+
status: 401,
|
|
27
|
+
reason: actorResult.reason
|
|
28
|
+
};
|
|
29
|
+
if (!actor) return {
|
|
30
|
+
ok: false,
|
|
31
|
+
status: 401,
|
|
32
|
+
reason: "inactive"
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
return {
|
|
36
|
+
ok: true,
|
|
37
|
+
actor,
|
|
38
|
+
grant
|
|
39
|
+
};
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* A global capability, checked off the actor the guard already resolved — no query. This is the whole of RBAC that
|
|
43
|
+
* applies outside a space: platform-wide routes rather than "may you touch this space", which is `identity.can()` and
|
|
44
|
+
* needs the membership half too.
|
|
45
|
+
*
|
|
46
|
+
* An answer rather than a middleware, so it reads the same from any host. The distinction it exists to make is 401
|
|
47
|
+
* against 403: "nobody is here" and "you are here and this is not yours" are different facts, and collapsing them
|
|
48
|
+
* tells a signed-in caller to sign in again.
|
|
49
|
+
*/
|
|
50
|
+
var checkPermission = (actor, permission) => {
|
|
51
|
+
if (!actor?.id) return {
|
|
52
|
+
ok: false,
|
|
53
|
+
status: 401,
|
|
54
|
+
error: "Not authenticated"
|
|
55
|
+
};
|
|
56
|
+
if (!actor.permissions.includes(permission)) return {
|
|
57
|
+
ok: false,
|
|
58
|
+
status: 403,
|
|
59
|
+
error: "Insufficient permissions"
|
|
60
|
+
};
|
|
61
|
+
return { ok: true };
|
|
62
|
+
};
|
|
63
|
+
/**
|
|
64
|
+
* The space half: may this actor act on this space at all, and is being its owner required?
|
|
65
|
+
*
|
|
66
|
+
* The answer that matters is the middle one. A non-member gets **404, not 403** — telling a stranger "you may not
|
|
67
|
+
* touch this space" confirms the space exists, and whether a given slug belongs to somebody is not a fact an
|
|
68
|
+
* outsider gets to establish by asking. Owners and members are told apart afterwards, because by then the caller has
|
|
69
|
+
* already proved they belong there and 403 gives away nothing.
|
|
70
|
+
*
|
|
71
|
+
* Resolving the membership is the deployment's — its tables, and whether a route names a space by id or by slug.
|
|
72
|
+
*/
|
|
73
|
+
var checkSpaceAccess = (actor, membership, { owner = false } = {}) => {
|
|
74
|
+
if (!actor?.id) return {
|
|
75
|
+
ok: false,
|
|
76
|
+
status: 401,
|
|
77
|
+
error: "Not authenticated"
|
|
78
|
+
};
|
|
79
|
+
if (!membership) return {
|
|
80
|
+
ok: false,
|
|
81
|
+
status: 404,
|
|
82
|
+
error: "Space not found"
|
|
83
|
+
};
|
|
84
|
+
if (owner && !membership.isOwner) return {
|
|
85
|
+
ok: false,
|
|
86
|
+
status: 403,
|
|
87
|
+
error: "Insufficient permissions"
|
|
88
|
+
};
|
|
89
|
+
return { ok: true };
|
|
90
|
+
};
|
|
91
|
+
//#endregion
|
|
92
|
+
export { checkPermission, checkSpaceAccess, createAuthorizer, requirementFor };
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import { AccountAdapters, AuthApiConfig } from './api';
|
|
2
|
+
import { AuthPolicy, Requirement } from './authorize';
|
|
3
|
+
import { CredentialCarrier } from './credentials';
|
|
4
|
+
import { IdentityAdapters, IdentityConfig } from './identity';
|
|
5
|
+
import { TokenConfig } from './tokens';
|
|
6
|
+
import { SSRAuthCookie, SSRSession, SSRUser } from '@plitzi/sdk-shared';
|
|
7
|
+
/**
|
|
8
|
+
* Everything a deployment says about its own auth, in one object.
|
|
9
|
+
*
|
|
10
|
+
* The pieces underneath stay exported and composable — a host that wants to build the identity resolver alone, or
|
|
11
|
+
* swap one stage, still can. This exists because assembling them is not where anybody's judgement should go: there
|
|
12
|
+
* is one correct order, and the two facts that appear in more than one place have to agree.
|
|
13
|
+
*
|
|
14
|
+
* The cookie name is the one that mattered. It was stated twice — once for the readers that pull a credential off a
|
|
15
|
+
* request, once for the writers that put it there — and a deployment that changed one and not the other wrote its
|
|
16
|
+
* session under a name nothing read it back from. A session that silently does not exist, from a typo. Here it is
|
|
17
|
+
* said once and both sides derive from it.
|
|
18
|
+
*/
|
|
19
|
+
export interface AuthConfig {
|
|
20
|
+
/** The signing secret and the issuer that separate this deployment's credentials from every other's. */
|
|
21
|
+
tokens: TokenConfig;
|
|
22
|
+
/**
|
|
23
|
+
* What this deployment calls its session cookies, and where they are scoped. Defaults derive from the request
|
|
24
|
+
* host, which is right for a single-host deployment and wrong the moment an app and an API share a domain.
|
|
25
|
+
*/
|
|
26
|
+
cookie?: SSRAuthCookie;
|
|
27
|
+
/**
|
|
28
|
+
* The stores auth reads and writes. Identity is what the guard needs on every request; the account half is what
|
|
29
|
+
* the `/auth` flows need, and **what is absent decides what this deployment offers** — no `createAccount`, no
|
|
30
|
+
* signup, and the route answers 404 rather than failing at runtime.
|
|
31
|
+
*/
|
|
32
|
+
adapters: IdentityAdapters & AccountAdapters;
|
|
33
|
+
/** This deployment's own hosts and origins, and how it logs a refusal. */
|
|
34
|
+
identity?: IdentityConfig;
|
|
35
|
+
/** Password hashing, token generation, and which flows to offer at all. */
|
|
36
|
+
api?: AuthApiConfig;
|
|
37
|
+
/** Where the `/auth` flows are mounted, so the policy matches the routes. Default `/auth`. */
|
|
38
|
+
basePath?: string;
|
|
39
|
+
/** What a path with no rule of its own requires. Default `actor` — anything unlisted needs a session. */
|
|
40
|
+
fallback?: Requirement;
|
|
41
|
+
/** Extra rules, applied BEFORE the derived `/auth` ones so a deployment can always widen its own surface. */
|
|
42
|
+
rules?: AuthPolicy['rules'];
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* The whole auth cycle, wired.
|
|
46
|
+
*
|
|
47
|
+
* ```ts
|
|
48
|
+
* const auth = createAuth({
|
|
49
|
+
* tokens: { secret, issuer: 'https://acme.test', audience: ['https://api.acme.test'] },
|
|
50
|
+
* cookie: { name: 'acme_session' },
|
|
51
|
+
* adapters: myStore
|
|
52
|
+
* });
|
|
53
|
+
*
|
|
54
|
+
* // guard every request
|
|
55
|
+
* const result = await auth.authorize(req, req.url);
|
|
56
|
+
* // serve the flows
|
|
57
|
+
* for (const { method, path, handler } of auth.routes) { … }
|
|
58
|
+
* ```
|
|
59
|
+
*/
|
|
60
|
+
export declare const createAuth: (config: AuthConfig) => {
|
|
61
|
+
tokens: {
|
|
62
|
+
lifetimes: {
|
|
63
|
+
access: 86400;
|
|
64
|
+
refresh: number;
|
|
65
|
+
agent: number;
|
|
66
|
+
widget: number;
|
|
67
|
+
};
|
|
68
|
+
generateUserToken: (userId: number | string) => string;
|
|
69
|
+
generateRefreshToken: (userId: number | string) => string;
|
|
70
|
+
generateWidgetToken: () => string;
|
|
71
|
+
generateSpaceToken: (spaceId: number | string, origins: string[], scope?: import('./tokens').SpaceScope, { expiresAt }?: import('./tokens').SpaceTokenOptions) => string;
|
|
72
|
+
verifyUserToken: (token: string) => import('./tokens').VerifyResult<import('./tokens').UserTokenPayload>;
|
|
73
|
+
verifyRefreshToken: (token: string) => import('./tokens').VerifyResult<import('./tokens').RefreshTokenPayload>;
|
|
74
|
+
verifyWidgetToken: (token: string) => import('./tokens').VerifyResult<import('./tokens').WidgetTokenPayload>;
|
|
75
|
+
verifySpaceToken: (token: string) => import('./tokens').VerifyResult<import('./tokens').SpaceTokenPayload & {
|
|
76
|
+
spaceId: number;
|
|
77
|
+
spaceScope: import('./tokens').SpaceScope;
|
|
78
|
+
}>;
|
|
79
|
+
needsRotation: (token: string) => boolean;
|
|
80
|
+
expiresInSeconds: (token: string) => number | undefined;
|
|
81
|
+
};
|
|
82
|
+
identity: {
|
|
83
|
+
resolveActor: (carrier: CredentialCarrier) => Promise<import('./identity').ActorResult>;
|
|
84
|
+
resolveActorFromToken: (token: string) => Promise<import('./identity').ActorResult>;
|
|
85
|
+
resolveGrant: (carrier: CredentialCarrier, options?: import('./identity').GrantOptions) => Promise<import('./identity').GrantResult>;
|
|
86
|
+
resolveGrantFromToken: (token: string, origin: string, { skipOrigin, host }?: import('./identity').GrantOptions) => Promise<import('./identity').GrantResult>;
|
|
87
|
+
can: (actor: import('./identity').Actor, spaceId: number, permission: string) => Promise<boolean>;
|
|
88
|
+
grantCan: (grant: import('./identity').Grant, permission: string) => Promise<boolean>;
|
|
89
|
+
};
|
|
90
|
+
api: {
|
|
91
|
+
capabilities: {
|
|
92
|
+
passwordLogin: boolean;
|
|
93
|
+
refresh: boolean;
|
|
94
|
+
signup: boolean;
|
|
95
|
+
passwordReset: boolean;
|
|
96
|
+
emailVerification: boolean;
|
|
97
|
+
exchange: boolean;
|
|
98
|
+
};
|
|
99
|
+
describe: () => import('./api').AuthOutcome;
|
|
100
|
+
session: (actor?: import('./identity').Actor) => import('./api').AuthOutcome;
|
|
101
|
+
login: (credentials: Record<string, unknown>) => Promise<import('./api').AuthOutcome>;
|
|
102
|
+
refresh: (refreshToken?: string) => Promise<import('./api').AuthOutcome>;
|
|
103
|
+
logout: (credentials: {
|
|
104
|
+
accessToken?: string;
|
|
105
|
+
refreshToken?: string;
|
|
106
|
+
}) => Promise<import('./api').AuthOutcome>;
|
|
107
|
+
revokeSessions: (userId?: number) => Promise<import('./api').AuthOutcome>;
|
|
108
|
+
exchange: (provider: string, token: string, carrier: CredentialCarrier) => Promise<import('./api').AuthOutcome>;
|
|
109
|
+
signup: (fields: Record<string, unknown>) => Promise<import('./api').AuthOutcome>;
|
|
110
|
+
forgotPassword: (email: string) => Promise<import('./api').AuthOutcome>;
|
|
111
|
+
resetPassword: (token: string, password: string) => Promise<import('./api').AuthOutcome>;
|
|
112
|
+
validateAccount: (token: string) => Promise<import('./api').AuthOutcome>;
|
|
113
|
+
resendVerification: (email: string) => Promise<import('./api').AuthOutcome>;
|
|
114
|
+
issueSession: (userId: number) => Promise<SSRSession>;
|
|
115
|
+
resolveActor: (carrier: CredentialCarrier) => Promise<import('./identity').ActorResult>;
|
|
116
|
+
};
|
|
117
|
+
cookies: {
|
|
118
|
+
write: (req: {
|
|
119
|
+
hostname: string;
|
|
120
|
+
}, res: import('./session').CookieSink, session: SSRSession) => void;
|
|
121
|
+
clear: (req: {
|
|
122
|
+
hostname: string;
|
|
123
|
+
}, res: import('./session').CookieSink) => void;
|
|
124
|
+
writeFlow: (req: {
|
|
125
|
+
hostname: string;
|
|
126
|
+
}, res: import('./session').CookieSink, value: string, ttlSeconds: number) => void;
|
|
127
|
+
clearFlow: (req: {
|
|
128
|
+
hostname: string;
|
|
129
|
+
}, res: import('./session').CookieSink) => void;
|
|
130
|
+
readFlow: (req: import('./session').CookieCarrier) => string | undefined;
|
|
131
|
+
resolveSessionToken: (req: import('./session').CookieCarrier) => string | undefined;
|
|
132
|
+
resolveRefreshToken: (req: import('./session').CookieCarrier, body?: unknown) => string | undefined;
|
|
133
|
+
};
|
|
134
|
+
policy: AuthPolicy;
|
|
135
|
+
/** Where these flows were mounted, so whatever serves them reads it here rather than defaulting to `/auth`
|
|
136
|
+
* on its own — a host that guessed would serve the routes somewhere the policy above does not guard. */
|
|
137
|
+
basePath: string;
|
|
138
|
+
/** The naming this was built with, so a page server takes it from here instead of being told a second time. */
|
|
139
|
+
cookieConfig: SSRAuthCookie | undefined;
|
|
140
|
+
/** The `/auth` flows as descriptors, ready for whatever serves HTTP here. */
|
|
141
|
+
routes: import('./routes').AuthRoute[];
|
|
142
|
+
/** May this request proceed, and as whom. */
|
|
143
|
+
authorize: (carrier: CredentialCarrier, path: string) => Promise<import('./authorize').AuthorizeResult>;
|
|
144
|
+
/** Does what a flow's answer says about the session cookies. */
|
|
145
|
+
applySession: (req: {
|
|
146
|
+
hostname: string;
|
|
147
|
+
}, res: import('./session').CookieSink, outcome: import('./api').AuthOutcome, cookies: import('./session').SessionCookies) => void;
|
|
148
|
+
/** Both halves of a space permission: a global capability, and membership of that space. */
|
|
149
|
+
can: (actor: import('./identity').Actor, spaceId: number, permission: string) => Promise<boolean>;
|
|
150
|
+
/**
|
|
151
|
+
* The three adapters a page server asks for, already answered. Spread these into `createServer`'s `adapters`
|
|
152
|
+
* and a rendered page knows who is looking at it, `POST /auth/login` signs them in, `POST /auth/logout` signs
|
|
153
|
+
* them out, and the cookies are written and cleared by the same code that reads them back.
|
|
154
|
+
*
|
|
155
|
+
* They exist because the page server speaks in sessions and users while the flows above answer in outcomes,
|
|
156
|
+
* and translating between the two is a step with exactly one right answer — which makes it the server's, not
|
|
157
|
+
* something for every deployment to rediscover.
|
|
158
|
+
*/
|
|
159
|
+
ssrAdapters: {
|
|
160
|
+
authenticate: (credentials: Record<string, string>) => Promise<SSRSession | undefined>;
|
|
161
|
+
getUser: (req: CredentialCarrier) => Promise<SSRUser | undefined>;
|
|
162
|
+
endSession: (req: CredentialCarrier) => Promise<void>;
|
|
163
|
+
};
|
|
164
|
+
};
|
|
165
|
+
export type Auth = ReturnType<typeof createAuth>;
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { createSessionCookies, sessionCookieParams } from "./session.js";
|
|
2
|
+
import { createTokens } from "./tokens.js";
|
|
3
|
+
import { createCarriers, presentedOrigin } from "./credentials.js";
|
|
4
|
+
import { createIdentity } from "./identity.js";
|
|
5
|
+
import { createAuthorizer } from "./authorize.js";
|
|
6
|
+
import { createAuthApi } from "./api.js";
|
|
7
|
+
import { applySessionOutcome, authPolicyRules, authRoutes } from "./routes.js";
|
|
8
|
+
//#region src/core/auth/createAuth.ts
|
|
9
|
+
/**
|
|
10
|
+
* The whole auth cycle, wired.
|
|
11
|
+
*
|
|
12
|
+
* ```ts
|
|
13
|
+
* const auth = createAuth({
|
|
14
|
+
* tokens: { secret, issuer: 'https://acme.test', audience: ['https://api.acme.test'] },
|
|
15
|
+
* cookie: { name: 'acme_session' },
|
|
16
|
+
* adapters: myStore
|
|
17
|
+
* });
|
|
18
|
+
*
|
|
19
|
+
* // guard every request
|
|
20
|
+
* const result = await auth.authorize(req, req.url);
|
|
21
|
+
* // serve the flows
|
|
22
|
+
* for (const { method, path, handler } of auth.routes) { … }
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
var createAuth = (config) => {
|
|
26
|
+
const tokens = createTokens(config.tokens);
|
|
27
|
+
const cookieName = (hostname) => sessionCookieParams(hostname, config.cookie).name;
|
|
28
|
+
const cookies = createSessionCookies(config.cookie);
|
|
29
|
+
const identity = createIdentity({
|
|
30
|
+
tokens,
|
|
31
|
+
carriers: createCarriers(cookieName),
|
|
32
|
+
presentedOrigin,
|
|
33
|
+
adapters: config.adapters,
|
|
34
|
+
config: config.identity
|
|
35
|
+
});
|
|
36
|
+
const api = createAuthApi({
|
|
37
|
+
tokens,
|
|
38
|
+
identity,
|
|
39
|
+
adapters: config.adapters,
|
|
40
|
+
config: config.api
|
|
41
|
+
});
|
|
42
|
+
const basePath = config.basePath ?? "/auth";
|
|
43
|
+
const policy = {
|
|
44
|
+
rules: [...config.rules ?? [], ...authPolicyRules(basePath)],
|
|
45
|
+
fallback: config.fallback ?? "actor"
|
|
46
|
+
};
|
|
47
|
+
return {
|
|
48
|
+
tokens,
|
|
49
|
+
identity,
|
|
50
|
+
api,
|
|
51
|
+
cookies,
|
|
52
|
+
policy,
|
|
53
|
+
/** Where these flows were mounted, so whatever serves them reads it here rather than defaulting to `/auth`
|
|
54
|
+
* on its own — a host that guessed would serve the routes somewhere the policy above does not guard. */
|
|
55
|
+
basePath,
|
|
56
|
+
/** The naming this was built with, so a page server takes it from here instead of being told a second time. */
|
|
57
|
+
cookieConfig: config.cookie,
|
|
58
|
+
/** The `/auth` flows as descriptors, ready for whatever serves HTTP here. */
|
|
59
|
+
routes: authRoutes({
|
|
60
|
+
api,
|
|
61
|
+
cookies
|
|
62
|
+
}),
|
|
63
|
+
/** May this request proceed, and as whom. */
|
|
64
|
+
authorize: createAuthorizer(identity, policy),
|
|
65
|
+
/** Does what a flow's answer says about the session cookies. */
|
|
66
|
+
applySession: applySessionOutcome,
|
|
67
|
+
/** Both halves of a space permission: a global capability, and membership of that space. */
|
|
68
|
+
can: identity.can,
|
|
69
|
+
/**
|
|
70
|
+
* The three adapters a page server asks for, already answered. Spread these into `createServer`'s `adapters`
|
|
71
|
+
* and a rendered page knows who is looking at it, `POST /auth/login` signs them in, `POST /auth/logout` signs
|
|
72
|
+
* them out, and the cookies are written and cleared by the same code that reads them back.
|
|
73
|
+
*
|
|
74
|
+
* They exist because the page server speaks in sessions and users while the flows above answer in outcomes,
|
|
75
|
+
* and translating between the two is a step with exactly one right answer — which makes it the server's, not
|
|
76
|
+
* something for every deployment to rediscover.
|
|
77
|
+
*/
|
|
78
|
+
ssrAdapters: {
|
|
79
|
+
authenticate: async (credentials) => {
|
|
80
|
+
const outcome = await api.login(credentials);
|
|
81
|
+
return outcome.ok ? outcome.session : void 0;
|
|
82
|
+
},
|
|
83
|
+
getUser: async (req) => {
|
|
84
|
+
const resolved = await identity.resolveActor(req);
|
|
85
|
+
if (!resolved.ok) return;
|
|
86
|
+
const { id, username, email, verified, permissions, roles, token, expiresAt } = resolved.actor;
|
|
87
|
+
return {
|
|
88
|
+
id,
|
|
89
|
+
username,
|
|
90
|
+
email,
|
|
91
|
+
verified,
|
|
92
|
+
permissions,
|
|
93
|
+
roles,
|
|
94
|
+
token,
|
|
95
|
+
expiresAt
|
|
96
|
+
};
|
|
97
|
+
},
|
|
98
|
+
endSession: async (req) => {
|
|
99
|
+
await api.logout({ accessToken: cookies.resolveSessionToken(req) });
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
};
|
|
104
|
+
//#endregion
|
|
105
|
+
export { createAuth };
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { IncomingHttpHeaders } from 'node:http';
|
|
2
|
+
/**
|
|
3
|
+
* The shape both an Express `Request` and this server's own `SSRRequest` satisfy. Everything that reads a credential
|
|
4
|
+
* off a request goes through it, so header/cookie precedence is stated once instead of once per transport.
|
|
5
|
+
*/
|
|
6
|
+
export interface CredentialCarrier {
|
|
7
|
+
headers: IncomingHttpHeaders;
|
|
8
|
+
hostname: string;
|
|
9
|
+
query?: Record<string, unknown>;
|
|
10
|
+
/** Populated by cookie-parser on Express; absent elsewhere, where the header is parsed. */
|
|
11
|
+
cookies?: Record<string, string>;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Where a credential of each kind is allowed to ride.
|
|
15
|
+
*
|
|
16
|
+
* `Authorization: Bearer` carries a session token on one role and a space token on another, so it is a candidate for
|
|
17
|
+
* both and the typed verifier decides which it actually is — that is what `scope` is for. Trying the wrong kind
|
|
18
|
+
* costs nothing: it fails on its scope claim before any database is touched.
|
|
19
|
+
*/
|
|
20
|
+
export declare const createCarriers: (sessionCookieName: (hostname: string) => string) => {
|
|
21
|
+
userTokenCandidates: (carrier: CredentialCarrier) => string[];
|
|
22
|
+
spaceTokenCandidates: (carrier: CredentialCarrier) => string[];
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* The origin the caller claims to be presenting from — the `Origin` header, falling back to the host it addressed.
|
|
26
|
+
* Distinct from this server's own origin (see `requestOrigin` in the request parser): this one is the claim a
|
|
27
|
+
* credential's domain binding is checked against.
|
|
28
|
+
*/
|
|
29
|
+
export declare const presentedOrigin: (carrier: CredentialCarrier) => string;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
//#region src/core/auth/credentials.ts
|
|
2
|
+
var parseCookieHeader = (cookieHeader) => {
|
|
3
|
+
const cookies = {};
|
|
4
|
+
for (const part of cookieHeader.split(";")) {
|
|
5
|
+
const eqIndex = part.indexOf("=");
|
|
6
|
+
if (eqIndex === -1) continue;
|
|
7
|
+
cookies[part.slice(0, eqIndex).trim()] = decodeURIComponent(part.slice(eqIndex + 1).trim());
|
|
8
|
+
}
|
|
9
|
+
return cookies;
|
|
10
|
+
};
|
|
11
|
+
var readCookies = (carrier) => {
|
|
12
|
+
if (carrier.cookies) return carrier.cookies;
|
|
13
|
+
const cookieHeader = carrier.headers.cookie;
|
|
14
|
+
return cookieHeader ? parseCookieHeader(cookieHeader) : {};
|
|
15
|
+
};
|
|
16
|
+
var headerValue = (value) => (Array.isArray(value) ? value[0] : value)?.trim() ?? "";
|
|
17
|
+
var bearer = (carrier) => headerValue(carrier.headers.authorization).replace(/^Bearer\s+/i, "");
|
|
18
|
+
var unique = (candidates) => [...new Set(candidates.filter(Boolean))];
|
|
19
|
+
/**
|
|
20
|
+
* Where a credential of each kind is allowed to ride.
|
|
21
|
+
*
|
|
22
|
+
* `Authorization: Bearer` carries a session token on one role and a space token on another, so it is a candidate for
|
|
23
|
+
* both and the typed verifier decides which it actually is — that is what `scope` is for. Trying the wrong kind
|
|
24
|
+
* costs nothing: it fails on its scope claim before any database is touched.
|
|
25
|
+
*/
|
|
26
|
+
var createCarriers = (sessionCookieName) => ({
|
|
27
|
+
userTokenCandidates: (carrier) => unique([
|
|
28
|
+
headerValue(carrier.headers["plitzi-access-token"]),
|
|
29
|
+
bearer(carrier),
|
|
30
|
+
readCookies(carrier)[sessionCookieName(carrier.hostname)] ?? ""
|
|
31
|
+
]),
|
|
32
|
+
spaceTokenCandidates: (carrier) => {
|
|
33
|
+
const queryToken = carrier.query?.["access-token"];
|
|
34
|
+
return unique([
|
|
35
|
+
headerValue(carrier.headers["x-access-token"]),
|
|
36
|
+
bearer(carrier),
|
|
37
|
+
typeof queryToken === "string" ? queryToken : ""
|
|
38
|
+
]);
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
/**
|
|
42
|
+
* The origin the caller claims to be presenting from — the `Origin` header, falling back to the host it addressed.
|
|
43
|
+
* Distinct from this server's own origin (see `requestOrigin` in the request parser): this one is the claim a
|
|
44
|
+
* credential's domain binding is checked against.
|
|
45
|
+
*/
|
|
46
|
+
var presentedOrigin = (carrier) => headerValue(carrier.headers.origin) || carrier.hostname;
|
|
47
|
+
//#endregion
|
|
48
|
+
export { createCarriers, presentedOrigin };
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Declared domains are stored and signed as full origins (`https://site.example.com`) while a request host is bare
|
|
3
|
+
* (`site.example.com`), so both sides are reduced to a hostname before being compared. A non-web value still reduces
|
|
4
|
+
* to something — `plitzi-desktop` to itself, `chrome-extension://…` to its authority — but neither is a host a
|
|
5
|
+
* request ever reports, so it never matches.
|
|
6
|
+
*/
|
|
7
|
+
export declare const hostnameOf: (value: string) => string;
|
|
8
|
+
/** The wildcard a space sets when its embed target is genuinely unknown. Named so an API can warn about it. */
|
|
9
|
+
export declare const ANY_DOMAIN = "*";
|
|
10
|
+
/**
|
|
11
|
+
* May a token declaring `origins` be presented on `host`?
|
|
12
|
+
*
|
|
13
|
+
* `platformHosts` are this deployment's own — its builder, its renderer, its MCP endpoint — which serve first-party
|
|
14
|
+
* traffic for every space and are therefore valid destinations for any token, whatever domains it declares. They are
|
|
15
|
+
* passed in rather than read from configuration here because only the deployment knows what it runs.
|
|
16
|
+
*/
|
|
17
|
+
export declare const domainAllowed: (host: string, origins: string[], platformHosts?: string[]) => boolean;
|
|
18
|
+
/**
|
|
19
|
+
* User input arrives as whatever someone typed — `example.com`, `https://example.com/`, `HTTPS://Example.com/x`. It
|
|
20
|
+
* is stored as a canonical origin so the signed claim, the stored column and the comparison all agree.
|
|
21
|
+
*/
|
|
22
|
+
export declare const normalizeDomain: (value: string) => string | undefined;
|
|
23
|
+
/**
|
|
24
|
+
* Who may put this space in an iframe, as CSP `frame-ancestors` sources.
|
|
25
|
+
*
|
|
26
|
+
* The deployment's own hosts are the floor — a builder previews every space in one — and a space widens it with the
|
|
27
|
+
* domains its owner declared. `*` opts out entirely. Without this a published space is framable from any site on the
|
|
28
|
+
* web, which is how one customer wraps another's space inside their own page and passes it off as theirs.
|
|
29
|
+
*
|
|
30
|
+
* Unlike the token's domain binding, this one is enforced by the browser, which is why it is worth stating even
|
|
31
|
+
* though a determined caller can ignore the header: it stops the attack that needs a real visitor's browser.
|
|
32
|
+
*/
|
|
33
|
+
export declare const frameAncestors: (declared: string[], platformHosts?: string[]) => string[];
|
|
34
|
+
/**
|
|
35
|
+
* Which origins a request bearing this grant may be answered for.
|
|
36
|
+
*
|
|
37
|
+
* A space is reachable from the origins its own token declares, plus this deployment's own apps; `*` means anywhere,
|
|
38
|
+
* and a grant that declares nothing at all falls back to the deployment's own unless it allows anonymous origins.
|
|
39
|
+
* Returning `true` means "reflect whatever asked", which is what a CORS layer wants for the wildcard case.
|
|
40
|
+
*/
|
|
41
|
+
export declare const corsOrigins: (declared: string[] | undefined, platformOrigins?: string[], allowWithoutOrigin?: boolean) => true | string[];
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
//#region src/core/auth/domains.ts
|
|
2
|
+
/**
|
|
3
|
+
* Declared domains are stored and signed as full origins (`https://site.example.com`) while a request host is bare
|
|
4
|
+
* (`site.example.com`), so both sides are reduced to a hostname before being compared. A non-web value still reduces
|
|
5
|
+
* to something — `plitzi-desktop` to itself, `chrome-extension://…` to its authority — but neither is a host a
|
|
6
|
+
* request ever reports, so it never matches.
|
|
7
|
+
*/
|
|
8
|
+
var hostnameOf = (value) => {
|
|
9
|
+
const trimmed = value.trim().toLowerCase();
|
|
10
|
+
if (!trimmed) return "";
|
|
11
|
+
try {
|
|
12
|
+
return new URL(trimmed.includes("://") ? trimmed : `https://${trimmed}`).hostname;
|
|
13
|
+
} catch {
|
|
14
|
+
return "";
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
/** The wildcard a space sets when its embed target is genuinely unknown. Named so an API can warn about it. */
|
|
18
|
+
var ANY_DOMAIN = "*";
|
|
19
|
+
/**
|
|
20
|
+
* May a token declaring `origins` be presented on `host`?
|
|
21
|
+
*
|
|
22
|
+
* `platformHosts` are this deployment's own — its builder, its renderer, its MCP endpoint — which serve first-party
|
|
23
|
+
* traffic for every space and are therefore valid destinations for any token, whatever domains it declares. They are
|
|
24
|
+
* passed in rather than read from configuration here because only the deployment knows what it runs.
|
|
25
|
+
*/
|
|
26
|
+
var domainAllowed = (host, origins, platformHosts = []) => {
|
|
27
|
+
if (origins.includes("*")) return true;
|
|
28
|
+
const hostname = hostnameOf(host);
|
|
29
|
+
if (!hostname) return false;
|
|
30
|
+
return [...platformHosts.map(hostnameOf), ...origins.map(hostnameOf)].filter(Boolean).includes(hostname);
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* User input arrives as whatever someone typed — `example.com`, `https://example.com/`, `HTTPS://Example.com/x`. It
|
|
34
|
+
* is stored as a canonical origin so the signed claim, the stored column and the comparison all agree.
|
|
35
|
+
*/
|
|
36
|
+
var normalizeDomain = (value) => {
|
|
37
|
+
const trimmed = value.trim();
|
|
38
|
+
if (trimmed === "*") return "*";
|
|
39
|
+
if (!hostnameOf(trimmed)) return;
|
|
40
|
+
try {
|
|
41
|
+
const url = new URL(trimmed.includes("://") ? trimmed : `https://${trimmed}`);
|
|
42
|
+
return `${url.protocol}//${url.host}`;
|
|
43
|
+
} catch {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* Who may put this space in an iframe, as CSP `frame-ancestors` sources.
|
|
49
|
+
*
|
|
50
|
+
* The deployment's own hosts are the floor — a builder previews every space in one — and a space widens it with the
|
|
51
|
+
* domains its owner declared. `*` opts out entirely. Without this a published space is framable from any site on the
|
|
52
|
+
* web, which is how one customer wraps another's space inside their own page and passes it off as theirs.
|
|
53
|
+
*
|
|
54
|
+
* Unlike the token's domain binding, this one is enforced by the browser, which is why it is worth stating even
|
|
55
|
+
* though a determined caller can ignore the header: it stops the attack that needs a real visitor's browser.
|
|
56
|
+
*/
|
|
57
|
+
var frameAncestors = (declared, platformHosts = []) => {
|
|
58
|
+
if (declared.includes("*")) return ["*"];
|
|
59
|
+
return [.../* @__PURE__ */ new Set([
|
|
60
|
+
"'self'",
|
|
61
|
+
...platformHosts,
|
|
62
|
+
...declared
|
|
63
|
+
])];
|
|
64
|
+
};
|
|
65
|
+
/**
|
|
66
|
+
* Which origins a request bearing this grant may be answered for.
|
|
67
|
+
*
|
|
68
|
+
* A space is reachable from the origins its own token declares, plus this deployment's own apps; `*` means anywhere,
|
|
69
|
+
* and a grant that declares nothing at all falls back to the deployment's own unless it allows anonymous origins.
|
|
70
|
+
* Returning `true` means "reflect whatever asked", which is what a CORS layer wants for the wildcard case.
|
|
71
|
+
*/
|
|
72
|
+
var corsOrigins = (declared, platformOrigins = [], allowWithoutOrigin = false) => {
|
|
73
|
+
const origins = declared ?? [];
|
|
74
|
+
if (origins.includes("*") || origins.length === 0 && allowWithoutOrigin) return true;
|
|
75
|
+
return [.../* @__PURE__ */ new Set([...platformOrigins, ...origins])];
|
|
76
|
+
};
|
|
77
|
+
//#endregion
|
|
78
|
+
export { ANY_DOMAIN, corsOrigins, domainAllowed, frameAncestors, hostnameOf, normalizeDomain };
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { CredentialCarrier } from './credentials';
|
|
2
|
+
import { AuthFailure, SpaceScope, Tokens } from './tokens';
|
|
3
|
+
/** A Plitzi-style account, as whatever stores accounts reports it. `permissions` are its GLOBAL capabilities. */
|
|
4
|
+
export interface Actor {
|
|
5
|
+
id: number;
|
|
6
|
+
username: string;
|
|
7
|
+
email: string;
|
|
8
|
+
verified: boolean;
|
|
9
|
+
roles: string[];
|
|
10
|
+
permissions: string[];
|
|
11
|
+
token: string;
|
|
12
|
+
/** Unix seconds the presented credential dies at, off the stored row rather than the claim. */
|
|
13
|
+
expiresAt: number;
|
|
14
|
+
}
|
|
15
|
+
/** A space token, resolved. `userId` is set for `agent` grants and names the member who consented. */
|
|
16
|
+
export interface Grant {
|
|
17
|
+
spaceId: number;
|
|
18
|
+
scope: SpaceScope;
|
|
19
|
+
userId?: number;
|
|
20
|
+
origins: string[];
|
|
21
|
+
}
|
|
22
|
+
/** What an account may do inside ONE space. */
|
|
23
|
+
export interface SpaceMembership {
|
|
24
|
+
spaceId: number;
|
|
25
|
+
isOwner: boolean;
|
|
26
|
+
role: string;
|
|
27
|
+
permissions: string[];
|
|
28
|
+
}
|
|
29
|
+
/** The stored side of a space token — the row that makes a signature revocable. */
|
|
30
|
+
export interface StoredSpaceToken {
|
|
31
|
+
spaceId: number;
|
|
32
|
+
scope: SpaceScope;
|
|
33
|
+
userId?: number;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* What identity resolution cannot work out on its own: where accounts, space tokens and memberships are kept. This
|
|
37
|
+
* is the whole database surface authorization needs, and the reason a deployment can bring any store it likes.
|
|
38
|
+
*/
|
|
39
|
+
export interface IdentityAdapters {
|
|
40
|
+
/**
|
|
41
|
+
* The account a session token belongs to, looked up **by the token**. The row is the revocation switch: issuing a
|
|
42
|
+
* new session overwrites it, which is what makes rotation effective, so a token that no longer matches a row is
|
|
43
|
+
* revoked however valid its signature still is.
|
|
44
|
+
*/
|
|
45
|
+
findAccountByToken: (token: string) => Promise<Actor | undefined>;
|
|
46
|
+
/**
|
|
47
|
+
* The stored space token. No row, no grant — which is also what its absence means: a deployment that serves only
|
|
48
|
+
* its own pages issues no space credentials, and omitting this refuses every grant instead of forcing a stub that
|
|
49
|
+
* returns undefined.
|
|
50
|
+
*/
|
|
51
|
+
findSpaceToken?: (token: string) => Promise<StoredSpaceToken | undefined>;
|
|
52
|
+
/** Membership of one space. Without it, every space-level permission check refuses. */
|
|
53
|
+
findMembership?: (userId: number, spaceId: number) => Promise<SpaceMembership | undefined>;
|
|
54
|
+
}
|
|
55
|
+
export interface IdentityConfig {
|
|
56
|
+
/** This deployment's own hosts, which serve first-party traffic for every space. */
|
|
57
|
+
platformHosts?: string[];
|
|
58
|
+
/** Origins always accepted regardless of what a token declares — the deployment's own apps. */
|
|
59
|
+
platformOrigins?: string[];
|
|
60
|
+
/** Whether a request with no `Origin` at all may carry a space token. */
|
|
61
|
+
allowWithoutOrigin?: boolean;
|
|
62
|
+
log?: (message: string, meta: Record<string, unknown>) => void;
|
|
63
|
+
}
|
|
64
|
+
export type ActorResult = {
|
|
65
|
+
ok: true;
|
|
66
|
+
actor: Actor;
|
|
67
|
+
} | {
|
|
68
|
+
ok: false;
|
|
69
|
+
reason: AuthFailure;
|
|
70
|
+
};
|
|
71
|
+
export type GrantResult = {
|
|
72
|
+
ok: true;
|
|
73
|
+
grant: Grant;
|
|
74
|
+
} | {
|
|
75
|
+
ok: false;
|
|
76
|
+
reason: AuthFailure;
|
|
77
|
+
};
|
|
78
|
+
export interface GrantOptions {
|
|
79
|
+
/**
|
|
80
|
+
* Skips the Origin/embed check. Correct for non-browser transports (MCP, analytics ingest, WS upgrade). It does
|
|
81
|
+
* NOT skip the domain binding below — that one is the point.
|
|
82
|
+
*/
|
|
83
|
+
skipOrigin?: boolean;
|
|
84
|
+
/**
|
|
85
|
+
* The host the request actually arrived on. A render token is only valid on the domains it declares, and unlike
|
|
86
|
+
* `Origin` the host cannot be chosen by the caller — it is where the request was routed.
|
|
87
|
+
*/
|
|
88
|
+
host?: string;
|
|
89
|
+
}
|
|
90
|
+
export interface Carriers {
|
|
91
|
+
userTokenCandidates: (carrier: CredentialCarrier) => string[];
|
|
92
|
+
spaceTokenCandidates: (carrier: CredentialCarrier) => string[];
|
|
93
|
+
}
|
|
94
|
+
export declare const createIdentity: ({ tokens, carriers, adapters, config, presentedOrigin }: {
|
|
95
|
+
tokens: Tokens;
|
|
96
|
+
carriers: Carriers;
|
|
97
|
+
adapters: IdentityAdapters;
|
|
98
|
+
config?: IdentityConfig;
|
|
99
|
+
presentedOrigin: (carrier: CredentialCarrier) => string;
|
|
100
|
+
}) => {
|
|
101
|
+
resolveActor: (carrier: CredentialCarrier) => Promise<ActorResult>;
|
|
102
|
+
resolveActorFromToken: (token: string) => Promise<ActorResult>;
|
|
103
|
+
resolveGrant: (carrier: CredentialCarrier, options?: GrantOptions) => Promise<GrantResult>;
|
|
104
|
+
resolveGrantFromToken: (token: string, origin: string, { skipOrigin, host }?: GrantOptions) => Promise<GrantResult>;
|
|
105
|
+
can: (actor: Actor, spaceId: number, permission: string) => Promise<boolean>;
|
|
106
|
+
grantCan: (grant: Grant, permission: string) => Promise<boolean>;
|
|
107
|
+
};
|
|
108
|
+
export type Identity = ReturnType<typeof createIdentity>;
|