@neat.is/core 0.5.3 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-X2AMX3QZ.js → chunk-5PVQJLPR.js} +272 -13
- package/dist/chunk-5PVQJLPR.js.map +1 -0
- package/dist/{chunk-CFDPIMRP.js → chunk-BZ3AJVAC.js} +9 -3
- package/dist/chunk-BZ3AJVAC.js.map +1 -0
- package/dist/{chunk-GJHEZC5K.js → chunk-CS4GHQO3.js} +458 -111
- package/dist/chunk-CS4GHQO3.js.map +1 -0
- package/dist/{chunk-I72HTUOG.js → chunk-MVINCLQM.js} +2 -2
- package/dist/cli.cjs +1190 -458
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +140 -25
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +849 -286
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +4 -4
- package/dist/neatd.cjs +858 -295
- package/dist/neatd.cjs.map +1 -1
- package/dist/neatd.js +3 -3
- package/dist/{otel-grpc-IDMIH6ZY.js → otel-grpc-XS45HBET.js} +3 -3
- package/dist/server.cjs +540 -173
- package/dist/server.cjs.map +1 -1
- package/dist/server.js +3 -3
- package/package.json +2 -2
- package/dist/chunk-CFDPIMRP.js.map +0 -1
- package/dist/chunk-GJHEZC5K.js.map +0 -1
- package/dist/chunk-X2AMX3QZ.js.map +0 -1
- /package/dist/{chunk-I72HTUOG.js.map → chunk-MVINCLQM.js.map} +0 -0
- /package/dist/{otel-grpc-IDMIH6ZY.js.map → otel-grpc-XS45HBET.js.map} +0 -0
package/dist/cli.js
CHANGED
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
-
PROVIDER_DISPATCH,
|
|
4
3
|
clearDaemonRecord,
|
|
5
|
-
|
|
4
|
+
deprovisionConnector,
|
|
5
|
+
getProviderFieldSchema,
|
|
6
|
+
isPushProvider,
|
|
7
|
+
knownProviderNames,
|
|
6
8
|
portFromListenAddress,
|
|
9
|
+
provisionConnector,
|
|
7
10
|
readDaemonRecord,
|
|
8
11
|
resolveHost,
|
|
9
12
|
resolveNeatVersion,
|
|
10
13
|
validateConnectorEntry,
|
|
11
14
|
writeDaemonRecord
|
|
12
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-5PVQJLPR.js";
|
|
13
16
|
import {
|
|
14
17
|
buildSearchIndex
|
|
15
18
|
} from "./chunk-BIY46Q6U.js";
|
|
@@ -68,10 +71,10 @@ import {
|
|
|
68
71
|
startPersistLoop,
|
|
69
72
|
startStalenessLoop,
|
|
70
73
|
upsertConnectorEntry
|
|
71
|
-
} from "./chunk-
|
|
74
|
+
} from "./chunk-CS4GHQO3.js";
|
|
72
75
|
import {
|
|
73
76
|
startOtelGrpcReceiver
|
|
74
|
-
} from "./chunk-
|
|
77
|
+
} from "./chunk-MVINCLQM.js";
|
|
75
78
|
import {
|
|
76
79
|
__dirname,
|
|
77
80
|
__require,
|
|
@@ -79,7 +82,7 @@ import {
|
|
|
79
82
|
buildOtelReceiver,
|
|
80
83
|
listenSteppingOtlp,
|
|
81
84
|
readAuthEnv
|
|
82
|
-
} from "./chunk-
|
|
85
|
+
} from "./chunk-BZ3AJVAC.js";
|
|
83
86
|
|
|
84
87
|
// src/cli.ts
|
|
85
88
|
import path10 from "path";
|
|
@@ -1182,9 +1185,12 @@ ${OTEL_ENDPOINT_RESOLVER_ESM}
|
|
|
1182
1185
|
${OTEL_OTLP_PROTOCOL_JS}
|
|
1183
1186
|
${OTEL_OTLP_HEADERS_JS}
|
|
1184
1187
|
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
+
// Keep dependency loading inside the guard. Static ESM imports are evaluated
|
|
1189
|
+
// before any try/catch and would crash the host app when an install failed.
|
|
1190
|
+
try {
|
|
1191
|
+
const { NodeSDK } = await import('@opentelemetry/sdk-node')
|
|
1192
|
+
const { getNodeAutoInstrumentations } = await import('@opentelemetry/auto-instrumentations-node')
|
|
1193
|
+
const { trace, context } = await import('@opentelemetry/api')
|
|
1188
1194
|
|
|
1189
1195
|
${CALLSITE_PROCESSOR_JS}
|
|
1190
1196
|
|
|
@@ -1193,6 +1199,14 @@ __INSTRUMENTATION_BLOCK__
|
|
|
1193
1199
|
const sdk = new NodeSDK({ instrumentations })
|
|
1194
1200
|
sdk.start()
|
|
1195
1201
|
${neatWireCaptureSource(false)}
|
|
1202
|
+
} catch (__neatOtelErr) {
|
|
1203
|
+
const __neatMsg = String((__neatOtelErr && __neatOtelErr.message) || __neatOtelErr)
|
|
1204
|
+
if (/Cannot find (?:module|package)|MODULE_NOT_FOUND|ERR_MODULE_NOT_FOUND/.test(__neatMsg)) {
|
|
1205
|
+
console.warn('[neat] OpenTelemetry is not active: its packages are not installed, so this app is running without OBSERVED tracing. Run your package manager install and restart to enable it.')
|
|
1206
|
+
} else {
|
|
1207
|
+
console.warn('[neat] OpenTelemetry failed to start; the app is running without OBSERVED tracing: ' + __neatMsg)
|
|
1208
|
+
}
|
|
1209
|
+
}
|
|
1196
1210
|
`;
|
|
1197
1211
|
var OTEL_INIT_TS = `${OTEL_INIT_HEADER}
|
|
1198
1212
|
${OTEL_INIT_STAMP}
|
|
@@ -1207,9 +1221,12 @@ ${OTEL_ENDPOINT_RESOLVER_ESM}
|
|
|
1207
1221
|
${OTEL_OTLP_PROTOCOL_JS}
|
|
1208
1222
|
${OTEL_OTLP_HEADERS_JS}
|
|
1209
1223
|
|
|
1210
|
-
import
|
|
1211
|
-
|
|
1212
|
-
|
|
1224
|
+
// Top-level await preserves the static import's ordering: the host entry does
|
|
1225
|
+
// not run until instrumentation has started (or safely degraded).
|
|
1226
|
+
try {
|
|
1227
|
+
const { NodeSDK } = await import('@opentelemetry/sdk-node')
|
|
1228
|
+
const { getNodeAutoInstrumentations } = await import('@opentelemetry/auto-instrumentations-node')
|
|
1229
|
+
const { trace, context } = await import('@opentelemetry/api')
|
|
1213
1230
|
|
|
1214
1231
|
${CALLSITE_PROCESSOR_TS}
|
|
1215
1232
|
|
|
@@ -1218,6 +1235,14 @@ __INSTRUMENTATION_BLOCK__
|
|
|
1218
1235
|
const sdk = new NodeSDK({ instrumentations })
|
|
1219
1236
|
sdk.start()
|
|
1220
1237
|
${neatWireCaptureSource(true)}
|
|
1238
|
+
} catch (__neatOtelErr) {
|
|
1239
|
+
const __neatMsg = String((__neatOtelErr && __neatOtelErr.message) || __neatOtelErr)
|
|
1240
|
+
if (/Cannot find (?:module|package)|MODULE_NOT_FOUND|ERR_MODULE_NOT_FOUND/.test(__neatMsg)) {
|
|
1241
|
+
console.warn('[neat] OpenTelemetry is not active: its packages are not installed, so this app is running without OBSERVED tracing. Run your package manager install and restart to enable it.')
|
|
1242
|
+
} else {
|
|
1243
|
+
console.warn('[neat] OpenTelemetry failed to start; the app is running without OBSERVED tracing: ' + __neatMsg)
|
|
1244
|
+
}
|
|
1245
|
+
}
|
|
1221
1246
|
`;
|
|
1222
1247
|
function renderNodeOtelInit(template, serviceName, projectName, registrations = []) {
|
|
1223
1248
|
const block = registrations.length === 0 ? "" : `
|
|
@@ -3513,9 +3538,26 @@ function printSummary(result, graph, dashboardUrl, daemonLog) {
|
|
|
3513
3538
|
} else {
|
|
3514
3539
|
console.log("running locally \u2014 open the dashboard, no token needed");
|
|
3515
3540
|
}
|
|
3541
|
+
const failedInstalls = (result.steps.apply.packageManagerInstalls ?? []).filter(
|
|
3542
|
+
(i) => i.exitCode !== 0
|
|
3543
|
+
);
|
|
3516
3544
|
if (daemonLog !== null) {
|
|
3517
3545
|
console.log("");
|
|
3518
3546
|
console.log(`daemon running in the background (logs: ${daemonLog})`);
|
|
3547
|
+
}
|
|
3548
|
+
if (failedInstalls.length > 0) {
|
|
3549
|
+
if (daemonLog === null) console.log("");
|
|
3550
|
+
console.log(
|
|
3551
|
+
"instrumentation is wired into your manifests, but it is NOT yet active:"
|
|
3552
|
+
);
|
|
3553
|
+
console.log(
|
|
3554
|
+
"the dependency install did not complete, so the OTel SDK never landed and"
|
|
3555
|
+
);
|
|
3556
|
+
console.log("OBSERVED edges will stay empty until you finish the install. Fix it:");
|
|
3557
|
+
for (const i of failedInstalls) {
|
|
3558
|
+
console.log(` run \`${i.pm} install\` in ${i.cwd}`);
|
|
3559
|
+
}
|
|
3560
|
+
} else if (daemonLog !== null) {
|
|
3519
3561
|
console.log(
|
|
3520
3562
|
"next: run your app or your test suite \u2014 OBSERVED edges fill in as it executes,"
|
|
3521
3563
|
);
|
|
@@ -3566,6 +3608,8 @@ function parseConnectorArgs(args) {
|
|
|
3566
3608
|
positional: [],
|
|
3567
3609
|
skipValidate: false,
|
|
3568
3610
|
plaintext: false,
|
|
3611
|
+
help: false,
|
|
3612
|
+
json: false,
|
|
3569
3613
|
fields: {}
|
|
3570
3614
|
};
|
|
3571
3615
|
const positional = [];
|
|
@@ -3579,6 +3623,14 @@ function parseConnectorArgs(args) {
|
|
|
3579
3623
|
out.plaintext = true;
|
|
3580
3624
|
continue;
|
|
3581
3625
|
}
|
|
3626
|
+
if (arg === "--help" || arg === "-h") {
|
|
3627
|
+
out.help = true;
|
|
3628
|
+
continue;
|
|
3629
|
+
}
|
|
3630
|
+
if (arg === "--json") {
|
|
3631
|
+
out.json = true;
|
|
3632
|
+
continue;
|
|
3633
|
+
}
|
|
3582
3634
|
if (arg.startsWith("--")) {
|
|
3583
3635
|
let flag = arg;
|
|
3584
3636
|
let value;
|
|
@@ -3655,19 +3707,20 @@ function plaintextFields(ref) {
|
|
|
3655
3707
|
async function connectorAdd(args, deps) {
|
|
3656
3708
|
let provider = args.positional[0];
|
|
3657
3709
|
if (!provider && deps.interactive) {
|
|
3658
|
-
provider = (await deps.prompt(`Provider (${
|
|
3710
|
+
provider = (await deps.prompt(`Provider (${knownProviderNames().join(", ")}):`)).trim();
|
|
3659
3711
|
}
|
|
3660
3712
|
if (!provider) {
|
|
3661
3713
|
deps.err("neat connector add: a provider is required (e.g. `neat connector add supabase`)");
|
|
3662
3714
|
return 2;
|
|
3663
3715
|
}
|
|
3664
|
-
const dispatch =
|
|
3716
|
+
const dispatch = getProviderFieldSchema(provider);
|
|
3665
3717
|
if (!dispatch) {
|
|
3666
3718
|
deps.err(
|
|
3667
|
-
`neat connector add: unknown provider "${provider}". known providers: ${
|
|
3719
|
+
`neat connector add: unknown provider "${provider}". known providers: ${knownProviderNames().join(", ")}`
|
|
3668
3720
|
);
|
|
3669
3721
|
return 2;
|
|
3670
3722
|
}
|
|
3723
|
+
const push = isPushProvider(provider);
|
|
3671
3724
|
let project = args.project;
|
|
3672
3725
|
if (project === void 0 && deps.interactive) {
|
|
3673
3726
|
const answer = (await deps.prompt("Project (blank = the project the daemon is bootstrapping):")).trim();
|
|
@@ -3706,7 +3759,7 @@ async function connectorAdd(args, deps) {
|
|
|
3706
3759
|
credential,
|
|
3707
3760
|
...Object.keys(options).length > 0 ? { options } : {}
|
|
3708
3761
|
};
|
|
3709
|
-
if (!args.skipValidate) {
|
|
3762
|
+
if (!push && !args.skipValidate) {
|
|
3710
3763
|
const outcome = await validateConnectorEntry(entry2, deps.env, deps.fetchImpl);
|
|
3711
3764
|
const code = reportPreWriteValidation(outcome, deps);
|
|
3712
3765
|
if (code !== 0) return code;
|
|
@@ -3717,14 +3770,32 @@ async function connectorAdd(args, deps) {
|
|
|
3717
3770
|
`neat connector add: storing a literal secret at rest for ${plaintext.join(", ")} \u2014 prefer an env-var reference like \`$PROVIDER_TOKEN\` (pass --plaintext to silence this).`
|
|
3718
3771
|
);
|
|
3719
3772
|
}
|
|
3773
|
+
if (push) {
|
|
3774
|
+
if (args.skipValidate) {
|
|
3775
|
+
deps.out("note: --skip-validate has no effect for a push provider \u2014 provisioning the drain is the add.");
|
|
3776
|
+
}
|
|
3777
|
+
const outcome = await provisionConnector(entry2, deps.env, deps.fetchImpl);
|
|
3778
|
+
if (outcome.status !== "ok") {
|
|
3779
|
+
deps.err(
|
|
3780
|
+
`neat connector add: could not provision the ${provider} connector \u2014 ${outcome.reason}. Nothing was written.`
|
|
3781
|
+
);
|
|
3782
|
+
return 1;
|
|
3783
|
+
}
|
|
3784
|
+
if (outcome.options) entry2.options = { ...entry2.options ?? {}, ...outcome.options };
|
|
3785
|
+
if (outcome.note) deps.out(`note: ${outcome.note}`);
|
|
3786
|
+
}
|
|
3720
3787
|
const { replaced } = await upsertConnectorEntry(entry2, deps.home);
|
|
3721
3788
|
const verb = replaced ? "updated" : "added";
|
|
3722
3789
|
const where = project ? `project "${project}"` : "the bootstrapping project";
|
|
3723
3790
|
deps.out(`${verb} connector "${id}" (${provider}) for ${where}.`);
|
|
3724
|
-
if (
|
|
3725
|
-
deps.out("
|
|
3791
|
+
if (push) {
|
|
3792
|
+
deps.out("The drain is live \u2014 traces arrive at the daemon's OTLP receiver. No poll or restart needed.");
|
|
3793
|
+
} else {
|
|
3794
|
+
if (args.skipValidate) {
|
|
3795
|
+
deps.out("skipped validation (--skip-validate) \u2014 the credential is checked at the next daemon poll.");
|
|
3796
|
+
}
|
|
3797
|
+
deps.out("Restart the project's daemon (or start it) to begin polling this connector.");
|
|
3726
3798
|
}
|
|
3727
|
-
deps.out("Restart the project's daemon (or start it) to begin polling this connector.");
|
|
3728
3799
|
return 0;
|
|
3729
3800
|
}
|
|
3730
3801
|
function reportPreWriteValidation(outcome, deps) {
|
|
@@ -3750,10 +3821,26 @@ function reportPreWriteValidation(outcome, deps) {
|
|
|
3750
3821
|
return 2;
|
|
3751
3822
|
}
|
|
3752
3823
|
}
|
|
3753
|
-
async function connectorList(deps, filterProject) {
|
|
3824
|
+
async function connectorList(deps, filterProject, json = false) {
|
|
3754
3825
|
const config = await readConnectorsConfig(deps.home);
|
|
3755
3826
|
let entries = config.connectors;
|
|
3756
3827
|
if (filterProject) entries = entries.filter((e) => e.project === filterProject);
|
|
3828
|
+
if (json) {
|
|
3829
|
+
const rows = entries.map((e) => ({
|
|
3830
|
+
id: e.id,
|
|
3831
|
+
provider: e.provider,
|
|
3832
|
+
project: e.project ?? null,
|
|
3833
|
+
kind: isPushProvider(e.provider) ? "push" : "pull",
|
|
3834
|
+
credential: describeCredential(e.credential, deps.env).map((c) => ({
|
|
3835
|
+
...c.field ? { field: c.field } : {},
|
|
3836
|
+
ref: c.display,
|
|
3837
|
+
...c.status ? { status: c.status } : { kind: c.kind }
|
|
3838
|
+
})),
|
|
3839
|
+
...e.options ? { options: e.options } : {}
|
|
3840
|
+
}));
|
|
3841
|
+
deps.out(JSON.stringify(rows, null, 2));
|
|
3842
|
+
return 0;
|
|
3843
|
+
}
|
|
3757
3844
|
if (entries.length === 0) {
|
|
3758
3845
|
deps.out(
|
|
3759
3846
|
filterProject ? `no connectors configured for project "${filterProject}".` : "no connectors configured. run `neat connector add <provider>` to add one."
|
|
@@ -3776,6 +3863,22 @@ async function connectorRemove(deps, id) {
|
|
|
3776
3863
|
deps.err("neat connector remove: missing <id>. run `neat connector list` to see configured ids.");
|
|
3777
3864
|
return 2;
|
|
3778
3865
|
}
|
|
3866
|
+
const config = await readConnectorsConfig(deps.home);
|
|
3867
|
+
const entry2 = config.connectors.find((c) => c.id === id);
|
|
3868
|
+
if (!entry2) {
|
|
3869
|
+
deps.err(`neat connector remove: no connector with id "${id}". run \`neat connector list\` to see configured ids.`);
|
|
3870
|
+
return 1;
|
|
3871
|
+
}
|
|
3872
|
+
if (isPushProvider(entry2.provider)) {
|
|
3873
|
+
const outcome = await deprovisionConnector(entry2, deps.env, deps.fetchImpl);
|
|
3874
|
+
if (outcome.status !== "ok") {
|
|
3875
|
+
deps.err(
|
|
3876
|
+
`neat connector remove: could not delete the ${entry2.provider} drain \u2014 ${outcome.reason}. The entry was kept so you can retry (or delete the drain in the Vercel dashboard, then re-run).`
|
|
3877
|
+
);
|
|
3878
|
+
return 1;
|
|
3879
|
+
}
|
|
3880
|
+
if (outcome.note) deps.out(`note: ${outcome.note}`);
|
|
3881
|
+
}
|
|
3779
3882
|
const removed = await removeConnectorEntry(id, deps.home);
|
|
3780
3883
|
if (!removed) {
|
|
3781
3884
|
deps.err(`neat connector remove: no connector with id "${id}". run \`neat connector list\` to see configured ids.`);
|
|
@@ -3816,13 +3919,20 @@ async function connectorTest(deps, id) {
|
|
|
3816
3919
|
}
|
|
3817
3920
|
function printConnectorUsage(write) {
|
|
3818
3921
|
write("usage: neat connector <add|list|remove|test> [args]");
|
|
3922
|
+
write(` providers: ${knownProviderNames().join(", ")}`);
|
|
3923
|
+
write(" pull (polled): supabase, railway, firebase, cloudflare");
|
|
3924
|
+
write(" push (drains): vercel \u2014 provisions a Vercel trace Drain that forwards");
|
|
3925
|
+
write(" traces to the daemon's OTLP receiver; no app instrumentation");
|
|
3819
3926
|
write(" add <provider> add a connector; validates the credential first (--skip-validate to skip)");
|
|
3820
3927
|
write(" flags: --project <name> --credential/--token <$VAR|value> --id <id>");
|
|
3821
3928
|
write(" --<option> <value> (provider-specific) --plaintext --skip-validate");
|
|
3929
|
+
write(" vercel: neat connector add vercel --token $VERCEL_TOKEN \\");
|
|
3930
|
+
write(" --otel-token $NEAT_OTEL_TOKEN --team-id <teamId> \\");
|
|
3931
|
+
write(" --endpoint https://<public-host>/v1/traces [--project-ids <id,id>]");
|
|
3822
3932
|
write(" list list configured connectors (credentials shown redacted)");
|
|
3823
3933
|
write(" flags: --project <name>");
|
|
3824
|
-
write(" remove <id> remove a connector by id");
|
|
3825
|
-
write(" test <id> re-run
|
|
3934
|
+
write(" remove <id> remove a connector by id (a push provider also has its drain deleted)");
|
|
3935
|
+
write(" test <id> re-run validation for an existing connector (a push provider re-tests its drain)");
|
|
3826
3936
|
}
|
|
3827
3937
|
async function runConnectorCommand(rawArgs, deps = {}) {
|
|
3828
3938
|
const resolved = resolveDeps(deps);
|
|
@@ -3832,11 +3942,15 @@ async function runConnectorCommand(rawArgs, deps = {}) {
|
|
|
3832
3942
|
return 2;
|
|
3833
3943
|
}
|
|
3834
3944
|
const a = parsed.value;
|
|
3945
|
+
if (a.help) {
|
|
3946
|
+
printConnectorUsage(resolved.out);
|
|
3947
|
+
return 0;
|
|
3948
|
+
}
|
|
3835
3949
|
switch (a.subcommand) {
|
|
3836
3950
|
case "add":
|
|
3837
3951
|
return connectorAdd(a, resolved);
|
|
3838
3952
|
case "list":
|
|
3839
|
-
return connectorList(resolved, a.project);
|
|
3953
|
+
return connectorList(resolved, a.project, a.json);
|
|
3840
3954
|
case "remove":
|
|
3841
3955
|
return connectorRemove(resolved, a.positional[0]);
|
|
3842
3956
|
case "test":
|
|
@@ -4787,8 +4901,9 @@ function usage2() {
|
|
|
4787
4901
|
console.log(" --dry-run run extraction in-memory; do not write");
|
|
4788
4902
|
console.log(" --no-instrument skip the SDK install apply step");
|
|
4789
4903
|
console.log(" --json emit the delta summary as JSON");
|
|
4790
|
-
console.log(" connector Configure
|
|
4791
|
-
console.log(" firebase, cloudflare).
|
|
4904
|
+
console.log(" connector Configure OBSERVED connectors \u2014 pull (supabase, railway,");
|
|
4905
|
+
console.log(" firebase, cloudflare) and push (vercel, via a trace Drain).");
|
|
4906
|
+
console.log(" Subcommands:");
|
|
4792
4907
|
console.log(" add <provider> add a connector; validates the credential");
|
|
4793
4908
|
console.log(" against the provider first (--skip-validate to skip)");
|
|
4794
4909
|
console.log(" flags: --project <name>, --credential/--token <$VAR|value>,");
|