@getargvio/argvio 0.1.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { Histogram, Counter } from '@opentelemetry/api';
1
+ import { Tracer, Histogram, Counter } from '@opentelemetry/api';
2
2
  import { Logger } from '@opentelemetry/api-logs';
3
3
  import { LoggerProvider } from '@opentelemetry/sdk-logs';
4
4
  import { MeterProvider } from '@opentelemetry/sdk-metrics';
@@ -15,17 +15,20 @@ import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node';
15
15
  * allowed at the tier below it. Compare with plain `<`/`<=`/`>=` — the
16
16
  * numeric values are significant, not just distinct enum tags.
17
17
  *
18
- * TODO(schema): the wire string values in {@link tierToString} are
19
- * provisional pending the server-side allowlist file being confirmed.
20
- * They MUST match the `public` server's semantic allowlist exactly, or
21
- * the server will reject/strip the resource attribute.
18
+ * The wire string values in {@link tierToString} MUST match the
19
+ * consent_tiers names in the `public` server's allowlist
20
+ * (schema/allowlist/v1.yaml in getargvio/argvio) exactly, or the server
21
+ * rejects the record.
22
22
  */
23
23
  declare const Tier: {
24
- /** No persistent or cross-invocation identifiers; aggregate counts only. */
24
+ /**
25
+ * No persistent or cross-invocation identifiers: command name, exit
26
+ * code, duration, CLI version, OS/arch and CI environment only.
27
+ */
25
28
  readonly Anonymous: 0;
26
- /** Adds command path, flag names (not values), exit code, and latency. */
29
+ /** Adds an opaque per-process session ID, an opaque per-install ID, flag names (never values), and classified (not raw) error types. */
27
30
  readonly Basic: 1;
28
- /** Adds session correlation and classified (not raw) error signatures. */
31
+ /** Reserved: the server allowlist permits some fields here, but this SDK sends nothing beyond `Tier.Basic`. */
29
32
  readonly Full: 2;
30
33
  /**
31
34
  * The explicit opt-in tier: raw error detail (stack traces, messages)
@@ -77,6 +80,18 @@ declare const ErrorCategory: {
77
80
  };
78
81
  type ErrorCategory = (typeof ErrorCategory)[keyof typeof ErrorCategory];
79
82
  declare function isValidErrorCategory(value: string): value is ErrorCategory;
83
+ /**
84
+ * What a vendor's classifier returns for an error: the {@link ErrorCategory}
85
+ * plus, optionally, a fixed-vocabulary `reason` that says more precisely
86
+ * what failed (e.g. `"no-token"`, `"invalid-url"`). The reason must be an
87
+ * identifier chosen in code (`^[a-z0-9][a-z0-9._-]*$`, at most 64 bytes),
88
+ * never error text or anything derived from user input; one that doesn't
89
+ * match is dropped, not rewritten. Sent at `Tier.Basic`+.
90
+ */
91
+ interface ErrorClassification {
92
+ category: ErrorCategory;
93
+ reason?: string;
94
+ }
80
95
 
81
96
  /**
82
97
  * Resolves the consent tier that should be used for the current
@@ -186,6 +201,19 @@ interface ClientOptions {
186
201
  * build itself rather than any individual invocation.
187
202
  */
188
203
  resourceAttributes?: Record<string, string>;
204
+ /**
205
+ * Where the install ID (`cli.install_id`, `Tier.Basic`+) is persisted.
206
+ * Defaults to `argvio-install-id` in the same per-CLI config directory
207
+ * as `FileConsentProvider`'s consent file. `''` turns install IDs off.
208
+ */
209
+ installIdPath?: string;
210
+ /**
211
+ * How this CLI was installed (for example `'brew'`, `'npm'`, `'curl'` or
212
+ * `'binary'`), reported on the session start event at every consent tier.
213
+ * The SDK can't tell on its own, so the vendor supplies it, typically from
214
+ * a value stamped in at build time. Omit to send nothing.
215
+ */
216
+ installMethod?: string;
189
217
  }
190
218
 
191
219
  /** A snapshot of in-process telemetry-about-telemetry: never sent over the network. */
