@dszp/netsapiens-lib 0.3.1 → 0.5.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 +26 -4
- package/dist/attribution.d.ts +11 -0
- package/dist/attribution.d.ts.map +1 -0
- package/dist/attribution.js +113 -0
- package/dist/attribution.js.map +1 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/inventory.d.ts +59 -5
- package/dist/inventory.d.ts.map +1 -1
- package/dist/inventory.js +72 -4
- package/dist/inventory.js.map +1 -1
- package/dist/model.d.ts +8 -0
- package/dist/model.d.ts.map +1 -1
- package/dist/nsClient.d.ts +6 -0
- package/dist/nsClient.d.ts.map +1 -1
- package/dist/nsClient.js +27 -0
- package/dist/nsClient.js.map +1 -1
- package/package.json +4 -3
- package/src/attribution.selftest.ts +73 -0
- package/src/attribution.ts +104 -0
- package/src/index.ts +2 -1
- package/src/inventory.selftest.ts +49 -5
- package/src/inventory.ts +98 -9
- package/src/model.ts +8 -0
- package/src/nsClient.selftest.ts +46 -0
- package/src/nsClient.ts +32 -0
package/dist/nsClient.js
CHANGED
|
@@ -207,6 +207,31 @@ export async function fetchDomainSnapshot(client, domain, opts = {}) {
|
|
|
207
207
|
if (devs.length)
|
|
208
208
|
devicesByUser[ext] = devs;
|
|
209
209
|
});
|
|
210
|
+
// SORTED before it leaves. These fill under `mapLimit`, so the order is whichever read failed first —
|
|
211
|
+
// a list that reshuffles between two reads of the same broken domain reads as data that changed, and a
|
|
212
|
+
// consumer prints this straight at an operator.
|
|
213
|
+
deviceReadFailures.sort();
|
|
214
|
+
}
|
|
215
|
+
// Per-user SMS numbers, same shape and reason as devices above: the domain-level list (see
|
|
216
|
+
// includeSmsNumbers) does not say which user a number belongs to.
|
|
217
|
+
let smsNumbersByUser;
|
|
218
|
+
let smsReadFailures;
|
|
219
|
+
if (opts.includeUserSmsNumbers) {
|
|
220
|
+
smsNumbersByUser = {};
|
|
221
|
+
smsReadFailures = [];
|
|
222
|
+
const seats = users.filter((u) => !String(u['service-code'] ?? '').trim().toLowerCase().startsWith('system-'));
|
|
223
|
+
await mapLimit(seats, conc, async (u) => {
|
|
224
|
+
const ext = String(u.user ?? '');
|
|
225
|
+
if (!ext)
|
|
226
|
+
return;
|
|
227
|
+
const list = await soft(`${base}/users/${enc(ext)}/smsnumbers`).catch(() => {
|
|
228
|
+
smsReadFailures.push(ext);
|
|
229
|
+
return [];
|
|
230
|
+
});
|
|
231
|
+
if (list.length)
|
|
232
|
+
smsNumbersByUser[ext] = list;
|
|
233
|
+
});
|
|
234
|
+
smsReadFailures.sort(); // same reason as deviceReadFailures above
|
|
210
235
|
}
|
|
211
236
|
const answerrulesByUser = {};
|
|
212
237
|
await mapLimit(users, conc, async (u) => {
|
|
@@ -267,6 +292,8 @@ export async function fetchDomainSnapshot(client, domain, opts = {}) {
|
|
|
267
292
|
...(smsnumbers ? { smsnumbers } : {}),
|
|
268
293
|
...(devicesByUser ? { devicesByUser } : {}),
|
|
269
294
|
...(deviceReadFailures ? { deviceReadFailures } : {}),
|
|
295
|
+
...(smsNumbersByUser ? { smsNumbersByUser } : {}),
|
|
296
|
+
...(smsReadFailures ? { smsReadFailures } : {}),
|
|
270
297
|
...(attendantDetailsByUser && Object.keys(attendantDetailsByUser).length ? { attendantDetailsByUser } : {}),
|
|
271
298
|
...(attendantDialrulesByExt && Object.keys(attendantDialrulesByExt).length ? { attendantDialrulesByExt } : {}),
|
|
272
299
|
...(dialrulesByPlan ? { dialrulesByPlan } : {}),
|
package/dist/nsClient.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nsClient.js","sourceRoot":"","sources":["../src/nsClient.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH,MAAM,OAAO,UAAW,SAAQ,KAAK;IAGjB;IACA;IACA;IAEA;IANlB,YACE,OAAe,EACC,MAAc,EACd,IAAY,EACZ,IAAa;IAC7B,gGAAgG;IAChF,MAAe;QAE/B,KAAK,CAAC,OAAO,CAAC,CAAC;QANC,WAAM,GAAN,MAAM,CAAQ;QACd,SAAI,GAAJ,IAAI,CAAQ;QACZ,SAAI,GAAJ,IAAI,CAAS;QAEb,WAAM,GAAN,MAAM,CAAS;QAG/B,IAAI,CAAC,IAAI,GAAG,YAAY,CAAC;IAC3B,CAAC;CACF;AAWD;;;;;;;;;;;GAWG;AACH;;;;;;;GAOG;AACH,MAAM,UAAU,gBAAgB,CAAC,MAAc;IAC7C,MAAM,CAAC,GAAG,MAAM,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IAC1D,IAAI,CAAM,CAAC;IACX,IAAI,CAAC;QACH,CAAC,GAAG,IAAI,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;IAC9B,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,sBAAsB,MAAM,sCAAsC,CAAC,CAAC;IACtF,CAAC;IACD,IAAI,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,QAAQ,EAAE,CAAC;QAC3D,MAAM,IAAI,KAAK,CAAC,sBAAsB,MAAM,yFAAyF,CAAC,CAAC;IACzI,CAAC;IACD,OAAO,CAAC,CAAC,IAAI,CAAC;AAChB,CAAC;AAED,MAAM,OAAO,QAAQ;IACV,QAAQ,CAAS;IACjB,MAAM,CAAS;IACf,UAAU,CAAe;IAElC,YAAY,GAAmB;QAC7B,IAAI,CAAC,QAAQ,GAAG,WAAW,gBAAgB,CAAC,GAAG,CAAC,MAAM,CAAC,YAAY,CAAC;QACpE,IAAI,CAAC,MAAM,GAAG,GAAG,CAAC,KAAK,CAAC;QACxB,IAAI,CAAC,UAAU,GAAG,GAAG,CAAC,SAAS,IAAI,KAAK,CAAC;IAC3C,CAAC;IAED,KAAK,CAAC,GAAG,CAAc,IAAY,EAAE,KAAuC;QAC1E,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC;QAC1C,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,IAAI,EAAE,CAAC;YAAE,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;QAErF,8FAA8F;QAC9F,+FAA+F;QAC/F,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,CAAC;QAChC,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE;YACxC,MAAM,EAAE,KAAK;YACb,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,IAAI,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,kBAAkB,EAAE;SAChF,CAAC,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;QAC9B,IAAI,MAAM,GAAY,IAAI,CAAC;QAC3B,IAAI,IAAI,EAAE,CAAC;YACT,IAAI,CAAC;gBACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YAC5B,CAAC;YAAC,MAAM,CAAC;gBACP,gDAAgD;YAClD,CAAC;QACH,CAAC;QACD,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACZ,0FAA0F;YAC1F,8FAA8F;YAC9F,yEAAyE;YACzE,MAAM,MAAM,GAAG,CAAC,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;YACvH,MAAM,IAAI,GAAG,GAAG,CAAC,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC,iDAAiD,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC,2BAA2B,CAAC,CAAC,CAAC,EAAE,CAAC;YAC5I,MAAM,IAAI,UAAU,CAAC,OAAO,IAAI,MAAM,GAAG,CAAC,MAAM,GAAG,IAAI,KAAK,MAAM,EAAE,EAAE,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;QAClG,CAAC;QACD,OAAO,MAAW,CAAC;IACrB,CAAC;CACF;AAED,mGAAmG;AACnG,MAAM,UAAU,OAAO,CAAC,GAAY;IAClC,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC;QAAE,OAAO,GAAY,CAAC;IAC5C,IAAI,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ;QAAE,OAAO,CAAC,GAAU,CAAC,CAAC;IACxD,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,6FAA6F;AAC7F,KAAK,UAAU,QAAQ,CAAI,KAAU,EAAE,KAAa,EAAE,EAA6C;IACjG,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,EAAE,EAAE,KAAK,IAAI,EAAE;QAC/E,OAAO,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC;YACxB,MAAM,GAAG,GAAG,CAAC,EAAE,CAAC;YAChB,MAAM,EAAE,CAAC,KAAK,CAAC,GAAG,CAAE,EAAE,GAAG,CAAC,CAAC;QAC7B,CAAC;IACH,CAAC,CAAC,CAAC;IACH,MAAM,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;AAC7B,CAAC;AAED,MAAM,GAAG,GAAG,kBAAkB,CAAC;AAE/B;iFACiF;AACjF,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,MAAgB;IAChD,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC;IACnD,OAAO,IAAI;SACR,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACX,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,MAAM,IAAI,EAAE,CAAC;QAC9B,GAAG,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAChE,GAAG,CAAC,CAAC,CAAC,kBAAkB,CAAC,KAAK,KAAK,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC7D,CAAC,CAAC;SACF,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;AAC7B,CAAC;AAyCD;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,MAAgB,EAAE,MAAc,EAAE,OAA6B,EAAE;IACzG,MAAM,IAAI,GAAG,IAAI,CAAC,WAAW,IAAI,CAAC,CAAC;IACnC,MAAM,IAAI,GAAG,YAAY,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;IACvC,MAAM,IAAI,GAAG,KAAK,EAAE,CAAS,EAAkB,EAAE;QAC/C,IAAI,CAAC;YACH,OAAO,OAAO,CAAC,MAAM,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QACtC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,GAAG,YAAY,UAAU,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG;gBAAE,OAAO,EAAE,CAAC;YAC/D,MAAM,GAAG,CAAC;QACZ,CAAC;IACH,CAAC,CAAC;IAEF,MAAM,SAAS,GAAG,OAAO,CAAC,MAAM,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC;IACnE,MAAM,CAAC,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,cAAc,EAAE,SAAS,EAAE,UAAU,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QAC7G,IAAI,CAAC,GAAG,IAAI,aAAa,CAAC;QAC1B,IAAI,CAAC,GAAG,IAAI,QAAQ,CAAC;QACrB,IAAI,CAAC,GAAG,IAAI,aAAa,CAAC;QAC1B,IAAI,CAAC,GAAG,IAAI,eAAe,CAAC;QAC5B,IAAI,CAAC,GAAG,IAAI,iBAAiB,CAAC;QAC9B,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,IAAI,YAAY,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC;QAC9E,mGAAmG;QACnG,qGAAqG;QACrG,IAAI,CAAC,iBAAiB,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,IAAI,oBAAoB,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC;KACxF,CAAC,CAAC;IAEH,mGAAmG;IACnG,mEAAmE;IACnE,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;QACjB,IAAI,iBAAoD,CAAC;QACzD,IAAI,IAAI,CAAC,mBAAmB,EAAE,CAAC;YAC7B,MAAM,KAAK,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,wCAAwC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;YAC/H,iBAAiB,GAAG,EAAE,CAAC;YACvB,MAAM,QAAQ,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;gBACtC,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,GAAG,IAAI,UAAU,GAAG,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;gBAChF,IAAI,KAAK,CAAC,MAAM;oBAAE,iBAAkB,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC;YAClD,CAAC,CAAC,CAAC;QACL,CAAC;QACD,OAAO;YACL,IAAI,EAAE,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,cAAc;YAChG,GAAG,CAAC,iBAAiB,CAAC,CAAC,CAAC,EAAE,iBAAiB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACnD,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACnC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACtC,CAAC;IACJ,CAAC;IAED,qGAAqG;IACrG,qEAAqE;IACrE,IAAI,aAAgD,CAAC;IACrD,IAAI,kBAAwC,CAAC;IAC7C,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC;QACxB,aAAa,GAAG,EAAE,CAAC;QACnB,kBAAkB,GAAG,EAAE,CAAC;QACxB,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,cAAc,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC;QAC/G,MAAM,QAAQ,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;YACtC,MAAM,GAAG,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;YACjC,IAAI,CAAC,GAAG;gBAAE,OAAO;YACjB,8FAA8F;YAC9F,6FAA6F;YAC7F,2DAA2D;YAC3D,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,GAAG,IAAI,UAAU,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE;gBACtE,kBAAmB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;gBAC9B,OAAO,EAAE,CAAC;YACZ,CAAC,CAAC,CAAC;YACH,IAAI,IAAI,CAAC,MAAM;gBAAE,aAAc,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC;QAC9C,CAAC,CAAC,CAAC;IACL,CAAC;IAED,MAAM,iBAAiB,GAA0B,EAAE,CAAC;IACpD,MAAM,QAAQ,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;QACtC,MAAM,GAAG,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;QACjC,IAAI,CAAC,GAAG;YAAE,OAAO;QACjB,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,GAAG,IAAI,UAAU,GAAG,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;QAClF,IAAI,KAAK,CAAC,MAAM;YAAE,iBAAiB,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;IACnD,CAAC,CAAC,CAAC;IAEH,MAAM,aAAa,GAA0B,EAAE,CAAC;IAChD,MAAM,QAAQ,CAAC,UAAU,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;QAC3C,MAAM,GAAG,GAAG,MAAM,CAAC,CAAC,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC;QACtC,IAAI,CAAC,GAAG;YAAE,OAAO;QACjB,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,GAAG,IAAI,eAAe,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;QAChF,IAAI,GAAG,CAAC,MAAM;YAAE,aAAa,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC;IAC3C,CAAC,CAAC,CAAC;IAEH,gGAAgG;IAChG,iGAAiG;IACjG,gGAAgG;IAChG,iHAAiH;IACjH,IAAI,sBAAyD,CAAC;IAC9D,IAAI,uBAA0D,CAAC;IAC/D,IAAI,IAAI,CAAC,qBAAqB,IAAI,IAAI,EAAE,CAAC;QACvC,MAAM,IAAI,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC,EAAE,CAAC,IAAI,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,iBAAiB,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC;QACxJ,sBAAsB,GAAG,EAAE,CAAC;QAC5B,KAAK,MAAM,CAAC,IAAI,IAAI;YAAE,sBAAsB,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC,wCAAwC;QACpG,MAAM,QAAQ,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;YACrC,MAAM,MAAM,GAAG,CAAC,MAAM,IAAI,CAAC,GAAG,IAAI,UAAU,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,mBAAmB,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YAC9G,IAAI,MAAM;gBAAE,sBAAuB,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC1D,CAAC,CAAC,CAAC;QACH,uBAAuB,GAAG,EAAE,CAAC;QAC7B,MAAM,QAAQ,CAAC,CAAC,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;YACvE,MAAM,EAAE,GAAG,MAAM,IAAI,CAAC,GAAG,IAAI,cAAc,GAAG,CAAC,GAAG,MAAM,IAAI,GAAG,EAAE,CAAC,YAAY,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;YAChG,IAAI,EAAE,CAAC,MAAM;gBAAE,uBAAwB,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC;QACpD,CAAC,CAAC,CAAC;IACL,CAAC;IAED,IAAI,eAAkD,CAAC;IACvD,IAAI,IAAI,CAAC,gBAAgB,EAAE,CAAC;QAC1B,eAAe,GAAG,EAAE,CAAC,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC,GAAG,IAAI,cAAc,GAAG,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;IAC3G,CAAC;IAED,OAAO;QACL,IAAI,EAAE,EAAE,MAAM,EAAE;QAChB,MAAM,EAAE,SAAS;QACjB,UAAU;QACV,KAAK;QACL,UAAU;QACV,YAAY;QACZ,cAAc;QACd,iBAAiB;QACjB,aAAa;QACb,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACnC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACrC,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC3C,GAAG,CAAC,kBAAkB,CAAC,CAAC,CAAC,EAAE,kBAAkB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACrD,GAAG,CAAC,sBAAsB,IAAI,MAAM,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,sBAAsB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC3G,GAAG,CAAC,uBAAuB,IAAI,MAAM,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,uBAAuB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC9G,GAAG,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE,eAAe,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAChD,CAAC;AACJ,CAAC"}
|
|
1
|
+
{"version":3,"file":"nsClient.js","sourceRoot":"","sources":["../src/nsClient.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH,MAAM,OAAO,UAAW,SAAQ,KAAK;IAGjB;IACA;IACA;IAEA;IANlB,YACE,OAAe,EACC,MAAc,EACd,IAAY,EACZ,IAAa;IAC7B,gGAAgG;IAChF,MAAe;QAE/B,KAAK,CAAC,OAAO,CAAC,CAAC;QANC,WAAM,GAAN,MAAM,CAAQ;QACd,SAAI,GAAJ,IAAI,CAAQ;QACZ,SAAI,GAAJ,IAAI,CAAS;QAEb,WAAM,GAAN,MAAM,CAAS;QAG/B,IAAI,CAAC,IAAI,GAAG,YAAY,CAAC;IAC3B,CAAC;CACF;AAWD;;;;;;;;;;;GAWG;AACH;;;;;;;GAOG;AACH,MAAM,UAAU,gBAAgB,CAAC,MAAc;IAC7C,MAAM,CAAC,GAAG,MAAM,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IAC1D,IAAI,CAAM,CAAC;IACX,IAAI,CAAC;QACH,CAAC,GAAG,IAAI,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;IAC9B,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,sBAAsB,MAAM,sCAAsC,CAAC,CAAC;IACtF,CAAC;IACD,IAAI,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,QAAQ,EAAE,CAAC;QAC3D,MAAM,IAAI,KAAK,CAAC,sBAAsB,MAAM,yFAAyF,CAAC,CAAC;IACzI,CAAC;IACD,OAAO,CAAC,CAAC,IAAI,CAAC;AAChB,CAAC;AAED,MAAM,OAAO,QAAQ;IACV,QAAQ,CAAS;IACjB,MAAM,CAAS;IACf,UAAU,CAAe;IAElC,YAAY,GAAmB;QAC7B,IAAI,CAAC,QAAQ,GAAG,WAAW,gBAAgB,CAAC,GAAG,CAAC,MAAM,CAAC,YAAY,CAAC;QACpE,IAAI,CAAC,MAAM,GAAG,GAAG,CAAC,KAAK,CAAC;QACxB,IAAI,CAAC,UAAU,GAAG,GAAG,CAAC,SAAS,IAAI,KAAK,CAAC;IAC3C,CAAC;IAED,KAAK,CAAC,GAAG,CAAc,IAAY,EAAE,KAAuC;QAC1E,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC;QAC1C,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,IAAI,EAAE,CAAC;YAAE,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;QAErF,8FAA8F;QAC9F,+FAA+F;QAC/F,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,CAAC;QAChC,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE;YACxC,MAAM,EAAE,KAAK;YACb,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,IAAI,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,kBAAkB,EAAE;SAChF,CAAC,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;QAC9B,IAAI,MAAM,GAAY,IAAI,CAAC;QAC3B,IAAI,IAAI,EAAE,CAAC;YACT,IAAI,CAAC;gBACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YAC5B,CAAC;YAAC,MAAM,CAAC;gBACP,gDAAgD;YAClD,CAAC;QACH,CAAC;QACD,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACZ,0FAA0F;YAC1F,8FAA8F;YAC9F,yEAAyE;YACzE,MAAM,MAAM,GAAG,CAAC,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;YACvH,MAAM,IAAI,GAAG,GAAG,CAAC,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC,iDAAiD,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC,2BAA2B,CAAC,CAAC,CAAC,EAAE,CAAC;YAC5I,MAAM,IAAI,UAAU,CAAC,OAAO,IAAI,MAAM,GAAG,CAAC,MAAM,GAAG,IAAI,KAAK,MAAM,EAAE,EAAE,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;QAClG,CAAC;QACD,OAAO,MAAW,CAAC;IACrB,CAAC;CACF;AAED,mGAAmG;AACnG,MAAM,UAAU,OAAO,CAAC,GAAY;IAClC,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC;QAAE,OAAO,GAAY,CAAC;IAC5C,IAAI,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ;QAAE,OAAO,CAAC,GAAU,CAAC,CAAC;IACxD,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,6FAA6F;AAC7F,KAAK,UAAU,QAAQ,CAAI,KAAU,EAAE,KAAa,EAAE,EAA6C;IACjG,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,EAAE,EAAE,KAAK,IAAI,EAAE;QAC/E,OAAO,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC;YACxB,MAAM,GAAG,GAAG,CAAC,EAAE,CAAC;YAChB,MAAM,EAAE,CAAC,KAAK,CAAC,GAAG,CAAE,EAAE,GAAG,CAAC,CAAC;QAC7B,CAAC;IACH,CAAC,CAAC,CAAC;IACH,MAAM,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;AAC7B,CAAC;AAED,MAAM,GAAG,GAAG,kBAAkB,CAAC;AAE/B;iFACiF;AACjF,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,MAAgB;IAChD,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC;IACnD,OAAO,IAAI;SACR,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACX,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,MAAM,IAAI,EAAE,CAAC;QAC9B,GAAG,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAChE,GAAG,CAAC,CAAC,CAAC,kBAAkB,CAAC,KAAK,KAAK,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC7D,CAAC,CAAC;SACF,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;AAC7B,CAAC;AA+CD;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,MAAgB,EAAE,MAAc,EAAE,OAA6B,EAAE;IACzG,MAAM,IAAI,GAAG,IAAI,CAAC,WAAW,IAAI,CAAC,CAAC;IACnC,MAAM,IAAI,GAAG,YAAY,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;IACvC,MAAM,IAAI,GAAG,KAAK,EAAE,CAAS,EAAkB,EAAE;QAC/C,IAAI,CAAC;YACH,OAAO,OAAO,CAAC,MAAM,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QACtC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,GAAG,YAAY,UAAU,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG;gBAAE,OAAO,EAAE,CAAC;YAC/D,MAAM,GAAG,CAAC;QACZ,CAAC;IACH,CAAC,CAAC;IAEF,MAAM,SAAS,GAAG,OAAO,CAAC,MAAM,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC;IACnE,MAAM,CAAC,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,cAAc,EAAE,SAAS,EAAE,UAAU,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QAC7G,IAAI,CAAC,GAAG,IAAI,aAAa,CAAC;QAC1B,IAAI,CAAC,GAAG,IAAI,QAAQ,CAAC;QACrB,IAAI,CAAC,GAAG,IAAI,aAAa,CAAC;QAC1B,IAAI,CAAC,GAAG,IAAI,eAAe,CAAC;QAC5B,IAAI,CAAC,GAAG,IAAI,iBAAiB,CAAC;QAC9B,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,IAAI,YAAY,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC;QAC9E,mGAAmG;QACnG,qGAAqG;QACrG,IAAI,CAAC,iBAAiB,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,IAAI,oBAAoB,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC;KACxF,CAAC,CAAC;IAEH,mGAAmG;IACnG,mEAAmE;IACnE,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;QACjB,IAAI,iBAAoD,CAAC;QACzD,IAAI,IAAI,CAAC,mBAAmB,EAAE,CAAC;YAC7B,MAAM,KAAK,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,wCAAwC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;YAC/H,iBAAiB,GAAG,EAAE,CAAC;YACvB,MAAM,QAAQ,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;gBACtC,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,GAAG,IAAI,UAAU,GAAG,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;gBAChF,IAAI,KAAK,CAAC,MAAM;oBAAE,iBAAkB,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC;YAClD,CAAC,CAAC,CAAC;QACL,CAAC;QACD,OAAO;YACL,IAAI,EAAE,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,cAAc;YAChG,GAAG,CAAC,iBAAiB,CAAC,CAAC,CAAC,EAAE,iBAAiB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACnD,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACnC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACtC,CAAC;IACJ,CAAC;IAED,qGAAqG;IACrG,qEAAqE;IACrE,IAAI,aAAgD,CAAC;IACrD,IAAI,kBAAwC,CAAC;IAC7C,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC;QACxB,aAAa,GAAG,EAAE,CAAC;QACnB,kBAAkB,GAAG,EAAE,CAAC;QACxB,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,cAAc,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC;QAC/G,MAAM,QAAQ,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;YACtC,MAAM,GAAG,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;YACjC,IAAI,CAAC,GAAG;gBAAE,OAAO;YACjB,8FAA8F;YAC9F,6FAA6F;YAC7F,2DAA2D;YAC3D,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,GAAG,IAAI,UAAU,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE;gBACtE,kBAAmB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;gBAC9B,OAAO,EAAE,CAAC;YACZ,CAAC,CAAC,CAAC;YACH,IAAI,IAAI,CAAC,MAAM;gBAAE,aAAc,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC;QAC9C,CAAC,CAAC,CAAC;QACH,sGAAsG;QACtG,uGAAuG;QACvG,gDAAgD;QAChD,kBAAkB,CAAC,IAAI,EAAE,CAAC;IAC5B,CAAC;IAED,2FAA2F;IAC3F,kEAAkE;IAClE,IAAI,gBAAmD,CAAC;IACxD,IAAI,eAAqC,CAAC;IAC1C,IAAI,IAAI,CAAC,qBAAqB,EAAE,CAAC;QAC/B,gBAAgB,GAAG,EAAE,CAAC;QACtB,eAAe,GAAG,EAAE,CAAC;QACrB,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,cAAc,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC;QAC/G,MAAM,QAAQ,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;YACtC,MAAM,GAAG,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;YACjC,IAAI,CAAC,GAAG;gBAAE,OAAO;YACjB,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,GAAG,IAAI,UAAU,GAAG,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE;gBACzE,eAAgB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;gBAC3B,OAAO,EAAE,CAAC;YACZ,CAAC,CAAC,CAAC;YACH,IAAI,IAAI,CAAC,MAAM;gBAAE,gBAAiB,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC;QACjD,CAAC,CAAC,CAAC;QACH,eAAe,CAAC,IAAI,EAAE,CAAC,CAAG,0CAA0C;IACtE,CAAC;IAED,MAAM,iBAAiB,GAA0B,EAAE,CAAC;IACpD,MAAM,QAAQ,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;QACtC,MAAM,GAAG,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;QACjC,IAAI,CAAC,GAAG;YAAE,OAAO;QACjB,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,GAAG,IAAI,UAAU,GAAG,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;QAClF,IAAI,KAAK,CAAC,MAAM;YAAE,iBAAiB,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;IACnD,CAAC,CAAC,CAAC;IAEH,MAAM,aAAa,GAA0B,EAAE,CAAC;IAChD,MAAM,QAAQ,CAAC,UAAU,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;QAC3C,MAAM,GAAG,GAAG,MAAM,CAAC,CAAC,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC;QACtC,IAAI,CAAC,GAAG;YAAE,OAAO;QACjB,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,GAAG,IAAI,eAAe,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;QAChF,IAAI,GAAG,CAAC,MAAM;YAAE,aAAa,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC;IAC3C,CAAC,CAAC,CAAC;IAEH,gGAAgG;IAChG,iGAAiG;IACjG,gGAAgG;IAChG,iHAAiH;IACjH,IAAI,sBAAyD,CAAC;IAC9D,IAAI,uBAA0D,CAAC;IAC/D,IAAI,IAAI,CAAC,qBAAqB,IAAI,IAAI,EAAE,CAAC;QACvC,MAAM,IAAI,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC,EAAE,CAAC,IAAI,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,iBAAiB,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC;QACxJ,sBAAsB,GAAG,EAAE,CAAC;QAC5B,KAAK,MAAM,CAAC,IAAI,IAAI;YAAE,sBAAsB,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC,wCAAwC;QACpG,MAAM,QAAQ,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;YACrC,MAAM,MAAM,GAAG,CAAC,MAAM,IAAI,CAAC,GAAG,IAAI,UAAU,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,mBAAmB,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YAC9G,IAAI,MAAM;gBAAE,sBAAuB,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC1D,CAAC,CAAC,CAAC;QACH,uBAAuB,GAAG,EAAE,CAAC;QAC7B,MAAM,QAAQ,CAAC,CAAC,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;YACvE,MAAM,EAAE,GAAG,MAAM,IAAI,CAAC,GAAG,IAAI,cAAc,GAAG,CAAC,GAAG,MAAM,IAAI,GAAG,EAAE,CAAC,YAAY,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;YAChG,IAAI,EAAE,CAAC,MAAM;gBAAE,uBAAwB,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC;QACpD,CAAC,CAAC,CAAC;IACL,CAAC;IAED,IAAI,eAAkD,CAAC;IACvD,IAAI,IAAI,CAAC,gBAAgB,EAAE,CAAC;QAC1B,eAAe,GAAG,EAAE,CAAC,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC,GAAG,IAAI,cAAc,GAAG,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;IAC3G,CAAC;IAED,OAAO;QACL,IAAI,EAAE,EAAE,MAAM,EAAE;QAChB,MAAM,EAAE,SAAS;QACjB,UAAU;QACV,KAAK;QACL,UAAU;QACV,YAAY;QACZ,cAAc;QACd,iBAAiB;QACjB,aAAa;QACb,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACnC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACrC,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC3C,GAAG,CAAC,kBAAkB,CAAC,CAAC,CAAC,EAAE,kBAAkB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACrD,GAAG,CAAC,gBAAgB,CAAC,CAAC,CAAC,EAAE,gBAAgB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACjD,GAAG,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE,eAAe,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC/C,GAAG,CAAC,sBAAsB,IAAI,MAAM,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,sBAAsB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC3G,GAAG,CAAC,uBAAuB,IAAI,MAAM,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,uBAAuB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC9G,GAAG,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE,eAAe,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAChD,CAAC;AACJ,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dszp/netsapiens-lib",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Portable, Node-free NetSapiens toolkit: split read/write API clients, JWT (ns_t) validation, and a snapshot -> FlowGraph -> Mermaid call-flow resolver/renderer. Runs unchanged in a Cloudflare Worker, Node, or the browser.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -59,7 +59,7 @@
|
|
|
59
59
|
"//prepublishOnly": "Publish-only build with sourcemaps OFF. The `files` globs exclude dist/**/*.map on purpose (they point at src/, which does not ship), but tsc still emits a //# sourceMappingURL pointer into every .js/.d.ts -- so consumers' devtools 404 chasing maps that were never published. Dropping the pointer at publish time is what the exclusion always meant. A normal `pnpm build` keeps maps for link: consumers.",
|
|
60
60
|
"prepublishOnly": "tsc -p tsconfig.json --sourceMap false --declarationMap false",
|
|
61
61
|
"//test": "The offline suite — green on a fresh clone with no credentials and no fixtures. test:ns is NOT included: it needs a domain snapshot that (correctly) isn't in the repo.",
|
|
62
|
-
"test": "pnpm run test:jwt && pnpm run test:principal && pnpm run test:resolver && pnpm run test:raster && pnpm run test:nswrite && pnpm run test:nssync && pnpm run test:eligibility && pnpm run test:nsauth && pnpm test:nssubs && pnpm test:nsdevice && pnpm run test:inventory",
|
|
62
|
+
"test": "pnpm run test:jwt && pnpm run test:principal && pnpm run test:resolver && pnpm run test:raster && pnpm run test:nswrite && pnpm run test:nssync && pnpm run test:eligibility && pnpm run test:nsauth && pnpm test:nssubs && pnpm test:nsdevice && pnpm run test:inventory && pnpm run test:attribution",
|
|
63
63
|
"test:jwt": "tsx src/jwt.selftest.ts",
|
|
64
64
|
"test:ns": "tsx src/nsClient.selftest.ts",
|
|
65
65
|
"test:nswrite": "tsx src/nsWriteClient.selftest.ts",
|
|
@@ -71,7 +71,8 @@
|
|
|
71
71
|
"test:eligibility": "tsx src/eligibility.selftest.ts",
|
|
72
72
|
"test:nssubs": "tsx src/nsSubscriptions.selftest.ts",
|
|
73
73
|
"test:nsdevice": "tsx src/nsDevice.selftest.ts",
|
|
74
|
-
"test:inventory": "tsx src/inventory.selftest.ts"
|
|
74
|
+
"test:inventory": "tsx src/inventory.selftest.ts",
|
|
75
|
+
"test:attribution": "tsx src/attribution.selftest.ts"
|
|
75
76
|
},
|
|
76
77
|
"devDependencies": {
|
|
77
78
|
"tsx": "^4.22.4",
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/** Offline test for item→site attribution. pnpm test:attribution */
|
|
2
|
+
import { attributeDomainInventory } from './attribution.js';
|
|
3
|
+
import { listDomainInventory } from './inventory.js';
|
|
4
|
+
import type { Snapshot } from './model.js';
|
|
5
|
+
|
|
6
|
+
let pass = 0, fail = 0;
|
|
7
|
+
const ok = (c: boolean, m: string) => { c ? pass++ : fail++; console.log(`${c ? 'PASS' : 'FAIL'} ${m}`); };
|
|
8
|
+
|
|
9
|
+
const snap: Snapshot = {
|
|
10
|
+
meta: { domain: 'acme.example' },
|
|
11
|
+
users: [
|
|
12
|
+
{ user: '100', site: 'North', 'service-code': '', 'emergency-address-id': 'a-1' },
|
|
13
|
+
{ user: '101', site: 'South', 'service-code': '', 'emergency-address-id': 'a-1' },
|
|
14
|
+
{ user: '102', site: 'South', 'service-code': '', 'emergency-address-id': 'a-2' },
|
|
15
|
+
{ user: '103', site: '', 'service-code': '' }, // no site
|
|
16
|
+
{ user: '701', site: 'North', 'service-code': 'system-queue' }, // a queue is a user too
|
|
17
|
+
{ user: '702', site: '', 'service-code': 'system-tod' }, // a site-less system user
|
|
18
|
+
],
|
|
19
|
+
phonenumbers: [
|
|
20
|
+
{ phonenumber: '13175550100', 'dial-rule-application': 'to-user', 'dial-rule-translation-destination-user': '100' },
|
|
21
|
+
{ phonenumber: '13175550101', 'dial-rule-application': 'to-user', 'dial-rule-translation-destination-user': '701' },
|
|
22
|
+
{ phonenumber: '13175550102', 'dial-rule-application': 'to-connection', 'dial-rule-translation-destination-user': '' },
|
|
23
|
+
{ phonenumber: '13175550103', 'dial-rule-application': 'to-user', 'dial-rule-translation-destination-user': '103' },
|
|
24
|
+
{ phonenumber: '13175550104', 'dial-rule-application': 'to-user', 'dial-rule-translation-destination-user': '999' },
|
|
25
|
+
{ phonenumber: '13175550106', 'dial-rule-application': 'to-user', 'dial-rule-translation-destination-user': '702' },
|
|
26
|
+
],
|
|
27
|
+
addresses: [
|
|
28
|
+
{ 'emergency-address-id': 'a-1', 'address-name': 'Shared' },
|
|
29
|
+
{ 'emergency-address-id': 'a-2', 'address-name': 'South only' },
|
|
30
|
+
{ 'emergency-address-id': 'a-3', 'address-name': 'Nobody' },
|
|
31
|
+
],
|
|
32
|
+
smsnumbers: [{ number: '13175550100' }, { number: '13175550102' }, { number: '13175550199' }],
|
|
33
|
+
smsNumbersByUser: { '100': [{ number: '13175550100' }], '103': [{ number: '13175550102' }] },
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const a = attributeDomainInventory(snap).items;
|
|
37
|
+
const d = listDomainInventory(snap);
|
|
38
|
+
const allKeys = [...d.extensions, ...d.dids, ...d.e911Addresses, ...d.smsNumbers].map((i) => i.key);
|
|
39
|
+
ok(allKeys.every((k) => k in a), 'every extension, number, address and SMS number has an attribution');
|
|
40
|
+
ok(Object.keys(a).length === allKeys.length, 'and nothing else does (system users are not items)');
|
|
41
|
+
|
|
42
|
+
ok(a['ext:100']!.site === 'North' && a['ext:100']!.how === 'own-site', 'an extension is attributed to its own site');
|
|
43
|
+
ok(a['ext:103']!.site === null && a['ext:103']!.how === 'unattributed:no-site', 'an extension with a blank site is unattributed:no-site');
|
|
44
|
+
|
|
45
|
+
ok(a['did:13175550100']!.site === 'North' && a['did:13175550100']!.how === 'via-user:100', 'a number routed to a user inherits that user\'s site');
|
|
46
|
+
ok(a['did:13175550101']!.site === 'North' && a['did:13175550101']!.how === 'via-user:701', 'a number routed to a system user with a site inherits that site, same as a real user');
|
|
47
|
+
ok(a['did:13175550106']!.site === null && a['did:13175550106']!.how === 'unattributed:routed-to:system-tod', 'a number routed to a site-less system user names its service code');
|
|
48
|
+
ok(a['did:13175550102']!.site === null && a['did:13175550102']!.how === 'unattributed:routed-to:to-connection', 'a number routed to a connection names the application');
|
|
49
|
+
ok(a['did:13175550103']!.site === null && a['did:13175550103']!.how === 'unattributed:no-site', 'a number routed to a site-less user is no-site, not routed-to');
|
|
50
|
+
ok(a['did:13175550104']!.site === null && a['did:13175550104']!.how === 'unattributed:routed-to:to-user', 'a number whose destination user does not exist falls back to the application name');
|
|
51
|
+
|
|
52
|
+
ok(a['addr:a-1']!.site === null && a['addr:a-1']!.how === 'unattributed:shared-across:North,South', 'an address referenced from two sites is shared, sites sorted');
|
|
53
|
+
ok(a['addr:a-2']!.site === 'South' && a['addr:a-2']!.how === 'via-users:102', 'an address referenced from one site follows it and names the users');
|
|
54
|
+
ok(a['addr:a-3']!.site === null && a['addr:a-3']!.how === 'unattributed:unreferenced', 'an address nobody references is unreferenced');
|
|
55
|
+
|
|
56
|
+
ok(a['sms:13175550100']!.site === 'North' && a['sms:13175550100']!.how === 'via-user:100', 'an SMS number follows the user it is enabled on');
|
|
57
|
+
ok(a['sms:13175550102']!.site === null && a['sms:13175550102']!.how === 'unattributed:no-site', 'an SMS number on a site-less user is no-site');
|
|
58
|
+
ok(a['sms:13175550199']!.site === null && a['sms:13175550199']!.how === 'unattributed:sms-user-unknown', 'an SMS number no per-user list claims is sms-user-unknown');
|
|
59
|
+
|
|
60
|
+
// Without the per-user read at all, every SMS number is unknown — never guessed.
|
|
61
|
+
const noUser = attributeDomainInventory({ ...snap, smsNumbersByUser: undefined }).items;
|
|
62
|
+
ok(noUser['sms:13175550100']!.how === 'unattributed:sms-user-unknown', 'with no per-user SMS read, SMS numbers are sms-user-unknown');
|
|
63
|
+
|
|
64
|
+
// The address rule reads REAL extensions only: a queue referencing an address must not place it.
|
|
65
|
+
const queueAddr = attributeDomainInventory({ ...snap, users: [{ user: '701', site: 'North', 'service-code': 'system-queue', 'emergency-address-id': 'a-3' }], addresses: [{ 'emergency-address-id': 'a-3' }] }).items;
|
|
66
|
+
ok(queueAddr['addr:a-3']!.how === 'unattributed:unreferenced', 'a system user referencing an address does not attribute it');
|
|
67
|
+
|
|
68
|
+
// A number routed to a system user by an application other than to-user still names the service code.
|
|
69
|
+
const devRoute = attributeDomainInventory({ ...snap, phonenumbers: [{ phonenumber: '13175550105', 'dial-rule-application': 'to-single-device', 'dial-rule-translation-destination-user': '101' }] }).items;
|
|
70
|
+
ok(devRoute['did:13175550105']!.site === 'South' && devRoute['did:13175550105']!.how === 'via-user:101', 'to-single-device to a real user inherits the site like to-user');
|
|
71
|
+
|
|
72
|
+
console.log(`\n${pass} passed, ${fail} failed`);
|
|
73
|
+
if (fail) process.exit(1);
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which SITE each inventory item belongs to, and how that was decided. Pure: feed it the same
|
|
3
|
+
* `Snapshot` `listDomainInventory` takes, get one verdict per item key.
|
|
4
|
+
*
|
|
5
|
+
* ## Why a library concern
|
|
6
|
+
*
|
|
7
|
+
* A NetSapiens domain can be billed in pieces — one account per site, or one account for most of
|
|
8
|
+
* it and another for one branch — and the phone system already knows most of what is needed to
|
|
9
|
+
* split it: a user carries `site`, a number carries its destination user, an SMS number is enabled
|
|
10
|
+
* on a user, an address is referenced by users. What it does NOT know is who pays; that stays with
|
|
11
|
+
* the consumer. This module answers "which site", never "which account".
|
|
12
|
+
*
|
|
13
|
+
* ## The rules
|
|
14
|
+
*
|
|
15
|
+
* - An extension: its own `site` (`own-site`), or `unattributed:no-site` when blank.
|
|
16
|
+
* - A number: the site of its `dial-rule-translation-destination-user` when that names a user WITH a
|
|
17
|
+
* site (`via-user:<ext>`) — real or system, whatever the application (`to-user`, `to-single-device`);
|
|
18
|
+
* a queue at the North site is a North number. Only a site-less system user falls back to
|
|
19
|
+
* `routed-to:<that user's service-code>`; when the destination names nobody, `routed-to:<application>`;
|
|
20
|
+
* a site-less real user is `no-site`.
|
|
21
|
+
* - An address: the one site every REAL extension referencing it sits on (`via-users:<exts>`);
|
|
22
|
+
* `shared-across:<sites>` when they sit on more than one; `unreferenced` when none does;
|
|
23
|
+
* `no-site` when the referencing users have no site.
|
|
24
|
+
* - An SMS number: the site of the user whose per-user list carries it (`via-user:<ext>`), or
|
|
25
|
+
* `sms-user-unknown` when no per-user list does — including when the per-user read was never
|
|
26
|
+
* made. Never guessed from the domain-level list, which does not say.
|
|
27
|
+
*
|
|
28
|
+
* ## Keys are joined by index
|
|
29
|
+
*
|
|
30
|
+
* `listDomainInventory` maps each source array 1:1 and in order, and this module relies on that to
|
|
31
|
+
* put an item's KEY (which may be a derived `~hash`) beside its RECORD's routing fields. That
|
|
32
|
+
* invariant is this library's own, and this is the one place allowed to lean on it.
|
|
33
|
+
*/
|
|
34
|
+
import { isSystemUser, listDomainInventory, str, usersByExt } from './inventory.js';
|
|
35
|
+
import type { Rec, Snapshot } from './model.js';
|
|
36
|
+
|
|
37
|
+
export interface ItemAttribution {
|
|
38
|
+
/** The site this item belongs to; `null` when it cannot be placed. */
|
|
39
|
+
site: string | null;
|
|
40
|
+
/** `own-site` | `via-user:<ext>` | `via-users:<ext,ext>` | `unattributed:<reason>`. */
|
|
41
|
+
how: string;
|
|
42
|
+
}
|
|
43
|
+
export interface DomainAttribution { items: Record<string, ItemAttribution> }
|
|
44
|
+
|
|
45
|
+
const none = (reason: string): ItemAttribution => ({ site: null, how: `unattributed:${reason}` });
|
|
46
|
+
|
|
47
|
+
export function attributeDomainInventory(snapshot: Snapshot): DomainAttribution {
|
|
48
|
+
const users: Rec[] = Array.isArray(snapshot.users) ? snapshot.users : [];
|
|
49
|
+
const phonenumbers: Rec[] = Array.isArray(snapshot.phonenumbers) ? snapshot.phonenumbers : [];
|
|
50
|
+
const addresses: Rec[] = Array.isArray(snapshot.addresses) ? snapshot.addresses : [];
|
|
51
|
+
const smsnumbers: Rec[] = Array.isArray(snapshot.smsnumbers) ? snapshot.smsnumbers : [];
|
|
52
|
+
const byUser = snapshot.smsNumbersByUser;
|
|
53
|
+
const d = listDomainInventory(snapshot);
|
|
54
|
+
const items: Record<string, ItemAttribution> = {};
|
|
55
|
+
|
|
56
|
+
const userByExt = usersByExt(users);
|
|
57
|
+
|
|
58
|
+
// Extensions: the detail already carries `site`, so no record is needed here.
|
|
59
|
+
for (const x of d.extensions) items[x.key] = x.site ? { site: x.site, how: 'own-site' } : none('no-site');
|
|
60
|
+
|
|
61
|
+
// Numbers, by index against `phonenumbers`.
|
|
62
|
+
for (let i = 0; i < d.dids.length; i++) {
|
|
63
|
+
const key = d.dids[i]!.key, p = phonenumbers[i] ?? {};
|
|
64
|
+
const app = str(p['dial-rule-application']) || 'unknown';
|
|
65
|
+
const dest = str(p['dial-rule-translation-destination-user']);
|
|
66
|
+
const u = dest ? userByExt.get(dest) : undefined;
|
|
67
|
+
if (!u) { items[key] = none(`routed-to:${app}`); continue; }
|
|
68
|
+
const site = str(u.site);
|
|
69
|
+
if (!site) { items[key] = isSystemUser(u) ? none(`routed-to:${str(u['service-code'])}`) : none('no-site'); continue; }
|
|
70
|
+
items[key] = { site, how: `via-user:${dest}` };
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Addresses, by index against `addresses`; referenced by REAL extensions only.
|
|
74
|
+
const refs = new Map<string, Rec[]>();
|
|
75
|
+
for (const u of users) {
|
|
76
|
+
if (isSystemUser(u)) continue;
|
|
77
|
+
const id = str(u['emergency-address-id']);
|
|
78
|
+
if (!id) continue;
|
|
79
|
+
const list = refs.get(id) ?? []; list.push(u); refs.set(id, list);
|
|
80
|
+
}
|
|
81
|
+
for (let i = 0; i < d.e911Addresses.length; i++) {
|
|
82
|
+
const key = d.e911Addresses[i]!.key, id = str((addresses[i] ?? {})['emergency-address-id']);
|
|
83
|
+
const who = id ? refs.get(id) ?? [] : [];
|
|
84
|
+
if (!who.length) { items[key] = none('unreferenced'); continue; }
|
|
85
|
+
const sites = [...new Set(who.map((u) => str(u.site)).filter(Boolean))].sort();
|
|
86
|
+
if (sites.length === 0) items[key] = none('no-site');
|
|
87
|
+
else if (sites.length === 1) items[key] = { site: sites[0]!, how: `via-users:${who.map((u) => str(u.user)).filter(Boolean).sort().join(',')}` };
|
|
88
|
+
else items[key] = none(`shared-across:${sites.join(',')}`);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// SMS numbers, by index against `smsnumbers`, joined to a user through the per-user lists.
|
|
92
|
+
const extBySms = new Map<string, string>();
|
|
93
|
+
if (byUser) for (const [ext, list] of Object.entries(byUser)) for (const s of Array.isArray(list) ? list : []) { const n = str(s.number); if (n && !extBySms.has(n)) extBySms.set(n, ext); }
|
|
94
|
+
for (let i = 0; i < d.smsNumbers.length; i++) {
|
|
95
|
+
const key = d.smsNumbers[i]!.key, n = str((smsnumbers[i] ?? {}).number);
|
|
96
|
+
const ext = n ? extBySms.get(n) : undefined;
|
|
97
|
+
const u = ext ? userByExt.get(ext) : undefined;
|
|
98
|
+
if (!u) { items[key] = none('sms-user-unknown'); continue; }
|
|
99
|
+
const site = str(u.site);
|
|
100
|
+
items[key] = site ? { site, how: `via-user:${ext}` } : none('no-site');
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return { items };
|
|
104
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -37,7 +37,8 @@ export {
|
|
|
37
37
|
} from './html.js';
|
|
38
38
|
export { resolveSvgSize, rasterizerScript } from './raster.js';
|
|
39
39
|
export { NsClient, NsApiError, assertBareServer, fetchDomainSnapshot, listDomains, asArray, type NsClientConfig, type FetchSnapshotOptions } from './nsClient.js';
|
|
40
|
-
export { countDomainInventory, listDomainInventory, itemsFor, itemLabel, type DomainInventory, type DomainInventoryDetail, type ExtensionItem, type NumberItem, type AddressItem, type SmsItem, type InventoryItem } from './inventory.js';
|
|
40
|
+
export { countDomainInventory, countInventoryDetail, listDomainInventory, itemsFor, itemLabel, destinationOf, usersByExt, type DomainInventory, type DomainInventoryDetail, type ExtensionItem, type NumberItem, type AddressItem, type SmsItem, type InventoryItem } from './inventory.js';
|
|
41
|
+
export { attributeDomainInventory, type DomainAttribution, type ItemAttribution } from './attribution.js';
|
|
41
42
|
export { NsWriteClient, type NsWriteClientConfig } from './nsWriteClient.js';
|
|
42
43
|
export {
|
|
43
44
|
supportsSynchronous,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/** Offline test for the domain inventory counter. pnpm test:inventory */
|
|
2
|
-
import { countDomainInventory, listDomainInventory, itemsFor, itemLabel } from './inventory.js';
|
|
3
|
-
import type { Snapshot } from './model.js';
|
|
2
|
+
import { countDomainInventory, listDomainInventory, itemsFor, itemLabel, destinationOf, usersByExt } from './inventory.js';
|
|
3
|
+
import type { Rec, Snapshot } from './model.js';
|
|
4
4
|
|
|
5
5
|
let pass = 0, fail = 0;
|
|
6
6
|
const ok = (c: boolean, m: string) => { c ? pass++ : fail++; console.log(`${c ? 'PASS' : 'FAIL'} ${m}`); };
|
|
@@ -14,7 +14,7 @@ const snap: Snapshot = {
|
|
|
14
14
|
{ user: '103', 'user-scope': 'Basic User', 'service-code': '' },
|
|
15
15
|
{ user: '104', 'user-scope': 'Basic User', 'service-code': '' },
|
|
16
16
|
{ user: '700', 'user-scope': 'Basic User', 'service-code': 'system-aa' },
|
|
17
|
-
{ user: '701', 'user-scope': 'Basic User', 'service-code': 'system-queue' },
|
|
17
|
+
{ user: '701', 'user-scope': 'Basic User', 'service-code': 'system-queue', 'name-first-name': 'Sales' },
|
|
18
18
|
{ user: '702', 'user-scope': 'Basic User', 'service-code': 'system-tod' },
|
|
19
19
|
],
|
|
20
20
|
devicesByUser: {
|
|
@@ -28,8 +28,10 @@ const snap: Snapshot = {
|
|
|
28
28
|
'103': [{ aor: 'sip:103t@acme.example', 'device-models-model': 'Teams' }],
|
|
29
29
|
},
|
|
30
30
|
phonenumbers: [
|
|
31
|
-
{ phonenumber: '13175550100'
|
|
32
|
-
{ phonenumber: '
|
|
31
|
+
{ phonenumber: '13175550100', 'dial-rule-translation-destination-user': '100', 'dial-rule-description': ' Portal Created: User - 1001 ' },
|
|
32
|
+
{ phonenumber: '13175550101' },
|
|
33
|
+
{ phonenumber: '18005550102', 'dial-rule-translation-destination-user': '701' },
|
|
34
|
+
{ phonenumber: '18335550103' },
|
|
33
35
|
],
|
|
34
36
|
addresses: [
|
|
35
37
|
{ 'emergency-address-id': 'a-1', 'address-name': 'HQ', 'address-line-1': '1 Main St', 'address-city': 'Springfield' },
|
|
@@ -91,15 +93,33 @@ ok(sysDev.devices.total === 0, 'a system user device is not counted');
|
|
|
91
93
|
ok(e100.site === 'North', '[list] site is carried');
|
|
92
94
|
ok(e100.deviceCount === 1 && e100.deviceModels[0] === 'Yealink T54W', '[list] device count and models, never the MAC');
|
|
93
95
|
ok(e100.teams === false, '[list] a desk phone is not Teams');
|
|
96
|
+
const e101 = d.extensions.find((x) => x.ext === '101')!;
|
|
97
|
+
ok(
|
|
98
|
+
JSON.stringify(e101.devices) === JSON.stringify([
|
|
99
|
+
{ name: '101a', model: 'Yealink T54W', teams: false },
|
|
100
|
+
{ name: '101b', model: 'Yealink T31P', teams: false },
|
|
101
|
+
{ name: '101c', model: '(unknown)', teams: false },
|
|
102
|
+
]),
|
|
103
|
+
'[list] devices lists every device with its name, model and teams flag, in order',
|
|
104
|
+
);
|
|
94
105
|
const e103 = d.extensions.find((x) => x.ext === '103')!;
|
|
95
106
|
ok(e103.teams === true, '[list] a device whose aor local part is <ext>t marks the extension Teams-connected');
|
|
96
107
|
ok(e103.deviceCount === 0 && e103.deviceModels.length === 0, '[list] and that connector is not counted as a device');
|
|
108
|
+
ok(
|
|
109
|
+
JSON.stringify(e103.devices) === JSON.stringify([{ name: '103t', model: '', teams: true }]),
|
|
110
|
+
'[list] devices includes the Teams connector with an empty model, even though deviceCount excludes it',
|
|
111
|
+
);
|
|
112
|
+
ok(d.extensions.find((x) => x.ext === '104')!.devices.length === 0, '[list] no devices means an empty devices list, not a throw');
|
|
97
113
|
ok(d.extensions.find((x) => x.ext === '101')!.transcription === true, '[list] transcription flag');
|
|
98
114
|
ok(d.extensions.find((x) => x.ext === '103')!.name === '', '[list] a user with no name has an empty name, not "undefined undefined"');
|
|
99
115
|
ok(d.extensions.find((x) => x.ext === '103')!.anyDevice === true, '[list] an extension with only the Teams connector still has a device');
|
|
100
116
|
ok(d.extensions.find((x) => x.ext === '104')!.anyDevice === false, '[list] and one with nothing has none');
|
|
101
117
|
ok(d.dids.length === 4 && d.dids.filter((n) => n.kind === 'tollFree').length === 2, '[list] numbers with kind');
|
|
102
118
|
ok(d.dids[0]!.key === 'did:13175550100', '[list] a number key is did:<phonenumber>');
|
|
119
|
+
ok(d.dids[0]!.destination === 'to user 100 — Ann Lee', '[list] a number routed to a real user names them');
|
|
120
|
+
ok(d.dids[0]!.description === 'Portal Created: User - 1001', '[list] dial-rule-description is carried and trimmed');
|
|
121
|
+
ok(d.dids[1]!.destination === '' && d.dids[1]!.description === '', '[list] a number with no routing fields is blank, not "undefined"');
|
|
122
|
+
ok(d.dids[2]!.destination === 'to queue 701 — Sales', '[list] a number routed to a system queue names the queue');
|
|
103
123
|
ok(d.e911Addresses.length === 2, '[list] two address items');
|
|
104
124
|
ok(d.e911Addresses[0]!.key === 'addr:a-1', '[list] an address key is addr:<emergency-address-id>');
|
|
105
125
|
ok(d.e911Addresses[0]!.label === 'HQ — 1 Main St, Springfield', '[list] an address label is name — line 1, city');
|
|
@@ -209,5 +229,29 @@ ok(sysDev.devices.total === 0, 'a system user device is not counted');
|
|
|
209
229
|
ok(derived(forward) === derived(reversed), '[order] reversing the phonenumbers array leaves the did:~ keys unchanged');
|
|
210
230
|
}
|
|
211
231
|
|
|
232
|
+
// ── usersByExt / destinationOf ───────────────────────────────────────────────────────────────────────
|
|
233
|
+
{
|
|
234
|
+
const usersFx: Rec[] = [
|
|
235
|
+
{ user: '100', 'name-first-name': 'Ann', 'name-last-name': 'Lee' },
|
|
236
|
+
{ user: '701', 'service-code': 'system-queue', 'name-first-name': 'Sales' },
|
|
237
|
+
{ user: '702', 'service-code': 'system-' },
|
|
238
|
+
];
|
|
239
|
+
const byExt = usersByExt(usersFx);
|
|
240
|
+
ok(byExt.size === 3, '[usersByExt] one entry per non-blank user');
|
|
241
|
+
const deduped = usersByExt([...usersFx, { user: '100', 'name-first-name': 'Duplicate' }]);
|
|
242
|
+
ok(deduped.get('100')!['name-first-name'] === 'Ann', '[usersByExt] the FIRST record for a repeated extension wins');
|
|
243
|
+
|
|
244
|
+
ok(destinationOf({ 'dial-rule-translation-destination-user': '100' }, byExt) === 'to user 100 — Ann Lee', '[destinationOf] a real extension names the person');
|
|
245
|
+
ok(destinationOf({ 'dial-rule-translation-destination-user': '701' }, byExt) === 'to queue 701 — Sales', '[destinationOf] a system-queue destination strips the system- prefix and names the queue');
|
|
246
|
+
ok(destinationOf({ 'dial-rule-translation-destination-user': '702' }, byExt) === 'to system 702', '[destinationOf] a bare "system-" service code has nothing left to strip, so kind falls back to "system" rather than a double space');
|
|
247
|
+
ok(destinationOf({ 'dial-rule-translation-destination-user': '999', 'dial-rule-application': 'to-user' }, byExt) === 'to user 999', '[destinationOf] an unknown destination falls back to the application, to- stripped');
|
|
248
|
+
ok(
|
|
249
|
+
destinationOf({ 'dial-rule-translation-destination-user': '999', 'dial-rule-translation-destination-host': 'other.example' }, byExt) === 'to user 999@other.example',
|
|
250
|
+
'[destinationOf] an unknown destination with a host appends @host',
|
|
251
|
+
);
|
|
252
|
+
ok(destinationOf({ 'dial-rule-application': 'to-connection' }, byExt) === 'to connection', '[destinationOf] no destination, application only — to- stripped so it does not read "to to-connection"');
|
|
253
|
+
ok(destinationOf({}, byExt) === '', '[destinationOf] neither field set is empty, not "to undefined"');
|
|
254
|
+
}
|
|
255
|
+
|
|
212
256
|
console.log(`\n${pass} passed, ${fail} failed`);
|
|
213
257
|
if (fail) process.exit(1);
|
package/src/inventory.ts
CHANGED
|
@@ -7,10 +7,11 @@
|
|
|
7
7
|
* ## Counts, and the lists behind them
|
|
8
8
|
*
|
|
9
9
|
* A device record from NetSapiens carries the SIP registration password. `listDomainInventory` builds
|
|
10
|
-
* per-item lists — an extension's name and site, a number's kind, an address's
|
|
11
|
-
* allowlist of named fields, and `countDomainInventory` is a fold over those same
|
|
12
|
-
*
|
|
13
|
-
*
|
|
10
|
+
* per-item lists — an extension's name and site, a number's kind and routing destination, an address's
|
|
11
|
+
* label — from an allowlist of named fields, and `countDomainInventory` is a fold over those same
|
|
12
|
+
* lists. The allowlist now includes a device's NAME (its `aor` local part, e.g. `101b` — the same
|
|
13
|
+
* short id the portal shows) alongside its model; a device's MAC, SIP password and email never appear,
|
|
14
|
+
* and nothing here should be added that carries one.
|
|
14
15
|
*
|
|
15
16
|
* ## Every countable dimension is a numeric leaf
|
|
16
17
|
*
|
|
@@ -89,10 +90,27 @@ export interface ExtensionItem {
|
|
|
89
90
|
deviceCount: number;
|
|
90
91
|
/** `device-models-model` per handset, `(unknown)` when blank. Never the MAC. */
|
|
91
92
|
deviceModels: string[];
|
|
93
|
+
/**
|
|
94
|
+
* Every device on this extension, in record order, connector included: `name` is the `aor` local
|
|
95
|
+
* part (`sip:101b@acme.example` → `101b`) — the device NAME as the portal shows it — `model` is
|
|
96
|
+
* `device-models-model` (`(unknown)` when blank on a handset, `''` for the Teams connector, which
|
|
97
|
+
* has no model), and `teams` marks the connector entry itself. `deviceCount`/`deviceModels`/`teams`
|
|
98
|
+
* above stay handset-only; this list is the one place a connector's own row shows up. Never the MAC
|
|
99
|
+
* or the SIP password.
|
|
100
|
+
*/
|
|
101
|
+
devices: Array<{ name: string; model: string; teams: boolean }>;
|
|
92
102
|
/** `deviceCount > 0 || teams` — has a device of any kind, handset or connector. */
|
|
93
103
|
anyDevice: boolean;
|
|
94
104
|
}
|
|
95
|
-
export interface NumberItem {
|
|
105
|
+
export interface NumberItem {
|
|
106
|
+
key: string /* did:<phonenumber>, or did:~<hash> when the number is blank */;
|
|
107
|
+
number: string;
|
|
108
|
+
kind: 'local' | 'tollFree';
|
|
109
|
+
/** Where the number routes, for a person: see {@link destinationOf}. `''` when the record says nothing. */
|
|
110
|
+
destination: string;
|
|
111
|
+
/** `dial-rule-description` trimmed — the note the portal writes ("Portal Created: User - 1001"); `''` when blank. */
|
|
112
|
+
description: string;
|
|
113
|
+
}
|
|
96
114
|
export interface AddressItem { key: string /* addr:<emergency-address-id>, or addr:~<hash> when the id is blank */; label: string }
|
|
97
115
|
export interface SmsItem { key: string /* sms:<number>, or sms:~<hash> when the number is blank */; number: string }
|
|
98
116
|
export type InventoryItem = ExtensionItem | NumberItem | AddressItem | SmsItem;
|
|
@@ -110,7 +128,7 @@ export interface DomainInventoryDetail {
|
|
|
110
128
|
/** NANP toll-free area codes, 800 through 888. A number outside this set is counted local. */
|
|
111
129
|
const TOLL_FREE = new Set(['800', '833', '844', '855', '866', '877', '888']);
|
|
112
130
|
|
|
113
|
-
const str = (v: unknown): string => (typeof v === 'string' ? v.trim() : v == null ? '' : String(v).trim());
|
|
131
|
+
export const str = (v: unknown): string => (typeof v === 'string' ? v.trim() : v == null ? '' : String(v).trim());
|
|
114
132
|
const bump = (into: Record<string, number>, key: string): void => { into[key] = (into[key] ?? 0) + 1; };
|
|
115
133
|
|
|
116
134
|
/**
|
|
@@ -144,7 +162,7 @@ function identityKey(kind: string, id: string, seed: string): string {
|
|
|
144
162
|
}
|
|
145
163
|
|
|
146
164
|
/** Is this user one of NetSapiens' internal routing objects rather than a seat? */
|
|
147
|
-
function isSystemUser(user: Rec): boolean {
|
|
165
|
+
export function isSystemUser(user: Rec): boolean {
|
|
148
166
|
return str(user['service-code']).toLowerCase().startsWith('system-');
|
|
149
167
|
}
|
|
150
168
|
|
|
@@ -188,10 +206,71 @@ function extensionItem(u: Rec, devices: Rec[]): ExtensionItem {
|
|
|
188
206
|
// A device whose model is blank is listed under a named bucket rather than dropped: a missing
|
|
189
207
|
// model is a provisioning gap worth seeing, and a silently smaller total hides it.
|
|
190
208
|
deviceModels: handsets.map((d) => str(d['device-models-model']) || '(unknown)'),
|
|
209
|
+
// Every device, including the Teams connector — this is a display list, not a seat count.
|
|
210
|
+
devices: devices.map((d) => {
|
|
211
|
+
const isTeams = ext ? aorLocal(d) === `${ext}t` : false;
|
|
212
|
+
return { name: aorLocal(d), model: isTeams ? '' : str(d['device-models-model']) || '(unknown)', teams: isTeams };
|
|
213
|
+
}),
|
|
191
214
|
anyDevice: handsets.length > 0 || teams,
|
|
192
215
|
};
|
|
193
216
|
}
|
|
194
217
|
|
|
218
|
+
/**
|
|
219
|
+
* One record per non-blank `user`, first one wins. The same rule `attribution.ts` needs to join a
|
|
220
|
+
* number's `dial-rule-translation-destination-user` (or an SMS number, or an address) back to the
|
|
221
|
+
* user it belongs to — extracted here so there is exactly one copy of it in the library.
|
|
222
|
+
*/
|
|
223
|
+
export function usersByExt(users: Rec[]): Map<string, Rec> {
|
|
224
|
+
const map = new Map<string, Rec>();
|
|
225
|
+
for (const u of users) {
|
|
226
|
+
const ext = str(u.user);
|
|
227
|
+
if (ext && !map.has(ext)) map.set(ext, u);
|
|
228
|
+
}
|
|
229
|
+
return map;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Where a phone number routes, in words a person reads at a glance — not the raw NetSapiens dial
|
|
234
|
+
* rule fields. Pure; looks the destination user up in `userByExt` ({@link usersByExt}) so it can
|
|
235
|
+
* name a real extension or a system object (`system-queue` → `queue`, `system-aa` → `aa`, and so
|
|
236
|
+
* on) rather than just echoing back an extension number.
|
|
237
|
+
*
|
|
238
|
+
* - The destination names a REAL extension → `to user <ext> — <First Last>` (the name is omitted,
|
|
239
|
+
* dash and all, when both name fields are blank).
|
|
240
|
+
* - The destination names a SYSTEM user (a queue, an attendant, a time-of-day router) →
|
|
241
|
+
* `to <kind> <ext> — <name>`, `kind` being the `service-code` with its `system-` prefix stripped
|
|
242
|
+
* (`queue`, `aa`, `tod`, the raw code for anything else, or `system` when stripping leaves
|
|
243
|
+
* nothing — a bare `system-` service code); name omitted the same way.
|
|
244
|
+
* - The destination is set but names nobody NetSapiens knows about → `to <application> <dest>`
|
|
245
|
+
* (`dial-rule-application` with a leading `to-` stripped, so `to-user` reads as `user`; falls back
|
|
246
|
+
* to `user` itself when the application is blank), plus `@<host>` whenever
|
|
247
|
+
* `dial-rule-translation-destination-host` is non-empty — this module has no domain to compare it
|
|
248
|
+
* against, so any non-empty host is shown.
|
|
249
|
+
* - No destination but an application is set → `to <application>` (`to-connection` → `to connection`,
|
|
250
|
+
* `to-voicemail` → `to voicemail`).
|
|
251
|
+
* - Neither is set → `''`.
|
|
252
|
+
*/
|
|
253
|
+
export function destinationOf(p: Rec, userByExt: Map<string, Rec>): string {
|
|
254
|
+
const dest = str(p['dial-rule-translation-destination-user']);
|
|
255
|
+
const app = str(p['dial-rule-application']).replace(/^to-/i, '');
|
|
256
|
+
const host = str(p['dial-rule-translation-destination-host']);
|
|
257
|
+
|
|
258
|
+
if (dest) {
|
|
259
|
+
const u = userByExt.get(dest);
|
|
260
|
+
if (u) {
|
|
261
|
+
const name = `${str(u['name-first-name'])} ${str(u['name-last-name'])}`.trim();
|
|
262
|
+
if (isSystemUser(u)) {
|
|
263
|
+
const kind = str(u['service-code']).replace(/^system-/i, '') || 'system';
|
|
264
|
+
return name ? `to ${kind} ${dest} — ${name}` : `to ${kind} ${dest}`;
|
|
265
|
+
}
|
|
266
|
+
return name ? `to user ${dest} — ${name}` : `to user ${dest}`;
|
|
267
|
+
}
|
|
268
|
+
const hostPart = host ? `@${host}` : '';
|
|
269
|
+
return `to ${app || 'user'} ${dest}${hostPart}`;
|
|
270
|
+
}
|
|
271
|
+
return app ? `to ${app}` : '';
|
|
272
|
+
}
|
|
273
|
+
|
|
195
274
|
/**
|
|
196
275
|
* The items behind every count. Pure. Fields are copied by name from an allowlist; no record passes
|
|
197
276
|
* through, so a device's MAC or SIP password cannot reach a consumer by accident.
|
|
@@ -230,10 +309,13 @@ export function listDomainInventory(snapshot: Snapshot): DomainInventoryDetail {
|
|
|
230
309
|
const item = extensionItem(u, devicesByUser[ext] ?? []);
|
|
231
310
|
(isSystemUser(u) ? systemUsers : extensions).push(item);
|
|
232
311
|
}
|
|
312
|
+
const userByExt = usersByExt(users);
|
|
233
313
|
const dids: NumberItem[] = phonenumbers.map((p) => {
|
|
234
314
|
const number = str(p.phonenumber);
|
|
235
315
|
const kind: 'local' | 'tollFree' = isTollFree(number) ? 'tollFree' : 'local';
|
|
236
|
-
|
|
316
|
+
const destination = destinationOf(p, userByExt);
|
|
317
|
+
const description = str(p['dial-rule-description']);
|
|
318
|
+
return { key: identityKey('did', number, JSON.stringify({ number, kind })), number, kind, destination, description };
|
|
237
319
|
});
|
|
238
320
|
const e911Addresses: AddressItem[] = addresses.map((a, i) => {
|
|
239
321
|
const id = str(a['emergency-address-id']);
|
|
@@ -258,7 +340,14 @@ export function listDomainInventory(snapshot: Snapshot): DomainInventoryDetail {
|
|
|
258
340
|
|
|
259
341
|
/** The counts, as a fold over {@link listDomainInventory} so the two can never disagree. */
|
|
260
342
|
export function countDomainInventory(snapshot: Snapshot): DomainInventory {
|
|
261
|
-
|
|
343
|
+
return countInventoryDetail(listDomainInventory(snapshot));
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
/**
|
|
347
|
+
* Count an item list. Exposed separately so a consumer that has FILTERED the lists — to one site, to
|
|
348
|
+
* one billing account — gets counts that agree with what it kept, rather than re-counting the snapshot.
|
|
349
|
+
*/
|
|
350
|
+
export function countInventoryDetail(d: DomainInventoryDetail): DomainInventory {
|
|
262
351
|
const inv: DomainInventory = {
|
|
263
352
|
extensions: { total: 0, byScope: {}, byServiceCode: {}, byDeviceCount: { '0': 0, '1': 0, '2': 0, '3+': 0 }, withAnyDevice: 0, withNoDevice: 0 },
|
|
264
353
|
systemUsers: { total: d.systemUsers.length, byServiceCode: {} },
|
package/src/model.ts
CHANGED
|
@@ -102,6 +102,14 @@ export interface Snapshot {
|
|
|
102
102
|
* that returns the list. Present only when the fetch asked for them.
|
|
103
103
|
*/
|
|
104
104
|
smsnumbers?: Rec[];
|
|
105
|
+
/**
|
|
106
|
+
* SMS-enabled numbers PER USER — GET /domains/{d}/users/{ext}/smsnumbers, one call per real
|
|
107
|
+
* extension, present only when `includeUserSmsNumbers` was asked for. The domain-level list
|
|
108
|
+
* (`smsnumbers`) does not say which user a number is enabled on; this does.
|
|
109
|
+
*/
|
|
110
|
+
smsNumbersByUser?: Record<string, Rec[]>;
|
|
111
|
+
/** Extensions whose per-user SMS read failed with something other than 404 — same contract as `deviceReadFailures`. */
|
|
112
|
+
smsReadFailures?: string[];
|
|
105
113
|
autoattendants?: Rec[];
|
|
106
114
|
dialrulesByPlan?: Record<string, Rec[]>;
|
|
107
115
|
answerrulesByUser?: Record<string, Rec[]>;
|