@suss/ir-core 0.7.2 → 0.9.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.cjs CHANGED
@@ -30,6 +30,7 @@ __export(index_exports, {
30
30
  GraphqlOperationSemanticsSchema: () => GraphqlOperationSemanticsSchema,
31
31
  GraphqlResolverSemanticsSchema: () => GraphqlResolverSemanticsSchema,
32
32
  MessageBusSemanticsSchema: () => MessageBusSemanticsSchema,
33
+ MetricSemanticsSchema: () => MetricSemanticsSchema,
33
34
  RestSemanticsSchema: () => RestSemanticsSchema,
34
35
  RuntimeConfigSemanticsSchema: () => RuntimeConfigSemanticsSchema,
35
36
  SemanticsSchema: () => SemanticsSchema,
@@ -53,6 +54,7 @@ __export(index_exports, {
53
54
  ecsContainerInstanceName: () => ecsContainerInstanceName,
54
55
  exchangesHttpResponses: () => exchangesHttpResponses,
55
56
  fileInCodeScope: () => fileInCodeScope,
57
+ fixedTextLength: () => fixedTextLength,
56
58
  fnIdentityKey: () => fnIdentityKey,
57
59
  formatChannel: () => formatChannel,
58
60
  functionCallBinding: () => functionCallBinding,
@@ -63,6 +65,8 @@ __export(index_exports, {
63
65
  isGraphqlOperationBinding: () => isGraphqlOperationBinding,
64
66
  messageBusBinding: () => messageBusBinding,
65
67
  methodsAgree: () => methodsAgree,
68
+ metricBinding: () => metricBinding,
69
+ metricIdentityKey: () => metricIdentityKey,
66
70
  namePatternFromSub: () => namePatternFromSub,
67
71
  namePatternKey: () => namePatternKey,
68
72
  namesAgree: () => namesAgree,
@@ -78,6 +82,7 @@ __export(index_exports, {
78
82
  ruleBoundaryMatchesKey: () => ruleBoundaryMatchesKey,
79
83
  runtimeConfigBinding: () => runtimeConfigBinding,
80
84
  semanticsAgree: () => semanticsAgree,
85
+ semconvAttributes: () => semconvAttributes,
81
86
  servesRequest: () => servesRequest,
82
87
  storageBinding: () => storageBinding,
83
88
  typeDefinitionKey: () => typeDefinitionKey,
@@ -104,6 +109,10 @@ var GraphqlOperationSemanticsSchema = import_zod.z.object({
104
109
  var graphqlOperationSemantics = defineBoundarySemantics({
105
110
  name: "graphql-operation",
106
111
  schema: GraphqlOperationSemanticsSchema,
112
+ semconv: {
113
+ operationName: { name: "graphql.operation.name" },
114
+ operationType: { name: "graphql.operation.type" }
115
+ },
107
116
  behavior: {
108
117
  /**
109
118
  * An operation gets a data-and-errors document back, which the
@@ -131,12 +140,15 @@ function fnIdentityKey(packageName, exportPath) {
131
140
  function busIdentityKey(messageBus, subject) {
132
141
  return `bus:${messageBus} ${subject}`;
133
142
  }
143
+ function metricIdentityKey(metricSystem, metricType) {
144
+ return `metric:${metricSystem} ${metricType}`;
145
+ }
134
146
 
135
147
  // src/schemas.ts
136
- var import_zod10 = require("zod");
148
+ var import_zod11 = require("zod");
137
149
 
138
150
  // src/semantics/registry.ts
139
- var import_zod9 = require("zod");
151
+ var import_zod10 = require("zod");
140
152
 
141
153
  // src/semantics/functionCall.ts
142
154
  var import_zod2 = require("zod");
@@ -174,6 +186,9 @@ var FunctionCallSemanticsSchema = import_zod2.z.object({
174
186
  var functionCallSemantics = defineBoundarySemantics({
175
187
  name: "function-call",
176
188
  schema: FunctionCallSemanticsSchema,
189
+ // A call that never leaves the process does not produce a span, and
190
+ // the conventions do not name one. All of it is ours.
191
+ semconv: {},
177
192
  behavior: {
178
193
  /** A call returns a value, which is not a status and a body. */
179
194
  exchangesHttpResponses: false,
@@ -214,6 +229,9 @@ var GraphqlResolverSemanticsSchema = import_zod3.z.object({
214
229
  var graphqlResolverSemantics = defineBoundarySemantics({
215
230
  name: "graphql-resolver",
216
231
  schema: GraphqlResolverSemanticsSchema,
232
+ // The conventions name the operation a client sent, not the
233
+ // resolver the server ran for one field of it.
234
+ semconv: {},
217
235
  behavior: {
218
236
  /** A resolver returns a field value, not a status and a body. */
219
237
  exchangesHttpResponses: false,
@@ -262,13 +280,19 @@ function channelsPair(a, b) {
262
280
  var MessageBusSemanticsSchema = import_zod4.z.object({
263
281
  name: import_zod4.z.literal("message-bus"),
264
282
  messageBus: import_zod4.z.enum([
265
- "sqs",
266
- "sns",
283
+ // The conventions spell the two AWS buses this way, one with an
284
+ // underscore and one with a dot, so these are their strings and
285
+ // not a typo.
286
+ "aws_sqs",
287
+ "aws.sns",
267
288
  "s3",
268
289
  "eventbridge",
269
290
  "bullmq",
270
291
  "kafka",
271
- "nats"
292
+ "nats",
293
+ "cloudflare-queues",
294
+ "cloudflare-cron",
295
+ "cloudflare-tail"
272
296
  ]),
273
297
  /**
274
298
  * Stable channel identifier: a CFN logical id, a queue or topic name,
@@ -281,6 +305,10 @@ var MessageBusSemanticsSchema = import_zod4.z.object({
281
305
  var messageBusSemantics = defineBoundarySemantics({
282
306
  name: "message-bus",
283
307
  schema: MessageBusSemanticsSchema,
308
+ semconv: {
309
+ messageBus: { name: "messaging.system" },
310
+ channel: { name: "messaging.destination.name" }
311
+ },
284
312
  behavior: {
285
313
  /** A message goes onto the channel and nothing comes back. */
286
314
  exchangesHttpResponses: false,
@@ -339,25 +367,58 @@ var messageBusSemantics = defineBoundarySemantics({
339
367
  }
340
368
  });
341
369
 
342
- // src/semantics/rest.ts
370
+ // src/semantics/metric.ts
343
371
  var import_zod5 = require("zod");
344
- var RestSemanticsSchema = import_zod5.z.object({
345
- name: import_zod5.z.literal("rest"),
372
+ var MetricSemanticsSchema = import_zod5.z.object({
373
+ name: import_zod5.z.literal("metric"),
374
+ /** Which system the series lives in: cloud-monitoring, cloudwatch. */
375
+ metricSystem: import_zod5.z.string(),
376
+ /**
377
+ * The type string the system knows the metric by, spelled the way
378
+ * both sides spell it. Null when the source states one this reader
379
+ * could not settle, as with a query it could not read: a metric
380
+ * nobody could name pairs with nothing rather than with whatever
381
+ * happens to share its source text.
382
+ */
383
+ metricType: import_zod5.z.string().nullable()
384
+ });
385
+ var metricSemantics = defineBoundarySemantics({
386
+ name: "metric",
387
+ schema: MetricSemanticsSchema,
388
+ // OpenTelemetry knows a metric by its instrument name, and has no
389
+ // attribute for the system it lives in or the type string it goes by.
390
+ semconv: {},
391
+ behavior: {
392
+ exchangesHttpResponses: false,
393
+ reportsUnpairedItself: false,
394
+ identityKey(semantics) {
395
+ if (semantics.metricType === null) {
396
+ return null;
397
+ }
398
+ return metricIdentityKey(semantics.metricSystem, semantics.metricType);
399
+ }
400
+ }
401
+ });
402
+
403
+ // src/semantics/rest.ts
404
+ var import_zod6 = require("zod");
405
+ var RestSemanticsSchema = import_zod6.z.object({
406
+ name: import_zod6.z.literal("rest"),
346
407
  /**
347
408
  * Uppercase HTTP method ("GET", "POST", …), `"*"` for a handler that
348
409
  * responds to every method, or null when this source does not say
349
410
  * which method.
350
411
  */
351
- method: import_zod5.z.string().min(1).nullable(),
412
+ method: import_zod6.z.string().min(1).nullable(),
352
413
  /** Normalized route path ("/users/{id}"), or null when this source does not give one. */
353
- path: import_zod5.z.string().min(1).nullable(),
414
+ path: import_zod6.z.string().min(1).nullable(),
354
415
  /**
355
416
  * Status codes the producing source explicitly declared (OpenAPI
356
417
  * responses, CFN MethodResponses, ts-rest router statuses). They are
357
418
  * kept here so the pairing layer can see them without unwrapping any
358
419
  * metadata. Absent, or empty, for a source that was inferred.
359
420
  */
360
- declaredResponses: import_zod5.z.array(import_zod5.z.number()).optional()
421
+ declaredResponses: import_zod6.z.array(import_zod6.z.number()).optional()
361
422
  });
362
423
  function normalizePath(path) {
363
424
  let normalized = path.replace(/:([a-zA-Z_]\w*)/g, "{$1}");
@@ -396,6 +457,14 @@ function routePathAdmits(declaredPath, requestPath) {
396
457
  var restSemantics = defineBoundarySemantics({
397
458
  name: "rest",
398
459
  schema: RestSemanticsSchema,
460
+ semconv: {
461
+ // A span states the one method a request used, so a route that
462
+ // responds to every method has nothing to compare.
463
+ method: { name: "http.request.method", placeholderValues: ["*"] },
464
+ path: { name: "http.route" }
465
+ // declaredResponses is a list, and http.response.status_code is
466
+ // the one status a request got back.
467
+ },
399
468
  behavior: {
400
469
  /** A request goes out, a status and a body come back. */
401
470
  exchangesHttpResponses: true,
@@ -468,20 +537,21 @@ var restSemantics = defineBoundarySemantics({
468
537
  });
469
538
 
470
539
  // src/semantics/runtimeConfig.ts
471
- var import_zod7 = require("zod");
540
+ var import_zod8 = require("zod");
472
541
 
473
542
  // src/deployableUnit.ts
474
- var import_zod6 = require("zod");
475
- var DeployableUnitSchema = import_zod6.z.object({
476
- deploymentTarget: import_zod6.z.enum([
543
+ var import_zod7 = require("zod");
544
+ var DeployableUnitSchema = import_zod7.z.object({
545
+ deploymentTarget: import_zod7.z.enum([
477
546
  "lambda",
478
547
  "ecs-task",
479
548
  "container",
480
- "k8s-deployment"
549
+ "k8s-deployment",
550
+ "worker"
481
551
  ]),
482
552
  // An empty name would agree with every other empty name, so a unit
483
553
  // with no name has to leave the field off instead.
484
- instanceName: import_zod6.z.string().min(1)
554
+ instanceName: import_zod7.z.string().min(1)
485
555
  });
486
556
  function ecsContainerInstanceName(taskDefinitionLogicalId, containerName) {
487
557
  return `${taskDefinitionLogicalId}/${containerName}`;
@@ -489,11 +559,15 @@ function ecsContainerInstanceName(taskDefinitionLogicalId, containerName) {
489
559
 
490
560
  // src/semantics/runtimeConfig.ts
491
561
  var RuntimeConfigSemanticsSchema = DeployableUnitSchema.extend({
492
- name: import_zod7.z.literal("runtime-config")
562
+ name: import_zod8.z.literal("runtime-config")
493
563
  });
494
564
  var runtimeConfigSemantics = defineBoundarySemantics({
495
565
  name: "runtime-config",
496
566
  schema: RuntimeConfigSemanticsSchema,
567
+ // service.name and cloud.resource_id name the same deployable, but
568
+ // instanceName is the deployment template's logical id, which is
569
+ // neither of those strings.
570
+ semconv: {},
497
571
  behavior: {
498
572
  /** A process reads its config at startup, and nothing replies. */
499
573
  exchangesHttpResponses: false,
@@ -503,28 +577,28 @@ var runtimeConfigSemantics = defineBoundarySemantics({
503
577
  });
504
578
 
505
579
  // src/semantics/storage.ts
506
- var import_zod8 = require("zod");
507
- var StorageSemanticsSchema = import_zod8.z.object({
508
- name: import_zod8.z.literal("storage"),
580
+ var import_zod9 = require("zod");
581
+ var StorageSemanticsSchema = import_zod9.z.object({
582
+ name: import_zod9.z.literal("storage"),
509
583
  /**
510
- * Which store this is: postgres, mysql, sqlite, dynamodb. Two
511
- * products' containers can share a name, so this keeps them apart,
512
- * and it is what a finding message calls the store.
584
+ * Which store this is: postgresql, mysql, aws.dynamodb, or our own
585
+ * word for one OpenTelemetry never named, such as s3. Two products'
586
+ * containers can share a name, so this keeps them apart.
513
587
  */
514
- storageSystem: import_zod8.z.string(),
588
+ storageSystem: import_zod9.z.string(),
515
589
  /**
516
590
  * The ORM, schema, or deployment scope. A single-database setup uses
517
591
  * `"default"`, and a monorepo with several schemas gives each one its
518
592
  * own value.
519
593
  */
520
- scope: import_zod8.z.string(),
594
+ scope: import_zod9.z.string(),
521
595
  /**
522
596
  * The table, bucket, collection, or index, as the source declares
523
597
  * it, or null when the source states one this reader could not
524
598
  * settle. A null container pairs with nothing, rather than with
525
599
  * whatever its source text happens to spell.
526
600
  */
527
- container: import_zod8.z.string().nullable(),
601
+ container: import_zod9.z.string().nullable(),
528
602
  /**
529
603
  * A secondary way into the container, a DynamoDB global secondary
530
604
  * index or an Elasticsearch alias, each with its own key fields.
@@ -532,11 +606,19 @@ var StorageSemanticsSchema = import_zod8.z.object({
532
606
  * index and a query through the table are different accesses, so
533
607
  * they pair separately.
534
608
  */
535
- accessPath: import_zod8.z.string().nullable()
609
+ accessPath: import_zod9.z.string().nullable()
536
610
  });
537
611
  var storageSemantics = defineBoundarySemantics({
538
612
  name: "storage",
539
613
  schema: StorageSemanticsSchema,
614
+ semconv: {
615
+ storageSystem: { name: "db.system.name" },
616
+ // "default" is our word for a source that named no database.
617
+ scope: { name: "db.namespace", placeholderValues: ["default"] },
618
+ container: { name: "db.collection.name" }
619
+ // A secondary index has no attribute of its own, so accessPath
620
+ // stays our word.
621
+ },
540
622
  behavior: {
541
623
  /** A query returns rows or items, not a status and a body. */
542
624
  exchangesHttpResponses: false,
@@ -546,14 +628,15 @@ var storageSemantics = defineBoundarySemantics({
546
628
  });
547
629
 
548
630
  // src/semantics/registry.ts
549
- var SemanticsSchema = import_zod9.z.discriminatedUnion("name", [
631
+ var SemanticsSchema = import_zod10.z.discriminatedUnion("name", [
550
632
  restSemantics.schema,
551
633
  functionCallSemantics.schema,
552
634
  graphqlResolverSemantics.schema,
553
635
  graphqlOperationSemantics.schema,
554
636
  runtimeConfigSemantics.schema,
555
637
  storageSemantics.schema,
556
- messageBusSemantics.schema
638
+ messageBusSemantics.schema,
639
+ metricSemantics.schema
557
640
  ]);
558
641
  var DEFINITIONS = [
559
642
  restSemantics,
@@ -562,48 +645,55 @@ var DEFINITIONS = [
562
645
  graphqlOperationSemantics,
563
646
  runtimeConfigSemantics,
564
647
  storageSemantics,
565
- messageBusSemantics
648
+ messageBusSemantics,
649
+ metricSemantics
566
650
  ];
567
651
  var BY_NAME = new Map(
568
652
  DEFINITIONS.map((d) => [d.name, d])
569
653
  );
570
654
  function behaviorOf(semantics) {
571
- const definition = BY_NAME.get(semantics.name);
655
+ return definitionFor(semantics.name).behavior;
656
+ }
657
+ function definitionFor(name) {
658
+ const definition = BY_NAME.get(name);
572
659
  if (definition === void 0) {
573
- throw new Error(`no boundary behavior for semantics "${semantics.name}"`);
660
+ throw new Error(`no boundary definition for semantics "${name}"`);
574
661
  }
575
- return definition.behavior;
662
+ return definition;
663
+ }
664
+ function semconvMappingOf(semantics) {
665
+ return definitionFor(semantics.name).semconv;
576
666
  }
577
667
  function allBehaviors() {
578
668
  return DEFINITIONS.map((d) => d.behavior);
579
669
  }
580
670
 
581
671
  // src/schemas.ts
582
- var ConfidenceSourceSchema = import_zod10.z.enum([
672
+ var ConfidenceSourceSchema = import_zod11.z.enum([
583
673
  "inferred_static",
584
674
  "inferred_ai",
585
675
  "declared",
586
676
  "derived"
587
677
  ]);
588
- var ConfidenceLevelSchema = import_zod10.z.enum(["high", "medium", "low"]);
589
- var CorroborationSchema = import_zod10.z.object({
590
- outcome: import_zod10.z.enum(["observed", "refuted", "untested"]),
678
+ var ConfidenceLevelSchema = import_zod11.z.enum(["high", "medium", "low"]);
679
+ var CorroborationSchema = import_zod11.z.object({
680
+ outcome: import_zod11.z.enum(["observed", "refuted", "untested"]),
591
681
  /** Executions that produced a verdict for this claim. */
592
- runs: import_zod10.z.number(),
682
+ runs: import_zod11.z.number(),
593
683
  /** Present when refuted: the input and observation that disagreed. */
594
- counterexample: import_zod10.z.unknown().optional(),
684
+ counterexample: import_zod11.z.unknown().optional(),
595
685
  /** Present when untested: why no verdict was reachable. */
596
- reason: import_zod10.z.string().optional()
686
+ reason: import_zod11.z.string().optional()
597
687
  });
598
- var ConfidenceInfoSchema = import_zod10.z.object({
688
+ var ConfidenceInfoSchema = import_zod11.z.object({
599
689
  source: ConfidenceSourceSchema,
600
690
  level: ConfidenceLevelSchema,
601
691
  corroboration: CorroborationSchema.optional()
602
692
  });
603
- var SourceLocationSchema = import_zod10.z.object({
604
- file: import_zod10.z.string(),
605
- range: import_zod10.z.object({ start: import_zod10.z.number(), end: import_zod10.z.number() }),
606
- exportName: import_zod10.z.string().nullable(),
693
+ var SourceLocationSchema = import_zod11.z.object({
694
+ file: import_zod11.z.string(),
695
+ range: import_zod11.z.object({ start: import_zod11.z.number(), end: import_zod11.z.number() }),
696
+ exportName: import_zod11.z.string().nullable(),
607
697
  /**
608
698
  * The project the extract was pointed at, by the name that project
609
699
  * calls itself.
@@ -613,47 +703,47 @@ var SourceLocationSchema = import_zod10.z.object({
613
703
  * summaries puts them on top of each other. This field is what tells
614
704
  * them apart, and what a reader groups by.
615
705
  */
616
- workspace: import_zod10.z.string().optional()
706
+ workspace: import_zod11.z.string().optional()
617
707
  });
618
- var BoundaryBindingSchema = import_zod10.z.object({
619
- transport: import_zod10.z.string(),
708
+ var BoundaryBindingSchema = import_zod11.z.object({
709
+ transport: import_zod11.z.string(),
620
710
  semantics: SemanticsSchema,
621
- recognition: import_zod10.z.string()
711
+ recognition: import_zod11.z.string()
622
712
  });
623
713
  function typeDefinitionKey(ref) {
624
714
  return ref.def ?? null;
625
715
  }
626
- var TypeShapeSchema = import_zod10.z.lazy(
627
- () => import_zod10.z.discriminatedUnion("type", [
628
- import_zod10.z.object({
629
- type: import_zod10.z.literal("record"),
630
- properties: import_zod10.z.record(import_zod10.z.string(), TypeShapeSchema),
631
- spreads: import_zod10.z.array(import_zod10.z.object({ sourceText: import_zod10.z.string() })).optional()
716
+ var TypeShapeSchema = import_zod11.z.lazy(
717
+ () => import_zod11.z.discriminatedUnion("type", [
718
+ import_zod11.z.object({
719
+ type: import_zod11.z.literal("record"),
720
+ properties: import_zod11.z.record(import_zod11.z.string(), TypeShapeSchema),
721
+ spreads: import_zod11.z.array(import_zod11.z.object({ sourceText: import_zod11.z.string() })).optional()
632
722
  }),
633
- import_zod10.z.object({ type: import_zod10.z.literal("dictionary"), values: TypeShapeSchema }),
634
- import_zod10.z.object({ type: import_zod10.z.literal("array"), items: TypeShapeSchema }),
635
- import_zod10.z.object({
636
- type: import_zod10.z.literal("literal"),
637
- value: import_zod10.z.union([import_zod10.z.string(), import_zod10.z.number(), import_zod10.z.boolean()]),
638
- raw: import_zod10.z.string().optional()
723
+ import_zod11.z.object({ type: import_zod11.z.literal("dictionary"), values: TypeShapeSchema }),
724
+ import_zod11.z.object({ type: import_zod11.z.literal("array"), items: TypeShapeSchema }),
725
+ import_zod11.z.object({
726
+ type: import_zod11.z.literal("literal"),
727
+ value: import_zod11.z.union([import_zod11.z.string(), import_zod11.z.number(), import_zod11.z.boolean()]),
728
+ raw: import_zod11.z.string().optional()
639
729
  }),
640
- import_zod10.z.object({ type: import_zod10.z.literal("text") }),
641
- import_zod10.z.object({ type: import_zod10.z.literal("integer") }),
642
- import_zod10.z.object({ type: import_zod10.z.literal("number") }),
643
- import_zod10.z.object({ type: import_zod10.z.literal("boolean") }),
644
- import_zod10.z.object({ type: import_zod10.z.literal("null") }),
645
- import_zod10.z.object({ type: import_zod10.z.literal("undefined") }),
646
- import_zod10.z.object({
647
- type: import_zod10.z.literal("union"),
648
- variants: import_zod10.z.array(TypeShapeSchema)
730
+ import_zod11.z.object({ type: import_zod11.z.literal("text") }),
731
+ import_zod11.z.object({ type: import_zod11.z.literal("integer") }),
732
+ import_zod11.z.object({ type: import_zod11.z.literal("number") }),
733
+ import_zod11.z.object({ type: import_zod11.z.literal("boolean") }),
734
+ import_zod11.z.object({ type: import_zod11.z.literal("null") }),
735
+ import_zod11.z.object({ type: import_zod11.z.literal("undefined") }),
736
+ import_zod11.z.object({
737
+ type: import_zod11.z.literal("union"),
738
+ variants: import_zod11.z.array(TypeShapeSchema)
649
739
  }),
650
- import_zod10.z.object({
651
- type: import_zod10.z.literal("ref"),
652
- name: import_zod10.z.string(),
653
- from: import_zod10.z.string().optional(),
654
- def: import_zod10.z.string().optional()
740
+ import_zod11.z.object({
741
+ type: import_zod11.z.literal("ref"),
742
+ name: import_zod11.z.string(),
743
+ from: import_zod11.z.string().optional(),
744
+ def: import_zod11.z.string().optional()
655
745
  }),
656
- import_zod10.z.object({ type: import_zod10.z.literal("unknown") })
746
+ import_zod11.z.object({ type: import_zod11.z.literal("unknown") })
657
747
  ])
658
748
  );
659
749
  var MAX_DEFINITION_DEPTH = 6;
@@ -697,6 +787,25 @@ function withDefinitionsInlined(shape, definitions, depth = 0, inProgress = /* @
697
787
  return shape;
698
788
  }
699
789
 
790
+ // src/semconv.ts
791
+ function semconvAttributes(binding) {
792
+ const semantics = binding.semantics;
793
+ const attributes = {};
794
+ for (const [field, attribute] of Object.entries(
795
+ semconvMappingOf(binding.semantics)
796
+ )) {
797
+ const value = semantics[field];
798
+ if (typeof value !== "string") {
799
+ continue;
800
+ }
801
+ if (attribute.placeholderValues?.includes(value) === true) {
802
+ continue;
803
+ }
804
+ attributes[attribute.name] = value;
805
+ }
806
+ return attributes;
807
+ }
808
+
700
809
  // src/boundaryKey.ts
701
810
  function boundaryKey(binding) {
702
811
  return behaviorOf(binding.semantics).identityKey(binding.semantics);
@@ -794,9 +903,22 @@ function hasNameHole(name) {
794
903
  function namePatternKey(name) {
795
904
  return name.replace(HOLE, "{}");
796
905
  }
906
+ function fixedTextLength(name) {
907
+ return name.replace(HOLE, "").length;
908
+ }
909
+ function isHole(part) {
910
+ return part.startsWith("{") && part.endsWith("}");
911
+ }
912
+ function quote(text) {
913
+ return text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
914
+ }
915
+ function holeSource(_following) {
916
+ return ".+";
917
+ }
797
918
  function admits(pattern, name) {
798
- const source = pattern.split(/(\{[^}]*\})/).map(
799
- (part) => part.startsWith("{") && part.endsWith("}") ? ".+" : part.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")
919
+ const parts = pattern.split(/(\{[^}]*\})/);
920
+ const source = parts.map(
921
+ (part, index) => isHole(part) ? holeSource(parts[index + 1] ?? "") : quote(part)
800
922
  ).join("");
801
923
  return new RegExp(`^${source}$`).test(name);
802
924
  }
@@ -822,25 +944,25 @@ function namesAgree(a, b) {
822
944
  }
823
945
 
824
946
  // src/suppressions.ts
825
- var import_zod11 = require("zod");
826
- var SuppressionSideSchema = import_zod11.z.object({
827
- summary: import_zod11.z.string().optional(),
828
- transitionId: import_zod11.z.string().optional()
947
+ var import_zod12 = require("zod");
948
+ var SuppressionSideSchema = import_zod12.z.object({
949
+ summary: import_zod12.z.string().optional(),
950
+ transitionId: import_zod12.z.string().optional()
829
951
  }).optional();
830
- var SuppressionRuleSchema = import_zod11.z.object({
952
+ var SuppressionRuleSchema = import_zod12.z.object({
831
953
  /**
832
954
  * The finding kind to match, behavioural or intent. It is an open
833
955
  * string here because this package is below both IRs, and the loader
834
956
  * is what validates it against the published kind enums.
835
957
  */
836
- kind: import_zod11.z.string().optional(),
958
+ kind: import_zod12.z.string().optional(),
837
959
  /**
838
960
  * Boundary as a human-readable key, e.g. "GET /pet/{petId}" or
839
961
  * "fn:@acme/api::getUser". REST keys are normalized via the same
840
962
  * path normalizer the checkers use, so `:id` and `{id}` compare
841
963
  * equal.
842
964
  */
843
- boundary: import_zod11.z.string().optional(),
965
+ boundary: import_zod12.z.string().optional(),
844
966
  /**
845
967
  * Consumer-side discriminators, the narrowest useful match. These
846
968
  * mean something only for behavioural findings: a rule that
@@ -863,15 +985,15 @@ var SuppressionRuleSchema = import_zod11.z.object({
863
985
  * kind-only or boundary-only matches, which also silence future
864
986
  * regressions in that category.
865
987
  */
866
- scope: import_zod11.z.enum(["narrow", "broad"]).default("narrow"),
988
+ scope: import_zod12.z.enum(["narrow", "broad"]).default("narrow"),
867
989
  /** Required human-written justification. */
868
- reason: import_zod11.z.string().min(1),
990
+ reason: import_zod12.z.string().min(1),
869
991
  /** What to do when a finding matches. */
870
- effect: import_zod11.z.enum(["mark", "downgrade", "hide"]).default("mark")
992
+ effect: import_zod12.z.enum(["mark", "downgrade", "hide"]).default("mark")
871
993
  }).strict();
872
- var SuppressionFileSchema = import_zod11.z.object({
873
- version: import_zod11.z.literal(1),
874
- rules: import_zod11.z.array(SuppressionRuleSchema)
994
+ var SuppressionFileSchema = import_zod12.z.object({
995
+ version: import_zod12.z.literal(1),
996
+ rules: import_zod12.z.array(SuppressionRuleSchema)
875
997
  }).strict();
876
998
  function validateRule(rule) {
877
999
  if (rule.scope === "broad") {
@@ -1185,6 +1307,17 @@ function messageBusBinding(opts) {
1185
1307
  recognition: opts.recognition
1186
1308
  };
1187
1309
  }
1310
+ function metricBinding(opts) {
1311
+ return {
1312
+ transport: opts.metricSystem,
1313
+ semantics: {
1314
+ name: "metric",
1315
+ metricSystem: opts.metricSystem,
1316
+ metricType: namedOrNull(opts.metricType, "metric type")
1317
+ },
1318
+ recognition: opts.recognition
1319
+ };
1320
+ }
1188
1321
  // Annotate the CommonJS export names for ESM import in node:
1189
1322
  0 && (module.exports = {
1190
1323
  BoundaryBindingSchema,
@@ -1197,6 +1330,7 @@ function messageBusBinding(opts) {
1197
1330
  GraphqlOperationSemanticsSchema,
1198
1331
  GraphqlResolverSemanticsSchema,
1199
1332
  MessageBusSemanticsSchema,
1333
+ MetricSemanticsSchema,
1200
1334
  RestSemanticsSchema,
1201
1335
  RuntimeConfigSemanticsSchema,
1202
1336
  SemanticsSchema,
@@ -1220,6 +1354,7 @@ function messageBusBinding(opts) {
1220
1354
  ecsContainerInstanceName,
1221
1355
  exchangesHttpResponses,
1222
1356
  fileInCodeScope,
1357
+ fixedTextLength,
1223
1358
  fnIdentityKey,
1224
1359
  formatChannel,
1225
1360
  functionCallBinding,
@@ -1230,6 +1365,8 @@ function messageBusBinding(opts) {
1230
1365
  isGraphqlOperationBinding,
1231
1366
  messageBusBinding,
1232
1367
  methodsAgree,
1368
+ metricBinding,
1369
+ metricIdentityKey,
1233
1370
  namePatternFromSub,
1234
1371
  namePatternKey,
1235
1372
  namesAgree,
@@ -1245,6 +1382,7 @@ function messageBusBinding(opts) {
1245
1382
  ruleBoundaryMatchesKey,
1246
1383
  runtimeConfigBinding,
1247
1384
  semanticsAgree,
1385
+ semconvAttributes,
1248
1386
  servesRequest,
1249
1387
  storageBinding,
1250
1388
  typeDefinitionKey,