@forestadmin/workflow-executor 1.12.0 → 1.14.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.
Files changed (59) hide show
  1. package/README.md +4 -0
  2. package/dist/adapters/agent-client-agent-port.d.ts +1 -1
  3. package/dist/adapters/agent-client-agent-port.js +3 -3
  4. package/dist/adapters/ai-client-adapter.d.ts +5 -1
  5. package/dist/adapters/ai-client-adapter.js +4 -1
  6. package/dist/adapters/always-error-ai-model-port.d.ts +5 -1
  7. package/dist/adapters/always-error-ai-model-port.js +6 -1
  8. package/dist/adapters/server-ai-adapter.d.ts +5 -1
  9. package/dist/adapters/server-ai-adapter.js +4 -1
  10. package/dist/adapters/step-outcome-to-update-step-mapper.js +4 -1
  11. package/dist/build-workflow-executor.js +87 -2
  12. package/dist/crypto/credential-encryption.d.ts +10 -0
  13. package/dist/crypto/credential-encryption.js +75 -0
  14. package/dist/defaults.d.ts +1 -0
  15. package/dist/defaults.js +5 -2
  16. package/dist/errors.d.ts +18 -0
  17. package/dist/errors.js +50 -2
  18. package/dist/executors/mcp-step-executor.d.ts +7 -2
  19. package/dist/executors/mcp-step-executor.js +78 -14
  20. package/dist/executors/step-executor-factory.d.ts +1 -1
  21. package/dist/executors/step-executor-factory.js +24 -3
  22. package/dist/executors/trigger-record-action-step-executor.js +10 -4
  23. package/dist/http/executor-http-server.d.ts +12 -0
  24. package/dist/http/executor-http-server.js +90 -1
  25. package/dist/http/mcp-oauth-credentials.d.ts +24 -0
  26. package/dist/http/mcp-oauth-credentials.js +77 -0
  27. package/dist/index.d.ts +7 -1
  28. package/dist/index.js +10 -3
  29. package/dist/oauth/keyed-mutex.d.ts +5 -0
  30. package/dist/oauth/keyed-mutex.js +27 -0
  31. package/dist/oauth/refresh-grant.d.ts +15 -0
  32. package/dist/oauth/refresh-grant.js +112 -0
  33. package/dist/oauth/token-endpoint-url.d.ts +2 -0
  34. package/dist/oauth/token-endpoint-url.js +103 -0
  35. package/dist/oauth/token-service.d.ts +34 -0
  36. package/dist/oauth/token-service.js +172 -0
  37. package/dist/ports/agent-port.d.ts +1 -0
  38. package/dist/ports/ai-model-port.d.ts +5 -1
  39. package/dist/ports/mcp-oauth-credentials-store.d.ts +24 -0
  40. package/dist/ports/mcp-oauth-credentials-store.js +3 -0
  41. package/dist/ports/run-store.d.ts +1 -0
  42. package/dist/remote-tool-fetcher.d.ts +7 -2
  43. package/dist/remote-tool-fetcher.js +53 -6
  44. package/dist/runner.d.ts +2 -0
  45. package/dist/runner.js +3 -3
  46. package/dist/stores/database-mcp-oauth-credentials-store.d.ts +22 -0
  47. package/dist/stores/database-mcp-oauth-credentials-store.js +188 -0
  48. package/dist/stores/database-store.d.ts +1 -1
  49. package/dist/stores/database-store.js +17 -50
  50. package/dist/stores/in-memory-mcp-oauth-credentials-store.d.ts +13 -0
  51. package/dist/stores/in-memory-mcp-oauth-credentials-store.js +44 -0
  52. package/dist/stores/in-memory-store.d.ts +1 -0
  53. package/dist/stores/in-memory-store.js +6 -1
  54. package/dist/stores/schema-migrations.d.ts +19 -0
  55. package/dist/stores/schema-migrations.js +69 -0
  56. package/dist/types/validated/execution.d.ts +6 -0
  57. package/dist/types/validated/step-outcome.d.ts +10 -0
  58. package/dist/types/validated/step-outcome.js +7 -2
  59. package/package.json +4 -4