@@ -198,7 +226,32 @@ interface Stats {
198
226
  recoveredErrors: number;
199
227
  }
200
228
 
229
+ /** Options for {@link Client.recordCounter}. */
230
+ interface CounterOptions {
231
+ /**
232
+ * Splits the counter into series (e.g. a tool or HTTP verb). A fixed
233
+ * identifier chosen in code, subject to the same rules as the counter name.
234
+ */
235
+ label?: string;
236
+ }
237
+ /** One completed command, for {@link Client.recordCommand}. */
238
+ interface CommandResult {
239
+ /** The full command path, as for {@link Client.recordCommandInvocation}. */
240
+ path: string;
241
+ /** Names (never values) of the flags the user set. Only sent at `Tier.Basic`+. */
242
+ flagNames?: readonly string[];
243
+ /** When the command began, in epoch milliseconds. Defaults to `durationMs` before now. */
244
+ startMs?: number;
245
+ /** How long the command ran, in milliseconds. */
246
+ durationMs: number;
247
+ /** The command's exit code; non-zero counts as an error. */
248
+ exitCode: number;
249
+ }
201
250
  interface ClientParams {
251
+ cliName?: string;
252
+ installIdPath?: string | undefined;
253
+ installMethod?: string | undefined;
254
+ tracer?: Tracer;
202
255
  disabled: boolean;
203
256
  initError: Error | null;
204
257
  tier: Tier;
@@ -210,8 +263,8 @@ interface ClientParams {
210
263
  logger?: Logger;
211
264
  latencyHist?: Histogram;
212
265
  invocationsCounter?: Counter;
213
- sessionsCounter?: Counter;
214
266
  errorEventsCounter?: Counter;
267
+ productCounter?: Counter;
215
268
  }
216
269
  /**
217
270
  * The entry point for emitting telemetry. Every method is safe to call
@@ -232,14 +285,21 @@ declare class Client {
232
285
  private shuttingDown;
233
286
  private shutdownStarted;
234
287
  private sessionId;
288
+ private sessionStarted;
289
+ private readonly cliName;
290
+ private readonly installIdPath;
291
+ private readonly installMethod;
292
+ private installId;
293
+ private readonly activatedFeatures;
294
+ private readonly tracer;
235
295
  private readonly tracerProvider;
236
296
  private readonly meterProvider;
237
297
  private readonly loggerProvider;
238
298
  private readonly logger;
239
299
  private readonly latencyHist;
240
300
  private readonly invocationsCounter;
241
- private readonly sessionsCounter;
242
301
  private readonly errorEventsCounter;
302
+ private readonly productCounter;
243
303
  /** @internal use {@link createClient} */
244
304
  constructor(params: ClientParams);
245
305
  private enabled;
@@ -248,46 +308,83 @@ declare class Client {
248
308
  private gate;
249
309
  private tierAttr;
250
310
  private emitEvent;
311
+ private emitEventNow;
312
+ private name;
251
313
  /**
252
- * Lazily generates a session correlation ID at `Tier.Full`+. A random,
314
+ * Lazily generates a session correlation ID at `Tier.Basic`+. A random,
253
315
  * non-persistent identifier scoped to a single process invocation —
254
316
  * not a user or device identifier.
255
317
  */
256
318
  private ensureSessionId;
257
319
  /**
258
- * Records the start of a CLI process session. Call once, as early as
259
- * possible. At `Tier.Anonymous` this only increments an aggregate
260
- * session counter. At `Tier.Basic`+ it also emits a `cli.session_start`
261
- * event. At `Tier.Full`+ the event carries a per-process session
262
- * correlation ID.
320
+ * The session and install ID attributes for a record, empty below
321
+ * `Tier.Basic`. May read or create the install ID file, so call it from
322
+ * inside a queued job rather than on the caller's stack.
323
+ */
324
+ private identityAttrs;
325
+ /**
326
+ * Records the start of a CLI process session, which is what the server
327
+ * counts sessions, active installs and retention from. Call it as early
328
+ * as possible (the yargs/commander integrations do it for you); only the
329
+ * first call per Client emits anything.
330
+ *
331
+ * At `Tier.Anonymous` the event carries no identifiers. At `Tier.Basic`+
332
+ * it also carries the per-process session ID and the install ID, a
333
+ * random UUID persisted in the CLI's config directory the first time it
334
+ * is needed — never derived from the user or machine.
335
+ *
336
+ * At `Tier.Basic`+ it also carries startup overhead
337
+ * (`cli.startup.duration_ms`): the time from process start to this call,
338
+ * so it covers module loading and framework setup. Call it just before
339
+ * the command runs, as the integrations do. And when running as a Node
340
+ * single executable application, it carries the binary's size
341
+ * (`cli.binary.size_bytes`). Either is omitted if unavailable, never 0.
263
342
  */
264
343
  recordSessionStart(): void;
265
- /** Records the end of a CLI process session. Call once, symmetric with {@link recordSessionStart}. */
266
- recordSessionEnd(): void;
267
344
  /**
268
345
  * Records that a command began executing. `commandPath` should be the
269
- * full command path (e.g. `"mycli sub subsub"`), not just the leaf
270
- * command name. `flagNames` is the list of flag *names* the user set —
271
- * never flag values, which this SDK never accepts anywhere in the
272
- * taxonomy.
346
+ * full command path (e.g. `"mycli sub subsub"`); it is reported as the
347
+ * dotted command name (`"sub.subsub"`). `flagNames` is the list of flag
348
+ * *names* the user set — never flag values, which this SDK never
349
+ * accepts anywhere in the taxonomy.
273
350
  *
274
- * At `Tier.Anonymous` this only increments an aggregate invocation
275
- * counter with no path/flag detail. At `Tier.Basic`+ the full command
276
- * path and flag names are included.
351
+ * The command name is recorded at every tier; flag names and the
352
+ * session ID at `Tier.Basic`+.
277
353
  */
278
354
  recordCommandInvocation(commandPath: string, flagNames?: readonly string[]): void;
279
355
  /**
280
- * Records the exit code a command finished with. Pass `""` for
281
- * `commandPath` if unknown (e.g. a single-command CLI). At
282
- * `Tier.Anonymous` the exit code is recorded without a command path.
283
- * At `Tier.Basic`+ the command path is included.
356
+ * Records a completed command: a `cli.command.<name>` span covering its
357
+ * execution, plus the `cli.command.invocations` and
358
+ * `cli.command.duration` metrics. This is what the server's command
359
+ * frequency, latency, error-rate and exit-code dashboards are built
360
+ * from, so call it once for every command that ran (the integrations
361
+ * do). Available at every tier; flag names, peak memory and CPU time
362
+ * only at `Tier.Basic`+.
363
+ *
364
+ * Peak memory (`cli.process.peak_rss_bytes`) and CPU time
365
+ * (`cli.process.cpu_time_ms`) are read once from the process, so they are
366
+ * process-wide and cumulative: right for a CLI that runs one command per
367
+ * process, but in a long-lived or multi-command process each call
368
+ * reports totals since the process started. A measure the platform can't
369
+ * provide is omitted.
284
370
  */
285
- recordExitCode(commandPath: string, code: number): void;
371
+ recordCommand(result: CommandResult): void;
286
372
  /**
287
- * Records how long a command took to execute, in milliseconds, on a
288
- * histogram (`cli.command.duration`). Available at every tier.
373
+ * Records that the user used one of the vendor's features, so the server
374
+ * can tell which features an install has adopted and how soon after
375
+ * installing. Emitted at `Tier.Basic`+ only; nothing is sent at
376
+ * `Tier.Anonymous`. The event carries the feature name, the command name
377
+ * when `commandPath` is given, and the session and install IDs.
378
+ *
379
+ * `feature` must be a fixed identifier chosen by the vendor in code
380
+ * (e.g. `"export-csv"`), **never user input** such as a flag value, path
381
+ * or argument. It is truncated to the server's 64 character limit.
382
+ *
383
+ * Each feature is reported at most once per process, however often this
384
+ * is called, to keep volume down. The server derives "first use" per
385
+ * install itself, so repeat reports within a run add nothing.
289
386
  */
290
- recordLatency(commandPath: string, durationMs: number): void;
387
+ recordFeatureActivated(feature: string, commandPath?: string): void;
291
388
  /** Records that a command's help output was requested (`-h`/`--help` or an explicit help command). */
292
389
  recordHelpFlagUsage(commandPath: string): void;
293
390
  /**
@@ -296,10 +393,43 @@ declare class Client {
296
393
  * deliberately the only error-recording capability available below
297
394
  * `Tier.OptIn`. Raw error detail is only reachable via {@link optIn}.
298
395
  *
299
- * Requires `Tier.Full`+; at lower tiers this is a no-op (counted in
300
- * `stats().belowTierDropped`).
396
+ * At every tier this counts the error on the `cli.errors` metric by
397
+ * command. At `Tier.Basic`+ the category is attached as the error type
398
+ * and a `cli.error.raised` event is emitted too, tied to the session and
399
+ * install.
400
+ *
401
+ * `reason` is an optional, finer classification from a fixed vocabulary
402
+ * you define (e.g. `"no-token"`, `"invalid-url"`), sent at `Tier.Basic`+
403
+ * as `cli.error.reason` on both of those. It must be an identifier chosen
404
+ * in code, **never error text or user input**: this SDK does not scrub it.
405
+ * It must match `^[a-z0-9][a-z0-9._-]*$` and be at most 64 bytes; one that
406
+ * doesn't is dropped (the error is still recorded, without a reason).
301
407
  */
302
- recordError(commandPath: string, category?: ErrorCategory): void;
408
+ recordError(commandPath: string, category?: ErrorCategory, reason?: string): void;
409
+ /**
410
+ * Adds `n` to a vendor-defined counter, sent as the `cli.counter` metric
411
+ * with the `cli.counter.name` and, if given, `cli.counter.label`
412
+ * attributes. Increments are summed in memory: one data point per name
413
+ * and label is sent at each export, however often this is called, so it
414
+ * is cheap in a hot loop.
415
+ *
416
+ * **Counters are accepted at the anonymous tier.** They are sent at every
417
+ * tier, including `Tier.Anonymous` and in CI, even when the user has made
418
+ * no consent choice. Nothing identifies the user, but `name` and `label`
419
+ * are strings you choose, so a mistake here puts text into anonymous
420
+ * data. They must be fixed identifiers chosen in code, **never user
421
+ * input, file paths, host names, URLs, tokens or anything derived from
422
+ * them**. This SDK does not scrub them.
423
+ *
424
+ * `name` and `label` must match `^[a-z0-9][a-z0-9._-]*$` and be at most
425
+ * 64 bytes. If either does not, nothing is recorded: the increment is
426
+ * dropped, not trimmed or sent without its label. `n` must be a positive
427
+ * integer; anything else is ignored. The server caps the number of
428
+ * distinct names and labels per tenant and folds the rest into `other`.
429
+ *
430
+ * Never throws, and does nothing on a disabled Client.
431
+ */
432
+ recordCounter(name: string, n: number, options?: CounterOptions): void;
303
433
  /**
304
434
  * Returns an {@link OptInScope} if, and only if, this Client's resolved
305
435
  * consent tier is `Tier.OptIn`; otherwise returns `undefined`. There is
@@ -359,6 +489,11 @@ declare function createClient(apiKey: string, cliName: string, cliVersion: strin
359
489
 
360
490
  /** Reports whether the current process appears to be running inside a CI system. */
361
491
  declare function isCI(): boolean;
492
+ /**
493
+ * Returns which CI provider the process runs in, `'unknown'` for an
494
+ * unrecognized CI system, or `undefined` outside CI.
495
+ */
496
+ declare function detectCIProvider(): string | undefined;
362
497
  /**
363
498
  * Reports whether the `DO_NOT_TRACK` environment variable
364
499
  * (https://do-not-track.dev) requests telemetry be disabled. Any value
@@ -435,20 +570,86 @@ declare class FileConsentProvider implements ConsentProvider {
435
570
  * can assert on them without relying on string literals staying in
436
571
  * sync.
437
572
  *
438
- * TODO(schema): these keys are provisional and must be checked against
439
- * the authoritative server-side allowlist before v0.1.0 ships.
573
+ * Every event, span, metric and attribute name in this file is taken from
574
+ * the `public` server's allowlist (schema/allowlist/v1.yaml in
575
+ * getargvio/argvio), which rejects anything else. Change them only
576
+ * together with a server-side schema version.
440
577
  */
441
- declare const AttrCommandPath = "cli.command.path";
442
- declare const AttrCommandFlags = "cli.command.flags";
578
+ declare const AttrCommandName = "cli.command.name";
443
579
  declare const AttrExitCode = "cli.command.exit_code";
444
- declare const AttrHelpUsed = "cli.command.help_used";
445
- declare const AttrSessionId = "cli.session.id";
446
- declare const AttrErrorCategory = "cli.error.category";
447
- /** TierOptIn only. */
580
+ declare const AttrDurationMs = "cli.command.duration_ms";
581
+ /** `Tier.Basic`+. Peak resident set size of the process, in bytes. */
582
+ declare const AttrPeakRssBytes = "cli.process.peak_rss_bytes";
583
+ /** `Tier.Basic`+. User plus system CPU time of the process, in milliseconds. */
584
+ declare const AttrCpuTimeMs = "cli.process.cpu_time_ms";
585
+ /**
586
+ * `Tier.Basic`+. Size of the CLI's binary, in bytes. Only on
587
+ * `cli.session.started`, and only for a Node single executable application.
588
+ */
589
+ declare const AttrBinarySizeBytes = "cli.binary.size_bytes";
590
+ /**
591
+ * `Tier.Basic`+. Time from process start to the point the command begins
592
+ * running, in milliseconds. Only on `cli.session.started`.
593
+ */
594
+ declare const AttrStartupDurationMs = "cli.startup.duration_ms";
595
+ /** `Tier.Basic`+. */
596
+ declare const AttrFlagNames = "cli.flag.names";
597
+ /** `Tier.Basic`+. */
598
+ declare const AttrSessionId = "cli.session_id";
599
+ /** `Tier.Basic`+. */
600
+ declare const AttrInstallId = "cli.install_id";
601
+ declare const AttrHelpFlag = "cli.help.flag";
602
+ /** How the CLI was installed; supplied by the vendor via the `installMethod` option. */
603
+ declare const AttrInstallMethod = "cli.install.method";
604
+ /** `Tier.Basic`+. A fixed feature identifier supplied by the vendor. */
605
+ declare const AttrActivationFeature = "cli.activation.feature";
606
+ /** `Tier.Basic`+. */
607
+ declare const AttrErrorType = "cli.error.type";
608
+ /**
609
+ * `Tier.Basic`+. A vendor-assigned reason from a fixed vocabulary, alongside
610
+ * the error type. Never error text.
611
+ */
612
+ declare const AttrErrorReason = "cli.error.reason";
613
+ /** `Tier.OptIn` only. */
448
614
  declare const AttrErrorMessage = "cli.error.message";
449
- /** TierOptIn only. */
450
- declare const AttrErrorStack = "cli.error.stack";
451
- /** The name of the histogram instrument `recordLatency` records to (unit: milliseconds). */
615
+ /** `Tier.OptIn` only. */
616
+ declare const AttrErrorStack = "cli.error.stacktrace";
617
+ /**
618
+ * Every tier. The name of a vendor-defined counter, a fixed identifier
619
+ * chosen in code. Sent on `cli.counter`.
620
+ */
621
+ declare const AttrCounterName = "cli.counter.name";
622
+ /**
623
+ * Every tier. An optional fixed identifier that splits one counter into
624
+ * series, chosen in code. Sent on `cli.counter`.
625
+ */
626
+ declare const AttrCounterLabel = "cli.counter.label";
627
+ /** Log event names. */
628
+ declare const EventSessionStarted = "cli.session.started";
629
+ declare const EventCommandInvoked = "cli.command.invoked";
630
+ declare const EventCommandCompleted = "cli.command.completed";
631
+ declare const EventFeatureActivated = "cli.feature.activated";
632
+ declare const EventHelpViewed = "cli.help.viewed";
633
+ declare const EventErrorRaised = "cli.error.raised";
634
+ /**
635
+ * Prefixes the name of the span `recordCommand` emits for each command
636
+ * (e.g. `cli.command.deploy.push`). The server's command dashboards
637
+ * (frequency, latency, error rate, exit codes) are built from these spans.
638
+ */
639
+ declare const SpanCommandPrefix = "cli.command.";
640
+ /** Metric instrument names. */
641
+ declare const MetricCommandInvocations = "cli.command.invocations";
642
+ /** Unit: milliseconds. */
452
643
  declare const MetricCommandDuration = "cli.command.duration";
644
+ declare const MetricErrors = "cli.errors";
645
+ /** Unit: 1. A vendor-defined counter, see {@link Client.recordCounter}. */
646
+ declare const MetricCounter = "cli.counter";
647
+
648
+ /** Resource attribute keys describing the CLI build and host, promoted by the server into filterable columns. */
649
+ declare const ResourceAttrCLIVersion = "cli.version";
650
+ declare const ResourceAttrOS = "cli.os";
651
+ declare const ResourceAttrArch = "cli.arch";
652
+ declare const ResourceAttrIsCI = "cli.is_ci";
653
+ declare const ResourceAttrCIProvider = "cli.ci_provider";
453
654
 
454
- export { AttrCommandFlags, AttrCommandPath, AttrErrorCategory, AttrErrorMessage, AttrErrorStack, AttrExitCode, AttrHelpUsed, AttrSessionId, Client, type ClientOptions, type ConsentProvider, DEFAULT_AUTH_HEADER, DEFAULT_ENDPOINT_GRPC, DEFAULT_ENDPOINT_HTTP, DEFAULT_EXPORT_TIMEOUT_MS, DEFAULT_QUEUE_SIZE, DEFAULT_SHUTDOWN_TIMEOUT_MS, DisabledProvider, EnvConsentProvider, ErrorCategory, FileConsentProvider, type FileConsentProviderOptions, MetricCommandDuration, OptInScope, RESOURCE_ATTR_TIER, StaticProvider, type Stats, Tier, type Transport, chainProviders, clampTier, createClient, isCI, isDoNotTrackRequested, isValidErrorCategory, isValidTier, parseTier, tierAllows, tierToString };
655
+ export { AttrActivationFeature, AttrBinarySizeBytes, AttrCommandName, AttrCounterLabel, AttrCounterName, AttrCpuTimeMs, AttrDurationMs, AttrErrorMessage, AttrErrorReason, AttrErrorStack, AttrErrorType, AttrExitCode, AttrFlagNames, AttrHelpFlag, AttrInstallId, AttrInstallMethod, AttrPeakRssBytes, AttrSessionId, AttrStartupDurationMs, Client, type ClientOptions, type CommandResult, type ConsentProvider, type CounterOptions, DEFAULT_AUTH_HEADER, DEFAULT_ENDPOINT_GRPC, DEFAULT_ENDPOINT_HTTP, DEFAULT_EXPORT_TIMEOUT_MS, DEFAULT_QUEUE_SIZE, DEFAULT_SHUTDOWN_TIMEOUT_MS, DisabledProvider, EnvConsentProvider, ErrorCategory, type ErrorClassification, EventCommandCompleted, EventCommandInvoked, EventErrorRaised, EventFeatureActivated, EventHelpViewed, EventSessionStarted, FileConsentProvider, type FileConsentProviderOptions, MetricCommandDuration, MetricCommandInvocations, MetricCounter, MetricErrors, OptInScope, RESOURCE_ATTR_TIER, ResourceAttrArch, ResourceAttrCIProvider, ResourceAttrCLIVersion, ResourceAttrIsCI, ResourceAttrOS, SpanCommandPrefix, StaticProvider, type Stats, Tier, type Transport, chainProviders, clampTier, createClient, detectCIProvider, isCI, isDoNotTrackRequested, isValidErrorCategory, isValidTier, parseTier, tierAllows, tierToString };