@things-factory/help 10.1.247 → 10.1.254

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.
@@ -1 +1 @@
1
- {"version":3,"file":"help-index.js","sourceRoot":"","sources":["../server/help-index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;GAWG;;;AA8DH,gCAUC;AAWD,kCAcC;AAGD,0CAmBC;AAGD,kCAIC;AAGD,0CAcC;AAGD,wBASC;AA3GD,MAAM,MAAM,GAAG,qDAAqD,CAAA;AACpE,MAAM,QAAQ,GAA2B,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,CAAA;AAE1M,SAAS,MAAM,CAAC,IAAY;IAC1B,OAAO,IAAI,CAAC,OAAO,CAAC,2BAA2B,EAAE,CAAC,KAAK,EAAE,IAAY,EAAE,EAAE;QACvE,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC;YACpB,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,KAAK,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAA;YAC3G,OAAO,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAA;QACnE,CAAC;QACD,OAAO,QAAQ,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,IAAI,KAAK,CAAA;IAC9C,CAAC,CAAC,CAAA;AACJ,CAAC;AAED,0GAA0G;AAC1G,SAAgB,UAAU,CAAC,IAAY;IACrC,OAAO,MAAM,CACX,IAAI;SACD,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC;SACpB,OAAO,CAAC,kBAAkB,EAAE,GAAG,CAAC;SAChC,OAAO,CAAC,oCAAoC,EAAE,MAAM,CAAC;SACrD,OAAO,CAAC,UAAU,EAAE,GAAG,CAAC,CAC5B;SACE,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC;SACpB,IAAI,EAAE,CAAA;AACX,CAAC;AAED,SAAS,aAAa,CAAC,IAAY;IACjC,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,eAAe,CAAC,CAAA;IACxC,MAAM,GAAG,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;IAC/C,OAAO,GAAG,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,CAAA;AACzD,CAAC;AAID,oDAAoD;AACpD,SAAgB,WAAW,CAAC,IAAY;IACtC,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IACtC,MAAM,EAAE,GAAG,8BAA8B,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IACpD,MAAM,KAAK,GAAG,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAA;IACzC,MAAM,OAAO,GAAG,yDAAyD,CAAA;IACzE,MAAM,KAAK,GAAG,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,GAAG,CAAC,KAAM,EAAE,GAAG,EAAE,GAAG,CAAC,KAAM,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAA;IACzK,MAAM,KAAK,GAAU,EAAE,CAAA;IACvB,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,IAAI,IAAI,CAAC,MAAM,CAAC,CAAC,CAAA;IACnE,IAAI,IAAI;QAAE,KAAK,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAA;IACxD,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE;QACxB,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,CAAA;QACpE,KAAK,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,EAAE,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,IAAI,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAA;IACtH,CAAC,CAAC,CAAA;IACF,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,CAAA;AACzB,CAAC;AAED,uHAAuH;AACvH,SAAgB,eAAe,CAAC,QAAgB;IAC9C,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;IAClC,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,CAAA;IACtF,MAAM,KAAK,GAAU,EAAE,CAAA;IACvB,IAAI,OAAO,GAAQ,EAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,EAAE,CAAA;IACnD,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,OAAO,GAAG,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAC9C,IAAI,OAAO,EAAE,CAAC;YACZ,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;YACnB,OAAO,GAAG,EAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,CAAA;QAC/D,CAAC;aAAM,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,OAAO,CAAC,IAAI,IAAI,IAAI,GAAG,IAAI,CAAA;IAC5D,CAAC;IACD,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;IACnB,OAAO;QACL,KAAK;QACL,KAAK,EAAE,KAAK;aACT,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,yBAAyB,EAAE,IAAI,CAAC,CAAC,OAAO,CAAC,wBAAwB,EAAE,IAAI,CAAC,CAAC,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;aACpL,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC;KAC7B,CAAA;AACH,CAAC;AAED,gEAAgE;AAChE,SAAgB,WAAW,CAAC,IAAY;IACtC,MAAM,KAAK,GAAG,2DAA2D,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IACpF,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAA;IACvB,OAAO,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC,CAAkB,EAAE,CAAA;AACnF,CAAC;AAED,iDAAiD;AACjD,SAAgB,eAAe,CAAC,IAAY,EAAE,OAAe;IAC3D,MAAM,IAAI,GAAG,WAAW,CAAC,IAAI,CAAC,CAAA;IAC9B,IAAI,CAAC,IAAI;QAAE,OAAO,EAAE,CAAA;IACpB,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,IAAI,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,OAAO,CAAC,CAAA;IAC/F,MAAM,aAAa,GAAG,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAG,CAAA;IAC3D,OAAO,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACxB,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,OAAO,EAAE,IAAI,CAAC,OAAO;QACrB,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,KAAK,EAAE,IAAI,CAAC,KAAK,IAAI,aAAa;QAClC,aAAa;QACb,OAAO,EAAE,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC;QACjC,IAAI,EAAE,IAAI,CAAC,IAAI;KAChB,CAAC,CAAC,CAAA;AACL,CAAC;AAED,oHAAoH;AACpH,SAAgB,MAAM,CAAC,IAAY;IACjC,MAAM,GAAG,GAAa,EAAE,CAAA;IACxB,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,oDAAoD,CAAC,IAAI,EAAE,EAAE,CAAC;QACvG,IAAI,uCAAuC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;YACtD,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC;gBAAE,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;YACnC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,EAAE;gBAAE,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAA;QACxE,CAAC;aAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC;YAAE,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IAChE,CAAC;IACD,OAAO,GAAG,CAAA;AACZ,CAAC;AAED,MAAM,EAAE,GAAG,GAAG,CAAA;AACd,MAAM,CAAC,GAAG,IAAI,CAAA;AACd,2FAA2F;AAC3F,MAAM,YAAY,GAAG,CAAC,CAAA;AACtB,MAAM,eAAe,GAAG,CAAC,CAAA;AAIzB,MAAa,SAAS;IAKpB,YAAY,KAAiB;QAHrB,OAAE,GAAG,IAAI,GAAG,EAAkB,CAAA;QAIpC,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE;YAC9B,MAAM,MAAM,GAAG,IAAI,GAAG,EAAkB,CAAA;YACxC,MAAM,GAAG,GAAG,CAAC,KAAe,EAAE,MAAc,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAA;YAC1H,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,YAAY,CAAC,CAAA;YACrC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAA;YACzB,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,EAAE,CAAC,CAAC,EAAE,CAAA;QACtF,CAAC,CAAC,CAAA;QACF,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,OAAO;YAAE,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,MAAM,CAAC,IAAI,EAAE;gBAAE,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAA;QACzH,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,CAAC,GAAG,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,IAAI,CAAC,CAAC,CAAA;IAC1G,CAAC;IAED,IAAI,IAAI;QACN,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,CAAA;IAC5B,CAAC;IAED,0HAA0H;IAClH,UAAU,CAAC,KAAa,EAAE,IAAI,GAAG,EAAE;QACzC,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,KAAK,KAAK,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAA;QACvG,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,CAAA;IACxF,CAAC;IAEO,QAAQ,CAAC,IAAa;QAC5B,MAAM,MAAM,GAAG,IAAI,GAAG,EAA8B,CAAA;QACpD,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE;YACjC,MAAM,EAAE,KAAK,EAAE,GAAG,KAAK,CAAC,IAAI,CAAA;YAC5B,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC;gBAAE,MAAM,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,CAAA;YACvE,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,KAAK,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;QAC9C,CAAC,CAAC,CAAA;IACJ,CAAC;IAED,MAAM,CAAC,KAAa,EAAE,UAA6B,EAAE;QACnD,MAAM,KAAK,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;QACzC,IAAI,CAAC,KAAK,CAAC,MAAM;YAAE,OAAO,EAAE,CAAA;QAC5B,MAAM,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAA;QAC7B,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAA;QAChD,MAAM,IAAI,GAAc,EAAE,CAAA;QAC1B,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;YAChD,MAAM,EAAE,IAAI,EAAE,GAAG,KAAK,CAAA;YACtB,IAAI,KAAK,IAAI,IAAI,CAAC,KAAK,KAAK,KAAK,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,KAAK,GAAG,GAAG,CAAC;gBAAE,SAAQ;YAClF,IAAI,KAAK,GAAG,CAAC,CAAA;YACb,IAAI,IAAI,GAAG,CAAC,CAAA;YACZ,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;gBACzB,MAAM,EAAE,GAAG,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;gBACjC,IAAI,CAAC,EAAE;oBAAE,SAAQ;gBACjB,IAAI,EAAE,CAAA;gBACN,MAAM,EAAE,GAAG,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;gBACjC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,GAAG,GAAG,CAAC,GAAG,CAAC,EAAE,GAAG,GAAG,CAAC,CAAC,CAAA;gBACrD,KAAK,IAAI,CAAC,GAAG,GAAG,EAAE,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,aAAa,CAAC,CAAC,CAAA;YAChG,CAAC;YACD,MAAM,QAAQ,GAAG,IAAI,GAAG,KAAK,CAAC,MAAM,CAAA;YACpC,IAAI,CAAC,KAAK,IAAI,QAAQ,GAAG,CAAC,OAAO,CAAC,WAAW,IAAI,GAAG,CAAC;gBAAE,SAAQ;YAC/D,IAAI,OAAO,CAAC,QAAQ,IAAI,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAG,CAAC,QAAQ,CAAC,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;gBAAE,KAAK,IAAI,eAAe,CAAA;YAC/G,IAAI,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,aAAa,EAAE,IAAI,CAAC,aAAa,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,IAAI,CAAC,GAAG,IAAI,EAAE,QAAQ,EAAE,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG,GAAG,CAAC,GAAG,GAAG,EAAE,CAAC,CAAA;QAC1N,CAAC;QACD,OAAO,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC,CAAC,CAAA;IAC5E,CAAC;IAED,0FAA0F;IAC1F,IAAI,CAAC,KAAa,EAAE,OAAO,GAAG,EAAE,EAAE,IAAa;QAC7C,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,IAAI,CAAC,CAAA;QAC3C,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,KAAK,KAAK,IAAI,GAAG,CAAC,IAAI,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;QACnH,IAAI,CAAC,KAAK,CAAC,MAAM;YAAE,OAAO,IAAI,CAAA;QAC9B,IAAI,CAAC,OAAO;YAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,aAAa,EAAE,aAAa,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,aAAa,EAAE,IAAI,EAAE,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,KAAK,KAAK,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAA;QACjN,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,KAAK,OAAO,CAAC,CAAA;QACvD,OAAO,IAAI,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,aAAa,EAAE,IAAI,CAAC,aAAa,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAA;IAChH,CAAC;IAED,uFAAuF;IACvF,KAAK,CAAC,KAAa,EAAE,OAAO,GAAG,EAAE;QAC/B,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,KAAK,KAAK,IAAI,CAAC,CAAC,OAAO,IAAI,GAAG,CAAC,IAAI,CAAC,OAAO,KAAK,OAAO,CAAC,CAAC,CAAA;IACzG,CAAC;CACF;AA7ED,8BA6EC","sourcesContent":["/*\n * The help documents, cut into the parts a reader is sent to — the one index the screen's `?` and the AI assistant both\n * ask (ADR-0181). Nothing links a screen to a part by hand: the part is found. Every document under /helps counts, html\n * and markdown, in every language it is written in.\n *\n * A part is a heading with an id (`<h2 id=\"leave\">`) and what follows it up to the next heading of the same depth or\n * higher — the same cut `ox-doc section=` shows. The text before the first such heading is the document's own part\n * (section ''). Pure: the store reads the files, this reads text.\n *\n * Korean is not cut at spaces — 「지출결의를」 and 「지출결의」 must meet — so words are cut into pairs of letters (bigrams)\n * and ranked with BM25. A Latin word stays whole.\n */\n\nexport interface HelpPart {\n /** `office/guide-employee` — the path under /helps without the language and the extension. */\n topic: string\n /** The heading's id; '' for the part before the first heading. */\n section: string\n /** The language of the file (`ko`), or '' for the file with no language in its name (the fallback). */\n lang: string\n /** The heading's words; for section '' the document's title. */\n title: string\n /** The document's title, so a part reads as 「사용 안내 › 휴가 내기」. */\n documentTitle: string\n /** The first sentence of the part — what a list shows before the whole is read. */\n summary: string\n /** The words of the part, tags taken out. */\n text: string\n}\n\nexport interface HelpHit {\n topic: string\n section: string\n title: string\n documentTitle: string\n summary: string\n score: number\n /** The share of the question's words the part holds (0-1). */\n coverage: number\n}\n\nexport interface HelpSearchOptions {\n /** The reader's language — a topic is read in it, else in its base (`ko` of `ko-KR`), else the fallback file. */\n lang?: string\n /** Only topics under this path (`office`). */\n scope?: string\n /**\n * Who reads (`finance`). A document written for them — its last name ends `-finance` (`office/guide-finance`) — weighs\n * more, so the same screen opens the part of that reader's work.\n */\n audience?: string\n limit?: number\n /**\n * The share of the question's words a part must hold — 0.5 unless named. Pairs of letters are many, so a question of\n * words no document has (「zzzz 없는말」) still meets some of them (「없는」); a part holding half the words is about it.\n */\n minCoverage?: number\n}\n\nconst BLOCKS = /<(script|style|svg|template|math)\\b[\\s\\S]*?<\\/\\1>/gi\nconst ENTITIES: Record<string, string> = { amp: '&', lt: '<', gt: '>', quot: '\"', apos: \"'\", nbsp: ' ', middot: '·', rsaquo: '›', lsaquo: '‹', rarr: '→', larr: '←', hellip: '…', ndash: '–', mdash: '—' }\n\nfunction decode(text: string): string {\n return text.replace(/&(#x?[0-9a-f]+|[a-z]+);/gi, (whole, name: string) => {\n if (name[0] === '#') {\n const code = name[1] === 'x' || name[1] === 'X' ? parseInt(name.slice(2), 16) : parseInt(name.slice(1), 10)\n return Number.isFinite(code) ? String.fromCodePoint(code) : whole\n }\n return ENTITIES[name.toLowerCase()] ?? whole\n })\n}\n\n/** The words of a piece of html: blocks that draw rather than say are dropped, an image keeps its alt. */\nexport function textOfHtml(html: string): string {\n return decode(\n html\n .replace(BLOCKS, ' ')\n .replace(/<!--[\\s\\S]*?-->/g, ' ')\n .replace(/<img\\b[^>]*\\balt=\"([^\"]*)\"[^>]*>/gi, ' $1 ')\n .replace(/<[^>]+>/g, ' ')\n )\n .replace(/\\s+/g, ' ')\n .trim()\n}\n\nfunction firstSentence(text: string): string {\n const cut = text.search(/(?<=[.!?。])\\s/)\n const one = cut > 0 ? text.slice(0, cut) : text\n return one.length > 160 ? one.slice(0, 157) + '…' : one\n}\n\ntype Cut = { section: string; title: string; text: string }\n\n/** The parts of an html document, and its title. */\nexport function partsOfHtml(html: string): { title: string; parts: Cut[] } {\n const body = html.replace(BLOCKS, ' ')\n const h1 = /<h1\\b[^>]*>([\\s\\S]*?)<\\/h1>/i.exec(body)\n const title = h1 ? textOfHtml(h1[1]) : ''\n const heading = /<h([2-4])\\b[^>]*\\bid=\"([^\"]+)\"[^>]*>([\\s\\S]*?)<\\/h\\1>/gi\n const marks = [...body.matchAll(heading)].map(one => ({ depth: Number(one[1]), id: one[2], title: textOfHtml(one[3]), at: one.index!, end: one.index! + one[0].length }))\n const parts: Cut[] = []\n const head = textOfHtml(body.slice(0, marks[0]?.at ?? body.length))\n if (head) parts.push({ section: '', title, text: head })\n marks.forEach((mark, i) => {\n const next = marks.slice(i + 1).find(one => one.depth <= mark.depth)\n parts.push({ section: mark.id, title: mark.title, text: textOfHtml(body.slice(mark.end, next?.at ?? body.length)) })\n })\n return { title, parts }\n}\n\n/** The parts of a markdown document. Markdown headings carry no id, so its parts are found but opened as the whole. */\nexport function partsOfMarkdown(markdown: string): { title: string; parts: Cut[] } {\n const lines = markdown.split('\\n')\n const title = lines.find(line => /^#\\s/.test(line))?.replace(/^#\\s+/, '').trim() ?? ''\n const parts: Cut[] = []\n let current: Cut = { section: '', title, text: '' }\n for (const line of lines) {\n const heading = /^(#{2,4})\\s+(.*)$/.exec(line)\n if (heading) {\n parts.push(current)\n current = { section: '', title: heading[2].trim(), text: '' }\n } else if (!/^#\\s/.test(line)) current.text += line + '\\n'\n }\n parts.push(current)\n return {\n title,\n parts: parts\n .map(part => ({ ...part, text: part.text.replace(/!\\[([^\\]]*)\\]\\([^)]*\\)/g, '$1').replace(/\\[([^\\]]*)\\]\\([^)]*\\)/g, '$1').replace(/[*_`>|#-]+/g, ' ').replace(/\\s+/g, ' ').trim() }))\n .filter(part => part.text)\n }\n}\n\n/** `office/guide.ko.html` → topic `office/guide`, lang `ko`. */\nexport function topicOfFile(path: string): { topic: string; lang: string; kind: 'html' | 'md' } | null {\n const match = /^\\/?(.+?)(?:\\.([a-z]{2}(?:-[A-Za-z]{2,4})?))?\\.(html|md)$/.exec(path)\n if (!match) return null\n return { topic: match[1], lang: match[2] ?? '', kind: match[3] as 'html' | 'md' }\n}\n\n/** One document's parts, ready for the index. */\nexport function partsOfDocument(path: string, content: string): HelpPart[] {\n const file = topicOfFile(path)\n if (!file) return []\n const { title, parts } = file.kind === 'html' ? partsOfHtml(content) : partsOfMarkdown(content)\n const documentTitle = title || file.topic.split('/').pop()!\n return parts.map(part => ({\n topic: file.topic,\n section: part.section,\n lang: file.lang,\n title: part.title || documentTitle,\n documentTitle,\n summary: firstSentence(part.text),\n text: part.text\n }))\n}\n\n/** The words of a text as the index counts them: a Latin word whole, a run of Hangul or Han as its letter pairs. */\nexport function tokens(text: string): string[] {\n const out: string[] = []\n for (const run of text.toLowerCase().match(/[\\p{Script=Hangul}\\p{Script=Han}]+|[\\p{L}\\p{N}]+/gu) ?? []) {\n if (/^[\\p{Script=Hangul}\\p{Script=Han}]+$/u.test(run)) {\n if (run.length === 1) out.push(run)\n for (let i = 0; i < run.length - 1; i++) out.push(run.slice(i, i + 2))\n } else if (run.length > 1 || /\\p{N}/u.test(run)) out.push(run)\n }\n return out\n}\n\nconst K1 = 1.2\nconst B = 0.75\n/* A title is what the part is about; its words count as much as three times the body's. */\nconst TITLE_WEIGHT = 3\nconst AUDIENCE_WEIGHT = 2\n\ntype Entry = { part: HelpPart; counts: Map<string, number>; length: number }\n\nexport class HelpIndex {\n private entries: Entry[]\n private df = new Map<string, number>()\n private averageLength: number\n\n constructor(parts: HelpPart[]) {\n this.entries = parts.map(part => {\n const counts = new Map<string, number>()\n const add = (words: string[], weight: number) => words.forEach(word => counts.set(word, (counts.get(word) ?? 0) + weight))\n add(tokens(part.title), TITLE_WEIGHT)\n add(tokens(part.text), 1)\n return { part, counts, length: [...counts.values()].reduce((sum, n) => sum + n, 0) }\n })\n for (const entry of this.entries) for (const word of entry.counts.keys()) this.df.set(word, (this.df.get(word) ?? 0) + 1)\n this.averageLength = this.entries.reduce((sum, one) => sum + one.length, 0) / (this.entries.length || 1)\n }\n\n get size(): number {\n return this.entries.length\n }\n\n /** The language a topic is read in: the reader's, its base, else the file with none in its name — as /helps serves it. */\n private languageOf(topic: string, lang = ''): string | undefined {\n const written = new Set(this.entries.filter(one => one.part.topic === topic).map(one => one.part.lang))\n return [lang, lang.split('-')[0], ''].find(one => written.has(one)) ?? [...written][0]\n }\n\n private readable(lang?: string): Entry[] {\n const chosen = new Map<string, string | undefined>()\n return this.entries.filter(entry => {\n const { topic } = entry.part\n if (!chosen.has(topic)) chosen.set(topic, this.languageOf(topic, lang))\n return entry.part.lang === chosen.get(topic)\n })\n }\n\n search(query: string, options: HelpSearchOptions = {}): HelpHit[] {\n const words = [...new Set(tokens(query))]\n if (!words.length) return []\n const n = this.entries.length\n const scope = options.scope?.replace(/\\/+$/, '')\n const hits: HelpHit[] = []\n for (const entry of this.readable(options.lang)) {\n const { part } = entry\n if (scope && part.topic !== scope && !part.topic.startsWith(scope + '/')) continue\n let score = 0\n let held = 0\n for (const word of words) {\n const tf = entry.counts.get(word)\n if (!tf) continue\n held++\n const df = this.df.get(word) ?? 0\n const idf = Math.log(1 + (n - df + 0.5) / (df + 0.5))\n score += (idf * tf * (K1 + 1)) / (tf + K1 * (1 - B + (B * entry.length) / this.averageLength))\n }\n const coverage = held / words.length\n if (!score || coverage < (options.minCoverage ?? 0.5)) continue\n if (options.audience && part.topic.split('/').pop()!.endsWith(`-${options.audience}`)) score *= AUDIENCE_WEIGHT\n hits.push({ topic: part.topic, section: part.section, title: part.title, documentTitle: part.documentTitle, summary: part.summary, score: Math.round(score * 1000) / 1000, coverage: Math.round(coverage * 100) / 100 })\n }\n return hits.sort((a, b) => b.score - a.score).slice(0, options.limit ?? 5)\n }\n\n /** One part in the reader's language — or the whole document when no section is named. */\n read(topic: string, section = '', lang?: string): { topic: string; section: string; title: string; documentTitle: string; text: string } | null {\n const chosen = this.languageOf(topic, lang)\n const parts = this.entries.filter(one => one.part.topic === topic && one.part.lang === chosen).map(one => one.part)\n if (!parts.length) return null\n if (!section) return { topic, section: '', title: parts[0].documentTitle, documentTitle: parts[0].documentTitle, text: parts.map(one => (one.section ? `## ${one.title}\\n${one.text}` : one.text)).join('\\n\\n') }\n const part = parts.find(one => one.section === section)\n return part ? { topic, section, title: part.title, documentTitle: part.documentTitle, text: part.text } : null\n }\n\n /** Whether a topic is written, and its section when one is named — in any language. */\n holds(topic: string, section = ''): boolean {\n return this.entries.some(one => one.part.topic === topic && (!section || one.part.section === section))\n }\n}\n"]}
1
+ {"version":3,"file":"help-index.js","sourceRoot":"","sources":["../server/help-index.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * The help documents, cut into the parts a reader is sent to — the one index the screen's `?` and the AI assistant both\n * ask (ADR-0181). Nothing links a screen to a part by hand: the part is found. Every document under /helps counts, html\n * and markdown, in every language it is written in.\n *\n * A part is a heading with an id (`<h2 id=\"leave\">`) and what follows it up to the next heading of the same depth or\n * higher — the same cut `ox-doc section=` shows. The text before the first such heading is the document's own part\n * (section ''). Pure: the store reads the files, this reads text.\n *\n * Korean is not cut at spaces — 「지출결의를」 and 「지출결의」 must meet — so words are cut into pairs of letters (bigrams)\n * and ranked with BM25. A Latin word stays whole.\n */\n\nexport interface HelpPart {\n /** `office/guide-employee` — the path under /helps without the language and the extension. */\n topic: string\n /** The heading's id; '' for the part before the first heading. */\n section: string\n /** The language of the file (`ko`), or '' for the file with no language in its name (the fallback). */\n lang: string\n /** The heading's words; for section '' the document's title. */\n title: string\n /** The document's title, so a part reads as 「사용 안내 › 휴가 내기」. */\n documentTitle: string\n /** The first sentence of the part — what a list shows before the whole is read. */\n summary: string\n /** The words of the part, tags taken out. */\n text: string\n /** Where the part opens when it is not a help page - a part of a source (`regulations?regulation=WORK&clause=3`). */\n link?: string\n}\n\nexport interface HelpHit {\n topic: string\n section: string\n title: string\n documentTitle: string\n summary: string\n score: number\n /** The share of the question's words the part holds (0-1). */\n coverage: number\n /** Where it opens, for a part of a source; a help part opens on the help page. */\n link?: string\n}\n\n/** One part read, or the whole document. */\nexport interface HelpReading {\n topic: string\n section: string\n title: string\n documentTitle: string\n text: string\n link?: string\n}\n\nexport interface HelpSearchOptions {\n /** The reader's language — a topic is read in it, else in its base (`ko` of `ko-KR`), else the fallback file. */\n lang?: string\n /** Only topics under this path (`office`). */\n scope?: string\n /**\n * Who reads (`finance`). A document written for them — its last name ends `-finance` (`office/guide-finance`) — weighs\n * more, so the same screen opens the part of that reader's work.\n */\n audience?: string\n limit?: number\n /**\n * The request - a source's parts (ADR-0187 decision 12) are found only for the request's domain, and only when the\n * source lets the request's person read them. Without it only the documents are searched.\n */\n context?: any\n /**\n * The share of the question's words a part must hold — 0.5 unless named. Pairs of letters are many, so a question of\n * words no document has (「zzzz 없는말」) still meets some of them (「없는」); a part holding half the words is about it.\n */\n minCoverage?: number\n}\n\nconst BLOCKS = /<(script|style|svg|template|math)\\b[\\s\\S]*?<\\/\\1>/gi\nconst ENTITIES: Record<string, string> = { amp: '&', lt: '<', gt: '>', quot: '\"', apos: \"'\", nbsp: ' ', middot: '·', rsaquo: '›', lsaquo: '‹', rarr: '→', larr: '←', hellip: '…', ndash: '–', mdash: '—' }\n\nfunction decode(text: string): string {\n return text.replace(/&(#x?[0-9a-f]+|[a-z]+);/gi, (whole, name: string) => {\n if (name[0] === '#') {\n const code = name[1] === 'x' || name[1] === 'X' ? parseInt(name.slice(2), 16) : parseInt(name.slice(1), 10)\n return Number.isFinite(code) ? String.fromCodePoint(code) : whole\n }\n return ENTITIES[name.toLowerCase()] ?? whole\n })\n}\n\n/** The words of a piece of html: blocks that draw rather than say are dropped, an image keeps its alt. */\nexport function textOfHtml(html: string): string {\n return decode(\n html\n .replace(BLOCKS, ' ')\n .replace(/<!--[\\s\\S]*?-->/g, ' ')\n .replace(/<img\\b[^>]*\\balt=\"([^\"]*)\"[^>]*>/gi, ' $1 ')\n .replace(/<[^>]+>/g, ' ')\n )\n .replace(/\\s+/g, ' ')\n .trim()\n}\n\nfunction firstSentence(text: string): string {\n const cut = text.search(/(?<=[.!?。])\\s/)\n const one = cut > 0 ? text.slice(0, cut) : text\n return one.length > 160 ? one.slice(0, 157) + '…' : one\n}\n\ntype Cut = { section: string; title: string; text: string }\n\n/** The parts of an html document, and its title. */\nexport function partsOfHtml(html: string): { title: string; parts: Cut[] } {\n const body = html.replace(BLOCKS, ' ')\n const h1 = /<h1\\b[^>]*>([\\s\\S]*?)<\\/h1>/i.exec(body)\n const title = h1 ? textOfHtml(h1[1]) : ''\n const heading = /<h([2-4])\\b[^>]*\\bid=\"([^\"]+)\"[^>]*>([\\s\\S]*?)<\\/h\\1>/gi\n const marks = [...body.matchAll(heading)].map(one => ({ depth: Number(one[1]), id: one[2], title: textOfHtml(one[3]), at: one.index!, end: one.index! + one[0].length }))\n const parts: Cut[] = []\n const head = textOfHtml(body.slice(0, marks[0]?.at ?? body.length))\n if (head) parts.push({ section: '', title, text: head })\n marks.forEach((mark, i) => {\n const next = marks.slice(i + 1).find(one => one.depth <= mark.depth)\n parts.push({ section: mark.id, title: mark.title, text: textOfHtml(body.slice(mark.end, next?.at ?? body.length)) })\n })\n return { title, parts }\n}\n\n/** The parts of a markdown document. Markdown headings carry no id, so its parts are found but opened as the whole. */\nexport function partsOfMarkdown(markdown: string): { title: string; parts: Cut[] } {\n const lines = markdown.split('\\n')\n const title = lines.find(line => /^#\\s/.test(line))?.replace(/^#\\s+/, '').trim() ?? ''\n const parts: Cut[] = []\n let current: Cut = { section: '', title, text: '' }\n for (const line of lines) {\n const heading = /^(#{2,4})\\s+(.*)$/.exec(line)\n if (heading) {\n parts.push(current)\n current = { section: '', title: heading[2].trim(), text: '' }\n } else if (!/^#\\s/.test(line)) current.text += line + '\\n'\n }\n parts.push(current)\n return {\n title,\n parts: parts\n .map(part => ({ ...part, text: part.text.replace(/!\\[([^\\]]*)\\]\\([^)]*\\)/g, '$1').replace(/\\[([^\\]]*)\\]\\([^)]*\\)/g, '$1').replace(/[*_`>|#-]+/g, ' ').replace(/\\s+/g, ' ').trim() }))\n .filter(part => part.text)\n }\n}\n\n/** `office/guide.ko.html` → topic `office/guide`, lang `ko`. */\nexport function topicOfFile(path: string): { topic: string; lang: string; kind: 'html' | 'md' } | null {\n const match = /^\\/?(.+?)(?:\\.([a-z]{2}(?:-[A-Za-z]{2,4})?))?\\.(html|md)$/.exec(path)\n if (!match) return null\n return { topic: match[1], lang: match[2] ?? '', kind: match[3] as 'html' | 'md' }\n}\n\n/** One document's parts, ready for the index. */\nexport function partsOfDocument(path: string, content: string): HelpPart[] {\n const file = topicOfFile(path)\n if (!file) return []\n const { title, parts } = file.kind === 'html' ? partsOfHtml(content) : partsOfMarkdown(content)\n const documentTitle = title || file.topic.split('/').pop()!\n return parts.map(part => ({\n topic: file.topic,\n section: part.section,\n lang: file.lang,\n title: part.title || documentTitle,\n documentTitle,\n summary: firstSentence(part.text),\n text: part.text\n }))\n}\n\n/** The words of a text as the index counts them: a Latin word whole, a run of Hangul or Han as its letter pairs. */\nexport function tokens(text: string): string[] {\n const out: string[] = []\n for (const run of text.toLowerCase().match(/[\\p{Script=Hangul}\\p{Script=Han}]+|[\\p{L}\\p{N}]+/gu) ?? []) {\n if (/^[\\p{Script=Hangul}\\p{Script=Han}]+$/u.test(run)) {\n if (run.length === 1) out.push(run)\n for (let i = 0; i < run.length - 1; i++) out.push(run.slice(i, i + 2))\n } else if (run.length > 1 || /\\p{N}/u.test(run)) out.push(run)\n }\n return out\n}\n\nconst K1 = 1.2\nconst B = 0.75\n/* A title is what the part is about; its words count as much as three times the body's. */\nconst TITLE_WEIGHT = 3\nconst AUDIENCE_WEIGHT = 2\n\ntype Entry = { part: HelpPart; counts: Map<string, number>; length: number }\n\nexport class HelpIndex {\n private entries: Entry[]\n private df = new Map<string, number>()\n private averageLength: number\n\n constructor(parts: HelpPart[]) {\n this.entries = parts.map(part => {\n const counts = new Map<string, number>()\n const add = (words: string[], weight: number) => words.forEach(word => counts.set(word, (counts.get(word) ?? 0) + weight))\n add(tokens(part.title), TITLE_WEIGHT)\n add(tokens(part.text), 1)\n return { part, counts, length: [...counts.values()].reduce((sum, n) => sum + n, 0) }\n })\n for (const entry of this.entries) for (const word of entry.counts.keys()) this.df.set(word, (this.df.get(word) ?? 0) + 1)\n this.averageLength = this.entries.reduce((sum, one) => sum + one.length, 0) / (this.entries.length || 1)\n }\n\n get size(): number {\n return this.entries.length\n }\n\n /** The language a topic is read in: the reader's, its base, else the file with none in its name — as /helps serves it. */\n private languageOf(topic: string, lang = ''): string | undefined {\n const written = new Set(this.entries.filter(one => one.part.topic === topic).map(one => one.part.lang))\n return [lang, lang.split('-')[0], ''].find(one => written.has(one)) ?? [...written][0]\n }\n\n private readable(lang?: string): Entry[] {\n const chosen = new Map<string, string | undefined>()\n return this.entries.filter(entry => {\n const { topic } = entry.part\n if (!chosen.has(topic)) chosen.set(topic, this.languageOf(topic, lang))\n return entry.part.lang === chosen.get(topic)\n })\n }\n\n search(query: string, options: HelpSearchOptions = {}): HelpHit[] {\n const words = [...new Set(tokens(query))]\n if (!words.length) return []\n const n = this.entries.length\n const scope = options.scope?.replace(/\\/+$/, '')\n const hits: HelpHit[] = []\n for (const entry of this.readable(options.lang)) {\n const { part } = entry\n if (scope && part.topic !== scope && !part.topic.startsWith(scope + '/')) continue\n let score = 0\n let held = 0\n for (const word of words) {\n const tf = entry.counts.get(word)\n if (!tf) continue\n held++\n const df = this.df.get(word) ?? 0\n const idf = Math.log(1 + (n - df + 0.5) / (df + 0.5))\n score += (idf * tf * (K1 + 1)) / (tf + K1 * (1 - B + (B * entry.length) / this.averageLength))\n }\n const coverage = held / words.length\n if (!score || coverage < (options.minCoverage ?? 0.5)) continue\n if (options.audience && part.topic.split('/').pop()!.endsWith(`-${options.audience}`)) score *= AUDIENCE_WEIGHT\n hits.push({ topic: part.topic, section: part.section, title: part.title, documentTitle: part.documentTitle, summary: part.summary, score: Math.round(score * 1000) / 1000, coverage: Math.round(coverage * 100) / 100, ...(part.link ? { link: part.link } : {}) })\n }\n return hits.sort((a, b) => b.score - a.score).slice(0, options.limit ?? 5)\n }\n\n /** One part in the reader's language — or the whole document when no section is named. */\n read(topic: string, section = '', lang?: string): HelpReading | null {\n const chosen = this.languageOf(topic, lang)\n const parts = this.entries.filter(one => one.part.topic === topic && one.part.lang === chosen).map(one => one.part)\n if (!parts.length) return null\n if (!section) return { topic, section: '', title: parts[0].documentTitle, documentTitle: parts[0].documentTitle, text: parts.map(one => (one.section ? `## ${one.title}\\n${one.text}` : one.text)).join('\\n\\n') }\n const part = parts.find(one => one.section === section)\n return part ? { topic, section, title: part.title, documentTitle: part.documentTitle, text: part.text, ...(part.link ? { link: part.link } : {}) } : null\n }\n\n /** Whether a topic is written, and its section when one is named — in any language. */\n holds(topic: string, section = ''): boolean {\n return this.entries.some(one => one.part.topic === topic && (!section || one.part.section === section))\n }\n}\n"]}
@@ -0,0 +1,20 @@
1
+ import { HelpIndex, type HelpPart } from './help-index.js';
2
+ export interface HelpSource {
3
+ /** `regulation` - the module's own name for it. */
4
+ name: string;
5
+ /** Every part of the domain the source holds now. A part's topic starts with the source's name (`regulation/WORK`). */
6
+ partsOf(domain: {
7
+ id: string;
8
+ }): Promise<HelpPart[]>;
9
+ /** Whether the request's person may read the source's parts of the request's domain. */
10
+ mayRead(context: any): Promise<boolean>;
11
+ }
12
+ /** What a module calls at load to add its text to the help's search. */
13
+ export declare function registerHelpSource(source: HelpSource): void;
14
+ /** What a source calls when its text of a domain changed - the next search indexes it again. */
15
+ export declare function invalidateHelpSource(name: string, domainId: string): void;
16
+ /** The indexes of the sources the request may read, of its domain. */
17
+ export declare function readableSourceIndexes(context: any): Promise<{
18
+ name: string;
19
+ index: HelpIndex;
20
+ }[]>;
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.registerHelpSource = registerHelpSource;
4
+ exports.invalidateHelpSource = invalidateHelpSource;
5
+ exports.readableSourceIndexes = readableSourceIndexes;
6
+ /*
7
+ * 도움말의 출처 (ADR-0187 decision 12, the place ADR-0181 decision 2 left) - text a company keeps while it runs, found by
8
+ * the same search as the help the application ships: a module registers a source, the parts of each domain are indexed
9
+ * apart and kept in memory, and the source says who of the domain may read them. A source that changes asks to be indexed
10
+ * again. The documents stay one index for everyone; a source's index is a domain's.
11
+ */
12
+ const help_index_js_1 = require("./help-index.js");
13
+ const SOURCES = new Map();
14
+ /* source name → domain id → its parts, indexed - or the indexing under way. */
15
+ const INDEXES = new Map();
16
+ /** What a module calls at load to add its text to the help's search. */
17
+ function registerHelpSource(source) {
18
+ SOURCES.set(source.name, source);
19
+ INDEXES.delete(source.name);
20
+ }
21
+ /** What a source calls when its text of a domain changed - the next search indexes it again. */
22
+ function invalidateHelpSource(name, domainId) {
23
+ INDEXES.get(name)?.delete(domainId);
24
+ }
25
+ function indexOf(source, domain) {
26
+ let byDomain = INDEXES.get(source.name);
27
+ if (!byDomain)
28
+ INDEXES.set(source.name, (byDomain = new Map()));
29
+ let index = byDomain.get(domain.id);
30
+ if (!index) {
31
+ index = source.partsOf(domain).then(parts => new help_index_js_1.HelpIndex(parts));
32
+ /* A failed indexing is not kept - the next search tries again. */
33
+ index.catch(() => byDomain.get(domain.id) === index && byDomain.delete(domain.id));
34
+ byDomain.set(domain.id, index);
35
+ }
36
+ return index;
37
+ }
38
+ /** The indexes of the sources the request may read, of its domain. */
39
+ async function readableSourceIndexes(context) {
40
+ const domain = context?.state?.domain;
41
+ if (!domain?.id || !context?.state?.user)
42
+ return [];
43
+ const out = [];
44
+ for (const source of SOURCES.values()) {
45
+ if (!(await source.mayRead(context).catch(() => false)))
46
+ continue;
47
+ out.push({ name: source.name, index: await indexOf(source, domain) });
48
+ }
49
+ return out;
50
+ }
51
+ //# sourceMappingURL=help-sources.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"help-sources.js","sourceRoot":"","sources":["../server/help-sources.ts"],"names":[],"mappings":";;AAsBA,gDAGC;AAGD,oDAEC;AAgBD,sDASC;AAvDD;;;;;GAKG;AACH,mDAA0D;AAW1D,MAAM,OAAO,GAAG,IAAI,GAAG,EAAsB,CAAA;AAC7C,+EAA+E;AAC/E,MAAM,OAAO,GAAG,IAAI,GAAG,EAA2C,CAAA;AAElE,wEAAwE;AACxE,SAAgB,kBAAkB,CAAC,MAAkB;IACnD,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,CAAA;IAChC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;AAC7B,CAAC;AAED,gGAAgG;AAChG,SAAgB,oBAAoB,CAAC,IAAY,EAAE,QAAgB;IACjE,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAA;AACrC,CAAC;AAED,SAAS,OAAO,CAAC,MAAkB,EAAE,MAAsB;IACzD,IAAI,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;IACvC,IAAI,CAAC,QAAQ;QAAE,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,QAAQ,GAAG,IAAI,GAAG,EAAE,CAAC,CAAC,CAAA;IAC/D,IAAI,KAAK,GAAG,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAA;IACnC,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,yBAAS,CAAC,KAAK,CAAC,CAAC,CAAA;QAClE,kEAAkE;QAClE,KAAK,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,QAAS,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,KAAK,IAAI,QAAS,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAA;QACpF,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,EAAE,KAAK,CAAC,CAAA;IAChC,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC;AAED,sEAAsE;AAC/D,KAAK,UAAU,qBAAqB,CAAC,OAAY;IACtD,MAAM,MAAM,GAAG,OAAO,EAAE,KAAK,EAAE,MAAM,CAAA;IACrC,IAAI,CAAC,MAAM,EAAE,EAAE,IAAI,CAAC,OAAO,EAAE,KAAK,EAAE,IAAI;QAAE,OAAO,EAAE,CAAA;IACnD,MAAM,GAAG,GAAyC,EAAE,CAAA;IACpD,KAAK,MAAM,MAAM,IAAI,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC;QACtC,IAAI,CAAC,CAAC,MAAM,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC;YAAE,SAAQ;QACjE,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,MAAM,OAAO,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,CAAA;IACvE,CAAC;IACD,OAAO,GAAG,CAAA;AACZ,CAAC","sourcesContent":["/*\n * 도움말의 출처 (ADR-0187 decision 12, the place ADR-0181 decision 2 left) - text a company keeps while it runs, found by\n * the same search as the help the application ships: a module registers a source, the parts of each domain are indexed\n * apart and kept in memory, and the source says who of the domain may read them. A source that changes asks to be indexed\n * again. The documents stay one index for everyone; a source's index is a domain's.\n */\nimport { HelpIndex, type HelpPart } from './help-index.js'\n\nexport interface HelpSource {\n /** `regulation` - the module's own name for it. */\n name: string\n /** Every part of the domain the source holds now. A part's topic starts with the source's name (`regulation/WORK`). */\n partsOf(domain: { id: string }): Promise<HelpPart[]>\n /** Whether the request's person may read the source's parts of the request's domain. */\n mayRead(context: any): Promise<boolean>\n}\n\nconst SOURCES = new Map<string, HelpSource>()\n/* source name → domain id → its parts, indexed - or the indexing under way. */\nconst INDEXES = new Map<string, Map<string, Promise<HelpIndex>>>()\n\n/** What a module calls at load to add its text to the help's search. */\nexport function registerHelpSource(source: HelpSource): void {\n SOURCES.set(source.name, source)\n INDEXES.delete(source.name)\n}\n\n/** What a source calls when its text of a domain changed - the next search indexes it again. */\nexport function invalidateHelpSource(name: string, domainId: string): void {\n INDEXES.get(name)?.delete(domainId)\n}\n\nfunction indexOf(source: HelpSource, domain: { id: string }): Promise<HelpIndex> {\n let byDomain = INDEXES.get(source.name)\n if (!byDomain) INDEXES.set(source.name, (byDomain = new Map()))\n let index = byDomain.get(domain.id)\n if (!index) {\n index = source.partsOf(domain).then(parts => new HelpIndex(parts))\n /* A failed indexing is not kept - the next search tries again. */\n index.catch(() => byDomain!.get(domain.id) === index && byDomain!.delete(domain.id))\n byDomain.set(domain.id, index)\n }\n return index\n}\n\n/** The indexes of the sources the request may read, of its domain. */\nexport async function readableSourceIndexes(context: any): Promise<{ name: string; index: HelpIndex }[]> {\n const domain = context?.state?.domain\n if (!domain?.id || !context?.state?.user) return []\n const out: { name: string; index: HelpIndex }[] = []\n for (const source of SOURCES.values()) {\n if (!(await source.mayRead(context).catch(() => false))) continue\n out.push({ name: source.name, index: await indexOf(source, domain) })\n }\n return out\n}\n"]}
@@ -1,12 +1,9 @@
1
- import { HelpIndex, type HelpHit, type HelpSearchOptions } from './help-index.js';
1
+ import { HelpIndex, type HelpHit, type HelpReading, type HelpSearchOptions } from './help-index.js';
2
2
  export declare function helpIndex(): HelpIndex;
3
- /** The parts of the help that answer a question — the screen's `?` and the AI assistant ask the same. */
4
- export declare function searchHelp(query: string, options?: HelpSearchOptions): HelpHit[];
5
- /** One part of the help in the reader's language, or the whole document when no section is named. */
6
- export declare function readHelp(topic: string, section?: string, lang?: string): {
7
- topic: string;
8
- section: string;
9
- title: string;
10
- documentTitle: string;
11
- text: string;
12
- };
3
+ /**
4
+ * The parts of the help that answer a question — the screen's `?` and the AI assistant ask the same. With the request
5
+ * in `options.context`, the parts of the sources its person may read are searched with the documents (ADR-0187 decision 12).
6
+ */
7
+ export declare function searchHelp(query: string, options?: HelpSearchOptions): Promise<HelpHit[]>;
8
+ /** One part of the help in the reader's language, or the whole document when no section is named - a source's too, to whom may read it. */
9
+ export declare function readHelp(topic: string, section?: string, lang?: string, context?: any): Promise<HelpReading | null>;
@@ -6,6 +6,7 @@ exports.readHelp = readHelp;
6
6
  const tslib_1 = require("tslib");
7
7
  const path_1 = tslib_1.__importDefault(require("path"));
8
8
  const help_index_js_1 = require("./help-index.js");
9
+ const help_sources_js_1 = require("./help-sources.js");
9
10
  /*
10
11
  * The index of the help documents the application serves — read from where /helps is served (dist-app/helps), once, and
11
12
  * again whenever the client is rebuilt in development (webpack writes to memory then, as help-router reads).
@@ -54,12 +55,26 @@ function helpIndex() {
54
55
  }
55
56
  return index;
56
57
  }
57
- /** The parts of the help that answer a question — the screen's `?` and the AI assistant ask the same. */
58
- function searchHelp(query, options = {}) {
59
- return helpIndex().search(query, options);
58
+ /**
59
+ * The parts of the help that answer a question — the screen's `?` and the AI assistant ask the same. With the request
60
+ * in `options.context`, the parts of the sources its person may read are searched with the documents (ADR-0187 decision 12).
61
+ */
62
+ async function searchHelp(query, options = {}) {
63
+ const { context, ...rest } = options;
64
+ const limit = rest.limit ?? 5;
65
+ const hits = helpIndex().search(query, rest);
66
+ for (const { index } of await (0, help_sources_js_1.readableSourceIndexes)(context))
67
+ hits.push(...index.search(query, rest));
68
+ return hits.sort((a, b) => b.score - a.score).slice(0, limit);
60
69
  }
61
- /** One part of the help in the reader's language, or the whole document when no section is named. */
62
- function readHelp(topic, section = '', lang) {
63
- return helpIndex().read(topic, section, lang);
70
+ /** One part of the help in the reader's language, or the whole document when no section is named - a source's too, to whom may read it. */
71
+ async function readHelp(topic, section = '', lang, context) {
72
+ const found = helpIndex().read(topic, section, lang);
73
+ if (found)
74
+ return found;
75
+ for (const { name, index } of await (0, help_sources_js_1.readableSourceIndexes)(context))
76
+ if (topic.startsWith(`${name}/`))
77
+ return index.read(topic, section, lang);
78
+ return null;
64
79
  }
65
80
  //# sourceMappingURL=help-store.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"help-store.js","sourceRoot":"","sources":["../server/help-store.ts"],"names":[],"mappings":";;AAuCA,8BAcC;AAGD,gCAEC;AAGD,4BAEC;;AA/DD,wDAAuB;AAEvB,mDAAkG;AAElG;;;GAGG;AACH,IAAI,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;AACtB,IAAI,KAA4B,CAAA;AAEhC,OAAO,CAAC,EAAE,CAAC,gBAAuB,EAAE,CAAC,IAAa,EAAE,kBAAuB,EAAE,EAAE;IAC7E,EAAE,GAAG,kBAAkB,CAAA;IACvB,KAAK,GAAG,SAAS,CAAA;AACnB,CAAC,CAAC,CAAA;AAEF,SAAS,SAAS;IAChB,OAAO,cAAI,CAAC,OAAO,CAAC,cAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,UAAU,EAAE,OAAO,CAAC,CAAA;AAC7D,CAAC;AAED,SAAS,KAAK,CAAC,GAAW,EAAE,MAAM,GAAG,EAAE;IACrC,IAAI,KAAe,CAAA;IACnB,IAAI,CAAC;QACH,KAAK,GAAG,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,CAAA;IAC7B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAA;IACX,CAAC;IACD,OAAO,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE;QAC1B,MAAM,IAAI,GAAG,cAAI,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAA;QACjC,MAAM,QAAQ,GAAG,MAAM,CAAC,CAAC,CAAC,GAAG,MAAM,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAA;QACpD,IAAI,CAAC;YACH,IAAI,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE;gBAAE,OAAO,KAAK,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAA;QACnE,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,EAAE,CAAA;QACX,CAAC;QACD,OAAO,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAA;IACpD,CAAC,CAAC,CAAA;AACJ,CAAC;AAED,SAAgB,SAAS;IACvB,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,IAAI,GAAG,SAAS,EAAE,CAAA;QACxB,KAAK,GAAG,IAAI,yBAAS,CACnB,KAAK,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE;YACzB,IAAI,CAAC;gBACH,OAAO,IAAA,+BAAe,EAAC,IAAI,EAAE,MAAM,CAAC,EAAE,CAAC,YAAY,CAAC,cAAI,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,CAAA;YAC9E,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,EAAE,CAAA;YACX,CAAC;QACH,CAAC,CAAC,CACH,CAAA;IACH,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC;AAED,yGAAyG;AACzG,SAAgB,UAAU,CAAC,KAAa,EAAE,UAA6B,EAAE;IACvE,OAAO,SAAS,EAAE,CAAC,MAAM,CAAC,KAAK,EAAE,OAAO,CAAC,CAAA;AAC3C,CAAC;AAED,qGAAqG;AACrG,SAAgB,QAAQ,CAAC,KAAa,EAAE,OAAO,GAAG,EAAE,EAAE,IAAa;IACjE,OAAO,SAAS,EAAE,CAAC,IAAI,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,CAAC,CAAA;AAC/C,CAAC","sourcesContent":["import path from 'path'\n\nimport { HelpIndex, partsOfDocument, type HelpHit, type HelpSearchOptions } from './help-index.js'\n\n/*\n * The index of the help documents the application serves — read from where /helps is served (dist-app/helps), once, and\n * again whenever the client is rebuilt in development (webpack writes to memory then, as help-router reads).\n */\nvar fs = require('fs')\nlet index: HelpIndex | undefined\n\nprocess.on('client-rebuilt' as any, (_app: unknown, compilerFileSystem: any) => {\n fs = compilerFileSystem\n index = undefined\n})\n\nfunction helpsRoot(): string {\n return path.resolve(path.resolve('.'), 'dist-app', 'helps')\n}\n\nfunction files(dir: string, prefix = ''): string[] {\n let names: string[]\n try {\n names = fs.readdirSync(dir)\n } catch {\n return []\n }\n return names.flatMap(name => {\n const full = path.join(dir, name)\n const relative = prefix ? `${prefix}/${name}` : name\n try {\n if (fs.statSync(full).isDirectory()) return files(full, relative)\n } catch {\n return []\n }\n return /\\.(html|md)$/.test(name) ? [relative] : []\n })\n}\n\nexport function helpIndex(): HelpIndex {\n if (!index) {\n const root = helpsRoot()\n index = new HelpIndex(\n files(root).flatMap(file => {\n try {\n return partsOfDocument(file, String(fs.readFileSync(path.join(root, file))))\n } catch {\n return []\n }\n })\n )\n }\n return index\n}\n\n/** The parts of the help that answer a question — the screen's `?` and the AI assistant ask the same. */\nexport function searchHelp(query: string, options: HelpSearchOptions = {}): HelpHit[] {\n return helpIndex().search(query, options)\n}\n\n/** One part of the help in the reader's language, or the whole document when no section is named. */\nexport function readHelp(topic: string, section = '', lang?: string) {\n return helpIndex().read(topic, section, lang)\n}\n"]}
1
+ {"version":3,"file":"help-store.js","sourceRoot":"","sources":["../server/help-store.ts"],"names":[],"mappings":"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","sourcesContent":["import path from 'path'\n\nimport { HelpIndex, partsOfDocument, type HelpHit, type HelpReading, type HelpSearchOptions } from './help-index.js'\nimport { readableSourceIndexes } from './help-sources.js'\n\n/*\n * The index of the help documents the application serves — read from where /helps is served (dist-app/helps), once, and\n * again whenever the client is rebuilt in development (webpack writes to memory then, as help-router reads).\n */\nvar fs = require('fs')\nlet index: HelpIndex | undefined\n\nprocess.on('client-rebuilt' as any, (_app: unknown, compilerFileSystem: any) => {\n fs = compilerFileSystem\n index = undefined\n})\n\nfunction helpsRoot(): string {\n return path.resolve(path.resolve('.'), 'dist-app', 'helps')\n}\n\nfunction files(dir: string, prefix = ''): string[] {\n let names: string[]\n try {\n names = fs.readdirSync(dir)\n } catch {\n return []\n }\n return names.flatMap(name => {\n const full = path.join(dir, name)\n const relative = prefix ? `${prefix}/${name}` : name\n try {\n if (fs.statSync(full).isDirectory()) return files(full, relative)\n } catch {\n return []\n }\n return /\\.(html|md)$/.test(name) ? [relative] : []\n })\n}\n\nexport function helpIndex(): HelpIndex {\n if (!index) {\n const root = helpsRoot()\n index = new HelpIndex(\n files(root).flatMap(file => {\n try {\n return partsOfDocument(file, String(fs.readFileSync(path.join(root, file))))\n } catch {\n return []\n }\n })\n )\n }\n return index\n}\n\n/**\n * The parts of the help that answer a question — the screen's `?` and the AI assistant ask the same. With the request\n * in `options.context`, the parts of the sources its person may read are searched with the documents (ADR-0187 decision 12).\n */\nexport async function searchHelp(query: string, options: HelpSearchOptions = {}): Promise<HelpHit[]> {\n const { context, ...rest } = options\n const limit = rest.limit ?? 5\n const hits = helpIndex().search(query, rest)\n for (const { index } of await readableSourceIndexes(context)) hits.push(...index.search(query, rest))\n return hits.sort((a, b) => b.score - a.score).slice(0, limit)\n}\n\n/** One part of the help in the reader's language, or the whole document when no section is named - a source's too, to whom may read it. */\nexport async function readHelp(topic: string, section = '', lang?: string, context?: any): Promise<HelpReading | null> {\n const found = helpIndex().read(topic, section, lang)\n if (found) return found\n for (const { name, index } of await readableSourceIndexes(context)) if (topic.startsWith(`${name}/`)) return index.read(topic, section, lang)\n return null\n}\n"]}
@@ -1,3 +1,4 @@
1
1
  import './routes.js';
2
2
  export * from './help-index.js';
3
3
  export { helpIndex, searchHelp, readHelp } from './help-store.js';
4
+ export { registerHelpSource, invalidateHelpSource, type HelpSource } from './help-sources.js';
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.readHelp = exports.searchHelp = exports.helpIndex = void 0;
3
+ exports.invalidateHelpSource = exports.registerHelpSource = exports.readHelp = exports.searchHelp = exports.helpIndex = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  require("./routes.js");
6
6
  tslib_1.__exportStar(require("./help-index.js"), exports);
@@ -8,4 +8,7 @@ var help_store_js_1 = require("./help-store.js");
8
8
  Object.defineProperty(exports, "helpIndex", { enumerable: true, get: function () { return help_store_js_1.helpIndex; } });
9
9
  Object.defineProperty(exports, "searchHelp", { enumerable: true, get: function () { return help_store_js_1.searchHelp; } });
10
10
  Object.defineProperty(exports, "readHelp", { enumerable: true, get: function () { return help_store_js_1.readHelp; } });
11
+ var help_sources_js_1 = require("./help-sources.js");
12
+ Object.defineProperty(exports, "registerHelpSource", { enumerable: true, get: function () { return help_sources_js_1.registerHelpSource; } });
13
+ Object.defineProperty(exports, "invalidateHelpSource", { enumerable: true, get: function () { return help_sources_js_1.invalidateHelpSource; } });
11
14
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../server/index.ts"],"names":[],"mappings":";;;;AAAA,uBAAoB;AAEpB,0DAA+B;AAC/B,iDAAiE;AAAxD,0GAAA,SAAS,OAAA;AAAE,2GAAA,UAAU,OAAA;AAAE,yGAAA,QAAQ,OAAA","sourcesContent":["import './routes.js'\n\nexport * from './help-index.js'\nexport { helpIndex, searchHelp, readHelp } from './help-store.js'\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../server/index.ts"],"names":[],"mappings":";;;;AAAA,uBAAoB;AAEpB,0DAA+B;AAC/B,iDAAiE;AAAxD,0GAAA,SAAS,OAAA;AAAE,2GAAA,UAAU,OAAA;AAAE,yGAAA,QAAQ,OAAA;AACxC,qDAA6F;AAApF,qHAAA,kBAAkB,OAAA;AAAE,uHAAA,oBAAoB,OAAA","sourcesContent":["import './routes.js'\n\nexport * from './help-index.js'\nexport { helpIndex, searchHelp, readHelp } from './help-store.js'\nexport { registerHelpSource, invalidateHelpSource, type HelpSource } from './help-sources.js'\n"]}
@@ -18,12 +18,13 @@ process.on('client-rebuilt', (app, compilerFileSystem) => {
18
18
  exports.helpRouter.get('/search', async (context) => {
19
19
  const { q = '', scope, audience, limit, coverage } = context.query;
20
20
  const minCoverage = Number(coverage);
21
- context.body = (0, help_store_js_1.searchHelp)(String(q), {
21
+ context.body = await (0, help_store_js_1.searchHelp)(String(q), {
22
22
  lang: context.language,
23
23
  scope: scope || undefined,
24
24
  audience: audience || undefined,
25
25
  limit: Math.min(Math.max(Number(limit) || 5, 1), 20),
26
- minCoverage: minCoverage > 0 && minCoverage <= 1 ? minCoverage : undefined
26
+ minCoverage: minCoverage > 0 && minCoverage <= 1 ? minCoverage : undefined,
27
+ context
27
28
  });
28
29
  context.type = 'application/json; charset=UTF-8';
29
30
  });
@@ -1 +1 @@
1
- {"version":3,"file":"help-router.js","sourceRoot":"","sources":["../../server/routers/help-router.ts"],"names":[],"mappings":"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","sourcesContent":["import Router from 'koa-router'\nimport path from 'path'\n\nimport { searchHelp } from '../help-store.js'\n\nexport const helpRouter = new Router()\n\nvar fs = require('fs')\n\nprocess.on('client-rebuilt' as any, (app, compilerFileSystem) => {\n /* change filesystem whenever webpacking assets done. only for development mode. */\n fs = compilerFileSystem\n})\n\n/*\n * 도움말 검색(ADR-0181) — 화면의 `?` 가 「이 화면의 도움말」을, AI 비서가 질문의 도움말을 같은 색인에서 찾는다.\n * `q` 는 검색어, `scope` 는 주제 경로(`office`), `audience` 는 읽는 사람(`finance`), 언어는 요청의 것.\n */\nhelpRouter.get('/search', async context => {\n const { q = '', scope, audience, limit, coverage } = context.query as Record<string, string | undefined>\n const minCoverage = Number(coverage)\n context.body = searchHelp(String(q), {\n lang: (context as any).language,\n scope: scope || undefined,\n audience: audience || undefined,\n limit: Math.min(Math.max(Number(limit) || 5, 1), 20),\n minCoverage: minCoverage > 0 && minCoverage <= 1 ? minCoverage : undefined\n })\n context.type = 'application/json; charset=UTF-8'\n})\n\nhelpRouter.get('/(.+)/index.md', async (context, next) => {\n const appRootPath = path.resolve('.')\n const PUBLIC_ROOT = path.resolve(appRootPath, 'dist-app') // webpack config output.path\n const { path: pathname } = context\n const folder = pathname.slice(0, pathname.lastIndexOf('/index.md'))\n const folderName = PUBLIC_ROOT + folder\n\n if (fs.existsSync(`${folderName}/index.md`)) {\n context.url = `${pathname}`\n return next()\n }\n\n // If index.md doesn't exist, list topics in the folder\n const topicList = []\n\n // List all files in the folder\n const folderContents = fs.readdirSync(folderName)\n\n // Loop through the files to find matching topics\n for (const file of folderContents) {\n // Check if the file matches the {topic}.{locale}.md pattern\n const topicLocaleMatch = file.match(/(.+)\\.(.+)\\.md/)\n if (topicLocaleMatch) {\n const [, topic, locale] = topicLocaleMatch\n topicList.push(`- [${topic}](${folder}/${topic}.md)`)\n } else {\n // Check if the file matches the {topic}.md pattern\n const topicMatch = file.match(/(.+)\\.md/)\n if (topicMatch) {\n const [, topic] = topicMatch\n topicList.push(`- [${topic}](${folder}/${topic}.md)`)\n }\n }\n }\n\n // If topics are found, return the list in markdown format\n if (topicList.length > 0) {\n const uniqueList = [...new Set(topicList)]\n const topicListMarkdown = [`# ${folder}`, ...uniqueList].join('\\n\\n')\n context.body = topicListMarkdown\n context.type = 'text/markdown; charset=UTF-8'\n } else {\n // If no topics found, you can return a message or handle it as you like\n context.body = 'No topics found in this folder.'\n }\n})\n\nhelpRouter.get('/(.+).md', async (context, next) => {\n const appRootPath = path.resolve('.')\n const PUBLIC_ROOT = path.resolve(appRootPath, 'dist-app') // webpack config output.path\n\n const { language, i18next, path: pathname } = context\n\n const filePath = PUBLIC_ROOT + pathname\n const fileName = filePath.slice(0, filePath.lastIndexOf('.md'))\n const pathnameNoExt = pathname.slice(0, pathname.lastIndexOf('.md'))\n\n var fallbacks = language.indexOf('-') !== -1 ? [language.split('-')[0]] : []\n const fallbackLng = i18next?.options?.fallbackLng\n if (fallbackLng && !fallbacks.includes(fallbackLng)) {\n fallbacks.push(fallbackLng)\n }\n\n var loc = [language, ...fallbacks].find(loc => fs.existsSync(`${fileName}.${loc}.md`))\n if (loc !== undefined) {\n context.url = `${pathnameNoExt}.${loc}.md`\n }\n\n return next()\n})\n\n/*\n * 리치 문서(.html) — 마크다운과 동일한 로케일 해석. ox-doc(ox-markdown 의 리치 짝)이 소비.\n * 정적 파일·로케일 자동 해석 구조를 그대로 확장(호출부는 topic 하나만, 다국어 링크 복잡함 제거).\n */\nhelpRouter.get('/(.+).html', async (context, next) => {\n const appRootPath = path.resolve('.')\n const PUBLIC_ROOT = path.resolve(appRootPath, 'dist-app') // webpack config output.path\n\n const { language, i18next, path: pathname } = context\n\n const filePath = PUBLIC_ROOT + pathname\n const fileName = filePath.slice(0, filePath.lastIndexOf('.html'))\n const pathnameNoExt = pathname.slice(0, pathname.lastIndexOf('.html'))\n\n var fallbacks = language.indexOf('-') !== -1 ? [language.split('-')[0]] : []\n const fallbackLng = i18next?.options?.fallbackLng\n if (fallbackLng && !fallbacks.includes(fallbackLng)) {\n fallbacks.push(fallbackLng)\n }\n\n var loc = [language, ...fallbacks].find(loc => fs.existsSync(`${fileName}.${loc}.html`))\n if (loc !== undefined) {\n context.url = `${pathnameNoExt}.${loc}.html`\n }\n\n return next()\n})\n"]}
1
+ {"version":3,"file":"help-router.js","sourceRoot":"","sources":["../../server/routers/help-router.ts"],"names":[],"mappings":"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","sourcesContent":["import Router from 'koa-router'\nimport path from 'path'\n\nimport { searchHelp } from '../help-store.js'\n\nexport const helpRouter = new Router()\n\nvar fs = require('fs')\n\nprocess.on('client-rebuilt' as any, (app, compilerFileSystem) => {\n /* change filesystem whenever webpacking assets done. only for development mode. */\n fs = compilerFileSystem\n})\n\n/*\n * 도움말 검색(ADR-0181) — 화면의 `?` 가 「이 화면의 도움말」을, AI 비서가 질문의 도움말을 같은 색인에서 찾는다.\n * `q` 는 검색어, `scope` 는 주제 경로(`office`), `audience` 는 읽는 사람(`finance`), 언어는 요청의 것.\n */\nhelpRouter.get('/search', async context => {\n const { q = '', scope, audience, limit, coverage } = context.query as Record<string, string | undefined>\n const minCoverage = Number(coverage)\n context.body = await searchHelp(String(q), {\n lang: (context as any).language,\n scope: scope || undefined,\n audience: audience || undefined,\n limit: Math.min(Math.max(Number(limit) || 5, 1), 20),\n minCoverage: minCoverage > 0 && minCoverage <= 1 ? minCoverage : undefined,\n context\n })\n context.type = 'application/json; charset=UTF-8'\n})\n\nhelpRouter.get('/(.+)/index.md', async (context, next) => {\n const appRootPath = path.resolve('.')\n const PUBLIC_ROOT = path.resolve(appRootPath, 'dist-app') // webpack config output.path\n const { path: pathname } = context\n const folder = pathname.slice(0, pathname.lastIndexOf('/index.md'))\n const folderName = PUBLIC_ROOT + folder\n\n if (fs.existsSync(`${folderName}/index.md`)) {\n context.url = `${pathname}`\n return next()\n }\n\n // If index.md doesn't exist, list topics in the folder\n const topicList = []\n\n // List all files in the folder\n const folderContents = fs.readdirSync(folderName)\n\n // Loop through the files to find matching topics\n for (const file of folderContents) {\n // Check if the file matches the {topic}.{locale}.md pattern\n const topicLocaleMatch = file.match(/(.+)\\.(.+)\\.md/)\n if (topicLocaleMatch) {\n const [, topic, locale] = topicLocaleMatch\n topicList.push(`- [${topic}](${folder}/${topic}.md)`)\n } else {\n // Check if the file matches the {topic}.md pattern\n const topicMatch = file.match(/(.+)\\.md/)\n if (topicMatch) {\n const [, topic] = topicMatch\n topicList.push(`- [${topic}](${folder}/${topic}.md)`)\n }\n }\n }\n\n // If topics are found, return the list in markdown format\n if (topicList.length > 0) {\n const uniqueList = [...new Set(topicList)]\n const topicListMarkdown = [`# ${folder}`, ...uniqueList].join('\\n\\n')\n context.body = topicListMarkdown\n context.type = 'text/markdown; charset=UTF-8'\n } else {\n // If no topics found, you can return a message or handle it as you like\n context.body = 'No topics found in this folder.'\n }\n})\n\nhelpRouter.get('/(.+).md', async (context, next) => {\n const appRootPath = path.resolve('.')\n const PUBLIC_ROOT = path.resolve(appRootPath, 'dist-app') // webpack config output.path\n\n const { language, i18next, path: pathname } = context\n\n const filePath = PUBLIC_ROOT + pathname\n const fileName = filePath.slice(0, filePath.lastIndexOf('.md'))\n const pathnameNoExt = pathname.slice(0, pathname.lastIndexOf('.md'))\n\n var fallbacks = language.indexOf('-') !== -1 ? [language.split('-')[0]] : []\n const fallbackLng = i18next?.options?.fallbackLng\n if (fallbackLng && !fallbacks.includes(fallbackLng)) {\n fallbacks.push(fallbackLng)\n }\n\n var loc = [language, ...fallbacks].find(loc => fs.existsSync(`${fileName}.${loc}.md`))\n if (loc !== undefined) {\n context.url = `${pathnameNoExt}.${loc}.md`\n }\n\n return next()\n})\n\n/*\n * 리치 문서(.html) — 마크다운과 동일한 로케일 해석. ox-doc(ox-markdown 의 리치 짝)이 소비.\n * 정적 파일·로케일 자동 해석 구조를 그대로 확장(호출부는 topic 하나만, 다국어 링크 복잡함 제거).\n */\nhelpRouter.get('/(.+).html', async (context, next) => {\n const appRootPath = path.resolve('.')\n const PUBLIC_ROOT = path.resolve(appRootPath, 'dist-app') // webpack config output.path\n\n const { language, i18next, path: pathname } = context\n\n const filePath = PUBLIC_ROOT + pathname\n const fileName = filePath.slice(0, filePath.lastIndexOf('.html'))\n const pathnameNoExt = pathname.slice(0, pathname.lastIndexOf('.html'))\n\n var fallbacks = language.indexOf('-') !== -1 ? [language.split('-')[0]] : []\n const fallbackLng = i18next?.options?.fallbackLng\n if (fallbackLng && !fallbacks.includes(fallbackLng)) {\n fallbacks.push(fallbackLng)\n }\n\n var loc = [language, ...fallbacks].find(loc => fs.existsSync(`${fileName}.${loc}.html`))\n if (loc !== undefined) {\n context.url = `${pathnameNoExt}.${loc}.html`\n }\n\n return next()\n})\n"]}