@@ -0,0 +1,103 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.default = assertSafeTokenEndpoint;
7
+ const net_1 = __importDefault(require("net"));
8
+ const errors_1 = require("../errors");
9
+ // The token endpoint comes from the deposit body, and the executor POSTs the refresh grant (with
10
+ // client credentials) to it — so an unconstrained value is an SSRF vector. The guard rejects hosts
11
+ // that are never a legitimate endpoint but are prime SSRF targets (loopback, link-local /
12
+ // cloud-metadata) and requires TLS, while deliberately allowing private (RFC1918) hosts: a private
13
+ // OAuth provider reached over the internal network is a supported deployment, so blocking it would
14
+ // break a real use case. http and loopback are relaxed only when NODE_ENV explicitly opts in
15
+ // (development/test) — see isRelaxedEnv. Only IP literals are inspected — resolving a hostname here
16
+ // would be racy (it can resolve to a different address at fetch time), not safer.
17
+ // Fail closed: the strict rules (https + no loopback) apply everywhere UNLESS NODE_ENV explicitly
18
+ // opts into the local-dev relaxation. An unset or misspelled NODE_ENV stays strict, so a
19
+ // misconfigured deploy can't silently allow loopback targets or cleartext http.
20
+ function isRelaxedEnv() {
21
+ return process.env.NODE_ENV === 'development' || process.env.NODE_ENV === 'test';
22
+ }
23
+ function unbracket(hostname) {
24
+ return hostname.startsWith('[') && hostname.endsWith(']') ? hostname.slice(1, -1) : hostname;
25
+ }
26
+ function classifyIpv4(host) {
27
+ const [a, b] = host.split('.').map(Number);
28
+ return {
29
+ loopback: a === 127, // 127.0.0.0/8
30
+ linkLocal: a === 169 && b === 254, // 169.254.0.0/16
31
+ unspecified: a === 0, // 0.0.0.0/8 — "this host"; connects to loopback on Linux
32
+ };
33
+ }
34
+ // Returns the embedded IPv4 of an IPv4-mapped IPv6 address (otherwise null). The WHATWG URL parser
35
+ // normalizes `::ffff:127.0.0.1` to the hex form `::ffff:7f00:1`, which would otherwise dodge the
36
+ // IPv4 loopback/link-local checks and still reach the executor's loopback / metadata interface.
37
+ function embeddedIpv4(host) {
38
+ const tail = host.toLowerCase().match(/^::ffff:(.+)$/)?.[1];
39
+ if (!tail)
40
+ return null;
41
+ if (net_1.default.isIPv4(tail))
42
+ return tail;
43
+ const hex = tail.match(/^([0-9a-f]{1,4}):([0-9a-f]{1,4})$/);
44
+ if (!hex)
45
+ return null;
46
+ const hi = parseInt(hex[1], 16); // high 16 bits → first two octets
47
+ const lo = parseInt(hex[2], 16); // low 16 bits → last two octets
48
+ return `${Math.floor(hi / 256)}.${hi % 256}.${Math.floor(lo / 256)}.${lo % 256}`;
49
+ }
50
+ function classify(host) {
51
+ const kind = net_1.default.isIP(host);
52
+ if (kind === 4)
53
+ return classifyIpv4(host);
54
+ if (kind === 6) {
55
+ const mapped = embeddedIpv4(host);
56
+ if (mapped)
57
+ return classifyIpv4(mapped);
58
+ const normalized = host.toLowerCase().split('%')[0]; // drop any zone id
59
+ const firstHextet = normalized.split(':')[0];
60
+ return {
61
+ loopback: normalized === '::1' || normalized === '0:0:0:0:0:0:0:1',
62
+ linkLocal: /^fe[89ab]/.test(firstHextet), // fe80::/10
63
+ unspecified: normalized === '::' || normalized === '0:0:0:0:0:0:0:0',
64
+ };
65
+ }
66
+ // Not an IP literal. Reject the reserved loopback names — bare `localhost`, the `.localhost` TLD
67
+ // (RFC 6761), and their trailing-dot FQDN forms — since they resolve to loopback. Other hostnames
68
+ // are left to the scheme rule; their DNS is not resolved here (a hostname pointed at an internal
69
+ // IP is the filtering-agent's job, not this string check).
70
+ return {
71
+ loopback: /^localhost\.?$|\.localhost\.?$/.test(host.toLowerCase()),
72
+ linkLocal: false,
73
+ unspecified: false,
74
+ };
75
+ }
76
+ function assertSafeTokenEndpoint(raw) {
77
+ let url;
78
+ try {
79
+ url = new URL(raw);
80
+ }
81
+ catch {
82
+ throw new errors_1.InvalidTokenEndpointError('it is not a valid absolute URL');
83
+ }
84
+ if (url.protocol !== 'https:' && url.protocol !== 'http:') {
85
+ throw new errors_1.InvalidTokenEndpointError('it must use http or https');
86
+ }
87
+ const { loopback, linkLocal, unspecified } = classify(unbracket(url.hostname));
88
+ if (unspecified) {
89
+ throw new errors_1.InvalidTokenEndpointError('it points at the unspecified address (0.0.0.0 / ::)');
90
+ }
91
+ if (linkLocal) {
92
+ throw new errors_1.InvalidTokenEndpointError('it points at a link-local / metadata address');
93
+ }
94
+ if (!isRelaxedEnv()) {
95
+ if (url.protocol !== 'https:') {
96
+ throw new errors_1.InvalidTokenEndpointError('it must use https');
97
+ }
98
+ if (loopback) {
99
+ throw new errors_1.InvalidTokenEndpointError('it points at the executor host (loopback)');
100
+ }
101
+ }
102
+ }
103
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidG9rZW4tZW5kcG9pbnQtdXJsLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL29hdXRoL3Rva2VuLWVuZHBvaW50LXVybC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQW9GQSwwQ0FnQ0M7QUFwSEQsOENBQXNCO0FBRXRCLHNDQUFzRDtBQUV0RCxpR0FBaUc7QUFDakcsbUdBQW1HO0FBQ25HLDBGQUEwRjtBQUMxRixtR0FBbUc7QUFDbkcsbUdBQW1HO0FBQ25HLDZGQUE2RjtBQUM3RixvR0FBb0c7QUFDcEcsa0ZBQWtGO0FBRWxGLGtHQUFrRztBQUNsRyx5RkFBeUY7QUFDekYsZ0ZBQWdGO0FBQ2hGLFNBQVMsWUFBWTtJQUNuQixPQUFPLE9BQU8sQ0FBQyxHQUFHLENBQUMsUUFBUSxLQUFLLGFBQWEsSUFBSSxPQUFPLENBQUMsR0FBRyxDQUFDLFFBQVEsS0FBSyxNQUFNLENBQUM7QUFDbkYsQ0FBQztBQUVELFNBQVMsU0FBUyxDQUFDLFFBQWdCO0lBQ2pDLE9BQU8sUUFBUSxDQUFDLFVBQVUsQ0FBQyxHQUFHLENBQUMsSUFBSSxRQUFRLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxRQUFRLENBQUM7QUFDL0YsQ0FBQztBQUlELFNBQVMsWUFBWSxDQUFDLElBQVk7SUFDaEMsTUFBTSxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUMsQ0FBQztJQUUzQyxPQUFPO1FBQ0wsUUFBUSxFQUFFLENBQUMsS0FBSyxHQUFHLEVBQUUsY0FBYztRQUNuQyxTQUFTLEVBQUUsQ0FBQyxLQUFLLEdBQUcsSUFBSSxDQUFDLEtBQUssR0FBRyxFQUFFLGlCQUFpQjtRQUNwRCxXQUFXLEVBQUUsQ0FBQyxL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
@@ -0,0 +1,34 @@
1
+ import type { RefreshGrantParams, RefreshGrantResult } from './refresh-grant';
2
+ import type CredentialEncryption from '../crypto/credential-encryption';
3
+ import type { Logger } from '../ports/logger-port';
4
+ import type { McpOAuthCredentialsStore } from '../ports/mcp-oauth-credentials-store';
5
+ export interface OAuthTokenServiceOptions {
6
+ store: McpOAuthCredentialsStore;
7
+ encryption: CredentialEncryption;
8
+ logger?: Logger;
9
+ expirySkewS?: number;
10
+ refreshAccessToken?: (params: RefreshGrantParams) => Promise<RefreshGrantResult>;
11
+ now?: () => number;
12
+ }
13
+ export default class OAuthTokenService {
14
+ private readonly store;
15
+ private readonly encryption;
16
+ private readonly logger?;
17
+ private readonly expirySkewMs;
18
+ private readonly refreshAccessToken;
19
+ private readonly now;
20
+ private readonly cache;
21
+ private readonly mutex;
22
+ private readonly evictionEpoch;
23
+ constructor(options: OAuthTokenServiceOptions);
24
+ getAccessToken(userId: number, mcpServerId: string, options?: {
25
+ forceRefresh?: boolean;
26
+ }): Promise<string>;
27
+ evict(userId: number, mcpServerId: string): void;
28
+ private readCache;
29
+ private refreshAndCache;
30
+ private runGrantWithRotationRetry;
31
+ private toGrantParams;
32
+ private persistRotatedRefreshToken;
33
+ }
34
+ //# sourceMappingURL=token-service.d.ts.map
@@ -0,0 +1,172 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const defaults_1 = require("../defaults");
7
+ const errors_1 = require("../errors");
8
+ const keyed_mutex_1 = __importDefault(require("./keyed-mutex"));
9
+ const refresh_grant_1 = __importDefault(require("./refresh-grant"));
10
+ // Acquires an MCP OAuth access token for a (user, server): serves a cached token until it nears
11
+ // expiry, otherwise runs the refresh-token grant under a per-key mutex (one in-flight refresh per
12
+ // user+server in this process) and recovers from a concurrent refresh-token rotation via a single
13
+ // re-read + retry. A missing credential or a genuinely rejected refresh raises
14
+ // OAuthReauthRequiredError so the step pauses for re-authentication.
15
+ class OAuthTokenService {
16
+ constructor(options) {
17
+ this.cache = new Map();
18
+ this.mutex = new keyed_mutex_1.default();
19
+ // Bumped on evict() so a refresh already in flight for a key can detect a disconnect that landed
20
+ // mid-refresh and skip repopulating the cache for the now-deleted credential.
21
+ this.evictionEpoch = new Map();
22
+ this.store = options.store;
23
+ this.encryption = options.encryption;
24
+ this.logger = options.logger;
25
+ this.expirySkewMs = (options.expirySkewS ?? defaults_1.DEFAULT_OAUTH_EXPIRY_SKEW_S) * 1000;
26
+ this.refreshAccessToken = options.refreshAccessToken ?? refresh_grant_1.default;
27
+ this.now = options.now ?? Date.now;
28
+ }
29
+ async getAccessToken(userId, mcpServerId, options) {
30
+ const key = `${userId}:${mcpServerId}`;
31
+ const forceRefresh = options?.forceRefresh ?? false;
32
+ if (!forceRefresh) {
33
+ const cached = this.readCache(key);
34
+ if (cached)
35
+ return cached;
36
+ }
37
+ return this.mutex.runExclusive(key, async () => {
38
+ // Re-check inside the lock: a concurrent caller may have just refreshed for this key.
39
+ if (!forceRefresh) {
40
+ const cached = this.readCache(key);
41
+ if (cached)
42
+ return cached;
43
+ }
44
+ return this.refreshAndCache(userId, mcpServerId, key);
45
+ });
46
+ }
47
+ // Drop the cached access token for a (user, server). Called on credential delete so a disconnect
48
+ // takes effect immediately, instead of the executor serving the cached token until it expires.
49
+ evict(userId, mcpServerId) {
50
+ const key = `${userId}:${mcpServerId}`;
51
+ this.cache.delete(key);
52
+ this.evictionEpoch.set(key, (this.evictionEpoch.get(key) ?? 0) + 1);
53
+ }
54
+ readCache(key) {
55
+ const entry = this.cache.get(key);
56
+ if (!entry)
57
+ return undefined;
58
+ if (this.now() >= entry.expiresAtMs - this.expirySkewMs) {
59
+ // Drop expired entries on read so the cache can't grow without bound across many keys.
60
+ this.cache.delete(key);
61
+ return undefined;
62
+ }
63
+ return entry.accessToken;
64
+ }
65
+ async refreshAndCache(userId, mcpServerId, key) {
66
+ const epochAtStart = this.evictionEpoch.get(key) ?? 0;
67
+ const credential = await this.store.get(userId, mcpServerId);
68
+ if (!credential)
69
+ throw new errors_1.OAuthReauthRequiredError(mcpServerId);
70
+ const { result, credential: grantedCredential } = await this.runGrantWithRotationRetry(credential, userId, mcpServerId);
71
+ const evictedDuringRefresh = (this.evictionEpoch.get(key) ?? 0) !== epochAtStart;
72
+ // Skip caching if the credential was disconnected mid-refresh (would serve a token for a deleted
73
+ // credential) or the grant carried no expiry (never servable); the in-flight caller still gets it.
74
+ if (!evictedDuringRefresh && result.expiresInS !== undefined) {
75
+ this.cache.set(key, {
76
+ accessToken: result.accessToken,
77
+ expiresAtMs: this.now() + result.expiresInS * 1000,
78
+ });
79
+ }
80
+ else {
81
+ this.cache.delete(key);
82
+ }
83
+ if (result.refreshToken) {
84
+ await this.persistRotatedRefreshToken(grantedCredential, result.refreshToken);
85
+ }
86
+ return result.accessToken;
87
+ }
88
+ // On invalid_grant a peer instance likely rotated the refresh token out from under us: re-read the
89
+ // row and retry once with the current token; a second invalid_grant (or an unchanged token) is a
90
+ // genuine revocation and forces re-auth. Returns the credential whose token produced the grant so
91
+ // the caller writes the rotated token back onto that (current) row, not the stale one.
92
+ async runGrantWithRotationRetry(credential, userId, mcpServerId) {
93
+ try {
94
+ const result = await this.refreshAccessToken(this.toGrantParams(credential));
95
+ return { result, credential };
96
+ }
97
+ catch (error) {
98
+ if (!(error instanceof errors_1.OAuthInvalidGrantError))
99
+ throw error;
100
+ // A peer rotated the refresh token iff the stored value changed since we read it.
101
+ const latest = await this.store.get(userId, mcpServerId);
102
+ const wasRotated = latest !== null &&
103
+ latest.refreshTokenEnc.toString('base64') !== credential.refreshTokenEnc.toString('base64');
104
+ if (!latest || !wasRotated) {
105
+ throw new errors_1.OAuthReauthRequiredError(mcpServerId);
106
+ }
107
+ try {
108
+ const result = await this.refreshAccessToken(this.toGrantParams(latest));
109
+ return { result, credential: latest };
110
+ }
111
+ catch (retryError) {
112
+ if (retryError instanceof errors_1.OAuthInvalidGrantError) {
113
+ throw new errors_1.OAuthReauthRequiredError(mcpServerId);
114
+ }
115
+ throw retryError;
116
+ }
117
+ }
118
+ }
119
+ // Decrypt happens here. A decrypt failure with the key PRESENT (auth-tag mismatch — the row was
120
+ // encrypted under a since-rotated/hard-swapped key, or is corrupt) is recoverable: re-consent
121
+ // re-deposits under the current key, so surface it as needs-oauth-reauth. A missing key
122
+ // (ExecutorEncryptionKeyMissingError) is an operator misconfig, not re-consent-resolvable, so it
123
+ // propagates as a terminal error (a re-deposit would just 503 at the deposit endpoint).
124
+ toGrantParams(credential) {
125
+ try {
126
+ return {
127
+ tokenEndpoint: credential.tokenEndpoint,
128
+ refreshToken: this.encryption.decrypt(credential.refreshTokenEnc),
129
+ clientId: credential.clientId,
130
+ clientSecret: credential.clientSecretEnc
131
+ ? this.encryption.decrypt(credential.clientSecretEnc)
132
+ : null,
133
+ tokenEndpointAuthMethod: credential.tokenEndpointAuthMethod,
134
+ scopes: credential.scopes,
135
+ };
136
+ }
137
+ catch (error) {
138
+ if (error instanceof errors_1.ExecutorEncryptionKeyMissingError)
139
+ throw error;
140
+ throw new errors_1.OAuthReauthRequiredError(credential.mcpServerId);
141
+ }
142
+ }
143
+ async persistRotatedRefreshToken(credential, refreshToken) {
144
+ try {
145
+ const encrypted = this.encryption.encrypt(refreshToken);
146
+ // Id-scoped so a disconnect (or disconnect + re-authorize) after the grant read leaves an
147
+ // absent or different row — the rotated-token write-back then can't resurrect or clobber it.
148
+ await this.store.updateIfPresent(credential.id, {
149
+ userId: credential.userId,
150
+ mcpServerId: credential.mcpServerId,
151
+ refreshTokenEnc: encrypted.ciphertext,
152
+ clientId: credential.clientId,
153
+ clientSecretEnc: credential.clientSecretEnc,
154
+ clientSecretExpiresAt: credential.clientSecretExpiresAt,
155
+ tokenEndpoint: credential.tokenEndpoint,
156
+ tokenEndpointAuthMethod: credential.tokenEndpointAuthMethod,
157
+ scopes: credential.scopes,
158
+ });
159
+ }
160
+ catch (error) {
161
+ // A failed write-back is not fatal: the access token just obtained is valid for this call.
162
+ // The rotated refresh token is lost, so a later refresh forces re-authentication — the safe
163
+ // fallback, and better than failing the current operation over a transient write error.
164
+ this.logger?.('Error', 'Failed to persist rotated MCP OAuth refresh token', {
165
+ mcpServerId: credential.mcpServerId,
166
+ error: error instanceof Error ? error.message : String(error),
167
+ });
168
+ }
169
+ }
170
+ }
171
+ exports.default = OAuthTokenService;
172
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidG9rZW4tc2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9vYXV0aC90b2tlbi1zZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7O0FBUUEsMENBQTBEO0FBQzFELHNDQUltQjtBQUNuQixnRUFBdUM7QUFDdkMsb0VBQXdEO0FBZ0J4RCxnR0FBZ0c7QUFDaEcsa0dBQWtHO0FBQ2xHLGtHQUFrRztBQUNsRywrRUFBK0U7QUFDL0UscUVBQXFFO0FBQ3JFLE1BQXFCLGlCQUFpQjtJQWFwQyxZQUFZLE9BQWlDO1FBTjVCLFVBQUssR0FBRyxJQUFJLEdBQUcsRUFBdUIsQ0FBQztRQUN2QyxVQUFLLEdBQUcsSUFBSSxxQkFBVSxFQUFFLENBQUM7UUFDMUMsaUdBQWlHO1FBQ2pHLDhFQUE4RTtRQUM3RCxrQkFBYSxHQUFHLElBQUksR0FBRyxFQUFrQixDQUFDO1FBR3pELElBQUksQ0FBQyxLQUFLLEdBQUcsT0FBTyxDQUFDLEtBQUssQ0FBQztRQUMzQixJQUFJLENBQUMsVUFBVSxHQUFHLE9BQU8sQ0FBQyxVQUFVLENBQUM7UUFDckMsSUFBSSxDQUFDLE1BQU0sR0FBRyxPQUFPLENBQUMsTUFBTSxDQUFDO1FBQzdCLElBQUksQ0FBQyxZQUFZLEdBQUcsQ0FBQyxPQUFPLENBQUMsV0FBVyxJQUFJLHNDQUEyQixDQUFDLEdBQUcsSUFBSSxDQUFDO1FBQ2hGLElBQUksQ0FBQyxrQkFBa0IsR0FBRyxPQUFPLENBQUMsa0JBQWtCLElBQUksdUJBQXlCLENBQUM7UUFDbEYsSUFBSSxDQUFDLEdBQUcsR0FBRyxPQUFPLENBQUMsR0FBRyxJQUFJLElBQUksQ0FBQyxHQUFHLENBQUM7SUFDckMsQ0FBQztJQUVELEtBQUssQ0FBQyxjQUFjLENBQ2xCLE1BQWMsRUFDZCxXQUFtQixFQUNuQixPQUFvQztRQUVwQyxNQUFNLEdBQUcsR0FBRyxHQUFHLE1BQU0sSUFBSSxXQUFXLEVBQUUsQ0FBQztRQUN2QyxNQUFNLFlBQVksR0FB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
@@ -36,6 +36,7 @@ export type ExecuteActionQuery = {
36
36
  action: string;
37
37
  id?: Id[];
38
38
  values?: Record<string, unknown>;
39
+ approvalMessage?: string;
39
40
  };
