@suss/ir-core 0.34.0 → 0.35.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
@@ -54,7 +54,6 @@ __export(index_exports, {
54
54
  boundaryKey: () => boundaryKey,
55
55
  boundaryLabel: () => boundaryLabel,
56
56
  boundaryNameString: () => boundaryNameString,
57
- bucketRank: () => bucketRank,
58
57
  bucketsMeet: () => bucketsMeet,
59
58
  busIdentityKey: () => busIdentityKey,
60
59
  busesAgree: () => busesAgree,
@@ -78,6 +77,7 @@ __export(index_exports, {
78
77
  groundBinding: () => groundBinding,
79
78
  groundedPairingKey: () => groundedPairingKey,
80
79
  hasNameHole: () => hasNameHole,
80
+ hostCanBeOwn: () => hostCanBeOwn,
81
81
  ioBinding: () => ioBinding,
82
82
  ioIdentityKey: () => ioIdentityKey,
83
83
  isGraphqlOperationBinding: () => isGraphqlOperationBinding,
@@ -98,7 +98,9 @@ __export(index_exports, {
98
98
  namesNothing: () => namesNothing,
99
99
  normalizePath: () => normalizePath,
100
100
  normalizeRuleBoundary: () => normalizeRuleBoundary,
101
+ operationKey: () => operationKey,
101
102
  packageExportBinding: () => packageExportBinding,
103
+ pairRank: () => pairRank,
102
104
  pairingKey: () => pairingKey,
103
105
  parseBoundaryName: () => parseBoundaryName,
104
106
  parseChannel: () => parseChannel,
@@ -135,7 +137,8 @@ __export(index_exports, {
135
137
  validateRule: () => validateRule,
136
138
  withDefinitionsInlined: () => withDefinitionsInlined,
137
139
  withRewrittenPaths: () => withRewrittenPaths,
138
- withinScope: () => withinScope
140
+ withinScope: () => withinScope,
141
+ withoutOwnHost: () => withoutOwnHost
139
142
  });
140
143
  module.exports = __toCommonJS(index_exports);
141
144
 
@@ -655,6 +658,38 @@ function pathAfterOrigin(text) {
655
658
  function statesAnOrigin(text) {
656
659
  return SCHEME_ORIGIN.test(text) || PROTOCOL_RELATIVE_ORIGIN.test(text);
657
660
  }
661
+ var PRIVATE_SUFFIXES = [
662
+ "local",
663
+ "internal",
664
+ "localhost",
665
+ "lan",
666
+ "home.arpa",
667
+ "svc",
668
+ "test",
669
+ "example",
670
+ "invalid",
671
+ "example.com",
672
+ "example.net",
673
+ "example.org"
674
+ ];
675
+ var PRIVATE_IPV4 = /^(?:127\.|10\.|192\.168\.|169\.254\.|172\.(?:1[6-9]|2\d|3[01])\.|0\.0\.0\.0$)/;
676
+ function hostnameOf(host) {
677
+ const lower = host.toLowerCase();
678
+ const name = lower.startsWith("[") ? lower.slice(0, lower.indexOf("]") + 1) : lower.split(":")[0] ?? lower;
679
+ return name.replace(/\.$/, "");
680
+ }
681
+ function hostCanBeOwn(host) {
682
+ const name = hostnameOf(host);
683
+ if (name === "[::1]" || /^\[f[cd]/.test(name) || PRIVATE_IPV4.test(name)) {
684
+ return true;
685
+ }
686
+ if (!name.includes(".")) {
687
+ return true;
688
+ }
689
+ return PRIVATE_SUFFIXES.some(
690
+ (suffix) => name === suffix || name.endsWith(`.${suffix}`)
691
+ );
692
+ }
658
693
 
659
694
  // src/semantics/pathPattern.ts
660
695
  var HOLE_RANGE_SUFFIX = {
@@ -721,14 +756,18 @@ function shapedItem(segment) {
721
756
  return ".*";
722
757
  }
723
758
  if (part.startsWith("{")) {
724
- return "[^/]+";
759
+ return /[?*]\}$/.test(part) ? "[^/]*" : "[^/]+";
725
760
  }
726
761
  return escapedForRegex(part);
727
762
  }).join("");
763
+ const holes = segment.match(/\{[^}]*\}|\*/g) ?? [];
764
+ const text = segment.replace(/\{[^}]*\}|\*/g, "");
728
765
  return {
729
766
  kind: "shaped",
730
767
  shape: segment.replace(/\{[^}]*\}/g, "{}"),
731
- test: new RegExp(`^${source}$`)
768
+ test: new RegExp(`^${source}$`),
769
+ bare: holes.every((hole) => hole === "*" || /[?*]\}$/.test(hole)) ? text : null,
770
+ textLength: text.length
732
771
  };
733
772
  }
734
773
  function itemsOf(segment) {
@@ -748,10 +787,35 @@ function segmentsOf(alternative) {
748
787
  const trimmed = alternative.startsWith("/") ? alternative.slice(1) : alternative;
749
788
  return trimmed === "" ? [] : trimmed.split("/");
750
789
  }
790
+ function patternSegmentsOf(alternative) {
791
+ const segments = segmentsOf(alternative);
792
+ const first = segments[0];
793
+ const opensWithBaseUrl = !alternative.startsWith("/") && first !== void 0 && HOLE_SEGMENT.test(first);
794
+ return opensWithBaseUrl ? segments.slice(1) : segments;
795
+ }
796
+ function pathAfterBaseUrl(path) {
797
+ const segments = segmentsOf(path);
798
+ const first = segments[0];
799
+ if (path.startsWith("/") || first === void 0 || segments.length < 2 || !HOLE_SEGMENT.test(first)) {
800
+ return path;
801
+ }
802
+ return `/${segments.slice(1).join("/")}`;
803
+ }
804
+ var PATTERNS = /* @__PURE__ */ new Map();
805
+ var PATTERN_CACHE_LIMIT = 5e4;
751
806
  function patternOf(path) {
752
- return alternativesOf(path).map(
753
- (alternative) => segmentsOf(alternative).flatMap(itemsOf)
807
+ const known = PATTERNS.get(path);
808
+ if (known !== void 0) {
809
+ return known;
810
+ }
811
+ const pattern = alternativesOf(path).map(
812
+ (alternative) => patternSegmentsOf(alternative).flatMap(itemsOf)
754
813
  );
814
+ if (PATTERNS.size >= PATTERN_CACHE_LIMIT) {
815
+ PATTERNS.clear();
816
+ }
817
+ PATTERNS.set(path, pattern);
818
+ return pattern;
755
819
  }
756
820
  function literalItemsOf(path) {
757
821
  return segmentsOf(path).map((text) => ({ kind: "text", text }));
@@ -830,17 +894,104 @@ function pathSpansShapes(path) {
830
894
  function countOf(items, kinds) {
831
895
  return items.filter((item) => kinds.includes(item.kind)).length;
832
896
  }
833
- function pathSpecificity(path) {
834
- const alternatives = patternOf(path);
835
- const ranks = alternatives.map((items) => [
897
+ function readingSpecificity(items) {
898
+ return [
836
899
  countOf(items, ["text"]),
837
900
  countOf(items, ["shaped"]),
838
901
  -countOf(items, ["optional", "star"])
839
- ]);
840
- const loosest = ranks.reduce(
841
- (low, rank) => compareRanks(rank, low) < 0 ? rank : low
902
+ ];
903
+ }
904
+ function segmentFit(route, request) {
905
+ if (!meetOnOneSegment(route, request)) {
906
+ return "apart";
907
+ }
908
+ if (request.kind === "text") {
909
+ if (route.kind === "text") {
910
+ return "stated";
911
+ }
912
+ return route.kind === "shaped" ? "shaped" : "free";
913
+ }
914
+ if (absorbsAnything(route)) {
915
+ return "free";
916
+ }
917
+ if (request.kind !== "shaped") {
918
+ return "guess";
919
+ }
920
+ if (route.kind === "shaped") {
921
+ return "free";
922
+ }
923
+ return route.kind === "text" && request.bare === route.text ? "stated" : "guess";
924
+ }
925
+ function shapedText(item) {
926
+ return item.kind === "shaped" ? item.textLength : 0;
927
+ }
928
+ function betterFit(a, b) {
929
+ return a === void 0 || compareRanks(b, a) > 0;
930
+ }
931
+ function bestFit(route, request) {
932
+ const width = request.length + 1;
933
+ const best = new Array((route.length + 1) * width);
934
+ best[0] = [0, 0];
935
+ const offer = (i, j, fit) => {
936
+ const at = i * width + j;
937
+ if (betterFit(best[at], fit)) {
938
+ best[at] = fit;
939
+ }
940
+ };
941
+ for (let reached = 0; reached <= route.length + request.length; reached += 1) {
942
+ for (let i = Math.max(0, reached - request.length); i <= Math.min(route.length, reached); i += 1) {
943
+ const j = reached - i;
944
+ const fit = best[i * width + j];
945
+ if (fit === void 0) {
946
+ continue;
947
+ }
948
+ const left = route[i];
949
+ const right = request[j];
950
+ if (left !== void 0 && skippable(left)) {
951
+ offer(i + 1, j, fit);
952
+ }
953
+ if (right !== void 0 && skippable(right)) {
954
+ offer(i, j + 1, fit);
955
+ }
956
+ if (left === void 0 || right === void 0) {
957
+ continue;
958
+ }
959
+ if (left.kind === "star" && right.kind === "star") {
960
+ continue;
961
+ }
962
+ const kind = segmentFit(left, right);
963
+ if (kind === "apart" || kind === "guess") {
964
+ continue;
965
+ }
966
+ offer(
967
+ left.kind === "star" ? i : i + 1,
968
+ right.kind === "star" ? j : j + 1,
969
+ [
970
+ fit[0] + (kind === "stated" ? 1 : 0),
971
+ fit[1] + (kind === "shaped" ? shapedText(left) : 0)
972
+ ]
973
+ );
974
+ }
975
+ }
976
+ return best[route.length * width + request.length] ?? null;
977
+ }
978
+ function requestRank(route, request) {
979
+ let found = null;
980
+ for (const routeItems of patternOf(route)) {
981
+ for (const requestItems of patternOf(request)) {
982
+ const fit = bestFit(routeItems, requestItems);
983
+ const rank = fit === null ? null : [...fit, ...readingSpecificity(routeItems)];
984
+ if (rank !== null && (found === null || compareRanks(rank, found) > 0)) {
985
+ found = rank;
986
+ }
987
+ }
988
+ }
989
+ return found;
990
+ }
991
+ function isCatchAll(route) {
992
+ return patternOf(route).some(
993
+ (items) => items.length > 0 && items.every(absorbsAnything) && items.some((item) => item.kind === "star")
842
994
  );
843
- return [...loosest, 1 - alternatives.length];
844
995
  }
845
996
  function compareRanks(a, b) {
846
997
  const length = Math.max(a.length, b.length);
@@ -870,7 +1021,18 @@ var RestSemanticsSchema = import_zod7.z.object({
870
1021
  * here so the pairing layer can see them without unwrapping any
871
1022
  * metadata. Absent or empty for an inferred source.
872
1023
  */
873
- declaredResponses: import_zod7.z.array(import_zod7.z.number()).optional()
1024
+ declaredResponses: import_zod7.z.array(import_zod7.z.number()).optional(),
1025
+ /**
1026
+ * The host a client wrote in an absolute URL, with its port
1027
+ * (`api.example.com:8443`). A piece suss could not read is written
1028
+ * `{name}`. Absent for a relative URL and for a route.
1029
+ */
1030
+ host: import_zod7.z.string().min(1).optional(),
1031
+ /**
1032
+ * True for a route the framework also serves with `.{format}` after
1033
+ * its path, the way Rails serves `/search.json` from `get "search"`.
1034
+ */
1035
+ optionalFormat: import_zod7.z.boolean().optional()
874
1036
  });
875
1037
  var OPENING_HOLE = /^\{([^{}]+)\}(.*)$/;
876
1038
  function baseUrlReference(semantics) {
@@ -878,7 +1040,10 @@ function baseUrlReference(semantics) {
878
1040
  return label === void 0 ? null : referenceFromName(patternHole(label));
879
1041
  }
880
1042
  function normalizePath(path) {
881
- let normalized = path.replace(/:([a-zA-Z_]\w*)([?+*]?)/g, "{$1$2}");
1043
+ let normalized = withoutParameterConstraints(path).replace(
1044
+ /:([a-zA-Z_]\w*)([?+*]?)/g,
1045
+ "{$1$2}"
1046
+ );
882
1047
  if (normalized.length > 1 && normalized.endsWith("/")) {
883
1048
  normalized = normalized.slice(0, -1);
884
1049
  }
@@ -888,6 +1053,46 @@ function normalizePath(path) {
888
1053
  );
889
1054
  return normalized;
890
1055
  }
1056
+ function withoutParameterConstraints(path) {
1057
+ let out = "";
1058
+ let i = 0;
1059
+ while (i < path.length) {
1060
+ const name = /^:[a-zA-Z_]\w*\(/.exec(path.slice(i));
1061
+ if (name === null) {
1062
+ out += path[i];
1063
+ i += 1;
1064
+ continue;
1065
+ }
1066
+ const open = i + name[0].length - 1;
1067
+ const close = closingParenthesis(path, open);
1068
+ if (close === -1) {
1069
+ return out + path.slice(i);
1070
+ }
1071
+ out += path.slice(i, open);
1072
+ i = close + 1;
1073
+ }
1074
+ return out;
1075
+ }
1076
+ function closingParenthesis(text, open) {
1077
+ let depth = 0;
1078
+ for (let i = open; i < text.length; i += 1) {
1079
+ const char = text[i];
1080
+ if (char === "\\") {
1081
+ i += 1;
1082
+ continue;
1083
+ }
1084
+ if (char === "(") {
1085
+ depth += 1;
1086
+ }
1087
+ if (char === ")") {
1088
+ depth -= 1;
1089
+ if (depth === 0) {
1090
+ return i;
1091
+ }
1092
+ }
1093
+ }
1094
+ return -1;
1095
+ }
891
1096
  function pathShape(path) {
892
1097
  return normalizePath(path).replace(/\{[^{}]*?([?+*]?)\}/g, "{$1}");
893
1098
  }
@@ -903,6 +1108,40 @@ function routePathAdmits(declaredPath, requestPath) {
903
1108
  function routePathsMeet(a, b) {
904
1109
  return pathsMeet(normalizePath(a), normalizePath(b));
905
1110
  }
1111
+ function readHost(semantics) {
1112
+ const host = semantics.host;
1113
+ return host === void 0 || /[{(]/.test(host) ? void 0 : host;
1114
+ }
1115
+ function hostsAgree(a, b) {
1116
+ return readHost(a) === readHost(b);
1117
+ }
1118
+ function hostUnread(semantics) {
1119
+ if (semantics.host !== void 0) {
1120
+ return readHost(semantics) === void 0;
1121
+ }
1122
+ return baseUrlReference(semantics) !== null;
1123
+ }
1124
+ function servedPath(semantics, path) {
1125
+ const normalized = normalizePath(path);
1126
+ return semantics.optionalFormat === true ? `${normalized}(|.{format})` : normalized;
1127
+ }
1128
+ function withoutHost(semantics) {
1129
+ const { host: _host, ...rest } = semantics;
1130
+ return rest;
1131
+ }
1132
+ function groundedBaseUrl(semantics, deployment) {
1133
+ const reference = baseUrlReference(semantics);
1134
+ if (reference === null) {
1135
+ return null;
1136
+ }
1137
+ const base = deployment.setTo(reference);
1138
+ if (base === null) {
1139
+ return null;
1140
+ }
1141
+ const rest = OPENING_HOLE.exec(semantics.path ?? "")?.[2] ?? "";
1142
+ const grounded = pathAfterOrigin(`${base}${rest}`);
1143
+ return { ...semantics, path: grounded === "" ? "/" : grounded };
1144
+ }
906
1145
  var restSemantics = defineBoundarySemantics({
907
1146
  name: "rest",
908
1147
  schema: RestSemanticsSchema,
@@ -941,19 +1180,46 @@ var restSemantics = defineBoundarySemantics({
941
1180
  if (semantics.method === null || semantics.path === null) {
942
1181
  return null;
943
1182
  }
944
- return `rest ${pathShape(semantics.path)}`;
1183
+ const shape = pathShape(pathAfterBaseUrl(normalizePath(semantics.path)));
1184
+ const host = readHost(semantics);
1185
+ return host === void 0 ? `rest ${shape}` : `rest //${host}${shape}`;
1186
+ },
1187
+ /**
1188
+ * A spec writes `/teams/{team_id}` where the route that serves it
1189
+ * writes `/teams/:id`. The method stays in, so a `"*"` handler is
1190
+ * never compared with the document for one method.
1191
+ */
1192
+ operationKey(semantics) {
1193
+ if (semantics.method === null || semantics.path === null) {
1194
+ return null;
1195
+ }
1196
+ return `${semantics.method.toUpperCase()} ${pathShape(semantics.path)}`;
945
1197
  },
946
1198
  sidesAgree(a, b) {
947
- return methodsAgree(a.method, b.method);
1199
+ return methodsAgree(a.method, b.method) && hostsAgree(a, b);
948
1200
  },
949
1201
  spansBuckets(semantics) {
950
- return semantics.path !== null && pathSpansShapes(normalizePath(semantics.path));
1202
+ return semantics.path !== null && (semantics.optionalFormat === true || pathSpansShapes(normalizePath(semantics.path)));
951
1203
  },
952
1204
  bucketsMeet(a, b) {
953
- return a.path !== null && b.path !== null && routePathsMeet(a.path, b.path);
1205
+ return a.path !== null && b.path !== null && hostsAgree(a, b) && pathsMeet(servedPath(a, a.path), servedPath(b, b.path));
954
1206
  },
955
- bucketRank(semantics) {
956
- return semantics.path === null ? [] : pathSpecificity(normalizePath(semantics.path));
1207
+ /**
1208
+ * A catch-all route never takes a call whose host suss could not
1209
+ * read, since nothing else ties that call to this app.
1210
+ */
1211
+ pairRank(provider, consumer) {
1212
+ if (provider.path === null || consumer.path === null) {
1213
+ return [];
1214
+ }
1215
+ const route = normalizePath(provider.path);
1216
+ if (hostUnread(consumer) && isCatchAll(route)) {
1217
+ return null;
1218
+ }
1219
+ return requestRank(
1220
+ servedPath(provider, provider.path),
1221
+ normalizePath(consumer.path)
1222
+ );
957
1223
  },
958
1224
  /**
959
1225
  * The identity key, with a missing half still readable: `ANY` when
@@ -994,27 +1260,29 @@ var restSemantics = defineBoundarySemantics({
994
1260
  },
995
1261
  /**
996
1262
  * A call whose base URL the deployment fills in, resolved to the
997
- * path it reaches.
1263
+ * path it reaches, and a call to a host that can be the project's
1264
+ * own, with the host left out so it meets the route.
998
1265
  *
999
- * The source cannot settle this on its own, so the adapter leaves
1000
- * the hole in. `API_BASE` could be `http://backend.internal`, and
1001
- * then the path is `/orders`. It could equally be `/api/v2`, and
1266
+ * The source cannot settle a base URL on its own, so the adapter
1267
+ * leaves the hole in. `API_BASE` could be `http://backend.internal`,
1268
+ * and then the path is `/orders`. It could equally be `/api/v2`, and
1002
1269
  * then the path is `/api/v2/orders`. Filling in the deployed value
1003
- * and reading the path back out gets the right one either way.
1004
- * `baseUrlReference` finds the hole that is the base URL.
1270
+ * and reading the path back out gets the right one either way, and
1271
+ * a base the deployment sets counts as the app's own.
1005
1272
  */
1006
- groundName(semantics, deployment) {
1007
- const reference = baseUrlReference(semantics);
1008
- if (reference === null) {
1009
- return null;
1010
- }
1011
- const base = deployment.setTo(reference);
1012
- if (base === null) {
1273
+ /** A listed host matches with or without the port the call gives. */
1274
+ withoutOwnHost(semantics, ownHosts) {
1275
+ const host = semantics.host?.toLowerCase();
1276
+ if (host === void 0) {
1013
1277
  return null;
1014
1278
  }
1015
- const rest = OPENING_HOLE.exec(semantics.path ?? "")?.[2] ?? "";
1016
- const grounded = pathAfterOrigin(`${base}${rest}`);
1017
- return { ...semantics, path: grounded === "" ? "/" : grounded };
1279
+ return ownHosts.has(host) || ownHosts.has(host.replace(/:\d+$/, "")) ? withoutHost(semantics) : null;
1280
+ },
1281
+ groundName(semantics, deployment) {
1282
+ const based = groundedBaseUrl(semantics, deployment);
1283
+ const grounded = based ?? semantics;
1284
+ const host = readHost(grounded);
1285
+ return host !== void 0 && hostCanBeOwn(host) ? withoutHost(grounded) : based;
1018
1286
  },
1019
1287
  nameReference: baseUrlReference,
1020
1288
  ruleBoundary: {
@@ -1460,6 +1728,13 @@ function withRewrittenPaths(binding, rewrite) {
1460
1728
  semantics: behavior.rewritePaths(binding.semantics, rewrite)
1461
1729
  };
1462
1730
  }
1731
+ function withoutOwnHost(binding, ownHosts) {
1732
+ const semantics = behaviorOf(binding.semantics).withoutOwnHost?.(
1733
+ binding.semantics,
1734
+ ownHosts
1735
+ );
1736
+ return semantics === void 0 || semantics === null ? binding : { ...binding, semantics };
1737
+ }
1463
1738
  function groundedPairingKey(binding, deployment) {
1464
1739
  return pairingKey(groundBinding(binding, deployment));
1465
1740
  }
@@ -1475,6 +1750,10 @@ function pairingKey(binding) {
1475
1750
  const behavior = behaviorOf(binding.semantics);
1476
1751
  return (behavior.pairingKey ?? behavior.identityKey)(binding.semantics);
1477
1752
  }
1753
+ function operationKey(binding) {
1754
+ const behavior = behaviorOf(binding.semantics);
1755
+ return (behavior.operationKey ?? behavior.identityKey)(binding.semantics);
1756
+ }
1478
1757
  function semanticsAgree(a, b) {
1479
1758
  if (a.name !== b.name) {
1480
1759
  return false;
@@ -1492,8 +1771,12 @@ function bucketsMeet(a, b) {
1492
1771
  const meet = behaviorOf(a.semantics).bucketsMeet;
1493
1772
  return meet !== void 0 && meet(a.semantics, b.semantics);
1494
1773
  }
1495
- function bucketRank(binding) {
1496
- return behaviorOf(binding.semantics).bucketRank?.(binding.semantics) ?? [];
1774
+ function pairRank(provider, consumer) {
1775
+ if (provider.semantics.name !== consumer.semantics.name) {
1776
+ return null;
1777
+ }
1778
+ const rank = behaviorOf(provider.semantics).pairRank;
1779
+ return rank === void 0 ? [] : rank(provider.semantics, consumer.semantics);
1497
1780
  }
1498
1781
  function boundaryLabel(binding) {
1499
1782
  const behavior = behaviorOf(binding.semantics);
@@ -1681,7 +1964,9 @@ var EffectRelationSchema = RelationSchema.exclude(["provides"]);
1681
1964
  var import_zod15 = require("zod");
1682
1965
  var SuppressionSideSchema = import_zod15.z.object({
1683
1966
  summary: import_zod15.z.string().optional(),
1684
- transitionId: import_zod15.z.string().optional()
1967
+ transitionId: import_zod15.z.string().optional(),
1968
+ /** The field on that side, for a finding about one field and no transition. */
1969
+ field: import_zod15.z.string().optional()
1685
1970
  }).optional();
1686
1971
  var SuppressionRuleSchema = import_zod15.z.object({
1687
1972
  /**
@@ -1968,7 +2253,9 @@ function restBinding(opts) {
1968
2253
  name: "rest",
1969
2254
  method: method === null ? null : method.toUpperCase(),
1970
2255
  path: namedOrNull(opts.path, "rest path"),
1971
- ...opts.declaredResponses !== void 0 ? { declaredResponses: opts.declaredResponses } : {}
2256
+ ...opts.declaredResponses !== void 0 ? { declaredResponses: opts.declaredResponses } : {},
2257
+ ...opts.host !== void 0 && opts.host !== "" ? { host: opts.host } : {},
2258
+ ...opts.optionalFormat === true ? { optionalFormat: true } : {}
1972
2259
  },
1973
2260
  recognition: opts.recognition
1974
2261
  };
@@ -2127,7 +2414,6 @@ function ioBinding(opts) {
2127
2414
  boundaryKey,
2128
2415
  boundaryLabel,
2129
2416
  boundaryNameString,
2130
- bucketRank,
2131
2417
  bucketsMeet,
2132
2418
  busIdentityKey,
2133
2419
  busesAgree,
@@ -2151,6 +2437,7 @@ function ioBinding(opts) {
2151
2437
  groundBinding,
2152
2438
  groundedPairingKey,
2153
2439
  hasNameHole,
2440
+ hostCanBeOwn,
2154
2441
  ioBinding,
2155
2442
  ioIdentityKey,
2156
2443
  isGraphqlOperationBinding,
@@ -2171,7 +2458,9 @@ function ioBinding(opts) {
2171
2458
  namesNothing,
2172
2459
  normalizePath,
2173
2460
  normalizeRuleBoundary,
2461
+ operationKey,
2174
2462
  packageExportBinding,
2463
+ pairRank,
2175
2464
  pairingKey,
2176
2465
  parseBoundaryName,
2177
2466
  parseChannel,
@@ -2208,5 +2497,6 @@ function ioBinding(opts) {
2208
2497
  validateRule,
2209
2498
  withDefinitionsInlined,
2210
2499
  withRewrittenPaths,
2211
- withinScope
2500
+ withinScope,
2501
+ withoutOwnHost
2212
2502
  });