@suss/ir-core 0.8.0 → 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,8 +280,11 @@ 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",
@@ -284,6 +305,10 @@ var MessageBusSemanticsSchema = import_zod4.z.object({
284
305
  var messageBusSemantics = defineBoundarySemantics({
285
306
  name: "message-bus",
286
307
  schema: MessageBusSemanticsSchema,
308
+ semconv: {
309
+ messageBus: { name: "messaging.system" },
310
+ channel: { name: "messaging.destination.name" }
311
+ },
287
312
  behavior: {
288
313
  /** A message goes onto the channel and nothing comes back. */
289
314
  exchangesHttpResponses: false,
@@ -342,25 +367,58 @@ var messageBusSemantics = defineBoundarySemantics({
342
367
  }
343
368
  });
344
369
 
345
- // src/semantics/rest.ts
370
+ // src/semantics/metric.ts
346
371
  var import_zod5 = require("zod");
347
- var RestSemanticsSchema = import_zod5.z.object({
348
- 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"),
349
407
  /**
350
408
  * Uppercase HTTP method ("GET", "POST", …), `"*"` for a handler that
351
409
  * responds to every method, or null when this source does not say
352
410
  * which method.
353
411
  */
354
- method: import_zod5.z.string().min(1).nullable(),
412
+ method: import_zod6.z.string().min(1).nullable(),
355
413
  /** Normalized route path ("/users/{id}"), or null when this source does not give one. */
356
- path: import_zod5.z.string().min(1).nullable(),
414
+ path: import_zod6.z.string().min(1).nullable(),
357
415
  /**
358
416
  * Status codes the producing source explicitly declared (OpenAPI
359
417
  * responses, CFN MethodResponses, ts-rest router statuses). They are
360
418
  * kept here so the pairing layer can see them without unwrapping any
361
419
  * metadata. Absent, or empty, for a source that was inferred.
362
420
  */
363
- declaredResponses: import_zod5.z.array(import_zod5.z.number()).optional()
421
+ declaredResponses: import_zod6.z.array(import_zod6.z.number()).optional()
364
422
  });
365
423
  function normalizePath(path) {
366
424
  let normalized = path.replace(/:([a-zA-Z_]\w*)/g, "{$1}");
@@ -399,6 +457,14 @@ function routePathAdmits(declaredPath, requestPath) {
399
457
  var restSemantics = defineBoundarySemantics({
400
458
  name: "rest",
401
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
+ },
402
468
  behavior: {
403
469
  /** A request goes out, a status and a body come back. */
404
470
  exchangesHttpResponses: true,
@@ -471,12 +537,12 @@ var restSemantics = defineBoundarySemantics({
471
537
  });
472
538
 
473
539
  // src/semantics/runtimeConfig.ts
474
- var import_zod7 = require("zod");
540
+ var import_zod8 = require("zod");
475
541
 
476
542
  // src/deployableUnit.ts
477
- var import_zod6 = require("zod");
478
- var DeployableUnitSchema = import_zod6.z.object({
479
- deploymentTarget: import_zod6.z.enum([
543
+ var import_zod7 = require("zod");
544
+ var DeployableUnitSchema = import_zod7.z.object({
545
+ deploymentTarget: import_zod7.z.enum([
480
546
  "lambda",
481
547
  "ecs-task",
482
548
  "container",
@@ -485,7 +551,7 @@ var DeployableUnitSchema = import_zod6.z.object({
485
551
  ]),
486
552
  // An empty name would agree with every other empty name, so a unit
487
553
  // with no name has to leave the field off instead.
488
- instanceName: import_zod6.z.string().min(1)
554
+ instanceName: import_zod7.z.string().min(1)
489
555
  });
490
556
  function ecsContainerInstanceName(taskDefinitionLogicalId, containerName) {
491
557
  return `${taskDefinitionLogicalId}/${containerName}`;
@@ -493,11 +559,15 @@ function ecsContainerInstanceName(taskDefinitionLogicalId, containerName) {
493
559
 
494
560
  // src/semantics/runtimeConfig.ts
495
561
  var RuntimeConfigSemanticsSchema = DeployableUnitSchema.extend({
496
- name: import_zod7.z.literal("runtime-config")
562
+ name: import_zod8.z.literal("runtime-config")
497
563
  });
498
564
  var runtimeConfigSemantics = defineBoundarySemantics({
499
565
  name: "runtime-config",
500
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: {},
501
571
  behavior: {
502
572
  /** A process reads its config at startup, and nothing replies. */
503
573
  exchangesHttpResponses: false,
@@ -507,28 +577,28 @@ var runtimeConfigSemantics = defineBoundarySemantics({
507
577
  });
508
578
 
509
579
  // src/semantics/storage.ts
510
- var import_zod8 = require("zod");
511
- var StorageSemanticsSchema = import_zod8.z.object({
512
- 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"),
513
583
  /**
514
- * Which store this is: postgres, mysql, sqlite, dynamodb. Two
515
- * products' containers can share a name, so this keeps them apart,
516
- * 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.
517
587
  */
518
- storageSystem: import_zod8.z.string(),
588
+ storageSystem: import_zod9.z.string(),
519
589
  /**
520
590
  * The ORM, schema, or deployment scope. A single-database setup uses
521
591
  * `"default"`, and a monorepo with several schemas gives each one its
522
592
  * own value.
523
593
  */
524
- scope: import_zod8.z.string(),
594
+ scope: import_zod9.z.string(),
525
595
  /**
526
596
  * The table, bucket, collection, or index, as the source declares
527
597
  * it, or null when the source states one this reader could not
528
598
  * settle. A null container pairs with nothing, rather than with
529
599
  * whatever its source text happens to spell.
530
600
  */
531
- container: import_zod8.z.string().nullable(),
601
+ container: import_zod9.z.string().nullable(),
532
602
  /**
533
603
  * A secondary way into the container, a DynamoDB global secondary
534
604
  * index or an Elasticsearch alias, each with its own key fields.
@@ -536,11 +606,19 @@ var StorageSemanticsSchema = import_zod8.z.object({
536
606
  * index and a query through the table are different accesses, so
537
607
  * they pair separately.
538
608
  */
539
- accessPath: import_zod8.z.string().nullable()
609
+ accessPath: import_zod9.z.string().nullable()
540
610
  });
541
611
  var storageSemantics = defineBoundarySemantics({
542
612
  name: "storage",
543
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
+ },
544
622
  behavior: {
545
623
  /** A query returns rows or items, not a status and a body. */
546
624
  exchangesHttpResponses: false,
@@ -550,14 +628,15 @@ var storageSemantics = defineBoundarySemantics({
550
628
  });
551
629
 
552
630
  // src/semantics/registry.ts
553
- var SemanticsSchema = import_zod9.z.discriminatedUnion("name", [
631
+ var SemanticsSchema = import_zod10.z.discriminatedUnion("name", [
554
632
  restSemantics.schema,
555
633
  functionCallSemantics.schema,
556
634
  graphqlResolverSemantics.schema,
557
635
  graphqlOperationSemantics.schema,
558
636
  runtimeConfigSemantics.schema,
559
637
  storageSemantics.schema,
560
- messageBusSemantics.schema
638
+ messageBusSemantics.schema,
639
+ metricSemantics.schema
561
640
  ]);
562
641
  var DEFINITIONS = [
563
642
  restSemantics,
@@ -566,48 +645,55 @@ var DEFINITIONS = [
566
645
  graphqlOperationSemantics,
567
646
  runtimeConfigSemantics,
568
647
  storageSemantics,
569
- messageBusSemantics
648
+ messageBusSemantics,
649
+ metricSemantics
570
650
  ];
571
651
  var BY_NAME = new Map(
572
652
  DEFINITIONS.map((d) => [d.name, d])
573
653
  );
574
654
  function behaviorOf(semantics) {
575
- 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);
576
659
  if (definition === void 0) {
577
- throw new Error(`no boundary behavior for semantics "${semantics.name}"`);
660
+ throw new Error(`no boundary definition for semantics "${name}"`);
578
661
  }
579
- return definition.behavior;
662
+ return definition;
663
+ }
664
+ function semconvMappingOf(semantics) {
665
+ return definitionFor(semantics.name).semconv;
580
666
  }
581
667
  function allBehaviors() {
582
668
  return DEFINITIONS.map((d) => d.behavior);
583
669
  }
584
670
 
585
671
  // src/schemas.ts
586
- var ConfidenceSourceSchema = import_zod10.z.enum([
672
+ var ConfidenceSourceSchema = import_zod11.z.enum([
587
673
  "inferred_static",
588
674
  "inferred_ai",
589
675
  "declared",
590
676
  "derived"
591
677
  ]);
592
- var ConfidenceLevelSchema = import_zod10.z.enum(["high", "medium", "low"]);
593
- var CorroborationSchema = import_zod10.z.object({
594
- 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"]),
595
681
  /** Executions that produced a verdict for this claim. */
596
- runs: import_zod10.z.number(),
682
+ runs: import_zod11.z.number(),
597
683
  /** Present when refuted: the input and observation that disagreed. */
598
- counterexample: import_zod10.z.unknown().optional(),
684
+ counterexample: import_zod11.z.unknown().optional(),
599
685
  /** Present when untested: why no verdict was reachable. */
600
- reason: import_zod10.z.string().optional()
686
+ reason: import_zod11.z.string().optional()
601
687
  });
602
- var ConfidenceInfoSchema = import_zod10.z.object({
688
+ var ConfidenceInfoSchema = import_zod11.z.object({
603
689
  source: ConfidenceSourceSchema,
604
690
  level: ConfidenceLevelSchema,
605
691
  corroboration: CorroborationSchema.optional()
606
692
  });
607
- var SourceLocationSchema = import_zod10.z.object({
608
- file: import_zod10.z.string(),
609
- range: import_zod10.z.object({ start: import_zod10.z.number(), end: import_zod10.z.number() }),
610
- 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(),
611
697
  /**
612
698
  * The project the extract was pointed at, by the name that project
613
699
  * calls itself.
@@ -617,47 +703,47 @@ var SourceLocationSchema = import_zod10.z.object({
617
703
  * summaries puts them on top of each other. This field is what tells
618
704
  * them apart, and what a reader groups by.
619
705
  */
620
- workspace: import_zod10.z.string().optional()
706
+ workspace: import_zod11.z.string().optional()
621
707
  });
622
- var BoundaryBindingSchema = import_zod10.z.object({
623
- transport: import_zod10.z.string(),
708
+ var BoundaryBindingSchema = import_zod11.z.object({
709
+ transport: import_zod11.z.string(),
624
710
  semantics: SemanticsSchema,
625
- recognition: import_zod10.z.string()
711
+ recognition: import_zod11.z.string()
626
712
  });
627
713
  function typeDefinitionKey(ref) {
628
714
  return ref.def ?? null;
629
715
  }
630
- var TypeShapeSchema = import_zod10.z.lazy(
631
- () => import_zod10.z.discriminatedUnion("type", [
632
- import_zod10.z.object({
633
- type: import_zod10.z.literal("record"),
634
- properties: import_zod10.z.record(import_zod10.z.string(), TypeShapeSchema),
635
- 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()
636
722
  }),
637
- import_zod10.z.object({ type: import_zod10.z.literal("dictionary"), values: TypeShapeSchema }),
638
- import_zod10.z.object({ type: import_zod10.z.literal("array"), items: TypeShapeSchema }),
639
- import_zod10.z.object({
640
- type: import_zod10.z.literal("literal"),
641
- value: import_zod10.z.union([import_zod10.z.string(), import_zod10.z.number(), import_zod10.z.boolean()]),
642
- 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()
643
729
  }),
644
- import_zod10.z.object({ type: import_zod10.z.literal("text") }),
645
- import_zod10.z.object({ type: import_zod10.z.literal("integer") }),
646
- import_zod10.z.object({ type: import_zod10.z.literal("number") }),
647
- import_zod10.z.object({ type: import_zod10.z.literal("boolean") }),
648
- import_zod10.z.object({ type: import_zod10.z.literal("null") }),
649
- import_zod10.z.object({ type: import_zod10.z.literal("undefined") }),
650
- import_zod10.z.object({
651
- type: import_zod10.z.literal("union"),
652
- 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)
653
739
  }),
654
- import_zod10.z.object({
655
- type: import_zod10.z.literal("ref"),
656
- name: import_zod10.z.string(),
657
- from: import_zod10.z.string().optional(),
658
- 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()
659
745
  }),
660
- import_zod10.z.object({ type: import_zod10.z.literal("unknown") })
746
+ import_zod11.z.object({ type: import_zod11.z.literal("unknown") })
661
747
  ])
662
748
  );
663
749
  var MAX_DEFINITION_DEPTH = 6;
@@ -701,6 +787,25 @@ function withDefinitionsInlined(shape, definitions, depth = 0, inProgress = /* @
701
787
  return shape;
702
788
  }
703
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
+
704
809
  // src/boundaryKey.ts
705
810
  function boundaryKey(binding) {
706
811
  return behaviorOf(binding.semantics).identityKey(binding.semantics);
@@ -798,9 +903,22 @@ function hasNameHole(name) {
798
903
  function namePatternKey(name) {
799
904
  return name.replace(HOLE, "{}");
800
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
+ }
801
918
  function admits(pattern, name) {
802
- const source = pattern.split(/(\{[^}]*\})/).map(
803
- (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)
804
922
  ).join("");
805
923
  return new RegExp(`^${source}$`).test(name);
806
924
  }
@@ -826,25 +944,25 @@ function namesAgree(a, b) {
826
944
  }
827
945
 
828
946
  // src/suppressions.ts
829
- var import_zod11 = require("zod");
830
- var SuppressionSideSchema = import_zod11.z.object({
831
- summary: import_zod11.z.string().optional(),
832
- 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()
833
951
  }).optional();
834
- var SuppressionRuleSchema = import_zod11.z.object({
952
+ var SuppressionRuleSchema = import_zod12.z.object({
835
953
  /**
836
954
  * The finding kind to match, behavioural or intent. It is an open
837
955
  * string here because this package is below both IRs, and the loader
838
956
  * is what validates it against the published kind enums.
839
957
  */
840
- kind: import_zod11.z.string().optional(),
958
+ kind: import_zod12.z.string().optional(),
841
959
  /**
842
960
  * Boundary as a human-readable key, e.g. "GET /pet/{petId}" or
843
961
  * "fn:@acme/api::getUser". REST keys are normalized via the same
844
962
  * path normalizer the checkers use, so `:id` and `{id}` compare
845
963
  * equal.
846
964
  */
847
- boundary: import_zod11.z.string().optional(),
965
+ boundary: import_zod12.z.string().optional(),
848
966
  /**
849
967
  * Consumer-side discriminators, the narrowest useful match. These
850
968
  * mean something only for behavioural findings: a rule that
@@ -867,15 +985,15 @@ var SuppressionRuleSchema = import_zod11.z.object({
867
985
  * kind-only or boundary-only matches, which also silence future
868
986
  * regressions in that category.
869
987
  */
870
- scope: import_zod11.z.enum(["narrow", "broad"]).default("narrow"),
988
+ scope: import_zod12.z.enum(["narrow", "broad"]).default("narrow"),
871
989
  /** Required human-written justification. */
872
- reason: import_zod11.z.string().min(1),
990
+ reason: import_zod12.z.string().min(1),
873
991
  /** What to do when a finding matches. */
874
- effect: import_zod11.z.enum(["mark", "downgrade", "hide"]).default("mark")
992
+ effect: import_zod12.z.enum(["mark", "downgrade", "hide"]).default("mark")
875
993
  }).strict();
876
- var SuppressionFileSchema = import_zod11.z.object({
877
- version: import_zod11.z.literal(1),
878
- 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)
879
997
  }).strict();
880
998
  function validateRule(rule) {
881
999
  if (rule.scope === "broad") {
@@ -1189,6 +1307,17 @@ function messageBusBinding(opts) {
1189
1307
  recognition: opts.recognition
1190
1308
  };
1191
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
+ }
1192
1321
  // Annotate the CommonJS export names for ESM import in node:
1193
1322
  0 && (module.exports = {
1194
1323
  BoundaryBindingSchema,
@@ -1201,6 +1330,7 @@ function messageBusBinding(opts) {
1201
1330
  GraphqlOperationSemanticsSchema,
1202
1331
  GraphqlResolverSemanticsSchema,
1203
1332
  MessageBusSemanticsSchema,
1333
+ MetricSemanticsSchema,
1204
1334
  RestSemanticsSchema,
1205
1335
  RuntimeConfigSemanticsSchema,
1206
1336
  SemanticsSchema,
@@ -1224,6 +1354,7 @@ function messageBusBinding(opts) {
1224
1354
  ecsContainerInstanceName,
1225
1355
  exchangesHttpResponses,
1226
1356
  fileInCodeScope,
1357
+ fixedTextLength,
1227
1358
  fnIdentityKey,
1228
1359
  formatChannel,
1229
1360
  functionCallBinding,
@@ -1234,6 +1365,8 @@ function messageBusBinding(opts) {
1234
1365
  isGraphqlOperationBinding,
1235
1366
  messageBusBinding,
1236
1367
  methodsAgree,
1368
+ metricBinding,
1369
+ metricIdentityKey,
1237
1370
  namePatternFromSub,
1238
1371
  namePatternKey,
1239
1372
  namesAgree,
@@ -1249,6 +1382,7 @@ function messageBusBinding(opts) {
1249
1382
  ruleBoundaryMatchesKey,
1250
1383
  runtimeConfigBinding,
1251
1384
  semanticsAgree,
1385
+ semconvAttributes,
1252
1386
  servesRequest,
1253
1387
  storageBinding,
1254
1388
  typeDefinitionKey,