40
41
  export type GetActionFormQuery = {
41
42
  collection: string;
@@ -1,4 +1,4 @@
1
- import type { BaseChatModel, RemoteTool, ToolConfig } from '@forestadmin/ai-proxy';
1
+ import type { BaseChatModel, McpServerLoadFailure, RemoteTool, ToolConfig } from '@forestadmin/ai-proxy';
2
2
  export interface GetModelOptions {
3
3
  aiConfigName?: string;
4
4
  userId?: number;
@@ -6,6 +6,10 @@ export interface GetModelOptions {
6
6
  export interface AiModelPort {
7
7
  getModel(options?: GetModelOptions): BaseChatModel;
8
8
  loadRemoteTools(configs: Record<string, ToolConfig>): Promise<RemoteTool[]>;
9
+ loadRemoteToolsWithFailures(configs: Record<string, ToolConfig>): Promise<{
10
+ tools: RemoteTool[];
11
+ failures: McpServerLoadFailure[];
12
+ }>;
9
13
  closeConnections(): Promise<void>;
10
14
  }
11
15
  //# sourceMappingURL=ai-model-port.d.ts.map
@@ -0,0 +1,24 @@
1
+ import type { Logger } from './logger-port';
2
+ export interface McpOAuthCredentialInput {
3
+ userId: number;
4
+ mcpServerId: string;
5
+ refreshTokenEnc: Buffer;
6
+ clientId?: string | null;
7
+ clientSecretEnc?: Buffer | null;
8
+ clientSecretExpiresAt?: Date | null;
9
+ tokenEndpoint: string;
10
+ tokenEndpointAuthMethod?: string | null;
11
+ scopes?: string | null;
12
+ }
13
+ export interface StoredMcpOAuthCredential extends McpOAuthCredentialInput {
14
+ id: number;
15
+ }
16
+ export interface McpOAuthCredentialsStore {
17
+ init(logger?: Logger): Promise<void>;
18
+ close(logger?: Logger): Promise<void>;
19
+ get(userId: number, mcpServerId: string): Promise<StoredMcpOAuthCredential | null>;
20
+ upsert(credential: McpOAuthCredentialInput): Promise<void>;
21
+ updateIfPresent(id: number, credential: McpOAuthCredentialInput): Promise<void>;
22
+ delete(userId: number, mcpServerId: string): Promise<void>;
23
+ }
24
+ //# sourceMappingURL=mcp-oauth-credentials-store.d.ts.map
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWNwLW9hdXRoLWNyZWRlbnRpYWxzLXN0b3JlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3BvcnRzL21jcC1vYXV0aC1jcmVkZW50aWFscy1zdG9yZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiIn0=
@@ -5,5 +5,6 @@ export interface RunStore {
5
5
  close(logger?: Logger): Promise<void>;
6
6
  getStepExecutions(runId: string): Promise<StepExecutionData[]>;
7
7
  saveStepExecution(runId: string, stepExecution: StepExecutionData): Promise<void>;
8
+ deleteStepExecution(runId: string, stepIndex: number): Promise<void>;
8
9
  }
9
10
  //# sourceMappingURL=run-store.d.ts.map
@@ -1,3 +1,4 @@
1
+ import type OAuthTokenService from './oauth/token-service';
1
2
  import type { AiModelPort } from './ports/ai-model-port';
2
3
  import type { Logger } from './ports/logger-port';
3
4
  import type { WorkflowPort } from './ports/workflow-port';
@@ -6,13 +7,17 @@ export declare function scopeConfigsToServer(configs: Record<string, ToolConfig>
6
7
  export interface FetchRemoteToolsResult {
7
8
  tools: RemoteTool[];
8
9
  mcpServerName?: string;
10
+ loadFailed?: boolean;
11
+ reloadWithFreshAuth?: () => Promise<RemoteTool[]>;
9
12
  }
10
13
  export default class RemoteToolFetcher {
11
14
  private readonly workflowPort;
12
15
  private readonly aiModelPort;
13
16
  private readonly logger;
14
- constructor(workflowPort: WorkflowPort, aiModelPort: AiModelPort, logger: Logger);
15
- fetch(mcpServerId: string): Promise<FetchRemoteToolsResult>;
17
+ private readonly oauthTokenService;
18
+ constructor(workflowPort: WorkflowPort, aiModelPort: AiModelPort, logger: Logger, oauthTokenService: OAuthTokenService);
19
+ fetch(mcpServerId: string, userId: number): Promise<FetchRemoteToolsResult>;
20
+ private fetchOAuthTools;
16
21
  private warnMissingTargetServer;
17
22
  private errorOnPartialLoadFailure;
18
23
  }
@@ -1,26 +1,72 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.scopeConfigsToServer = scopeConfigsToServer;
4
+ const ai_proxy_1 = require("@forestadmin/ai-proxy");
5
+ const errors_1 = require("./errors");
6
+ const OAUTH2_AUTH_TYPE = 'oauth2';
4
7
  // Match by config.id, not by Record key: server names can collide across configs.
5
8
  function scopeConfigsToServer(configs, mcpServerId) {
6
9
  return Object.fromEntries(Object.entries(configs).filter(([, cfg]) => cfg.id === mcpServerId));
7
10
  }
11
+ function readAuthType(config) {
12
+ return config?.authType;
13
+ }
8
14
  class RemoteToolFetcher {
9
- constructor(workflowPort, aiModelPort, logger) {
15
+ constructor(workflowPort, aiModelPort, logger, oauthTokenService) {
16
+ // Fail loudly here instead of a cryptic undefined dereference at the first OAuth fetch —
17
+ // Runner/RunnerConfig are public API, so a JS caller can bypass the compile-time check.
18
+ if (!oauthTokenService) {
19
+ throw new Error('RemoteToolFetcher requires an OAuth token service (mcpOAuthTokenService)');
20
+ }
10
21
  this.workflowPort = workflowPort;
11
22
  this.aiModelPort = aiModelPort;
12
23
  this.logger = logger;
24
+ this.oauthTokenService = oauthTokenService;
13
25
  }
14
- async fetch(mcpServerId) {
26
+ async fetch(mcpServerId, userId) {
15
27
  const configs = await this.workflowPort.getMcpServerConfigs();
16
28
  const scoped = scopeConfigsToServer(configs, mcpServerId);
17
29
  const [mcpServerName] = Object.keys(scoped);
18
30
  this.warnMissingTargetServer(configs, scoped, mcpServerId, mcpServerName);
19
31
  if (Object.keys(scoped).length === 0)
20
32
  return { tools: [], mcpServerName };
33
+ if (readAuthType(scoped[mcpServerName]) === OAUTH2_AUTH_TYPE) {
34
+ return this.fetchOAuthTools(scoped, mcpServerName, mcpServerId, userId);
35
+ }
21
36
  const tools = await this.aiModelPort.loadRemoteTools(scoped);
22
- this.errorOnPartialLoadFailure(scoped, tools, mcpServerId, mcpServerName);
23
- return { tools, mcpServerName };
37
+ const loadFailed = this.errorOnPartialLoadFailure(scoped, tools, mcpServerId, mcpServerName);
38
+ return { tools, mcpServerName, loadFailed };
39
+ }
40
+ // OAuth2 path: acquire a per-user access token, inject it as a Bearer header, then list tools.
41
+ // Tool listing is the first authenticated call, so an auth failure here forces one token refresh
42
+ // and a single retry; a still-failing load is a genuine re-auth case.
43
+ async fetchOAuthTools(scoped, mcpServerName, mcpServerId, userId) {
44
+ const tokenService = this.oauthTokenService;
45
+ const attemptLoad = async (forceRefresh) => {
46
+ const token = await tokenService.getAccessToken(userId, mcpServerId, { forceRefresh });
47
+ const bearer = `Bearer ${token}`;
48
+ // All scoped configs share this mcpServerId, so inject the token for every one — not just the
49
+ // first key — or extra same-id servers load unauthenticated and report spurious auth failures.
50
+ const injected = (0, ai_proxy_1.injectOauthTokens)({
51
+ configs: scoped,
52
+ tokensByMcpServerName: Object.fromEntries(Object.keys(scoped).map(name => [name, bearer])),
53
+ }) ?? scoped;
54
+ const { tools, failures } = await this.aiModelPort.loadRemoteToolsWithFailures(injected);
55
+ return { tools, hasAuthFailure: failures.some(failure => failure.kind === 'auth') };
56
+ };
57
+ const reloadWithFreshAuth = async () => {
58
+ const attempt = await attemptLoad(true);
59
+ if (attempt.hasAuthFailure)
60
+ throw new errors_1.OAuthReauthRequiredError(mcpServerId);
61
+ this.errorOnPartialLoadFailure(scoped, attempt.tools, mcpServerId, mcpServerName);
62
+ return attempt.tools;
63
+ };
64
+ const initial = await attemptLoad(false);
65
+ if (initial.hasAuthFailure) {
66
+ return { tools: await reloadWithFreshAuth(), mcpServerName, reloadWithFreshAuth };
67
+ }
68
+ const loadFailed = this.errorOnPartialLoadFailure(scoped, initial.tools, mcpServerId, mcpServerName);
69
+ return { tools: initial.tools, mcpServerName, reloadWithFreshAuth, loadFailed };
24
70
  }
25
71
  // Distinguish "no configs at all" (deployment misconfig) from "configs exist but none match"
26
72
  // (orchestrator/executor drift on server id) — both yield zero tools, but ops need to know
@@ -44,13 +90,14 @@ class RemoteToolFetcher {
44
90
  .filter(([, cfg]) => !loadedMcpServerIds.has(cfg.id))
45
91
  .map(([name]) => name);
46
92
  if (failedConfigNames.length === 0)
47
- return;
93
+ return false;
48
94
  this.logger('Error', 'MCP servers failed to load tools', {
49
95
  requestedMcpServerId: mcpServerId,
50
96
  mcpServerName,
51
97
  failedConfigNames,
52
98
  });
99
+ return true;
53
100
  }
54
101
  }
55
102
  exports.default = RemoteToolFetcher;
56
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVtb3RlLXRvb2wtZmV0Y2hlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9yZW1vdGUtdG9vbC1mZXRjaGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBTUEsb0RBS0M7QUFORCxrRkFBa0Y7QUFDbEYsU0FBZ0Isb0JBQW9CLENBQ2xDLE9BQW1DLEVBQ25DLFdBQW1CO0lBRW5CLE9BQU8sTUFBTSxDQUFDLFdBQVcsQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRSxHQUFHLENBQUMsRUFBRSxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsS0FBSyxXQUFXLENBQUMsQ0FBQyxDQUFDO0FBQ2pHLENBQUM7QUFPRCxNQUFxQixpQkFBaUI7SUFLcEMsWUFBWSxZQUEwQixFQUFFLFdBQXdCLEVBQUUsTUFBYztRQUM5RSxJQUFJLENBQUMsWUFBWSxHQUFHLFlBQVksQ0FBQztRQUNqQyxJQUFJLENBQUMsV0FBVyxHQUFHLFdBQVcsQ0FBQztRQUMvQixJQUFJLENBQUMsTUFBTSxHQUFHLE1BQU0sQ0FBQztJQUN2QixDQUFDO0lBRUQsS0FBSyxDQUFDLEtBQUssQ0FBQyxXQUFtQjtRQUM3QixNQUFNLE9BQU8sR0FBRyxNQUFNLElBQUksQ0FBQyxZQUFZLENBQUMsbUJBQW1CLEVBQUUsQ0FBQztRQUM5RCxNQUFNLE1BQU0sR0FBRyxvQkFBb0IsQ0FBQyxPQUFPLEVBQUUsV0FBVyxDQUFDLENBQUM7UUFDMUQsTUFBTSxDQUFDLGFBQWEsQ0FBQyxHQUFHLE1BQU0sQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUM7UUFFNUMsSUFBSSxDQUFDLHVCQUF1QixDQUFDLE9BQU8sRUFBRSxNQUFNLEVBQUUsV0FBVyxFQUFFLGFBQWEsQ0FBQyxDQUFDO1FBRTFFLElBQUksTUFBTSxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQyxNQUFNLEtBQUssQ0FBQztZQUFFLE9BQU8sRUFBRSxLQUFLLEVBQUUsRUFBRSxFQUFFLGFBQWEsRUFBRSxDQUFDO1FBRTFFLE1BQU0sS0FBSyxHQUFHLE1BQU0sSUFBSSxDQUFDLFdBQVcsQ0FBQyxlQUFlLENBQUMsTUFBTSxDQUFDLENBQUM7UUFFN0QsSUFBSSxDQUFDLHlCQUF5QixDQUFDLE1BQU0sRUFBRSxLQUFLLEVBQUUsV0FBVyxFQUFFLGFBQWEsQ0FBQyxDQUFDO1FBRTFFLE9BQU8sRUFBRSxLQUFLLEVBQUUsYUFBYSxFQUFFLENBQUM7SUFDbEMsQ0FBQztJQUVELDZGQUE2RjtJQUM3RiwyRkFBMkY7SUFDM0Ysb0JBQW9CO0lBQ1osdUJBQXVCLENBQzdCLE9BQW1DLEVBQ25DLE1BQWtDLEVBQ2xDLFdBQW1CLEVBQ25CLGFBQWlDO1FBRWpDLElBQUksTUFBTSxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQyxNQUFNLEdBQUcsQ0FBQztZQUFFLE9BQU87UUFFM0MsTUFBTSxxQkFBcUIsR0FBRyxNQUFNLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQzthQUNqRCxHQUFHLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDO2FBQ2xCLE1BQU0sQ0FBQyxDQUFDLEVBQUUsRUFBZ0IsRUFBRSxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDO1FBRTdDLElBQUksQ0FBQyxNQUFNLENBQ1QsTUFBTSxFQUNOLE1BQU0sQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUMsTUFBTSxLQUFLLENBQUM7WUFDL0IsQ0FBQyxDQUFDLG9FQUFvRTtZQUN0RSxDQUFDLENBQUMsOERBQThELEVBQ2xFLEVBQUUsb0JBQW9CLEVBQUUsV0FBVyxFQUFFLGFBQWEsRUFBRSxxQkFBcUIsRUFBRSxDQUM1RSxDQUFDO0lBQ0osQ0FBQztJQUVELDRGQUE0RjtJQUM1Riw0RkFBNEY7SUFDNUYseUZBQXlGO0lBQ2pGLHlCQUF5QixDQUMvQixNQUFrQyxFQUNsQyxLQUFtQixFQUNuQixXQUFtQixFQUNuQixhQUFpQztRQUVqQyxNQUFNLGtCQUFrQixHQUFHLElBQUksR0FBRyxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsV0FBVyxDQUFDLENBQUMsQ0FBQztRQUNsRSxNQUFNLGlCQUFpQixHQUFHLE1BQU0sQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDO2FBQzdDLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRSxHQUFHLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxrQkFBa0IsQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxDQUFDO2FBQ3BELEdBQUcsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLEVBQUUsRUFBRSxDQUFDLElBQUksQ0FBQyxDQUFDO1FBRXpCLElBQUksaUJBQWlCLENBQUMsTUFBTSxLQUFLLENBQUM7WUFBRSxPQUFPO1FBRTNDLElBQUksQ0FBQyxNQUFNLENBQUMsT0FBTyxFQUFFLGtDQUFrQyxFQUFFO1lBQ3ZELG9CQUFvQixFQUFFLFdBQVc7WUFDakMsYUFBYTtZQUNiLGlCQUFpQjtTQUNsQixDQUFDLENBQUM7SUFDTCxDQUFDO0NBQ0Y7QUF6RUQsb0NBeUVDIn0=
103
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVtb3RlLXRvb2wtZmV0Y2hlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9yZW1vdGUtdG9vbC1mZXRjaGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBYUEsb0RBS0M7QUFaRCxvREFBMEQ7QUFFMUQscUNBQW9EO0FBRXBELE1BQU0sZ0JBQWdCLEdBQUcsUUFBUSxDQUFDO0FBRWxDLGtGQUFrRjtBQUNsRixTQUFnQixvQkFBb0IsQ0FDbEMsT0FBbUMsRUFDbkMsV0FBbUI7SUFFbkIsT0FBTyxNQUFNLENBQUMsV0FBVyxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUFFLEdBQUcsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxHQUFHLENBQUMsRUFBRSxLQUFLLFdBQVcsQ0FBQyxDQUFDLENBQUM7QUFDakcsQ0FBQztBQUVELFNBQVMsWUFBWSxDQUFDLE1BQThCO0lBQ2xELE9BQVEsTUFBNEMsRUFBRSxRQUFRLENBQUM7QUFDakUsQ0FBQztBQWNELE1BQXFCLGlCQUFpQjtJQU1wQyxZQUNFLFlBQTBCLEVBQzFCLFdBQXdCLEVBQ3hCLE1BQWMsRUFDZCxpQkFBb0M7UUFFcEMseUZBQXlGO1FBQ3pGLHdGQUF3RjtRQUN4RixJQUFJLENBQUMsaUJBQWlCLEVBQUUsQ0FBQztZQUN2QixNQUFNLElBQUksS0FBSyxDQUFDLDBFQUEwRSxDQUFDLENBQUM7UUFDOUYsQ0FBQztRQUVELElBQUksQ0FBQyxZQUFZLEdBQUcsWUFBWSxDQUFDO1FBQ2pDLElBQUksQ0FBQyxXQUFXLEdBQUcsV0FBVyxDQUFDO1FBQy9CLElBQUksQ0FBQyxNQUFNLEdBQUcsTUFBTSxDQUFDO1FBQ3JCLElBQUksQ0FBQyxpQkFBaUIsR0FBRyxpQkFBaUIsQ0FBQztJQUM3QyxDQUFDO0lBRUQsS0FBSyxDQUFDLEtBQUssQ0FBQyxXQUFtQixFQUFFLE1BQWM7UUFDN0MsTUFBTSxPQUFPLEdBQUcsTUFBTSxJ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
package/dist/runner.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import type OAuthTokenService from './oauth/token-service';
1
2
  import type { ActivityLogPortFactory } from './ports/activity-log-port';
2
3
  import type { AgentPort } from './ports/agent-port';
3
4
  import type { AiModelPort } from './ports/ai-model-port';
@@ -22,6 +23,7 @@ export interface RunnerConfig {
22
23
  stepTimeoutS?: number;
23
24
  aiInvokeTimeoutS?: number;
24
25
  maxChainDepth?: number;
26
+ mcpOAuthTokenService: OAuthTokenService;
25
27
  }
26
28
  export default class Runner {
27
29
  private readonly config;
package/dist/runner.js CHANGED
@@ -20,7 +20,7 @@ class Runner {
20
20
  this._state = 'idle';
21
21
  this.config = config;
22
22
  this.logger = config.logger ?? (0, console_logger_1.default)();
23
- this.remoteToolFetcher = new remote_tool_fetcher_1.default(config.workflowPort, config.aiModelPort, this.logger);
23
+ this.remoteToolFetcher = new remote_tool_fetcher_1.default(config.workflowPort, config.aiModelPort, this.logger, config.mcpOAuthTokenService);
24
24
  }
25
25
  get state() {
26
26
  return this._state;
@@ -216,7 +216,7 @@ class Runner {
216
216
  while (true) {
217
217
  let result;
218
218
  try {
219
- const executor = await step_executor_factory_1.default.create(currentStep, this.contextConfig, this.config.activityLogPortFactory.forRun(currentToken), mcpServerId => this.remoteToolFetcher.fetch(mcpServerId), currentIncomingData, currentToken);
219
+ const executor = await step_executor_factory_1.default.create(currentStep, this.contextConfig, this.config.activityLogPortFactory.forRun(currentToken), (mcpServerId, userId) => this.remoteToolFetcher.fetch(mcpServerId, userId), currentIncomingData, currentToken);
220
220
  result = await executor.execute();
221
221
  }
222
222
  catch (error) {
@@ -333,4 +333,4 @@ class Runner {
333
333
  }
334
334
  }
335
335
  exports.default = Runner;
336
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicnVubmVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL3J1bm5lci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQVlBLCtFQUE0RDtBQUM1RCx5Q0FBNkU7QUFDN0UscUNBT2tCO0FBQ2xCLDhGQUFvRTtBQUNwRSxzRkFBMkQ7QUFDM0QsZ0ZBQXNEO0FBQ3RELGlFQUF1RTtBQUN2RSwwRUFBaUQ7QUE0QmpELHlHQUF5RztBQUN6RyxNQUFNLEVBQUUsT0FBTyxFQUFFLGdCQUFnQixFQUFFLEdBQUcsT0FBTyxDQUFDLGlCQUFpQixDQUF3QixDQUFDO0FBRXhGLE1BQXFCLE1BQU07SUFRekIsWUFBWSxNQUFvQjtRQU54QixpQkFBWSxHQUEwQixJQUFJLENBQUM7UUFDbEMsaUJBQVksR0FBRyxJQUFJLGdDQUFtQixFQUFFLENBQUM7UUFHbEQsV0FBTSxHQUFnQixNQUFNLENBQUM7UUFHbkMsSUFBSSxDQUFDLE1BQU0sR0FBRyxNQUFNLENBQUM7UUFDckIsSUFBSSxDQUFDLE1BQU0sR0FBRyxNQUFNLENBQUMsTUFBTSxJQUFJLElBQUEsd0JBQW1CLEdBQUUsQ0FBQztRQUNyRCxJQUFJLENBQUMsaUJBQWlCLEdBQUcsSUFBSSw2QkFBaUIsQ0FDNUMsTUFBTSxDQUFDLFlBQVksRUFDbkIsTUFBTSxDQUFDLFdBQVcsRUFDbEIsSUFBSSxDQUFDLE1BQU0sQ0FDWixDQUFDO0lBQ0osQ0FBQztJQUVELElBQUksS0FBSztRQUNQLE9BQU8sSUFBSSxDQUFDLE1BQU0sQ0FBQztJQUNyQixDQUFDO0lBRUQsS0FBSyxDQUFDLEtBQUs7UUFDVCxJQUFJLElBQUksQ0FBQyxNQUFNLEtBQUssU0FBUyxJQUFJLElBQUksQ0FBQyxNQUFNLEtBQUssVUFBVSxFQUFFLENBQUM7WUFDNUQsTUFBTSxJQUFJLEtBQUssQ0FBQyxpREFBaUQsQ0FBQyxDQUFDO1FBQ3JFLENBQUM7UUFFRCxJQUFJLElBQUksQ0FBQyxNQUFNLEtBQUssU0FBUztZQUFFLE9BQU87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
336
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicnVubmVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL3J1bm5lci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQWFBLCtFQUE0RDtBQUM1RCx5Q0FBNkU7QUFDN0UscUNBT2tCO0FBQ2xCLDhGQUFvRTtBQUNwRSxzRkFBMkQ7QUFDM0QsZ0ZBQXNEO0FBQ3RELGlFQUF1RTtBQUN2RSwwRUFBaUQ7QUErQmpELHlHQUF5RztBQUN6RyxNQUFNLEVBQUUsT0FBTyxFQUFFLGdCQUFnQixFQUFFLEdBQUcsT0FBTyxDQUFDLGlCQUFpQixDQUF3QixDQUFDO0FBRXhGLE1BQXFCLE1BQU07SUFRekIsWUFBWSxNQUFvQjtRQU54QixpQkFBWSxHQUEwQixJQUFJLENBQUM7UUFDbEMsaUJBQVksR0FBRyxJQUFJLGdDQUFtQixFQUFFLENBQUM7UUFHbEQsV0FBTSxHQUFnQixNQUFNLENBQUM7UUFHbkMsSUFBSSxDQUFDLE1BQU0sR0FBRyxNQUFNLENBQUM7UUFDckIsSUFBSSxDQUFDLE1BQU0sR0FBRyxNQUFNLENBQUMsTUFBTSxJQUFJLElBQUEsd0JBQW1CLEdBQUUsQ0FBQztRQUNyRCxJQUFJLENBQUMsaUJBQWlCLEdBQUcsSUFBSSw2QkFBaUIsQ0FDNUMsTUFBTSxDQUFDLFlBQVksRUFDbkIsTUFBTSxDQUFDLFdBQVcsRUFDbEIsSUFBSSxDQUFDLE1BQU0sRUFDWCxNQUFNLENBQUMsb0JBQW9CLENBQzVCLENBQUM7SUFDSixDQUFDO0lBRUQsSUFBSSxLQUFLO1FBQ1AsT0FBTyxJQUFJLENBQUMsTUFBTSxDQUFDO0lBQ3JCLENBQUM7SUFFRCxLQUFLLENBQUMsS0FBSztRQUNULElBQUksSUFBSSxDQUFDLE1BQU0sS0FBSyxTQUFTLElBQUksSUFBSSxDQUFDLE1BQU0sS0FBSyxVQUFVLEVBQUUsQ0FBQztZQUM1RCxNQUFNLElBQUksS0FBSyxDQUFDLGlEQUFpRCxDQUFDLENBQUM7UUFDckUsQ0FBQztRQUVELElBQUksSUFBSSxDQUFDLE1B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