@capxul/cli 4.20.0-beta.2 → 4.20.0-beta.4
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/README.md +20 -4
- package/dist/main.mjs +1219 -162
- package/dist/main.mjs.map +1 -1
- package/package.json +4 -3
package/dist/main.mjs
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire } from "node:module";
|
|
3
|
-
import process$1, { exit, platform, versions } from "node:process";
|
|
4
|
-
import { Cause, Clock, Config, Console, Context, Crypto, Data, Deferred, Duration, Effect, Exit, Fiber, FiberSet, FileSystem, Layer, Logger, Metric, Option, Path, Queue, Redacted, Ref, Result, Schedule, Schema, SchemaGetter, SchemaIssue, SchemaParser, Scope, Stdio, Stream, Tracer } from "effect";
|
|
3
|
+
import process$1, { arch, exit, platform, versions } from "node:process";
|
|
4
|
+
import { Cause, Clock, Config, Console, Context, Crypto, Data, Deferred, Duration, Effect, Exit, Fiber, FiberSet, FileSystem, Layer, LogLevel, Logger, Metric, Option, Path, Queue, Redacted, Ref, References, Result, Schedule, Schema, SchemaGetter, SchemaIssue, SchemaParser, Scope, Stdio, Stream, Tracer } from "effect";
|
|
5
5
|
import { NodeRuntime, NodeServices } from "@effect/platform-node";
|
|
6
6
|
import { CliConfig, CliError, Command, Flag, GlobalFlag, Primitive } from "effect/unstable/cli";
|
|
7
7
|
import * as nc from "node:crypto";
|
|
8
|
-
import { FetchHttpClient, Headers, HttpBody, HttpClient, HttpClientRequest, HttpClientResponse, HttpTraceContext } from "effect/unstable/http";
|
|
8
|
+
import { FetchHttpClient, Headers, HttpBody, HttpClient, HttpClientError, HttpClientRequest, HttpClientResponse, HttpTraceContext } from "effect/unstable/http";
|
|
9
9
|
import { OtlpExporter, OtlpLogger, OtlpMetrics, OtlpSerialization, OtlpTracer } from "effect/unstable/observability";
|
|
10
10
|
import { resolve } from "path";
|
|
11
11
|
import util from "util";
|
|
@@ -473,7 +473,12 @@ const CREDENTIAL_FIELDS = /* @__PURE__ */ new Set([
|
|
|
473
473
|
"authcode",
|
|
474
474
|
"authorizationcode",
|
|
475
475
|
"oauthcode",
|
|
476
|
-
"codeverifier"
|
|
476
|
+
"codeverifier",
|
|
477
|
+
"devicecode",
|
|
478
|
+
"usercode",
|
|
479
|
+
"continuitytoken",
|
|
480
|
+
"refreshattemptid",
|
|
481
|
+
"revocationtoken"
|
|
477
482
|
]);
|
|
478
483
|
/** Match credential fields by meaning, without hiding token addresses or replay IDs. */
|
|
479
484
|
function isCredentialField(name, context) {
|
|
@@ -2398,6 +2403,8 @@ const COUNTRY_CODE_RE = /^[A-Z]{2}$/;
|
|
|
2398
2403
|
const ACCOUNT_ID_RE = /^account_[0-9A-Za-z]+$/;
|
|
2399
2404
|
const PARTY_ID_RE$1 = /^party_[0-9A-Za-z]+$/;
|
|
2400
2405
|
const APP_ID_RE = /^app_[0-7][0-9A-HJKMNP-TV-Z]{25}$/;
|
|
2406
|
+
const CLIENT_REQUEST_ID_RE = /^creq_[0-7][0-9A-HJKMNP-TV-Z]{25}$/;
|
|
2407
|
+
const CLIENT_GRANT_ID_RE = /^cgrant_[0-7][0-9A-HJKMNP-TV-Z]{25}$/;
|
|
2401
2408
|
const TX_HASH_RE = /^0x[0-9a-f]{64}$/i;
|
|
2402
2409
|
const WEI_RE = /^[0-9]+$/;
|
|
2403
2410
|
Math.floor(Number.MAX_SAFE_INTEGER / 1e3);
|
|
@@ -6531,6 +6538,91 @@ const ContactActionProps = {
|
|
|
6531
6538
|
reason_code: OptionalReasonCode
|
|
6532
6539
|
};
|
|
6533
6540
|
/** One completed online CLI diagnostic. No command input or provider text. */
|
|
6541
|
+
const CLI_COMMAND_NAMES = [
|
|
6542
|
+
"capxul",
|
|
6543
|
+
"doctor",
|
|
6544
|
+
"telemetry",
|
|
6545
|
+
"telemetry.status",
|
|
6546
|
+
"telemetry.enable",
|
|
6547
|
+
"telemetry.disable",
|
|
6548
|
+
"unknown"
|
|
6549
|
+
];
|
|
6550
|
+
const CLI_CAPABILITIES = [
|
|
6551
|
+
"cli",
|
|
6552
|
+
"diagnostics",
|
|
6553
|
+
"collection"
|
|
6554
|
+
];
|
|
6555
|
+
const CLI_INVOCATION_KINDS = [
|
|
6556
|
+
"command",
|
|
6557
|
+
"help",
|
|
6558
|
+
"version",
|
|
6559
|
+
"completion",
|
|
6560
|
+
"parse_refusal",
|
|
6561
|
+
"collection_control"
|
|
6562
|
+
];
|
|
6563
|
+
const CliRelease = Schema.String.check(Schema.isPattern(/^[A-Za-z0-9][A-Za-z0-9._+-]{0,127}$/u));
|
|
6564
|
+
const CliInvocationProps = {
|
|
6565
|
+
...TelemetryEnvelopeProps,
|
|
6566
|
+
schema_version: Schema.Literal(1),
|
|
6567
|
+
command: Schema.Literals(CLI_COMMAND_NAMES),
|
|
6568
|
+
capability: Schema.Literals(CLI_CAPABILITIES),
|
|
6569
|
+
invocation_kind: Schema.Literals(CLI_INVOCATION_KINDS),
|
|
6570
|
+
invocation_id: Schema.String.check(Schema.isPattern(/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/u)),
|
|
6571
|
+
cli_identity_kind: Schema.optional(Schema.Literal("anonymous")),
|
|
6572
|
+
anonymous_id: Schema.optional(Schema.String.check(Schema.isPattern(/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/u))),
|
|
6573
|
+
occurred_at: Schema.Number,
|
|
6574
|
+
cli_version: CliRelease,
|
|
6575
|
+
sdk_version: CliRelease,
|
|
6576
|
+
release: CliRelease,
|
|
6577
|
+
platform: Schema.Literals([
|
|
6578
|
+
"darwin",
|
|
6579
|
+
"linux",
|
|
6580
|
+
"unknown"
|
|
6581
|
+
]),
|
|
6582
|
+
architecture: Schema.Literals([
|
|
6583
|
+
"arm64",
|
|
6584
|
+
"x64",
|
|
6585
|
+
"unknown"
|
|
6586
|
+
]),
|
|
6587
|
+
ci: Schema.Boolean,
|
|
6588
|
+
tty: Schema.Boolean,
|
|
6589
|
+
output_mode: Schema.Literals(["human", "json"])
|
|
6590
|
+
};
|
|
6591
|
+
const CliFirstUsedTelemetryEventSchema = Schema.Struct({
|
|
6592
|
+
name: Schema.Literal("cli_first_used"),
|
|
6593
|
+
props: Schema.Struct(CliInvocationProps)
|
|
6594
|
+
});
|
|
6595
|
+
const CliCommandStartedTelemetryEventSchema = Schema.Struct({
|
|
6596
|
+
name: Schema.Literal("cli_command_started"),
|
|
6597
|
+
props: Schema.Struct({
|
|
6598
|
+
...CliInvocationProps,
|
|
6599
|
+
invocation_kind: Schema.Literals([
|
|
6600
|
+
"command",
|
|
6601
|
+
"help",
|
|
6602
|
+
"version"
|
|
6603
|
+
])
|
|
6604
|
+
})
|
|
6605
|
+
});
|
|
6606
|
+
const CliCommandCompletedTelemetryEventSchema = Schema.Struct({
|
|
6607
|
+
name: Schema.Literal("cli_command_completed"),
|
|
6608
|
+
props: Schema.Struct({
|
|
6609
|
+
...CliInvocationProps,
|
|
6610
|
+
outcome: Schema.Literals([
|
|
6611
|
+
"succeeded",
|
|
6612
|
+
"refused",
|
|
6613
|
+
"failed",
|
|
6614
|
+
"cancelled"
|
|
6615
|
+
]),
|
|
6616
|
+
duration_ms: Schema.Number,
|
|
6617
|
+
error_code: Schema.optional(Schema.Literals([
|
|
6618
|
+
...CAPXUL_ERROR_CODES,
|
|
6619
|
+
"CLI_USAGE",
|
|
6620
|
+
"CLI_CONFIG",
|
|
6621
|
+
"CLI_STORAGE",
|
|
6622
|
+
"CLI_DEFECT"
|
|
6623
|
+
]))
|
|
6624
|
+
})
|
|
6625
|
+
});
|
|
6534
6626
|
const CliDiagnosticCompletedTelemetryEventSchema = Schema.Struct({
|
|
6535
6627
|
name: Schema.Literal("cli_diagnostic_completed"),
|
|
6536
6628
|
props: Schema.Struct({
|
|
@@ -6832,6 +6924,9 @@ const TELEMETRY_EVENT_SCHEMAS = {
|
|
|
6832
6924
|
}),
|
|
6833
6925
|
ui_contact_action_completed: UiContactActionCompletedTelemetryEventSchema,
|
|
6834
6926
|
cli_diagnostic_completed: CliDiagnosticCompletedTelemetryEventSchema,
|
|
6927
|
+
cli_first_used: CliFirstUsedTelemetryEventSchema,
|
|
6928
|
+
cli_command_started: CliCommandStartedTelemetryEventSchema,
|
|
6929
|
+
cli_command_completed: CliCommandCompletedTelemetryEventSchema,
|
|
6835
6930
|
activity_annotation_saved: ActivityAnnotationSavedTelemetryEventSchema,
|
|
6836
6931
|
ui_activity_action_completed: UiActivityActionCompletedTelemetryEventSchema,
|
|
6837
6932
|
auth_otp_requested: AuthOtpRequestedTelemetryEventSchema,
|
|
@@ -7540,6 +7635,30 @@ const PAYMENT_DOCUMENT_KINDS = [
|
|
|
7540
7635
|
"receipt",
|
|
7541
7636
|
"withdrawal"
|
|
7542
7637
|
];
|
|
7638
|
+
/** Native browser projection, distinct from the issuer's persisted request state. */
|
|
7639
|
+
const CLIENT_AUTHORIZATION_PHASE = {
|
|
7640
|
+
OTP_REQUIRED: "otp_required",
|
|
7641
|
+
REVIEW: "review",
|
|
7642
|
+
PROCESSING: "processing",
|
|
7643
|
+
CONNECTED: "connected",
|
|
7644
|
+
REFUSED: "refused"
|
|
7645
|
+
};
|
|
7646
|
+
CLIENT_AUTHORIZATION_PHASE.OTP_REQUIRED, CLIENT_AUTHORIZATION_PHASE.REVIEW, CLIENT_AUTHORIZATION_PHASE.PROCESSING, CLIENT_AUTHORIZATION_PHASE.CONNECTED, CLIENT_AUTHORIZATION_PHASE.REFUSED;
|
|
7647
|
+
/** Closed native refusals; existing Capxul error codes retain their own meaning. */
|
|
7648
|
+
const CLIENT_AUTHORIZATION_REFUSALS = [
|
|
7649
|
+
"signup_required",
|
|
7650
|
+
"setup_required",
|
|
7651
|
+
"already_signed_up",
|
|
7652
|
+
"identity_mismatch",
|
|
7653
|
+
"invalid_request",
|
|
7654
|
+
"request_expired",
|
|
7655
|
+
"request_denied",
|
|
7656
|
+
"cancelled",
|
|
7657
|
+
"grant_revoked",
|
|
7658
|
+
"grant_expired",
|
|
7659
|
+
"refresh_reused",
|
|
7660
|
+
"revoke_unconfirmed"
|
|
7661
|
+
];
|
|
7543
7662
|
//#endregion
|
|
7544
7663
|
//#region ../../packages/wire/src/financial-ops.ts
|
|
7545
7664
|
const MINOR_UNIT_STRING_RE = /^[0-9]+$/;
|
|
@@ -9241,6 +9360,251 @@ function isSafeField(field, value) {
|
|
|
9241
9360
|
return value.length > 0 && value.length <= rule.maxLength && value === value.trim() && !value.includes("://") && !containsSensitiveMaterial(value) && rule.pattern.test(value);
|
|
9242
9361
|
}
|
|
9243
9362
|
//#endregion
|
|
9363
|
+
//#region ../../packages/wire/src/client-authorization.ts
|
|
9364
|
+
const NATIVE_CLIENT_ID = "capxul-cli";
|
|
9365
|
+
const NATIVE_CLIENT_SCOPE = "account:read";
|
|
9366
|
+
const NATIVE_CLIENT_LIMITS = {
|
|
9367
|
+
accessMs: 36e5,
|
|
9368
|
+
renewalMs: 2592e6,
|
|
9369
|
+
absoluteMs: 7776e6,
|
|
9370
|
+
requestMs: 6e5,
|
|
9371
|
+
pollSeconds: 5,
|
|
9372
|
+
imageBytes: 5242880
|
|
9373
|
+
};
|
|
9374
|
+
const strict = { parseOptions: { onExcessProperty: "error" } };
|
|
9375
|
+
const text$2 = (max) => Schema.String.check(Schema.isMinLength(1), Schema.isMaxLength(max));
|
|
9376
|
+
const nonNegativeInt = Schema.Number.check(Schema.makeFilter((n) => Number.isSafeInteger(n) && n >= 0));
|
|
9377
|
+
const normalize = (f) => Schema.String.pipe(Schema.decodeTo(Schema.String, {
|
|
9378
|
+
decode: SchemaGetter.transform(f),
|
|
9379
|
+
encode: SchemaGetter.transform((s) => s)
|
|
9380
|
+
}));
|
|
9381
|
+
const ClientRequestIdSchema = Schema.String.pipe(Schema.refine((s) => CLIENT_REQUEST_ID_RE.test(s)));
|
|
9382
|
+
const ClientGrantIdSchema = Schema.String.pipe(Schema.refine((s) => CLIENT_GRANT_ID_RE.test(s)));
|
|
9383
|
+
const authUserId = Schema.String.pipe(Schema.refine((s) => s.length > 0));
|
|
9384
|
+
const keyId = Schema.String.pipe(Schema.refine((s) => s.length > 0));
|
|
9385
|
+
const email = normalize((s) => s.toLowerCase()).pipe(Schema.refine((s) => EMAIL_RE$1.test(s))).check(Schema.isMaxLength(254));
|
|
9386
|
+
const handle = Schema.String.pipe(Schema.refine((s) => HANDLE_RE$1.test(s)));
|
|
9387
|
+
const country = normalize((s) => s.toUpperCase()).pipe(Schema.refine((s) => COUNTRY_CODE_RE.test(s)));
|
|
9388
|
+
const credential = Schema.RedactedFromValue(Schema.String.check(Schema.isMinLength(32), Schema.isMaxLength(8192), Schema.isPattern(/^[A-Za-z0-9._~-]+$/u)), { label: "native authorization credential" });
|
|
9389
|
+
const otp = Schema.RedactedFromValue(Schema.String.check(Schema.isPattern(/^[0-9]{6}$/u)), { label: "OTP" });
|
|
9390
|
+
const scopes = Schema.Tuple([Schema.Literal(NATIVE_CLIENT_SCOPE)]);
|
|
9391
|
+
/** Exact HTTPS origin, no credentials/path/query and no retired cloud deployment. */
|
|
9392
|
+
const NativeHttpsOriginSchema = Schema.String.check(Schema.makeFilter((value) => {
|
|
9393
|
+
try {
|
|
9394
|
+
const url = new URL(value);
|
|
9395
|
+
const host = url.hostname.toLowerCase().replace(/\.$/u, "");
|
|
9396
|
+
return url.protocol === "https:" && value === url.origin && !url.username && !url.password && !url.search && !url.hash && host !== "convex.cloud" && !host.endsWith(".convex.cloud") && host !== "convex.site" && !host.endsWith(".convex.site");
|
|
9397
|
+
} catch {
|
|
9398
|
+
return false;
|
|
9399
|
+
}
|
|
9400
|
+
}, { message: "must be a canonical credential-free HTTPS origin outside retired Convex cloud hosts" }));
|
|
9401
|
+
const NativeClientConfigurationSchema = Schema.Struct({
|
|
9402
|
+
clientId: Schema.Literal(NATIVE_CLIENT_ID),
|
|
9403
|
+
applicationId: AppIdSchema,
|
|
9404
|
+
keyId,
|
|
9405
|
+
environment: Schema.Literals([
|
|
9406
|
+
"development",
|
|
9407
|
+
"staging",
|
|
9408
|
+
"production"
|
|
9409
|
+
]),
|
|
9410
|
+
keyEnvironment: Schema.Literals(["test", "live"]),
|
|
9411
|
+
issuer: NativeHttpsOriginSchema,
|
|
9412
|
+
verificationOrigin: NativeHttpsOriginSchema
|
|
9413
|
+
}).annotate(strict).check(Schema.makeFilter((c) => c.keyEnvironment === (c.environment === "production" ? "live" : "test"), { message: "key environment must match the configured deployment" })).annotate(strict);
|
|
9414
|
+
const NativeSignupProfileSchema = Schema.Struct({
|
|
9415
|
+
displayName: normalize((s) => s.trim()).check(Schema.isMinLength(1), Schema.isMaxLength(200)),
|
|
9416
|
+
country,
|
|
9417
|
+
handle,
|
|
9418
|
+
payoutAddresses: Schema.optional(Schema.Array(Schema.Struct({
|
|
9419
|
+
chain: Schema.Literals([
|
|
9420
|
+
"evm",
|
|
9421
|
+
"solana",
|
|
9422
|
+
"starknet"
|
|
9423
|
+
]),
|
|
9424
|
+
address: text$2(256)
|
|
9425
|
+
}).annotate(strict)).check(Schema.isMaxLength(10))),
|
|
9426
|
+
image: Schema.optional(Schema.Struct({
|
|
9427
|
+
mediaType: Schema.Literals([
|
|
9428
|
+
"image/jpeg",
|
|
9429
|
+
"image/png",
|
|
9430
|
+
"image/webp"
|
|
9431
|
+
]),
|
|
9432
|
+
byteLength: Schema.Number.check(Schema.isInt(), Schema.isBetween({
|
|
9433
|
+
minimum: 1,
|
|
9434
|
+
maximum: NATIVE_CLIENT_LIMITS.imageBytes
|
|
9435
|
+
})),
|
|
9436
|
+
sha256: Schema.String.check(Schema.isPattern(/^[0-9a-f]{64}$/u))
|
|
9437
|
+
}).annotate(strict))
|
|
9438
|
+
}).annotate(strict);
|
|
9439
|
+
const ClientAuthorizationIntentSchema = Schema.Union([Schema.Struct({ mode: Schema.Literal("login") }).annotate(strict), Schema.Struct({
|
|
9440
|
+
mode: Schema.Literal("signup"),
|
|
9441
|
+
profile: NativeSignupProfileSchema
|
|
9442
|
+
}).annotate(strict)]).annotate(strict);
|
|
9443
|
+
Schema.Struct({
|
|
9444
|
+
clientId: Schema.Literal(NATIVE_CLIENT_ID),
|
|
9445
|
+
email,
|
|
9446
|
+
intent: ClientAuthorizationIntentSchema,
|
|
9447
|
+
waitMs: Schema.Number.check(Schema.isInt(), Schema.isBetween({
|
|
9448
|
+
minimum: 1,
|
|
9449
|
+
maximum: NATIVE_CLIENT_LIMITS.requestMs
|
|
9450
|
+
})),
|
|
9451
|
+
continuityToken: Schema.optional(credential)
|
|
9452
|
+
}).annotate(strict);
|
|
9453
|
+
const request = {
|
|
9454
|
+
requestId: ClientRequestIdSchema,
|
|
9455
|
+
revision: nonNegativeInt,
|
|
9456
|
+
expiresAt: EpochMsSchema
|
|
9457
|
+
};
|
|
9458
|
+
const principal = {
|
|
9459
|
+
authUserId,
|
|
9460
|
+
email
|
|
9461
|
+
};
|
|
9462
|
+
const profileSummary = {
|
|
9463
|
+
displayName: text$2(200),
|
|
9464
|
+
handle,
|
|
9465
|
+
country
|
|
9466
|
+
};
|
|
9467
|
+
Schema.Union([
|
|
9468
|
+
Schema.Struct({
|
|
9469
|
+
...request,
|
|
9470
|
+
phase: Schema.Literal(CLIENT_AUTHORIZATION_PHASE.OTP_REQUIRED),
|
|
9471
|
+
email,
|
|
9472
|
+
resendAt: EpochMsSchema
|
|
9473
|
+
}).annotate(strict),
|
|
9474
|
+
Schema.Struct({
|
|
9475
|
+
...request,
|
|
9476
|
+
phase: Schema.Literal(CLIENT_AUTHORIZATION_PHASE.REVIEW),
|
|
9477
|
+
...principal,
|
|
9478
|
+
clientLabel: Schema.Literal("Capxul CLI"),
|
|
9479
|
+
scopes,
|
|
9480
|
+
intent: ClientAuthorizationIntentSchema,
|
|
9481
|
+
setupState: Schema.Literals([
|
|
9482
|
+
"not_required",
|
|
9483
|
+
"new",
|
|
9484
|
+
"resumable"
|
|
9485
|
+
])
|
|
9486
|
+
}).annotate(strict).check(Schema.makeFilter((v) => v.intent.mode === "login" === (v.setupState === "not_required"), { message: "login review cannot permit account setup" })),
|
|
9487
|
+
Schema.Struct({
|
|
9488
|
+
...request,
|
|
9489
|
+
phase: Schema.Literal(CLIENT_AUTHORIZATION_PHASE.PROCESSING),
|
|
9490
|
+
...principal,
|
|
9491
|
+
purpose: Schema.Literals(["login", "signup"]),
|
|
9492
|
+
step: Schema.Literals([
|
|
9493
|
+
"profile",
|
|
9494
|
+
"wallet",
|
|
9495
|
+
"account",
|
|
9496
|
+
"delivery"
|
|
9497
|
+
])
|
|
9498
|
+
}).annotate(strict).check(Schema.makeFilter((v) => v.purpose === "signup" || v.step === "delivery", { message: "login may wait for delivery but cannot enter signup processing" })),
|
|
9499
|
+
Schema.Struct({
|
|
9500
|
+
...request,
|
|
9501
|
+
phase: Schema.Literal(CLIENT_AUTHORIZATION_PHASE.CONNECTED),
|
|
9502
|
+
...principal,
|
|
9503
|
+
...profileSummary,
|
|
9504
|
+
accountId: AccountIdSchema,
|
|
9505
|
+
grantId: ClientGrantIdSchema
|
|
9506
|
+
}).annotate(strict),
|
|
9507
|
+
Schema.Struct({
|
|
9508
|
+
...request,
|
|
9509
|
+
phase: Schema.Literal(CLIENT_AUTHORIZATION_PHASE.REFUSED),
|
|
9510
|
+
reason: Schema.Literals(CLIENT_AUTHORIZATION_REFUSALS),
|
|
9511
|
+
code: Schema.Literals(CAPXUL_ERROR_CODES),
|
|
9512
|
+
field: Schema.optional(Schema.Literals([
|
|
9513
|
+
"email",
|
|
9514
|
+
"displayName",
|
|
9515
|
+
"country",
|
|
9516
|
+
"handle",
|
|
9517
|
+
"image",
|
|
9518
|
+
"payoutAddresses"
|
|
9519
|
+
])),
|
|
9520
|
+
retryable: Schema.Boolean
|
|
9521
|
+
}).annotate(strict)
|
|
9522
|
+
]).annotate(strict);
|
|
9523
|
+
Schema.Struct({
|
|
9524
|
+
requestId: ClientRequestIdSchema,
|
|
9525
|
+
revision: nonNegativeInt
|
|
9526
|
+
}).annotate(strict);
|
|
9527
|
+
Schema.Struct({
|
|
9528
|
+
requestId: ClientRequestIdSchema,
|
|
9529
|
+
code: otp
|
|
9530
|
+
}).annotate(strict);
|
|
9531
|
+
Schema.Struct({
|
|
9532
|
+
client_id: Schema.Literal(NATIVE_CLIENT_ID),
|
|
9533
|
+
grant_type: Schema.Literal("refresh_token"),
|
|
9534
|
+
refresh_token: credential,
|
|
9535
|
+
refreshAttemptId: Schema.RedactedFromValue(Schema.String.check(Schema.isPattern(/^[A-Za-z0-9_-]{32,128}$/u)), { label: "refresh attempt" })
|
|
9536
|
+
}).annotate(strict);
|
|
9537
|
+
Schema.Struct({
|
|
9538
|
+
client_id: Schema.Literal(NATIVE_CLIENT_ID),
|
|
9539
|
+
applicationId: AppIdSchema,
|
|
9540
|
+
resource: text$2(2048),
|
|
9541
|
+
token_type: Schema.Literal("Bearer"),
|
|
9542
|
+
access_token: credential,
|
|
9543
|
+
refresh_token: credential,
|
|
9544
|
+
scope: Schema.Literal(NATIVE_CLIENT_SCOPE),
|
|
9545
|
+
expires_in: Schema.Number.check(Schema.isInt(), Schema.isBetween({
|
|
9546
|
+
minimum: 1,
|
|
9547
|
+
maximum: NATIVE_CLIENT_LIMITS.accessMs / 1e3
|
|
9548
|
+
})),
|
|
9549
|
+
grantId: ClientGrantIdSchema,
|
|
9550
|
+
...principal,
|
|
9551
|
+
accountId: AccountIdSchema,
|
|
9552
|
+
issuedAt: EpochMsSchema,
|
|
9553
|
+
grantCreatedAt: EpochMsSchema,
|
|
9554
|
+
accessExpiresAt: EpochMsSchema,
|
|
9555
|
+
renewalExpiresAt: EpochMsSchema,
|
|
9556
|
+
absoluteExpiresAt: EpochMsSchema,
|
|
9557
|
+
revision: nonNegativeInt
|
|
9558
|
+
}).annotate(strict).check(Schema.makeFilter((t) => t.grantCreatedAt <= t.issuedAt && t.absoluteExpiresAt - t.grantCreatedAt === NATIVE_CLIENT_LIMITS.absoluteMs && t.renewalExpiresAt <= Math.min(t.issuedAt + NATIVE_CLIENT_LIMITS.renewalMs, t.absoluteExpiresAt) && t.accessExpiresAt <= Math.min(t.issuedAt + NATIVE_CLIENT_LIMITS.accessMs, t.renewalExpiresAt) && t.expires_in === Math.floor((t.accessExpiresAt - t.issuedAt) / 1e3), { message: "native credentials must obey the approved access, renewal and absolute deadlines" })).annotate(strict);
|
|
9559
|
+
/** One endpoint mapping; consumers cannot substitute callback or resource URLs. */
|
|
9560
|
+
function nativeClientEndpoints(config) {
|
|
9561
|
+
const resource = `${config.issuer}/api/auth/native`;
|
|
9562
|
+
return {
|
|
9563
|
+
resource,
|
|
9564
|
+
device_authorization_endpoint: `${resource}/device/code`,
|
|
9565
|
+
token_endpoint: `${resource}/token`,
|
|
9566
|
+
revocation_endpoint: `${resource}/revoke`,
|
|
9567
|
+
session_endpoint: `${resource}/session`,
|
|
9568
|
+
verification_uri: `${config.verificationOrigin}/connect`
|
|
9569
|
+
};
|
|
9570
|
+
}
|
|
9571
|
+
Schema.Struct({
|
|
9572
|
+
protocol: Schema.Literal("capxul.client-authorization"),
|
|
9573
|
+
version: Schema.Literal(1),
|
|
9574
|
+
configuration: NativeClientConfigurationSchema,
|
|
9575
|
+
scopes_supported: scopes,
|
|
9576
|
+
grant_types_supported: Schema.Tuple([Schema.Literal("urn:ietf:params:oauth:grant-type:device_code"), Schema.Literal("refresh_token")]),
|
|
9577
|
+
resource: text$2(2048),
|
|
9578
|
+
device_authorization_endpoint: text$2(2048),
|
|
9579
|
+
token_endpoint: text$2(2048),
|
|
9580
|
+
revocation_endpoint: text$2(2048),
|
|
9581
|
+
session_endpoint: text$2(2048),
|
|
9582
|
+
verification_uri: text$2(2048)
|
|
9583
|
+
}).annotate(strict).check(Schema.makeFilter((m) => {
|
|
9584
|
+
const expected = nativeClientEndpoints(m.configuration);
|
|
9585
|
+
return m.resource === expected.resource && m.device_authorization_endpoint === expected.device_authorization_endpoint && m.token_endpoint === expected.token_endpoint && m.revocation_endpoint === expected.revocation_endpoint && m.session_endpoint === expected.session_endpoint && m.verification_uri === expected.verification_uri;
|
|
9586
|
+
}, { message: "native endpoints must match their configured issuer and verification origin" })).annotate(strict);
|
|
9587
|
+
Schema.Struct({
|
|
9588
|
+
client_id: Schema.Literal(NATIVE_CLIENT_ID),
|
|
9589
|
+
grant_type: Schema.Literal("urn:ietf:params:oauth:grant-type:device_code"),
|
|
9590
|
+
device_code: credential
|
|
9591
|
+
}).annotate(strict);
|
|
9592
|
+
Schema.Struct({
|
|
9593
|
+
requestId: ClientRequestIdSchema,
|
|
9594
|
+
device_code: credential,
|
|
9595
|
+
user_code: Schema.RedactedFromValue(Schema.String.check(Schema.isPattern(/^[A-Z0-9]{4}-[A-Z0-9]{4}$/u)), { label: "device user code" }),
|
|
9596
|
+
continuityToken: credential,
|
|
9597
|
+
verification_uri: text$2(2048),
|
|
9598
|
+
expires_in: Schema.Number.check(Schema.isInt(), Schema.isBetween({
|
|
9599
|
+
minimum: 1,
|
|
9600
|
+
maximum: NATIVE_CLIENT_LIMITS.requestMs / 1e3
|
|
9601
|
+
})),
|
|
9602
|
+
interval: Schema.Number.check(Schema.isInt(), Schema.isBetween({
|
|
9603
|
+
minimum: NATIVE_CLIENT_LIMITS.pollSeconds,
|
|
9604
|
+
maximum: NATIVE_CLIENT_LIMITS.requestMs / 1e3
|
|
9605
|
+
}))
|
|
9606
|
+
}).annotate(strict);
|
|
9607
|
+
//#endregion
|
|
9244
9608
|
//#region ../../packages/sdk/src/internal/invocation-observation.ts
|
|
9245
9609
|
const INVOCATION_OBSERVATION = Symbol("capxul.invocation-observation");
|
|
9246
9610
|
const FAILURE_INVOCATION_SNAPSHOT = Symbol("capxul.failure-invocation-snapshot");
|
|
@@ -11693,7 +12057,7 @@ function subscribeActivity(deps, actor, controls, onChange) {
|
|
|
11693
12057
|
}
|
|
11694
12058
|
//#endregion
|
|
11695
12059
|
//#region ../../packages/sdk/package.json
|
|
11696
|
-
var version$1 = "4.20.0-beta.
|
|
12060
|
+
var version$1 = "4.20.0-beta.4";
|
|
11697
12061
|
//#endregion
|
|
11698
12062
|
//#region ../../packages/sdk/src/telemetry/exception-projection.ts
|
|
11699
12063
|
/** Fixed fallback for failures that have no safe message. */
|
|
@@ -13753,6 +14117,381 @@ async function recoverRawDigestSigner(input) {
|
|
|
13753
14117
|
}
|
|
13754
14118
|
}
|
|
13755
14119
|
//#endregion
|
|
14120
|
+
//#region ../../packages/observability/src/engineering-delivery.ts
|
|
14121
|
+
/** Fixed admission limits for one CLI invocation and its SDK client. */
|
|
14122
|
+
const CLI_ENGINEERING_LIMITS = Object.freeze({
|
|
14123
|
+
records: 80,
|
|
14124
|
+
ordinaryRecords: 64,
|
|
14125
|
+
recordBytes: 16384,
|
|
14126
|
+
requests: 5,
|
|
14127
|
+
ordinaryRequests: 2,
|
|
14128
|
+
requestBytes: 1572864,
|
|
14129
|
+
metricSeries: 16,
|
|
14130
|
+
requestTimeoutMs: 1e3
|
|
14131
|
+
});
|
|
14132
|
+
const metricNames = /* @__PURE__ */ new Set(["capxul.cli.command.count", "capxul.cli.command.duration"]);
|
|
14133
|
+
const metricValues = {
|
|
14134
|
+
command: CLI_COMMAND_NAMES,
|
|
14135
|
+
capability: CLI_CAPABILITIES,
|
|
14136
|
+
invocation_kind: CLI_INVOCATION_KINDS,
|
|
14137
|
+
outcome: [
|
|
14138
|
+
"succeeded",
|
|
14139
|
+
"refused",
|
|
14140
|
+
"failed",
|
|
14141
|
+
"cancelled"
|
|
14142
|
+
],
|
|
14143
|
+
capxul_env: [
|
|
14144
|
+
"development",
|
|
14145
|
+
"staging",
|
|
14146
|
+
"production",
|
|
14147
|
+
"local"
|
|
14148
|
+
],
|
|
14149
|
+
unit: [
|
|
14150
|
+
"1",
|
|
14151
|
+
"s",
|
|
14152
|
+
"ms"
|
|
14153
|
+
]
|
|
14154
|
+
};
|
|
14155
|
+
/** Only this bounded registry is supplied to the CLI's metric producers. */
|
|
14156
|
+
var CliMetricRegistry = class extends Map {
|
|
14157
|
+
dropped;
|
|
14158
|
+
enabled;
|
|
14159
|
+
constructor(dropped, enabled = true) {
|
|
14160
|
+
super();
|
|
14161
|
+
this.dropped = dropped;
|
|
14162
|
+
this.enabled = enabled;
|
|
14163
|
+
}
|
|
14164
|
+
set(key, entry) {
|
|
14165
|
+
if (!this.enabled || !metricNames.has(entry.id) || !this.has(key) && this.size >= CLI_ENGINEERING_LIMITS.metricSeries) {
|
|
14166
|
+
this.dropped();
|
|
14167
|
+
return this;
|
|
14168
|
+
}
|
|
14169
|
+
const labels = Object.entries(entry.attributes ?? {});
|
|
14170
|
+
const state = entry.hooks.get(Context.empty());
|
|
14171
|
+
const buckets = typeof state === "object" && state !== null && "buckets" in state ? state.buckets : void 0;
|
|
14172
|
+
if (!["Counter", "Histogram"].includes(entry.type) || (entry.description?.length ?? 0) > 128 || labels.length > 6 || labels.some(([name, value]) => !metricValues[name]?.includes(String(value))) || entry.type === "Histogram" && (!Array.isArray(buckets) || buckets.length > 32)) {
|
|
14173
|
+
this.dropped();
|
|
14174
|
+
return this;
|
|
14175
|
+
}
|
|
14176
|
+
return super.set(key, entry);
|
|
14177
|
+
}
|
|
14178
|
+
};
|
|
14179
|
+
/** Shared, closure-owned admission state; no queue or mutable counters are exposed. */
|
|
14180
|
+
function makeCliEngineeringBudget() {
|
|
14181
|
+
let records = 0, peakRecords = 0, activeRequests = 0, requestBytes = 0;
|
|
14182
|
+
let peakRequests = 0, peakRequestBytes = 0, dropped = 0;
|
|
14183
|
+
const drop = () => {
|
|
14184
|
+
dropped += 1;
|
|
14185
|
+
};
|
|
14186
|
+
const metricRegistry = new CliMetricRegistry(drop);
|
|
14187
|
+
return Object.freeze({
|
|
14188
|
+
metricRegistry,
|
|
14189
|
+
emptyMetricRegistry: () => new CliMetricRegistry(drop, false),
|
|
14190
|
+
drop,
|
|
14191
|
+
admitRecord(terminal) {
|
|
14192
|
+
if (records >= (terminal ? CLI_ENGINEERING_LIMITS.records : CLI_ENGINEERING_LIMITS.ordinaryRecords)) {
|
|
14193
|
+
drop();
|
|
14194
|
+
return;
|
|
14195
|
+
}
|
|
14196
|
+
records += 1;
|
|
14197
|
+
peakRecords = Math.max(peakRecords, records);
|
|
14198
|
+
let released = false;
|
|
14199
|
+
return () => {
|
|
14200
|
+
if (!released) {
|
|
14201
|
+
released = true;
|
|
14202
|
+
records -= 1;
|
|
14203
|
+
}
|
|
14204
|
+
};
|
|
14205
|
+
},
|
|
14206
|
+
admitRequest(bytes, terminal) {
|
|
14207
|
+
if (bytes > CLI_ENGINEERING_LIMITS.requestBytes || activeRequests >= (terminal ? CLI_ENGINEERING_LIMITS.requests : CLI_ENGINEERING_LIMITS.ordinaryRequests)) {
|
|
14208
|
+
drop();
|
|
14209
|
+
return;
|
|
14210
|
+
}
|
|
14211
|
+
activeRequests += 1;
|
|
14212
|
+
requestBytes += bytes;
|
|
14213
|
+
peakRequests = Math.max(peakRequests, activeRequests);
|
|
14214
|
+
peakRequestBytes = Math.max(peakRequestBytes, requestBytes);
|
|
14215
|
+
return () => {
|
|
14216
|
+
activeRequests -= 1;
|
|
14217
|
+
requestBytes -= bytes;
|
|
14218
|
+
};
|
|
14219
|
+
},
|
|
14220
|
+
snapshot() {
|
|
14221
|
+
return {
|
|
14222
|
+
records,
|
|
14223
|
+
reservedRecordBytes: records * CLI_ENGINEERING_LIMITS.recordBytes,
|
|
14224
|
+
peakRecords,
|
|
14225
|
+
peakReservedRecordBytes: peakRecords * CLI_ENGINEERING_LIMITS.recordBytes,
|
|
14226
|
+
activeRequests,
|
|
14227
|
+
requestBytes,
|
|
14228
|
+
peakRequests,
|
|
14229
|
+
peakRequestBytes,
|
|
14230
|
+
dropped,
|
|
14231
|
+
metricSeries: metricRegistry.size
|
|
14232
|
+
};
|
|
14233
|
+
}
|
|
14234
|
+
});
|
|
14235
|
+
}
|
|
14236
|
+
const text$1 = (value) => typeof value === "string" ? value.slice(0, 128) : "capxul.engineering";
|
|
14237
|
+
const attributes = (input, limit = 32) => {
|
|
14238
|
+
const out = {};
|
|
14239
|
+
let count = 0;
|
|
14240
|
+
let bytes = 0;
|
|
14241
|
+
try {
|
|
14242
|
+
for (const key in input) {
|
|
14243
|
+
if (count++ >= limit) break;
|
|
14244
|
+
if (key.length > 64) continue;
|
|
14245
|
+
const value = Object.getOwnPropertyDescriptor(input, key)?.value;
|
|
14246
|
+
const scalar = typeof value === "string" ? value.slice(0, 128) : typeof value === "boolean" || typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
14247
|
+
if (scalar === void 0) continue;
|
|
14248
|
+
bytes += new TextEncoder().encode(JSON.stringify([key, scalar])).length;
|
|
14249
|
+
if (bytes > (limit >= 24 ? 2e3 : 300)) break;
|
|
14250
|
+
out[key] = scalar;
|
|
14251
|
+
}
|
|
14252
|
+
} catch {}
|
|
14253
|
+
return out;
|
|
14254
|
+
};
|
|
14255
|
+
const terminalName = (name) => name === "cli.command.completed" || CLI_COMMAND_NAMES.some((command) => name === `cli.command.${command}`);
|
|
14256
|
+
/** Native exporters retain their serialization and scheduling; this owns admission only. */
|
|
14257
|
+
function cliEngineeringDelivery(budget, ownsMetrics) {
|
|
14258
|
+
const closed = Deferred.makeUnsafe();
|
|
14259
|
+
let isClosed = false;
|
|
14260
|
+
let metricsRunning = false;
|
|
14261
|
+
const logs = [];
|
|
14262
|
+
const spans = /* @__PURE__ */ new Map();
|
|
14263
|
+
const terminalBodies = /* @__PURE__ */ new WeakSet();
|
|
14264
|
+
const bodyLeases = /* @__PURE__ */ new WeakMap();
|
|
14265
|
+
const pendingBodies = /* @__PURE__ */ new Set();
|
|
14266
|
+
const holdBody = (body, releases) => {
|
|
14267
|
+
if (releases.length === 0) return;
|
|
14268
|
+
const lease = {
|
|
14269
|
+
started: false,
|
|
14270
|
+
release: () => {
|
|
14271
|
+
if (!pendingBodies.delete(lease)) return;
|
|
14272
|
+
bodyLeases.delete(body);
|
|
14273
|
+
for (const release of releases) release();
|
|
14274
|
+
}
|
|
14275
|
+
};
|
|
14276
|
+
bodyLeases.set(body, lease);
|
|
14277
|
+
pendingBodies.add(lease);
|
|
14278
|
+
};
|
|
14279
|
+
const discardBody = (body) => bodyLeases.get(body)?.release();
|
|
14280
|
+
const drainLogs = () => {
|
|
14281
|
+
for (const release of logs.splice(0)) release();
|
|
14282
|
+
};
|
|
14283
|
+
const close = () => {
|
|
14284
|
+
isClosed = true;
|
|
14285
|
+
Deferred.doneUnsafe(closed, Effect.void);
|
|
14286
|
+
for (const lease of pendingBodies) if (!lease.started) lease.release();
|
|
14287
|
+
drainLogs();
|
|
14288
|
+
for (const release of spans.values()) release();
|
|
14289
|
+
spans.clear();
|
|
14290
|
+
if (ownsMetrics) budget.metricRegistry.clear();
|
|
14291
|
+
};
|
|
14292
|
+
return {
|
|
14293
|
+
close,
|
|
14294
|
+
discardBody,
|
|
14295
|
+
metrics(run) {
|
|
14296
|
+
return Effect.suspend(() => {
|
|
14297
|
+
if (isClosed || metricsRunning) return Effect.void;
|
|
14298
|
+
metricsRunning = true;
|
|
14299
|
+
return run.pipe(Effect.ensuring(Effect.sync(() => {
|
|
14300
|
+
metricsRunning = false;
|
|
14301
|
+
})));
|
|
14302
|
+
});
|
|
14303
|
+
},
|
|
14304
|
+
logger(delegate) {
|
|
14305
|
+
return Logger.make((options) => {
|
|
14306
|
+
if (isClosed) return;
|
|
14307
|
+
let release;
|
|
14308
|
+
try {
|
|
14309
|
+
const message = text$1(Array.isArray(options.message) ? Object.getOwnPropertyDescriptor(options.message, "0")?.value : options.message);
|
|
14310
|
+
release = budget.admitRecord(terminalName(message));
|
|
14311
|
+
if (release === void 0) return;
|
|
14312
|
+
const context = Context.add(options.fiber.context, References.CurrentLogAnnotations, attributes(options.fiber.getRef(References.CurrentLogAnnotations)));
|
|
14313
|
+
const fiber = Object.create(options.fiber);
|
|
14314
|
+
Object.defineProperty(fiber, "getRef", { value: (ref) => Context.get(context, ref) });
|
|
14315
|
+
logs.push(release);
|
|
14316
|
+
delegate.log({
|
|
14317
|
+
...options,
|
|
14318
|
+
message,
|
|
14319
|
+
cause: Cause.empty,
|
|
14320
|
+
fiber
|
|
14321
|
+
});
|
|
14322
|
+
} catch {
|
|
14323
|
+
if (release !== void 0) {
|
|
14324
|
+
const index = logs.indexOf(release);
|
|
14325
|
+
if (index !== -1) logs.splice(index, 1);
|
|
14326
|
+
release();
|
|
14327
|
+
}
|
|
14328
|
+
budget.drop();
|
|
14329
|
+
}
|
|
14330
|
+
});
|
|
14331
|
+
},
|
|
14332
|
+
tracer(delegate) {
|
|
14333
|
+
return Tracer.make({
|
|
14334
|
+
span(options) {
|
|
14335
|
+
const name = text$1(options.name);
|
|
14336
|
+
const release = isClosed ? void 0 : budget.admitRecord(terminalName(name));
|
|
14337
|
+
const spanOptions = {
|
|
14338
|
+
...options,
|
|
14339
|
+
name,
|
|
14340
|
+
annotations: Context.empty(),
|
|
14341
|
+
links: []
|
|
14342
|
+
};
|
|
14343
|
+
const span = release === void 0 ? new Tracer.NativeSpan({
|
|
14344
|
+
...spanOptions,
|
|
14345
|
+
sampled: false
|
|
14346
|
+
}) : delegate.span(spanOptions);
|
|
14347
|
+
if (release !== void 0) spans.set(span.spanId, release);
|
|
14348
|
+
const wrapped = Object.create(span);
|
|
14349
|
+
let fields = 0, events = 0, links = 0, attributeBytes = 0;
|
|
14350
|
+
let ended = false;
|
|
14351
|
+
Object.defineProperties(wrapped, {
|
|
14352
|
+
attribute: { value: (key, value) => {
|
|
14353
|
+
if (fields >= 32 && !span.attributes.has(key)) {
|
|
14354
|
+
budget.drop();
|
|
14355
|
+
return;
|
|
14356
|
+
}
|
|
14357
|
+
const safe = attributes({ [key]: value }, 1);
|
|
14358
|
+
if (!Object.hasOwn(safe, key)) return;
|
|
14359
|
+
const previous = span.attributes.has(key) ? new TextEncoder().encode(JSON.stringify([key, span.attributes.get(key)])).length : 0;
|
|
14360
|
+
const next = new TextEncoder().encode(JSON.stringify([key, safe[key]])).length;
|
|
14361
|
+
if (attributeBytes - previous + next > 2e3) {
|
|
14362
|
+
budget.drop();
|
|
14363
|
+
return;
|
|
14364
|
+
}
|
|
14365
|
+
attributeBytes += next - previous;
|
|
14366
|
+
if (!span.attributes.has(key)) fields += 1;
|
|
14367
|
+
span.attribute(key, safe[key]);
|
|
14368
|
+
} },
|
|
14369
|
+
event: { value: (eventName, time, attrs) => {
|
|
14370
|
+
if (events++ >= 2) {
|
|
14371
|
+
budget.drop();
|
|
14372
|
+
return;
|
|
14373
|
+
}
|
|
14374
|
+
span.event(text$1(eventName), time, attributes(attrs ?? {}, 4));
|
|
14375
|
+
} },
|
|
14376
|
+
addLinks: { value: (items) => {
|
|
14377
|
+
for (const item of items.slice(0, Math.max(0, 2 - links))) {
|
|
14378
|
+
if (!/^[a-f0-9]{32}$/u.test(item.span.traceId) || !/^[a-f0-9]{16}$/u.test(item.span.spanId)) {
|
|
14379
|
+
budget.drop();
|
|
14380
|
+
continue;
|
|
14381
|
+
}
|
|
14382
|
+
span.addLinks([{
|
|
14383
|
+
span: Tracer.externalSpan({
|
|
14384
|
+
traceId: item.span.traceId,
|
|
14385
|
+
spanId: item.span.spanId,
|
|
14386
|
+
sampled: item.span.sampled
|
|
14387
|
+
}),
|
|
14388
|
+
attributes: attributes(item.attributes, 4)
|
|
14389
|
+
}]);
|
|
14390
|
+
links += 1;
|
|
14391
|
+
}
|
|
14392
|
+
} },
|
|
14393
|
+
end: { value: (time, exit) => {
|
|
14394
|
+
if (ended) return;
|
|
14395
|
+
ended = true;
|
|
14396
|
+
span.end(time, Exit.isFailure(exit) ? Exit.fail("CLI operation failed") : Exit.void);
|
|
14397
|
+
} }
|
|
14398
|
+
});
|
|
14399
|
+
wrapped.addLinks(options.links ?? []);
|
|
14400
|
+
return wrapped;
|
|
14401
|
+
},
|
|
14402
|
+
...delegate.context === void 0 ? {} : { context: delegate.context.bind(delegate) }
|
|
14403
|
+
});
|
|
14404
|
+
},
|
|
14405
|
+
serialization(delegate) {
|
|
14406
|
+
return {
|
|
14407
|
+
logs(data) {
|
|
14408
|
+
const releases = logs.splice(0);
|
|
14409
|
+
try {
|
|
14410
|
+
const body = delegate.logs(data);
|
|
14411
|
+
if (data.resourceLogs.some((r) => r.scopeLogs.some((s) => s.logRecords?.some((l) => l.body?.stringValue === "cli.command.completed")))) terminalBodies.add(body);
|
|
14412
|
+
holdBody(body, releases);
|
|
14413
|
+
return body;
|
|
14414
|
+
} catch (error) {
|
|
14415
|
+
for (const release of releases) release();
|
|
14416
|
+
throw error;
|
|
14417
|
+
}
|
|
14418
|
+
},
|
|
14419
|
+
traces(data) {
|
|
14420
|
+
const releases = [];
|
|
14421
|
+
for (const resource of data.resourceSpans) for (const scope of resource.scopeSpans) for (const span of scope.spans) {
|
|
14422
|
+
const release = spans.get(span.spanId);
|
|
14423
|
+
if (release !== void 0) releases.push(release);
|
|
14424
|
+
spans.delete(span.spanId);
|
|
14425
|
+
}
|
|
14426
|
+
try {
|
|
14427
|
+
const body = delegate.traces(data);
|
|
14428
|
+
if (data.resourceSpans.some((r) => r.scopeSpans.some((s) => s.spans.some((span) => terminalName(span.name))))) terminalBodies.add(body);
|
|
14429
|
+
holdBody(body, releases);
|
|
14430
|
+
return body;
|
|
14431
|
+
} catch (error) {
|
|
14432
|
+
for (const release of releases) release();
|
|
14433
|
+
throw error;
|
|
14434
|
+
}
|
|
14435
|
+
},
|
|
14436
|
+
metrics(data) {
|
|
14437
|
+
const body = delegate.metrics(data);
|
|
14438
|
+
terminalBodies.add(body);
|
|
14439
|
+
return body;
|
|
14440
|
+
}
|
|
14441
|
+
};
|
|
14442
|
+
},
|
|
14443
|
+
transport(client, enabled = () => true) {
|
|
14444
|
+
const retrying = HttpClient.transform(client, (response, request) => Effect.suspend(() => {
|
|
14445
|
+
if (enabled()) return response;
|
|
14446
|
+
budget.drop();
|
|
14447
|
+
return Effect.succeed(HttpClientResponse.fromWeb(request, new Response(null)));
|
|
14448
|
+
})).pipe(HttpClient.transformResponse((response) => Effect.tap(response, (result) => {
|
|
14449
|
+
let received = 0;
|
|
14450
|
+
return Stream.runForEach(result.stream, (chunk) => Effect.sync(() => {
|
|
14451
|
+
received += chunk.byteLength;
|
|
14452
|
+
if (received > 65536) throw new Error("Engineering response limit exceeded");
|
|
14453
|
+
})).pipe(Effect.catchTag("HttpClientError", (error) => error.reason._tag === "EmptyBodyError" ? Effect.void : Effect.fail(error)));
|
|
14454
|
+
}))).pipe(HttpClient.filterStatusOk, HttpClient.retryTransient({
|
|
14455
|
+
times: 1,
|
|
14456
|
+
schedule: Schedule.spaced("100 millis").pipe(Schedule.addDelay(({ input }) => Effect.map(Clock.currentTimeMillis, (now) => {
|
|
14457
|
+
if (!HttpClientError.isHttpClientError(input) || input.reason._tag !== "StatusCodeError" || input.reason.response.status !== 429) return Duration.zero;
|
|
14458
|
+
const header = input.reason.response.headers["retry-after"];
|
|
14459
|
+
const numeric = Number(header);
|
|
14460
|
+
const delay = header === void 0 ? 2e3 : Number.isFinite(numeric) ? numeric * 1e3 : Date.parse(header) - now;
|
|
14461
|
+
return Duration.millis(Number.isFinite(delay) ? Math.min(2e3, Math.max(0, delay)) : 2e3);
|
|
14462
|
+
})))
|
|
14463
|
+
}));
|
|
14464
|
+
return HttpClient.transform(retrying, (response, request) => Effect.suspend(() => {
|
|
14465
|
+
if (isClosed) {
|
|
14466
|
+
discardBody(request.body);
|
|
14467
|
+
return Effect.succeed(HttpClientResponse.fromWeb(request, new Response(null)));
|
|
14468
|
+
}
|
|
14469
|
+
const droppedResponse = () => HttpClientResponse.fromWeb(request, new Response(null, { status: 200 }));
|
|
14470
|
+
if (request.body._tag === "Empty") {
|
|
14471
|
+
discardBody(request.body);
|
|
14472
|
+
return Effect.succeed(droppedResponse());
|
|
14473
|
+
}
|
|
14474
|
+
const bytes = request.body.contentLength;
|
|
14475
|
+
const release = budget.admitRequest(bytes ?? Number.POSITIVE_INFINITY, terminalBodies.has(request.body));
|
|
14476
|
+
if (release === void 0) {
|
|
14477
|
+
discardBody(request.body);
|
|
14478
|
+
return Effect.succeed(droppedResponse());
|
|
14479
|
+
}
|
|
14480
|
+
const lease = bodyLeases.get(request.body);
|
|
14481
|
+
if (lease !== void 0) lease.started = true;
|
|
14482
|
+
return response.pipe(Effect.asVoid, Effect.timeoutOption(CLI_ENGINEERING_LIMITS.requestTimeoutMs), Effect.raceFirst(Deferred.await(closed).pipe(Effect.andThen(Effect.interrupt))), Effect.tap((result) => Effect.sync(() => {
|
|
14483
|
+
if (Option.isNone(result)) budget.drop();
|
|
14484
|
+
})), Effect.catchCause(() => Effect.sync(() => {
|
|
14485
|
+
budget.drop();
|
|
14486
|
+
})), Effect.as(droppedResponse()), Effect.ensuring(Effect.sync(() => {
|
|
14487
|
+
release();
|
|
14488
|
+
discardBody(request.body);
|
|
14489
|
+
})));
|
|
14490
|
+
}));
|
|
14491
|
+
}
|
|
14492
|
+
};
|
|
14493
|
+
}
|
|
14494
|
+
//#endregion
|
|
13756
14495
|
//#region ../../packages/observability/src/engineering.ts
|
|
13757
14496
|
const ENGINEERING_CAPXUL_ENVS = [
|
|
13758
14497
|
"development",
|
|
@@ -13927,10 +14666,13 @@ const MINIMAL_NUMBERS = /* @__PURE__ */ new Set([
|
|
|
13927
14666
|
const MINIMAL_CORRELATIONS = /* @__PURE__ */ new Set([
|
|
13928
14667
|
"correlation_id",
|
|
13929
14668
|
"journey_id",
|
|
13930
|
-
"invocation_id"
|
|
14669
|
+
"invocation_id",
|
|
14670
|
+
"posthogDistinctId"
|
|
13931
14671
|
]);
|
|
13932
14672
|
const MINIMAL_METRIC_LABELS = /* @__PURE__ */ new Set([
|
|
13933
14673
|
"command",
|
|
14674
|
+
"capability",
|
|
14675
|
+
"invocation_kind",
|
|
13934
14676
|
"outcome",
|
|
13935
14677
|
"capxul_env",
|
|
13936
14678
|
"unit"
|
|
@@ -13938,7 +14680,7 @@ const MINIMAL_METRIC_LABELS = /* @__PURE__ */ new Set([
|
|
|
13938
14680
|
const MINIMAL_METRIC_NAMES = /* @__PURE__ */ new Set(["capxul.cli.command.count", "capxul.cli.command.duration"]);
|
|
13939
14681
|
const traceId = (value) => typeof value === "string" && /^(?!0+$)[0-9a-f]{32}$/u.test(value);
|
|
13940
14682
|
const spanId = (value) => typeof value === "string" && /^(?!0+$)[0-9a-f]{16}$/u.test(value);
|
|
13941
|
-
const minimalName = (value) => typeof value === "string" && (MINIMAL_LOG_NAMES.has(value) || isCapxulOperation(value)) ? value : "capxul.engineering";
|
|
14683
|
+
const minimalName = (value) => typeof value === "string" && (MINIMAL_LOG_NAMES.has(value) || isCapxulOperation(value) || CLI_COMMAND_NAMES.some((command) => value === `cli.command.${command}`)) ? value : "capxul.engineering";
|
|
13942
14684
|
const MINIMAL_ENUM_VALUES = /* @__PURE__ */ new Map([
|
|
13943
14685
|
["outcome", [
|
|
13944
14686
|
"succeeded",
|
|
@@ -13951,7 +14693,10 @@ const MINIMAL_ENUM_VALUES = /* @__PURE__ */ new Map([
|
|
|
13951
14693
|
["failure_mode", FAILURE_MODES$1],
|
|
13952
14694
|
["capxul_env", ENGINEERING_CAPXUL_ENVS],
|
|
13953
14695
|
["producer", ["browser", "server"]],
|
|
13954
|
-
["command",
|
|
14696
|
+
["command", CLI_COMMAND_NAMES],
|
|
14697
|
+
["capability", CLI_CAPABILITIES],
|
|
14698
|
+
["invocation_kind", CLI_INVOCATION_KINDS],
|
|
14699
|
+
["cli_identity_kind", ["anonymous"]],
|
|
13955
14700
|
["output_mode", ["human", "json"]],
|
|
13956
14701
|
["unit", [
|
|
13957
14702
|
"1",
|
|
@@ -14169,10 +14914,17 @@ function minimalSerialization(config) {
|
|
|
14169
14914
|
}
|
|
14170
14915
|
/** Attempt to drain all engineering signals; completion does not prove ingestion. */
|
|
14171
14916
|
const flushEngineeringTelemetry = Effect.flatMap(OtlpExporter.Flusher, (flusher) => flusher.flush);
|
|
14917
|
+
var EngineeringLog = class extends Context.Service()("capxul/EngineeringLog") {};
|
|
14918
|
+
/** Deliver an owned engineering record without changing the caller's console verbosity. */
|
|
14919
|
+
const logEngineeringInfo = (message, attributes) => {
|
|
14920
|
+
const record = Effect.logInfo(message).pipe(Effect.annotateLogs(attributes));
|
|
14921
|
+
return Effect.flatMap(LogLevel.isEnabled("Info"), (visible) => visible ? record : Effect.flatMap(EngineeringLog, (logger) => record.pipe(Effect.provideService(Logger.CurrentLoggers, /* @__PURE__ */ new Set([logger])), Effect.provideService(References.MinimumLogLevel, "All"))));
|
|
14922
|
+
};
|
|
14172
14923
|
/** Shared browser/server OTLP layer. OtlpLogger merges with incumbent loggers once. */
|
|
14173
14924
|
const makeEngineeringTelemetryLayer = (config) => {
|
|
14174
14925
|
const validated = validateEngineeringTelemetryConfig(config);
|
|
14175
14926
|
return Layer.suspend(() => {
|
|
14927
|
+
const bounded = validated.deliveryBudget === void 0 ? void 0 : cliEngineeringDelivery(validated.deliveryBudget, validated.serviceName === "capxul-cli");
|
|
14176
14928
|
const endpoints = postHogOtlpEndpoints(validated.host);
|
|
14177
14929
|
let disabled = false;
|
|
14178
14930
|
const enabled = () => {
|
|
@@ -14186,7 +14938,12 @@ const makeEngineeringTelemetryLayer = (config) => {
|
|
|
14186
14938
|
};
|
|
14187
14939
|
const delivery = {
|
|
14188
14940
|
...validated.shutdownTimeout === void 0 ? {} : { shutdownTimeout: validated.shutdownTimeout },
|
|
14189
|
-
...validated.exportInterval === void 0 ? {} : { exportInterval: validated.exportInterval }
|
|
14941
|
+
...validated.exportInterval === void 0 ? {} : { exportInterval: validated.exportInterval },
|
|
14942
|
+
...bounded === void 0 ? {} : {
|
|
14943
|
+
maxBatchSize: Number.MAX_SAFE_INTEGER,
|
|
14944
|
+
exportInterval: 1e3,
|
|
14945
|
+
shutdownTimeout: validated.serviceName === "capxul-cli" ? 0 : 500
|
|
14946
|
+
}
|
|
14190
14947
|
};
|
|
14191
14948
|
const resource = {
|
|
14192
14949
|
serviceName: validated.serviceName ?? "capxul-sdk",
|
|
@@ -14202,22 +14959,38 @@ const makeEngineeringTelemetryLayer = (config) => {
|
|
|
14202
14959
|
headers: validated.headers,
|
|
14203
14960
|
resource,
|
|
14204
14961
|
...delivery
|
|
14205
|
-
}).pipe(Effect.map((tracer) => makeLeakSafeEngineeringTracer(tracer, enabled)))).pipe(Layer.provideMerge(OtlpExporter.layerFlusher));
|
|
14206
|
-
const
|
|
14962
|
+
}).pipe(Effect.map((tracer) => makeLeakSafeEngineeringTracer(bounded?.tracer(tracer) ?? tracer, enabled)))).pipe(Layer.provideMerge(OtlpExporter.layerFlusher));
|
|
14963
|
+
const ownedLogging = Layer.effect(EngineeringLog, OtlpLogger.make({
|
|
14207
14964
|
url: endpoints.logs,
|
|
14208
14965
|
headers: validated.headers,
|
|
14209
14966
|
resource,
|
|
14210
|
-
...delivery
|
|
14211
|
-
|
|
14212
|
-
|
|
14213
|
-
|
|
14214
|
-
|
|
14967
|
+
...delivery,
|
|
14968
|
+
...bounded === void 0 ? {} : { excludeLogSpans: true }
|
|
14969
|
+
}).pipe(Effect.map((nativeLogger) => {
|
|
14970
|
+
const logger = bounded?.logger(nativeLogger) ?? nativeLogger;
|
|
14971
|
+
return Logger.make((options) => {
|
|
14972
|
+
if (enabled()) logger.log(options);
|
|
14973
|
+
});
|
|
14974
|
+
}))).pipe(Layer.provideMerge(OtlpExporter.layerFlusher));
|
|
14975
|
+
const logging = Logger.layer([EngineeringLog], { mergeWithExisting: true }).pipe(Layer.provideMerge(ownedLogging));
|
|
14976
|
+
const metricConfig = {
|
|
14215
14977
|
url: endpoints.metrics,
|
|
14216
14978
|
headers: validated.headers,
|
|
14217
14979
|
resource,
|
|
14218
14980
|
temporality: "delta",
|
|
14219
14981
|
...delivery
|
|
14220
|
-
}
|
|
14982
|
+
};
|
|
14983
|
+
const metrics = bounded === void 0 ? OtlpMetrics.layer(metricConfig) : validated.serviceName !== "capxul-cli" ? Layer.empty : Layer.effectDiscard(Effect.gen(function* () {
|
|
14984
|
+
const flusher = yield* OtlpExporter.Flusher;
|
|
14985
|
+
yield* OtlpMetrics.make({
|
|
14986
|
+
...metricConfig,
|
|
14987
|
+
exportInterval: Number.POSITIVE_INFINITY,
|
|
14988
|
+
shutdownTimeout: 0
|
|
14989
|
+
}).pipe(Effect.provideService(OtlpExporter.Flusher, {
|
|
14990
|
+
...flusher,
|
|
14991
|
+
register: (run) => flusher.register(bounded.metrics(run))
|
|
14992
|
+
}));
|
|
14993
|
+
})).pipe(Layer.provideMerge(OtlpExporter.layerFlusher));
|
|
14221
14994
|
const headerPolicy = Layer.merge(Layer.succeed(HttpClient.TracerHeaderFilter, traceHeaderFilter), Layer.succeed(Headers.CurrentRedactedNames, [credentialHeaderPattern]));
|
|
14222
14995
|
const browserLifecycle = Layer.effectDiscard(Effect.gen(function* () {
|
|
14223
14996
|
if (validated.producer !== "browser" || !hasBrowserDocument()) return;
|
|
@@ -14240,17 +15013,25 @@ const makeEngineeringTelemetryLayer = (config) => {
|
|
|
14240
15013
|
}));
|
|
14241
15014
|
}));
|
|
14242
15015
|
const transport = Layer.effect(HttpClient.HttpClient, Effect.map(HttpClient.HttpClient, (client) => {
|
|
14243
|
-
const
|
|
14244
|
-
|
|
15016
|
+
const originalTransport = validated.producer === "browser" && hasBrowserDocument() ? browserExportClient(client) : client;
|
|
15017
|
+
const selectedTransport = bounded?.transport(originalTransport, enabled) ?? originalTransport;
|
|
15018
|
+
return HttpClient.transform(selectedTransport, (response, request) => Effect.suspend(() => {
|
|
15019
|
+
if (enabled() && request.body._tag !== "Empty") return response;
|
|
15020
|
+
bounded?.discardBody(request.body);
|
|
15021
|
+
return Effect.succeed(HttpClientResponse.fromWeb(request, new Response(null, { status: 200 })));
|
|
15022
|
+
}));
|
|
14245
15023
|
})).pipe(Layer.provide(FetchHttpClient.layer));
|
|
14246
15024
|
const serialization = Layer.effect(OtlpSerialization.OtlpSerialization, Effect.map(OtlpSerialization.OtlpSerialization, (json) => {
|
|
14247
15025
|
const projected = minimalSerialization(validated);
|
|
14248
|
-
|
|
15026
|
+
const selected = validated.privacy === "minimal" ? projected : {
|
|
14249
15027
|
...json,
|
|
14250
15028
|
metrics: projected.metrics
|
|
14251
15029
|
};
|
|
15030
|
+
return bounded?.serialization(selected) ?? selected;
|
|
14252
15031
|
})).pipe(Layer.provide(OtlpSerialization.layerJson));
|
|
14253
|
-
|
|
15032
|
+
const combined = browserLifecycle.pipe(Layer.provideMerge(Layer.mergeAll(tracing, logging, metrics, headerPolicy)), Layer.provide(serialization), Layer.provide(transport));
|
|
15033
|
+
const scoped = bounded === void 0 ? combined : combined.pipe(Layer.provideMerge(Layer.effectDiscard(Effect.addFinalizer(() => Effect.sync(bounded.close)))));
|
|
15034
|
+
return validated.deliveryBudget === void 0 ? scoped : scoped.pipe(Layer.provideMerge(Layer.succeed(Metric.MetricRegistry, validated.serviceName === "capxul-cli" ? validated.deliveryBudget.metricRegistry : validated.deliveryBudget.emptyMetricRegistry())));
|
|
14254
15035
|
});
|
|
14255
15036
|
};
|
|
14256
15037
|
//#endregion
|
|
@@ -47769,6 +48550,7 @@ function postHogObservability(client, options = {}) {
|
|
|
47769
48550
|
product: postHogProductTelemetry(policy)
|
|
47770
48551
|
};
|
|
47771
48552
|
Object.defineProperty(module, HOST_ENGINEERING_POLICY, { value: Object.freeze({
|
|
48553
|
+
...options.engineeringDeliveryBudget === void 0 ? {} : { engineeringDeliveryBudget: options.engineeringDeliveryBudget },
|
|
47772
48554
|
...options.engineeringEnabled === void 0 ? {} : { engineeringEnabled: options.engineeringEnabled },
|
|
47773
48555
|
...options.engineeringPrivacy === void 0 ? {} : { engineeringPrivacy: options.engineeringPrivacy }
|
|
47774
48556
|
}) });
|
|
@@ -47806,6 +48588,7 @@ function isPromiseLike(value) {
|
|
|
47806
48588
|
function hostEngineeringPolicy(observability) {
|
|
47807
48589
|
const policy = observability?.[HOST_ENGINEERING_POLICY];
|
|
47808
48590
|
return {
|
|
48591
|
+
...policy?.engineeringDeliveryBudget === void 0 ? {} : { deliveryBudget: policy.engineeringDeliveryBudget },
|
|
47809
48592
|
...policy?.engineeringEnabled === void 0 ? {} : { enabled: policy.engineeringEnabled },
|
|
47810
48593
|
...policy?.engineeringPrivacy === void 0 ? {} : { privacy: policy.engineeringPrivacy }
|
|
47811
48594
|
};
|
|
@@ -49020,6 +49803,82 @@ function captureException(telemetry, error, context) {
|
|
|
49020
49803
|
}).pipe(Effect.flatten), () => Effect.void);
|
|
49021
49804
|
}
|
|
49022
49805
|
//#endregion
|
|
49806
|
+
//#region src/platform/observation-identity.ts
|
|
49807
|
+
const uuid = Schema.String.check(Schema.isPattern(/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/u));
|
|
49808
|
+
const person = Schema.String.check(Schema.isPattern(/^[^\s]{1,256}$/u));
|
|
49809
|
+
const binding = Schema.Struct({
|
|
49810
|
+
authUserId: person,
|
|
49811
|
+
eventId: uuid
|
|
49812
|
+
});
|
|
49813
|
+
const epoch = Schema.Struct({
|
|
49814
|
+
id: uuid,
|
|
49815
|
+
binding: Schema.NullOr(binding)
|
|
49816
|
+
});
|
|
49817
|
+
const ObservationIdentity = Schema.Struct({
|
|
49818
|
+
version: Schema.Literal(1),
|
|
49819
|
+
firstUse: Schema.Struct({
|
|
49820
|
+
eventId: uuid,
|
|
49821
|
+
observedAt: Schema.Int.check(Schema.isGreaterThanOrEqualTo(0))
|
|
49822
|
+
}),
|
|
49823
|
+
epoch
|
|
49824
|
+
});
|
|
49825
|
+
const ObservationIdentityChange = Schema.Union([
|
|
49826
|
+
Schema.Struct({ kind: Schema.Literal("acquire") }),
|
|
49827
|
+
Schema.Struct({
|
|
49828
|
+
kind: Schema.Literal("bind"),
|
|
49829
|
+
expectedEpoch: uuid,
|
|
49830
|
+
authUserId: person
|
|
49831
|
+
}),
|
|
49832
|
+
Schema.Struct({
|
|
49833
|
+
kind: Schema.Literal("rotate"),
|
|
49834
|
+
expectedEpoch: uuid
|
|
49835
|
+
})
|
|
49836
|
+
]);
|
|
49837
|
+
/** Observation bookkeeping only. The caller must obtain verified person facts from AUTH. */
|
|
49838
|
+
function transitionObservationIdentity(previous, change, fresh) {
|
|
49839
|
+
if (change.kind !== "acquire" && previous?.epoch.id !== change.expectedEpoch) return {
|
|
49840
|
+
state: previous,
|
|
49841
|
+
result: { status: "stale" }
|
|
49842
|
+
};
|
|
49843
|
+
let state = previous ?? {
|
|
49844
|
+
version: 1,
|
|
49845
|
+
firstUse: {
|
|
49846
|
+
eventId: fresh.eventId,
|
|
49847
|
+
observedAt: fresh.observedAt
|
|
49848
|
+
},
|
|
49849
|
+
epoch: {
|
|
49850
|
+
id: fresh.epochId,
|
|
49851
|
+
binding: null
|
|
49852
|
+
}
|
|
49853
|
+
};
|
|
49854
|
+
if (change.kind === "rotate" || change.kind === "acquire" && state.epoch.binding !== null) state = {
|
|
49855
|
+
...state,
|
|
49856
|
+
epoch: {
|
|
49857
|
+
id: fresh.epochId,
|
|
49858
|
+
binding: null
|
|
49859
|
+
}
|
|
49860
|
+
};
|
|
49861
|
+
else if (change.kind === "bind" && state.epoch.binding?.authUserId !== change.authUserId) state = {
|
|
49862
|
+
...state,
|
|
49863
|
+
epoch: {
|
|
49864
|
+
id: state.epoch.binding === null ? state.epoch.id : fresh.epochId,
|
|
49865
|
+
binding: {
|
|
49866
|
+
authUserId: change.authUserId,
|
|
49867
|
+
eventId: fresh.eventId
|
|
49868
|
+
}
|
|
49869
|
+
}
|
|
49870
|
+
};
|
|
49871
|
+
return {
|
|
49872
|
+
state,
|
|
49873
|
+
result: {
|
|
49874
|
+
status: "ready",
|
|
49875
|
+
firstUse: state.firstUse,
|
|
49876
|
+
firstUseClaimed: previous === null,
|
|
49877
|
+
epoch: state.epoch
|
|
49878
|
+
}
|
|
49879
|
+
};
|
|
49880
|
+
}
|
|
49881
|
+
//#endregion
|
|
49023
49882
|
//#region src/platform/state-files.ts
|
|
49024
49883
|
const Settings = Schema.Struct({
|
|
49025
49884
|
version: Schema.Literal(1),
|
|
@@ -49163,11 +50022,12 @@ const withLock = (file, body) => Effect.scoped(Effect.gen(function* () {
|
|
|
49163
50022
|
}));
|
|
49164
50023
|
return yield* body(path.join(lock, `${owner}.data`));
|
|
49165
50024
|
}));
|
|
49166
|
-
const replace = (file,
|
|
50025
|
+
const replace = (file, update) => Effect.gen(function* () {
|
|
49167
50026
|
const fs = yield* FileSystem.FileSystem;
|
|
49168
|
-
if (new TextEncoder().encode(content).length > 65536) return yield* Effect.fail(fail("Corrupt"));
|
|
49169
50027
|
return yield* withLock(file, (temporary) => Effect.gen(function* () {
|
|
49170
|
-
yield*
|
|
50028
|
+
const { content, value } = yield* update;
|
|
50029
|
+
if (content === null) return value;
|
|
50030
|
+
if (new TextEncoder().encode(content).length > 65536) return yield* Effect.fail(fail("Corrupt"));
|
|
49171
50031
|
const handle = yield* fs.open(temporary, {
|
|
49172
50032
|
flag: "wx",
|
|
49173
50033
|
mode: 384
|
|
@@ -49179,6 +50039,7 @@ const replace = (file, content, validate) => Effect.gen(function* () {
|
|
|
49179
50039
|
const path = yield* Path.Path;
|
|
49180
50040
|
yield* (yield* fs.open(path.dirname(file))).sync;
|
|
49181
50041
|
}));
|
|
50042
|
+
return value;
|
|
49182
50043
|
}));
|
|
49183
50044
|
});
|
|
49184
50045
|
const setCollectionEnabled = (file, enabled) => Effect.gen(function* () {
|
|
@@ -49187,9 +50048,33 @@ const setCollectionEnabled = (file, enabled) => Effect.gen(function* () {
|
|
|
49187
50048
|
version: 1,
|
|
49188
50049
|
collection: { enabled }
|
|
49189
50050
|
};
|
|
49190
|
-
yield* replace(location,
|
|
50051
|
+
yield* replace(location, readSettings(location).pipe(Effect.as({
|
|
50052
|
+
content: JSON.stringify(settings),
|
|
50053
|
+
value: void 0
|
|
50054
|
+
})));
|
|
49191
50055
|
return settings;
|
|
49192
50056
|
}).pipe(Effect.mapError(storageError));
|
|
50057
|
+
const changeObservationIdentity = (directory, input) => Effect.gen(function* () {
|
|
50058
|
+
const change = yield* Schema.decodeUnknownEffect(ObservationIdentityChange, { onExcessProperty: "error" })(input).pipe(Effect.mapError(() => fail("Corrupt")));
|
|
50059
|
+
const path = yield* Path.Path;
|
|
50060
|
+
const location = yield* locate(path.join(directory, "observation.json"), true);
|
|
50061
|
+
return yield* replace(location, Effect.gen(function* () {
|
|
50062
|
+
const content = yield* readFile(location);
|
|
50063
|
+
const previous = content === null ? null : yield* Schema.decodeUnknownEffect(Schema.fromJsonString(ObservationIdentity), { onExcessProperty: "error" })(content).pipe(Effect.mapError(() => fail("Corrupt")));
|
|
50064
|
+
const crypto = yield* Crypto.Crypto;
|
|
50065
|
+
const next = transitionObservationIdentity(previous, change, {
|
|
50066
|
+
epochId: yield* crypto.randomUUIDv4,
|
|
50067
|
+
eventId: yield* crypto.randomUUIDv4,
|
|
50068
|
+
observedAt: yield* Clock.currentTimeMillis
|
|
50069
|
+
});
|
|
50070
|
+
return {
|
|
50071
|
+
content: next.state === previous ? null : JSON.stringify(next.state),
|
|
50072
|
+
value: next.result
|
|
50073
|
+
};
|
|
50074
|
+
}));
|
|
50075
|
+
}).pipe(Effect.mapError(storageError));
|
|
50076
|
+
/** Call only for eligible collection. This never infers AUTH identity from stored state. */
|
|
50077
|
+
const acquireObservationIdentity = (directory) => changeObservationIdentity(directory, { kind: "acquire" });
|
|
49193
50078
|
//#endregion
|
|
49194
50079
|
//#region src/platform/collection-policy.ts
|
|
49195
50080
|
const decode = Schema.decodeUnknownOption(Schema.fromJsonString(Settings), { onExcessProperty: "error" });
|
|
@@ -49299,6 +50184,8 @@ function parsedCommand(cause) {
|
|
|
49299
50184
|
}
|
|
49300
50185
|
//#endregion
|
|
49301
50186
|
//#region src/runtime/config.ts
|
|
50187
|
+
const defaultHost = "https://us.i.posthog.com";
|
|
50188
|
+
const defaultProjectToken = Redacted.make("phc_BZuAVofrkNXzwpJkuDG7Rdfurir45fj2dudQvJZk847e");
|
|
49302
50189
|
const optionalText = (name) => Config.option(Config.string(name));
|
|
49303
50190
|
function httpOrigin(value, field) {
|
|
49304
50191
|
return Effect.try({
|
|
@@ -49312,14 +50199,12 @@ function httpOrigin(value, field) {
|
|
|
49312
50199
|
catch: () => configurationFailure(`The ${field} URL must be a valid approved origin.`)
|
|
49313
50200
|
});
|
|
49314
50201
|
}
|
|
49315
|
-
const
|
|
50202
|
+
const loadObservationConfig = Effect.gen(function* () {
|
|
49316
50203
|
const path = yield* Path.Path;
|
|
49317
50204
|
const values = yield* Config.all({
|
|
49318
50205
|
cliHome: optionalText("CAPXUL_CLI_HOME"),
|
|
49319
50206
|
home: optionalText("HOME"),
|
|
49320
50207
|
xdg: optionalText("XDG_CONFIG_HOME"),
|
|
49321
|
-
key: Config.option(Config.redacted("CAPXUL_PUBLISHABLE_KEY")),
|
|
49322
|
-
bootstrap: Config.string("CAPXUL_BOOTSTRAP_URL").pipe(Config.withDefault("https://api.staging.capxul.com")),
|
|
49323
50208
|
host: optionalText("CAPXUL_POSTHOG_HOST"),
|
|
49324
50209
|
token: Config.option(Config.redacted("CAPXUL_POSTHOG_PROJECT_TOKEN")),
|
|
49325
50210
|
disabled: Config.boolean("CAPXUL_TELEMETRY_DISABLED").pipe(Config.withDefault(false))
|
|
@@ -49333,19 +50218,29 @@ const loadConfig = Effect.gen(function* () {
|
|
|
49333
50218
|
else return yield* Effect.fail(configurationFailure("Set HOME or CAPXUL_CLI_HOME."));
|
|
49334
50219
|
}
|
|
49335
50220
|
const settingsPath = path.join(path.resolve(directory), "settings.json");
|
|
49336
|
-
const
|
|
49337
|
-
const posthogHost = Option.isSome(values.host) ? yield* httpOrigin(values.host.value, "PostHog") : void 0;
|
|
50221
|
+
const host = Option.getOrUndefined(values.host) ?? defaultHost;
|
|
49338
50222
|
return {
|
|
49339
50223
|
settingsPath,
|
|
49340
|
-
publishableKey: Option.getOrUndefined(values.key),
|
|
49341
|
-
bootstrapBaseUrl,
|
|
49342
50224
|
environment: "staging",
|
|
49343
|
-
posthogHost,
|
|
49344
|
-
projectToken: Option.getOrUndefined(values.token),
|
|
50225
|
+
posthogHost: host === void 0 ? void 0 : yield* httpOrigin(host, "PostHog"),
|
|
50226
|
+
projectToken: Option.getOrUndefined(values.token) ?? defaultProjectToken,
|
|
49345
50227
|
forcedDisabled: values.disabled,
|
|
49346
50228
|
collectionEnabled: collectionPolicy(settingsPath, values.disabled)
|
|
49347
50229
|
};
|
|
49348
50230
|
});
|
|
50231
|
+
const loadConfig = Effect.gen(function* () {
|
|
50232
|
+
const observation = yield* loadObservationConfig;
|
|
50233
|
+
const values = yield* Config.all({
|
|
50234
|
+
key: Config.option(Config.redacted("CAPXUL_PUBLISHABLE_KEY")),
|
|
50235
|
+
bootstrap: Config.string("CAPXUL_BOOTSTRAP_URL").pipe(Config.withDefault("https://api.staging.capxul.com"))
|
|
50236
|
+
}).pipe(Effect.mapError(() => configurationFailure("CLI environment configuration is invalid.")));
|
|
50237
|
+
const bootstrapBaseUrl = yield* httpOrigin(values.bootstrap, "bootstrap");
|
|
50238
|
+
return {
|
|
50239
|
+
...observation,
|
|
50240
|
+
bootstrapBaseUrl,
|
|
50241
|
+
publishableKey: Option.getOrUndefined(values.key)
|
|
50242
|
+
};
|
|
50243
|
+
});
|
|
49349
50244
|
const collectionStatus = (config) => Effect.gen(function* () {
|
|
49350
50245
|
const stored = (yield* readSettings(config.settingsPath))?.collection.enabled ?? null;
|
|
49351
50246
|
const enabled = config.collectionEnabled();
|
|
@@ -49369,33 +50264,13 @@ const codes = [
|
|
|
49369
50264
|
];
|
|
49370
50265
|
const identifier = Schema.String.check(Schema.isPattern(/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/u));
|
|
49371
50266
|
const version = Schema.String.check(Schema.isPattern(/^[A-Za-z0-9][A-Za-z0-9._+-]{0,127}$/u));
|
|
49372
|
-
const outcomeSchema = Schema.Literals([
|
|
49373
|
-
"succeeded",
|
|
49374
|
-
"refused",
|
|
49375
|
-
"failed",
|
|
49376
|
-
"cancelled"
|
|
49377
|
-
]);
|
|
49378
50267
|
const completionSchema = Schema.Struct({
|
|
49379
|
-
|
|
49380
|
-
command: Schema.Literal("doctor"),
|
|
49381
|
-
invocation_id: identifier,
|
|
50268
|
+
...CliCommandCompletedTelemetryEventSchema.fields.props.fields,
|
|
49382
50269
|
correlation_id: identifier,
|
|
49383
50270
|
journey_id: identifier,
|
|
49384
|
-
|
|
49385
|
-
"development",
|
|
49386
|
-
"staging",
|
|
49387
|
-
"production",
|
|
49388
|
-
"local"
|
|
49389
|
-
]),
|
|
49390
|
-
producer: Schema.Literal("server"),
|
|
49391
|
-
cli_version: version,
|
|
49392
|
-
sdk_version: version,
|
|
49393
|
-
outcome: outcomeSchema,
|
|
49394
|
-
duration_ms: Schema.Number,
|
|
50271
|
+
posthogDistinctId: Schema.optional(identifier),
|
|
49395
50272
|
wait_duration_ms: Schema.Number,
|
|
49396
|
-
retry_count: Schema.Literal(0)
|
|
49397
|
-
output_mode: Schema.Literals(["human", "json"]),
|
|
49398
|
-
error_code: Schema.optional(Schema.Literals(codes))
|
|
50273
|
+
retry_count: Schema.Literal(0)
|
|
49399
50274
|
});
|
|
49400
50275
|
const CAPTURE_CAPACITY = 32;
|
|
49401
50276
|
const CAPTURE_BYTES = 8192;
|
|
@@ -49409,13 +50284,15 @@ const own = (value, key) => {
|
|
|
49409
50284
|
return;
|
|
49410
50285
|
}
|
|
49411
50286
|
};
|
|
49412
|
-
const inactiveHost = () => postHogObservability(null, {
|
|
50287
|
+
const inactiveHost = (budget) => postHogObservability(null, {
|
|
49413
50288
|
enabled: false,
|
|
49414
|
-
engineeringEnabled: false
|
|
50289
|
+
engineeringEnabled: false,
|
|
50290
|
+
engineeringDeliveryBudget: budget
|
|
49415
50291
|
});
|
|
49416
50292
|
/** One invocation owns its records, metric registry, callback queue, and total flush deadline. */
|
|
49417
50293
|
function observeInvocation(input, work) {
|
|
49418
50294
|
return Effect.suspend(() => {
|
|
50295
|
+
const deliveryBudget = makeCliEngineeringBudget();
|
|
49419
50296
|
const finalizers = [];
|
|
49420
50297
|
const onFinalize = (finalizer) => {
|
|
49421
50298
|
finalizers.push(finalizer);
|
|
@@ -49424,7 +50301,7 @@ function observeInvocation(input, work) {
|
|
|
49424
50301
|
concurrency: "unbounded",
|
|
49425
50302
|
discard: true
|
|
49426
50303
|
}));
|
|
49427
|
-
const inactiveWork = Effect.acquireUseRelease(Effect.void, () => Effect.suspend(() => work(inactiveHost(), onFinalize)), () => finalize.pipe(Effect.interruptible, Effect.timeoutOption("2 seconds"), Effect.asVoid));
|
|
50304
|
+
const inactiveWork = Effect.acquireUseRelease(Effect.void, () => Effect.suspend(() => work(inactiveHost(deliveryBudget), onFinalize)), () => finalize.pipe(Effect.interruptible, Effect.timeoutOption("2 seconds"), Effect.asVoid));
|
|
49428
50305
|
let disabled = false;
|
|
49429
50306
|
const enabled = () => {
|
|
49430
50307
|
if (disabled) return false;
|
|
@@ -49435,12 +50312,13 @@ function observeInvocation(input, work) {
|
|
|
49435
50312
|
}
|
|
49436
50313
|
return !disabled;
|
|
49437
50314
|
};
|
|
49438
|
-
if (input.host === void 0 || input.projectToken === void 0 || !enabled()) return inactiveWork;
|
|
50315
|
+
if (input.kind === "completion" || input.kind === "collection_control" || input.host === void 0 || input.projectToken === void 0 || !enabled()) return inactiveWork;
|
|
49439
50316
|
const host = input.host;
|
|
49440
50317
|
const token = Redacted.value(input.projectToken);
|
|
49441
50318
|
let engineering;
|
|
49442
50319
|
try {
|
|
49443
50320
|
Schema.decodeUnknownSync(identifier)(input.invocationId);
|
|
50321
|
+
if (input.anonymousIdentity !== void 0) Schema.decodeUnknownSync(identifier)(input.anonymousIdentity.id);
|
|
49444
50322
|
Schema.decodeUnknownSync(version)(input.cliVersion);
|
|
49445
50323
|
engineering = makeEngineeringTelemetryLayer({
|
|
49446
50324
|
host,
|
|
@@ -49449,6 +50327,7 @@ function observeInvocation(input, work) {
|
|
|
49449
50327
|
producer: "server",
|
|
49450
50328
|
sdkVersion: input.sdkVersion,
|
|
49451
50329
|
serviceName: "capxul-cli",
|
|
50330
|
+
deliveryBudget,
|
|
49452
50331
|
enabled,
|
|
49453
50332
|
shutdownTimeout: 0,
|
|
49454
50333
|
exportInterval: "1 hour"
|
|
@@ -49456,7 +50335,7 @@ function observeInvocation(input, work) {
|
|
|
49456
50335
|
} catch {
|
|
49457
50336
|
return inactiveWork;
|
|
49458
50337
|
}
|
|
49459
|
-
const layer = Layer.merge(engineering, FetchHttpClient.layer).pipe(Layer.provideMerge(Layer.succeed(
|
|
50338
|
+
const layer = Layer.merge(engineering, FetchHttpClient.layer).pipe(Layer.provideMerge(Layer.succeed(Logger.LogToStderr, true)));
|
|
49460
50339
|
return Effect.scoped(Effect.gen(function* () {
|
|
49461
50340
|
const built = yield* Effect.exit(Layer.build(layer));
|
|
49462
50341
|
if (Exit.isFailure(built)) return yield* inactiveWork;
|
|
@@ -49472,30 +50351,47 @@ function observeInvocation(input, work) {
|
|
|
49472
50351
|
producer: "server",
|
|
49473
50352
|
cli_version: input.cliVersion,
|
|
49474
50353
|
sdk_version: input.sdkVersion,
|
|
50354
|
+
schema_version: 1,
|
|
50355
|
+
command: input.command,
|
|
50356
|
+
capability: input.capability,
|
|
50357
|
+
invocation_kind: input.kind,
|
|
50358
|
+
release: input.cliVersion,
|
|
50359
|
+
platform: input.platform ?? "unknown",
|
|
50360
|
+
architecture: input.architecture ?? "unknown",
|
|
50361
|
+
ci: input.ci ?? false,
|
|
50362
|
+
tty: input.tty ?? false,
|
|
50363
|
+
output_mode: input.outputMode ?? "human",
|
|
50364
|
+
...input.anonymousIdentity === void 0 ? {} : {
|
|
50365
|
+
anonymous_id: input.anonymousIdentity.id,
|
|
50366
|
+
cli_identity_kind: "anonymous"
|
|
50367
|
+
},
|
|
49475
50368
|
invocation_id: input.invocationId,
|
|
49476
50369
|
correlation_id: input.invocationId,
|
|
49477
50370
|
journey_id: input.invocationId
|
|
49478
50371
|
};
|
|
49479
|
-
const capture = (event, properties) => {
|
|
50372
|
+
const capture = (event, properties, identity) => {
|
|
49480
50373
|
if (!enabled()) {
|
|
49481
50374
|
dropped += 1;
|
|
49482
50375
|
return;
|
|
49483
50376
|
}
|
|
50377
|
+
const occurredAt = identity?.observedAt ?? clock.currentTimeMillisUnsafe();
|
|
49484
50378
|
const record = sanitizePostHogBrowserEvent({
|
|
49485
50379
|
event,
|
|
49486
50380
|
properties: {
|
|
49487
50381
|
...properties,
|
|
49488
50382
|
...envelope,
|
|
50383
|
+
occurred_at: occurredAt,
|
|
49489
50384
|
...nativeContext
|
|
49490
50385
|
}
|
|
49491
50386
|
});
|
|
49492
50387
|
const body = JSON.stringify({
|
|
49493
50388
|
api_key: token,
|
|
49494
50389
|
...record,
|
|
49495
|
-
uuid: crypto.randomUUID(),
|
|
50390
|
+
uuid: identity?.eventId ?? crypto.randomUUID(),
|
|
50391
|
+
timestamp: new Date(occurredAt).toISOString(),
|
|
49496
50392
|
properties: {
|
|
49497
50393
|
...record.properties,
|
|
49498
|
-
distinct_id: input.invocationId,
|
|
50394
|
+
distinct_id: input.anonymousIdentity?.id ?? input.invocationId,
|
|
49499
50395
|
$process_person_profile: false
|
|
49500
50396
|
}
|
|
49501
50397
|
});
|
|
@@ -49528,9 +50424,40 @@ function observeInvocation(input, work) {
|
|
|
49528
50424
|
...envelope
|
|
49529
50425
|
}
|
|
49530
50426
|
});
|
|
49531
|
-
if (Option.isSome(decoded) && Queue.sizeUnsafe(queue) <
|
|
50427
|
+
if (Option.isSome(decoded) && Queue.sizeUnsafe(queue) < 29) capture(event, { ...decoded.value.props });
|
|
49532
50428
|
else dropped += 1;
|
|
49533
50429
|
} };
|
|
50430
|
+
const clientHttp = HttpClient.transform(yield* HttpClient.HttpClient, (response, request) => Effect.suspend(() => {
|
|
50431
|
+
if (enabled()) return response;
|
|
50432
|
+
dropped += 1;
|
|
50433
|
+
return Effect.succeed(HttpClientResponse.fromWeb(request, new Response(null)));
|
|
50434
|
+
})).pipe(HttpClient.filterStatusOk, HttpClient.retryTransient({
|
|
50435
|
+
times: 1,
|
|
50436
|
+
schedule: Schedule.spaced("100 millis")
|
|
50437
|
+
}));
|
|
50438
|
+
const flushCaptures = Effect.gen(function* () {
|
|
50439
|
+
const pending = yield* Queue.clear(queue);
|
|
50440
|
+
if (!enabled()) {
|
|
50441
|
+
dropped += pending.length;
|
|
50442
|
+
return;
|
|
50443
|
+
}
|
|
50444
|
+
pendingCaptures += pending.length;
|
|
50445
|
+
yield* Effect.forEach(pending, (item) => Effect.suspend(() => {
|
|
50446
|
+
if (!enabled()) {
|
|
50447
|
+
dropped += 1;
|
|
50448
|
+
return Effect.void;
|
|
50449
|
+
}
|
|
50450
|
+
return clientHttp.execute(HttpClientRequest.post(`${host.replace(/\/+$/, "")}/capture/`).pipe(HttpClientRequest.bodyText(item, "application/json"))).pipe(Effect.asVoid, Effect.catchCause(() => Effect.sync(() => {
|
|
50451
|
+
dropped += 1;
|
|
50452
|
+
})));
|
|
50453
|
+
}).pipe(Effect.ensuring(Effect.sync(() => {
|
|
50454
|
+
pendingCaptures -= 1;
|
|
50455
|
+
}))), {
|
|
50456
|
+
concurrency: 4,
|
|
50457
|
+
discard: true
|
|
50458
|
+
});
|
|
50459
|
+
}).pipe(Effect.withTracerEnabled(false), Effect.provideService(HttpClient.TracerPropagationEnabled, false));
|
|
50460
|
+
let startDelivery;
|
|
49534
50461
|
let commandResult;
|
|
49535
50462
|
yield* Effect.gen(function* () {
|
|
49536
50463
|
const span = yield* Effect.currentSpan.pipe(Effect.orDie);
|
|
@@ -49543,15 +50470,39 @@ function observeInvocation(input, work) {
|
|
|
49543
50470
|
enabled,
|
|
49544
50471
|
engineeringEnabled: enabled,
|
|
49545
50472
|
engineeringPrivacy: "minimal",
|
|
50473
|
+
engineeringDeliveryBudget: deliveryBudget,
|
|
49546
50474
|
capxulEnv: input.environment,
|
|
49547
50475
|
context: {
|
|
49548
50476
|
application: "capxul-cli",
|
|
50477
|
+
...input.anonymousIdentity === void 0 ? {} : { anonymousId: input.anonymousIdentity.id },
|
|
49549
50478
|
release: input.cliVersion,
|
|
49550
50479
|
correlationId: input.invocationId,
|
|
49551
50480
|
journeyId: input.invocationId,
|
|
49552
50481
|
traceparent
|
|
49553
50482
|
}
|
|
49554
50483
|
});
|
|
50484
|
+
const firstUse = input.anonymousIdentity?.firstUse;
|
|
50485
|
+
if (firstUse !== void 0) {
|
|
50486
|
+
const first = Schema.decodeUnknownSync(CliFirstUsedTelemetryEventSchema)({
|
|
50487
|
+
name: "cli_first_used",
|
|
50488
|
+
props: {
|
|
50489
|
+
...envelope,
|
|
50490
|
+
occurred_at: firstUse.observedAt
|
|
50491
|
+
}
|
|
50492
|
+
});
|
|
50493
|
+
capture("cli_first_used", { ...first.props }, firstUse);
|
|
50494
|
+
}
|
|
50495
|
+
if (input.kind !== "parse_refusal") {
|
|
50496
|
+
const start = Schema.decodeUnknownSync(CliCommandStartedTelemetryEventSchema)({
|
|
50497
|
+
name: "cli_command_started",
|
|
50498
|
+
props: {
|
|
50499
|
+
...envelope,
|
|
50500
|
+
occurred_at: clock.currentTimeMillisUnsafe()
|
|
50501
|
+
}
|
|
50502
|
+
});
|
|
50503
|
+
capture("cli_command_started", { ...start.props });
|
|
50504
|
+
startDelivery = yield* Effect.forkScoped(flushCaptures.pipe(Effect.interruptible), { startImmediately: true });
|
|
50505
|
+
}
|
|
49555
50506
|
const waitStarted = clock.currentTimeMillisUnsafe();
|
|
49556
50507
|
const result = yield* Effect.exit(restore(Effect.suspend(() => work(observation, onFinalize))));
|
|
49557
50508
|
commandResult = result;
|
|
@@ -49564,8 +50515,12 @@ function observeInvocation(input, work) {
|
|
|
49564
50515
|
const duration = Math.max(0, clock.currentTimeMillisUnsafe() - started);
|
|
49565
50516
|
const completion = Schema.decodeUnknownSync(completionSchema)({
|
|
49566
50517
|
...envelope,
|
|
50518
|
+
...input.anonymousIdentity === void 0 ? {} : { posthogDistinctId: input.anonymousIdentity.id },
|
|
50519
|
+
occurred_at: clock.currentTimeMillisUnsafe(),
|
|
49567
50520
|
schema_version: 1,
|
|
49568
50521
|
command: input.command,
|
|
50522
|
+
capability: input.capability,
|
|
50523
|
+
invocation_kind: input.kind,
|
|
49569
50524
|
outcome,
|
|
49570
50525
|
duration_ms: duration,
|
|
49571
50526
|
wait_duration_ms: waitDuration,
|
|
@@ -49574,13 +50529,15 @@ function observeInvocation(input, work) {
|
|
|
49574
50529
|
...errorCode === void 0 ? {} : { error_code: errorCode }
|
|
49575
50530
|
});
|
|
49576
50531
|
yield* Effect.annotateCurrentSpan(completion);
|
|
49577
|
-
yield*
|
|
50532
|
+
yield* logEngineeringInfo("cli.command.completed", completion);
|
|
49578
50533
|
for (const diagnostic of sdkDiagnostics) yield* Effect.logInfo("cli.sdk.operation.failed").pipe(Effect.annotateLogs({
|
|
49579
50534
|
...envelope,
|
|
49580
50535
|
...diagnostic
|
|
49581
50536
|
}));
|
|
49582
50537
|
const metricAttributes = {
|
|
49583
50538
|
command: input.command,
|
|
50539
|
+
capability: input.capability,
|
|
50540
|
+
invocation_kind: input.kind,
|
|
49584
50541
|
outcome,
|
|
49585
50542
|
capxul_env: input.environment
|
|
49586
50543
|
};
|
|
@@ -49600,15 +50557,27 @@ function observeInvocation(input, work) {
|
|
|
49600
50557
|
unit: "s"
|
|
49601
50558
|
}
|
|
49602
50559
|
}), duration / 1e3);
|
|
49603
|
-
const
|
|
49604
|
-
name: "
|
|
50560
|
+
const terminal = Schema.decodeUnknownSync(CliCommandCompletedTelemetryEventSchema)({
|
|
50561
|
+
name: "cli_command_completed",
|
|
49605
50562
|
props: {
|
|
49606
50563
|
...envelope,
|
|
49607
|
-
|
|
50564
|
+
occurred_at: clock.currentTimeMillisUnsafe(),
|
|
50565
|
+
outcome,
|
|
50566
|
+
duration_ms: duration,
|
|
50567
|
+
...errorCode === void 0 ? {} : { error_code: errorCode }
|
|
49608
50568
|
}
|
|
49609
|
-
};
|
|
49610
|
-
|
|
49611
|
-
|
|
50569
|
+
});
|
|
50570
|
+
capture("cli_command_completed", { ...terminal.props });
|
|
50571
|
+
if (input.command === "doctor" && input.kind === "command" && input.network) {
|
|
50572
|
+
const diagnostic = Schema.decodeUnknownSync(CliDiagnosticCompletedTelemetryEventSchema)({
|
|
50573
|
+
name: "cli_diagnostic_completed",
|
|
50574
|
+
props: {
|
|
50575
|
+
...envelope,
|
|
50576
|
+
outcome
|
|
50577
|
+
}
|
|
50578
|
+
});
|
|
50579
|
+
capture("cli_diagnostic_completed", { ...diagnostic.props });
|
|
50580
|
+
}
|
|
49612
50581
|
if (Exit.isFailure(result)) {
|
|
49613
50582
|
const defect = result.cause.reasons.find(Cause.isDieReason);
|
|
49614
50583
|
if (defect !== void 0) {
|
|
@@ -49619,7 +50588,7 @@ function observeInvocation(input, work) {
|
|
|
49619
50588
|
if (typeof stack === "string") error.stack = stack.slice(0, 8192);
|
|
49620
50589
|
} catch {}
|
|
49621
50590
|
yield* captureException({
|
|
49622
|
-
emit: (exception) => Effect.sync(() => capture("$exception", projectException(exception.props))),
|
|
50591
|
+
emit: (exception) => Effect.sync(() => capture("$exception", projectException(exception.props, input.command))),
|
|
49623
50592
|
identify: () => Effect.void,
|
|
49624
50593
|
group: () => Effect.void,
|
|
49625
50594
|
reset: () => Effect.void
|
|
@@ -49628,41 +50597,12 @@ function observeInvocation(input, work) {
|
|
|
49628
50597
|
}
|
|
49629
50598
|
}).pipe(Effect.catchCause(() => Effect.void));
|
|
49630
50599
|
if (Exit.isFailure(result)) return yield* Effect.fail("CLI command failed");
|
|
49631
|
-
}).pipe(Effect.withSpan(
|
|
49632
|
-
const clientHttp = HttpClient.transform(yield* HttpClient.HttpClient, (response, request) => Effect.suspend(() => {
|
|
49633
|
-
if (enabled()) return response;
|
|
49634
|
-
dropped += 1;
|
|
49635
|
-
return Effect.succeed(HttpClientResponse.fromWeb(request, new Response(null)));
|
|
49636
|
-
})).pipe(HttpClient.filterStatusOk, HttpClient.retryTransient({
|
|
49637
|
-
times: 1,
|
|
49638
|
-
schedule: Schedule.spaced("100 millis")
|
|
49639
|
-
}));
|
|
49640
|
-
const flushCaptures = Effect.gen(function* () {
|
|
49641
|
-
const pending = yield* Queue.clear(queue);
|
|
49642
|
-
if (!enabled()) {
|
|
49643
|
-
dropped += pending.length;
|
|
49644
|
-
return;
|
|
49645
|
-
}
|
|
49646
|
-
pendingCaptures = pending.length;
|
|
49647
|
-
yield* Effect.forEach(pending, (item) => Effect.suspend(() => {
|
|
49648
|
-
if (!enabled()) {
|
|
49649
|
-
dropped += 1;
|
|
49650
|
-
return Effect.void;
|
|
49651
|
-
}
|
|
49652
|
-
return clientHttp.execute(HttpClientRequest.post(`${host.replace(/\/+$/, "")}/capture/`).pipe(HttpClientRequest.bodyText(item, "application/json"))).pipe(Effect.asVoid, Effect.catchCause(() => Effect.sync(() => {
|
|
49653
|
-
dropped += 1;
|
|
49654
|
-
})));
|
|
49655
|
-
}).pipe(Effect.ensuring(Effect.sync(() => {
|
|
49656
|
-
pendingCaptures -= 1;
|
|
49657
|
-
}))), {
|
|
49658
|
-
concurrency: 4,
|
|
49659
|
-
discard: true
|
|
49660
|
-
});
|
|
49661
|
-
}).pipe(Effect.withTracerEnabled(false), Effect.provideService(HttpClient.TracerPropagationEnabled, false));
|
|
50600
|
+
}).pipe(Effect.withSpan(`cli.command.${input.command}`), Effect.exit);
|
|
49662
50601
|
yield* Effect.all([
|
|
49663
50602
|
finalize,
|
|
49664
50603
|
flushCaptures,
|
|
49665
|
-
flushEngineeringTelemetry
|
|
50604
|
+
flushEngineeringTelemetry,
|
|
50605
|
+
startDelivery === void 0 ? Effect.void : Fiber.join(startDelivery)
|
|
49666
50606
|
], {
|
|
49667
50607
|
concurrency: "unbounded",
|
|
49668
50608
|
discard: true
|
|
@@ -49672,6 +50612,7 @@ function observeInvocation(input, work) {
|
|
|
49672
50612
|
yield* Queue.shutdown(queue);
|
|
49673
50613
|
try {
|
|
49674
50614
|
input.onDropped?.(dropped);
|
|
50615
|
+
input.onEngineeringDropped?.(deliveryBudget.snapshot().dropped);
|
|
49675
50616
|
} catch {}
|
|
49676
50617
|
if (commandResult === void 0) return yield* Effect.die("CLI observation could not start");
|
|
49677
50618
|
return yield* commandResult;
|
|
@@ -49706,7 +50647,7 @@ function projectSdkProperties(properties) {
|
|
|
49706
50647
|
if (failureMode !== void 0) output.failure_mode = failureMode;
|
|
49707
50648
|
return output;
|
|
49708
50649
|
}
|
|
49709
|
-
function projectException(properties) {
|
|
50650
|
+
function projectException(properties, command) {
|
|
49710
50651
|
const sanitized = sanitizePostHogBrowserEvent({
|
|
49711
50652
|
event: "$exception",
|
|
49712
50653
|
properties: { ...properties }
|
|
@@ -49730,8 +50671,8 @@ function projectException(properties) {
|
|
|
49730
50671
|
$exception_type: "CLI_DEFECT",
|
|
49731
50672
|
$exception_message: "CLI command failed",
|
|
49732
50673
|
$exception_level: "error",
|
|
49733
|
-
$exception_fingerprint: `cli.
|
|
49734
|
-
$issue_name:
|
|
50674
|
+
$exception_fingerprint: `cli.${command}.CLI_DEFECT:${frames[0]?.filename ?? "boundary"}:${frames[0]?.function ?? "unknown"}`,
|
|
50675
|
+
$issue_name: `CLI ${command} defect`,
|
|
49735
50676
|
$exception_list: [{
|
|
49736
50677
|
type: "CLI_DEFECT",
|
|
49737
50678
|
value: "CLI command failed",
|
|
@@ -49757,41 +50698,101 @@ function renderResult(mode, envelope, lines = []) {
|
|
|
49757
50698
|
}
|
|
49758
50699
|
//#endregion
|
|
49759
50700
|
//#region src/version.ts
|
|
49760
|
-
const cliVersion = "4.20.0-beta.
|
|
49761
|
-
const sdkVersion = "4.20.0-beta.
|
|
50701
|
+
const cliVersion = "4.20.0-beta.4";
|
|
50702
|
+
const sdkVersion = "4.20.0-beta.4";
|
|
50703
|
+
//#endregion
|
|
50704
|
+
//#region src/runtime/command-metadata.ts
|
|
50705
|
+
var CliCommandMetadata = class extends Context.Service()("capxul-cli/CommandMetadata") {};
|
|
50706
|
+
const collectionControl = (name) => name === "telemetry" || name === "telemetry.status" || name === "telemetry.enable" || name === "telemetry.disable";
|
|
50707
|
+
function metadataAtPath(root, path) {
|
|
50708
|
+
let selected = root;
|
|
50709
|
+
for (const part of path.slice(1)) {
|
|
50710
|
+
const child = selected.subcommands.flatMap((group) => group.commands).find((command) => command.name === part || command.alias === part);
|
|
50711
|
+
if (child === void 0) break;
|
|
50712
|
+
selected = child;
|
|
50713
|
+
}
|
|
50714
|
+
const metadata = Context.getOption(selected.annotations, CliCommandMetadata);
|
|
50715
|
+
return Option.isSome(metadata) && CLI_COMMAND_NAMES.includes(metadata.value.name) ? metadata.value : {
|
|
50716
|
+
name: "unknown",
|
|
50717
|
+
capability: "cli",
|
|
50718
|
+
observation: "command"
|
|
50719
|
+
};
|
|
50720
|
+
}
|
|
49762
50721
|
//#endregion
|
|
49763
50722
|
//#region src/runtime/run-command.ts
|
|
49764
50723
|
var CliRuntime = class extends Context.Service()("capxul-cli/Runtime") {};
|
|
49765
|
-
const
|
|
49766
|
-
|
|
49767
|
-
const
|
|
49768
|
-
yield*
|
|
49769
|
-
|
|
49770
|
-
|
|
49771
|
-
|
|
49772
|
-
const
|
|
50724
|
+
const acquireInvocationIdentity = (config, eligible) => Effect.gen(function* () {
|
|
50725
|
+
if (!eligible || config?.posthogHost === void 0 || config.projectToken === void 0 || !config.collectionEnabled()) return void 0;
|
|
50726
|
+
const path = yield* Path.Path;
|
|
50727
|
+
const acquired = yield* acquireObservationIdentity(path.dirname(config.settingsPath));
|
|
50728
|
+
return acquired.status === "ready" ? acquired : void 0;
|
|
50729
|
+
}).pipe(Effect.catchCause(() => Effect.succeed(void 0)));
|
|
50730
|
+
const runInvocation = (runtime, metadata, kind, work, network = false) => Effect.gen(function* () {
|
|
50731
|
+
const current = yield* Ref.get(runtime.current);
|
|
50732
|
+
if (current !== null) return yield* work(current.host, current.onFinalize);
|
|
50733
|
+
const invocationKind = kind === "completion" ? kind : collectionControl(metadata.name) ? "collection_control" : kind;
|
|
50734
|
+
const silent = invocationKind === "completion" || invocationKind === "collection_control";
|
|
50735
|
+
const invocation = {
|
|
50736
|
+
command: metadata.name,
|
|
50737
|
+
invocationId: runtime.invocationId,
|
|
50738
|
+
kind
|
|
50739
|
+
};
|
|
50740
|
+
yield* Ref.set(runtime.current, invocation);
|
|
50741
|
+
const config = runtime.observation;
|
|
50742
|
+
const identity = yield* acquireInvocationIdentity(config, !silent);
|
|
49773
50743
|
let dropped = 0;
|
|
49774
|
-
|
|
49775
|
-
|
|
49776
|
-
|
|
50744
|
+
let engineeringDropped = 0;
|
|
50745
|
+
return yield* observeInvocation({
|
|
50746
|
+
command: metadata.name,
|
|
50747
|
+
capability: metadata.capability,
|
|
50748
|
+
kind: invocationKind,
|
|
50749
|
+
network,
|
|
50750
|
+
invocationId: runtime.invocationId,
|
|
50751
|
+
...identity === void 0 ? {} : { anonymousIdentity: {
|
|
50752
|
+
id: identity.epoch.id,
|
|
50753
|
+
...identity.firstUseClaimed ? { firstUse: identity.firstUse } : {}
|
|
50754
|
+
} },
|
|
49777
50755
|
cliVersion,
|
|
49778
50756
|
sdkVersion,
|
|
49779
|
-
environment: config
|
|
49780
|
-
|
|
49781
|
-
|
|
49782
|
-
|
|
50757
|
+
environment: config?.environment ?? "staging",
|
|
50758
|
+
platform: runtime.platform === "darwin" || runtime.platform === "linux" ? runtime.platform : "unknown",
|
|
50759
|
+
architecture: runtime.architecture === "arm64" || runtime.architecture === "x64" ? runtime.architecture : "unknown",
|
|
50760
|
+
ci: runtime.ci,
|
|
50761
|
+
tty: runtime.tty,
|
|
50762
|
+
...!silent && config?.posthogHost !== void 0 ? { host: config.posthogHost } : {},
|
|
50763
|
+
...!silent && config?.projectToken !== void 0 ? { projectToken: config.projectToken } : {},
|
|
50764
|
+
enabled: identity === void 0 ? () => false : config?.collectionEnabled ?? (() => false),
|
|
49783
50765
|
outputMode: runtime.mode,
|
|
49784
50766
|
onDropped: (count) => {
|
|
49785
50767
|
dropped = count;
|
|
50768
|
+
},
|
|
50769
|
+
onEngineeringDropped: (count) => {
|
|
50770
|
+
engineeringDropped = count;
|
|
49786
50771
|
}
|
|
49787
|
-
}, (
|
|
49788
|
-
|
|
49789
|
-
|
|
49790
|
-
|
|
49791
|
-
|
|
49792
|
-
|
|
49793
|
-
|
|
49794
|
-
}
|
|
50772
|
+
}, (host, onFinalize) => Effect.gen(function* () {
|
|
50773
|
+
yield* Ref.set(runtime.current, {
|
|
50774
|
+
...invocation,
|
|
50775
|
+
host,
|
|
50776
|
+
onFinalize
|
|
50777
|
+
});
|
|
50778
|
+
return yield* work(host, onFinalize);
|
|
50779
|
+
})).pipe(Effect.onExit(() => {
|
|
50780
|
+
const notice = (dropped > 0 ? `Telemetry dropped ${dropped} records.\n` : "") + (engineeringDropped > 0 ? `Engineering telemetry dropped ${engineeringDropped} items.\n` : "");
|
|
50781
|
+
return notice === "" ? Effect.void : writeStderr(notice).pipe(Effect.catchCause(() => Effect.void));
|
|
50782
|
+
}));
|
|
50783
|
+
});
|
|
50784
|
+
const runCommand = (options, work) => Effect.gen(function* () {
|
|
50785
|
+
const runtime = yield* CliRuntime;
|
|
50786
|
+
return yield* runInvocation(runtime, options, "command", (host, onFinalize) => Effect.gen(function* () {
|
|
50787
|
+
const result = yield* work(yield* loadConfig, host, onFinalize);
|
|
50788
|
+
yield* renderResult(runtime.mode, {
|
|
50789
|
+
version: 1,
|
|
50790
|
+
command: options.name,
|
|
50791
|
+
invocationId: runtime.invocationId,
|
|
50792
|
+
outcome: "succeeded",
|
|
50793
|
+
data: result.data
|
|
50794
|
+
}, result.lines);
|
|
50795
|
+
}), options.network);
|
|
49795
50796
|
});
|
|
49796
50797
|
//#endregion
|
|
49797
50798
|
//#region src/platform/capxul.ts
|
|
@@ -49875,42 +50876,63 @@ const checkDoctor = (config, options) => Effect.gen(function* () {
|
|
|
49875
50876
|
});
|
|
49876
50877
|
//#endregion
|
|
49877
50878
|
//#region src/commands/doctor.ts
|
|
50879
|
+
const metadata = {
|
|
50880
|
+
name: "doctor",
|
|
50881
|
+
capability: "diagnostics",
|
|
50882
|
+
observation: "command"
|
|
50883
|
+
};
|
|
49878
50884
|
const doctor = Command.make("doctor", {
|
|
49879
50885
|
online: Flag.boolean("online").pipe(Flag.withDefault(false), Flag.withDescription("Also check the backend through the public SDK")),
|
|
49880
50886
|
timeoutMs: Flag.integer("timeout-ms").pipe(Flag.filter((value) => value >= 1 && value <= 3e5, () => "Use --timeout-ms between 1 and 300000."), Flag.withDefault(3e4), Flag.withDescription("Online check deadline in milliseconds (1 to 300000)"))
|
|
49881
50887
|
}, ({ online, timeoutMs }) => runCommand({
|
|
49882
|
-
|
|
50888
|
+
...metadata,
|
|
49883
50889
|
network: online
|
|
49884
50890
|
}, (config, observation, onFinalize) => checkDoctor(config, {
|
|
49885
50891
|
online,
|
|
49886
50892
|
timeoutMs,
|
|
49887
50893
|
...observation === void 0 ? {} : { observation },
|
|
49888
50894
|
...onFinalize === void 0 ? {} : { onFinalize }
|
|
49889
|
-
}))).pipe(Command.withDescription("Check local configuration; --online also checks the backend"));
|
|
50895
|
+
}))).pipe(Command.annotate(CliCommandMetadata, metadata), Command.withDescription("Check local configuration; --online also checks the backend"));
|
|
49890
50896
|
//#endregion
|
|
49891
50897
|
//#region src/commands/telemetry.ts
|
|
50898
|
+
const statusMetadata = {
|
|
50899
|
+
name: "telemetry.status",
|
|
50900
|
+
capability: "collection",
|
|
50901
|
+
observation: "collection-control"
|
|
50902
|
+
};
|
|
50903
|
+
const enableMetadata = {
|
|
50904
|
+
...statusMetadata,
|
|
50905
|
+
name: "telemetry.enable"
|
|
50906
|
+
};
|
|
50907
|
+
const disableMetadata = {
|
|
50908
|
+
...statusMetadata,
|
|
50909
|
+
name: "telemetry.disable"
|
|
50910
|
+
};
|
|
49892
50911
|
const report = (config) => collectionStatus(config).pipe(Effect.map((status) => ({
|
|
49893
50912
|
data: status,
|
|
49894
50913
|
lines: [
|
|
49895
50914
|
`Remote CLI observation ${status.enabled ? "enabled" : "disabled"}.`,
|
|
49896
50915
|
...status.configured ? [] : ["Remote delivery is not configured."],
|
|
49897
50916
|
...config.forcedDisabled ? ["CAPXUL_TELEMETRY_DISABLED overrides the saved preference."] : [],
|
|
49898
|
-
"
|
|
50917
|
+
"Commands collect usage and diagnostics. Collection controls and completions send nothing."
|
|
49899
50918
|
]
|
|
49900
50919
|
})));
|
|
49901
50920
|
const status = Command.make("status", {}, () => runCommand({
|
|
49902
|
-
|
|
50921
|
+
...statusMetadata,
|
|
49903
50922
|
network: false
|
|
49904
|
-
}, report));
|
|
50923
|
+
}, report)).pipe(Command.annotate(CliCommandMetadata, statusMetadata));
|
|
49905
50924
|
const enable = Command.make("enable", {}, () => runCommand({
|
|
49906
|
-
|
|
50925
|
+
...enableMetadata,
|
|
49907
50926
|
network: false
|
|
49908
|
-
}, (config) => setCollectionEnabled(config.settingsPath, true).pipe(Effect.andThen(report(config)))));
|
|
50927
|
+
}, (config) => setCollectionEnabled(config.settingsPath, true).pipe(Effect.andThen(report(config))))).pipe(Command.annotate(CliCommandMetadata, enableMetadata));
|
|
49909
50928
|
const disable = Command.make("disable", {}, () => runCommand({
|
|
49910
|
-
|
|
50929
|
+
...disableMetadata,
|
|
49911
50930
|
network: false
|
|
49912
|
-
}, (config) => setCollectionEnabled(config.settingsPath, false).pipe(Effect.andThen(report(config)))));
|
|
49913
|
-
const telemetry = Command.make("telemetry").pipe(Command.
|
|
50931
|
+
}, (config) => setCollectionEnabled(config.settingsPath, false).pipe(Effect.andThen(report(config))))).pipe(Command.annotate(CliCommandMetadata, disableMetadata));
|
|
50932
|
+
const telemetry = Command.make("telemetry").pipe(Command.annotate(CliCommandMetadata, {
|
|
50933
|
+
...statusMetadata,
|
|
50934
|
+
name: "telemetry"
|
|
50935
|
+
}), Command.withDescription("Show or change this CLI's collection preference"), Command.withSubcommands([
|
|
49914
50936
|
status,
|
|
49915
50937
|
enable,
|
|
49916
50938
|
disable
|
|
@@ -49940,52 +50962,87 @@ const outputMode = (args) => Effect.gen(function* () {
|
|
|
49940
50962
|
});
|
|
49941
50963
|
//#endregion
|
|
49942
50964
|
//#region src/command.ts
|
|
49943
|
-
const command = Command.make("capxul").pipe(Command.
|
|
50965
|
+
const command = Command.make("capxul").pipe(Command.annotate(CliCommandMetadata, {
|
|
50966
|
+
name: "capxul",
|
|
50967
|
+
capability: "cli",
|
|
50968
|
+
observation: "command"
|
|
50969
|
+
}), Command.withDescription("Capxul diagnostics and configuration"), Command.withSubcommands([doctor, telemetry]), Command.withGlobalFlags([JsonOutput]));
|
|
49944
50970
|
//#endregion
|
|
49945
50971
|
//#region src/runtime/entry.ts
|
|
50972
|
+
const completionFailure = (error) => {
|
|
50973
|
+
if (!CliError.isCliError(error)) return false;
|
|
50974
|
+
if (error._tag === "ShowHelp") return error.errors.some(completionFailure);
|
|
50975
|
+
return (error._tag === "InvalidValue" || error._tag === "MissingOption" || error._tag === "DuplicateOption") && (error.option === "completions" || error.option === "--completions");
|
|
50976
|
+
};
|
|
49946
50977
|
const runCli = (platform) => Effect.uninterruptibleMask((restore) => Effect.gen(function* () {
|
|
49947
50978
|
const stdio = yield* Stdio.Stdio;
|
|
50979
|
+
const stateServices = yield* Effect.context().pipe(Effect.map(Context.pick(Crypto.Crypto, FileSystem.FileSystem, Path.Path)));
|
|
49948
50980
|
const args = yield* stdio.args;
|
|
49949
50981
|
const mode = yield* outputMode(args);
|
|
49950
50982
|
const interactive = yield* stdio.stdinIsTerminal;
|
|
49951
50983
|
const cliConfig = yield* CliConfig.CliConfig;
|
|
49952
50984
|
const current = yield* Ref.make(null);
|
|
50985
|
+
const invocationId = yield* (yield* Crypto.Crypto).randomUUIDv4;
|
|
50986
|
+
const observation = yield* loadObservationConfig.pipe(Effect.catch(() => Effect.succeed(void 0)));
|
|
50987
|
+
const ci = yield* Config.string("CI").pipe(Config.withDefault("false"), Effect.map((value) => value !== "" && value !== "false" && value !== "0"), Effect.catch(() => Effect.succeed(false)));
|
|
50988
|
+
const runtime = {
|
|
50989
|
+
mode,
|
|
50990
|
+
current,
|
|
50991
|
+
invocationId,
|
|
50992
|
+
observation,
|
|
50993
|
+
...platform,
|
|
50994
|
+
architecture: arch,
|
|
50995
|
+
ci,
|
|
50996
|
+
tty: interactive
|
|
50997
|
+
};
|
|
49953
50998
|
const nativeConsole = yield* Console.Console;
|
|
49954
50999
|
const output = [];
|
|
49955
51000
|
const capture = (...values) => {
|
|
49956
51001
|
output.push(values.map(String).join(" "));
|
|
49957
51002
|
};
|
|
51003
|
+
const flushNative = Effect.suspend(() => {
|
|
51004
|
+
if (output.length === 0) return Effect.void;
|
|
51005
|
+
const text = output.splice(0).join("\n");
|
|
51006
|
+
return mode === "json" ? renderResult(mode, {
|
|
51007
|
+
version: 1,
|
|
51008
|
+
command: "capxul",
|
|
51009
|
+
invocationId: null,
|
|
51010
|
+
outcome: "succeeded",
|
|
51011
|
+
data: { text }
|
|
51012
|
+
}) : writeStdout(`${text}\n`);
|
|
51013
|
+
});
|
|
51014
|
+
const decorate = (flag, kind) => GlobalFlag.action({
|
|
51015
|
+
flag: flag.flag,
|
|
51016
|
+
run: (value, context) => runInvocation(runtime, metadataAtPath(context.command, context.commandPath), kind, () => flag.run(value, context).pipe(Effect.andThen(flushNative))).pipe(Effect.provide(stateServices), Effect.provideService(Stdio.Stdio, stdio), Effect.orDie)
|
|
51017
|
+
});
|
|
51018
|
+
const builtIns = cliConfig.builtIns.filter((flag) => interactive && !ci && mode === "human" || flag !== GlobalFlag.Wizard).map((flag) => flag === GlobalFlag.Help ? decorate(GlobalFlag.Help, "help") : flag === GlobalFlag.Version ? decorate(GlobalFlag.Version, "version") : flag === GlobalFlag.Completions ? decorate(GlobalFlag.Completions, "completion") : flag);
|
|
49958
51019
|
const exit = yield* restore(Command.runWith(command, {
|
|
49959
51020
|
version: cliVersion,
|
|
49960
51021
|
renderErrors: false
|
|
49961
|
-
})(args).pipe(Effect.provideService(CliRuntime, {
|
|
49962
|
-
mode,
|
|
49963
|
-
current,
|
|
49964
|
-
...platform
|
|
49965
|
-
}), Effect.provideService(CliConfig.CliConfig, { builtIns: interactive && mode === "human" ? cliConfig.builtIns : cliConfig.builtIns.filter((flag) => flag !== GlobalFlag.Wizard) }), Effect.provideService(Console.Console, {
|
|
51022
|
+
})(args).pipe(Effect.provideService(CliRuntime, runtime), Effect.provideService(CliConfig.CliConfig, { builtIns }), Effect.provideService(Console.Console, {
|
|
49966
51023
|
...nativeConsole,
|
|
49967
51024
|
log: capture,
|
|
49968
51025
|
info: capture
|
|
49969
51026
|
}))).pipe(Effect.exit);
|
|
49970
51027
|
if (Exit.isSuccess(exit)) {
|
|
49971
|
-
if (output.length > 0)
|
|
49972
|
-
|
|
49973
|
-
version: 1,
|
|
49974
|
-
command: "capxul",
|
|
49975
|
-
invocationId: null,
|
|
49976
|
-
outcome: "succeeded",
|
|
49977
|
-
data: { text: output.join("\n") }
|
|
49978
|
-
});
|
|
49979
|
-
else yield* writeStdout(`${output.join("\n")}\n`);
|
|
49980
|
-
}
|
|
51028
|
+
if ((yield* Ref.get(current)) === null && output.length > 0) yield* runInvocation(runtime, metadataAtPath(command, [command.name]), "help", () => flushNative);
|
|
51029
|
+
else yield* flushNative;
|
|
49981
51030
|
return 0;
|
|
49982
51031
|
}
|
|
51032
|
+
const error = Cause.squash(exit.cause);
|
|
51033
|
+
if ((yield* Ref.get(current)) === null) {
|
|
51034
|
+
const path = CliError.isCliError(error) && error._tag === "ShowHelp" ? error.commandPath : [];
|
|
51035
|
+
if (path.length > 0) {
|
|
51036
|
+
const metadata = metadataAtPath(command, path);
|
|
51037
|
+
if (metadata.name !== "unknown") yield* runInvocation(runtime, metadata, completionFailure(error) ? "completion" : "parse_refusal", () => Effect.failCause(exit.cause)).pipe(Effect.exit);
|
|
51038
|
+
}
|
|
51039
|
+
}
|
|
49983
51040
|
const invocation = yield* Ref.get(current);
|
|
49984
51041
|
const failure = classifyFailure(exit.cause);
|
|
49985
51042
|
yield* renderResult(mode, {
|
|
49986
51043
|
version: 1,
|
|
49987
|
-
command: invocation?.command ?? parsedCommand(exit.cause),
|
|
49988
|
-
invocationId: invocation?.invocationId
|
|
51044
|
+
command: invocation?.kind === "parse_refusal" || invocation?.kind === "completion" || invocation?.kind === "collection_control" ? parsedCommand(exit.cause) : invocation?.command ?? parsedCommand(exit.cause),
|
|
51045
|
+
invocationId: invocation?.kind === "command" ? invocation.invocationId : null,
|
|
49989
51046
|
outcome: failure.outcome,
|
|
49990
51047
|
error: {
|
|
49991
51048
|
code: failure.code,
|