@suss/ir-core 0.35.1 → 0.37.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/README.md CHANGED
@@ -33,6 +33,10 @@ The two sides rarely know the same amount. A CloudFormation template gives both
33
33
 
34
34
  The boundary key uses only the subject, so both forms end up in the same bucket, and `channelsPair` compares the buses within it.
35
35
 
36
+ A background job is a message too. For ActiveJob, Sidekiq and Celery the subject is the job class or the task name, and the bus part is the queue the job declares. A job with `queue_as :mailers` is `mailers#ReportExportJob`, and the enqueue `ReportExportJob.perform_later(id)` is `ReportExportJob`, so the two pair whichever queue the job runs on. A BullMQ worker takes every job on its queue, so for BullMQ the subject is the queue.
37
+
38
+ A job queue's work can also come from a scheduler that reads job names out of a config file, such as Sidekiq's `sidekiq.yml` or Celery beat, from another service, or through code the run cannot follow. `MESSAGE_BUS_TRAITS` marks every job queue `jobQueue`, BullMQ included, and the message-bus check does not report a consumer on one of them as having no producer. A send on a job queue whose job a pack could not settle has no channel, and the summary gets an `unfollowedCall` gap with the reason `unsettledJob`, whichever language the send is in.
39
+
36
40
  ## Boundary names
37
41
 
38
42
  A container or an access path in a summary is a string that means one of three things, and the braces alone decide which:
