@dgac/nmb2b-client
Version:
EUROCONTROL Network Manager B2B SOAP client
472 lines (454 loc) • 12.5 kB
JavaScript
// src/Airspace/index.ts
import { createClient } from "soap";
// src/constants.ts
import path from "path";
var B2B_VERSION = "27.0.0";
var getWSDLPath = ({
service,
flavour,
XSD_PATH
}) => path.join(
XSD_PATH,
`${B2B_VERSION}/${service}_${flavour}_${B2B_VERSION}.wsdl`
);
// src/security.ts
import invariant from "invariant";
// src/utils/debug.ts
import d from "debug";
var PREFIX = "@dgac/nmb2b-client";
var debug = d(PREFIX);
function log(ns) {
if (!ns) {
return debug;
}
return debug.extend(ns);
}
var debug_default = log;
// src/security.ts
import {
ClientSSLSecurity,
ClientSSLSecurityPFX,
BasicAuthSecurity
} from "soap";
import fs from "fs";
var debug2 = debug_default("security");
function prepareSecurity(config) {
const { security } = config;
if ("apiKeyId" in security) {
const { apiKeyId, apiSecretKey } = security;
debug2("Using ApiGateway security");
return new BasicAuthSecurity(apiKeyId, apiSecretKey);
} else if ("pfx" in security) {
const { pfx, passphrase } = security;
debug2("Using PFX certificates");
return new ClientSSLSecurityPFX(pfx, passphrase);
} else if ("cert" in security) {
debug2("Using PEM certificates");
const { key, cert, passphrase } = security;
return new ClientSSLSecurity(
key,
cert,
void 0,
passphrase ? { passphrase } : null
);
}
throw new Error("Invalid security object");
}
// src/utils/transformers/types.ts
import { UTCDate } from "@date-fns/utc";
import { format } from "date-fns";
// src/utils/timeFormats.ts
var timeFormat = "yyyy-MM-dd HH:mm";
var dateFormat = "yyyy-MM-dd";
var timeFormatWithSeconds = timeFormat + ":ss";
// src/utils/transformers/types.ts
var outputBase = {
integer: (text) => {
return parseInt(text, 10);
},
/**
*
* Parse a NMB2B date/datetime.
*
* All datetimes are assumed to be UTC.
*
* Per NM B2B documentation, we only need to support these formats:
* - DateTimeMinute: YYYY-MM-DD hh:mm
* - DateTimeSecond: YYYY-MM-DD hh:mm:ss
* - DateYearMonthDay: YYYY-MM-DD
*
* All dates are
* @param text NM B2B Date string
* @returns Parsed Date instance
*/
date: (text) => {
let [date, time] = text.split(" ");
if (!time) {
return new Date(text);
}
if (time.length === 5) {
time += ":00";
}
return /* @__PURE__ */ new Date(`${date}T${time}Z`);
}
};
var types = {
FlightLevel_DataType: {
input: null,
output: outputBase.integer
},
DurationHourMinute: {
input: (d2) => {
const totalMinutes = Math.floor(d2 / 60);
const hours = Math.floor(totalMinutes / 60);
const minutes = totalMinutes % 60;
return `${hours}`.padStart(2, "0") + `${minutes}`.padStart(2, "0");
},
output: (s) => {
const hours = parseInt(s.slice(0, 2), 10);
const minutes = parseInt(s.slice(2), 10);
return 60 * (60 * hours + minutes);
}
},
DurationHourMinuteSecond: {
input: (d2) => {
const totalMinutes = Math.floor(d2 / 60);
const hours = Math.floor(totalMinutes / 60);
const minutes = totalMinutes % 60;
return `${hours}`.padStart(2, "0") + `${minutes}`.padStart(2, "0") + `${d2 % 60}`.padStart(2, "0");
},
output: (s) => {
const hours = parseInt(s.slice(0, 2), 10);
const minutes = parseInt(s.slice(2, 4), 10);
const seconds = parseInt(s.slice(4), 10);
return 3600 * hours + 60 * minutes + seconds;
}
},
DurationMinute: {
input: (d2) => Math.floor(d2 / 60),
output: (d2) => 60 * d2
},
CountsValue: {
input: null,
output: outputBase.integer
},
DateTimeMinute: {
input: (d2) => format(new UTCDate(d2), timeFormat),
output: outputBase.date
},
DateYearMonthDay: {
input: (d2) => format(new UTCDate(d2), dateFormat),
output: outputBase.date
},
DateTimeSecond: {
input: (d2) => format(new UTCDate(d2), timeFormatWithSeconds),
output: outputBase.date
},
DistanceNM: {
input: null,
output: outputBase.integer
},
DistanceM: {
input: null,
output: outputBase.integer
},
Bearing: {
input: null,
output: outputBase.integer
},
OTMVThreshold: {
input: null,
output: outputBase.integer
}
};
// src/utils/transformers/serializer.ts
import { piped, identity, evolve, map } from "remeda";
function prepareSerializer(schema) {
const transformer = prepareTransformer(schema);
return piped(
reorderKeys(schema),
transformer ? evolve(transformer) : identity
// (obj) => {
// console.log(JSON.stringify(obj, null, 2));
// return obj;
// },
);
}
function reduceXSDType(str) {
return str.split("|")[0];
}
function prepareTransformer(schema) {
return Object.keys(schema).reduce((prev, curr) => {
let key = curr;
let isArray = false;
if (curr.endsWith("[]")) {
key = curr.slice(0, -2);
isArray = true;
}
if (typeof schema[curr] === "string") {
const type = reduceXSDType(schema[curr]);
if (types[type]?.input) {
const transformer = types[type].input;
return { ...prev, [key]: isArray ? map(transformer) : transformer };
}
} else if (typeof schema[curr] === "object") {
const subItem = prepareTransformer(schema[curr]);
if (subItem) {
return {
...prev,
[key]: isArray ? map(evolve(subItem)) : subItem
};
}
}
return prev;
}, null);
}
function reorderKeys(schema) {
return (obj) => {
return Object.keys(schema).reduce((prev, curr) => {
const lookupKey = curr.replace(/\[\]$/, "");
const isArrayExpected = curr.endsWith("[]");
if (!(lookupKey in obj)) {
return prev;
}
const currSchema = schema[curr];
if (typeof currSchema === "string") {
prev[lookupKey] = obj[lookupKey];
return prev;
}
if (typeof currSchema === "object") {
if (Object.keys(currSchema).filter(
(k) => k !== "targetNSAlias" && k !== "targetNamespace"
).length) {
prev[lookupKey] = isArrayExpected && obj[lookupKey] && Array.isArray(obj[lookupKey]) ? obj[lookupKey].map(reorderKeys(currSchema)) : reorderKeys(currSchema)(obj[lookupKey]);
return prev;
}
prev[lookupKey] = obj[lookupKey];
return prev;
}
return prev;
}, {});
};
}
// src/utils/transformers/index.ts
var deserializer = Object.entries(types).reduce((prev, [key, { output }]) => {
if (output) {
prev[key] = output;
}
return prev;
}, {});
// src/utils/instrumentation/withLog.ts
function withLog(namespace) {
const debug3 = debug_default(namespace);
return (fn) => (values, options) => {
if (values) {
debug3("Called with input %o", values);
} else {
debug3("Called");
}
return fn(values, options).then(
(res) => {
debug3("Succeded");
return res;
},
(err) => {
debug3("Failed");
return Promise.reject(
err instanceof Error ? err : new Error("Unknown error", { cause: err })
);
}
);
};
}
// src/utils/instrumentation/index.ts
import { pipe } from "remeda";
function instrument({
service,
query
}) {
return (fn) => pipe(fn, withLog(`${service}:${query}`));
}
// src/utils/NMB2BError.ts
var NMB2BError = class extends Error {
constructor({
reply
}) {
super();
if (reply.requestId) {
this.requestId = reply.requestId;
}
if (reply.requestReceptionTime) {
this.requestReceptionTime = reply.requestReceptionTime;
}
if (reply.sendTime) {
this.sendTime = reply.sendTime;
}
if (reply.inputValidationErrors) {
this.inputValidationErrors = reply.inputValidationErrors;
}
if (reply.warnings) {
this.warnings = reply.warnings;
}
if (reply.slaError) {
this.slaError = reply.slaError;
}
if (reply.reason) {
this.reason = reply.reason;
}
this.status = reply.status;
this.message = this.status;
if (this.reason) {
this.message = `${this.message}: ${this.reason}`;
}
}
};
// src/utils/internals.ts
function injectSendTime(values) {
const sendTime = /* @__PURE__ */ new Date();
if (!values || typeof values !== "object") {
return { sendTime };
}
return { sendTime, ...values };
}
function responseStatusHandler(resolve, reject) {
return (err, reply) => {
if (err) {
reject(err);
return;
}
if (reply.status === "OK") {
resolve(reply);
return;
} else {
const err2 = new NMB2BError({
reply
});
reject(err2);
return;
}
};
}
// src/Airspace/queryCompleteAIXMDatasets.ts
function prepareQueryCompleteAIXMDatasets(client) {
const schema = (
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
client.describe().AirspaceStructureService.AirspaceStructurePort.queryCompleteAIXMDatasets.input
);
const serializer = prepareSerializer(schema);
return instrument({
service: "Airspace",
query: "queryCompleteAIXMDatasets"
})(
(values, options) => new Promise((resolve, reject) => {
client.queryCompleteAIXMDatasets(
serializer(injectSendTime(values)),
options,
responseStatusHandler(resolve, reject)
);
})
);
}
// src/Airspace/retrieveAUP.ts
function prepareRetrieveAUP(client) {
const schema = (
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
client.describe().AirspaceAvailabilityService.AirspaceAvailabilityPort.retrieveAUP.input
);
const serializer = prepareSerializer(schema);
return instrument({
service: "Airspace",
query: "retrieveAUP"
})(
(values, options) => new Promise((resolve, reject) => {
client.retrieveAUP(
serializer(injectSendTime(values)),
options,
responseStatusHandler(resolve, reject)
);
})
);
}
// src/Airspace/retrieveAUPChain.ts
function prepareRetrieveAUPChain(client) {
const schema = (
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
client.describe().AirspaceAvailabilityService.AirspaceAvailabilityPort.retrieveAUPChain.input
);
const serializer = prepareSerializer(schema);
return instrument({
service: "Airspace",
query: "retrieveAUPChain"
})(
(values, options) => new Promise((resolve, reject) => {
client.retrieveAUPChain(
serializer(injectSendTime(values)),
options,
responseStatusHandler(resolve, reject)
);
})
);
}
// src/Airspace/retrieveEAUPChain.ts
function prepareRetrieveEAUPChain(client) {
const schema = (
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
client.describe().AirspaceAvailabilityService.AirspaceAvailabilityPort.retrieveEAUPChain.input
);
const serializer = prepareSerializer(schema);
return instrument({
service: "Airspace",
query: "retrieveEAUPChain"
})(
(values, options) => new Promise((resolve, reject) => {
client.retrieveEAUPChain(
serializer(injectSendTime(values)),
options,
responseStatusHandler(resolve, reject)
);
})
);
}
// src/Airspace/index.ts
var getWSDL = ({
XSD_PATH,
flavour
}) => getWSDLPath({ service: "AirspaceServices", flavour, XSD_PATH });
function createAirspaceServices(config) {
const WSDL = getWSDL(config);
const security = prepareSecurity(config);
return new Promise((resolve, reject) => {
createClient(WSDL, { customDeserializer: deserializer }, (err, client) => {
try {
if (err) {
reject(
err instanceof Error ? err : new Error("Unknown error", { cause: err })
);
return;
}
client.setSecurity(security);
resolve(client);
} catch (err2) {
console.log(err2);
reject(
err2 instanceof Error ? err2 : new Error("Unknown error", { cause: err2 })
);
return;
}
});
});
}
function getAirspaceClient(config) {
return createAirspaceServices(config).then((client) => ({
__soapClient: client,
config,
queryCompleteAIXMDatasets: prepareQueryCompleteAIXMDatasets(client),
retrieveAUPChain: prepareRetrieveAUPChain(client),
retrieveEAUPChain: prepareRetrieveEAUPChain(client),
retrieveAUP: prepareRetrieveAUP(client)
}));
}
export {
getAirspaceClient,
getWSDL
};
//# sourceMappingURL=index.js.map