@finsys/core 2.4.0 → 2.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/data/adapter-categories.json +156 -0
- package/dist/data/form-field-base-specs.json +0 -20
- package/dist/index.cjs +274 -36
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +467 -1
- package/dist/index.d.ts +467 -1
- package/dist/index.js +267 -36
- package/dist/index.js.map +1 -1
- package/dist/schema/adapter-manifest.schema.json +101 -0
- package/package.json +6 -1
package/dist/index.js
CHANGED
|
@@ -9,7 +9,7 @@ function getPastYearLabel(yearsAgo) {
|
|
|
9
9
|
const date = /* @__PURE__ */ new Date();
|
|
10
10
|
return (date.getFullYear() - yearsAgo).toString();
|
|
11
11
|
}
|
|
12
|
-
function evaluateExpression(expression,
|
|
12
|
+
function evaluateExpression(expression, data2) {
|
|
13
13
|
if (!expression) return true;
|
|
14
14
|
try {
|
|
15
15
|
let jsExpression = expression.replace(/\{([^}]+)\}/g, (_, key) => {
|
|
@@ -33,7 +33,7 @@ function evaluateExpression(expression, data) {
|
|
|
33
33
|
(_, ref, val) => `!(${ref} || []).includes('${val}')`
|
|
34
34
|
);
|
|
35
35
|
const func = new Function(`return ${jsExpression};`);
|
|
36
|
-
return !!func.call(
|
|
36
|
+
return !!func.call(data2 || {});
|
|
37
37
|
} catch (e) {
|
|
38
38
|
return false;
|
|
39
39
|
}
|
|
@@ -179,16 +179,16 @@ function groupFieldsByCategory(fields, categories) {
|
|
|
179
179
|
// src/rhf-generator.ts
|
|
180
180
|
import { z } from "zod";
|
|
181
181
|
function applyVisibilityValidation(baseObject, fields) {
|
|
182
|
-
return baseObject.superRefine((
|
|
182
|
+
return baseObject.superRefine((data2, ctx) => {
|
|
183
183
|
fields.forEach((field) => {
|
|
184
184
|
const isRequired = field.isRequired !== false && field.required !== false && field.type !== "html";
|
|
185
185
|
if (!isRequired) return;
|
|
186
186
|
let isVisible = field.visible !== false;
|
|
187
187
|
if (isVisible && field.visibleIf) {
|
|
188
|
-
isVisible = evaluateExpression(field.visibleIf,
|
|
188
|
+
isVisible = evaluateExpression(field.visibleIf, data2);
|
|
189
189
|
}
|
|
190
190
|
if (isVisible) {
|
|
191
|
-
const value =
|
|
191
|
+
const value = data2[field.name];
|
|
192
192
|
const isEmpty = value === void 0 || value === null || value === "" || Array.isArray(value) && value.length === 0;
|
|
193
193
|
if (isEmpty) {
|
|
194
194
|
ctx.addIssue({
|
|
@@ -649,22 +649,22 @@ var ajv = new Ajv({ allErrors: true, strict: false });
|
|
|
649
649
|
var addFormatsFn = addFormats.default || addFormats;
|
|
650
650
|
addFormatsFn(ajv);
|
|
651
651
|
ajv.addSchema(unified_form_schema_default, "unified-form.schema.json");
|
|
652
|
-
function validateFormConfig(
|
|
652
|
+
function validateFormConfig(data2) {
|
|
653
653
|
const validate = ajv.getSchema("unified-form.schema.json");
|
|
654
654
|
if (!validate) {
|
|
655
655
|
return { valid: false, message: "Could not load unified form schema" };
|
|
656
656
|
}
|
|
657
|
-
const valid = validate(
|
|
657
|
+
const valid = validate(data2);
|
|
658
658
|
return {
|
|
659
659
|
valid: !!valid,
|
|
660
660
|
errors: validate.errors || void 0
|
|
661
661
|
};
|
|
662
662
|
}
|
|
663
|
-
function validateFormSpec(
|
|
664
|
-
return validateFormConfig(
|
|
663
|
+
function validateFormSpec(data2) {
|
|
664
|
+
return validateFormConfig(data2);
|
|
665
665
|
}
|
|
666
|
-
function validatePagesConfig(
|
|
667
|
-
return validateFormConfig(
|
|
666
|
+
function validatePagesConfig(data2) {
|
|
667
|
+
return validateFormConfig(data2);
|
|
668
668
|
}
|
|
669
669
|
|
|
670
670
|
// src/form-field-category.ts
|
|
@@ -1121,10 +1121,10 @@ var _FormSpec = class _FormSpec {
|
|
|
1121
1121
|
if (Array.isArray(jsonData.fields)) {
|
|
1122
1122
|
fieldObjects = jsonData.fields;
|
|
1123
1123
|
} else if (typeof jsonData.fields === "object" && jsonData.fields !== null) {
|
|
1124
|
-
fieldObjects = Object.entries(jsonData.fields).map(([name,
|
|
1124
|
+
fieldObjects = Object.entries(jsonData.fields).map(([name, data2]) => {
|
|
1125
1125
|
return {
|
|
1126
1126
|
name,
|
|
1127
|
-
...
|
|
1127
|
+
...data2
|
|
1128
1128
|
};
|
|
1129
1129
|
});
|
|
1130
1130
|
}
|
|
@@ -7888,7 +7888,6 @@ var form_field_base_specs_default = {
|
|
|
7888
7888
|
name: "bank_statement_t1",
|
|
7889
7889
|
displayName: "Bank Statement (Month T-1)",
|
|
7890
7890
|
type: "file",
|
|
7891
|
-
enableIf: "{formOfDisclosure} contains 'consented'",
|
|
7892
7891
|
ihs_column_names: [
|
|
7893
7892
|
"accountHolderNameT1",
|
|
7894
7893
|
"statementDateT1",
|
|
@@ -7905,7 +7904,6 @@ var form_field_base_specs_default = {
|
|
|
7905
7904
|
name: "bank_statement_t2",
|
|
7906
7905
|
displayName: "Bank Statement (Month T-2)",
|
|
7907
7906
|
type: "file",
|
|
7908
|
-
enableIf: "{formOfDisclosure} contains 'consented'",
|
|
7909
7907
|
ihs_column_names: [
|
|
7910
7908
|
"accountHolderNameT2",
|
|
7911
7909
|
"statementDateT2",
|
|
@@ -7922,7 +7920,6 @@ var form_field_base_specs_default = {
|
|
|
7922
7920
|
name: "bank_statement_t3",
|
|
7923
7921
|
displayName: "Bank Statement (Month T-3)",
|
|
7924
7922
|
type: "file",
|
|
7925
|
-
enableIf: "{formOfDisclosure} contains 'consented'",
|
|
7926
7923
|
ihs_column_names: [
|
|
7927
7924
|
"accountHolderNameT3",
|
|
7928
7925
|
"statementDateT3",
|
|
@@ -7939,7 +7936,6 @@ var form_field_base_specs_default = {
|
|
|
7939
7936
|
name: "bank_statement_t4",
|
|
7940
7937
|
displayName: "Bank Statement (Month T-4)",
|
|
7941
7938
|
type: "file",
|
|
7942
|
-
enableIf: "{formOfDisclosure} contains 'consented'",
|
|
7943
7939
|
ihs_column_names: [
|
|
7944
7940
|
"accountHolderNameT4",
|
|
7945
7941
|
"statementDateT4",
|
|
@@ -7956,7 +7952,6 @@ var form_field_base_specs_default = {
|
|
|
7956
7952
|
name: "bank_statement_t5",
|
|
7957
7953
|
displayName: "Bank Statement (Month T-5)",
|
|
7958
7954
|
type: "file",
|
|
7959
|
-
enableIf: "{formOfDisclosure} contains 'consented'",
|
|
7960
7955
|
ihs_column_names: [
|
|
7961
7956
|
"accountHolderNameT5",
|
|
7962
7957
|
"statementDateT5",
|
|
@@ -7973,7 +7968,6 @@ var form_field_base_specs_default = {
|
|
|
7973
7968
|
name: "bank_statement_t6",
|
|
7974
7969
|
displayName: "Bank Statement (Month T-6)",
|
|
7975
7970
|
type: "file",
|
|
7976
|
-
enableIf: "{formOfDisclosure} contains 'consented'",
|
|
7977
7971
|
ihs_column_names: [
|
|
7978
7972
|
"accountHolderNameT6",
|
|
7979
7973
|
"statementDateT6",
|
|
@@ -7990,7 +7984,6 @@ var form_field_base_specs_default = {
|
|
|
7990
7984
|
name: "financials",
|
|
7991
7985
|
displayName: "Audited Financial Statement",
|
|
7992
7986
|
type: "file",
|
|
7993
|
-
enableIf: "{formOfDisclosure} contains 'consented'",
|
|
7994
7987
|
ihs_column_names: [
|
|
7995
7988
|
"shareCapital",
|
|
7996
7989
|
"totalEquityT1",
|
|
@@ -8012,7 +8005,6 @@ var form_field_base_specs_default = {
|
|
|
8012
8005
|
name: "financials_fincap_t1",
|
|
8013
8006
|
displayName: "Audited Financial Statement (T-1) (FinCap)",
|
|
8014
8007
|
type: "file",
|
|
8015
|
-
enableIf: "{formOfDisclosure} contains 'consented'",
|
|
8016
8008
|
ihs_column_names: [
|
|
8017
8009
|
"nonCurrentAssetsSubsidiaryCompaniesT1",
|
|
8018
8010
|
"nonCurrentAssetsAssociatedCompaniesT1",
|
|
@@ -8257,7 +8249,6 @@ var form_field_base_specs_default = {
|
|
|
8257
8249
|
name: "financials_fincap_t2",
|
|
8258
8250
|
displayName: "Audited Financial Statement (T-2) (FinCap)",
|
|
8259
8251
|
type: "file",
|
|
8260
|
-
enableIf: "{formOfDisclosure} contains 'consented'",
|
|
8261
8252
|
ihs_column_names: [
|
|
8262
8253
|
"nonCurrentAssetsSubsidiaryCompaniesT3",
|
|
8263
8254
|
"nonCurrentAssetsAssociatedCompaniesT3",
|
|
@@ -8384,7 +8375,6 @@ var form_field_base_specs_default = {
|
|
|
8384
8375
|
name: "form9",
|
|
8385
8376
|
displayName: "Form 9 / Section 17 / Form D",
|
|
8386
8377
|
type: "file",
|
|
8387
|
-
enableIf: "{formOfDisclosure} contains 'consented'",
|
|
8388
8378
|
ihs_column_names: [
|
|
8389
8379
|
"incorporatedDate",
|
|
8390
8380
|
"companyName",
|
|
@@ -8396,7 +8386,6 @@ var form_field_base_specs_default = {
|
|
|
8396
8386
|
name: "ssm",
|
|
8397
8387
|
displayName: "SSM Company Profile",
|
|
8398
8388
|
type: "file",
|
|
8399
|
-
enableIf: "{formOfDisclosure} contains 'consented'",
|
|
8400
8389
|
ihs_column_names: [
|
|
8401
8390
|
"ssmCompanyName",
|
|
8402
8391
|
"ssmCompanyRegNo",
|
|
@@ -8421,7 +8410,6 @@ var form_field_base_specs_default = {
|
|
|
8421
8410
|
name: "ic",
|
|
8422
8411
|
displayName: "Identification Card (Front)",
|
|
8423
8412
|
type: "file",
|
|
8424
|
-
enableIf: "{formOfDisclosure} contains 'consented'",
|
|
8425
8413
|
ihs_column_names: [
|
|
8426
8414
|
"icNumber",
|
|
8427
8415
|
"icName",
|
|
@@ -8439,7 +8427,6 @@ var form_field_base_specs_default = {
|
|
|
8439
8427
|
name: "epf_statement_t1",
|
|
8440
8428
|
displayName: "Employees' Provident Fund (T-1)",
|
|
8441
8429
|
type: "file",
|
|
8442
|
-
enableIf: "{formOfDisclosure} contains 'consented'",
|
|
8443
8430
|
ihs_column_names: [
|
|
8444
8431
|
"epfAccountHolderNameT1",
|
|
8445
8432
|
"epfAccountHolderAddressT1",
|
|
@@ -8457,7 +8444,6 @@ var form_field_base_specs_default = {
|
|
|
8457
8444
|
name: "epf_statement_t2",
|
|
8458
8445
|
displayName: "Employees' Provident Fund (T-2)",
|
|
8459
8446
|
type: "file",
|
|
8460
|
-
enableIf: "{formOfDisclosure} contains 'consented'",
|
|
8461
8447
|
ihs_column_names: [
|
|
8462
8448
|
"epfAccountHolderNameT2",
|
|
8463
8449
|
"epfAccountHolderAddressT2",
|
|
@@ -8475,7 +8461,6 @@ var form_field_base_specs_default = {
|
|
|
8475
8461
|
name: "payslip_statement_t1",
|
|
8476
8462
|
displayName: "Payslip Statement (Month T-1)",
|
|
8477
8463
|
type: "file",
|
|
8478
|
-
enableIf: "{formOfDisclosure} contains 'consented'",
|
|
8479
8464
|
ihs_column_names: [
|
|
8480
8465
|
"payslipEmployerNameT1",
|
|
8481
8466
|
"payslipEmployeeNameT1",
|
|
@@ -8499,7 +8484,6 @@ var form_field_base_specs_default = {
|
|
|
8499
8484
|
name: "payslip_statement_t2",
|
|
8500
8485
|
displayName: "Payslip Statement (Month T-2)",
|
|
8501
8486
|
type: "file",
|
|
8502
|
-
enableIf: "{formOfDisclosure} contains 'consented'",
|
|
8503
8487
|
ihs_column_names: [
|
|
8504
8488
|
"payslipEmployerNameT2",
|
|
8505
8489
|
"payslipEmployeeNameT2",
|
|
@@ -8523,7 +8507,6 @@ var form_field_base_specs_default = {
|
|
|
8523
8507
|
name: "payslip_statement_t3",
|
|
8524
8508
|
displayName: "Payslip Statement (Month T-3)",
|
|
8525
8509
|
type: "file",
|
|
8526
|
-
enableIf: "{formOfDisclosure} contains 'consented'",
|
|
8527
8510
|
ihs_column_names: [
|
|
8528
8511
|
"payslipEmployerNameT3",
|
|
8529
8512
|
"payslipEmployeeNameT3",
|
|
@@ -8547,7 +8530,6 @@ var form_field_base_specs_default = {
|
|
|
8547
8530
|
name: "payslip_statement_t4",
|
|
8548
8531
|
displayName: "Payslip Statement (Month T-4)",
|
|
8549
8532
|
type: "file",
|
|
8550
|
-
enableIf: "{formOfDisclosure} contains 'consented'",
|
|
8551
8533
|
ihs_column_names: [
|
|
8552
8534
|
"payslipEmployerNameT4",
|
|
8553
8535
|
"payslipEmployeeNameT4",
|
|
@@ -8571,7 +8553,6 @@ var form_field_base_specs_default = {
|
|
|
8571
8553
|
name: "payslip_statement_t5",
|
|
8572
8554
|
displayName: "Payslip Statement (Month T-5)",
|
|
8573
8555
|
type: "file",
|
|
8574
|
-
enableIf: "{formOfDisclosure} contains 'consented'",
|
|
8575
8556
|
ihs_column_names: [
|
|
8576
8557
|
"payslipEmployerNameT5",
|
|
8577
8558
|
"payslipEmployeeNameT5",
|
|
@@ -8595,7 +8576,6 @@ var form_field_base_specs_default = {
|
|
|
8595
8576
|
name: "payslip_statement_t6",
|
|
8596
8577
|
displayName: "Payslip Statement (Month T-6)",
|
|
8597
8578
|
type: "file",
|
|
8598
|
-
enableIf: "{formOfDisclosure} contains 'consented'",
|
|
8599
8579
|
ihs_column_names: [
|
|
8600
8580
|
"payslipEmployerNameT6",
|
|
8601
8581
|
"payslipEmployeeNameT6",
|
|
@@ -9402,18 +9382,18 @@ function buildTableForGroup(groupName, fields, ihsData) {
|
|
|
9402
9382
|
const items = [];
|
|
9403
9383
|
for (const [baseName, periodMap] of Object.entries(columnGroups)) {
|
|
9404
9384
|
const numeric = isNumericField(baseName);
|
|
9405
|
-
const
|
|
9385
|
+
const data2 = {};
|
|
9406
9386
|
const formattedData = {};
|
|
9407
9387
|
for (const period of periods) {
|
|
9408
9388
|
const colName = periodMap[period];
|
|
9409
9389
|
const value = colName ? ihsData[colName] ?? null : null;
|
|
9410
|
-
|
|
9390
|
+
data2[period] = value;
|
|
9411
9391
|
formattedData[period] = formatValue(value, numeric);
|
|
9412
9392
|
}
|
|
9413
9393
|
items.push({
|
|
9414
9394
|
displayName: getDisplayName(baseName),
|
|
9415
9395
|
timePeriods: periods,
|
|
9416
|
-
data,
|
|
9396
|
+
data: data2,
|
|
9417
9397
|
formattedData,
|
|
9418
9398
|
type: tableType,
|
|
9419
9399
|
isNumeric: numeric
|
|
@@ -9770,7 +9750,253 @@ function resolveExtractionStatus(ihsRecord, jobRecords) {
|
|
|
9770
9750
|
);
|
|
9771
9751
|
return { documents, summary };
|
|
9772
9752
|
}
|
|
9753
|
+
|
|
9754
|
+
// src/adapter.ts
|
|
9755
|
+
var AdapterError = class extends Error {
|
|
9756
|
+
constructor(reason, message, cause) {
|
|
9757
|
+
super(message);
|
|
9758
|
+
this.name = "AdapterError";
|
|
9759
|
+
this.reason = reason;
|
|
9760
|
+
this.cause = cause;
|
|
9761
|
+
}
|
|
9762
|
+
};
|
|
9763
|
+
|
|
9764
|
+
// src/adapter-aggregation.ts
|
|
9765
|
+
var ALL_AGGREGATION_OPS = [
|
|
9766
|
+
"sum",
|
|
9767
|
+
"mean",
|
|
9768
|
+
"latest",
|
|
9769
|
+
"max",
|
|
9770
|
+
"count"
|
|
9771
|
+
];
|
|
9772
|
+
function applyAggregation(op, instances) {
|
|
9773
|
+
if (instances.length === 0) {
|
|
9774
|
+
return op === "count" ? 0 : null;
|
|
9775
|
+
}
|
|
9776
|
+
if (op === "count") {
|
|
9777
|
+
return instances.reduce(
|
|
9778
|
+
(acc, i) => i.value !== null && i.value !== void 0 ? acc + 1 : acc,
|
|
9779
|
+
0
|
|
9780
|
+
);
|
|
9781
|
+
}
|
|
9782
|
+
if (op === "latest") {
|
|
9783
|
+
let pick = instances[0];
|
|
9784
|
+
for (let i = 1; i < instances.length; i++) {
|
|
9785
|
+
if (instances[i].observedAt > pick.observedAt) pick = instances[i];
|
|
9786
|
+
}
|
|
9787
|
+
return pick.value;
|
|
9788
|
+
}
|
|
9789
|
+
const nums = [];
|
|
9790
|
+
for (const i of instances) {
|
|
9791
|
+
if (typeof i.value === "number" && Number.isFinite(i.value)) {
|
|
9792
|
+
nums.push(i.value);
|
|
9793
|
+
} else if (i.value !== null && typeof i.value !== "undefined") {
|
|
9794
|
+
throw new Error(
|
|
9795
|
+
`applyAggregation: '${op}' requires numeric values; got ${typeof i.value}`
|
|
9796
|
+
);
|
|
9797
|
+
}
|
|
9798
|
+
}
|
|
9799
|
+
if (nums.length === 0) return null;
|
|
9800
|
+
switch (op) {
|
|
9801
|
+
case "sum":
|
|
9802
|
+
return nums.reduce((a, b) => a + b, 0);
|
|
9803
|
+
case "mean":
|
|
9804
|
+
return nums.reduce((a, b) => a + b, 0) / nums.length;
|
|
9805
|
+
case "max":
|
|
9806
|
+
return nums.reduce((a, b) => a > b ? a : b);
|
|
9807
|
+
}
|
|
9808
|
+
}
|
|
9809
|
+
|
|
9810
|
+
// src/data/adapter-categories.json
|
|
9811
|
+
var adapter_categories_default = {
|
|
9812
|
+
schemaVersion: "1.0.0",
|
|
9813
|
+
categories: [
|
|
9814
|
+
{
|
|
9815
|
+
id: "telco-carrier",
|
|
9816
|
+
displayName: "Telco Carrier",
|
|
9817
|
+
description: "Mobile carrier bill-payment + account-history signals. Any telco vendor (Celcom, Maxis, DiGi, U-Mobile, etc.) implementing this category produces the same canonical field set.",
|
|
9818
|
+
canonicalTable: "ihs_alt_data_telco",
|
|
9819
|
+
fields: [
|
|
9820
|
+
{
|
|
9821
|
+
name: "telcoOnTimePaymentRatio24m",
|
|
9822
|
+
type: "number",
|
|
9823
|
+
unit: "ratio",
|
|
9824
|
+
range: [0, 1],
|
|
9825
|
+
description: "Fraction of bills paid on time over the last 24 months. Strongest single telco predictor; \u22650.95 is the clean-history signal."
|
|
9826
|
+
},
|
|
9827
|
+
{
|
|
9828
|
+
name: "telcoTenureMonths",
|
|
9829
|
+
type: "number",
|
|
9830
|
+
unit: "months",
|
|
9831
|
+
range: [0, 600],
|
|
9832
|
+
description: "Account age. \u226548 months is the thin-file uplift trigger."
|
|
9833
|
+
},
|
|
9834
|
+
{
|
|
9835
|
+
name: "telcoSuspensionsCount24m",
|
|
9836
|
+
type: "number",
|
|
9837
|
+
unit: "count",
|
|
9838
|
+
range: [0, 100],
|
|
9839
|
+
description: "Non-payment-driven account suspensions in the last 24 months. \u22653 is a strong distress signal."
|
|
9840
|
+
},
|
|
9841
|
+
{
|
|
9842
|
+
name: "telcoLateDays24m",
|
|
9843
|
+
type: "number",
|
|
9844
|
+
unit: "days",
|
|
9845
|
+
range: [0, 800],
|
|
9846
|
+
description: "Cumulative days late across all bills in the trailing 24-month window."
|
|
9847
|
+
},
|
|
9848
|
+
{
|
|
9849
|
+
name: "telcoHandsetFinancingActive",
|
|
9850
|
+
type: "boolean",
|
|
9851
|
+
description: "Has an active handset-EMI account currently. Proxy for financing capacity already extended."
|
|
9852
|
+
},
|
|
9853
|
+
{
|
|
9854
|
+
name: "telcoHandsetFinancingDelinquent",
|
|
9855
|
+
type: "boolean",
|
|
9856
|
+
description: "Recent handset-EMI delinquency in the last 24 months. Distress signal even with otherwise clean bill payment."
|
|
9857
|
+
},
|
|
9858
|
+
{
|
|
9859
|
+
name: "telcoArpuMyr",
|
|
9860
|
+
type: "number",
|
|
9861
|
+
unit: "MYR",
|
|
9862
|
+
range: [0, 1e4],
|
|
9863
|
+
description: "Average Revenue Per User (monthly) in Malaysian Ringgit. Coarse spending-capacity proxy."
|
|
9864
|
+
}
|
|
9865
|
+
]
|
|
9866
|
+
},
|
|
9867
|
+
{
|
|
9868
|
+
id: "payment-network",
|
|
9869
|
+
displayName: "Payment Network",
|
|
9870
|
+
description: "Merchant-side payment-flow signals from POS / gateway networks (iPay88, GHL, etc.). Captures actual transaction velocity rather than self-reported revenue.",
|
|
9871
|
+
canonicalTable: "ihs_alt_data_payments",
|
|
9872
|
+
fields: [
|
|
9873
|
+
{
|
|
9874
|
+
name: "paymentsMonthlyVolumeMyrT3",
|
|
9875
|
+
type: "number",
|
|
9876
|
+
unit: "MYR",
|
|
9877
|
+
range: [0, 1e8],
|
|
9878
|
+
description: "Mean monthly inbound transaction volume (RM) over the trailing 3 months."
|
|
9879
|
+
},
|
|
9880
|
+
{
|
|
9881
|
+
name: "paymentsMonthlyVolumeMyrT12",
|
|
9882
|
+
type: "number",
|
|
9883
|
+
unit: "MYR",
|
|
9884
|
+
range: [0, 1e8],
|
|
9885
|
+
description: "Mean monthly inbound transaction volume (RM) over the trailing 12 months. Pair with T3 for trend direction."
|
|
9886
|
+
},
|
|
9887
|
+
{
|
|
9888
|
+
name: "paymentsArpuStability12m",
|
|
9889
|
+
type: "number",
|
|
9890
|
+
unit: "ratio",
|
|
9891
|
+
range: [0, 1],
|
|
9892
|
+
description: "Coefficient-of-variation inverse over monthly ARPU in the trailing 12 months. Closer to 1 = steadier; closer to 0 = volatile."
|
|
9893
|
+
},
|
|
9894
|
+
{
|
|
9895
|
+
name: "paymentsDisputeRate12m",
|
|
9896
|
+
type: "number",
|
|
9897
|
+
unit: "ratio",
|
|
9898
|
+
range: [0, 1],
|
|
9899
|
+
description: "Fraction of transactions disputed or refunded in the trailing 12 months."
|
|
9900
|
+
},
|
|
9901
|
+
{
|
|
9902
|
+
name: "paymentsCustomerConcentrationTop5Pct",
|
|
9903
|
+
type: "number",
|
|
9904
|
+
unit: "ratio",
|
|
9905
|
+
range: [0, 1],
|
|
9906
|
+
description: "Revenue share from the top-5 recurring customers. Above ~0.7 is concentration risk."
|
|
9907
|
+
},
|
|
9908
|
+
{
|
|
9909
|
+
name: "paymentsActiveTenureMonths",
|
|
9910
|
+
type: "number",
|
|
9911
|
+
unit: "months",
|
|
9912
|
+
range: [0, 600],
|
|
9913
|
+
description: "Months since first transaction on the payment network. Establishment / continuity proxy."
|
|
9914
|
+
}
|
|
9915
|
+
]
|
|
9916
|
+
},
|
|
9917
|
+
{
|
|
9918
|
+
id: "bank-statement",
|
|
9919
|
+
displayName: "Bank Statement",
|
|
9920
|
+
description: "Per-month bank-statement extractions. Naturally multi-instance: one statement per (account, month). Eval components typically aggregate across instances (sum closing balance, max debit, count of bounced transactions).",
|
|
9921
|
+
canonicalTable: "ihs_alt_data_bank_statements",
|
|
9922
|
+
fields: [
|
|
9923
|
+
{
|
|
9924
|
+
name: "bankStatementMonth",
|
|
9925
|
+
type: "string",
|
|
9926
|
+
description: "Statement period in YYYY-MM format. Used as the instance_key discriminator + by the `latest` aggregation operator."
|
|
9927
|
+
},
|
|
9928
|
+
{
|
|
9929
|
+
name: "bankClosingBalanceMyr",
|
|
9930
|
+
type: "number",
|
|
9931
|
+
unit: "MYR",
|
|
9932
|
+
range: [-1e8, 1e8],
|
|
9933
|
+
description: "Closing balance for the statement period."
|
|
9934
|
+
},
|
|
9935
|
+
{
|
|
9936
|
+
name: "bankTotalCreditsMyr",
|
|
9937
|
+
type: "number",
|
|
9938
|
+
unit: "MYR",
|
|
9939
|
+
range: [0, 1e8],
|
|
9940
|
+
description: "Sum of credit transactions during the period."
|
|
9941
|
+
},
|
|
9942
|
+
{
|
|
9943
|
+
name: "bankTotalDebitsMyr",
|
|
9944
|
+
type: "number",
|
|
9945
|
+
unit: "MYR",
|
|
9946
|
+
range: [0, 1e8],
|
|
9947
|
+
description: "Sum of debit transactions during the period."
|
|
9948
|
+
},
|
|
9949
|
+
{
|
|
9950
|
+
name: "bankLargestSingleCreditMyr",
|
|
9951
|
+
type: "number",
|
|
9952
|
+
unit: "MYR",
|
|
9953
|
+
range: [0, 1e8],
|
|
9954
|
+
description: "Largest single inbound transaction in the period. Useful for spotting one-off injections vs steady revenue."
|
|
9955
|
+
},
|
|
9956
|
+
{
|
|
9957
|
+
name: "bankBouncedTransactionsCount",
|
|
9958
|
+
type: "number",
|
|
9959
|
+
unit: "count",
|
|
9960
|
+
range: [0, 1e3],
|
|
9961
|
+
description: "Bounced / returned transactions in the period. Distress signal at counts > 0."
|
|
9962
|
+
}
|
|
9963
|
+
]
|
|
9964
|
+
}
|
|
9965
|
+
]
|
|
9966
|
+
};
|
|
9967
|
+
|
|
9968
|
+
// src/adapter-categories.ts
|
|
9969
|
+
var data = adapter_categories_default;
|
|
9970
|
+
function categorySchemaOf(id) {
|
|
9971
|
+
const found = data.categories.find((c) => c.id === id);
|
|
9972
|
+
if (!found) {
|
|
9973
|
+
throw new Error(
|
|
9974
|
+
`Unknown adapter category: ${id}. Available: ${data.categories.map((c) => c.id).join(", ")}`
|
|
9975
|
+
);
|
|
9976
|
+
}
|
|
9977
|
+
return found;
|
|
9978
|
+
}
|
|
9979
|
+
function categoryFieldsOf(id) {
|
|
9980
|
+
return categorySchemaOf(id).fields.map((f) => f.name);
|
|
9981
|
+
}
|
|
9982
|
+
function allCategories() {
|
|
9983
|
+
return data.categories;
|
|
9984
|
+
}
|
|
9985
|
+
var fieldToCategory = (() => {
|
|
9986
|
+
const m = /* @__PURE__ */ new Map();
|
|
9987
|
+
for (const cat of data.categories) {
|
|
9988
|
+
for (const f of cat.fields) {
|
|
9989
|
+
m.set(f.name, cat.id);
|
|
9990
|
+
}
|
|
9991
|
+
}
|
|
9992
|
+
return m;
|
|
9993
|
+
})();
|
|
9994
|
+
function categoryForField(field) {
|
|
9995
|
+
return fieldToCategory.get(field) ?? null;
|
|
9996
|
+
}
|
|
9773
9997
|
export {
|
|
9998
|
+
ALL_AGGREGATION_OPS,
|
|
9999
|
+
AdapterError,
|
|
9774
10000
|
BASE_FIELD_SPECS,
|
|
9775
10001
|
BasicFormField,
|
|
9776
10002
|
DEFAULT_VALIDATOR_DEFINITIONS,
|
|
@@ -9791,8 +10017,13 @@ export {
|
|
|
9791
10017
|
IhsStatus,
|
|
9792
10018
|
IhsValueFormat,
|
|
9793
10019
|
Role,
|
|
10020
|
+
allCategories,
|
|
10021
|
+
applyAggregation,
|
|
9794
10022
|
applyDynamicTitles,
|
|
9795
10023
|
buildFileFieldTables,
|
|
10024
|
+
categoryFieldsOf,
|
|
10025
|
+
categoryForField,
|
|
10026
|
+
categorySchemaOf,
|
|
9796
10027
|
evaluateExpression,
|
|
9797
10028
|
extractTimePeriods,
|
|
9798
10029
|
generateRHFSchema,
|