@routr/connect 2.0.8-alpha.2 → 2.0.8-alpha.20

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.
@@ -0,0 +1,28 @@
1
+ import { MessageRequest, CommonTypes as CT, CommonConnect as CC } from "@routr/common";
2
+ import { RoutingDirection } from "./types";
3
+ export declare const checkAccess: (accessRequest: {
4
+ apiClient: CC.APIClient;
5
+ request: MessageRequest;
6
+ caller: CC.RoutableResourceUnion;
7
+ callee: CC.RoutableResourceUnion;
8
+ routingDirection: RoutingDirection;
9
+ }) => Promise<Record<string, unknown>>;
10
+ export declare const checkAgentOrPeerAccess: (request: MessageRequest, caller: CC.RoutableResourceUnion) => Promise<{
11
+ message: {
12
+ responseType: CT.ResponseType;
13
+ wwwAuthenticate: {
14
+ scheme: string;
15
+ realm: string;
16
+ qop: string;
17
+ opaque: string;
18
+ stale: boolean;
19
+ nonce: string;
20
+ algorithm: string;
21
+ };
22
+ };
23
+ }>;
24
+ export declare const checkAccessFromPSTN: (apiClient: CC.APIClient, request: MessageRequest, callee: CC.INumber) => Promise<{
25
+ message: {
26
+ responseType: CT.ResponseType;
27
+ };
28
+ }>;
package/dist/access.js ADDED
@@ -0,0 +1,117 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.checkAccessFromPSTN = exports.checkAgentOrPeerAccess = exports.checkAccess = void 0;
13
+ /*
14
+ * Copyright (C) 2022 by Fonoster Inc (https://fonoster.com)
15
+ * http://github.com/fonoster
16
+ *
17
+ * This file is part of Routr.
18
+ *
19
+ * Licensed under the MIT License (the "License");
20
+ * you may not use this file except in compliance with
21
+ * the License. You may obtain a copy of the License at
22
+ *
23
+ * https://opensource.org/licenses/MIT
24
+ *
25
+ * Unless required by applicable law or agreed to in writing, software
26
+ * distributed under the License is distributed on an "AS IS" BASIS,
27
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
28
+ * See the License for the specific language governing permissions and
29
+ * limitations under the License.
30
+ */
31
+ const logger_1 = require("@fonoster/logger");
32
+ const common_1 = require("@routr/common");
33
+ const types_1 = require("./types");
34
+ const logger = (0, logger_1.getLogger)({ service: "connect", filePath: __filename });
35
+ const checkAccess = (accessRequest) => __awaiter(void 0, void 0, void 0, function* () {
36
+ const { apiClient, request, caller, callee, routingDirection } = accessRequest;
37
+ switch (routingDirection) {
38
+ case types_1.RoutingDirection.PEER_TO_PSTN:
39
+ case types_1.RoutingDirection.AGENT_TO_AGENT:
40
+ case types_1.RoutingDirection.AGENT_TO_PSTN:
41
+ return (0, exports.checkAgentOrPeerAccess)(request, caller);
42
+ case types_1.RoutingDirection.FROM_PSTN:
43
+ return (0, exports.checkAccessFromPSTN)(apiClient, request, callee);
44
+ case types_1.RoutingDirection.UNKNOWN:
45
+ return common_1.Auth.createForbideenResponse();
46
+ }
47
+ });
48
+ exports.checkAccess = checkAccess;
49
+ const checkAgentOrPeerAccess = (request, caller) => __awaiter(void 0, void 0, void 0, function* () {
50
+ // Calculate and return challenge
51
+ if (request.message.authorization) {
52
+ const auth = Object.assign({}, request.message.authorization);
53
+ auth.method = request.method;
54
+ const credentials = caller.credentials;
55
+ // Calculate response and compare with the one send by the endpoint
56
+ const calcRes = common_1.Auth.calculateAuthResponse(auth, {
57
+ username: credentials === null || credentials === void 0 ? void 0 : credentials.username,
58
+ secret: credentials === null || credentials === void 0 ? void 0 : credentials.password
59
+ });
60
+ if (calcRes !== auth.response) {
61
+ return common_1.Auth.createUnauthorizedResponse(request.message.requestUri.host);
62
+ }
63
+ }
64
+ else {
65
+ return common_1.Auth.createUnauthorizedResponse(request.message.requestUri.host);
66
+ }
67
+ });
68
+ exports.checkAgentOrPeerAccess = checkAgentOrPeerAccess;
69
+ const checkAccessFromPSTN = (apiClient, request, callee) => __awaiter(void 0, void 0, void 0, function* () {
70
+ // Get the Trunk associated with the SIP URI
71
+ const trunk = (yield apiClient.trunks.findBy({
72
+ fieldName: "inboundUri",
73
+ fieldValue: request.message.requestUri.host
74
+ })).items[0];
75
+ // If the Trunk or Number doesn't exist reject the call
76
+ if (!callee || !trunk) {
77
+ return common_1.Auth.createForbideenResponse();
78
+ }
79
+ if (callee.trunk.ref !== trunk.ref) {
80
+ return common_1.Auth.createForbideenResponse();
81
+ }
82
+ // Verify that the IP is whitelisted which means getting the access control list for the trunk
83
+ if (trunk.accessControlList) {
84
+ try {
85
+ const allow = trunk.accessControlList.allow.filter((net) => {
86
+ return common_1.IpUtils.hasIp(net, request.sender.host);
87
+ })[0];
88
+ if (!allow) {
89
+ return common_1.Auth.createUnauthorizedResponseWithoutChallenge();
90
+ }
91
+ }
92
+ catch (e) {
93
+ logger.error(e);
94
+ return common_1.Auth.createServerInternalErrorResponse();
95
+ }
96
+ }
97
+ // If the Trunk has a User/Password we must verify that the User/Password are valid
98
+ if (trunk.inboundCredentials) {
99
+ // Calculate and return challenge
100
+ if (request.message.authorization) {
101
+ const auth = Object.assign({}, request.message.authorization);
102
+ auth.method = request.method;
103
+ // Calculate response and compare with the one send by the endpoint
104
+ const calcRes = common_1.Auth.calculateAuthResponse(auth, {
105
+ username: trunk.inboundCredentials.username,
106
+ secret: trunk.inboundCredentials.password
107
+ });
108
+ if (calcRes !== auth.response) {
109
+ return common_1.Auth.createUnauthorizedResponse(request.message.requestUri.host);
110
+ }
111
+ }
112
+ else {
113
+ return common_1.Auth.createUnauthorizedResponse(request.message.requestUri.host);
114
+ }
115
+ }
116
+ });
117
+ exports.checkAccessFromPSTN = checkAccessFromPSTN;
package/dist/errors.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { ROUTING_DIRECTION } from "./types";
1
+ import { RoutingDirection } from "./types";
2
2
  /**
3
3
  * Throw when the API server is unavailable.
4
4
  */
