@powerhousedao/reactor-workflow 6.2.3-dev.11

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.
@@ -0,0 +1,797 @@
1
+ import { DEDUPE_KEY_PROPERTY, StoreScope } from "@powerhousedao/pieces-framework";
2
+ import { mkdir, writeFile } from "node:fs/promises";
3
+ import path from "node:path";
4
+ import { randomUUID } from "node:crypto";
5
+ import { ssrfIpClassifier } from "@powerhousedao/pieces-framework/host";
6
+ import { Cron } from "croner";
7
+ import dgram from "node:dgram";
8
+ import dns from "node:dns";
9
+ import net, { isIP } from "node:net";
10
+ import { AsyncLocalStorage } from "node:async_hooks";
11
+ //#region src/pieces/activepieces/types.ts
12
+ function getActions(piece) {
13
+ return (typeof piece.actions === "function" ? piece.actions() : piece.actions) ?? {};
14
+ }
15
+ function getTriggers(piece) {
16
+ return (typeof piece.triggers === "function" ? piece.triggers() : piece.triggers) ?? {};
17
+ }
18
+ //#endregion
19
+ //#region src/pieces/activepieces/context/stubs.ts
20
+ var UnsupportedContextMemberError = class extends Error {
21
+ member;
22
+ constructor(member) {
23
+ super(`Piece used unimplemented context member "${member}". Implement it in the adapter or reject the piece at conformance time.`);
24
+ this.name = "UnsupportedContextMemberError";
25
+ this.member = member;
26
+ }
27
+ };
28
+ function throwingStub(memberPath) {
29
+ return new Proxy(function stub() {}, {
30
+ get(_target, prop) {
31
+ if (typeof prop !== "string" || prop === "then") return void 0;
32
+ throw new UnsupportedContextMemberError(`${memberPath}.${prop}`);
33
+ },
34
+ apply() {
35
+ throw new UnsupportedContextMemberError(memberPath);
36
+ }
37
+ });
38
+ }
39
+ function withTouchTracking(base, touched, onTouch) {
40
+ return new Proxy(base, { get(target, prop, receiver) {
41
+ if (typeof prop === "string" && prop !== "then") {
42
+ const member = prop in target ? prop : `UNDOCUMENTED:${prop}`;
43
+ touched.add(member);
44
+ onTouch?.(member);
45
+ }
46
+ return Reflect.get(target, prop, receiver);
47
+ } });
48
+ }
49
+ //#endregion
50
+ //#region src/pieces/activepieces/worker/protocol.ts
51
+ const LOG_WRITE = "log.write";
52
+ const OUTPUT_UPDATE = "output.update";
53
+ const STORE_GET = "store.get";
54
+ const STORE_PUT = "store.put";
55
+ const STORE_DELETE = "store.delete";
56
+ const REACTOR_MODELS = "reactor.models";
57
+ const REACTOR_MODEL = "reactor.model";
58
+ const REACTOR_GET = "reactor.get";
59
+ const REACTOR_FIND = "reactor.find";
60
+ const REACTOR_CREATE = "reactor.create";
61
+ const REACTOR_EXECUTE = "reactor.execute";
62
+ //#endregion
63
+ //#region src/pieces/activepieces/worker/json-safe.ts
64
+ function jsonSafe(value) {
65
+ try {
66
+ return JSON.parse(JSON.stringify(value));
67
+ } catch {
68
+ return String(value);
69
+ }
70
+ }
71
+ //#endregion
72
+ //#region src/pieces/activepieces/context/store-scope.ts
73
+ function normalizeStoreScope(scope) {
74
+ return scope === StoreScope.PROJECT || scope === "PROJECT" ? "PROJECT" : "FLOW";
75
+ }
76
+ //#endregion
77
+ //#region src/pieces/activepieces/context/action.ts
78
+ var InMemoryConnectionsProvider = class {
79
+ values;
80
+ constructor(values = {}) {
81
+ this.values = new Map(Object.entries(values));
82
+ }
83
+ set(key, value) {
84
+ this.values.set(key, value);
85
+ }
86
+ get(key) {
87
+ return Promise.resolve(this.values.get(key) ?? null);
88
+ }
89
+ };
90
+ var InMemoryKeyValueStore = class {
91
+ entries;
92
+ constructor(seed = {}) {
93
+ this.entries = new Map(Object.entries(seed));
94
+ }
95
+ snapshot() {
96
+ return Object.fromEntries(this.entries);
97
+ }
98
+ put(key, value, scope) {
99
+ const stored = jsonSafe(value);
100
+ this.entries.set(this.scoped(key, scope), stored);
101
+ return Promise.resolve(stored);
102
+ }
103
+ get(key, scope) {
104
+ return Promise.resolve(this.entries.get(this.scoped(key, scope)) ?? null);
105
+ }
106
+ delete(key, scope) {
107
+ this.entries.delete(this.scoped(key, scope));
108
+ return Promise.resolve();
109
+ }
110
+ scoped(key, scope) {
111
+ return scope === "PROJECT" ? `PROJECT:${key}` : key;
112
+ }
113
+ };
114
+ function buildActionContext(options) {
115
+ const { identity = {} } = options;
116
+ const store = options.store ?? new InMemoryKeyValueStore();
117
+ const touched = /* @__PURE__ */ new Set();
118
+ return {
119
+ context: withTouchTracking({
120
+ executionType: options.executionType ?? "BEGIN",
121
+ auth: options.auth,
122
+ propsValue: options.propsValue,
123
+ store: {
124
+ put: (key, value, scope) => store.put(key, value, normalizeStoreScope(scope)),
125
+ get: (key, scope) => store.get(key, normalizeStoreScope(scope)),
126
+ delete: (key, scope) => store.delete(key, normalizeStoreScope(scope))
127
+ },
128
+ connections: options.connections ?? throwingStub("connections"),
129
+ tags: throwingStub("tags"),
130
+ server: throwingStub("server"),
131
+ files: options.files ?? throwingStub("files"),
132
+ output: options.output ?? throwingStub("output"),
133
+ reactor: options.reactor ?? throwingStub("reactor"),
134
+ agent: throwingStub("agent"),
135
+ run: {
136
+ id: identity.runId ?? "run",
137
+ stop: throwingStub("run.stop"),
138
+ pause: throwingStub("run.pause"),
139
+ respond: throwingStub("run.respond"),
140
+ createWaitpoint: throwingStub("run.createWaitpoint"),
141
+ waitForWaitpoint: throwingStub("run.waitForWaitpoint")
142
+ },
143
+ project: {
144
+ id: identity.projectId ?? "project",
145
+ externalId: () => Promise.resolve(identity.projectId ?? "project")
146
+ },
147
+ flows: {
148
+ list: throwingStub("flows.list"),
149
+ current: {
150
+ id: identity.flowId ?? "flow",
151
+ version: { id: identity.flowVersionId ?? "flow-version" }
152
+ }
153
+ },
154
+ step: { name: identity.stepName ?? "step" },
155
+ generateResumeUrl: throwingStub("generateResumeUrl")
156
+ }, touched, options.onTouch),
157
+ touched
158
+ };
159
+ }
160
+ //#endregion
161
+ //#region src/pieces/activepieces/context/limits.ts
162
+ const DEFAULT_MAX_FILE_BYTES = 8 * 1024 * 1024;
163
+ function maxFileBytes() {
164
+ const raw = process.env.PH_PIECE_MAX_FILE_BYTES;
165
+ if (raw === void 0) return DEFAULT_MAX_FILE_BYTES;
166
+ const parsed = Number(raw);
167
+ return Number.isFinite(parsed) && parsed > 0 ? Math.floor(parsed) : DEFAULT_MAX_FILE_BYTES;
168
+ }
169
+ var FileTooLargeError = class extends Error {
170
+ size;
171
+ limit;
172
+ constructor(size, limit = maxFileBytes()) {
173
+ super(`File of ${size} bytes exceeds the ${limit} byte limit (raise PH_PIECE_MAX_FILE_BYTES to allow more)`);
174
+ this.name = "FileTooLargeError";
175
+ this.size = size;
176
+ this.limit = limit;
177
+ }
178
+ };
179
+ function assertWithinLimit(size) {
180
+ const limit = maxFileBytes();
181
+ if (size > limit) throw new FileTooLargeError(size, limit);
182
+ }
183
+ //#endregion
184
+ //#region src/pieces/activepieces/context/files.ts
185
+ const APFILE_SCHEME = "apfile://";
186
+ var DataUriFilesService = class {
187
+ write(file) {
188
+ const data = Buffer.isBuffer(file.data) ? file.data : Buffer.from(file.data);
189
+ if (data.byteLength > maxFileBytes()) return Promise.reject(new FileTooLargeError(data.byteLength));
190
+ return Promise.resolve(`data:application/octet-stream;base64,${data.toString("base64")}`);
191
+ }
192
+ };
193
+ const EXTENSION_TYPES = {
194
+ pdf: "application/pdf",
195
+ png: "image/png",
196
+ jpg: "image/jpeg",
197
+ jpeg: "image/jpeg",
198
+ webp: "image/webp",
199
+ tif: "image/tiff",
200
+ tiff: "image/tiff",
201
+ txt: "text/plain",
202
+ json: "application/json",
203
+ csv: "text/csv"
204
+ };
205
+ function contentTypeFor(fileName) {
206
+ const extension = fileName.split(".").pop()?.toLowerCase();
207
+ return extension ? EXTENSION_TYPES[extension] : void 0;
208
+ }
209
+ var StagedFilesService = class {
210
+ files = [];
211
+ constructor(stagingDir) {
212
+ this.stagingDir = stagingDir;
213
+ }
214
+ staged() {
215
+ return [...this.files];
216
+ }
217
+ async write(file) {
218
+ const data = Buffer.isBuffer(file.data) ? file.data : Buffer.from(file.data);
219
+ assertWithinLimit(data.byteLength);
220
+ const token = randomUUID();
221
+ const fileName = file.fileName && file.fileName !== "" ? file.fileName : token;
222
+ const target = path.join(this.stagingDir, token);
223
+ await mkdir(this.stagingDir, { recursive: true });
224
+ await writeFile(target, data);
225
+ this.files.push({
226
+ token: `${APFILE_SCHEME}${token}`,
227
+ path: target,
228
+ fileName,
229
+ size: data.byteLength,
230
+ contentType: contentTypeFor(fileName)
231
+ });
232
+ return `${APFILE_SCHEME}${token}`;
233
+ }
234
+ };
235
+ function rewriteFileRefs(value, refs) {
236
+ if (refs.size === 0) return value;
237
+ if (typeof value === "string") return refs.get(value) ?? value;
238
+ if (Array.isArray(value)) return value.map((entry) => rewriteFileRefs(entry, refs));
239
+ if (typeof value === "object" && value !== null) {
240
+ const out = {};
241
+ for (const [key, entry] of Object.entries(value)) out[key] = rewriteFileRefs(entry, refs);
242
+ return out;
243
+ }
244
+ return value;
245
+ }
246
+ //#endregion
247
+ //#region src/pieces/activepieces/context/trigger.ts
248
+ const MIN_SCHEDULE_INTERVAL_MS = 6e4;
249
+ var InvalidCronExpressionError = class extends Error {
250
+ constructor(cronExpression) {
251
+ super(`Invalid cron expression "${cronExpression}"`);
252
+ this.name = "InvalidCronExpressionError";
253
+ }
254
+ };
255
+ var InvalidScheduleIntervalError = class extends Error {
256
+ constructor(intervalMs) {
257
+ super(`Invalid schedule interval ${String(intervalMs)}: expected a whole number of milliseconds, at least ${MIN_SCHEDULE_INTERVAL_MS}`);
258
+ this.name = "InvalidScheduleIntervalError";
259
+ }
260
+ };
261
+ function validateSchedule(request) {
262
+ if ("intervalMs" in request) {
263
+ const { intervalMs } = request;
264
+ if (!Number.isInteger(intervalMs) || intervalMs < 6e4) throw new InvalidScheduleIntervalError(intervalMs);
265
+ return { intervalMs };
266
+ }
267
+ const timezone = request.timezone ?? "UTC";
268
+ let parsed;
269
+ try {
270
+ parsed = new Cron(request.cronExpression, {
271
+ timezone,
272
+ legacyMode: false
273
+ });
274
+ } catch {
275
+ throw new InvalidCronExpressionError(request.cronExpression);
276
+ }
277
+ if (!parsed.nextRun()) throw new InvalidCronExpressionError(request.cronExpression);
278
+ return {
279
+ cronExpression: request.cronExpression,
280
+ timezone
281
+ };
282
+ }
283
+ function buildTriggerContext(options) {
284
+ const { identity = {} } = options;
285
+ const store = options.store ?? new InMemoryKeyValueStore();
286
+ const touched = /* @__PURE__ */ new Set();
287
+ const schedules = [];
288
+ const listeners = [];
289
+ const prefix = options.storePrefix ?? "";
290
+ const flowId = identity.flowId ?? "flow";
291
+ const scopedKey = (key, scope) => normalizeStoreScope(scope) === "PROJECT" ? `${prefix}${key}` : `${prefix}flow_${flowId}/${key}`;
292
+ const address = (key, scope) => options.hostPartitionedStore ? [key, normalizeStoreScope(scope)] : [scopedKey(key, scope), void 0];
293
+ return {
294
+ context: withTouchTracking({
295
+ auth: options.auth,
296
+ propsValue: options.propsValue,
297
+ isRepublish: options.isRepublish ?? false,
298
+ store: {
299
+ put: (key, value, scope) => {
300
+ const [at, partition] = address(key, scope);
301
+ return store.put(at, value, partition);
302
+ },
303
+ get: (key, scope) => store.get(...address(key, scope)),
304
+ delete: (key, scope) => store.delete(...address(key, scope))
305
+ },
306
+ flows: {
307
+ list: options.flows?.list.bind(options.flows) ?? throwingStub("flows.list"),
308
+ current: {
309
+ id: identity.flowId ?? "flow",
310
+ version: { id: identity.flowVersionId ?? "flow-version" }
311
+ }
312
+ },
313
+ step: { name: identity.stepName ?? "trigger" },
314
+ project: {
315
+ id: identity.projectId ?? "project",
316
+ externalId: () => Promise.resolve(identity.projectId ?? "project")
317
+ },
318
+ connections: options.connections ?? { get: throwingStub("connections.get") },
319
+ server: options.server ?? throwingStub("server"),
320
+ webhookUrl: options.webhookUrl ?? "http://localhost:0/webhook",
321
+ payload: options.payload,
322
+ setSchedule: (schedule) => {
323
+ schedules.push(validateSchedule(schedule));
324
+ },
325
+ app: { createListeners: (listener) => {
326
+ listeners.push(listener);
327
+ } },
328
+ files: options.files ?? throwingStub("files")
329
+ }, touched, options.onTouch),
330
+ touched,
331
+ schedules,
332
+ listeners
333
+ };
334
+ }
335
+ function extractDedupeKey(payload) {
336
+ if (typeof payload !== "object" || payload === null) return void 0;
337
+ const value = payload[DEDUPE_KEY_PROPERTY];
338
+ return typeof value === "string" ? value : void 0;
339
+ }
340
+ var TriggerHookNotImplementedError = class extends Error {
341
+ constructor(triggerName, hook) {
342
+ super(`Trigger "${triggerName}" does not implement ${hook}()`);
343
+ this.name = "TriggerHookNotImplementedError";
344
+ }
345
+ };
346
+ async function runTriggerHook(trigger, hook, handle) {
347
+ const fn = trigger[hook];
348
+ if (typeof fn !== "function") throw new TriggerHookNotImplementedError(trigger.name ?? "unknown", hook);
349
+ return await fn.call(trigger, handle.context);
350
+ }
351
+ //#endregion
352
+ //#region src/pieces/activepieces/worker/egress.ts
353
+ const EGRESS_DENIED_CODE = "EGRESS_DENIED";
354
+ const DEFAULT_EGRESS_POLICY = {};
355
+ var EgressDeniedError = class extends Error {
356
+ code = EGRESS_DENIED_CODE;
357
+ host;
358
+ port;
359
+ address;
360
+ constructor(reason, where) {
361
+ super(`Egress denied: ${reason}`);
362
+ this.name = "EgressDeniedError";
363
+ this.host = where.host;
364
+ this.port = where.port;
365
+ this.address = where.address;
366
+ }
367
+ };
368
+ const IPV4_COMPATIBLE = new net.BlockList();
369
+ IPV4_COMPATIBLE.addSubnet("::", 96, "ipv6");
370
+ function familyOf(address) {
371
+ return isIP(address) === 6 ? "ipv6" : "ipv4";
372
+ }
373
+ function parseAddress(value) {
374
+ const bare = value.split("%")[0];
375
+ return isIP(bare) === 0 ? void 0 : bare;
376
+ }
377
+ function addAllowedAddress(list, spec) {
378
+ const slash = spec.indexOf("/");
379
+ const mask = slash === -1 ? "" : spec.slice(slash + 1);
380
+ const address = parseAddress(slash === -1 ? spec : spec.slice(0, slash));
381
+ if (!address) throw new Error(`Egress policy entry "${spec}" is not an IP address`);
382
+ const family = familyOf(address);
383
+ const width = family === "ipv6" ? 128 : 32;
384
+ const prefix = mask === "" ? width : Number(mask);
385
+ if (!Number.isInteger(prefix) || prefix < 1 || prefix > width) throw new Error(`Egress policy entry "${spec}" has an invalid prefix`);
386
+ list.addSubnet(address, prefix, family);
387
+ }
388
+ const nativeLookup = originalOf(dns, "lookup");
389
+ const RESOLVER_METHODS = [
390
+ "resolve",
391
+ "resolve4",
392
+ "resolve6",
393
+ "resolveAny",
394
+ "resolveCaa",
395
+ "resolveCname",
396
+ "resolveMx",
397
+ "resolveNaptr",
398
+ "resolveNs",
399
+ "resolvePtr",
400
+ "resolveSoa",
401
+ "resolveSrv",
402
+ "resolveTxt",
403
+ "reverse"
404
+ ];
405
+ function isPrivateAddress(value) {
406
+ const address = parseAddress(value);
407
+ if (!address) return true;
408
+ if (IPV4_COMPATIBLE.check(address, familyOf(address))) return true;
409
+ return ssrfIpClassifier.isBlockedIp({
410
+ ip: address,
411
+ allowList: []
412
+ });
413
+ }
414
+ function compile(policy) {
415
+ const hosts = policy.allowHosts?.map((host) => host.trim().toLowerCase());
416
+ const ports = policy.allowPorts?.map((port) => {
417
+ if (!Number.isInteger(port) || port < 0 || port > 65535) throw new Error(`Egress policy port ${String(port)} is out of range`);
418
+ return port;
419
+ });
420
+ const specs = policy.allowAddresses ?? [];
421
+ const addresses = new net.BlockList();
422
+ for (const spec of specs) addAllowedAddress(addresses, spec);
423
+ return {
424
+ hosts: hosts && hosts.length > 0 ? hosts : void 0,
425
+ addresses: specs.length > 0 ? addresses : void 0,
426
+ ports: ports && ports.length > 0 ? ports : void 0,
427
+ allowPrivate: policy.allowPrivateAddresses === true
428
+ };
429
+ }
430
+ function hostAllowed(policy, host) {
431
+ if (!policy.hosts) return true;
432
+ const name = host.toLowerCase();
433
+ return policy.hosts.some((entry) => entry.startsWith("*.") ? name.length > entry.length - 1 && name.endsWith(entry.slice(1)) : entry === name);
434
+ }
435
+ function addressAllowed(policy, address) {
436
+ const ip = parseAddress(address);
437
+ if (!ip) return false;
438
+ if (policy.addresses?.check(ip, familyOf(ip))) return true;
439
+ return policy.allowPrivate || !isPrivateAddress(ip);
440
+ }
441
+ let inFlight;
442
+ const started = new AsyncLocalStorage();
443
+ function policiesInForce() {
444
+ const inherited = started.getStore();
445
+ const policies = [];
446
+ if (inFlight) policies.push(inFlight);
447
+ if (inherited && inherited !== inFlight) policies.push(inherited);
448
+ return policies;
449
+ }
450
+ async function runWithEgressPolicy(policy, work) {
451
+ const compiled = policy ? compile(policy) : void 0;
452
+ installEgressGuard();
453
+ inFlight = compiled;
454
+ try {
455
+ return await started.run(compiled, work);
456
+ } finally {
457
+ if (inFlight === compiled) inFlight = void 0;
458
+ }
459
+ }
460
+ function normalizeConnectArgs(args) {
461
+ if (Array.isArray(args[0])) {
462
+ const [options, callback] = args[0];
463
+ return {
464
+ options: { ...options },
465
+ callback
466
+ };
467
+ }
468
+ const first = args[0];
469
+ let options = {};
470
+ if (typeof first === "object" && first !== null) options = { ...first };
471
+ else if (typeof first === "string" && Number.isNaN(Number(first))) options.path = first;
472
+ else {
473
+ options.port = first;
474
+ if (typeof args[1] === "string") options.host = args[1];
475
+ }
476
+ const last = args[args.length - 1];
477
+ return {
478
+ options,
479
+ callback: typeof last === "function" ? last : void 0
480
+ };
481
+ }
482
+ function guardedLookup(policies, host, port) {
483
+ return (hostname, options, callback) => {
484
+ const asked = options;
485
+ nativeLookup(hostname, options, (error, result, family) => {
486
+ if (error) {
487
+ callback(error);
488
+ return;
489
+ }
490
+ try {
491
+ const entries = asked.all ? result : [{
492
+ address: result,
493
+ family: family ?? 0
494
+ }];
495
+ const permitted = entries.filter((entry) => policies.every((policy) => addressAllowed(policy, entry.address)));
496
+ if (permitted.length === 0) {
497
+ callback(new EgressDeniedError(`host "${host}" resolves to ${entries.map((entry) => entry.address).join(", ") || "nothing"}, which the policy does not permit`, {
498
+ host,
499
+ port,
500
+ address: entries[0]?.address
501
+ }));
502
+ return;
503
+ }
504
+ if (asked.all) callback(null, permitted);
505
+ else callback(null, permitted[0].address, permitted[0].family);
506
+ } catch (failure) {
507
+ callback(failure instanceof Error ? failure : new Error(String(failure)));
508
+ }
509
+ });
510
+ };
511
+ }
512
+ function denyReason(policies, options) {
513
+ if (typeof options.path === "string") return new EgressDeniedError(`connections to local socket "${options.path}" are not permitted`, { host: options.path });
514
+ const host = typeof options.host === "string" ? options.host : "";
515
+ const port = options.port === void 0 ? void 0 : Number(options.port);
516
+ for (const policy of policies) {
517
+ if (policy.ports && (port === void 0 || !policy.ports.includes(port))) return new EgressDeniedError(`port ${String(port)} on host "${host}" is not permitted`, {
518
+ host,
519
+ port
520
+ });
521
+ if (!hostAllowed(policy, host)) return new EgressDeniedError(`host "${host}" is not on the allowlist`, {
522
+ host,
523
+ port
524
+ });
525
+ if (isIP(host) && !addressAllowed(policy, host)) return new EgressDeniedError(`address ${host} is not permitted`, {
526
+ host,
527
+ port,
528
+ address: host
529
+ });
530
+ }
531
+ }
532
+ function failLater(emitter, error, callback) {
533
+ process.nextTick(() => {
534
+ if (typeof callback === "function") callback(error);
535
+ else emitter.emit("error", error);
536
+ });
537
+ }
538
+ function originalOf(target, name) {
539
+ return Object.getOwnPropertyDescriptor(target, name)?.value;
540
+ }
541
+ function resolverDenial(method, args) {
542
+ const host = typeof args[0] === "string" ? args[0] : "";
543
+ return new EgressDeniedError(`DNS ${method}("${host}") is not permitted; use a hostname in a request instead`, { host });
544
+ }
545
+ function refuseResolvers(target, promised) {
546
+ for (const method of RESOLVER_METHODS) {
547
+ const original = originalOf(target, method);
548
+ if (typeof original !== "function") continue;
549
+ function refused(...args) {
550
+ if (policiesInForce().length === 0) return original.apply(this, args);
551
+ const denied = resolverDenial(method, args);
552
+ if (promised) return Promise.reject(denied);
553
+ const callback = args[args.length - 1];
554
+ if (typeof callback !== "function") throw denied;
555
+ process.nextTick(() => callback(denied));
556
+ }
557
+ seal(target, method, refused);
558
+ }
559
+ }
560
+ function seal(target, name, value) {
561
+ Object.defineProperty(target, name, {
562
+ value,
563
+ writable: false,
564
+ configurable: false,
565
+ enumerable: false
566
+ });
567
+ }
568
+ let installed = false;
569
+ function installEgressGuard() {
570
+ if (installed) return;
571
+ installed = true;
572
+ const connect = originalOf(net.Socket.prototype, "connect");
573
+ function patchedConnect(...args) {
574
+ const policies = policiesInForce();
575
+ if (policies.length === 0) return connect.apply(this, args);
576
+ const { options, callback } = normalizeConnectArgs(args);
577
+ if (typeof options.path !== "string" && !options.host) options.host = "localhost";
578
+ const denied = denyReason(policies, options);
579
+ if (denied) {
580
+ process.nextTick(() => this.destroy(denied));
581
+ return this;
582
+ }
583
+ if (typeof options.host === "string" && !isIP(options.host)) options.lookup = guardedLookup(policies, options.host, options.port === void 0 ? void 0 : Number(options.port));
584
+ return connect.call(this, options, callback);
585
+ }
586
+ seal(net.Socket.prototype, "connect", patchedConnect);
587
+ const send = originalOf(dgram.Socket.prototype, "send");
588
+ function patchedSend(...args) {
589
+ if (policiesInForce().length === 0) {
590
+ send.apply(this, args);
591
+ return;
592
+ }
593
+ const host = args.find((arg, index) => index > 0 && typeof arg === "string");
594
+ const last = args[args.length - 1];
595
+ failLater(this, new EgressDeniedError(`UDP to "${host ?? "the requested address"}" is not permitted`, { host: host ?? "" }), typeof last === "function" ? last : void 0);
596
+ }
597
+ seal(dgram.Socket.prototype, "send", patchedSend);
598
+ const bind = originalOf(dgram.Socket.prototype, "bind");
599
+ function patchedBind(...args) {
600
+ if (policiesInForce().length === 0) return bind.apply(this, args);
601
+ failLater(this, new EgressDeniedError("binding a UDP socket is not permitted", { host: "" }), void 0);
602
+ return this;
603
+ }
604
+ seal(dgram.Socket.prototype, "bind", patchedBind);
605
+ const listen = originalOf(net.Server.prototype, "listen");
606
+ function patchedListen(...args) {
607
+ if (policiesInForce().length === 0) return listen.apply(this, args);
608
+ failLater(this, new EgressDeniedError("listening for connections is not permitted", { host: "" }), void 0);
609
+ return this;
610
+ }
611
+ seal(net.Server.prototype, "listen", patchedListen);
612
+ refuseResolvers(dns, false);
613
+ refuseResolvers(dns.Resolver.prototype, false);
614
+ refuseResolvers(dns.promises, true);
615
+ refuseResolvers(dns.promises.Resolver.prototype, true);
616
+ }
617
+ //#endregion
618
+ //#region src/pieces/activepieces/worker/redact.ts
619
+ const REDACTED_PREFIX = "[redacted:";
620
+ const SECRET_MARKER = "[redacted:secret]";
621
+ const CIRCULAR_MARKER = "[circular]";
622
+ const TRUNCATED_MARKER = "[truncated]";
623
+ const ERROR_MAX_DEPTH = 8;
624
+ const ERROR_MAX_NODES = 1e3;
625
+ const STACK_GUARD_DEPTH = 200;
626
+ const SENSITIVE_NAMES = new Set([
627
+ "auth",
628
+ "authorization",
629
+ "proxyauthorization",
630
+ "wwwauthenticate",
631
+ "authtoken",
632
+ "xauthtoken",
633
+ "apikey",
634
+ "xapikey",
635
+ "apisecret",
636
+ "bearer",
637
+ "cookie",
638
+ "setcookie",
639
+ "credential",
640
+ "credentials",
641
+ "password",
642
+ "passwd",
643
+ "passphrase",
644
+ "pwd",
645
+ "privatekey",
646
+ "secret",
647
+ "secrettext",
648
+ "sessionid",
649
+ "signature",
650
+ "token"
651
+ ]);
652
+ const SENSITIVE_SUFFIXES = [
653
+ "apikey",
654
+ "credentials",
655
+ "password",
656
+ "privatekey",
657
+ "secret",
658
+ "token"
659
+ ];
660
+ const TEXT_FIELD = new RegExp(String.raw`\b(authorization|proxy-authorization|api[-_]?key|x-api-key|access[-_]?token|refresh[-_]?token|client[-_]?secret|set-cookie|cookie|password|secret|token|(?:[a-z0-9]+[-_])*signature(?:[-_][a-z0-9]+)*)\b(["']?)(\s*[:=]\s*)(["']?)((?:(?:Bearer|Basic|Token)\s+)?[^\s",;&)}]+)\4`, "gi");
661
+ const AUTH_SCHEME = /\b(Bearer|Basic|Token)\s+([A-Za-z0-9._~+/=-]{8,})/g;
662
+ const QUERY_PARAM = /([?&])([A-Za-z0-9_.%[\]-]+)=([^&\s"'<>]+)/g;
663
+ const URL_USERINFO = /([a-z][a-z0-9+.-]*:\/\/)([^/\s:@]+):([^/\s@]+)@/gi;
664
+ function normalizeName(name) {
665
+ return name.toLowerCase().replace(/[^a-z0-9]/g, "");
666
+ }
667
+ function isSensitiveName(name) {
668
+ const normalized = normalizeName(name);
669
+ if (!normalized) return false;
670
+ if (SENSITIVE_NAMES.has(normalized)) return true;
671
+ if (normalized.includes("signature")) return true;
672
+ return SENSITIVE_SUFFIXES.some((suffix) => normalized.length > suffix.length && normalized.endsWith(suffix));
673
+ }
674
+ function marker(name) {
675
+ return `[redacted:${name.toLowerCase()}]`;
676
+ }
677
+ function shannonEntropy(text) {
678
+ const counts = /* @__PURE__ */ new Map();
679
+ for (const char of text) counts.set(char, (counts.get(char) ?? 0) + 1);
680
+ let entropy = 0;
681
+ for (const count of counts.values()) {
682
+ const p = count / text.length;
683
+ entropy -= p * Math.log2(p);
684
+ }
685
+ return entropy;
686
+ }
687
+ const MIN_VALUE_LENGTH = 8;
688
+ const MIN_DISTINCT_CHARS = 5;
689
+ const MIN_ENTROPY_BITS = 2;
690
+ const MIN_DECLARED_LENGTH = 4;
691
+ function isRedactableValue(value) {
692
+ if (typeof value !== "string") return false;
693
+ if (value.length < MIN_VALUE_LENGTH) return false;
694
+ if (new Set(value).size < MIN_DISTINCT_CHARS) return false;
695
+ return shannonEntropy(value) >= MIN_ENTROPY_BITS;
696
+ }
697
+ function isDeclaredValue(value) {
698
+ return typeof value === "string" && value.length >= MIN_DECLARED_LENGTH;
699
+ }
700
+ const STRUCTURAL_NAMES = new Set(["type", "authtype"]);
701
+ const URL_LIKE = /^[a-z][a-z0-9+.-]*:\/\//i;
702
+ function collectSecretValues(value, into = /* @__PURE__ */ new Set(), depth = 0) {
703
+ if (depth > ERROR_MAX_DEPTH) return into;
704
+ if (isRedactableValue(value)) {
705
+ if (!URL_LIKE.test(value)) into.add(value);
706
+ return into;
707
+ }
708
+ if (Array.isArray(value)) {
709
+ for (const entry of value) collectSecretValues(entry, into, depth + 1);
710
+ return into;
711
+ }
712
+ if (typeof value === "object" && value !== null) for (const [key, entry] of Object.entries(value)) {
713
+ if (STRUCTURAL_NAMES.has(normalizeName(key))) continue;
714
+ collectSecretValues(entry, into, depth + 1);
715
+ }
716
+ return into;
717
+ }
718
+ const thrownSecrets = /* @__PURE__ */ new WeakMap();
719
+ function rememberSecrets(error, values) {
720
+ if (typeof error === "object" && error !== null && values.length > 0) thrownSecrets.set(error, values);
721
+ return error;
722
+ }
723
+ function secretsFor(error) {
724
+ if (typeof error !== "object" || error === null) return [];
725
+ return thrownSecrets.get(error) ?? [];
726
+ }
727
+ function preparePass(options) {
728
+ return {
729
+ values: [...options?.values ?? []].filter(isDeclaredValue).sort((a, b) => b.length - a.length),
730
+ maxDepth: options?.maxDepth ?? STACK_GUARD_DEPTH,
731
+ maxNodes: options?.maxNodes ?? Number.POSITIVE_INFINITY,
732
+ nodes: 0
733
+ };
734
+ }
735
+ function safeDecode(name) {
736
+ try {
737
+ return decodeURIComponent(name);
738
+ } catch {
739
+ return name;
740
+ }
741
+ }
742
+ function replaceValues(text, values) {
743
+ let result = text;
744
+ for (const value of values) {
745
+ if (result.includes(value)) result = result.split(value).join(SECRET_MARKER);
746
+ const encoded = encodeURIComponent(value);
747
+ if (encoded !== value && result.includes(encoded)) result = result.split(encoded).join(SECRET_MARKER);
748
+ }
749
+ return result;
750
+ }
751
+ function redactText(text, pass) {
752
+ let result = replaceValues(text, pass.values);
753
+ result = result.replace(URL_USERINFO, (_match, scheme, user) => `${scheme}${user}:${marker("password")}@`);
754
+ result = result.replace(QUERY_PARAM, (match, sep, name) => isSensitiveName(safeDecode(name)) ? `${sep}${name}=${marker(name)}` : match);
755
+ result = result.replace(AUTH_SCHEME, (_match, scheme) => `${scheme} ${marker(scheme)}`);
756
+ return result.replace(TEXT_FIELD, (match, name, nameQuote, sep, quote, value) => value.startsWith("[redacted:") ? match : `${name}${nameQuote}${sep}${quote}${marker(name)}${quote}`);
757
+ }
758
+ function walk(value, pass, depth, seen) {
759
+ if (typeof value === "string") return redactText(value, pass);
760
+ if (typeof value !== "object" || value === null) return value;
761
+ if (seen.has(value)) return CIRCULAR_MARKER;
762
+ if (depth >= pass.maxDepth) return TRUNCATED_MARKER;
763
+ if (pass.nodes >= pass.maxNodes) return TRUNCATED_MARKER;
764
+ pass.nodes += 1;
765
+ seen.add(value);
766
+ try {
767
+ if (Array.isArray(value)) return value.map((entry) => walk(entry, pass, depth + 1, seen));
768
+ const result = {};
769
+ for (const [key, entry] of Object.entries(value)) result[key] = isSensitiveName(key) ? marker(key) : walk(entry, pass, depth + 1, seen);
770
+ return result;
771
+ } finally {
772
+ seen.delete(value);
773
+ }
774
+ }
775
+ function redact(value, options) {
776
+ return walk(value, preparePass(options), 0, /* @__PURE__ */ new Set());
777
+ }
778
+ function redactError(value, options) {
779
+ return redact(value, {
780
+ maxDepth: ERROR_MAX_DEPTH,
781
+ maxNodes: ERROR_MAX_NODES,
782
+ ...options
783
+ });
784
+ }
785
+ function containsRedactedMarker(value, depth = 0) {
786
+ if (typeof value === "string") return value.includes(REDACTED_PREFIX);
787
+ if (typeof value !== "object" || value === null) return false;
788
+ if (depth >= STACK_GUARD_DEPTH) return false;
789
+ return Object.values(value).some((entry) => containsRedactedMarker(entry, depth + 1));
790
+ }
791
+ function redactMessage(text, options) {
792
+ return redactText(text, preparePass(options));
793
+ }
794
+ //#endregion
795
+ export { REACTOR_MODEL as A, jsonSafe as C, REACTOR_EXECUTE as D, REACTOR_CREATE as E, UnsupportedContextMemberError as F, throwingStub as I, withTouchTracking as L, STORE_DELETE as M, STORE_GET as N, REACTOR_FIND as O, STORE_PUT as P, getActions as R, buildActionContext as S, OUTPUT_UPDATE as T, FileTooLargeError as _, redactMessage as a, InMemoryConnectionsProvider as b, DEFAULT_EGRESS_POLICY as c, buildTriggerContext as d, extractDedupeKey as f, rewriteFileRefs as g, StagedFilesService as h, redactError as i, REACTOR_MODELS as j, REACTOR_GET as k, installEgressGuard as l, DataUriFilesService as m, containsRedactedMarker as n, rememberSecrets as o, runTriggerHook as p, redact as r, secretsFor as s, collectSecretValues as t, runWithEgressPolicy as u, assertWithinLimit as v, LOG_WRITE as w, InMemoryKeyValueStore as x, maxFileBytes as y, getTriggers as z };
796
+
797
+ //# sourceMappingURL=redact-C7LWgAyD.js.map