@plitzi/sdk-server 0.33.2 → 0.34.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 +44 -0
- package/README.md +283 -8
- package/dist/actions.d.ts +62 -0
- package/dist/actions.js +12 -0
- package/dist/adapters/cloudAdapters.d.ts +72 -0
- package/dist/adapters/cloudAdapters.js +303 -0
- package/dist/adapters/space/index.d.ts +93 -0
- package/dist/adapters/space/index.js +122 -0
- package/dist/adapters/space/resolvers.d.ts +69 -0
- package/dist/adapters/space/resolvers.js +79 -0
- package/dist/adapters/space/space.test.d.ts +1 -0
- package/dist/adapters/space/types.d.ts +64 -0
- package/dist/adapters/space/types.js +41 -0
- package/dist/auth.d.ts +50 -0
- package/dist/auth.js +19 -0
- package/dist/core/auth/api.d.ts +400 -11
- package/dist/core/auth/api.js +1044 -50
- package/dist/core/auth/createAuth.d.ts +135 -30
- package/dist/core/auth/createAuth.js +96 -24
- package/dist/core/auth/credentials.d.ts +9 -3
- package/dist/core/auth/credentials.js +10 -4
- package/dist/core/auth/csrf.d.ts +89 -0
- package/dist/core/auth/csrf.js +234 -0
- package/dist/core/auth/csrf.test.d.ts +1 -0
- package/dist/core/auth/identity.d.ts +6 -0
- package/dist/core/auth/identity.js +37 -8
- package/dist/core/auth/lifecycle.test.d.ts +1 -0
- package/dist/core/auth/oauth/index.d.ts +8 -0
- package/dist/core/auth/oauth/index.js +13 -15
- package/dist/core/auth/passwords.d.ts +15 -0
- package/dist/core/auth/passwords.js +32 -0
- package/dist/core/auth/redirects.d.ts +18 -0
- package/dist/core/auth/redirects.js +31 -0
- package/dist/core/auth/redirects.test.d.ts +1 -0
- package/dist/core/auth/routes.d.ts +4 -2
- package/dist/core/auth/routes.js +234 -9
- package/dist/core/auth/session.d.ts +11 -0
- package/dist/core/auth/session.js +1 -1
- package/dist/core/auth/spaceTokens.d.ts +38 -2
- package/dist/core/auth/spaceTokens.js +54 -2
- package/dist/core/auth/throttle.d.ts +5 -0
- package/dist/core/auth/throttle.js +81 -0
- package/dist/core/auth/throttle.test.d.ts +1 -0
- package/dist/core/auth/tokens.d.ts +83 -12
- package/dist/core/auth/tokens.js +51 -9
- package/dist/core/auth/totp.d.ts +48 -0
- package/dist/core/auth/totp.js +118 -0
- package/dist/core/auth/totp.test.d.ts +1 -0
- package/dist/core/createServer.d.ts +0 -6
- package/dist/core/createServer.js +35 -3
- package/dist/core/fontStore.d.ts +33 -0
- package/dist/core/fontStore.js +53 -0
- package/dist/core/fontStore.test.d.ts +1 -0
- package/dist/core/handlers/authMiddleware.js +1 -1
- package/dist/core/handlers/authRouteHandlers.d.ts +9 -1
- package/dist/core/handlers/authRouteHandlers.js +4 -3
- package/dist/core/handlers/csrfMiddleware.d.ts +20 -0
- package/dist/core/handlers/csrfMiddleware.js +32 -0
- package/dist/core/handlers/oauthRouteHandlers.d.ts +46 -0
- package/dist/core/handlers/oauthRouteHandlers.js +159 -0
- package/dist/core/handlers/socialRouteHandlers.d.ts +40 -0
- package/dist/core/handlers/socialRouteHandlers.js +129 -0
- package/dist/core/handlers/socialRouteHandlers.test.d.ts +1 -0
- package/dist/core/handlers/types.d.ts +22 -5
- package/dist/core/health.d.ts +11 -1
- package/dist/core/health.js +27 -3
- package/dist/core/http/dispatcher.d.ts +1 -1
- package/dist/core/http/dispatcher.js +20 -1
- package/dist/core/http/stages/authApi.js +1 -1
- package/dist/core/http/stages/fontAssets.d.ts +9 -0
- package/dist/core/http/stages/fontAssets.js +27 -0
- package/dist/core/http/stages/oauth.d.ts +19 -0
- package/dist/core/http/stages/oauth.js +118 -0
- package/dist/core/http/types.d.ts +12 -0
- package/dist/core/oauth/authorize.d.ts +22 -0
- package/dist/core/oauth/authorize.js +254 -0
- package/dist/core/oauth/authorize.test.d.ts +1 -0
- package/dist/core/oauth/challenge.d.ts +11 -0
- package/dist/core/oauth/challenge.js +33 -0
- package/dist/core/oauth/consentPage.d.ts +12 -0
- package/dist/core/oauth/consentPage.js +131 -0
- package/dist/core/oauth/metadata.d.ts +41 -0
- package/dist/core/oauth/metadata.js +71 -0
- package/dist/core/oauth/params.d.ts +5 -0
- package/dist/core/oauth/params.js +5 -0
- package/dist/core/oauth/pkce.d.ts +6 -0
- package/dist/core/oauth/pkce.js +15 -0
- package/dist/core/oauth/records.d.ts +72 -0
- package/dist/core/oauth/records.js +49 -0
- package/dist/core/oauth/register.d.ts +5 -0
- package/dist/core/oauth/register.js +55 -0
- package/dist/core/oauth/respond.d.ts +21 -0
- package/dist/core/oauth/respond.js +59 -0
- package/dist/core/oauth/token.d.ts +14 -0
- package/dist/core/oauth/token.js +130 -0
- package/dist/core/previewToken.d.ts +20 -0
- package/dist/core/previewToken.js +29 -1
- package/dist/core/server/pageServer.js +4 -1
- package/dist/core/services/action.d.ts +6 -4
- package/dist/core/services/action.js +103 -10
- package/dist/core/services/registry.js +2 -0
- package/dist/core/services/resolve.d.ts +8 -0
- package/dist/core/services/resolve.js +12 -1
- package/dist/core/staticFiles.js +1 -2
- package/dist/handlers.d.ts +7 -1
- package/dist/handlers.js +4 -1
- package/dist/helpers/buildResponseHelpers.d.ts +8 -0
- package/dist/helpers/buildResponseHelpers.js +9 -1
- package/dist/helpers/buildServerInfo.d.ts +8 -3
- package/dist/helpers/buildServerInfo.js +18 -14
- package/dist/helpers/cache/keys.d.ts +13 -0
- package/dist/helpers/cache/keys.js +12 -1
- package/dist/helpers/onAbort.d.ts +12 -0
- package/dist/helpers/onAbort.js +22 -0
- package/dist/helpers/onAbort.test.d.ts +1 -0
- package/dist/helpers/outboundGuard.d.ts +27 -0
- package/dist/helpers/outboundGuard.js +49 -0
- package/dist/helpers/outboundGuard.test.d.ts +1 -0
- package/dist/helpers/serverLog.d.ts +6 -3
- package/dist/helpers/serverLog.js +20 -3
- package/dist/index.d.ts +6 -0
- package/dist/index.js +9 -4
- package/dist/kernel.d.ts +5 -22
- package/dist/kernel.js +1 -14
- package/dist/modules/actions/{handler.js → connectorWrite.js} +5 -2
- package/dist/modules/actions/connectorWrite.test.d.ts +1 -0
- package/dist/modules/actions/index.d.ts +40 -0
- package/dist/modules/actions/index.js +46 -0
- package/dist/modules/actions/moduleFor.d.ts +3 -0
- package/dist/modules/actions/moduleFor.js +35 -0
- package/dist/modules/actions/moduleFor.test.d.ts +1 -0
- package/dist/modules/actions/runtime/check.d.ts +24 -0
- package/dist/modules/actions/runtime/check.js +111 -0
- package/dist/modules/actions/runtime/check.test.d.ts +1 -0
- package/dist/modules/actions/runtime/errors.d.ts +11 -0
- package/dist/modules/actions/runtime/errors.js +17 -0
- package/dist/modules/actions/runtime/guards.d.ts +126 -0
- package/dist/modules/actions/runtime/guards.js +246 -0
- package/dist/modules/actions/runtime/guards.test.d.ts +1 -0
- package/dist/modules/actions/runtime/kvStore.d.ts +27 -0
- package/dist/modules/actions/runtime/kvStore.js +41 -0
- package/dist/modules/actions/runtime/kvStore.test.d.ts +1 -0
- package/dist/modules/actions/runtime/limits.d.ts +11 -0
- package/dist/modules/actions/runtime/limits.js +35 -0
- package/dist/modules/actions/runtime/memoryKv.d.ts +2 -0
- package/dist/modules/actions/runtime/memoryKv.js +77 -0
- package/dist/modules/actions/runtime/namespaceKv.d.ts +9 -0
- package/dist/modules/actions/runtime/namespaceKv.js +19 -0
- package/dist/modules/actions/runtime/precheck.d.ts +27 -0
- package/dist/modules/actions/runtime/precheck.js +45 -0
- package/dist/modules/actions/runtime/renderResolver.d.ts +15 -0
- package/dist/modules/actions/runtime/renderResolver.js +130 -0
- package/dist/modules/actions/runtime/renderResolver.test.d.ts +1 -0
- package/dist/modules/actions/runtime/renderShare.d.ts +29 -0
- package/dist/modules/actions/runtime/renderShare.js +36 -0
- package/dist/modules/actions/runtime/renderShare.test.d.ts +1 -0
- package/dist/modules/actions/runtime/report.d.ts +14 -0
- package/dist/modules/actions/runtime/report.js +22 -0
- package/dist/modules/actions/runtime/runAction.d.ts +12 -0
- package/dist/modules/actions/runtime/runAction.js +405 -0
- package/dist/modules/actions/runtime/runAction.test.d.ts +1 -0
- package/dist/modules/actions/runtime/runLogger.d.ts +31 -0
- package/dist/modules/actions/runtime/runLogger.js +66 -0
- package/dist/modules/actions/runtime/runLogger.test.d.ts +1 -0
- package/dist/modules/actions/runtime/schedule.d.ts +35 -0
- package/dist/modules/actions/runtime/schedule.js +76 -0
- package/dist/modules/actions/runtime/schedule.test.d.ts +1 -0
- package/dist/modules/actions/runtime/scope.d.ts +40 -0
- package/dist/modules/actions/runtime/scope.js +103 -0
- package/dist/modules/actions/runtime/triggers.d.ts +12 -0
- package/dist/modules/actions/runtime/triggers.js +14 -0
- package/dist/modules/actions/taskCatalog.d.ts +26 -0
- package/dist/modules/actions/taskCatalog.js +24 -0
- package/dist/modules/actions/taskCatalog.test.d.ts +1 -0
- package/dist/modules/actions/tasks/auth.d.ts +2 -0
- package/dist/modules/actions/tasks/auth.js +40 -0
- package/dist/modules/actions/tasks/builtins.d.ts +8 -0
- package/dist/modules/actions/tasks/builtins.js +24 -0
- package/dist/modules/actions/tasks/connector.d.ts +2 -0
- package/dist/modules/actions/tasks/connector.js +141 -0
- package/dist/modules/actions/tasks/db.d.ts +2 -0
- package/dist/modules/actions/tasks/db.js +59 -0
- package/dist/modules/actions/tasks/db.test.d.ts +1 -0
- package/dist/modules/actions/tasks/flow.d.ts +3 -0
- package/dist/modules/actions/tasks/flow.js +109 -0
- package/dist/modules/actions/tasks/helpers.d.ts +16 -0
- package/dist/modules/actions/tasks/helpers.js +30 -0
- package/dist/modules/actions/tasks/http.d.ts +2 -0
- package/dist/modules/actions/tasks/http.js +111 -0
- package/dist/modules/actions/tasks/http.test.d.ts +1 -0
- package/dist/modules/actions/tasks/kv.d.ts +2 -0
- package/dist/modules/actions/tasks/kv.js +102 -0
- package/dist/modules/actions/tasks/kv.test.d.ts +1 -0
- package/dist/modules/actions/tasks/registry.d.ts +10 -0
- package/dist/modules/actions/tasks/registry.js +36 -0
- package/dist/modules/actions/tasks/transform.d.ts +2 -0
- package/dist/modules/actions/tasks/transform.js +34 -0
- package/dist/modules/actions/transport/callHandler.d.ts +24 -0
- package/dist/modules/actions/transport/callHandler.js +233 -0
- package/dist/modules/actions/transport/callHandler.test.d.ts +1 -0
- package/dist/modules/actions/transport/cancelHandler.d.ts +23 -0
- package/dist/modules/actions/transport/cancelHandler.js +23 -0
- package/dist/modules/actions/transport/catalogHandler.d.ts +18 -0
- package/dist/modules/actions/transport/catalogHandler.js +21 -0
- package/dist/modules/actions/transport/stream.d.ts +23 -0
- package/dist/modules/actions/transport/stream.js +100 -0
- package/dist/modules/actions/transport/verifySignature.d.ts +16 -0
- package/dist/modules/actions/transport/verifySignature.js +72 -0
- package/dist/modules/actions/transport/webhookHandler.d.ts +25 -0
- package/dist/modules/actions/transport/webhookHandler.js +206 -0
- package/dist/modules/actions/transport/webhookHandler.test.d.ts +1 -0
- package/dist/modules/actions/types.d.ts +234 -0
- package/dist/modules/connectors/engine.js +4 -1
- package/dist/modules/connectors/resolver.d.ts +10 -2
- package/dist/modules/connectors/resolver.js +8 -3
- package/dist/modules/mysql/accounts.d.ts +5 -0
- package/dist/modules/mysql/accounts.js +365 -0
- package/dist/modules/mysql/accounts.test.d.ts +1 -0
- package/dist/modules/mysql/admin.d.ts +58 -0
- package/dist/modules/mysql/admin.js +133 -0
- package/dist/modules/mysql/config.d.ts +82 -0
- package/dist/modules/mysql/config.js +30 -0
- package/dist/modules/mysql/identities.d.ts +35 -0
- package/dist/modules/mysql/identities.js +43 -0
- package/dist/modules/mysql/index.d.ts +67 -0
- package/dist/modules/mysql/index.js +62 -0
- package/dist/modules/mysql/pool.d.ts +3 -0
- package/dist/modules/mysql/pool.js +88 -0
- package/dist/modules/mysql/query.d.ts +12 -0
- package/dist/modules/mysql/query.js +21 -0
- package/dist/modules/mysql/schema.d.ts +43 -0
- package/dist/modules/mysql/schema.js +340 -0
- package/dist/modules/mysql/schema.test.d.ts +1 -0
- package/dist/modules/mysql/sessions.d.ts +33 -0
- package/dist/modules/mysql/sessions.js +46 -0
- package/dist/modules/mysql/spaceTokens.d.ts +11 -0
- package/dist/modules/mysql/spaceTokens.js +59 -0
- package/dist/modules/mysql/store.integration.test.d.ts +1 -0
- package/dist/modules/rsc/connectorRscData.d.ts +25 -0
- package/dist/modules/rsc/connectorRscData.js +51 -0
- package/dist/modules/rsc/connectorRscData.test.d.ts +1 -0
- package/dist/modules/rsc/handler.js +16 -3
- package/dist/modules/rsc/matchRscPage.d.ts +14 -0
- package/dist/modules/rsc/matchRscPage.js +26 -0
- package/dist/modules/rsc/resolveRscData.d.ts +14 -1
- package/dist/modules/rsc/resolveRscData.js +23 -34
- package/dist/modules/ssr/Component.d.ts +6 -2
- package/dist/modules/ssr/Component.js +3 -1
- package/dist/modules/ssr/draftSession.test.d.ts +1 -0
- package/dist/modules/ssr/handler.js +15 -2
- package/dist/modules/ssr/loadPluginComponents.js +22 -5
- package/dist/modules/ssr/prepareRender.js +87 -8
- package/dist/modules/ssr/prepareRender.test.d.ts +1 -0
- package/dist/modules/ssr/preview.d.ts +21 -8
- package/dist/modules/ssr/preview.js +38 -14
- package/dist/modules/ssr/registerExternalPlugins.js +2 -2
- package/dist/modules/ssr/resolvePageSeo.d.ts +18 -0
- package/dist/modules/ssr/resolvePageSeo.js +26 -0
- package/dist/modules/ssr/resolvePageSeo.test.d.ts +1 -0
- package/dist/modules/ssr/template.test.d.ts +1 -0
- package/dist/modules/ssr/views/template.ejs +71 -5
- package/dist/mysql.d.ts +26 -0
- package/dist/mysql.js +4 -0
- package/dist/oauth.d.ts +24 -0
- package/dist/oauth.js +10 -0
- package/dist/plugins/compile.d.ts +1 -0
- package/dist/plugins/compile.js +37 -3
- package/dist/plugins/manager.d.ts +40 -0
- package/dist/plugins/manager.js +113 -13
- package/dist/plugins/manager.test.d.ts +1 -0
- package/package.json +43 -14
- package/skills/plitzi-authoring/SKILL.md +252 -0
- /package/dist/{modules/actions/handler.test.d.ts → adapters/cloudAdapters.test.d.ts} +0 -0
- /package/dist/modules/actions/{handler.d.ts → connectorWrite.d.ts} +0 -0
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import { ActionRunError } from "../runtime/errors.js";
|
|
2
|
+
import { findTriggerNode, triggerParams } from "../runtime/triggers.js";
|
|
3
|
+
import { precheckRun } from "../runtime/precheck.js";
|
|
4
|
+
import onAbort from "../../../helpers/onAbort.js";
|
|
5
|
+
import { reportReject } from "../runtime/report.js";
|
|
6
|
+
import { verifySignature } from "./verifySignature.js";
|
|
7
|
+
import { triggerHasStaleVerify, triggerVerify } from "@plitzi/sdk-shared/actions";
|
|
8
|
+
//#region src/modules/actions/transport/webhookHandler.ts
|
|
9
|
+
var DEFAULT_PER_MINUTE = 60;
|
|
10
|
+
var send = (res, status, payload) => {
|
|
11
|
+
res.setStatus(status);
|
|
12
|
+
res.setHeader("Content-Type", "application/json; charset=utf-8");
|
|
13
|
+
res.setHeader("Cache-Control", "no-store");
|
|
14
|
+
res.send(JSON.stringify(payload));
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* The signing secret, from the credential the verification NAMES.
|
|
18
|
+
*
|
|
19
|
+
* Named outright rather than templated. This runs before anything else does — before the body is parsed, before a
|
|
20
|
+
* run exists — so there is no flow scope for a token to resolve against, and one that rendered to nothing would
|
|
21
|
+
* leave the endpoint verifying every request against an empty secret.
|
|
22
|
+
*/
|
|
23
|
+
var resolveSecret = async (verification, spaceId, getCredential) => {
|
|
24
|
+
const secret = (await getCredential?.(spaceId, verification.credential))?.[verification.secretField ?? "secret"];
|
|
25
|
+
return typeof secret === "string" ? secret : "";
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Handles an inbound webhook.
|
|
29
|
+
*
|
|
30
|
+
* The public face of an action, and the one an attacker can reach without a session — so everything that costs
|
|
31
|
+
* anything happens after the signature is checked, in this order: the action must exist and declare the trigger,
|
|
32
|
+
* the rate limit must allow it, the signature must verify, and only then does a run start.
|
|
33
|
+
*
|
|
34
|
+
* The answer is deliberately thin. A sender needs to know it was accepted; it has no business learning whether an
|
|
35
|
+
* action exists, why a run failed, or what the flow did — and a 404 that distinguishes "no such action" from
|
|
36
|
+
* "wrong signature" is an oracle for both.
|
|
37
|
+
*/
|
|
38
|
+
var handleActionWebhook = async (deps) => {
|
|
39
|
+
const { req, res, config, module, signal, actionId, callerId, lineage } = deps;
|
|
40
|
+
const { environment = "main", spaceId, revision = 0 } = req.ctx.spaceDeployment ?? {};
|
|
41
|
+
if (typeof spaceId !== "number") {
|
|
42
|
+
send(res, 404, { error: "Not found" });
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Every way this ends without a run, told to whoever configured the endpoint.
|
|
47
|
+
*
|
|
48
|
+
* A rejected webhook is the single most common way an integration is broken, and until this existed it was
|
|
49
|
+
* indistinguishable from the sender never firing: the reason went to the process log, where the person setting
|
|
50
|
+
* up the integration cannot see it. The SENDER still learns nothing it should not — that answer is unchanged.
|
|
51
|
+
*/
|
|
52
|
+
const reject = (reason, detail) => reportReject(config, {
|
|
53
|
+
actionId,
|
|
54
|
+
spaceId,
|
|
55
|
+
environment,
|
|
56
|
+
trigger: "webhook",
|
|
57
|
+
reason,
|
|
58
|
+
callerId,
|
|
59
|
+
...detail === void 0 ? {} : { detail }
|
|
60
|
+
});
|
|
61
|
+
const entry = await config.action?.lookups?.getAction(spaceId, actionId);
|
|
62
|
+
const trigger = entry ? findTriggerNode(entry.document.nodes, "webhook") : void 0;
|
|
63
|
+
if (!entry || !trigger) {
|
|
64
|
+
await reject("not_found", entry ? "The action declares no webhook trigger" : "No action with this identifier");
|
|
65
|
+
send(res, 404, { error: "Not found" });
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
const stepParams = triggerParams(trigger);
|
|
69
|
+
const verify = triggerVerify(stepParams);
|
|
70
|
+
/**
|
|
71
|
+
* A verification nothing reads is not an unsigned webhook — it is a broken one, and it is refused.
|
|
72
|
+
*
|
|
73
|
+
* The check used to be a JSON blob and is now fields on the step. A document stored before that carries the
|
|
74
|
+
* blob and no signing credential, and reading it as "unsigned" would turn a protected endpoint into a public
|
|
75
|
+
* one without a single line of it changing. Fail closed, and say which document to fix.
|
|
76
|
+
*/
|
|
77
|
+
if (triggerHasStaleVerify(stepParams)) {
|
|
78
|
+
console.error(`[Actions] webhook "${actionId}" in space ${spaceId} carries a signature check in a format nothing reads any more, so it is refused. Name the signing credential on the trigger step.`);
|
|
79
|
+
await reject("unverifiable", "The signature check is in a format nothing reads any more; name the signing credential on the trigger step");
|
|
80
|
+
send(res, 503, { error: "Unavailable" });
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
const perMinute = config.action?.rateLimit?.webhookPerMinute ?? DEFAULT_PER_MINUTE;
|
|
84
|
+
const window = Math.floor(Date.now() / 6e4);
|
|
85
|
+
try {
|
|
86
|
+
if (await module.kv(spaceId).increment(`hook:${actionId}:${callerId}:${window}`, 1, 120) > perMinute) {
|
|
87
|
+
res.setHeader("Retry-After", "60");
|
|
88
|
+
await reject("rate_limited", `More than ${perMinute} deliveries in one minute from this caller`);
|
|
89
|
+
send(res, 429, { error: "Too many requests" });
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
} catch {
|
|
93
|
+
await reject("unverifiable", "The rate-limit store could not answer, so the endpoint failed closed");
|
|
94
|
+
send(res, 503, { error: "Unavailable" });
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
const rawBody = req.body ?? "";
|
|
98
|
+
if (verify) {
|
|
99
|
+
const secret = await resolveSecret(verify, spaceId, config.action?.lookups?.getCredential);
|
|
100
|
+
const check = verifySignature(verify, secret, req.headers, rawBody);
|
|
101
|
+
if (!check.ok) {
|
|
102
|
+
console.warn(`[Actions] webhook "${actionId}" rejected: ${check.reason}`);
|
|
103
|
+
await reject("invalid_signature", check.reason);
|
|
104
|
+
send(res, 401, { error: "Invalid signature" });
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
let payload = {};
|
|
109
|
+
try {
|
|
110
|
+
const parsed = rawBody ? JSON.parse(rawBody) : {};
|
|
111
|
+
payload = parsed !== null && typeof parsed === "object" ? parsed : {};
|
|
112
|
+
} catch {
|
|
113
|
+
await reject("malformed_body", "The body is not JSON");
|
|
114
|
+
send(res, 400, { error: "Body is not JSON" });
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
const input = {
|
|
118
|
+
...payload,
|
|
119
|
+
payload
|
|
120
|
+
};
|
|
121
|
+
const limits = module.limitsFor(entry.document);
|
|
122
|
+
const begin = {
|
|
123
|
+
spaceId,
|
|
124
|
+
actionId: entry.id,
|
|
125
|
+
callerId,
|
|
126
|
+
input,
|
|
127
|
+
idempotencyKey: deliveryId(req),
|
|
128
|
+
sharedKey: true,
|
|
129
|
+
ttlMs: limits.timeoutMs
|
|
130
|
+
};
|
|
131
|
+
const replayed = await module.guards.replay(begin);
|
|
132
|
+
if (replayed) {
|
|
133
|
+
send(res, 202, {
|
|
134
|
+
accepted: true,
|
|
135
|
+
runId: replayed.runId,
|
|
136
|
+
status: replayed.status,
|
|
137
|
+
replayed: true
|
|
138
|
+
});
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
let run;
|
|
142
|
+
try {
|
|
143
|
+
precheckRun(entry, {
|
|
144
|
+
trigger: "webhook",
|
|
145
|
+
input,
|
|
146
|
+
lineage
|
|
147
|
+
});
|
|
148
|
+
run = await module.guards.begin(begin);
|
|
149
|
+
} catch (error) {
|
|
150
|
+
const reason = error instanceof ActionRunError ? error.reason : "failed";
|
|
151
|
+
await reject(reason, error instanceof Error ? error.message : void 0);
|
|
152
|
+
send(res, reason === "duplicate" ? 202 : 400, { accepted: reason === "duplicate" });
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
await config.adapters.meter?.({
|
|
156
|
+
kind: "server_action",
|
|
157
|
+
cached: false,
|
|
158
|
+
req,
|
|
159
|
+
spaceId,
|
|
160
|
+
environment,
|
|
161
|
+
revision
|
|
162
|
+
});
|
|
163
|
+
const abortRun = () => run.controller.abort();
|
|
164
|
+
const releaseAbort = onAbort(signal, abortRun);
|
|
165
|
+
let outcome;
|
|
166
|
+
try {
|
|
167
|
+
const result = await module.runAction({
|
|
168
|
+
entry,
|
|
169
|
+
input,
|
|
170
|
+
spaceId,
|
|
171
|
+
environment,
|
|
172
|
+
trigger: "webhook",
|
|
173
|
+
callerId,
|
|
174
|
+
runId: run.runId,
|
|
175
|
+
lineage,
|
|
176
|
+
signal: run.controller.signal
|
|
177
|
+
});
|
|
178
|
+
outcome = result;
|
|
179
|
+
send(res, 200, {
|
|
180
|
+
accepted: true,
|
|
181
|
+
runId: result.runId,
|
|
182
|
+
status: result.status
|
|
183
|
+
});
|
|
184
|
+
} catch (error) {
|
|
185
|
+
console.error("[Actions] webhook run failed:", error);
|
|
186
|
+
send(res, 500, { accepted: false });
|
|
187
|
+
} finally {
|
|
188
|
+
releaseAbort();
|
|
189
|
+
await module.guards.end(run, outcome);
|
|
190
|
+
}
|
|
191
|
+
};
|
|
192
|
+
/** The delivery id a provider sends, under the header names the common ones use. */
|
|
193
|
+
var deliveryId = (req) => {
|
|
194
|
+
for (const name of [
|
|
195
|
+
"x-plitzi-delivery",
|
|
196
|
+
"x-github-delivery",
|
|
197
|
+
"x-request-id",
|
|
198
|
+
"idempotency-key"
|
|
199
|
+
]) {
|
|
200
|
+
const value = req.headers[name];
|
|
201
|
+
const single = Array.isArray(value) ? value[0] : value;
|
|
202
|
+
if (single) return single;
|
|
203
|
+
}
|
|
204
|
+
};
|
|
205
|
+
//#endregion
|
|
206
|
+
export { handleActionWebhook };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
import { ActionEntry, ActionLimits, ActionRejectRecord, ActionRunRecord, ActionRunStatus, ActionTriggerType, ConnectorManifest, Environment, InteractionCallbackParam, InteractionNode, InteractionNodeStatus, SpaceRevision, SSRUser } from '@plitzi/sdk-shared';
|
|
2
|
+
/** Resolved secret material, as the connector engine already models it. */
|
|
3
|
+
export type ActionCredential = Record<string, string>;
|
|
4
|
+
/**
|
|
5
|
+
* A connector with its secret already resolved.
|
|
6
|
+
*
|
|
7
|
+
* Handed over as one thing because the engine needs both, and a task holding only the manifest would have to go
|
|
8
|
+
* looking for the credential itself — which is exactly the lookup that must not be open to a task. Authorizing
|
|
9
|
+
* the connector authorizes the credential it names: that is what the `/_action` write endpoint has always done.
|
|
10
|
+
*/
|
|
11
|
+
export type ResolvedConnector = {
|
|
12
|
+
manifest: ConnectorManifest;
|
|
13
|
+
credential?: ActionCredential;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* A connection to a database that is NOT this deployment's.
|
|
17
|
+
*
|
|
18
|
+
* Registered by the deployment, one per engine it supports, and reached only through a credential the space
|
|
19
|
+
* declared — which is the whole security position of `db.query`: a flow queries a database its owner configured,
|
|
20
|
+
* never the one holding other tenants' spaces.
|
|
21
|
+
*
|
|
22
|
+
* `params` are BOUND, never interpolated. The task refuses a statement containing a template for exactly that
|
|
23
|
+
* reason, and a driver that pastes them into the SQL itself would undo the rule from the other end.
|
|
24
|
+
*/
|
|
25
|
+
export type ActionDbDriver = {
|
|
26
|
+
/** Engine name a credential names, e.g. `mysql`, `postgres`. */
|
|
27
|
+
engine: string;
|
|
28
|
+
query: (dsn: string, sql: string, params: unknown[], signal: AbortSignal) => Promise<unknown[]>;
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* Where a deployment keeps the `kv` tasks' data — Redis, Memcached, a table, whatever it already runs.
|
|
32
|
+
*
|
|
33
|
+
* Deliberately the DUMBEST possible surface: five operations over strings, with no rule to obey. Everything that
|
|
34
|
+
* decides how a counter behaves — the key prefixing, the JSON round trip, and the one rule a rate limit lives or
|
|
35
|
+
* dies by — is `createKvStore`'s, above this. An adapter that had to remember "extend the TTL only when the
|
|
36
|
+
* counter did not exist" would be an adapter each deployment gets to write that rule wrongly in.
|
|
37
|
+
*
|
|
38
|
+
* Making it a seam at all is what keeps rate limiting and idempotency across replicas a deployment's decision
|
|
39
|
+
* rather than a silent no-op: the in-process default counts only its own replica, and honestly says so.
|
|
40
|
+
*/
|
|
41
|
+
export type ActionKvAdapter = {
|
|
42
|
+
/** The stored string, or undefined when the key is absent OR has expired. */
|
|
43
|
+
get: (key: string) => Promise<string | undefined>;
|
|
44
|
+
set: (key: string, value: string, ttlSeconds?: number) => Promise<void>;
|
|
45
|
+
delete: (key: string) => Promise<void>;
|
|
46
|
+
/** Adds to a counter and answers the NEW total. Must be atomic — this is what get-then-set cannot be. */
|
|
47
|
+
increment: (key: string, amount: number) => Promise<number>;
|
|
48
|
+
/** Sets a lifetime on a key that already exists. When to call it is decided above, never here. */
|
|
49
|
+
expire: (key: string, ttlSeconds: number) => Promise<void>;
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* The `kv` tasks' own view: values rather than strings, and a TTL that means what a caller expects.
|
|
53
|
+
*
|
|
54
|
+
* Built by `createKvStore` over an {@link ActionKvAdapter}, and then narrowed to one space by `namespaceKv`. A
|
|
55
|
+
* task never sees an adapter.
|
|
56
|
+
*/
|
|
57
|
+
export type ActionKvStore = {
|
|
58
|
+
get: (key: string) => Promise<unknown>;
|
|
59
|
+
set: (key: string, value: unknown, ttlSeconds?: number) => Promise<void>;
|
|
60
|
+
delete: (key: string) => Promise<void>;
|
|
61
|
+
increment: (key: string, amount: number, ttlSeconds?: number) => Promise<number>;
|
|
62
|
+
};
|
|
63
|
+
/** Re-exported so the module's files import one place. One type for actions and connectors: it is one concept. */
|
|
64
|
+
export type { SpaceRevision } from '@plitzi/sdk-shared';
|
|
65
|
+
/**
|
|
66
|
+
* How the server reaches a space's actions. Structurally identical in spirit to `ConnectorLookups`: the module
|
|
67
|
+
* never learns where a deployment stores anything.
|
|
68
|
+
*/
|
|
69
|
+
export type ActionLookups = {
|
|
70
|
+
getAction: (spaceId: number, actionId: string, at?: SpaceRevision) => Promise<ActionEntry | undefined>;
|
|
71
|
+
/** Only the builder's catalog, the MCP and the scheduler need the list; a page call never asks for it. */
|
|
72
|
+
listActions?: (spaceId: number, at?: SpaceRevision) => Promise<ActionEntry[]>;
|
|
73
|
+
getCredential?: (spaceId: number, identifier: string) => Promise<ActionCredential | undefined>;
|
|
74
|
+
getConnector?: (spaceId: number, connectorId: string, at?: SpaceRevision) => Promise<ConnectorManifest | undefined>;
|
|
75
|
+
};
|
|
76
|
+
/**
|
|
77
|
+
* The only door a task has to the outside world.
|
|
78
|
+
*
|
|
79
|
+
* `credential` and `connector` answer solely for identifiers the running document declared, so a task cannot reach
|
|
80
|
+
* a secret the action did not ask for — the check lives here rather than in each task, where it would be optional.
|
|
81
|
+
* `fetch` is the run's own: abort-wired and counted against the request budget.
|
|
82
|
+
*/
|
|
83
|
+
export type ActionTaskContext = {
|
|
84
|
+
runId: string;
|
|
85
|
+
spaceId: number;
|
|
86
|
+
environment: Environment;
|
|
87
|
+
trigger: ActionTriggerType;
|
|
88
|
+
user?: SSRUser;
|
|
89
|
+
/**
|
|
90
|
+
* Who is asking, as the transport identified them: `user:<id>` for a session, `ip:<address>` for everyone else,
|
|
91
|
+
* and `render` or `schedule` for the runs no visitor started.
|
|
92
|
+
*
|
|
93
|
+
* A task that must happen once per PERSON has nothing else to key on — a `public` action has no session, and an
|
|
94
|
+
* identifier the caller sent is not an identity. Coarse by construction, since a shared address is one caller,
|
|
95
|
+
* and personal data when it is one: a task that stores it is storing that.
|
|
96
|
+
*/
|
|
97
|
+
callerId: string;
|
|
98
|
+
signal: AbortSignal;
|
|
99
|
+
/**
|
|
100
|
+
* The flow scope as the current node sees it: `input`, every previous node's result by id, `user`, and the
|
|
101
|
+
* credentials the document declared. Read-only, and present because a `rawParams` task has to render templates
|
|
102
|
+
* against something.
|
|
103
|
+
*/
|
|
104
|
+
scope: Readonly<Record<string, unknown>>;
|
|
105
|
+
credential: (identifier: string) => Promise<ActionCredential | undefined>;
|
|
106
|
+
connector: (connectorId: string) => Promise<ResolvedConnector | undefined>;
|
|
107
|
+
fetch: typeof fetch;
|
|
108
|
+
/** Key/value storage, namespaced to this space by the runner — a key one space writes is a key only it reads. */
|
|
109
|
+
kv: ActionKvStore;
|
|
110
|
+
/** The database engines this deployment registered, for the `db.query` task. */
|
|
111
|
+
dbDrivers: ActionDbDriver[];
|
|
112
|
+
/** Pushes a `data` frame to a streaming caller. A no-op when nobody negotiated a stream. */
|
|
113
|
+
emit: (chunk: unknown) => void;
|
|
114
|
+
};
|
|
115
|
+
/**
|
|
116
|
+
* One step a server action can take.
|
|
117
|
+
*
|
|
118
|
+
* `params` is the same `InteractionCallbackParam` map the builder's WorkflowNode already renders, which is what
|
|
119
|
+
* lets a deployment's own task appear in its editor without a single change there.
|
|
120
|
+
*/
|
|
121
|
+
export type ActionTask<T extends Record<string, unknown> = Record<string, unknown>> = {
|
|
122
|
+
/** Addressed in a node as `<namespace>.<action>`. */
|
|
123
|
+
namespace: string;
|
|
124
|
+
action: string;
|
|
125
|
+
title: string;
|
|
126
|
+
description?: string;
|
|
127
|
+
params: Record<keyof T, InteractionCallbackParam<T>>;
|
|
128
|
+
/**
|
|
129
|
+
* Receive params BEFORE twig resolution. Only for a task whose whole job is to render a template — resolving
|
|
130
|
+
* first would consume the very tokens it exists to interpret. The client engine special-cases `twigTemplate` by
|
|
131
|
+
* name for this; a flag is the same rule without the name check.
|
|
132
|
+
*/
|
|
133
|
+
rawParams?: boolean;
|
|
134
|
+
run: (params: T, ctx: ActionTaskContext) => unknown;
|
|
135
|
+
};
|
|
136
|
+
/** A task with its addressable name resolved, as the registry stores and lists it. */
|
|
137
|
+
export type RegisteredTask = ActionTask<Record<string, unknown>> & {
|
|
138
|
+
name: string;
|
|
139
|
+
};
|
|
140
|
+
export type ActionTaskRegistry = {
|
|
141
|
+
get: (name: string) => RegisteredTask | undefined;
|
|
142
|
+
list: () => RegisteredTask[];
|
|
143
|
+
};
|
|
144
|
+
/** What a deployment hands to `createServer` under `actions`. Absent → the module is never constructed. */
|
|
145
|
+
export type ActionsConfig = {
|
|
146
|
+
lookups: ActionLookups;
|
|
147
|
+
/** Deployment-owned tasks, validated at boot against the built-ins. */
|
|
148
|
+
tasks?: ActionTask<never>[];
|
|
149
|
+
/** Ceilings a per-action document may tighten but never exceed. */
|
|
150
|
+
limits?: ActionLimits;
|
|
151
|
+
/** How many runs may be in flight at once. Counted per space and for the process as a whole. */
|
|
152
|
+
concurrency?: {
|
|
153
|
+
perSpace?: number;
|
|
154
|
+
perProcess?: number;
|
|
155
|
+
renderPerProcess?: number;
|
|
156
|
+
};
|
|
157
|
+
/** Where the `kv` tasks keep things. Omitted → an in-process Map, which is per-replica by definition. */
|
|
158
|
+
kv?: ActionKvAdapter;
|
|
159
|
+
/** Inbound webhooks are public, so they are counted per caller per minute. Default 60. */
|
|
160
|
+
rateLimit?: {
|
|
161
|
+
webhookPerMinute?: number;
|
|
162
|
+
};
|
|
163
|
+
/** Database engines this deployment lets a flow reach. Empty → the `db.query` task is not offered at all. */
|
|
164
|
+
dbDrivers?: ActionDbDriver[];
|
|
165
|
+
/**
|
|
166
|
+
* Called once per run that started, for a deployment that keeps a record.
|
|
167
|
+
*
|
|
168
|
+
* Best-effort by contract: it is awaited but never allowed to fail a run — a logging outage must not take an
|
|
169
|
+
* action down, which is the same rule metering follows.
|
|
170
|
+
*/
|
|
171
|
+
onRun?: (record: ActionRunRecord) => void | Promise<void>;
|
|
172
|
+
/**
|
|
173
|
+
* Called once per request that was REFUSED before it became a run.
|
|
174
|
+
*
|
|
175
|
+
* Its own hook rather than a status on `onRun`, because the two answer different questions and a deployment
|
|
176
|
+
* wants them in different places: runs are history, refusals are a fault report. Without it a webhook rejected
|
|
177
|
+
* for a bad signature is invisible to everyone but whoever reads the process log — which is nobody, on the
|
|
178
|
+
* afternoon the integration is being set up.
|
|
179
|
+
*
|
|
180
|
+
* Everything is reported, including the refusals that are somebody else retrying politely. Which of them are
|
|
181
|
+
* worth keeping is a policy the deployment owns; the mechanism does not decide it by staying quiet.
|
|
182
|
+
*/
|
|
183
|
+
onReject?: (record: ActionRejectRecord) => void | Promise<void>;
|
|
184
|
+
/**
|
|
185
|
+
* How long a COMPLETED run's answer may be replayed to a caller that asks for it again by the same key.
|
|
186
|
+
*
|
|
187
|
+
* Off by default, and it only ever applies to an explicit key — an `idempotencyKey` on the call, or the
|
|
188
|
+
* delivery id a webhook sender stamps. A derived key is a hash of the input, and two identical calls a minute
|
|
189
|
+
* apart are usually two things somebody wants to happen twice.
|
|
190
|
+
*
|
|
191
|
+
* Needs a shared {@link ActionKvAdapter} to mean anything across replicas, exactly as single-flight does.
|
|
192
|
+
*/
|
|
193
|
+
idempotency?: {
|
|
194
|
+
replayTtlMs?: number;
|
|
195
|
+
};
|
|
196
|
+
fetchImpl?: typeof fetch;
|
|
197
|
+
};
|
|
198
|
+
/** Re-exported so the module's own files import one place, and a deployment writing an `onRun` or an `onReject`
|
|
199
|
+
* sees the same shapes the module emits. */
|
|
200
|
+
export type { ActionRejectRecord, ActionRunRecord } from '@plitzi/sdk-shared';
|
|
201
|
+
export type ResolvedActionLimits = Required<ActionLimits>;
|
|
202
|
+
export type ActionRunRequest = {
|
|
203
|
+
entry: ActionEntry;
|
|
204
|
+
input: Record<string, unknown>;
|
|
205
|
+
spaceId: number;
|
|
206
|
+
environment: Environment;
|
|
207
|
+
trigger: ActionTriggerType;
|
|
208
|
+
user?: SSRUser;
|
|
209
|
+
/** Who is asking. Stated by whatever started the run — see {@link ActionTaskContext.callerId}. */
|
|
210
|
+
callerId: string;
|
|
211
|
+
runId: string;
|
|
212
|
+
/** Chain of run ids that caused this one; a run naming its own action is refused before its first node. */
|
|
213
|
+
lineage?: string[];
|
|
214
|
+
/**
|
|
215
|
+
* The published version this run belongs to, when a page started it.
|
|
216
|
+
*
|
|
217
|
+
* The action was read as of this revision, so the connectors it calls are read as of it too — a flow and the
|
|
218
|
+
* manifests it goes through are one published thing, and mixing versions inside one run is the discrepancy in
|
|
219
|
+
* miniature.
|
|
220
|
+
*/
|
|
221
|
+
at?: SpaceRevision;
|
|
222
|
+
emit?: (chunk: unknown) => void;
|
|
223
|
+
/** Reports each step as it settles, for a caller watching the run happen. Absent for a plain request/response. */
|
|
224
|
+
onNode?: (id: string, status: InteractionNodeStatus) => void;
|
|
225
|
+
signal?: AbortSignal;
|
|
226
|
+
};
|
|
227
|
+
export type ActionRunResult = {
|
|
228
|
+
runId: string;
|
|
229
|
+
status: ActionRunStatus;
|
|
230
|
+
/** Projected down to the document's declared `output`. Never the raw flow scope. */
|
|
231
|
+
output: Record<string, unknown>;
|
|
232
|
+
/** The same shape the dev-tools Interactions panel renders. Redacted before it leaves the process. */
|
|
233
|
+
trace: InteractionNode[];
|
|
234
|
+
};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { getByPath } from "./getByPath.js";
|
|
2
|
-
import {
|
|
2
|
+
import { assertOutboundAllowed } from "../../helpers/outboundGuard.js";
|
|
3
3
|
import { processTwig } from "@plitzi/sdk-shared/helpers/twigWrapper";
|
|
4
|
+
import { BODYLESS_METHODS, DEFAULT_READ_ENDPOINT, EMPTY_RESPONSE_METHODS } from "@plitzi/sdk-shared/connectors";
|
|
4
5
|
//#region src/modules/connectors/engine.ts
|
|
5
6
|
var DEFAULT_LIMIT = 10;
|
|
6
7
|
/** Only scalars can become a URL fragment, a header or a record key. Anything else is treated as absent. */
|
|
@@ -149,6 +150,7 @@ var fetchConnectorRecords = async ({ manifest, endpoint = DEFAULT_READ_ENDPOINT,
|
|
|
149
150
|
...renderEntries(read.query ?? {}, variables),
|
|
150
151
|
...renderFilters(resolved, connection.operators, variables)
|
|
151
152
|
}).forEach(([key, value]) => url.searchParams.set(key, value));
|
|
153
|
+
await assertOutboundAllowed(url);
|
|
152
154
|
const method = read.method ?? "GET";
|
|
153
155
|
const headers = {
|
|
154
156
|
...applyAuth(connection, variables, url),
|
|
@@ -200,6 +202,7 @@ var writeConnectorRecord = async ({ manifest, credential = {}, action, resource,
|
|
|
200
202
|
};
|
|
201
203
|
const url = new URL(render(operation.path, variables), connection.baseUrl);
|
|
202
204
|
Object.entries(renderEntries(operation.query ?? {}, variables)).forEach(([key, value]) => url.searchParams.set(key, value));
|
|
205
|
+
await assertOutboundAllowed(url);
|
|
203
206
|
const headers = {
|
|
204
207
|
...applyAuth(connection, variables, url),
|
|
205
208
|
...renderEntries(operation.headers ?? {}, variables)
|
|
@@ -1,8 +1,16 @@
|
|
|
1
1
|
import { ConnectorCredential, ConnectorManifest } from './types';
|
|
2
2
|
import { RscElementResolver } from '../rsc/resolveRscData';
|
|
3
|
+
import { SpaceRevision } from '@plitzi/sdk-shared';
|
|
3
4
|
export type ConnectorLookups = {
|
|
4
|
-
/**
|
|
5
|
-
|
|
5
|
+
/**
|
|
6
|
+
* Reads a manifest by id, as of a published revision. Server-side state: manifests name endpoints and must never
|
|
7
|
+
* reach the browser.
|
|
8
|
+
*
|
|
9
|
+
* `at` absent means the live document, the one the builder edits. A page passes the revision it was published
|
|
10
|
+
* at, so it reads through the manifest it shipped with rather than whatever it says after somebody points that
|
|
11
|
+
* connector at a different API.
|
|
12
|
+
*/
|
|
13
|
+
getConnector: (spaceId: number, connectorId: string, at?: SpaceRevision) => Promise<ConnectorManifest | undefined>;
|
|
6
14
|
/** Resolves the secret referenced by `manifest.credential`. */
|
|
7
15
|
getCredential?: (spaceId: number, identifier: string) => Promise<ConnectorCredential | undefined>;
|
|
8
16
|
fetchImpl?: typeof fetch;
|
|
@@ -28,11 +28,16 @@ var toPage = (queryParams, attributes) => {
|
|
|
28
28
|
* An element without a connector resolves to nothing rather than failing — an unconfigured provider on a page is a
|
|
29
29
|
* draft, not an error.
|
|
30
30
|
*/
|
|
31
|
-
var createConnectorResolver = ({ getConnector, getCredential, fetchImpl }) => async ({ element, flat, routeParams, queryParams, spaceId }) => {
|
|
31
|
+
var createConnectorResolver = ({ getConnector, getCredential, fetchImpl }) => async ({ element, flat, routeParams, queryParams, spaceId, environment, req }) => {
|
|
32
|
+
const deployment = req.ctx.spaceDeployment;
|
|
33
|
+
const at = {
|
|
34
|
+
environment: deployment?.environment ?? environment,
|
|
35
|
+
revision: deployment?.revision ?? 0
|
|
36
|
+
};
|
|
32
37
|
const attributes = element.attributes;
|
|
33
38
|
const { connector: connectorId, endpoint, resource, limit, singleRecord = false, filters } = attributes;
|
|
34
39
|
if (!connectorId) return;
|
|
35
|
-
const manifest = await getConnector(spaceId, connectorId);
|
|
40
|
+
const manifest = await getConnector(spaceId, connectorId, at);
|
|
36
41
|
if (!manifest) throw new Error(`Connector "${connectorId}" is not configured for space ${spaceId}`);
|
|
37
42
|
const credential = manifest.credential && getCredential ? await getCredential(spaceId, manifest.credential) : void 0;
|
|
38
43
|
const pageSize = toLimit(limit, singleRecord);
|
|
@@ -62,7 +67,7 @@ var createConnectorResolver = ({ getConnector, getCredential, fetchImpl }) => as
|
|
|
62
67
|
errorMessage: ""
|
|
63
68
|
};
|
|
64
69
|
if (manifest.projection === "full") return slice;
|
|
65
|
-
return projectSlice(slice, collectBoundPaths(flat, element.id, getSourceName(element.definition.type, element)));
|
|
70
|
+
return projectSlice(slice, collectBoundPaths(flat, element.id, getSourceName(element.definition.type, element.id)));
|
|
66
71
|
};
|
|
67
72
|
//#endregion
|
|
68
73
|
export { createConnectorResolver };
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { Tables } from './config';
|
|
2
|
+
import { Queryable } from './query';
|
|
3
|
+
import { AccountAdapters } from '../../core/auth/api';
|
|
4
|
+
import { IdentityAdapters } from '../../core/auth/identity';
|
|
5
|
+
export declare const createAccountStore: (db: Queryable, t: Tables) => IdentityAdapters & AccountAdapters;
|