@walkeros/cli 4.1.0 → 4.1.1-next-1779822275564
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 +32 -0
- package/dist/cli.js +1670 -1374
- package/dist/index.d.ts +568 -114
- package/dist/index.js +300 -111
- package/dist/index.js.map +1 -1
- package/package.json +7 -7
package/dist/index.js
CHANGED
|
@@ -2895,6 +2895,16 @@ export default async function(context = {}) {
|
|
|
2895
2895
|
|
|
2896
2896
|
const result = await startFlow(config);
|
|
2897
2897
|
|
|
2898
|
+
// Telemetry observer installation: the host (pipeline.ts) builds the
|
|
2899
|
+
// observer functions via createTelemetryObserver + createBatchedPoster
|
|
2900
|
+
// and forwards them through context. Added to collector.observers so the
|
|
2901
|
+
// runtime self-emission loop drives them.
|
|
2902
|
+
if (context.observers) {
|
|
2903
|
+
for (const observer of context.observers) {
|
|
2904
|
+
result.collector.observers.add(observer);
|
|
2905
|
+
}
|
|
2906
|
+
}
|
|
2907
|
+
|
|
2898
2908
|
const httpSource = Object.values(result.collector.sources || {})
|
|
2899
2909
|
.find(s => 'httpHandler' in s && typeof s.httpHandler === 'function');
|
|
2900
2910
|
|
|
@@ -2926,13 +2936,29 @@ function generateWebEntry(stage1Path, dataPayload, options = {}) {
|
|
|
2926
2936
|
}
|
|
2927
2937
|
}` : "";
|
|
2928
2938
|
const stage1Specifier = toFileImportSpecifier(stage1Path);
|
|
2929
|
-
|
|
2939
|
+
const telemetryImport = options.telemetry ? `
|
|
2940
|
+
import { createBatchedPoster as __cbp, createTelemetryObserver as __cto } from '@walkeros/core';` : "";
|
|
2941
|
+
const telemetryBlock = options.telemetry ? `
|
|
2942
|
+
// --- Telemetry wiring ---
|
|
2943
|
+
{
|
|
2944
|
+
const __emit = __cbp({
|
|
2945
|
+
url: ${JSON.stringify(options.telemetry.observerUrl)},
|
|
2946
|
+
token: ${JSON.stringify(options.telemetry.ingestToken)},
|
|
2947
|
+
});
|
|
2948
|
+
const __observer = __cto(__emit, {
|
|
2949
|
+
flowId: ${JSON.stringify(options.telemetry.flowId)},
|
|
2950
|
+
level: ${JSON.stringify(options.telemetry.level ?? "standard")},
|
|
2951
|
+
sample: ${JSON.stringify(options.telemetry.sample ?? 1)},
|
|
2952
|
+
});
|
|
2953
|
+
collector.observers.add(__observer);
|
|
2954
|
+
}` : "";
|
|
2955
|
+
return `import { startFlow, wireConfig } from '${stage1Specifier}';${telemetryImport}
|
|
2930
2956
|
|
|
2931
2957
|
const __configData = ${dataPayload};
|
|
2932
2958
|
|
|
2933
2959
|
(async () => {
|
|
2934
2960
|
const config = wireConfig(__configData);${envBlock}
|
|
2935
|
-
const { collector, elb } = await startFlow(config);${assignmentCode}
|
|
2961
|
+
const { collector, elb } = await startFlow(config);${telemetryBlock}${assignmentCode}
|
|
2936
2962
|
})();`;
|
|
2937
2963
|
}
|
|
2938
2964
|
function generateWrapEntry(stage1Path, options = {}) {
|
|
@@ -3014,11 +3040,27 @@ function generateWrapEntry(stage1Path, options = {}) {
|
|
|
3014
3040
|
}
|
|
3015
3041
|
}` : "";
|
|
3016
3042
|
const stage1Specifier = toFileImportSpecifier(stage1Path);
|
|
3017
|
-
|
|
3043
|
+
const telemetryImport = options.telemetry ? `
|
|
3044
|
+
import { createBatchedPoster as __cbp, createTelemetryObserver as __cto } from '@walkeros/core';` : "";
|
|
3045
|
+
const telemetryBlock = options.telemetry ? `
|
|
3046
|
+
// --- Telemetry wiring ---
|
|
3047
|
+
{
|
|
3048
|
+
const __emit = __cbp({
|
|
3049
|
+
url: ${JSON.stringify(options.telemetry.observerUrl)},
|
|
3050
|
+
token: ${JSON.stringify(options.telemetry.ingestToken)},
|
|
3051
|
+
});
|
|
3052
|
+
const __observer = __cto(__emit, {
|
|
3053
|
+
flowId: ${JSON.stringify(options.telemetry.flowId)},
|
|
3054
|
+
level: ${JSON.stringify(options.telemetry.level ?? "standard")},
|
|
3055
|
+
sample: ${JSON.stringify(options.telemetry.sample ?? 1)},
|
|
3056
|
+
});
|
|
3057
|
+
collector.observers.add(__observer);
|
|
3058
|
+
}` : "";
|
|
3059
|
+
return `import { startFlow, wireConfig, __configData } from '${stage1Specifier}';${telemetryImport}
|
|
3018
3060
|
|
|
3019
3061
|
(async () => {${preflightBlock}
|
|
3020
3062
|
const config = wireConfig(__configData);${envBlock}
|
|
3021
|
-
const { collector, elb } = await startFlow(config);${assignmentCode}
|
|
3063
|
+
const { collector, elb } = await startFlow(config);${telemetryBlock}${assignmentCode}
|
|
3022
3064
|
})();`;
|
|
3023
3065
|
}
|
|
3024
3066
|
function generateWrapEntryServer(stage1Path) {
|
|
@@ -3040,6 +3082,16 @@ export default async function(context = {}) {
|
|
|
3040
3082
|
|
|
3041
3083
|
const result = await startFlow(config);
|
|
3042
3084
|
|
|
3085
|
+
// Telemetry observer installation: the host (pipeline.ts) builds the
|
|
3086
|
+
// observer functions via createTelemetryObserver + createBatchedPoster
|
|
3087
|
+
// and forwards them through context. Added to collector.observers so the
|
|
3088
|
+
// runtime self-emission loop drives them.
|
|
3089
|
+
if (context.observers) {
|
|
3090
|
+
for (const observer of context.observers) {
|
|
3091
|
+
result.collector.observers.add(observer);
|
|
3092
|
+
}
|
|
3093
|
+
}
|
|
3094
|
+
|
|
3043
3095
|
const httpSource = Object.values(result.collector.sources || {})
|
|
3044
3096
|
.find(s => 'httpHandler' in s && typeof s.httpHandler === 'function');
|
|
3045
3097
|
|
|
@@ -3906,7 +3958,14 @@ function startDrainPump(pending, options = {}) {
|
|
|
3906
3958
|
}
|
|
3907
3959
|
|
|
3908
3960
|
// src/commands/push/flow-context.ts
|
|
3909
|
-
|
|
3961
|
+
function defaultPushError(error, startTime) {
|
|
3962
|
+
return {
|
|
3963
|
+
success: false,
|
|
3964
|
+
duration: Date.now() - startTime,
|
|
3965
|
+
error: getErrorMessage(error)
|
|
3966
|
+
};
|
|
3967
|
+
}
|
|
3968
|
+
async function withFlowContext(options, fn, onError) {
|
|
3910
3969
|
const {
|
|
3911
3970
|
esmPath,
|
|
3912
3971
|
platform,
|
|
@@ -3998,11 +4057,7 @@ async function withFlowContext(options, fn) {
|
|
|
3998
4057
|
}
|
|
3999
4058
|
return await fn(flowModule);
|
|
4000
4059
|
} catch (error) {
|
|
4001
|
-
return
|
|
4002
|
-
success: false,
|
|
4003
|
-
duration: Date.now() - startTime,
|
|
4004
|
-
error: getErrorMessage(error)
|
|
4005
|
-
};
|
|
4060
|
+
return (onError ?? defaultPushError)(error, startTime);
|
|
4006
4061
|
} finally {
|
|
4007
4062
|
if (timerControl) timerControl.restore();
|
|
4008
4063
|
if (savedFetch !== void 0) {
|
|
@@ -4064,6 +4119,28 @@ function cleanupNetworkPolyfills(savedFetch) {
|
|
|
4064
4119
|
global.fetch = savedFetch;
|
|
4065
4120
|
}
|
|
4066
4121
|
|
|
4122
|
+
// src/commands/push/simulation-result.ts
|
|
4123
|
+
init_utils2();
|
|
4124
|
+
function hasEvent(entry) {
|
|
4125
|
+
return entry.event != null;
|
|
4126
|
+
}
|
|
4127
|
+
function toError(error) {
|
|
4128
|
+
return error instanceof Error ? error : new Error(getErrorMessage(error));
|
|
4129
|
+
}
|
|
4130
|
+
function buildSimulationResult(args) {
|
|
4131
|
+
const { step, name, startTime, captured, usage, error } = args;
|
|
4132
|
+
const events = (captured ?? []).filter(hasEvent).map((entry) => entry.event);
|
|
4133
|
+
const calls = usage ? Object.values(usage).flat().map((call) => ({ fn: call.fn, args: call.args, ts: call.ts })) : [];
|
|
4134
|
+
return {
|
|
4135
|
+
step,
|
|
4136
|
+
name,
|
|
4137
|
+
events,
|
|
4138
|
+
calls,
|
|
4139
|
+
duration: Date.now() - startTime,
|
|
4140
|
+
...error !== void 0 ? { error: toError(error) } : {}
|
|
4141
|
+
};
|
|
4142
|
+
}
|
|
4143
|
+
|
|
4067
4144
|
// src/commands/push/prepare.ts
|
|
4068
4145
|
init_cli_logger();
|
|
4069
4146
|
init_tmp();
|
|
@@ -4167,6 +4244,13 @@ function dispatchSimulate(flags) {
|
|
|
4167
4244
|
// src/commands/push/run.ts
|
|
4168
4245
|
init_core();
|
|
4169
4246
|
init_config();
|
|
4247
|
+
function simulationToPushResult(result) {
|
|
4248
|
+
return {
|
|
4249
|
+
success: !result.error,
|
|
4250
|
+
duration: result.duration,
|
|
4251
|
+
...result.error ? { error: result.error.message } : {}
|
|
4252
|
+
};
|
|
4253
|
+
}
|
|
4170
4254
|
async function runPushCommand(options) {
|
|
4171
4255
|
const startTime = Date.now();
|
|
4172
4256
|
try {
|
|
@@ -4197,26 +4281,30 @@ async function runPushCommand(options) {
|
|
|
4197
4281
|
});
|
|
4198
4282
|
break;
|
|
4199
4283
|
case "source":
|
|
4200
|
-
result =
|
|
4201
|
-
|
|
4202
|
-
|
|
4203
|
-
silent: options.silent,
|
|
4204
|
-
verbose: options.verbose,
|
|
4205
|
-
snapshot: options.snapshot
|
|
4206
|
-
});
|
|
4207
|
-
break;
|
|
4208
|
-
case "transformer":
|
|
4209
|
-
result = await simulateTransformer(
|
|
4210
|
-
config,
|
|
4211
|
-
resolvedEvent,
|
|
4212
|
-
{
|
|
4213
|
-
transformerId: plan.ids[0],
|
|
4284
|
+
result = simulationToPushResult(
|
|
4285
|
+
await simulateSource(config, resolvedEvent, {
|
|
4286
|
+
sourceId: plan.ids[0],
|
|
4214
4287
|
flow: options.flow,
|
|
4215
|
-
mock: options.mock,
|
|
4216
4288
|
silent: options.silent,
|
|
4217
4289
|
verbose: options.verbose,
|
|
4218
4290
|
snapshot: options.snapshot
|
|
4219
|
-
}
|
|
4291
|
+
})
|
|
4292
|
+
);
|
|
4293
|
+
break;
|
|
4294
|
+
case "transformer":
|
|
4295
|
+
result = simulationToPushResult(
|
|
4296
|
+
await simulateTransformer(
|
|
4297
|
+
config,
|
|
4298
|
+
resolvedEvent,
|
|
4299
|
+
{
|
|
4300
|
+
transformerId: plan.ids[0],
|
|
4301
|
+
flow: options.flow,
|
|
4302
|
+
mock: options.mock,
|
|
4303
|
+
silent: options.silent,
|
|
4304
|
+
verbose: options.verbose,
|
|
4305
|
+
snapshot: options.snapshot
|
|
4306
|
+
}
|
|
4307
|
+
)
|
|
4220
4308
|
);
|
|
4221
4309
|
break;
|
|
4222
4310
|
case "destination":
|
|
@@ -4239,7 +4327,6 @@ async function runPushCommand(options) {
|
|
|
4239
4327
|
}
|
|
4240
4328
|
async function runDestinationSimulationLoop(config, event, destinationIds, options) {
|
|
4241
4329
|
const startTime = Date.now();
|
|
4242
|
-
const perDestination = {};
|
|
4243
4330
|
for (const destinationId of destinationIds) {
|
|
4244
4331
|
const r = await simulateDestination(config, event, {
|
|
4245
4332
|
destinationId,
|
|
@@ -4249,20 +4336,17 @@ async function runDestinationSimulationLoop(config, event, destinationIds, optio
|
|
|
4249
4336
|
verbose: options.verbose,
|
|
4250
4337
|
snapshot: options.snapshot
|
|
4251
4338
|
});
|
|
4252
|
-
|
|
4253
|
-
if (!r.success) {
|
|
4339
|
+
if (r.error) {
|
|
4254
4340
|
return {
|
|
4255
4341
|
success: false,
|
|
4256
4342
|
duration: Date.now() - startTime,
|
|
4257
|
-
error: `simulate destination.${destinationId}: ${r.error
|
|
4258
|
-
perDestination
|
|
4343
|
+
error: `simulate destination.${destinationId}: ${r.error.message}`
|
|
4259
4344
|
};
|
|
4260
4345
|
}
|
|
4261
4346
|
}
|
|
4262
4347
|
return {
|
|
4263
4348
|
success: true,
|
|
4264
|
-
duration: Date.now() - startTime
|
|
4265
|
-
perDestination
|
|
4349
|
+
duration: Date.now() - startTime
|
|
4266
4350
|
};
|
|
4267
4351
|
}
|
|
4268
4352
|
|
|
@@ -4626,20 +4710,27 @@ async function simulateSource(configOrPath, input, options) {
|
|
|
4626
4710
|
if (instance.flow?.collector?.command) {
|
|
4627
4711
|
await instance.flow.collector.command("shutdown");
|
|
4628
4712
|
}
|
|
4629
|
-
return {
|
|
4630
|
-
|
|
4631
|
-
|
|
4632
|
-
|
|
4633
|
-
|
|
4634
|
-
};
|
|
4635
|
-
}
|
|
4713
|
+
return buildSimulationResult({
|
|
4714
|
+
step: "source",
|
|
4715
|
+
name: options.sourceId,
|
|
4716
|
+
startTime,
|
|
4717
|
+
captured
|
|
4718
|
+
});
|
|
4719
|
+
},
|
|
4720
|
+
(error) => buildSimulationResult({
|
|
4721
|
+
step: "source",
|
|
4722
|
+
name: options.sourceId,
|
|
4723
|
+
startTime,
|
|
4724
|
+
error
|
|
4725
|
+
})
|
|
4636
4726
|
);
|
|
4637
4727
|
} catch (error) {
|
|
4638
|
-
return {
|
|
4639
|
-
|
|
4640
|
-
|
|
4641
|
-
|
|
4642
|
-
|
|
4728
|
+
return buildSimulationResult({
|
|
4729
|
+
step: "source",
|
|
4730
|
+
name: options.sourceId,
|
|
4731
|
+
startTime,
|
|
4732
|
+
error
|
|
4733
|
+
});
|
|
4643
4734
|
} finally {
|
|
4644
4735
|
await prepared.cleanup();
|
|
4645
4736
|
}
|
|
@@ -4648,11 +4739,12 @@ async function simulateTransformer(configOrPath, event, options) {
|
|
|
4648
4739
|
const startTime = Date.now();
|
|
4649
4740
|
const parsed = schemas3.PartialEventSchema.safeParse(event);
|
|
4650
4741
|
if (!parsed.success) {
|
|
4651
|
-
return {
|
|
4652
|
-
|
|
4653
|
-
|
|
4742
|
+
return buildSimulationResult({
|
|
4743
|
+
step: "transformer",
|
|
4744
|
+
name: options.transformerId,
|
|
4745
|
+
startTime,
|
|
4654
4746
|
error: parsed.error.message
|
|
4655
|
-
};
|
|
4747
|
+
});
|
|
4656
4748
|
}
|
|
4657
4749
|
let config;
|
|
4658
4750
|
if (typeof configOrPath === "string") {
|
|
@@ -4728,7 +4820,6 @@ async function simulateTransformer(configOrPath, event, options) {
|
|
|
4728
4820
|
const inputEvent = event;
|
|
4729
4821
|
const ingest = createIngest(options.transformerId);
|
|
4730
4822
|
const captured = [];
|
|
4731
|
-
captured.push({ event: { ...inputEvent }, timestamp: Date.now() });
|
|
4732
4823
|
logger.info(`Simulating transformer: ${options.transformerId}`);
|
|
4733
4824
|
let processedEvent = inputEvent;
|
|
4734
4825
|
const before = transformer.config.before;
|
|
@@ -4752,11 +4843,12 @@ async function simulateTransformer(configOrPath, event, options) {
|
|
|
4752
4843
|
if (beforeResult === null) {
|
|
4753
4844
|
captured.push({ event: null, timestamp: Date.now() });
|
|
4754
4845
|
await collector.command("shutdown");
|
|
4755
|
-
return {
|
|
4756
|
-
|
|
4757
|
-
|
|
4758
|
-
|
|
4759
|
-
|
|
4846
|
+
return buildSimulationResult({
|
|
4847
|
+
step: "transformer",
|
|
4848
|
+
name: options.transformerId,
|
|
4849
|
+
startTime,
|
|
4850
|
+
captured
|
|
4851
|
+
});
|
|
4760
4852
|
}
|
|
4761
4853
|
processedEvent = Array.isArray(beforeResult) ? beforeResult[0] : beforeResult;
|
|
4762
4854
|
}
|
|
@@ -4783,20 +4875,27 @@ async function simulateTransformer(configOrPath, event, options) {
|
|
|
4783
4875
|
captured.push({ event: processedEvent, timestamp: Date.now() });
|
|
4784
4876
|
}
|
|
4785
4877
|
await collector.command("shutdown");
|
|
4786
|
-
return {
|
|
4787
|
-
|
|
4788
|
-
|
|
4789
|
-
|
|
4790
|
-
|
|
4791
|
-
};
|
|
4792
|
-
}
|
|
4878
|
+
return buildSimulationResult({
|
|
4879
|
+
step: "transformer",
|
|
4880
|
+
name: options.transformerId,
|
|
4881
|
+
startTime,
|
|
4882
|
+
captured
|
|
4883
|
+
});
|
|
4884
|
+
},
|
|
4885
|
+
(error) => buildSimulationResult({
|
|
4886
|
+
step: "transformer",
|
|
4887
|
+
name: options.transformerId,
|
|
4888
|
+
startTime,
|
|
4889
|
+
error
|
|
4890
|
+
})
|
|
4793
4891
|
);
|
|
4794
4892
|
} catch (error) {
|
|
4795
|
-
return {
|
|
4796
|
-
|
|
4797
|
-
|
|
4798
|
-
|
|
4799
|
-
|
|
4893
|
+
return buildSimulationResult({
|
|
4894
|
+
step: "transformer",
|
|
4895
|
+
name: options.transformerId,
|
|
4896
|
+
startTime,
|
|
4897
|
+
error
|
|
4898
|
+
});
|
|
4800
4899
|
} finally {
|
|
4801
4900
|
await prepared.cleanup();
|
|
4802
4901
|
}
|
|
@@ -4805,11 +4904,12 @@ async function simulateDestination(configOrPath, event, options) {
|
|
|
4805
4904
|
const startTime = Date.now();
|
|
4806
4905
|
const parsed = schemas3.PartialEventSchema.safeParse(event);
|
|
4807
4906
|
if (!parsed.success) {
|
|
4808
|
-
return {
|
|
4809
|
-
|
|
4810
|
-
|
|
4907
|
+
return buildSimulationResult({
|
|
4908
|
+
step: "destination",
|
|
4909
|
+
name: options.destinationId,
|
|
4910
|
+
startTime,
|
|
4811
4911
|
error: parsed.error.message
|
|
4812
|
-
};
|
|
4912
|
+
});
|
|
4813
4913
|
}
|
|
4814
4914
|
let config;
|
|
4815
4915
|
if (typeof configOrPath === "string") {
|
|
@@ -4892,25 +4992,31 @@ async function simulateDestination(configOrPath, event, options) {
|
|
|
4892
4992
|
);
|
|
4893
4993
|
}
|
|
4894
4994
|
logger.info(`Simulating destination: ${options.destinationId}`);
|
|
4895
|
-
|
|
4995
|
+
await collector.push(event, {
|
|
4896
4996
|
include: [options.destinationId]
|
|
4897
4997
|
});
|
|
4898
4998
|
await collector.command("shutdown");
|
|
4899
|
-
return {
|
|
4900
|
-
|
|
4901
|
-
|
|
4902
|
-
|
|
4903
|
-
|
|
4904
|
-
|
|
4905
|
-
|
|
4906
|
-
|
|
4999
|
+
return buildSimulationResult({
|
|
5000
|
+
step: "destination",
|
|
5001
|
+
name: options.destinationId,
|
|
5002
|
+
startTime,
|
|
5003
|
+
usage: trackedCalls.length ? { [options.destinationId]: trackedCalls } : void 0
|
|
5004
|
+
});
|
|
5005
|
+
},
|
|
5006
|
+
(error) => buildSimulationResult({
|
|
5007
|
+
step: "destination",
|
|
5008
|
+
name: options.destinationId,
|
|
5009
|
+
startTime,
|
|
5010
|
+
error
|
|
5011
|
+
})
|
|
4907
5012
|
);
|
|
4908
5013
|
} catch (error) {
|
|
4909
|
-
return {
|
|
4910
|
-
|
|
4911
|
-
|
|
4912
|
-
|
|
4913
|
-
|
|
5014
|
+
return buildSimulationResult({
|
|
5015
|
+
step: "destination",
|
|
5016
|
+
name: options.destinationId,
|
|
5017
|
+
startTime,
|
|
5018
|
+
error
|
|
5019
|
+
});
|
|
4914
5020
|
} finally {
|
|
4915
5021
|
await prepared.cleanup();
|
|
4916
5022
|
}
|
|
@@ -5169,6 +5275,11 @@ init_utils3();
|
|
|
5169
5275
|
init_tmp();
|
|
5170
5276
|
import { writeFileSync as writeFileSync4 } from "fs";
|
|
5171
5277
|
import fs17 from "fs-extra";
|
|
5278
|
+
import {
|
|
5279
|
+
createBatchedPoster,
|
|
5280
|
+
createTelemetryObserver,
|
|
5281
|
+
resolveTelemetryOptions
|
|
5282
|
+
} from "@walkeros/core";
|
|
5172
5283
|
|
|
5173
5284
|
// src/runtime/health-server.ts
|
|
5174
5285
|
import http from "http";
|
|
@@ -5244,14 +5355,15 @@ async function loadBundle(file, context2, logger) {
|
|
|
5244
5355
|
}
|
|
5245
5356
|
|
|
5246
5357
|
// src/runtime/runner.ts
|
|
5247
|
-
async function loadFlow(file, config, logger, loggerConfig, healthServer) {
|
|
5358
|
+
async function loadFlow(file, config, logger, loggerConfig, healthServer, observers) {
|
|
5248
5359
|
const absolutePath = resolve3(file);
|
|
5249
5360
|
const flowDir = dirname4(absolutePath);
|
|
5250
5361
|
process.chdir(flowDir);
|
|
5251
5362
|
const flowContext = {
|
|
5252
5363
|
...config,
|
|
5253
5364
|
...loggerConfig ? { logger: loggerConfig } : {},
|
|
5254
|
-
...healthServer ? { sourceSettings: { port: void 0 } } : {}
|
|
5365
|
+
...healthServer ? { sourceSettings: { port: void 0 } } : {},
|
|
5366
|
+
...observers ? { observers } : {}
|
|
5255
5367
|
};
|
|
5256
5368
|
const result = await loadBundle(absolutePath, flowContext, logger);
|
|
5257
5369
|
if (healthServer && typeof result.httpHandler === "function") {
|
|
@@ -5266,7 +5378,7 @@ async function loadFlow(file, config, logger, loggerConfig, healthServer) {
|
|
|
5266
5378
|
httpHandler: result.httpHandler
|
|
5267
5379
|
};
|
|
5268
5380
|
}
|
|
5269
|
-
async function swapFlow(currentHandle, newFile, config, logger, loggerConfig, healthServer) {
|
|
5381
|
+
async function swapFlow(currentHandle, newFile, config, logger, loggerConfig, healthServer, observers) {
|
|
5270
5382
|
logger.info("Shutting down current flow for hot-swap...");
|
|
5271
5383
|
if (healthServer) {
|
|
5272
5384
|
healthServer.setFlowHandler(null);
|
|
@@ -5283,7 +5395,8 @@ async function swapFlow(currentHandle, newFile, config, logger, loggerConfig, he
|
|
|
5283
5395
|
config,
|
|
5284
5396
|
logger,
|
|
5285
5397
|
loggerConfig,
|
|
5286
|
-
healthServer
|
|
5398
|
+
healthServer,
|
|
5399
|
+
observers
|
|
5287
5400
|
);
|
|
5288
5401
|
logger.info("Flow swapped successfully");
|
|
5289
5402
|
return newHandle;
|
|
@@ -5353,6 +5466,24 @@ var instanceId = randomBytes(8).toString("hex");
|
|
|
5353
5466
|
function getInstanceId() {
|
|
5354
5467
|
return instanceId;
|
|
5355
5468
|
}
|
|
5469
|
+
async function applyTraceUntilFromResponse(response, logger) {
|
|
5470
|
+
let parsed;
|
|
5471
|
+
try {
|
|
5472
|
+
parsed = await response.json();
|
|
5473
|
+
} catch (error) {
|
|
5474
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
5475
|
+
logger.debug(`Heartbeat response parse failed: ${message}`);
|
|
5476
|
+
return;
|
|
5477
|
+
}
|
|
5478
|
+
if (typeof parsed !== "object" || parsed === null) return;
|
|
5479
|
+
if (!("traceUntil" in parsed)) return;
|
|
5480
|
+
const value = parsed.traceUntil;
|
|
5481
|
+
if (typeof value === "string" && value.length > 0) {
|
|
5482
|
+
process.env.WALKEROS_TRACE_UNTIL = value;
|
|
5483
|
+
} else if (value === null) {
|
|
5484
|
+
delete process.env.WALKEROS_TRACE_UNTIL;
|
|
5485
|
+
}
|
|
5486
|
+
}
|
|
5356
5487
|
function createHeartbeat(config, logger) {
|
|
5357
5488
|
let timer = null;
|
|
5358
5489
|
const startTime = Date.now();
|
|
@@ -5401,6 +5532,9 @@ function createHeartbeat(config, logger) {
|
|
|
5401
5532
|
if (response.ok && counters && current) {
|
|
5402
5533
|
lastReported = current;
|
|
5403
5534
|
}
|
|
5535
|
+
if (response.ok) {
|
|
5536
|
+
await applyTraceUntilFromResponse(response, logger);
|
|
5537
|
+
}
|
|
5404
5538
|
if (response.status === 401 || response.status === 403) {
|
|
5405
5539
|
logger.error(
|
|
5406
5540
|
`Heartbeat auth failed (${response.status}). Token may have expired \u2014 redeploy to rotate.`
|
|
@@ -5502,6 +5636,7 @@ async function runPipeline(options) {
|
|
|
5502
5636
|
logger.info(`walkeros/flow v${VERSION}`);
|
|
5503
5637
|
logger.info(`Instance: ${getInstanceId()}`);
|
|
5504
5638
|
const healthServer = await createHealthServer(port, logger);
|
|
5639
|
+
const telemetryObservers = buildTelemetryObservers(api?.flowId ?? "flow");
|
|
5505
5640
|
const runtimeConfig = { port };
|
|
5506
5641
|
let handle;
|
|
5507
5642
|
try {
|
|
@@ -5510,7 +5645,8 @@ async function runPipeline(options) {
|
|
|
5510
5645
|
runtimeConfig,
|
|
5511
5646
|
logger,
|
|
5512
5647
|
loggerConfig,
|
|
5513
|
-
healthServer
|
|
5648
|
+
healthServer,
|
|
5649
|
+
telemetryObservers
|
|
5514
5650
|
);
|
|
5515
5651
|
} catch (error) {
|
|
5516
5652
|
await healthServer.close();
|
|
@@ -5576,7 +5712,8 @@ async function runPipeline(options) {
|
|
|
5576
5712
|
runtimeConfig,
|
|
5577
5713
|
logger,
|
|
5578
5714
|
loggerConfig,
|
|
5579
|
-
healthServer
|
|
5715
|
+
healthServer,
|
|
5716
|
+
telemetryObservers
|
|
5580
5717
|
);
|
|
5581
5718
|
writeCache(
|
|
5582
5719
|
api.cacheDir,
|
|
@@ -5635,6 +5772,15 @@ async function runPipeline(options) {
|
|
|
5635
5772
|
await new Promise(() => {
|
|
5636
5773
|
});
|
|
5637
5774
|
}
|
|
5775
|
+
function buildTelemetryObservers(flowId) {
|
|
5776
|
+
const url = process.env.WALKEROS_OBSERVER_URL;
|
|
5777
|
+
const token = process.env.WALKEROS_INGEST_TOKEN;
|
|
5778
|
+
if (!url || !token) return void 0;
|
|
5779
|
+
const opts = resolveTelemetryOptions({ flowId });
|
|
5780
|
+
if (!opts) return void 0;
|
|
5781
|
+
const emit = createBatchedPoster({ url, token });
|
|
5782
|
+
return [createTelemetryObserver(emit, opts)];
|
|
5783
|
+
}
|
|
5638
5784
|
async function injectSecrets(api, logger) {
|
|
5639
5785
|
try {
|
|
5640
5786
|
const secrets = await fetchSecrets({
|
|
@@ -5871,7 +6017,7 @@ import chalk2 from "chalk";
|
|
|
5871
6017
|
// src/commands/validate/validators/contract.ts
|
|
5872
6018
|
var SECTION_KEYS = ["globals", "context", "custom", "user", "consent"];
|
|
5873
6019
|
var KNOWN_KEYS = /* @__PURE__ */ new Set([
|
|
5874
|
-
"
|
|
6020
|
+
"extend",
|
|
5875
6021
|
"description",
|
|
5876
6022
|
"events",
|
|
5877
6023
|
...SECTION_KEYS
|
|
@@ -5901,18 +6047,18 @@ function validateContract(input) {
|
|
|
5901
6047
|
continue;
|
|
5902
6048
|
}
|
|
5903
6049
|
const obj = entry;
|
|
5904
|
-
if (obj.
|
|
5905
|
-
if (typeof obj.
|
|
6050
|
+
if (obj.extend !== void 0) {
|
|
6051
|
+
if (typeof obj.extend !== "string") {
|
|
5906
6052
|
errors.push({
|
|
5907
|
-
path: `${name}.
|
|
5908
|
-
message: "
|
|
6053
|
+
path: `${name}.extend`,
|
|
6054
|
+
message: "extend must be a string",
|
|
5909
6055
|
code: "INVALID_EXTENDS"
|
|
5910
6056
|
});
|
|
5911
|
-
} else if (!contractNames.includes(obj.
|
|
6057
|
+
} else if (!contractNames.includes(obj.extend)) {
|
|
5912
6058
|
errors.push({
|
|
5913
|
-
path: `${name}.
|
|
5914
|
-
message: `
|
|
5915
|
-
value: obj.
|
|
6059
|
+
path: `${name}.extend`,
|
|
6060
|
+
message: `extend references non-existent contract "${obj.extend}"`,
|
|
6061
|
+
value: obj.extend,
|
|
5916
6062
|
code: "INVALID_EXTENDS"
|
|
5917
6063
|
});
|
|
5918
6064
|
}
|
|
@@ -5951,15 +6097,15 @@ function validateContract(input) {
|
|
|
5951
6097
|
while (current) {
|
|
5952
6098
|
if (visited.has(current)) {
|
|
5953
6099
|
errors.push({
|
|
5954
|
-
path: `${name}.
|
|
5955
|
-
message: `Circular
|
|
6100
|
+
path: `${name}.extend`,
|
|
6101
|
+
message: `Circular extend chain: ${[...visited, current].join(" \u2192 ")}`,
|
|
5956
6102
|
code: "CIRCULAR_EXTENDS"
|
|
5957
6103
|
});
|
|
5958
6104
|
break;
|
|
5959
6105
|
}
|
|
5960
6106
|
visited.add(current);
|
|
5961
6107
|
const entry = contracts[current];
|
|
5962
|
-
current = entry?.
|
|
6108
|
+
current = entry?.extend || "";
|
|
5963
6109
|
}
|
|
5964
6110
|
}
|
|
5965
6111
|
return {
|
|
@@ -6528,7 +6674,7 @@ function validateMapping(input) {
|
|
|
6528
6674
|
// src/commands/validate/validators/entry.ts
|
|
6529
6675
|
import Ajv from "ajv";
|
|
6530
6676
|
import { fetchPackageSchema } from "@walkeros/core";
|
|
6531
|
-
var CLIENT_HEADER = "walkeros-cli/4.1.
|
|
6677
|
+
var CLIENT_HEADER = "walkeros-cli/4.1.1-next-1779822275564";
|
|
6532
6678
|
var SECTIONS = ["destinations", "sources", "transformers"];
|
|
6533
6679
|
function resolveEntry(path20, flowConfig) {
|
|
6534
6680
|
const flows = flowConfig.flows;
|
|
@@ -7181,9 +7327,11 @@ async function whoamiCommand(options) {
|
|
|
7181
7327
|
// src/commands/projects/index.ts
|
|
7182
7328
|
init_auth();
|
|
7183
7329
|
init_output();
|
|
7184
|
-
async function listProjects() {
|
|
7330
|
+
async function listProjects(options = {}) {
|
|
7185
7331
|
const client = createApiClient();
|
|
7186
|
-
const { data, error } = await client.GET("/api/projects"
|
|
7332
|
+
const { data, error } = await client.GET("/api/projects", {
|
|
7333
|
+
params: { query: { cursor: options.cursor, limit: options.limit } }
|
|
7334
|
+
});
|
|
7187
7335
|
if (error) throw new Error(error.error?.message || "Failed to list projects");
|
|
7188
7336
|
return data;
|
|
7189
7337
|
}
|
|
@@ -7235,7 +7383,10 @@ async function handleResult(fn, options) {
|
|
|
7235
7383
|
}
|
|
7236
7384
|
}
|
|
7237
7385
|
async function listProjectsCommand(options) {
|
|
7238
|
-
await handleResult(
|
|
7386
|
+
await handleResult(
|
|
7387
|
+
() => listProjects({ cursor: options.cursor, limit: options.limit }),
|
|
7388
|
+
options
|
|
7389
|
+
);
|
|
7239
7390
|
}
|
|
7240
7391
|
async function getProjectCommand(projectId, options) {
|
|
7241
7392
|
await handleResult(
|
|
@@ -7279,7 +7430,9 @@ async function listFlows(options = {}) {
|
|
|
7279
7430
|
query: {
|
|
7280
7431
|
sort: options.sort,
|
|
7281
7432
|
order: options.order,
|
|
7282
|
-
include_deleted: options.includeDeleted ? "true" : void 0
|
|
7433
|
+
include_deleted: options.includeDeleted ? "true" : void 0,
|
|
7434
|
+
cursor: options.cursor,
|
|
7435
|
+
limit: options.limit
|
|
7283
7436
|
}
|
|
7284
7437
|
}
|
|
7285
7438
|
});
|
|
@@ -7383,7 +7536,9 @@ async function listFlowsCommand(options) {
|
|
|
7383
7536
|
projectId: options.project,
|
|
7384
7537
|
sort: options.sort,
|
|
7385
7538
|
order: options.order,
|
|
7386
|
-
includeDeleted: options.includeDeleted
|
|
7539
|
+
includeDeleted: options.includeDeleted,
|
|
7540
|
+
cursor: options.cursor,
|
|
7541
|
+
limit: options.limit
|
|
7387
7542
|
}),
|
|
7388
7543
|
options
|
|
7389
7544
|
);
|
|
@@ -7685,6 +7840,8 @@ async function listDeployments(options = {}) {
|
|
|
7685
7840
|
if (options.type) params.set("type", options.type);
|
|
7686
7841
|
if (options.status) params.set("status", options.status);
|
|
7687
7842
|
if (options.flowId) params.set("flowId", options.flowId);
|
|
7843
|
+
if (options.cursor) params.set("cursor", options.cursor);
|
|
7844
|
+
if (options.limit !== void 0) params.set("limit", String(options.limit));
|
|
7688
7845
|
const qs = params.toString();
|
|
7689
7846
|
const response = await apiFetch(
|
|
7690
7847
|
`/api/projects/${id}/deployments${qs ? `?${qs}` : ""}`
|
|
@@ -7782,7 +7939,9 @@ async function listDeploymentsCommand(options) {
|
|
|
7782
7939
|
() => listDeployments({
|
|
7783
7940
|
projectId: options.project,
|
|
7784
7941
|
type: options.type,
|
|
7785
|
-
status: options.status
|
|
7942
|
+
status: options.status,
|
|
7943
|
+
cursor: options.cursor,
|
|
7944
|
+
limit: options.limit
|
|
7786
7945
|
}),
|
|
7787
7946
|
options
|
|
7788
7947
|
);
|
|
@@ -8031,8 +8190,22 @@ init_bundle();
|
|
|
8031
8190
|
init_bundler();
|
|
8032
8191
|
import * as path19 from "path";
|
|
8033
8192
|
import * as os3 from "os";
|
|
8193
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
8034
8194
|
import fs18 from "fs-extra";
|
|
8035
8195
|
import * as esbuild2 from "esbuild";
|
|
8196
|
+
function getNodeResolutionPaths() {
|
|
8197
|
+
const here = path19.dirname(fileURLToPath2(import.meta.url));
|
|
8198
|
+
const candidates = [];
|
|
8199
|
+
let dir = here;
|
|
8200
|
+
for (let i = 0; i < 8; i++) {
|
|
8201
|
+
const candidate = path19.join(dir, "node_modules");
|
|
8202
|
+
candidates.push(candidate);
|
|
8203
|
+
const parent = path19.dirname(dir);
|
|
8204
|
+
if (parent === dir) break;
|
|
8205
|
+
dir = parent;
|
|
8206
|
+
}
|
|
8207
|
+
return candidates;
|
|
8208
|
+
}
|
|
8036
8209
|
async function wrapSkeleton(options) {
|
|
8037
8210
|
const {
|
|
8038
8211
|
skeletonPath,
|
|
@@ -8058,12 +8231,22 @@ async function wrapSkeleton(options) {
|
|
|
8058
8231
|
throw new Error(`wrapSkeleton: skeleton not found at ${skeletonPath}`);
|
|
8059
8232
|
}
|
|
8060
8233
|
const absoluteSkeletonPath = path19.resolve(skeletonPath);
|
|
8234
|
+
const tInput = options.telemetry;
|
|
8235
|
+
const tLevel = tInput?.level ?? "standard";
|
|
8236
|
+
const telemetry = tInput && tLevel !== "off" ? {
|
|
8237
|
+
observerUrl: tInput.observerUrl,
|
|
8238
|
+
ingestToken: tInput.ingestToken,
|
|
8239
|
+
flowId: tInput.flowId,
|
|
8240
|
+
level: tLevel,
|
|
8241
|
+
...tInput.sample !== void 0 ? { sample: tInput.sample } : {}
|
|
8242
|
+
} : void 0;
|
|
8061
8243
|
const entryText = platform === "browser" ? generateWrapEntry(absoluteSkeletonPath, {
|
|
8062
8244
|
...windowCollector ? { windowCollector } : {},
|
|
8063
8245
|
...windowElb ? { windowElb } : {},
|
|
8064
8246
|
...options.previewOrigin ? { previewOrigin: options.previewOrigin } : {},
|
|
8065
8247
|
...options.previewScope ? { previewScope: options.previewScope } : {},
|
|
8066
|
-
platform
|
|
8248
|
+
platform,
|
|
8249
|
+
...telemetry ? { telemetry } : {}
|
|
8067
8250
|
}) : generateWrapEntryServer(absoluteSkeletonPath);
|
|
8068
8251
|
const entryDir = await fs18.mkdtemp(path19.join(os3.tmpdir(), "walkeros-wrap-"));
|
|
8069
8252
|
const entryPath = path19.join(entryDir, "flow.mjs");
|
|
@@ -8076,6 +8259,12 @@ async function wrapSkeleton(options) {
|
|
|
8076
8259
|
format: "esm",
|
|
8077
8260
|
platform,
|
|
8078
8261
|
outfile: outputPath,
|
|
8262
|
+
// Resolve `@walkeros/core` (used by the telemetry block) from the CLI
|
|
8263
|
+
// package's own dependency tree and the workspace root. Without this,
|
|
8264
|
+
// esbuild looks under the temp entryDir which has no node_modules.
|
|
8265
|
+
// The wrap step always runs from inside the CLI process; both the
|
|
8266
|
+
// CLI's local node_modules and the workspace root are safe anchors.
|
|
8267
|
+
nodePaths: getNodeResolutionPaths(),
|
|
8079
8268
|
treeShaking: true,
|
|
8080
8269
|
logLevel: "error",
|
|
8081
8270
|
minify,
|