@@ -19,7 +19,7 @@ export declare class UnsuportedRoutingError extends Error {
19
19
  /**
20
20
  * Create a new ServiceUnavailableError.
21
21
  *
22
- * @param {string} routingDir - The routing direction
22
+ * @param {RoutingDirection} routingDirection - The routing direction
23
23
  */
24
- constructor(routingDir: ROUTING_DIRECTION);
24
+ constructor(routingDirection: RoutingDirection);
25
25
  }
package/dist/errors.js CHANGED
@@ -67,11 +67,11 @@ class UnsuportedRoutingError extends Error {
67
67
  /**
68
68
  * Create a new ServiceUnavailableError.
69
69
  *
70
- * @param {string} routingDir - The routing direction
70
+ * @param {RoutingDirection} routingDirection - The routing direction
71
71
  */
72
- constructor(routingDir) {
73
- super("unsupported routing direction: " + routingDir);
74
- this.code = grpc.status.UNKNOWN;
72
+ constructor(routingDirection) {
73
+ super("unsupported routing direction: " + routingDirection);
74
+ this.code = grpc.status.UNIMPLEMENTED;
75
75
  // Set the prototype explicitly.
76
76
  Object.setPrototypeOf(this, ServiceUnavailableError.prototype);
77
77
  }
@@ -1,6 +1,6 @@
1
1
  import { MessageRequest, Response } from "@routr/processor";
2
- import { ILocationService } from "@routr/location/src/types";
2
+ import { ILocationService } from "@routr/location";
3
3
  import { CommonConnect as CC } from "@routr/common";
4
- export declare const handleRegister: (location: ILocationService) => (request: MessageRequest, res: Response) => Promise<void>;
4
+ export declare const handleRegister: (apiClient: CC.APIClient, location: ILocationService) => (request: MessageRequest, res: Response) => Promise<void>;
5
5
  export declare const handleRegistry: (req: MessageRequest, res: Response) => void;
6
- export declare const handleRequest: (location: ILocationService, dataAPI?: CC.DataAPI) => (req: MessageRequest, res: Response) => Promise<void | MessageRequest>;
6
+ export declare const handleRequest: (location: ILocationService, apiClient?: CC.APIClient) => (req: MessageRequest, res: Response) => Promise<void>;
package/dist/handlers.js CHANGED
@@ -34,37 +34,67 @@ const processor_1 = require("@routr/processor");
34
34
  const function_1 = require("fp-ts/function");
35
35
  const router_1 = require("./router");
36
36
  const common_1 = require("@routr/common");
37
- const handleRegister = (location) => {
37
+ const utils_1 = require("./utils");
38
+ const handleRegister = (apiClient, location) => {
38
39
  return (request, res) => __awaiter(void 0, void 0, void 0, function* () {
39
- yield location.addRoute({
40
- aor: processor_1.Target.getTargetAOR(request),
41
- route: location_1.Helper.createRoute(request)
42
- });
43
- res.sendOk();
40
+ // Calculate and return challenge
41
+ if (request.message.authorization) {
42
+ const auth = Object.assign({}, request.message.authorization);
43
+ auth.method = request.method;
44
+ const fromURI = request.message.from.address.uri;
45
+ const peerOrAgent = yield (0, utils_1.findResource)(apiClient, fromURI.host, fromURI.user);
46
+ if (!peerOrAgent) {
47
+ return res.send(common_1.Auth.createForbideenResponse());
48
+ }
49
+ const credentials = peerOrAgent.credentials;
50
+ // Calculate response and compare with the one send by the endpoint
51
+ const calcRes = common_1.Auth.calculateAuthResponse(auth, {
52
+ username: credentials === null || credentials === void 0 ? void 0 : credentials.username,
53
+ secret: credentials === null || credentials === void 0 ? void 0 : credentials.password
54
+ });
55
+ if (calcRes !== auth.response) {
56
+ return res.send(common_1.Auth.createUnauthorizedResponse(request.message.requestUri.host));
57
+ }
58
+ // TODO: Needs test
59
+ yield location.addRoute({
60
+ aor: "aor" in peerOrAgent ? peerOrAgent.aor : processor_1.Target.getTargetAOR(request),
61
+ route: location_1.Helper.createRoute(request)
62
+ });
63
+ res.sendOk();
64
+ }
65
+ else {
66
+ return res.send(common_1.Auth.createUnauthorizedResponse(request.message.requestUri.host));
67
+ }
44
68
  });
45
69
  };
46
70
  exports.handleRegister = handleRegister;
47
71
  // TODO: Needs test
48
72
  const handleRegistry = (req, res) => {
49
73
  const route = processor_1.Helper.createRouteFromLastMessage(req);
50
- res.send((0, function_1.pipe)(req, processor_1.Alterations.addSelfVia(route), processor_1.Alterations.decreaseMaxForwards, processor_1.Alterations.removeAuthorization, processor_1.Alterations.removeRoutes, processor_1.Alterations.removeXEdgePortRef));
74
+ res.send((0, function_1.pipe)(req, processor_1.Alterations.addSelfVia(route), processor_1.Alterations.decreaseMaxForwards, processor_1.Alterations.removeAuthorization, processor_1.Alterations.removeSelfRoutes, processor_1.Alterations.removeXEdgePortRef));
51
75
  };
52
76
  exports.handleRegistry = handleRegistry;
53
77
  // TODO: If request has X-Connect-Token then validate the JWT value and continue
54
- const handleRequest = (location, dataAPI) => (req, res) => __awaiter(void 0, void 0, void 0, function* () {
78
+ const handleRequest = (location, apiClient) => (req, res) => __awaiter(void 0, void 0, void 0, function* () {
55
79
  try {
56
80
  const route = processor_1.Extensions.getHeaderValue(req, common_1.CommonTypes.ExtraHeader.EDGEPORT_REF)
57
81
  ? processor_1.Helper.createRouteFromLastMessage(req)
58
- : yield (0, router_1.router)(location, dataAPI)(req);
82
+ : yield (0, router_1.router)(location, apiClient)(req);
59
83
  if (!route)
60
84
  return res.sendNotFound();
61
- // Forward request to peer edgeport
62
- if (req.edgePortRef !== route.edgePortRef) {
63
- return (0, function_1.pipe)(req, processor_1.Alterations.addSelfVia(route),
64
- // The LP address belongs to another edgeport
65
- processor_1.Alterations.addRouteToListeningPoint(route), processor_1.Alterations.addXEdgePortRef, processor_1.Alterations.decreaseMaxForwards);
85
+ // If route is not type Route then return
86
+ if (!("listeningPoints" in route)) {
87
+ return res.send(route);
88
+ }
89
+ else {
90
+ // Forward request to peer edgeport
91
+ if (req.edgePortRef !== route.edgePortRef) {
92
+ return res.send((0, function_1.pipe)(req, processor_1.Alterations.addSelfVia(route), processor_1.Alterations.addSelfRecordRoute(route),
93
+ // The order of the routes is important
94
+ processor_1.Alterations.addRouteToPeerEdgePort(route), processor_1.Alterations.addRouteToNextHop(route), processor_1.Alterations.addXEdgePortRef, processor_1.Alterations.decreaseMaxForwards));
95
+ }
96
+ res.send((0, tailor_1.tailor)(route, req));
66
97
  }
67
- res.send((0, tailor_1.tailor)(route, req));
68
98
  }
69
99
  catch (err) {
70
100
  res.sendError(err);
package/dist/router.d.ts CHANGED
@@ -1,5 +1,4 @@
1
- import { Route } from "@routr/common";
1
+ import { CommonConnect as CC, Route } from "@routr/common";
2
2
  import { MessageRequest } from "@routr/processor";
3
3
  import { ILocationService } from "@routr/location";
4
- import { CommonConnect as CC } from "@routr/common";
5
- export declare function router(location: ILocationService, dataAPI: CC.DataAPI): (req: MessageRequest) => Promise<Route>;
4
+ export declare function router(location: ILocationService, apiClient: CC.APIClient): (request: MessageRequest) => Promise<Route | Record<string, unknown>>;
package/dist/router.js CHANGED
@@ -32,33 +32,51 @@ const types_1 = require("./types");
32
32
  const common_1 = require("@routr/common");
33
33
  const utils_1 = require("./utils");
34
34
  const processor_1 = require("@routr/processor");
35
- const errors_1 = require("./errors");
36
35
  const location_1 = require("@routr/location");
36
+ const errors_1 = require("./errors");
37
37
  const logger_1 = require("@fonoster/logger");
38
- const common_2 = require("@routr/common");
38
+ const access_1 = require("./access");
39
39
  const logger = (0, logger_1.getLogger)({ service: "connect", filePath: __filename });
40
- const getSIPURI = (uri) => `sip:${uri.user}@${uri.host}`;
41
40
  // eslint-disable-next-line require-jsdoc
42
- function router(location, dataAPI) {
43
- return (req) => __awaiter(this, void 0, void 0, function* () {
44
- const fromURI = req.message.from.address.uri;
45
- const requestURI = req.message.requestUri;
41
+ function router(location, apiClient) {
42
+ return (request) => __awaiter(this, void 0, void 0, function* () {
43
+ const fromURI = request.message.from.address.uri;
44
+ const requestURI = request.message.requestUri;
45
+ const caller = yield (0, utils_1.findResource)(apiClient, fromURI.host, fromURI.user);
46
+ const callee = yield (0, utils_1.findResource)(apiClient, requestURI.host, requestURI.user);
47
+ const routingDirection = (0, utils_1.getRoutingDirection)(caller, callee);
46
48
  logger.verbose("routing request from: " +
47
- getSIPURI(fromURI) +
49
+ (0, utils_1.getSIPURI)(fromURI) +
48
50
  ", to: " +
49
- getSIPURI(requestURI), { fromURI: getSIPURI(fromURI), requestURI: getSIPURI(requestURI) });
50
- const caller = yield (0, utils_1.findResource)(dataAPI, fromURI.host, fromURI.user);
51
- const callee = yield (0, utils_1.findResource)(dataAPI, requestURI.host, requestURI.user);
52
- const routingDir = (0, utils_1.getRoutingDirection)(caller, callee);
53
- switch (routingDir) {
54
- case types_1.ROUTING_DIRECTION.AGENT_TO_PSTN:
55
- return yield toPSTN(dataAPI, req, caller, requestURI.user);
56
- case types_1.ROUTING_DIRECTION.AGENT_TO_AGENT:
57
- return agentToAgent(location, req);
58
- case types_1.ROUTING_DIRECTION.FROM_PSTN:
59
- return yield fromPSTN(location, dataAPI, callee);
51
+ (0, utils_1.getSIPURI)(requestURI), {
52
+ fromURI: (0, utils_1.getSIPURI)(fromURI),
53
+ requestURI: (0, utils_1.getSIPURI)(requestURI),
54
+ routingDirection
55
+ // sessionAffinityHeader: callee?.spec.location?.sessionAffinityHeader
56
+ });
57
+ if (request.method === common_1.CommonTypes.Method.INVITE) {
58
+ const failedCheck = yield (0, access_1.checkAccess)({
59
+ apiClient,
60
+ request,
61
+ caller,
62
+ callee,
63
+ routingDirection
64
+ });
65
+ if (failedCheck) {
66
+ return failedCheck;
67
+ }
68
+ }
69
+ switch (routingDirection) {
70
+ case types_1.RoutingDirection.AGENT_TO_AGENT:
71
+ return agentToAgent(location, request);
72
+ case types_1.RoutingDirection.AGENT_TO_PSTN:
73
+ return yield agentToPSTN(request, caller, requestURI.user);
74
+ case types_1.RoutingDirection.FROM_PSTN:
75
+ return yield fromPSTN(apiClient, location, callee, request);
76
+ case types_1.RoutingDirection.PEER_TO_PSTN:
77
+ return yield peerToPSTN(apiClient, request);
60
78
  default:
61
- throw new errors_1.UnsuportedRoutingError(routingDir);
79
+ throw new errors_1.UnsuportedRoutingError(routingDirection);
62
80
  }
63
81
  });
64
82
  }
@@ -66,33 +84,50 @@ exports.router = router;
66
84
  // eslint-disable-next-line require-jsdoc
67
85
  function agentToAgent(location, req) {
68
86
  return __awaiter(this, void 0, void 0, function* () {
69
- return (yield location.findRoutes({ aor: processor_1.Target.getTargetAOR(req) }))[0];
87
+ return (yield location.findRoutes({ aor: processor_1.Target.getTargetAOR(req), callId: req.ref }))[0];
70
88
  });
71
89
  }
72
90
  /**
73
91
  * From PSTN routing.
74
92
  *
93
+ * @param {APIClient} apiClient - API client
75
94
  * @param {ILocationService} location - Location service
76
- * @param {uknown} _
77
95
  * @param {Resource} callee - The callee
96
+ * @param {MessageRequest} req - The request
78
97
  * @return {Promise<Route>}
79
98
  */
80
- function fromPSTN(location, _, callee) {
99
+ function fromPSTN(apiClient, location, callee, req) {
81
100
  var _a;
82
101
  return __awaiter(this, void 0, void 0, function* () {
102
+ const sessionAffinityRef = processor_1.Extensions.getHeaderValue(req, callee.sessionAffinityHeader);
103
+ let backend;
104
+ if (callee.aorLink.startsWith("backend:")) {
105
+ const peer = (yield apiClient.peers.findBy({
106
+ fieldName: "aor",
107
+ fieldValue: callee.aorLink
108
+ })).items[0];
109
+ backend = {
110
+ ref: peer.ref,
111
+ balancingAlgorithm: peer.balancingAlgorithm,
112
+ withSessionAffinity: peer.withSessionAffinity
113
+ };
114
+ }
83
115
  const route = (yield location.findRoutes({
84
- aor: callee.spec.location.aorLink
116
+ aor: callee.aorLink,
117
+ callId: req.ref,
118
+ sessionAffinityRef,
119
+ backend
85
120
  }))[0];
86
121
  if (!route) {
87
- throw new location_1.NotRoutesFoundForAOR(callee.spec.location.aorLink);
122
+ throw new location_1.NotRoutesFoundForAOR(callee.aorLink);
88
123
  }
89
124
  if (!route.headers)
90
125
  route.headers = [];
91
- (_a = callee.spec.location.props) === null || _a === void 0 ? void 0 : _a.forEach((prop) => {
126
+ (_a = callee.extraHeaders) === null || _a === void 0 ? void 0 : _a.forEach((prop) => {
92
127
  const p = {
93
128
  name: prop.name,
94
129
  value: prop.value,
95
- action: common_2.CommonTypes.HeaderModifierAction.ADD
130
+ action: common_1.CommonTypes.HeaderModifierAction.ADD
96
131
  };
97
132
  route.headers.push(p);
98
133
  });
@@ -100,50 +135,92 @@ function fromPSTN(location, _, callee) {
100
135
  });
101
136
  }
102
137
  // eslint-disable-next-line require-jsdoc
103
- function toPSTN(dataAPI, req, caller, calleeNumber) {
104
- var _a, _b;
138
+ function agentToPSTN(req, agent, calleeNumber) {
139
+ var _a, _b, _c, _d, _e;
105
140
  return __awaiter(this, void 0, void 0, function* () {
106
- const domain = yield dataAPI.get(caller.spec.domainRef);
141
+ if (!((_a = agent.domain) === null || _a === void 0 ? void 0 : _a.egressPolicies)) {
142
+ // TODO: Create custom error
143
+ throw new Error(`no egress policy found for Domain ref: ${agent.domain.ref}`);
144
+ }
107
145
  // Look for Number in domain that matches regex callee
108
- const policy = (_a = domain.spec.context.egressPolicies) === null || _a === void 0 ? void 0 : _a.find((policy) => {
146
+ const policy = agent.domain.egressPolicies.find((policy) => {
109
147
  const regex = new RegExp(policy.rule);
110
148
  return regex.test(calleeNumber);
111
149
  });
112
- const number = yield dataAPI.get(policy === null || policy === void 0 ? void 0 : policy.numberRef);
113
- const trunk = yield dataAPI.get(number === null || number === void 0 ? void 0 : number.spec.trunkRef);
114
- if (!domain.spec.context.egressPolicies) {
115
- // TODO: Create custom error
116
- throw new Error(`no egress policy found for Domain ref: ${domain.ref}`);
117
- }
150
+ const trunk = (_b = policy.number) === null || _b === void 0 ? void 0 : _b.trunk;
118
151
  if (!trunk) {
119
- // TODO: Create custom error
120
- throw new Error(`no trunk associated with Number ref: ${number === null || number === void 0 ? void 0 : number.ref}`);
152
+ // This should never happen
153
+ throw new Error(`no trunk associated with Number ref: ${(_c = policy.number) === null || _c === void 0 ? void 0 : _c.ref}`);
121
154
  }
122
155
  const uri = (0, utils_1.getTrunkURI)(trunk);
123
- const egressListeningPoint = common_1.Helper.getListeningPoint(req, uri.transport);
156
+ return {
157
+ user: uri.user,
158
+ host: uri.host,
159
+ port: uri.port,
160
+ transport: (_d = uri.transport) === null || _d === void 0 ? void 0 : _d.toUpperCase(),
161
+ edgePortRef: req.edgePortRef,
162
+ listeningPoints: req.listeningPoints,
163
+ localnets: req.localnets,
164
+ externalAddrs: req.externalAddrs,
165
+ headers: [
166
+ // TODO: Find a more deterministic way to re-add the Privacy header
167
+ {
168
+ name: "Privacy",
169
+ action: common_1.CommonTypes.HeaderModifierAction.REMOVE
170
+ },
171
+ {
172
+ name: "Privacy",
173
+ value: ((_e = agent.privacy) === null || _e === void 0 ? void 0 : _e.toUpperCase()) === common_1.CommonTypes.Privacy.PRIVATE
174
+ ? common_1.CommonTypes.Privacy.PRIVATE.toLowerCase()
175
+ : common_1.CommonTypes.Privacy.NONE.toLowerCase(),
176
+ action: common_1.CommonTypes.HeaderModifierAction.ADD
177
+ },
178
+ (0, utils_1.createRemotePartyId)(trunk, policy.number),
179
+ (0, utils_1.createPAssertedIdentity)(req, trunk, policy.number),
180
+ yield (0, utils_1.createTrunkAuthentication)(trunk)
181
+ ]
182
+ };
183
+ });
184
+ }
185
+ // eslint-disable-next-line require-jsdoc
186
+ function peerToPSTN(apiClient, req) {
187
+ return __awaiter(this, void 0, void 0, function* () {
188
+ const numberTel = processor_1.Extensions.getHeaderValue(req, common_1.CommonTypes.ExtraHeader.DOD_NUMBER);
189
+ const privacy = processor_1.Extensions.getHeaderValue(req, common_1.CommonTypes.ExtraHeader.DOD_PRIVACY);
190
+ const number = yield (0, utils_1.findNumberByTelUrl)(apiClient, `tel:${numberTel}`);
191
+ if (!number) {
192
+ throw new Error(`no Number found for tel: ${numberTel}`);
193
+ }
194
+ if (!number.trunk) {
195
+ // TODO: Create custom error
196
+ throw new Error(`no trunk associated with Number ref: ${number.ref}`);
197
+ }
198
+ const uri = (0, utils_1.getTrunkURI)(number.trunk);
124
199
  return {
125
200
  user: uri.user,
126
201
  host: uri.host,
127
202
  port: uri.port,
128
203
  transport: uri.transport,
129
204
  edgePortRef: req.edgePortRef,
130
- egressListeningPoint,
205
+ listeningPoints: req.listeningPoints,
206
+ localnets: req.localnets,
207
+ externalAddrs: req.externalAddrs,
131
208
  headers: [
132
209
  // TODO: Find a more deterministic way to re-add the Privacy header
133
210
  {
134
211
  name: "Privacy",
135
- action: common_2.CommonTypes.HeaderModifierAction.REMOVE
212
+ action: common_1.CommonTypes.HeaderModifierAction.REMOVE
136
213
  },
137
214
  {
138
215
  name: "Privacy",
139
- value: ((_b = caller.spec.privacy) === null || _b === void 0 ? void 0 : _b.toLowerCase()) === common_2.CommonTypes.Privacy.PRIVATE
140
- ? common_2.CommonTypes.Privacy.PRIVATE
141
- : common_2.CommonTypes.Privacy.NONE,
142
- action: common_2.CommonTypes.HeaderModifierAction.ADD
216
+ value: (privacy === null || privacy === void 0 ? void 0 : privacy.toLocaleLowerCase()) === common_1.CommonTypes.Privacy.PRIVATE
217
+ ? common_1.CommonTypes.Privacy.PRIVATE.toLowerCase()
218
+ : common_1.CommonTypes.Privacy.NONE.toLowerCase(),
219
+ action: common_1.CommonTypes.HeaderModifierAction.ADD
143
220
  },
144
- (0, utils_1.createRemotePartyId)(trunk, number),
145
- (0, utils_1.createPAssertedIdentity)(req, trunk, number),
146
- yield (0, utils_1.createTrunkAuthentication)(dataAPI, trunk)
221
+ (0, utils_1.createRemotePartyId)(number.trunk, number),
222
+ (0, utils_1.createPAssertedIdentity)(req, number.trunk, number),
223
+ yield (0, utils_1.createTrunkAuthentication)(number.trunk)
147
224
  ]
148
225
  };
149
226
  });
package/dist/service.js CHANGED
@@ -70,7 +70,7 @@ function ConnectProcessor(config) {
70
70
  (0, handlers_1.handleRegistry)(req, res);
71
71
  }
72
72
  else {
73
- (0, handlers_1.handleRegister)(location)(req, res);
73
+ (0, handlers_1.handleRegister)(common_2.CommonConnect.apiClient({ apiAddr: config.apiAddr }), location)(req, res);
74
74
  }
75
75
  break;
76
76
  case common_1.Method.BYE:
@@ -78,7 +78,7 @@ function ConnectProcessor(config) {
78
78
  res.send((0, tailor_1.tailor)(processor_1.Helper.createRouteFromLastMessage(req), req));
79
79
  break;
80
80
  default:
81
- yield (0, handlers_1.handleRequest)(location, common_2.CommonConnect.dataAPI(config.apiAddr))(req, res);
81
+ (0, handlers_1.handleRequest)(location, common_2.CommonConnect.apiClient({ apiAddr: config.apiAddr }))(req, res);
82
82
  }
83
83
  }));
84
84
  }
package/dist/tailor.js CHANGED
@@ -22,7 +22,6 @@ exports.tailor = void 0;
22
22
  const processor_1 = require("@routr/processor");
23
23
  const function_1 = require("fp-ts/function");
24
24
  // Q: Should we add support for strict routing?
25
- const tailor = (route, req) => (0, function_1.pipe)(req, processor_1.Alterations.addSelfVia(route), processor_1.Alterations.applyXHeaders(route), processor_1.Alterations.addRoute(route), processor_1.Alterations.addSelfRecordRoute(route), processor_1.Alterations.decreaseMaxForwards, processor_1.Alterations.removeAuthorization, processor_1.Alterations.removeRoutes, processor_1.Alterations.removeXEdgePortRef
26
- // Add updateContact for SIP.js support
27
- );
25
+ // TODO: Add updateContact for SIP.js support
26
+ const tailor = (route, req) => (0, function_1.pipe)(req, processor_1.Alterations.decreaseMaxForwards, processor_1.Alterations.removeAuthorization, processor_1.Alterations.removeSelfRoutes, processor_1.Alterations.removeXEdgePortRef, processor_1.Alterations.addSelfVia(route), processor_1.Alterations.applyXHeaders(route), processor_1.Alterations.addSelfRecordRoute(route), processor_1.Alterations.addRouteToNextHop(route));
28
27
  exports.tailor = tailor;
package/dist/types.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { HeaderModifier } from "@routr/common";
2
- export declare enum ROUTING_DIRECTION {
2
+ export declare enum RoutingDirection {
3
3
  FROM_PSTN = "from-pstn",
4
4
  AGENT_TO_AGENT = "agent-to-agent",
5
5
  AGENT_TO_PSTN = "agent-to-pstn",
package/dist/types.js CHANGED
@@ -1,12 +1,13 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ROUTING_DIRECTION = void 0;
4
- var ROUTING_DIRECTION;
5
- (function (ROUTING_DIRECTION) {
6
- ROUTING_DIRECTION["FROM_PSTN"] = "from-pstn";
7
- ROUTING_DIRECTION["AGENT_TO_AGENT"] = "agent-to-agent";
8
- ROUTING_DIRECTION["AGENT_TO_PSTN"] = "agent-to-pstn";
9
- ROUTING_DIRECTION["PEER_TO_AGENT"] = "peer-to-agent";
10
- ROUTING_DIRECTION["PEER_TO_PSTN"] = "peer-to-pstn";
11
- ROUTING_DIRECTION["UNKNOWN"] = "unknown";
12
- })(ROUTING_DIRECTION = exports.ROUTING_DIRECTION || (exports.ROUTING_DIRECTION = {}));
3
+ exports.RoutingDirection = void 0;
4
+ var RoutingDirection;
5
+ (function (RoutingDirection) {
6
+ RoutingDirection["FROM_PSTN"] = "from-pstn";
7
+ RoutingDirection["AGENT_TO_AGENT"] = "agent-to-agent";
8
+ RoutingDirection["AGENT_TO_PSTN"] = "agent-to-pstn";
9
+ // WARNING: This is not supported yet
10
+ RoutingDirection["PEER_TO_AGENT"] = "peer-to-agent";
11
+ RoutingDirection["PEER_TO_PSTN"] = "peer-to-pstn";
12
+ RoutingDirection["UNKNOWN"] = "unknown";
13
+ })(RoutingDirection = exports.RoutingDirection || (exports.RoutingDirection = {}));
package/dist/utils.d.ts CHANGED
@@ -1,16 +1,20 @@
1
- import { HeaderModifier, MessageRequest, Transport } from "@routr/common";
2
- import { CommonConnect as CC } from "@routr/common";
3
- import { ROUTING_DIRECTION } from "./types";
4
- export declare const isKind: (res: CC.Resource, kind: CC.KIND) => boolean;
5
- export declare const findDomain: (dataAPI: CC.DataAPI, domainUri: string) => Promise<CC.Resource>;
6
- export declare const findResource: (dataAPI: CC.DataAPI, domainUri: string, userpart: string) => Promise<CC.Resource>;
7
- export declare const getRoutingDirection: (caller: CC.Resource, callee: CC.Resource) => ROUTING_DIRECTION;
8
- export declare const createPAssertedIdentity: (req: MessageRequest, trunk: CC.Resource, number: CC.Resource) => HeaderModifier;
9
- export declare const createRemotePartyId: (trunk: CC.Resource, number: CC.Resource) => HeaderModifier;
10
- export declare const createTrunkAuthentication: (dataAPI: CC.DataAPI, trunk: CC.Resource) => Promise<HeaderModifier>;
11
- export declare const getTrunkURI: (trunk: CC.Resource) => {
1
+ import { HeaderModifier, MessageRequest, Transport, CommonConnect as CC } from "@routr/common";
2
+ import { RoutingDirection } from "./types";
3
+ export declare const isKind: (res: CC.RoutableResourceUnion, kind: CC.Kind) => boolean;
4
+ export declare const findDomain: (apiClient: CC.APIClient, domainUri: string) => Promise<CC.Domain>;
5
+ export declare const findNumberByTelUrl: (apiClient: CC.APIClient, telUrl: string) => Promise<CC.INumber>;
6
+ export declare const findResource: (apiClient: CC.APIClient, domainUri: string, userpart: string) => Promise<CC.RoutableResourceUnion>;
7
+ export declare const getRoutingDirection: (caller: CC.RoutableResourceUnion, callee: CC.RoutableResourceUnion) => RoutingDirection;
8
+ export declare const createPAssertedIdentity: (req: MessageRequest, trunk: CC.Trunk, number: CC.INumber) => HeaderModifier;
9
+ export declare const createRemotePartyId: (trunk: CC.Trunk, number: CC.INumber) => HeaderModifier;
10
+ export declare const createTrunkAuthentication: (trunk: CC.Trunk) => Promise<HeaderModifier>;
11
+ export declare const getTrunkURI: (trunk: CC.Trunk) => {
12
12
  host: string;
13
13
  port: number;
14
14
  user: string;
15
15
  transport: Transport;
16
16
  };
17
+ export declare const getSIPURI: (uri: {
18
+ user?: string;
19
+ host: string;
20
+ }) => string;
package/dist/utils.js CHANGED
@@ -9,7 +9,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  });
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.getTrunkURI = exports.createTrunkAuthentication = exports.createRemotePartyId = exports.createPAssertedIdentity = exports.getRoutingDirection = exports.findResource = exports.findDomain = exports.isKind = void 0;
12
+ exports.getSIPURI = exports.getTrunkURI = exports.createTrunkAuthentication = exports.createRemotePartyId = exports.createPAssertedIdentity = exports.getRoutingDirection = exports.findResource = exports.findNumberByTelUrl = exports.findDomain = exports.isKind = void 0;
13
13
  /*
14
14
  * Copyright (C) 2022 by Fonoster Inc (https://fonoster.com)
15
15
  * http://github.com/fonoster/routr
@@ -29,116 +29,128 @@ exports.getTrunkURI = exports.createTrunkAuthentication = exports.createRemotePa
29
29
  * limitations under the License.
30
30
  */
31
31
  const common_1 = require("@routr/common");
32
- const common_2 = require("@routr/common");
33
32
  const types_1 = require("./types");
33
+ // OMG, this is so ugly and hacky
34
34
  const isKind = (res, kind) => {
35
- if (res == null && kind === common_2.CommonConnect.KIND.UNKNOWN) {
35
+ if (res == null && kind === common_1.CommonConnect.Kind.UNKNOWN) {
36
+ return true;
37
+ }
38
+ else if (res == null) {
39
+ return false;
40
+ }
41
+ else if ("privacy" in res && kind === common_1.CommonConnect.Kind.AGENT) {
42
+ return true;
43
+ }
44
+ else if ("telUrl" in res && kind === common_1.CommonConnect.Kind.NUMBER) {
45
+ return true;
46
+ }
47
+ else if ("username" in res && kind === common_1.CommonConnect.Kind.PEER) {
36
48
  return true;
37
49
  }
38
- return (res === null || res === void 0 ? void 0 : res.kind.toLowerCase()) === kind;
39
50
  };
40
51
  exports.isKind = isKind;
41
- const findDomain = (dataAPI, domainUri) => __awaiter(void 0, void 0, void 0, function* () {
42
- return (yield dataAPI.findBy({
43
- kind: common_2.CommonConnect.KIND.DOMAIN,
44
- criteria: common_2.CommonConnect.FindCriteria.FIND_DOMAIN_BY_DOMAINURI,
45
- parameters: {
46
- domainUri
47
- }
48
- }))[0];
52
+ const findDomain = (apiClient, domainUri) => __awaiter(void 0, void 0, void 0, function* () {
53
+ return (yield apiClient.domains.findBy({
54
+ fieldName: "domainUri",
55
+ fieldValue: domainUri
56
+ })).items[0];
49
57
  });
50
58
  exports.findDomain = findDomain;
51
- const findResource = (dataAPI, domainUri, userpart) => __awaiter(void 0, void 0, void 0, function* () {
52
- const domain = yield (0, exports.findDomain)(dataAPI, domainUri);
53
- // TODO: Fix jsonpath not working for logical AND and OR
54
- let res = (yield dataAPI.findBy({
55
- kind: common_2.CommonConnect.KIND.NUMBER,
56
- criteria: common_2.CommonConnect.FindCriteria.FIND_NUMBER_BY_TELURL,
57
- parameters: {
58
- telUrl: `tel:${userpart}`
59
- }
60
- }))[0];
61
- res =
62
- res == null
63
- ? (yield dataAPI.findBy({
64
- kind: common_2.CommonConnect.KIND.AGENT,
65
- criteria: common_2.CommonConnect.FindCriteria.FIND_AGENT_BY_USERNAME,
66
- parameters: {
67
- username: userpart
68
- }
69
- }))[0]
70
- : res;
71
- if ((0, exports.isKind)(res, common_2.CommonConnect.KIND.AGENT) && res.spec.domainRef != (domain === null || domain === void 0 ? void 0 : domain.ref)) {
59
+ const findNumberByTelUrl = (apiClient, telUrl) => __awaiter(void 0, void 0, void 0, function* () {
60
+ return (yield apiClient.numbers.findBy({
61
+ fieldName: "telUrl",
62
+ fieldValue: telUrl
63
+ })).items[0];
64
+ });
65
+ exports.findNumberByTelUrl = findNumberByTelUrl;
66
+ const findResource = (apiClient, domainUri, userpart) => __awaiter(void 0, void 0, void 0, function* () {
67
+ const domain = yield (0, exports.findDomain)(apiClient, domainUri);
68
+ // First, try to find a number
69
+ const number = yield (0, exports.findNumberByTelUrl)(apiClient, `tel:${userpart}`);
70
+ if (number != null)
71
+ return number;
72
+ // Next, try to find an agent
73
+ const agent = (yield apiClient.agents.findBy({
74
+ fieldName: "username",
75
+ fieldValue: userpart
76
+ })).items[0];
77
+ if (agent && agent.domain.ref != (domain === null || domain === void 0 ? void 0 : domain.ref)) {
72
78
  // Not in the same domain
73
79
  return null;
74
80
  }
75
- return res;
81
+ if (agent != null)
82
+ return agent;
83
+ // Next, try to find a peer
84
+ return (yield apiClient.peers.findBy({
85
+ fieldName: "username",
86
+ fieldValue: userpart
87
+ })).items[0];
76
88
  });
77
89
  exports.findResource = findResource;
78
90
  const getRoutingDirection = (caller, callee) => {
79
- if ((0, exports.isKind)(caller, common_2.CommonConnect.KIND.AGENT) && (0, exports.isKind)(callee, common_2.CommonConnect.KIND.AGENT)) {
80
- return types_1.ROUTING_DIRECTION.AGENT_TO_AGENT;
91
+ if ((0, exports.isKind)(caller, common_1.CommonConnect.Kind.AGENT) && (0, exports.isKind)(callee, common_1.CommonConnect.Kind.AGENT)) {
92
+ return types_1.RoutingDirection.AGENT_TO_AGENT;
81
93
  }
82
- if ((0, exports.isKind)(caller, common_2.CommonConnect.KIND.AGENT) && (0, exports.isKind)(callee, common_2.CommonConnect.KIND.UNKNOWN)) {
83
- return types_1.ROUTING_DIRECTION.AGENT_TO_PSTN;
94
+ if ((0, exports.isKind)(caller, common_1.CommonConnect.Kind.AGENT) && (0, exports.isKind)(callee, common_1.CommonConnect.Kind.UNKNOWN)) {
95
+ return types_1.RoutingDirection.AGENT_TO_PSTN;
84
96
  }
85
- if ((0, exports.isKind)(caller, common_2.CommonConnect.KIND.PEER) && (0, exports.isKind)(callee, common_2.CommonConnect.KIND.AGENT)) {
86
- return types_1.ROUTING_DIRECTION.PEER_TO_AGENT;
97
+ if ((0, exports.isKind)(caller, common_1.CommonConnect.Kind.PEER) && (0, exports.isKind)(callee, common_1.CommonConnect.Kind.AGENT)) {
98
+ return types_1.RoutingDirection.PEER_TO_AGENT;
87
99
  }
88
100
  // All we know is that the Number is managed by this instance of Routr
89
- if ((0, exports.isKind)(callee, common_2.CommonConnect.KIND.NUMBER)) {
90
- return types_1.ROUTING_DIRECTION.FROM_PSTN;
101
+ if ((0, exports.isKind)(callee, common_1.CommonConnect.Kind.NUMBER)) {
102
+ return types_1.RoutingDirection.FROM_PSTN;
91
103
  }
92
- if ((0, exports.isKind)(caller, common_2.CommonConnect.KIND.PEER) && (0, exports.isKind)(callee, common_2.CommonConnect.KIND.UNKNOWN)) {
93
- return types_1.ROUTING_DIRECTION.PEER_TO_PSTN;
104
+ if ((0, exports.isKind)(caller, common_1.CommonConnect.Kind.PEER) && (0, exports.isKind)(callee, common_1.CommonConnect.Kind.UNKNOWN)) {
105
+ return types_1.RoutingDirection.PEER_TO_PSTN;
94
106
  }
95
- return types_1.ROUTING_DIRECTION.UNKNOWN;
107
+ return types_1.RoutingDirection.UNKNOWN;
96
108
  };
97
109
  exports.getRoutingDirection = getRoutingDirection;
98
110
  const createPAssertedIdentity = (req, trunk, number) => {
99
111
  const displayName = req.message.from.address.displayName;
100
- const remoteNumber = number.spec.location.telUrl.split(":")[1];
112
+ const remoteNumber = number.telUrl.split(":")[1];
101
113
  const trunkHost = (0, exports.getTrunkURI)(trunk).host;
102
114
  return {
103
115
  name: "P-Asserted-Identity",
104
116
  value: displayName
105
117
  ? `"${displayName}" <sip:${remoteNumber}@${trunkHost};user=phone>`
106
118
  : `<sip:${remoteNumber}@${trunkHost};user=phone>`,
107
- action: common_2.CommonTypes.HeaderModifierAction.ADD
119
+ action: common_1.CommonTypes.HeaderModifierAction.ADD
108
120
  };
109
121
  };
110
122
  exports.createPAssertedIdentity = createPAssertedIdentity;
111
123
  const createRemotePartyId = (trunk, number) => {
112
- const remoteNumber = number.spec.location.telUrl.split(":")[1];
124
+ const remoteNumber = number.telUrl.split(":")[1];
113
125
  const trunkHost = (0, exports.getTrunkURI)(trunk).host;
114
126
  return {
115
127
  name: "Remote-Party-ID",
116
128
  value: `<sip:${remoteNumber}@${trunkHost}>;screen=yes;party=calling`,
117
- action: common_2.CommonTypes.HeaderModifierAction.ADD
129
+ action: common_1.CommonTypes.HeaderModifierAction.ADD
118
130
  };
119
131
  };
120
132
  exports.createRemotePartyId = createRemotePartyId;
121
- const createTrunkAuthentication = (dataAPI, trunk) => __awaiter(void 0, void 0, void 0, function* () {
133
+ const createTrunkAuthentication = (trunk) => __awaiter(void 0, void 0, void 0, function* () {
122
134
  var _a, _b;
123
- const credentials = yield dataAPI.get(trunk.spec.outbound.credentialsRef);
124
135
  return {
125
- name: common_2.CommonTypes.ExtraHeader.GATEWAY_AUTH,
126
- value: Buffer.from(`${(_a = credentials.spec.credentials) === null || _a === void 0 ? void 0 : _a.username}:${(_b = credentials.spec.credentials) === null || _b === void 0 ? void 0 : _b.password}`).toString("base64"),
127
- action: common_2.CommonTypes.HeaderModifierAction.ADD
136
+ name: common_1.CommonTypes.ExtraHeader.GATEWAY_AUTH,
137
+ value: Buffer.from(`${(_a = trunk.outboundCredentials) === null || _a === void 0 ? void 0 : _a.username}:${(_b = trunk.outboundCredentials) === null || _b === void 0 ? void 0 : _b.password}`).toString("base64"),
138
+ action: common_1.CommonTypes.HeaderModifierAction.ADD
128
139
  };
129
140
  });
130
141
  exports.createTrunkAuthentication = createTrunkAuthentication;
131
142
  const getTrunkURI = (trunk) => {
132
- var _a;
133
- const { user, host, port, transport } = (_a = trunk.spec.outbound) === null || _a === void 0 ? void 0 : _a.uris[0].uri;
134
- const t = !transport
135
- ? common_1.Transport.UDP
136
- : Object.values(common_1.Transport)[Object.values(common_1.Transport).indexOf(transport.toLowerCase())];
143
+ if (!trunk.uris) {
144
+ throw new Error(`trunk ${trunk.ref} has no outbound settings`);
145
+ }
146
+ const { user, host, port, transport } = trunk.uris[0];
137
147
  return {
138
148
  user,
139
149
  host,
140
150
  port: port !== null && port !== void 0 ? port : 5060,
141
- transport: t
151
+ transport: transport !== null && transport !== void 0 ? transport : common_1.Transport.UDP
142
152
  };
143
153
  };
144
154
  exports.getTrunkURI = getTrunkURI;
155
+ const getSIPURI = (uri) => uri.user ? `sip:${uri.user}@${uri.host}` : `sip:${uri.host}`;
156
+ exports.getSIPURI = getSIPURI;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@routr/connect",
3
- "version": "2.0.8-alpha.2",
3
+ "version": "2.0.8-alpha.20",
4
4
  "description": "Default processor",
5
5
  "author": "Pedro Sanders <psanders@fonoster.com>",
6
6
  "homepage": "https://github.com/fonoster/routr#readme",
@@ -28,9 +28,9 @@
28
28
  "@opentelemetry/sdk-trace-base": "^1.0.4",
29
29
  "@opentelemetry/sdk-trace-node": "^1.0.4",
30
30
  "@opentelemetry/semantic-conventions": "^1.0.4",
31
- "@routr/common": "^2.0.8-alpha.2",
32
- "@routr/location": "^2.0.8-alpha.2",
33
- "@routr/processor": "^2.0.8-alpha.2"
31
+ "@routr/common": "^2.0.8-alpha.20",
32
+ "@routr/location": "^2.0.8-alpha.20",
33
+ "@routr/processor": "^2.0.8-alpha.20"
34
34
  },
35
35
  "files": [
36
36
  "dist"
@@ -45,5 +45,5 @@
45
45
  "bugs": {
46
46
  "url": "https://github.com/fonoster/routr/issues"
47
47
  },
48
- "gitHead": "28ab976b0ef8b5cd34e278ea6fda13c518d7d052"
48
+ "gitHead": "a22ee8342d03f5dfe46fddba89ffe3e6d0d5deb6"
49
49
  }