@@ -248,7 +248,11 @@ var MessageBusSemanticsSchema = z5.object({
248
248
  "aws_kinesis",
249
249
  "aws_firehose",
250
250
  "gcp_pubsub",
251
+ // Job queues. The header says what their channel is.
251
252
  "bullmq",
253
+ "activejob",
254
+ "sidekiq",
255
+ "celery",
252
256
  "kafka",
253
257
  "nats",
254
258
  "cloudflare-queues",
@@ -264,6 +268,26 @@ var MessageBusSemanticsSchema = z5.object({
264
268
  */
265
269
  channel: z5.string().min(1).nullable()
266
270
  });
271
+ var MESSAGES = { jobQueue: false };
272
+ var JOBS = { jobQueue: true };
273
+ var MESSAGE_BUS_TRAITS = {
274
+ aws_sqs: MESSAGES,
275
+ "aws.sns": MESSAGES,
276
+ s3: MESSAGES,
277
+ eventbridge: MESSAGES,
278
+ aws_kinesis: MESSAGES,
279
+ aws_firehose: MESSAGES,
280
+ gcp_pubsub: MESSAGES,
281
+ bullmq: JOBS,
282
+ activejob: JOBS,
283
+ sidekiq: JOBS,
284
+ celery: JOBS,
285
+ kafka: MESSAGES,
286
+ nats: MESSAGES,
287
+ "cloudflare-queues": MESSAGES,
288
+ "cloudflare-cron": MESSAGES,
289
+ "cloudflare-tail": MESSAGES
290
+ };
267
291
  var messageBusSemantics = defineBoundarySemantics({
268
292
  name: "message-bus",
269
293
  schema: MessageBusSemanticsSchema,
@@ -280,6 +304,8 @@ var messageBusSemantics = defineBoundarySemantics({
280
304
  * the generic unmatched list leaves them out.
281
305
  */
282
306
  reportsUnpairedItself: true,
307
+ consumedAs: ["reads"],
308
+ unsettledJob: (semantics) => semantics.channel === null && MESSAGE_BUS_TRAITS[semantics.messageBus].jobQueue,
283
309
  /**
284
310
  * A channel that is null here can still pair. The dedicated pass
285
311
  * follows environment variable chains before comparing, so a
@@ -1198,6 +1224,7 @@ var runtimeConfigSemantics = defineBoundarySemantics({
1198
1224
  // comes from outside the code.
1199
1225
  leavesTheProcess: true,
1200
1226
  reportsUnpairedItself: false,
1227
+ findingsAreReadsByName: true,
1201
1228
  identityKey: () => null,
1202
1229
  // A reader sees which deployable's environment this is. Code that
1203
1230
  // reads a variable does not say which deployable runs it, so a read
@@ -1464,7 +1491,21 @@ var SourceLocationSchema = z13.object({
1464
1491
  * project's `suss.json` gives it. Set only when the project lists its
1465
1492
  * modules, and then on every unit whose file is under a module's root.
1466
1493
  */
1467
- module: z13.string().optional()
1494
+ module: z13.string().optional(),
1495
+ /**
1496
+ * The git repository the extract ran in. Summaries from several
1497
+ * repositories can share a folder, and two of them can both have
1498
+ * `src/index.ts::handler`; this says which one each came from, and
1499
+ * which commit, so a link opens the file that was read. `path` is
1500
+ * where `file` is measured from, relative to the repository's top.
1501
+ * Absent outside a repository.
1502
+ */
1503
+ repository: z13.object({
1504
+ name: z13.string(),
1505
+ path: z13.string(),
1506
+ remote: z13.string().optional(),
1507
+ commit: z13.string().optional()
1508
+ }).optional()
1468
1509
  });
1469
1510
  var BoundaryBindingSchema = z13.object({
1470
1511
  transport: z13.string(),
@@ -1529,23 +1570,25 @@ function withDefinitionsInlined(shape, definitions, depth = 0, inProgress = /* @
1529
1570
  /* @__PURE__ */ new Set([...inProgress, key])
1530
1571
  );
1531
1572
  }
1532
- if (shape.type === "record") {
1573
+ return withChildShapes(shape, deeper);
1574
+ }
1575
+ var CHILD_REBUILDS = {
1576
+ record: (shape, each) => {
1577
+ if (shape.type !== "record") {
1578
+ return shape;
1579
+ }
1533
1580
  const properties = {};
1534
1581
  for (const [name, value] of Object.entries(shape.properties)) {
1535
- properties[name] = deeper(value);
1582
+ properties[name] = each(value);
1536
1583
  }
1537
1584
  return { ...shape, properties };
1538
- }
1539
- if (shape.type === "array") {
1540
- return { ...shape, items: deeper(shape.items) };
1541
- }
1542
- if (shape.type === "dictionary") {
1543
- return { ...shape, values: deeper(shape.values) };
1544
- }
1545
- if (shape.type === "union") {
1546
- return { ...shape, variants: shape.variants.map(deeper) };
1547
- }
1548
- return shape;
1585
+ },
1586
+ array: (shape, each) => shape.type === "array" ? { ...shape, items: each(shape.items) } : shape,
1587
+ dictionary: (shape, each) => shape.type === "dictionary" ? { ...shape, values: each(shape.values) } : shape,
1588
+ union: (shape, each) => shape.type === "union" ? { ...shape, variants: shape.variants.map(each) } : shape
1589
+ };
1590
+ function withChildShapes(shape, each) {
1591
+ return CHILD_REBUILDS[shape.type]?.(shape, each) ?? shape;
1549
1592
  }
1550
1593
 
1551
1594
  export {
@@ -1565,6 +1608,7 @@ export {
1565
1608
  busesAgree,
1566
1609
  channelsPair,
1567
1610
  MessageBusSemanticsSchema,
1611
+ MESSAGE_BUS_TRAITS,
1568
1612
  MetricSemanticsSchema,
1569
1613
  dispatchByType,
1570
1614
  parseBoundaryName,
@@ -1612,5 +1656,6 @@ export {
1612
1656
  BoundaryBindingSchema,
1613
1657
  typeDefinitionKey,
1614
1658
  TypeShapeSchema,
1615
- withDefinitionsInlined
1659
+ withDefinitionsInlined,
1660
+ withChildShapes
1616
1661
  };
package/dist/index.cjs CHANGED
@@ -32,6 +32,7 @@ __export(index_exports, {
32
32
  GraphqlOperationSemanticsSchema: () => GraphqlOperationSemanticsSchema,
33
33
  GraphqlResolverSemanticsSchema: () => GraphqlResolverSemanticsSchema,
34
34
  IoSemanticsSchema: () => IoSemanticsSchema,
35
+ MESSAGE_BUS_TRAITS: () => MESSAGE_BUS_TRAITS,
35
36
  MessageBusSemanticsSchema: () => MessageBusSemanticsSchema,
36
37
  MetricSemanticsSchema: () => MetricSemanticsSchema,
37
38
  NOTHING_DEPLOYED: () => NOTHING_DEPLOYED,
@@ -61,12 +62,14 @@ __export(index_exports, {
61
62
  channelsPair: () => channelsPair,
62
63
  codeScopePath: () => codeScopePath,
63
64
  compareRanks: () => compareRanks,
65
+ consumedAs: () => consumedAs,
64
66
  countsForThreshold: () => countsForThreshold,
65
67
  dispatchByType: () => dispatchByType,
66
68
  displayLabel: () => displayLabel,
67
69
  ecsContainerInstanceName: () => ecsContainerInstanceName,
68
70
  exchangesHttpResponses: () => exchangesHttpResponses,
69
71
  fileInCodeScope: () => fileInCodeScope,
72
+ findingsAreReadsByName: () => findingsAreReadsByName,
70
73
  fixedTextLength: () => fixedTextLength,
71
74
  fnIdentityKey: () => fnIdentityKey,
72
75
  formatChannel: () => formatChannel,
@@ -82,6 +85,7 @@ __export(index_exports, {
82
85
  ioIdentityKey: () => ioIdentityKey,
83
86
  isGraphqlOperationBinding: () => isGraphqlOperationBinding,
84
87
  isModuleName: () => isModuleName,
88
+ isUnsettledJob: () => isUnsettledJob,
85
89
  labelWithDetail: () => labelWithDetail,
86
90
  leavesTheProcess: () => leavesTheProcess,
87
91
  messageBusBinding: () => messageBusBinding,
@@ -135,6 +139,7 @@ __export(index_exports, {
135
139
  unitIdentityKey: () => unitIdentityKey,
136
140
  unitInvocationBinding: () => unitInvocationBinding,
137
141
  validateRule: () => validateRule,
142
+ withChildShapes: () => withChildShapes,
138
143
  withDefinitionsInlined: () => withDefinitionsInlined,
139
144
  withRewrittenPaths: () => withRewrittenPaths,
140
145
  withinScope: () => withinScope,
@@ -392,7 +397,11 @@ var MessageBusSemanticsSchema = import_zod5.z.object({
392
397
  "aws_kinesis",
393
398
  "aws_firehose",
394
399
  "gcp_pubsub",
400
+ // Job queues. The header says what their channel is.
395
401
  "bullmq",
402
+ "activejob",
403
+ "sidekiq",
404
+ "celery",
396
405
  "kafka",
397
406
  "nats",
398
407
  "cloudflare-queues",
@@ -408,6 +417,26 @@ var MessageBusSemanticsSchema = import_zod5.z.object({
408
417
  */
409
418
  channel: import_zod5.z.string().min(1).nullable()
410
419
  });
420
+ var MESSAGES = { jobQueue: false };
421
+ var JOBS = { jobQueue: true };
422
+ var MESSAGE_BUS_TRAITS = {
423
+ aws_sqs: MESSAGES,
424
+ "aws.sns": MESSAGES,
425
+ s3: MESSAGES,
426
+ eventbridge: MESSAGES,
427
+ aws_kinesis: MESSAGES,
428
+ aws_firehose: MESSAGES,
429
+ gcp_pubsub: MESSAGES,
430
+ bullmq: JOBS,
431
+ activejob: JOBS,
432
+ sidekiq: JOBS,
433
+ celery: JOBS,
434
+ kafka: MESSAGES,
435
+ nats: MESSAGES,
436
+ "cloudflare-queues": MESSAGES,
437
+ "cloudflare-cron": MESSAGES,
438
+ "cloudflare-tail": MESSAGES
439
+ };
411
440
  var messageBusSemantics = defineBoundarySemantics({
412
441
  name: "message-bus",
413
442
  schema: MessageBusSemanticsSchema,
@@ -424,6 +453,8 @@ var messageBusSemantics = defineBoundarySemantics({
424
453
  * the generic unmatched list leaves them out.
425
454
  */
426
455
  reportsUnpairedItself: true,
456
+ consumedAs: ["reads"],
457
+ unsettledJob: (semantics) => semantics.channel === null && MESSAGE_BUS_TRAITS[semantics.messageBus].jobQueue,
427
458
  /**
428
459
  * A channel that is null here can still pair. The dedicated pass
429
460
  * follows environment variable chains before comparing, so a
@@ -1342,6 +1373,7 @@ var runtimeConfigSemantics = defineBoundarySemantics({
1342
1373
  // comes from outside the code.
1343
1374
  leavesTheProcess: true,
1344
1375
  reportsUnpairedItself: false,
1376
+ findingsAreReadsByName: true,
1345
1377
  identityKey: () => null,
1346
1378
  // A reader sees which deployable's environment this is. Code that
1347
1379
  // reads a variable does not say which deployable runs it, so a read
@@ -1608,7 +1640,21 @@ var SourceLocationSchema = import_zod13.z.object({
1608
1640
  * project's `suss.json` gives it. Set only when the project lists its
1609
1641
  * modules, and then on every unit whose file is under a module's root.
1610
1642
  */
1611
- module: import_zod13.z.string().optional()
1643
+ module: import_zod13.z.string().optional(),
1644
+ /**
1645
+ * The git repository the extract ran in. Summaries from several
1646
+ * repositories can share a folder, and two of them can both have
1647
+ * `src/index.ts::handler`; this says which one each came from, and
1648
+ * which commit, so a link opens the file that was read. `path` is
1649
+ * where `file` is measured from, relative to the repository's top.
1650
+ * Absent outside a repository.
1651
+ */
1652
+ repository: import_zod13.z.object({
1653
+ name: import_zod13.z.string(),
1654
+ path: import_zod13.z.string(),
1655
+ remote: import_zod13.z.string().optional(),
1656
+ commit: import_zod13.z.string().optional()
1657
+ }).optional()
1612
1658
  });
1613
1659
  var BoundaryBindingSchema = import_zod13.z.object({
1614
1660
  transport: import_zod13.z.string(),
@@ -1673,23 +1719,25 @@ function withDefinitionsInlined(shape, definitions, depth = 0, inProgress = /* @
1673
1719
  /* @__PURE__ */ new Set([...inProgress, key])
1674
1720
  );
1675
1721
  }
1676
- if (shape.type === "record") {
1722
+ return withChildShapes(shape, deeper);
1723
+ }
1724
+ var CHILD_REBUILDS = {
1725
+ record: (shape, each) => {
1726
+ if (shape.type !== "record") {
1727
+ return shape;
1728
+ }
1677
1729
  const properties = {};
1678
1730
  for (const [name, value] of Object.entries(shape.properties)) {
1679
- properties[name] = deeper(value);
1731
+ properties[name] = each(value);
1680
1732
  }
1681
1733
  return { ...shape, properties };
1682
- }
1683
- if (shape.type === "array") {
1684
- return { ...shape, items: deeper(shape.items) };
1685
- }
1686
- if (shape.type === "dictionary") {
1687
- return { ...shape, values: deeper(shape.values) };
1688
- }
1689
- if (shape.type === "union") {
1690
- return { ...shape, variants: shape.variants.map(deeper) };
1691
- }
1692
- return shape;
1734
+ },
1735
+ array: (shape, each) => shape.type === "array" ? { ...shape, items: each(shape.items) } : shape,
1736
+ dictionary: (shape, each) => shape.type === "dictionary" ? { ...shape, values: each(shape.values) } : shape,
1737
+ union: (shape, each) => shape.type === "union" ? { ...shape, variants: shape.variants.map(each) } : shape
1738
+ };
1739
+ function withChildShapes(shape, each) {
1740
+ return CHILD_REBUILDS[shape.type]?.(shape, each) ?? shape;
1693
1741
  }
1694
1742
 
1695
1743
  // src/semconv.ts
@@ -1803,6 +1851,15 @@ function exchangesHttpResponses(binding) {
1803
1851
  function leavesTheProcess(binding) {
1804
1852
  return behaviorOf(binding.semantics).leavesTheProcess;
1805
1853
  }
1854
+ function findingsAreReadsByName(binding) {
1855
+ return behaviorOf(binding.semantics).findingsAreReadsByName === true;
1856
+ }
1857
+ function consumedAs(binding) {
1858
+ return behaviorOf(binding.semantics).consumedAs ?? ["reads", "writes"];
1859
+ }
1860
+ function isUnsettledJob(binding) {
1861
+ return behaviorOf(binding.semantics).unsettledJob?.(binding.semantics) ?? false;
1862
+ }
1806
1863
  function canPair(binding) {
1807
1864
  const behavior = behaviorOf(binding.semantics);
1808
1865
  if (behavior.canPair !== void 0) {
@@ -1888,15 +1945,27 @@ function fileInCodeScope(file, scope) {
1888
1945
  const path = codeScopePath(file);
1889
1946
  return path === prefix || path.startsWith(`${prefix}/`);
1890
1947
  }
1891
- function parseHandler(handler) {
1948
+ function parseHandler(handler, runtime) {
1892
1949
  const trimmed = handler.trim();
1893
- const lastDot = trimmed.lastIndexOf(".");
1894
- if (lastDot <= 0 || lastDot === trimmed.length - 1) {
1950
+ return HANDLER_SPLITS[handlerSpelling(trimmed, runtime)](trimmed);
1951
+ }
1952
+ function handlerSpelling(handler, runtime) {
1953
+ if (runtime !== void 0) {
1954
+ return runtime.trim().toLowerCase().startsWith("ruby") ? "ruby" : "lastDot";
1955
+ }
1956
+ return handler.includes("::") ? "ruby" : "lastDot";
1957
+ }
1958
+ var HANDLER_SPLITS = {
1959
+ lastDot: (handler) => splitAt(handler, handler.lastIndexOf(".")),
1960
+ ruby: (handler) => splitAt(handler, handler.indexOf(".", handler.lastIndexOf("/") + 1))
1961
+ };
1962
+ function splitAt(handler, dot) {
1963
+ if (dot <= 0 || dot === handler.length - 1) {
1895
1964
  return null;
1896
1965
  }
1897
1966
  return {
1898
- modulePath: trimmed.slice(0, lastDot),
1899
- exportName: trimmed.slice(lastDot + 1)
1967
+ modulePath: handler.slice(0, dot),
1968
+ exportName: handler.slice(dot + 1)
1900
1969
  };
1901
1970
  }
1902
1971
 
@@ -2003,6 +2072,13 @@ var SuppressionRuleSchema = import_zod15.z.object({
2003
2072
  * only intent findings about a scenario with that title.
2004
2073
  */
2005
2074
  scenario: import_zod15.z.string().optional(),
2075
+ /**
2076
+ * The deployments, by name, that a finding about one environment read
2077
+ * is accepted for. The rule takes them off the finding's list, and
2078
+ * the finding stays while any deployment it lists is left. Without
2079
+ * this, a rule covers every deployment.
2080
+ */
2081
+ deployments: import_zod15.z.array(import_zod15.z.string().min(1)).min(1).optional(),
2006
2082
  /**
2007
2083
  * "narrow", the default, requires `kind` plus one of `boundary`,
2008
2084
  * `scenario`, `consumer.transitionId` or `provider.transitionId`, so
@@ -2392,6 +2468,7 @@ function ioBinding(opts) {
2392
2468
  GraphqlOperationSemanticsSchema,
2393
2469
  GraphqlResolverSemanticsSchema,
2394
2470
  IoSemanticsSchema,
2471
+ MESSAGE_BUS_TRAITS,
2395
2472
  MessageBusSemanticsSchema,
2396
2473
  MetricSemanticsSchema,
2397
2474
  NOTHING_DEPLOYED,
@@ -2421,12 +2498,14 @@ function ioBinding(opts) {
2421
2498
  channelsPair,
2422
2499
  codeScopePath,
2423
2500
  compareRanks,
2501
+ consumedAs,
2424
2502
  countsForThreshold,
2425
2503
  dispatchByType,
2426
2504
  displayLabel,
2427
2505
  ecsContainerInstanceName,
2428
2506
  exchangesHttpResponses,
2429
2507
  fileInCodeScope,
2508
+ findingsAreReadsByName,
2430
2509
  fixedTextLength,
2431
2510
  fnIdentityKey,
2432
2511
  formatChannel,
@@ -2442,6 +2521,7 @@ function ioBinding(opts) {
2442
2521
  ioIdentityKey,
2443
2522
  isGraphqlOperationBinding,
2444
2523
  isModuleName,
2524
+ isUnsettledJob,
2445
2525
  labelWithDetail,
2446
2526
  leavesTheProcess,
2447
2527
  messageBusBinding,
@@ -2495,6 +2575,7 @@ function ioBinding(opts) {
2495
2575
  unitIdentityKey,
2496
2576
  unitInvocationBinding,
2497
2577
  validateRule,
2578
+ withChildShapes,
2498
2579
  withDefinitionsInlined,
2499
2580
  withRewrittenPaths,
2500
2581
  withinScope,
package/dist/index.d.cts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { z } from 'zod';
2
- import { T as TypeShape, M as MessageBusSemantics, D as DeployableUnit, S as Semantics, B as BoundaryBindingSchema, C as ConfidenceInfoSchema, a as ConfidenceLevelSchema, b as ConfidenceSourceSchema, c as CorroborationSchema, d as SourceLocationSchema, e as MessageBusTechnology } from './schemas-lfg8kvak.cjs';
3
- export { f as DeployableUnitSchema, E as EVERY_FIELD, F as FunctionCallSemantics, g as FunctionCallSemanticsSchema, G as GraphqlOperationSemantics, h as GraphqlOperationSemanticsSchema, i as GraphqlResolverSemantics, j as GraphqlResolverSemanticsSchema, k as MessageBusSemanticsSchema, R as RestSemantics, l as RestSemanticsSchema, m as RuntimeConfigSemantics, n as RuntimeConfigSemanticsSchema, o as SemanticsSchema, p as StorageSemantics, q as StorageSemanticsSchema, r as TypeShapeSchema, s as ecsContainerInstanceName, t as isModuleName, u as methodsAgree, v as normalizePath, w as pathShape, x as routePathAdmits, y as routePathsMeet, z as storageContainerLabel, A as storageLabel, H as storageSystemLabel, I as typeDefinitionKey, J as withDefinitionsInlined } from './schemas-lfg8kvak.cjs';
2
+ import { T as TypeShape, M as MessageBusSemantics, D as DeployableUnit, S as Semantics, B as BoundaryBindingSchema, C as ConfidenceInfoSchema, a as ConfidenceLevelSchema, b as ConfidenceSourceSchema, c as CorroborationSchema, d as SourceLocationSchema, e as MessageBusTechnology } from './schemas-CL8yCMd0.cjs';
3
+ export { f as DeployableUnitSchema, E as EVERY_FIELD, F as FunctionCallSemantics, g as FunctionCallSemanticsSchema, G as GraphqlOperationSemantics, h as GraphqlOperationSemanticsSchema, i as GraphqlResolverSemantics, j as GraphqlResolverSemanticsSchema, k as MESSAGE_BUS_TRAITS, l as MessageBusSemanticsSchema, R as RestSemantics, m as RestSemanticsSchema, n as RuntimeConfigSemantics, o as RuntimeConfigSemanticsSchema, p as SemanticsSchema, q as StorageSemantics, r as StorageSemanticsSchema, s as TypeShapeSchema, t as ecsContainerInstanceName, u as isModuleName, v as methodsAgree, w as normalizePath, x as pathShape, y as routePathAdmits, z as routePathsMeet, A as storageContainerLabel, H as storageLabel, I as storageSystemLabel, J as typeDefinitionKey, K as withChildShapes, L as withDefinitionsInlined } from './schemas-CL8yCMd0.cjs';
4
4
 
5
5
  /**
6
6
  * The boundary-name syntax, parsed and printed in one place.
@@ -141,6 +141,38 @@ interface Deployment {
141
141
  /** A deployment that settles nothing, for a run with no template in it. */
142
142
  declare const NOTHING_DEPLOYED: Deployment;
143
143
 
144
+ /**
145
+ * What a unit does at a boundary, in the words `suss ask` uses.
146
+ *
147
+ * A user asks `what writes postgresql:invoices`, and an intent doc
148
+ * asserts "this outcome writes postgresql:invoices". The report, the
149
+ * question parser and the intent reader all have to spell the verbs the
150
+ * same way, so the verbs are defined here once.
151
+ *
152
+ * `provides` is a boundary the unit serves. `reads`, `writes` and
153
+ * `invokes` are what a call site does at a boundary somebody else
154
+ * serves. Calling a deployed unit by name is its own act, so it gets
155
+ * its own verb.
156
+ */
157
+
158
+ declare const RelationSchema: z.ZodEnum<{
159
+ provides: "provides";
160
+ reads: "reads";
161
+ writes: "writes";
162
+ invokes: "invokes";
163
+ }>;
164
+ type Relation = z.infer<typeof RelationSchema>;
165
+ /**
166
+ * The verbs an effect can have. A boundary a unit serves is not an
167
+ * effect of the unit, so `provides` is not one of them.
168
+ */
169
+ declare const EffectRelationSchema: z.ZodEnum<{
170
+ reads: "reads";
171
+ writes: "writes";
172
+ invokes: "invokes";
173
+ }>;
174
+ type EffectRelation = z.infer<typeof EffectRelationSchema>;
175
+
144
176
  /**
145
177
  * Structural comparison of two TypeShapes.
146
178
  *
@@ -340,6 +372,25 @@ interface BoundaryBehavior<S extends {
340
372
  * paired with nothing, so the generic unmatched list can leave it out.
341
373
  */
342
374
  reportsUnpairedItself: boolean;
375
+ /**
376
+ * Whether a finding with the reader on both sides is about one read,
377
+ * with the name read as its field, as an environment variable is. A
378
+ * rule accepts such a finding by the boundary and that name, so it
379
+ * keeps matching when the reader moves to another file.
380
+ */
381
+ findingsAreReadsByName?: boolean;
382
+ /**
383
+ * What a consumer bound to this boundary does there. A client of a
384
+ * route sends a request and reads the response, which is the default.
385
+ * A consumer of a channel only receives, so it reads.
386
+ */
387
+ consumedAs?: readonly Relation[];
388
+ /**
389
+ * Whether a send on this boundary enqueues a background job its pack
390
+ * could not settle, so the summary says what the job does is missing.
391
+ * A protocol that never sends a job leaves this undefined.
392
+ */
393
+ unsettledJob?(semantics: S): boolean;
343
394
  /**
344
395
  * Whether a boundary with these semantics can pair with anything.
345
396
  * Defaults to a non-null pairing key. A protocol whose dedicated
@@ -493,6 +544,14 @@ interface PackConfiguration {
493
544
  * not say.
494
545
  */
495
546
  readFromProject?: (projectRoot: string) => Record<string, unknown> | null;
547
+ /**
548
+ * The options whose value is a file or directory path, either one
549
+ * string or a list of them. A relative one is read against the config
550
+ * file, so a file kept outside the project points somewhere else. The
551
+ * CLI reports each path where nothing exists, instead of letting the
552
+ * pack look up classes in a directory that is not there.
553
+ */
554
+ paths?: readonly string[];
496
555
  }
497
556
  interface PackDeclaration {
498
557
  /**
@@ -630,6 +689,12 @@ declare function normalizeRuleBoundary(raw: string): string;
630
689
  declare function exchangesHttpResponses(binding: BoundaryBinding): boolean;
631
690
  /** Whether crossing this boundary leaves the process. */
632
691
  declare function leavesTheProcess(binding: BoundaryBinding): boolean;
692
+ /** Whether a finding at this binding with the reader on both sides is about one read of the name in its field. */
693
+ declare function findingsAreReadsByName(binding: BoundaryBinding): boolean;
694
+ /** What a consumer bound to this binding does there, reading and writing unless its protocol says otherwise. */
695
+ declare function consumedAs(binding: BoundaryBinding): readonly Relation[];
696
+ /** Whether a send on this binding enqueues a background job nothing settled. */
697
+ declare function isUnsettledJob(binding: BoundaryBinding): boolean;
633
698
  /**
634
699
  * Whether anything can pair with this binding: it has a pairing key,
635
700
  * or its protocol pairs keyless boundaries in a dedicated pass.
@@ -761,15 +826,28 @@ declare function codeScopePath(raw: string): string;
761
826
  declare function fileInCodeScope(file: string, scope: string): boolean;
762
827
  interface ParsedHandler {
763
828
  modulePath: string;
829
+ /**
830
+ * The function the platform calls, written the way the module's
831
+ * language writes it: `handler`, or `Billing::Handler.process` for a
832
+ * class method in Ruby.
833
+ */
764
834
  exportName: string;
765
835
  }
766
836
  /**
767
- * Split a handler string into its module path and exported symbol.
768
- * The final dot separates them: `"src/handlers/confirmToken.handler"` →
837
+ * Split a handler string into its module path and the function the
838
+ * platform calls. Most runtimes put the function after the final dot:
839
+ * `"src/handlers/confirmToken.handler"` gives
769
840
  * `{ modulePath: "src/handlers/confirmToken", exportName: "handler" }`.
841
+ *
842
+ * Ruby writes `file.method` or `file.Class.method`, and the class can be
843
+ * namespaced, as in `app.Billing::Handler.process`. A Ruby file name has
844
+ * no dot, so the module ends at the first dot. The runtime, when the
845
+ * manifest gives one, says which language wrote the handler; without
846
+ * one, a `::` marks a Ruby class.
847
+ *
770
848
  * Returns null when there's no dot, since there's no export to bind to.
771
849
  */
772
- declare function parseHandler(handler: string): ParsedHandler | null;
850
+ declare function parseHandler(handler: string, runtime?: string): ParsedHandler | null;
773
851
 
774
852
  /**
775
853
  * Dispatch on a discriminated union through a mapped-type Record, so a
@@ -813,38 +891,6 @@ declare function dispatchByType<T extends {
813
891
  */
814
892
  declare const PLATFORM_INJECTED_ENV_VARS: Record<DeployableUnit["deploymentTarget"], ReadonlyArray<string>>;
815
893
 
816
- /**
817
- * What a unit does at a boundary, in the words `suss ask` uses.
818
- *
819
- * A user asks `what writes postgresql:invoices`, and an intent doc
820
- * asserts "this outcome writes postgresql:invoices". The report, the
821
- * question parser and the intent reader all have to spell the verbs the
822
- * same way, so the verbs are defined here once.
823
- *
824
- * `provides` is a boundary the unit serves. `reads`, `writes` and
825
- * `invokes` are what a call site does at a boundary somebody else
826
- * serves. Calling a deployed unit by name is its own act, so it gets
827
- * its own verb.
828
- */
829
-
830
- declare const RelationSchema: z.ZodEnum<{
831
- provides: "provides";
832
- reads: "reads";
833
- writes: "writes";
834
- invokes: "invokes";
835
- }>;
836
- type Relation = z.infer<typeof RelationSchema>;
837
- /**
838
- * The verbs an effect can have. A boundary a unit serves is not an
839
- * effect of the unit, so `provides` is not one of them.
840
- */
841
- declare const EffectRelationSchema: z.ZodEnum<{
842
- reads: "reads";
843
- writes: "writes";
844
- invokes: "invokes";
845
- }>;
846
- type EffectRelation = z.infer<typeof EffectRelationSchema>;
847
-
848
894
  /**
849
895
  * Whether two route paths describe a request in common.
850
896
  *
@@ -901,6 +947,7 @@ declare const SuppressionRuleSchema: z.ZodObject<{
901
947
  field: z.ZodOptional<z.ZodString>;
902
948
  }, z.core.$strip>>;
903
949
  scenario: z.ZodOptional<z.ZodString>;
950
+ deployments: z.ZodOptional<z.ZodArray<z.ZodString>>;
904
951
  scope: z.ZodDefault<z.ZodEnum<{
905
952
  narrow: "narrow";
906
953
  broad: "broad";
@@ -929,6 +976,7 @@ declare const SuppressionFileSchema: z.ZodObject<{
929
976
  field: z.ZodOptional<z.ZodString>;
930
977
  }, z.core.$strip>>;
931
978
  scenario: z.ZodOptional<z.ZodString>;
979
+ deployments: z.ZodOptional<z.ZodArray<z.ZodString>>;
932
980
  scope: z.ZodDefault<z.ZodEnum<{
933
981
  narrow: "narrow";
934
982
  broad: "broad";
@@ -1211,4 +1259,4 @@ declare function ioBinding(opts: {
1211
1259
  target: string | null;
1212
1260
  }): BoundaryBinding;
1213
1261
 
1214
- export { type BoundaryBehavior, type BoundaryBinding, BoundaryBindingSchema, type BoundaryName, type BoundarySemanticsDefinition, type BusIdentityKey, type Channel, type ConfidenceInfo, ConfidenceInfoSchema, type ConfidenceLevel, ConfidenceLevelSchema, type ConfidenceSource, ConfidenceSourceSchema, type Corroboration, CorroborationSchema, DeployableUnit, type Deployment, type DispatchTable, type Ecosystem, type EffectRelation, EffectRelationSchema, type FindingSuppression, type FnIdentityKey, type GqlIdentityKey, type HoleRange, type IoIdentityKey, type IoSemantics, IoSemanticsSchema, type MatchResult, MessageBusSemantics, MessageBusTechnology, type MetricIdentityKey, type MetricSemantics, MetricSemanticsSchema, NOTHING_DEPLOYED, type NamePart, PLATFORM_INJECTED_ENV_VARS, type PackConfiguration, type PackDeclaration, type ParsedChannel, type ParsedHandler, type Reference, type Relation, RelationSchema, Semantics, type SemconvAttribute, type SemconvMapping, type SourceLocation, SourceLocationSchema, type SuppressableSeverity, type SuppressibleFinding, type SuppressionFile, SuppressionFileSchema, type SuppressionRule, SuppressionRuleSchema, TEST_TITLE_SEPARATOR, TypeShape, type UnitIdentityKey, type UnitInvocationSemantics, UnitInvocationSemanticsSchema, applySuppressionsToFindings, bindingIs, bindingTokens, bodyShapesMatch, boundaryKey, boundaryLabel, boundaryNameString, bucketsMeet, busIdentityKey, busesAgree, canPair, channelsPair, codeScopePath, compareRanks, countsForThreshold, dispatchByType, displayLabel, exchangesHttpResponses, fileInCodeScope, fixedTextLength, fnIdentityKey, formatChannel, functionCallBinding, gqlIdentityKey, graphqlOperationBinding, graphqlResolverBinding, groundBinding, groundedPairingKey, hasNameHole, hostCanBeOwn, ioBinding, ioIdentityKey, isGraphqlOperationBinding, labelWithDetail, leavesTheProcess, messageBusBinding, metricBinding, metricIdentityKey, moduleExportBinding, namePatternFromSub, namePatternKey, nameReference, namesAgree, namesBoundary, namesBoundaryExactly, namesNothing, normalizeRuleBoundary, operationKey, packageExportBinding, pairRank, pairingKey, parseBoundaryName, parseChannel, parseHandler, pathAfterOrigin, patternHole, rangedHole, referenceFromName, referenceName, referenceOf, reportsUnpairedItself, resourceNameIn, restBinding, ruleBoundaryMatchesKey, runtimeConfigBinding, semanticsAgree, semconvAttributes, servesRequest, setPiece, spansBuckets, spellingTokens, statesAnOrigin, storageBinding, testUnitName, unitIdentityKey, unitInvocationBinding, validateRule, withRewrittenPaths, withinScope, withoutOwnHost };
1262
+ export { type BoundaryBehavior, type BoundaryBinding, BoundaryBindingSchema, type BoundaryName, type BoundarySemanticsDefinition, type BusIdentityKey, type Channel, type ConfidenceInfo, ConfidenceInfoSchema, type ConfidenceLevel, ConfidenceLevelSchema, type ConfidenceSource, ConfidenceSourceSchema, type Corroboration, CorroborationSchema, DeployableUnit, type Deployment, type DispatchTable, type Ecosystem, type EffectRelation, EffectRelationSchema, type FindingSuppression, type FnIdentityKey, type GqlIdentityKey, type HoleRange, type IoIdentityKey, type IoSemantics, IoSemanticsSchema, type MatchResult, MessageBusSemantics, MessageBusTechnology, type MetricIdentityKey, type MetricSemantics, MetricSemanticsSchema, NOTHING_DEPLOYED, type NamePart, PLATFORM_INJECTED_ENV_VARS, type PackConfiguration, type PackDeclaration, type ParsedChannel, type ParsedHandler, type Reference, type Relation, RelationSchema, Semantics, type SemconvAttribute, type SemconvMapping, type SourceLocation, SourceLocationSchema, type SuppressableSeverity, type SuppressibleFinding, type SuppressionFile, SuppressionFileSchema, type SuppressionRule, SuppressionRuleSchema, TEST_TITLE_SEPARATOR, TypeShape, type UnitIdentityKey, type UnitInvocationSemantics, UnitInvocationSemanticsSchema, applySuppressionsToFindings, bindingIs, bindingTokens, bodyShapesMatch, boundaryKey, boundaryLabel, boundaryNameString, bucketsMeet, busIdentityKey, busesAgree, canPair, channelsPair, codeScopePath, compareRanks, consumedAs, countsForThreshold, dispatchByType, displayLabel, exchangesHttpResponses, fileInCodeScope, findingsAreReadsByName, fixedTextLength, fnIdentityKey, formatChannel, functionCallBinding, gqlIdentityKey, graphqlOperationBinding, graphqlResolverBinding, groundBinding, groundedPairingKey, hasNameHole, hostCanBeOwn, ioBinding, ioIdentityKey, isGraphqlOperationBinding, isUnsettledJob, labelWithDetail, leavesTheProcess, messageBusBinding, metricBinding, metricIdentityKey, moduleExportBinding, namePatternFromSub, namePatternKey, nameReference, namesAgree, namesBoundary, namesBoundaryExactly, namesNothing, normalizeRuleBoundary, operationKey, packageExportBinding, pairRank, pairingKey, parseBoundaryName, parseChannel, parseHandler, pathAfterOrigin, patternHole, rangedHole, referenceFromName, referenceName, referenceOf, reportsUnpairedItself, resourceNameIn, restBinding, ruleBoundaryMatchesKey, runtimeConfigBinding, semanticsAgree, semconvAttributes, servesRequest, setPiece, spansBuckets, spellingTokens, statesAnOrigin, storageBinding, testUnitName, unitIdentityKey, unitInvocationBinding, validateRule, withRewrittenPaths, withinScope, withoutOwnHost };
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { z } from 'zod';
2
- import { T as TypeShape, M as MessageBusSemantics, D as DeployableUnit, S as Semantics, B as BoundaryBindingSchema, C as ConfidenceInfoSchema, a as ConfidenceLevelSchema, b as ConfidenceSourceSchema, c as CorroborationSchema, d as SourceLocationSchema, e as MessageBusTechnology } from './schemas-lfg8kvak.js';
3
- export { f as DeployableUnitSchema, E as EVERY_FIELD, F as FunctionCallSemantics, g as FunctionCallSemanticsSchema, G as GraphqlOperationSemantics, h as GraphqlOperationSemanticsSchema, i as GraphqlResolverSemantics, j as GraphqlResolverSemanticsSchema, k as MessageBusSemanticsSchema, R as RestSemantics, l as RestSemanticsSchema, m as RuntimeConfigSemantics, n as RuntimeConfigSemanticsSchema, o as SemanticsSchema, p as StorageSemantics, q as StorageSemanticsSchema, r as TypeShapeSchema, s as ecsContainerInstanceName, t as isModuleName, u as methodsAgree, v as normalizePath, w as pathShape, x as routePathAdmits, y as routePathsMeet, z as storageContainerLabel, A as storageLabel, H as storageSystemLabel, I as typeDefinitionKey, J as withDefinitionsInlined } from './schemas-lfg8kvak.js';
2
+ import { T as TypeShape, M as MessageBusSemantics, D as DeployableUnit, S as Semantics, B as BoundaryBindingSchema, C as ConfidenceInfoSchema, a as ConfidenceLevelSchema, b as ConfidenceSourceSchema, c as CorroborationSchema, d as SourceLocationSchema, e as MessageBusTechnology } from './schemas-CL8yCMd0.js';
3
+ export { f as DeployableUnitSchema, E as EVERY_FIELD, F as FunctionCallSemantics, g as FunctionCallSemanticsSchema, G as GraphqlOperationSemantics, h as GraphqlOperationSemanticsSchema, i as GraphqlResolverSemantics, j as GraphqlResolverSemanticsSchema, k as MESSAGE_BUS_TRAITS, l as MessageBusSemanticsSchema, R as RestSemantics, m as RestSemanticsSchema, n as RuntimeConfigSemantics, o as RuntimeConfigSemanticsSchema, p as SemanticsSchema, q as StorageSemantics, r as StorageSemanticsSchema, s as TypeShapeSchema, t as ecsContainerInstanceName, u as isModuleName, v as methodsAgree, w as normalizePath, x as pathShape, y as routePathAdmits, z as routePathsMeet, A as storageContainerLabel, H as storageLabel, I as storageSystemLabel, J as typeDefinitionKey, K as withChildShapes, L as withDefinitionsInlined } from './schemas-CL8yCMd0.js';
4
4
 
5
5
  /**
6
6
  * The boundary-name syntax, parsed and printed in one place.
@@ -141,6 +141,38 @@ interface Deployment {
141
141
  /** A deployment that settles nothing, for a run with no template in it. */
142
142
  declare const NOTHING_DEPLOYED: Deployment;
143
143
 
144
+ /**
145
+ * What a unit does at a boundary, in the words `suss ask` uses.
146
+ *
147
+ * A user asks `what writes postgresql:invoices`, and an intent doc
148
+ * asserts "this outcome writes postgresql:invoices". The report, the
149
+ * question parser and the intent reader all have to spell the verbs the
150
+ * same way, so the verbs are defined here once.
151
+ *
152
+ * `provides` is a boundary the unit serves. `reads`, `writes` and
153
+ * `invokes` are what a call site does at a boundary somebody else
154
+ * serves. Calling a deployed unit by name is its own act, so it gets
155
+ * its own verb.
156
+ */
157
+
158
+ declare const RelationSchema: z.ZodEnum<{
159
+ provides: "provides";
160
+ reads: "reads";
161
+ writes: "writes";
162
+ invokes: "invokes";
163
+ }>;
164
+ type Relation = z.infer<typeof RelationSchema>;
165
+ /**
166
+ * The verbs an effect can have. A boundary a unit serves is not an
167
+ * effect of the unit, so `provides` is not one of them.
168
+ */
169
+ declare const EffectRelationSchema: z.ZodEnum<{
170
+ reads: "reads";
171
+ writes: "writes";
172
+ invokes: "invokes";
173
+ }>;
174
+ type EffectRelation = z.infer<typeof EffectRelationSchema>;
175
+
144
176
  /**
145
177
  * Structural comparison of two TypeShapes.
146
178
  *
@@ -340,6 +372,25 @@ interface BoundaryBehavior<S extends {
340
372
  * paired with nothing, so the generic unmatched list can leave it out.
341
373
  */
342
374
  reportsUnpairedItself: boolean;
375
+ /**
376
+ * Whether a finding with the reader on both sides is about one read,
377
+ * with the name read as its field, as an environment variable is. A
378
+ * rule accepts such a finding by the boundary and that name, so it
379
+ * keeps matching when the reader moves to another file.
380
+ */
381
+ findingsAreReadsByName?: boolean;
382
+ /**
383
+ * What a consumer bound to this boundary does there. A client of a
384
+ * route sends a request and reads the response, which is the default.
385
+ * A consumer of a channel only receives, so it reads.
386
+ */
387
+ consumedAs?: readonly Relation[];
388
+ /**
389
+ * Whether a send on this boundary enqueues a background job its pack
390
+ * could not settle, so the summary says what the job does is missing.
391
+ * A protocol that never sends a job leaves this undefined.
392
+ */
393
+ unsettledJob?(semantics: S): boolean;
343
394
  /**
344
395
  * Whether a boundary with these semantics can pair with anything.
345
396
  * Defaults to a non-null pairing key. A protocol whose dedicated
@@ -493,6 +544,14 @@ interface PackConfiguration {
493
544
  * not say.
494
545
  */
495
546
  readFromProject?: (projectRoot: string) => Record<string, unknown> | null;
547
+ /**
548
+ * The options whose value is a file or directory path, either one
549
+ * string or a list of them. A relative one is read against the config
550
+ * file, so a file kept outside the project points somewhere else. The
551
+ * CLI reports each path where nothing exists, instead of letting the
552
+ * pack look up classes in a directory that is not there.
553
+ */
554
+ paths?: readonly string[];
496
555
  }
497
556
  interface PackDeclaration {
498
557
  /**
@@ -630,6 +689,12 @@ declare function normalizeRuleBoundary(raw: string): string;
630
689
  declare function exchangesHttpResponses(binding: BoundaryBinding): boolean;
631
690
  /** Whether crossing this boundary leaves the process. */
632
691
  declare function leavesTheProcess(binding: BoundaryBinding): boolean;
692
+ /** Whether a finding at this binding with the reader on both sides is about one read of the name in its field. */
693
+ declare function findingsAreReadsByName(binding: BoundaryBinding): boolean;
694
+ /** What a consumer bound to this binding does there, reading and writing unless its protocol says otherwise. */
695
+ declare function consumedAs(binding: BoundaryBinding): readonly Relation[];
696
+ /** Whether a send on this binding enqueues a background job nothing settled. */
697
+ declare function isUnsettledJob(binding: BoundaryBinding): boolean;
633
698
  /**
634
699
  * Whether anything can pair with this binding: it has a pairing key,
635
700
  * or its protocol pairs keyless boundaries in a dedicated pass.
@@ -761,15 +826,28 @@ declare function codeScopePath(raw: string): string;
761
826
  declare function fileInCodeScope(file: string, scope: string): boolean;
762
827
  interface ParsedHandler {
763
828
  modulePath: string;
829
+ /**
830
+ * The function the platform calls, written the way the module's
831
+ * language writes it: `handler`, or `Billing::Handler.process` for a
832
+ * class method in Ruby.
833
+ */
764
834
  exportName: string;
765
835
  }
766
836
  /**
767
- * Split a handler string into its module path and exported symbol.
768
- * The final dot separates them: `"src/handlers/confirmToken.handler"` →
837
+ * Split a handler string into its module path and the function the
838
+ * platform calls. Most runtimes put the function after the final dot:
839
+ * `"src/handlers/confirmToken.handler"` gives
769
840
  * `{ modulePath: "src/handlers/confirmToken", exportName: "handler" }`.
841
+ *
842
+ * Ruby writes `file.method` or `file.Class.method`, and the class can be
843
+ * namespaced, as in `app.Billing::Handler.process`. A Ruby file name has
844
+ * no dot, so the module ends at the first dot. The runtime, when the
845
+ * manifest gives one, says which language wrote the handler; without
846
+ * one, a `::` marks a Ruby class.
847
+ *
770
848
  * Returns null when there's no dot, since there's no export to bind to.
771
849
  */
772
- declare function parseHandler(handler: string): ParsedHandler | null;
850
+ declare function parseHandler(handler: string, runtime?: string): ParsedHandler | null;
773
851
 
774
852
  /**
775
853
  * Dispatch on a discriminated union through a mapped-type Record, so a
@@ -813,38 +891,6 @@ declare function dispatchByType<T extends {
813
891
  */
814
892
  declare const PLATFORM_INJECTED_ENV_VARS: Record<DeployableUnit["deploymentTarget"], ReadonlyArray<string>>;
815
893
 
816
- /**
817
- * What a unit does at a boundary, in the words `suss ask` uses.
818
- *
819
- * A user asks `what writes postgresql:invoices`, and an intent doc
820
- * asserts "this outcome writes postgresql:invoices". The report, the
821
- * question parser and the intent reader all have to spell the verbs the
822
- * same way, so the verbs are defined here once.
823
- *
824
- * `provides` is a boundary the unit serves. `reads`, `writes` and
825
- * `invokes` are what a call site does at a boundary somebody else
826
- * serves. Calling a deployed unit by name is its own act, so it gets
827
- * its own verb.
828
- */
829
-
830
- declare const RelationSchema: z.ZodEnum<{
831
- provides: "provides";
832
- reads: "reads";
833
- writes: "writes";
834
- invokes: "invokes";
835
- }>;
836
- type Relation = z.infer<typeof RelationSchema>;
837
- /**
838
- * The verbs an effect can have. A boundary a unit serves is not an
839
- * effect of the unit, so `provides` is not one of them.
840
- */
841
- declare const EffectRelationSchema: z.ZodEnum<{
842
- reads: "reads";
843
- writes: "writes";
844
- invokes: "invokes";
845
- }>;
846
- type EffectRelation = z.infer<typeof EffectRelationSchema>;
847
-
848
894
  /**
849
895
  * Whether two route paths describe a request in common.
850
896
  *
@@ -901,6 +947,7 @@ declare const SuppressionRuleSchema: z.ZodObject<{
901
947
  field: z.ZodOptional<z.ZodString>;
902
948
  }, z.core.$strip>>;
903
949
  scenario: z.ZodOptional<z.ZodString>;
950
+ deployments: z.ZodOptional<z.ZodArray<z.ZodString>>;
904
951
  scope: z.ZodDefault<z.ZodEnum<{
905
952
  narrow: "narrow";
906
953
  broad: "broad";
@@ -929,6 +976,7 @@ declare const SuppressionFileSchema: z.ZodObject<{
929
976
  field: z.ZodOptional<z.ZodString>;
930
977
  }, z.core.$strip>>;
931
978
  scenario: z.ZodOptional<z.ZodString>;
979
+ deployments: z.ZodOptional<z.ZodArray<z.ZodString>>;
932
980
  scope: z.ZodDefault<z.ZodEnum<{
933
981
  narrow: "narrow";
934
982
  broad: "broad";
@@ -1211,4 +1259,4 @@ declare function ioBinding(opts: {
1211
1259
  target: string | null;
1212
1260
  }): BoundaryBinding;
1213
1261
 
1214
- export { type BoundaryBehavior, type BoundaryBinding, BoundaryBindingSchema, type BoundaryName, type BoundarySemanticsDefinition, type BusIdentityKey, type Channel, type ConfidenceInfo, ConfidenceInfoSchema, type ConfidenceLevel, ConfidenceLevelSchema, type ConfidenceSource, ConfidenceSourceSchema, type Corroboration, CorroborationSchema, DeployableUnit, type Deployment, type DispatchTable, type Ecosystem, type EffectRelation, EffectRelationSchema, type FindingSuppression, type FnIdentityKey, type GqlIdentityKey, type HoleRange, type IoIdentityKey, type IoSemantics, IoSemanticsSchema, type MatchResult, MessageBusSemantics, MessageBusTechnology, type MetricIdentityKey, type MetricSemantics, MetricSemanticsSchema, NOTHING_DEPLOYED, type NamePart, PLATFORM_INJECTED_ENV_VARS, type PackConfiguration, type PackDeclaration, type ParsedChannel, type ParsedHandler, type Reference, type Relation, RelationSchema, Semantics, type SemconvAttribute, type SemconvMapping, type SourceLocation, SourceLocationSchema, type SuppressableSeverity, type SuppressibleFinding, type SuppressionFile, SuppressionFileSchema, type SuppressionRule, SuppressionRuleSchema, TEST_TITLE_SEPARATOR, TypeShape, type UnitIdentityKey, type UnitInvocationSemantics, UnitInvocationSemanticsSchema, applySuppressionsToFindings, bindingIs, bindingTokens, bodyShapesMatch, boundaryKey, boundaryLabel, boundaryNameString, bucketsMeet, busIdentityKey, busesAgree, canPair, channelsPair, codeScopePath, compareRanks, countsForThreshold, dispatchByType, displayLabel, exchangesHttpResponses, fileInCodeScope, fixedTextLength, fnIdentityKey, formatChannel, functionCallBinding, gqlIdentityKey, graphqlOperationBinding, graphqlResolverBinding, groundBinding, groundedPairingKey, hasNameHole, hostCanBeOwn, ioBinding, ioIdentityKey, isGraphqlOperationBinding, labelWithDetail, leavesTheProcess, messageBusBinding, metricBinding, metricIdentityKey, moduleExportBinding, namePatternFromSub, namePatternKey, nameReference, namesAgree, namesBoundary, namesBoundaryExactly, namesNothing, normalizeRuleBoundary, operationKey, packageExportBinding, pairRank, pairingKey, parseBoundaryName, parseChannel, parseHandler, pathAfterOrigin, patternHole, rangedHole, referenceFromName, referenceName, referenceOf, reportsUnpairedItself, resourceNameIn, restBinding, ruleBoundaryMatchesKey, runtimeConfigBinding, semanticsAgree, semconvAttributes, servesRequest, setPiece, spansBuckets, spellingTokens, statesAnOrigin, storageBinding, testUnitName, unitIdentityKey, unitInvocationBinding, validateRule, withRewrittenPaths, withinScope, withoutOwnHost };
1262
+ export { type BoundaryBehavior, type BoundaryBinding, BoundaryBindingSchema, type BoundaryName, type BoundarySemanticsDefinition, type BusIdentityKey, type Channel, type ConfidenceInfo, ConfidenceInfoSchema, type ConfidenceLevel, ConfidenceLevelSchema, type ConfidenceSource, ConfidenceSourceSchema, type Corroboration, CorroborationSchema, DeployableUnit, type Deployment, type DispatchTable, type Ecosystem, type EffectRelation, EffectRelationSchema, type FindingSuppression, type FnIdentityKey, type GqlIdentityKey, type HoleRange, type IoIdentityKey, type IoSemantics, IoSemanticsSchema, type MatchResult, MessageBusSemantics, MessageBusTechnology, type MetricIdentityKey, type MetricSemantics, MetricSemanticsSchema, NOTHING_DEPLOYED, type NamePart, PLATFORM_INJECTED_ENV_VARS, type PackConfiguration, type PackDeclaration, type ParsedChannel, type ParsedHandler, type Reference, type Relation, RelationSchema, Semantics, type SemconvAttribute, type SemconvMapping, type SourceLocation, SourceLocationSchema, type SuppressableSeverity, type SuppressibleFinding, type SuppressionFile, SuppressionFileSchema, type SuppressionRule, SuppressionRuleSchema, TEST_TITLE_SEPARATOR, TypeShape, type UnitIdentityKey, type UnitInvocationSemantics, UnitInvocationSemanticsSchema, applySuppressionsToFindings, bindingIs, bindingTokens, bodyShapesMatch, boundaryKey, boundaryLabel, boundaryNameString, bucketsMeet, busIdentityKey, busesAgree, canPair, channelsPair, codeScopePath, compareRanks, consumedAs, countsForThreshold, dispatchByType, displayLabel, exchangesHttpResponses, fileInCodeScope, findingsAreReadsByName, fixedTextLength, fnIdentityKey, formatChannel, functionCallBinding, gqlIdentityKey, graphqlOperationBinding, graphqlResolverBinding, groundBinding, groundedPairingKey, hasNameHole, hostCanBeOwn, ioBinding, ioIdentityKey, isGraphqlOperationBinding, isUnsettledJob, labelWithDetail, leavesTheProcess, messageBusBinding, metricBinding, metricIdentityKey, moduleExportBinding, namePatternFromSub, namePatternKey, nameReference, namesAgree, namesBoundary, namesBoundaryExactly, namesNothing, normalizeRuleBoundary, operationKey, packageExportBinding, pairRank, pairingKey, parseBoundaryName, parseChannel, parseHandler, pathAfterOrigin, patternHole, rangedHole, referenceFromName, referenceName, referenceOf, reportsUnpairedItself, resourceNameIn, restBinding, ruleBoundaryMatchesKey, runtimeConfigBinding, semanticsAgree, semconvAttributes, servesRequest, setPiece, spansBuckets, spellingTokens, statesAnOrigin, storageBinding, testUnitName, unitIdentityKey, unitInvocationBinding, validateRule, withRewrittenPaths, withinScope, withoutOwnHost };
package/dist/index.js CHANGED
@@ -10,6 +10,7 @@ import {
10
10
  GraphqlOperationSemanticsSchema,
11
11
  GraphqlResolverSemanticsSchema,
12
12
  IoSemanticsSchema,
13
+ MESSAGE_BUS_TRAITS,
13
14
  MessageBusSemanticsSchema,
14
15
  MetricSemanticsSchema,
15
16
  RestSemanticsSchema,
@@ -62,8 +63,9 @@ import {
62
63
  storageSystemLabel,
63
64
  typeDefinitionKey,
64
65
  unitIdentityKey,
66
+ withChildShapes,
65
67
  withDefinitionsInlined
66
- } from "./chunk-A46EUIKC.js";
68
+ } from "./chunk-OROVMQY2.js";
67
69
 
68
70
  // src/semconv.ts
69
71
  function semconvAttributes(binding) {
@@ -176,6 +178,15 @@ function exchangesHttpResponses(binding) {
176
178
  function leavesTheProcess(binding) {
177
179
  return behaviorOf(binding.semantics).leavesTheProcess;
178
180
  }
181
+ function findingsAreReadsByName(binding) {
182
+ return behaviorOf(binding.semantics).findingsAreReadsByName === true;
183
+ }
184
+ function consumedAs(binding) {
185
+ return behaviorOf(binding.semantics).consumedAs ?? ["reads", "writes"];
186
+ }
187
+ function isUnsettledJob(binding) {
188
+ return behaviorOf(binding.semantics).unsettledJob?.(binding.semantics) ?? false;
189
+ }
179
190
  function canPair(binding) {
180
191
  const behavior = behaviorOf(binding.semantics);
181
192
  if (behavior.canPair !== void 0) {
@@ -261,15 +272,27 @@ function fileInCodeScope(file, scope) {
261
272
  const path = codeScopePath(file);
262
273
  return path === prefix || path.startsWith(`${prefix}/`);
263
274
  }
264
- function parseHandler(handler) {
275
+ function parseHandler(handler, runtime) {
265
276
  const trimmed = handler.trim();
266
- const lastDot = trimmed.lastIndexOf(".");
267
- if (lastDot <= 0 || lastDot === trimmed.length - 1) {
277
+ return HANDLER_SPLITS[handlerSpelling(trimmed, runtime)](trimmed);
278
+ }
279
+ function handlerSpelling(handler, runtime) {
280
+ if (runtime !== void 0) {
281
+ return runtime.trim().toLowerCase().startsWith("ruby") ? "ruby" : "lastDot";
282
+ }
283
+ return handler.includes("::") ? "ruby" : "lastDot";
284
+ }
285
+ var HANDLER_SPLITS = {
286
+ lastDot: (handler) => splitAt(handler, handler.lastIndexOf(".")),
287
+ ruby: (handler) => splitAt(handler, handler.indexOf(".", handler.lastIndexOf("/") + 1))
288
+ };
289
+ function splitAt(handler, dot) {
290
+ if (dot <= 0 || dot === handler.length - 1) {
268
291
  return null;
269
292
  }
270
293
  return {
271
- modulePath: trimmed.slice(0, lastDot),
272
- exportName: trimmed.slice(lastDot + 1)
294
+ modulePath: handler.slice(0, dot),
295
+ exportName: handler.slice(dot + 1)
273
296
  };
274
297
  }
275
298
 
@@ -376,6 +399,13 @@ var SuppressionRuleSchema = z2.object({
376
399
  * only intent findings about a scenario with that title.
377
400
  */
378
401
  scenario: z2.string().optional(),
402
+ /**
403
+ * The deployments, by name, that a finding about one environment read
404
+ * is accepted for. The rule takes them off the finding's list, and
405
+ * the finding stays while any deployment it lists is left. Without
406
+ * this, a rule covers every deployment.
407
+ */
408
+ deployments: z2.array(z2.string().min(1)).min(1).optional(),
379
409
  /**
380
410
  * "narrow", the default, requires `kind` plus one of `boundary`,
381
411
  * `scenario`, `consumer.transitionId` or `provider.transitionId`, so
@@ -764,6 +794,7 @@ export {
764
794
  GraphqlOperationSemanticsSchema,
765
795
  GraphqlResolverSemanticsSchema,
766
796
  IoSemanticsSchema,
797
+ MESSAGE_BUS_TRAITS,
767
798
  MessageBusSemanticsSchema,
768
799
  MetricSemanticsSchema,
769
800
  NOTHING_DEPLOYED,
@@ -793,12 +824,14 @@ export {
793
824
  channelsPair,
794
825
  codeScopePath,
795
826
  compareRanks,
827
+ consumedAs,
796
828
  countsForThreshold,
797
829
  dispatchByType,
798
830
  displayLabel,
799
831
  ecsContainerInstanceName,
800
832
  exchangesHttpResponses,
801
833
  fileInCodeScope,
834
+ findingsAreReadsByName,
802
835
  fixedTextLength,
803
836
  fnIdentityKey,
804
837
  formatChannel,
@@ -814,6 +847,7 @@ export {
814
847
  ioIdentityKey,
815
848
  isGraphqlOperationBinding,
816
849
  isModuleName,
850
+ isUnsettledJob,
817
851
  labelWithDetail,
818
852
  leavesTheProcess,
819
853
  messageBusBinding,
@@ -867,6 +901,7 @@ export {
867
901
  unitIdentityKey,
868
902
  unitInvocationBinding,
869
903
  validateRule,
904
+ withChildShapes,
870
905
  withDefinitionsInlined,
871
906
  withRewrittenPaths,
872
907
  withinScope,
@@ -76,6 +76,9 @@ declare const MessageBusSemanticsSchema: z.ZodObject<{
76
76
  aws_firehose: "aws_firehose";
77
77
  gcp_pubsub: "gcp_pubsub";
78
78
  bullmq: "bullmq";
79
+ activejob: "activejob";
80
+ sidekiq: "sidekiq";
81
+ celery: "celery";
79
82
  kafka: "kafka";
80
83
  nats: "nats";
81
84
  "cloudflare-queues": "cloudflare-queues";
@@ -90,6 +93,17 @@ type MessageBusSemantics = z.infer<typeof MessageBusSemanticsSchema>;
90
93
  * so there is no hand-written copy to fall out of step.
91
94
  */
92
95
  type MessageBusTechnology = MessageBusSemantics["messageBus"];
96
+ /** What a bus is like, where the checks treat one bus differently from another. */
97
+ interface MessageBusTraits {
98
+ /**
99
+ * The bus is a background job queue. A send whose job is unsettled
100
+ * leaves a gap, and a job no code enqueues is never an orphan: a
101
+ * scheduler config, another service, or code the run cannot follow
102
+ * may enqueue it.
103
+ */
104
+ jobQueue: boolean;
105
+ }
106
+ declare const MESSAGE_BUS_TRAITS: Record<MessageBusTechnology, MessageBusTraits>;
93
107
 
94
108
  /**
95
109
  * The list of protocol definitions, and the lookups built from it.
@@ -157,6 +171,9 @@ declare const SemanticsSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
157
171
  aws_firehose: "aws_firehose";
158
172
  gcp_pubsub: "gcp_pubsub";
159
173
  bullmq: "bullmq";
174
+ activejob: "activejob";
175
+ sidekiq: "sidekiq";
176
+ celery: "celery";
160
177
  kafka: "kafka";
161
178
  nats: "nats";
162
179
  "cloudflare-queues": "cloudflare-queues";
@@ -365,6 +382,12 @@ declare const SourceLocationSchema: z.ZodObject<{
365
382
  exportName: z.ZodNullable<z.ZodString>;
366
383
  workspace: z.ZodOptional<z.ZodString>;
367
384
  module: z.ZodOptional<z.ZodString>;
385
+ repository: z.ZodOptional<z.ZodObject<{
386
+ name: z.ZodString;
387
+ path: z.ZodString;
388
+ remote: z.ZodOptional<z.ZodString>;
389
+ commit: z.ZodOptional<z.ZodString>;
390
+ }, z.core.$strip>>;
368
391
  }, z.core.$strip>;
369
392
  declare const BoundaryBindingSchema: z.ZodObject<{
370
393
  transport: z.ZodString;
@@ -420,6 +443,9 @@ declare const BoundaryBindingSchema: z.ZodObject<{
420
443
  aws_firehose: "aws_firehose";
421
444
  gcp_pubsub: "gcp_pubsub";
422
445
  bullmq: "bullmq";
446
+ activejob: "activejob";
447
+ sidekiq: "sidekiq";
448
+ celery: "celery";
423
449
  kafka: "kafka";
424
450
  nats: "nats";
425
451
  "cloudflare-queues": "cloudflare-queues";
@@ -529,5 +555,7 @@ declare const TypeShapeSchema: z.ZodType<TypeShape>;
529
555
  * on this path, the same cycle guard the shape walk uses.
530
556
  */
531
557
  declare function withDefinitionsInlined(shape: TypeShape, definitions: Record<string, TypeShape> | undefined, depth?: number, inProgress?: ReadonlySet<string>): TypeShape;
558
+ /** The shape with `each` applied to every shape written directly inside it. One with nothing inside, such as a ref, comes back as it is. */
559
+ declare function withChildShapes(shape: TypeShape, each: (inner: TypeShape) => TypeShape): TypeShape;
532
560
 
533
- export { storageLabel as A, BoundaryBindingSchema as B, ConfidenceInfoSchema as C, type DeployableUnit as D, EVERY_FIELD as E, type FunctionCallSemantics as F, type GraphqlOperationSemantics as G, storageSystemLabel as H, typeDefinitionKey as I, withDefinitionsInlined as J, type MessageBusSemantics as M, type RestSemantics as R, type Semantics as S, type TypeShape as T, ConfidenceLevelSchema as a, ConfidenceSourceSchema as b, CorroborationSchema as c, SourceLocationSchema as d, type MessageBusTechnology as e, DeployableUnitSchema as f, FunctionCallSemanticsSchema as g, GraphqlOperationSemanticsSchema as h, type GraphqlResolverSemantics as i, GraphqlResolverSemanticsSchema as j, MessageBusSemanticsSchema as k, RestSemanticsSchema as l, type RuntimeConfigSemantics as m, RuntimeConfigSemanticsSchema as n, SemanticsSchema as o, type StorageSemantics as p, StorageSemanticsSchema as q, TypeShapeSchema as r, ecsContainerInstanceName as s, isModuleName as t, methodsAgree as u, normalizePath as v, pathShape as w, routePathAdmits as x, routePathsMeet as y, storageContainerLabel as z };
561
+ export { storageContainerLabel as A, BoundaryBindingSchema as B, ConfidenceInfoSchema as C, type DeployableUnit as D, EVERY_FIELD as E, type FunctionCallSemantics as F, type GraphqlOperationSemantics as G, storageLabel as H, storageSystemLabel as I, typeDefinitionKey as J, withChildShapes as K, withDefinitionsInlined as L, type MessageBusSemantics as M, type RestSemantics as R, type Semantics as S, type TypeShape as T, ConfidenceLevelSchema as a, ConfidenceSourceSchema as b, CorroborationSchema as c, SourceLocationSchema as d, type MessageBusTechnology as e, DeployableUnitSchema as f, FunctionCallSemanticsSchema as g, GraphqlOperationSemanticsSchema as h, type GraphqlResolverSemantics as i, GraphqlResolverSemanticsSchema as j, MESSAGE_BUS_TRAITS as k, MessageBusSemanticsSchema as l, RestSemanticsSchema as m, type RuntimeConfigSemantics as n, RuntimeConfigSemanticsSchema as o, SemanticsSchema as p, type StorageSemantics as q, StorageSemanticsSchema as r, TypeShapeSchema as s, ecsContainerInstanceName as t, isModuleName as u, methodsAgree as v, normalizePath as w, pathShape as x, routePathAdmits as y, routePathsMeet as z };
@@ -76,6 +76,9 @@ declare const MessageBusSemanticsSchema: z.ZodObject<{
76
76
  aws_firehose: "aws_firehose";
77
77
  gcp_pubsub: "gcp_pubsub";
78
78
  bullmq: "bullmq";
79
+ activejob: "activejob";
80
+ sidekiq: "sidekiq";
81
+ celery: "celery";
79
82
  kafka: "kafka";
80
83
  nats: "nats";
81
84
  "cloudflare-queues": "cloudflare-queues";
@@ -90,6 +93,17 @@ type MessageBusSemantics = z.infer<typeof MessageBusSemanticsSchema>;
90
93
  * so there is no hand-written copy to fall out of step.
91
94
  */
92
95
  type MessageBusTechnology = MessageBusSemantics["messageBus"];
96
+ /** What a bus is like, where the checks treat one bus differently from another. */
97
+ interface MessageBusTraits {
98
+ /**
99
+ * The bus is a background job queue. A send whose job is unsettled
100
+ * leaves a gap, and a job no code enqueues is never an orphan: a
101
+ * scheduler config, another service, or code the run cannot follow
102
+ * may enqueue it.
103
+ */
104
+ jobQueue: boolean;
105
+ }
106
+ declare const MESSAGE_BUS_TRAITS: Record<MessageBusTechnology, MessageBusTraits>;
93
107
 
94
108
  /**
95
109
  * The list of protocol definitions, and the lookups built from it.
@@ -157,6 +171,9 @@ declare const SemanticsSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
157
171
  aws_firehose: "aws_firehose";
158
172
  gcp_pubsub: "gcp_pubsub";
159
173
  bullmq: "bullmq";
174
+ activejob: "activejob";
175
+ sidekiq: "sidekiq";
176
+ celery: "celery";
160
177
  kafka: "kafka";
161
178
  nats: "nats";
162
179
  "cloudflare-queues": "cloudflare-queues";
@@ -365,6 +382,12 @@ declare const SourceLocationSchema: z.ZodObject<{
365
382
  exportName: z.ZodNullable<z.ZodString>;
366
383
  workspace: z.ZodOptional<z.ZodString>;
367
384
  module: z.ZodOptional<z.ZodString>;
385
+ repository: z.ZodOptional<z.ZodObject<{
386
+ name: z.ZodString;
387
+ path: z.ZodString;
388
+ remote: z.ZodOptional<z.ZodString>;
389
+ commit: z.ZodOptional<z.ZodString>;
390
+ }, z.core.$strip>>;
368
391
  }, z.core.$strip>;
369
392
  declare const BoundaryBindingSchema: z.ZodObject<{
370
393
  transport: z.ZodString;
@@ -420,6 +443,9 @@ declare const BoundaryBindingSchema: z.ZodObject<{
420
443
  aws_firehose: "aws_firehose";
421
444
  gcp_pubsub: "gcp_pubsub";
422
445
  bullmq: "bullmq";
446
+ activejob: "activejob";
447
+ sidekiq: "sidekiq";
448
+ celery: "celery";
423
449
  kafka: "kafka";
424
450
  nats: "nats";
425
451
  "cloudflare-queues": "cloudflare-queues";
@@ -529,5 +555,7 @@ declare const TypeShapeSchema: z.ZodType<TypeShape>;
529
555
  * on this path, the same cycle guard the shape walk uses.
530
556
  */
531
557
  declare function withDefinitionsInlined(shape: TypeShape, definitions: Record<string, TypeShape> | undefined, depth?: number, inProgress?: ReadonlySet<string>): TypeShape;
558
+ /** The shape with `each` applied to every shape written directly inside it. One with nothing inside, such as a ref, comes back as it is. */
559
+ declare function withChildShapes(shape: TypeShape, each: (inner: TypeShape) => TypeShape): TypeShape;
532
560
 
533
- export { storageLabel as A, BoundaryBindingSchema as B, ConfidenceInfoSchema as C, type DeployableUnit as D, EVERY_FIELD as E, type FunctionCallSemantics as F, type GraphqlOperationSemantics as G, storageSystemLabel as H, typeDefinitionKey as I, withDefinitionsInlined as J, type MessageBusSemantics as M, type RestSemantics as R, type Semantics as S, type TypeShape as T, ConfidenceLevelSchema as a, ConfidenceSourceSchema as b, CorroborationSchema as c, SourceLocationSchema as d, type MessageBusTechnology as e, DeployableUnitSchema as f, FunctionCallSemanticsSchema as g, GraphqlOperationSemanticsSchema as h, type GraphqlResolverSemantics as i, GraphqlResolverSemanticsSchema as j, MessageBusSemanticsSchema as k, RestSemanticsSchema as l, type RuntimeConfigSemantics as m, RuntimeConfigSemanticsSchema as n, SemanticsSchema as o, type StorageSemantics as p, StorageSemanticsSchema as q, TypeShapeSchema as r, ecsContainerInstanceName as s, isModuleName as t, methodsAgree as u, normalizePath as v, pathShape as w, routePathAdmits as x, routePathsMeet as y, storageContainerLabel as z };
561
+ export { storageContainerLabel as A, BoundaryBindingSchema as B, ConfidenceInfoSchema as C, type DeployableUnit as D, EVERY_FIELD as E, type FunctionCallSemantics as F, type GraphqlOperationSemantics as G, storageLabel as H, storageSystemLabel as I, typeDefinitionKey as J, withChildShapes as K, withDefinitionsInlined as L, type MessageBusSemantics as M, type RestSemantics as R, type Semantics as S, type TypeShape as T, ConfidenceLevelSchema as a, ConfidenceSourceSchema as b, CorroborationSchema as c, SourceLocationSchema as d, type MessageBusTechnology as e, DeployableUnitSchema as f, FunctionCallSemanticsSchema as g, GraphqlOperationSemanticsSchema as h, type GraphqlResolverSemantics as i, GraphqlResolverSemanticsSchema as j, MESSAGE_BUS_TRAITS as k, MessageBusSemanticsSchema as l, RestSemanticsSchema as m, type RuntimeConfigSemantics as n, RuntimeConfigSemanticsSchema as o, SemanticsSchema as p, type StorageSemantics as q, StorageSemanticsSchema as r, TypeShapeSchema as s, ecsContainerInstanceName as t, isModuleName as u, methodsAgree as v, normalizePath as w, pathShape as x, routePathAdmits as y, routePathsMeet as z };
package/dist/schemas.cjs CHANGED
@@ -37,6 +37,7 @@ __export(schemas_exports, {
37
37
  StorageSemanticsSchema: () => StorageSemanticsSchema,
38
38
  TypeShapeSchema: () => TypeShapeSchema,
39
39
  typeDefinitionKey: () => typeDefinitionKey,
40
+ withChildShapes: () => withChildShapes,
40
41
  withDefinitionsInlined: () => withDefinitionsInlined
41
42
  });
42
43
  module.exports = __toCommonJS(schemas_exports);
@@ -283,7 +284,11 @@ var MessageBusSemanticsSchema = import_zod5.z.object({
283
284
  "aws_kinesis",
284
285
  "aws_firehose",
285
286
  "gcp_pubsub",
287
+ // Job queues. The header says what their channel is.
286
288
  "bullmq",
289
+ "activejob",
290
+ "sidekiq",
291
+ "celery",
287
292
  "kafka",
288
293
  "nats",
289
294
  "cloudflare-queues",
@@ -299,6 +304,26 @@ var MessageBusSemanticsSchema = import_zod5.z.object({
299
304
  */
300
305
  channel: import_zod5.z.string().min(1).nullable()
301
306
  });
307
+ var MESSAGES = { jobQueue: false };
308
+ var JOBS = { jobQueue: true };
309
+ var MESSAGE_BUS_TRAITS = {
310
+ aws_sqs: MESSAGES,
311
+ "aws.sns": MESSAGES,
312
+ s3: MESSAGES,
313
+ eventbridge: MESSAGES,
314
+ aws_kinesis: MESSAGES,
315
+ aws_firehose: MESSAGES,
316
+ gcp_pubsub: MESSAGES,
317
+ bullmq: JOBS,
318
+ activejob: JOBS,
319
+ sidekiq: JOBS,
320
+ celery: JOBS,
321
+ kafka: MESSAGES,
322
+ nats: MESSAGES,
323
+ "cloudflare-queues": MESSAGES,
324
+ "cloudflare-cron": MESSAGES,
325
+ "cloudflare-tail": MESSAGES
326
+ };
302
327
  var messageBusSemantics = defineBoundarySemantics({
303
328
  name: "message-bus",
304
329
  schema: MessageBusSemanticsSchema,
@@ -315,6 +340,8 @@ var messageBusSemantics = defineBoundarySemantics({
315
340
  * the generic unmatched list leaves them out.
316
341
  */
317
342
  reportsUnpairedItself: true,
343
+ consumedAs: ["reads"],
344
+ unsettledJob: (semantics) => semantics.channel === null && MESSAGE_BUS_TRAITS[semantics.messageBus].jobQueue,
318
345
  /**
319
346
  * A channel that is null here can still pair. The dedicated pass
320
347
  * follows environment variable chains before comparing, so a
@@ -1111,6 +1138,7 @@ var runtimeConfigSemantics = defineBoundarySemantics({
1111
1138
  // comes from outside the code.
1112
1139
  leavesTheProcess: true,
1113
1140
  reportsUnpairedItself: false,
1141
+ findingsAreReadsByName: true,
1114
1142
  identityKey: () => null,
1115
1143
  // A reader sees which deployable's environment this is. Code that
1116
1144
  // reads a variable does not say which deployable runs it, so a read
@@ -1360,7 +1388,21 @@ var SourceLocationSchema = import_zod13.z.object({
1360
1388
  * project's `suss.json` gives it. Set only when the project lists its
1361
1389
  * modules, and then on every unit whose file is under a module's root.
1362
1390
  */
1363
- module: import_zod13.z.string().optional()
1391
+ module: import_zod13.z.string().optional(),
1392
+ /**
1393
+ * The git repository the extract ran in. Summaries from several
1394
+ * repositories can share a folder, and two of them can both have
1395
+ * `src/index.ts::handler`; this says which one each came from, and
1396
+ * which commit, so a link opens the file that was read. `path` is
1397
+ * where `file` is measured from, relative to the repository's top.
1398
+ * Absent outside a repository.
1399
+ */
1400
+ repository: import_zod13.z.object({
1401
+ name: import_zod13.z.string(),
1402
+ path: import_zod13.z.string(),
1403
+ remote: import_zod13.z.string().optional(),
1404
+ commit: import_zod13.z.string().optional()
1405
+ }).optional()
1364
1406
  });
1365
1407
  var BoundaryBindingSchema = import_zod13.z.object({
1366
1408
  transport: import_zod13.z.string(),
@@ -1425,23 +1467,25 @@ function withDefinitionsInlined(shape, definitions, depth = 0, inProgress = /* @
1425
1467
  /* @__PURE__ */ new Set([...inProgress, key])
1426
1468
  );
1427
1469
  }
1428
- if (shape.type === "record") {
1470
+ return withChildShapes(shape, deeper);
1471
+ }
1472
+ var CHILD_REBUILDS = {
1473
+ record: (shape, each) => {
1474
+ if (shape.type !== "record") {
1475
+ return shape;
1476
+ }
1429
1477
  const properties = {};
1430
1478
  for (const [name, value] of Object.entries(shape.properties)) {
1431
- properties[name] = deeper(value);
1479
+ properties[name] = each(value);
1432
1480
  }
1433
1481
  return { ...shape, properties };
1434
- }
1435
- if (shape.type === "array") {
1436
- return { ...shape, items: deeper(shape.items) };
1437
- }
1438
- if (shape.type === "dictionary") {
1439
- return { ...shape, values: deeper(shape.values) };
1440
- }
1441
- if (shape.type === "union") {
1442
- return { ...shape, variants: shape.variants.map(deeper) };
1443
- }
1444
- return shape;
1482
+ },
1483
+ array: (shape, each) => shape.type === "array" ? { ...shape, items: each(shape.items) } : shape,
1484
+ dictionary: (shape, each) => shape.type === "dictionary" ? { ...shape, values: each(shape.values) } : shape,
1485
+ union: (shape, each) => shape.type === "union" ? { ...shape, variants: shape.variants.map(each) } : shape
1486
+ };
1487
+ function withChildShapes(shape, each) {
1488
+ return CHILD_REBUILDS[shape.type]?.(shape, each) ?? shape;
1445
1489
  }
1446
1490
  // Annotate the CommonJS export names for ESM import in node:
1447
1491
  0 && (module.exports = {
@@ -1462,5 +1506,6 @@ function withDefinitionsInlined(shape, definitions, depth = 0, inProgress = /* @
1462
1506
  StorageSemanticsSchema,
1463
1507
  TypeShapeSchema,
1464
1508
  typeDefinitionKey,
1509
+ withChildShapes,
1465
1510
  withDefinitionsInlined
1466
1511
  });
@@ -1,2 +1,2 @@
1
1
  import 'zod';
2
- export { B as BoundaryBindingSchema, C as ConfidenceInfoSchema, a as ConfidenceLevelSchema, b as ConfidenceSourceSchema, c as CorroborationSchema, f as DeployableUnitSchema, g as FunctionCallSemanticsSchema, h as GraphqlOperationSemanticsSchema, j as GraphqlResolverSemanticsSchema, k as MessageBusSemanticsSchema, l as RestSemanticsSchema, n as RuntimeConfigSemanticsSchema, o as SemanticsSchema, d as SourceLocationSchema, q as StorageSemanticsSchema, T as TypeShape, r as TypeShapeSchema, I as typeDefinitionKey, J as withDefinitionsInlined } from './schemas-lfg8kvak.cjs';
2
+ export { B as BoundaryBindingSchema, C as ConfidenceInfoSchema, a as ConfidenceLevelSchema, b as ConfidenceSourceSchema, c as CorroborationSchema, f as DeployableUnitSchema, g as FunctionCallSemanticsSchema, h as GraphqlOperationSemanticsSchema, j as GraphqlResolverSemanticsSchema, l as MessageBusSemanticsSchema, m as RestSemanticsSchema, o as RuntimeConfigSemanticsSchema, p as SemanticsSchema, d as SourceLocationSchema, r as StorageSemanticsSchema, T as TypeShape, s as TypeShapeSchema, J as typeDefinitionKey, K as withChildShapes, L as withDefinitionsInlined } from './schemas-CL8yCMd0.cjs';
package/dist/schemas.d.ts CHANGED
@@ -1,2 +1,2 @@
1
1
  import 'zod';
2
- export { B as BoundaryBindingSchema, C as ConfidenceInfoSchema, a as ConfidenceLevelSchema, b as ConfidenceSourceSchema, c as CorroborationSchema, f as DeployableUnitSchema, g as FunctionCallSemanticsSchema, h as GraphqlOperationSemanticsSchema, j as GraphqlResolverSemanticsSchema, k as MessageBusSemanticsSchema, l as RestSemanticsSchema, n as RuntimeConfigSemanticsSchema, o as SemanticsSchema, d as SourceLocationSchema, q as StorageSemanticsSchema, T as TypeShape, r as TypeShapeSchema, I as typeDefinitionKey, J as withDefinitionsInlined } from './schemas-lfg8kvak.js';
2
+ export { B as BoundaryBindingSchema, C as ConfidenceInfoSchema, a as ConfidenceLevelSchema, b as ConfidenceSourceSchema, c as CorroborationSchema, f as DeployableUnitSchema, g as FunctionCallSemanticsSchema, h as GraphqlOperationSemanticsSchema, j as GraphqlResolverSemanticsSchema, l as MessageBusSemanticsSchema, m as RestSemanticsSchema, o as RuntimeConfigSemanticsSchema, p as SemanticsSchema, d as SourceLocationSchema, r as StorageSemanticsSchema, T as TypeShape, s as TypeShapeSchema, J as typeDefinitionKey, K as withChildShapes, L as withDefinitionsInlined } from './schemas-CL8yCMd0.js';
package/dist/schemas.js CHANGED
@@ -16,8 +16,9 @@ import {
16
16
  StorageSemanticsSchema,
17
17
  TypeShapeSchema,
18
18
  typeDefinitionKey,
19
+ withChildShapes,
19
20
  withDefinitionsInlined
20
- } from "./chunk-A46EUIKC.js";
21
+ } from "./chunk-OROVMQY2.js";
21
22
  export {
22
23
  BoundaryBindingSchema,
23
24
  ConfidenceInfoSchema,
@@ -36,5 +37,6 @@ export {
36
37
  StorageSemanticsSchema,
37
38
  TypeShapeSchema,
38
39
  typeDefinitionKey,
40
+ withChildShapes,
39
41
  withDefinitionsInlined
40
42
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@suss/ir-core",
3
- "version": "0.35.1",
3
+ "version": "0.37.0",
4
4
  "type": "module",
5
5
  "description": "The type primitives every suss summary is built from: type shapes, boundary bindings, source locations and confidence.",
6
6
  "keywords": [