@finsys/core 2.7.0 → 3.2.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 +1 -1
- package/dist/data/adapter-categories.json +235 -2
- package/dist/index.cjs +375 -32
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +44 -22
- package/dist/index.d.ts +44 -22
- package/dist/index.js +372 -32
- package/dist/index.js.map +1 -1
- package/dist/schema/adapter-manifest.schema.json +2 -2
- package/package.json +9 -2
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
The shared contract layer for the FinSys ecosystem. Two distinct surfaces:
|
|
4
4
|
|
|
5
5
|
1. **Unified form configuration** — generate Zod schemas, React Hook Form defaults, and SurveyJS JSON from a single JSON form spec.
|
|
6
|
-
2. **Source Adapter Framework** — vendor-agnostic contract for ingesting alternative-data sources (telco, payments, bank statements, etc.) into FinSys's canonical credit-signal vocabulary.
|
|
6
|
+
2. **Source Adapter Framework** — vendor-agnostic contract for ingesting alternative-data sources (telco, payments, bank statements, social-media presence, etc.) into FinSys's canonical credit-signal vocabulary. Categories are a runtime registry loaded from a single data file (see [Category Reference](./docs/category-reference.md)).
|
|
7
7
|
|
|
8
8
|
## Building a Source Adapter?
|
|
9
9
|
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
{
|
|
5
5
|
"id": "telco-carrier",
|
|
6
6
|
"displayName": "Telco Carrier",
|
|
7
|
-
"description": "Mobile carrier bill-payment + account-history signals. Any
|
|
7
|
+
"description": "Mobile carrier bill-payment + account-history signals. Any mobile carrier implementing this category produces the same canonical field set.",
|
|
8
8
|
"canonicalTable": "ihs_alt_data_telco",
|
|
9
9
|
"fields": [
|
|
10
10
|
{
|
|
@@ -57,7 +57,7 @@
|
|
|
57
57
|
{
|
|
58
58
|
"id": "payment-network",
|
|
59
59
|
"displayName": "Payment Network",
|
|
60
|
-
"description": "Merchant-side payment-flow signals from POS / gateway networks
|
|
60
|
+
"description": "Merchant-side payment-flow signals from POS / payment-gateway networks. Captures actual transaction velocity rather than self-reported revenue.",
|
|
61
61
|
"canonicalTable": "ihs_alt_data_payments",
|
|
62
62
|
"fields": [
|
|
63
63
|
{
|
|
@@ -151,6 +151,239 @@
|
|
|
151
151
|
"description": "Bounced / returned transactions in the period. Distress signal at counts > 0."
|
|
152
152
|
}
|
|
153
153
|
]
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
"id": "social-media",
|
|
157
|
+
"displayName": "Social Media Presence",
|
|
158
|
+
"description": "Public business-presence signals from social / commerce platforms — establishment, reach, engagement authenticity, customer reputation, and account standing. Vendor-agnostic: any platform exposing a public business profile maps its data to this canonical field set. Useful as thin-file corroboration of a borrower's operating reality where formal financials are sparse.",
|
|
159
|
+
"canonicalTable": "ihs_alt_data_social_media",
|
|
160
|
+
"fields": [
|
|
161
|
+
{
|
|
162
|
+
"name": "socialAccountTenureMonths",
|
|
163
|
+
"type": "number",
|
|
164
|
+
"unit": "months",
|
|
165
|
+
"range": [0, 600],
|
|
166
|
+
"description": "Age of the oldest verified public business presence across linked profiles. Establishment / continuity proxy, parallel to telco + payment-network tenure."
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
"name": "socialFollowerCount",
|
|
170
|
+
"type": "number",
|
|
171
|
+
"unit": "count",
|
|
172
|
+
"range": [0, 100000000],
|
|
173
|
+
"description": "Aggregate audience size across linked public profiles. Coarse reach / scale proxy — gameable on its own, so read alongside socialEngagementRate90d."
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
"name": "socialEngagementRate90d",
|
|
177
|
+
"type": "number",
|
|
178
|
+
"unit": "ratio",
|
|
179
|
+
"range": [0, 1],
|
|
180
|
+
"description": "Mean interactions per impression over the trailing 90 days. Authenticity signal: a large follower count with near-zero engagement indicates a bought or dormant audience."
|
|
181
|
+
},
|
|
182
|
+
{
|
|
183
|
+
"name": "socialPostingConsistency12m",
|
|
184
|
+
"type": "number",
|
|
185
|
+
"unit": "ratio",
|
|
186
|
+
"range": [0, 1],
|
|
187
|
+
"description": "Fraction of weeks in the trailing 12 months with at least one public post. Ongoing-operation signal — distinguishes an active business from a stale listing."
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
"name": "socialVerifiedBusinessAccount",
|
|
191
|
+
"type": "boolean",
|
|
192
|
+
"description": "Has at least one platform-verified business / commerce profile. Legitimacy signal — the platform has performed its own business-identity check."
|
|
193
|
+
},
|
|
194
|
+
{
|
|
195
|
+
"name": "socialCustomerRatingAvg",
|
|
196
|
+
"type": "number",
|
|
197
|
+
"unit": "rating",
|
|
198
|
+
"range": [0, 5],
|
|
199
|
+
"description": "Mean public customer rating (normalised to a 0–5 scale) across review-bearing profiles. Reputation signal; especially predictive for consumer-facing SMEs."
|
|
200
|
+
},
|
|
201
|
+
{
|
|
202
|
+
"name": "socialNegativeSentimentRatio90d",
|
|
203
|
+
"type": "number",
|
|
204
|
+
"unit": "ratio",
|
|
205
|
+
"range": [0, 1],
|
|
206
|
+
"description": "Fraction of public mentions / reviews classified as negative over the trailing 90 days. Reputation-risk / distress signal independent of overall rating volume."
|
|
207
|
+
},
|
|
208
|
+
{
|
|
209
|
+
"name": "socialAccountFlags24m",
|
|
210
|
+
"type": "number",
|
|
211
|
+
"unit": "count",
|
|
212
|
+
"range": [0, 100],
|
|
213
|
+
"description": "Policy strikes, suspensions, or content takedowns across linked profiles in the last 24 months. Distress signal, parallel to telcoSuspensionsCount24m."
|
|
214
|
+
}
|
|
215
|
+
]
|
|
216
|
+
},
|
|
217
|
+
{
|
|
218
|
+
"id": "trade-credit",
|
|
219
|
+
"displayName": "Trade Credit (Accounting)",
|
|
220
|
+
"description": "Accounts-receivable / accounts-payable aging and ledger-derived working-capital signals sourced from a business's accounting / ERP system. Captures how promptly the business collects from its debtors and pays its creditors, the aging profile and concentration of its receivables, and P&L / cash-conversion efficiency. Vendor-agnostic: any accounting or ERP system that exposes an AR/AP aging report plus a P&L summary maps its data to this canonical field set. A direct, high-signal view of trade-obligation behaviour — closer to formal credit history than most alternative data — and the anchor for cross-referencing self-reported accounting figures against bank-statement reality.",
|
|
221
|
+
"canonicalTable": "ihs_alt_data_trade_credit",
|
|
222
|
+
"fields": [
|
|
223
|
+
{
|
|
224
|
+
"name": "arDaysSalesOutstanding",
|
|
225
|
+
"type": "number",
|
|
226
|
+
"unit": "days",
|
|
227
|
+
"range": [0, 400],
|
|
228
|
+
"description": "Days Sales Outstanding — average days to collect a receivable. The headline collection-efficiency metric; lower is healthier, and a rising DSO is an early liquidity-stress signal."
|
|
229
|
+
},
|
|
230
|
+
{
|
|
231
|
+
"name": "apDaysPayableOutstanding",
|
|
232
|
+
"type": "number",
|
|
233
|
+
"unit": "days",
|
|
234
|
+
"range": [0, 400],
|
|
235
|
+
"description": "Days Payable Outstanding — average days the business takes to pay its suppliers. Context for DSO; a very high DPO can indicate the business is stretching its creditors to fund operations."
|
|
236
|
+
},
|
|
237
|
+
{
|
|
238
|
+
"name": "arTotalOutstandingMyr",
|
|
239
|
+
"type": "number",
|
|
240
|
+
"unit": "MYR",
|
|
241
|
+
"range": [0, 1000000000],
|
|
242
|
+
"description": "Total accounts-receivable balance outstanding (RM). The size of the debtor book the business is carrying."
|
|
243
|
+
},
|
|
244
|
+
{
|
|
245
|
+
"name": "arCurrentRatio",
|
|
246
|
+
"type": "number",
|
|
247
|
+
"unit": "ratio",
|
|
248
|
+
"range": [0, 1],
|
|
249
|
+
"description": "Fraction of the receivables book that is current (within payment terms, not yet overdue). Higher is healthier; the complement is the overdue share across all aging buckets."
|
|
250
|
+
},
|
|
251
|
+
{
|
|
252
|
+
"name": "arOverdue90PlusRatio",
|
|
253
|
+
"type": "number",
|
|
254
|
+
"unit": "ratio",
|
|
255
|
+
"range": [0, 1],
|
|
256
|
+
"description": "Fraction of the receivables book aged more than 90 days past terms. The key impairment / bad-debt risk signal from the AR aging report; elevated values indicate collection difficulty."
|
|
257
|
+
},
|
|
258
|
+
{
|
|
259
|
+
"name": "debtorConcentrationTop5Ratio",
|
|
260
|
+
"type": "number",
|
|
261
|
+
"unit": "ratio",
|
|
262
|
+
"range": [0, 1],
|
|
263
|
+
"description": "Share of total receivables owed by the top-5 debtors. Above ~0.6 is single-customer concentration risk — one debtor default would materially impair cash flow."
|
|
264
|
+
},
|
|
265
|
+
{
|
|
266
|
+
"name": "tradeReferenceDefaults12m",
|
|
267
|
+
"type": "number",
|
|
268
|
+
"unit": "count",
|
|
269
|
+
"range": [0, 1000],
|
|
270
|
+
"description": "Count of supplier-reported defaults or dishonoured / returned payments against the business in the trailing 12 months. Direct distress signal, parallel to a bureau default record."
|
|
271
|
+
},
|
|
272
|
+
{
|
|
273
|
+
"name": "accountingRevenue12mMyr",
|
|
274
|
+
"type": "number",
|
|
275
|
+
"unit": "MYR",
|
|
276
|
+
"range": [0, 1000000000],
|
|
277
|
+
"description": "Trailing-12-month turnover per the general ledger (RM). The cross-reference anchor: comparing this self-reported accounting revenue against payment-network volume and bank-statement inflows surfaces book-vs-reality inconsistencies."
|
|
278
|
+
},
|
|
279
|
+
{
|
|
280
|
+
"name": "grossMarginPct",
|
|
281
|
+
"type": "number",
|
|
282
|
+
"unit": "ratio",
|
|
283
|
+
"range": [0, 1],
|
|
284
|
+
"description": "Gross margin from the P&L (gross profit / revenue). Profitability-quality signal; a thin or declining margin constrains debt-service capacity even at healthy revenue."
|
|
285
|
+
},
|
|
286
|
+
{
|
|
287
|
+
"name": "cashConversionCycleDays",
|
|
288
|
+
"type": "number",
|
|
289
|
+
"unit": "days",
|
|
290
|
+
"range": [-200, 600],
|
|
291
|
+
"description": "Cash Conversion Cycle (DSO + days-inventory-outstanding − DPO). Working-capital efficiency; negative values (collect before paying suppliers) are strongest, very high values indicate cash tied up in operations."
|
|
292
|
+
}
|
|
293
|
+
]
|
|
294
|
+
},
|
|
295
|
+
{
|
|
296
|
+
"id": "geolocation",
|
|
297
|
+
"displayName": "Geolocation",
|
|
298
|
+
"description": "Hourly-granularity movement track plus derived mobility signals for an applicant, sourced from any location-capable provider (telco network location, mobile-SDK GPS, GIS / address-verification services). Two instance kinds share this category: point instances (instanceKey 'pt:<ISO-hour>') carry one observed position per hourly bucket, mirroring the bank-statement multi-instance pattern; a single summary instance (instanceKey 'summary') carries adapter-derived behaviour signals — most importantly work-pattern regularity (sustained weekday dwell at a stable work anchor corroborates income reliability), residential stability, vacation windows, and dwell in operator-flagged hotspot zones. Vendor-agnostic: the source classifies or the adapter infers place labels; no provider-specific semantics leak into the field set. Raw coordinates are sensitive personal data — product-plane persistence is gated on PDPA consent + CRA Act 710 s25 retention review.",
|
|
299
|
+
"canonicalTable": "ihs_alt_data_geolocation",
|
|
300
|
+
"fields": [
|
|
301
|
+
{
|
|
302
|
+
"name": "geoLatitude",
|
|
303
|
+
"type": "number",
|
|
304
|
+
"unit": "deg",
|
|
305
|
+
"range": [-90, 90],
|
|
306
|
+
"description": "Observed latitude for this hourly bucket (point instances only)."
|
|
307
|
+
},
|
|
308
|
+
{
|
|
309
|
+
"name": "geoLongitude",
|
|
310
|
+
"type": "number",
|
|
311
|
+
"unit": "deg",
|
|
312
|
+
"range": [-180, 180],
|
|
313
|
+
"description": "Observed longitude for this hourly bucket (point instances only)."
|
|
314
|
+
},
|
|
315
|
+
{
|
|
316
|
+
"name": "geoAccuracyM",
|
|
317
|
+
"type": "number",
|
|
318
|
+
"unit": "meters",
|
|
319
|
+
"range": [0, 100000],
|
|
320
|
+
"description": "Source-reported horizontal accuracy radius of the observation. Cell-tower fixes are typically hundreds of meters; GPS fixes tens."
|
|
321
|
+
},
|
|
322
|
+
{
|
|
323
|
+
"name": "geoBucket",
|
|
324
|
+
"type": "string",
|
|
325
|
+
"description": "ISO-8601 hour bucket of the observation, e.g. '2026-06-01T08'. Redundant with the instance key (pt:<bucket>) so consumers can query without parsing keys."
|
|
326
|
+
},
|
|
327
|
+
{
|
|
328
|
+
"name": "geoPlaceLabel",
|
|
329
|
+
"type": "string",
|
|
330
|
+
"description": "Classified place for the bucket: home | work | commute | leisure | travel | hotspot | other. Classified by the source or inferred by the adapter from anchor dwell."
|
|
331
|
+
},
|
|
332
|
+
{
|
|
333
|
+
"name": "geoWorkAttendanceRatio30d",
|
|
334
|
+
"type": "number",
|
|
335
|
+
"unit": "ratio",
|
|
336
|
+
"range": [0, 1],
|
|
337
|
+
"description": "Fraction of the last 30 weekdays with >= 6 hours of dwell at the inferred work anchor. The income-reliability headline: regular full-time work patterns corroborate declared employment income (summary instance only)."
|
|
338
|
+
},
|
|
339
|
+
{
|
|
340
|
+
"name": "geoWorkDailyHoursAvg30d",
|
|
341
|
+
"type": "number",
|
|
342
|
+
"unit": "hours",
|
|
343
|
+
"range": [0, 24],
|
|
344
|
+
"description": "Mean daily hours of work-anchor dwell across the last 30 weekdays (summary instance only)."
|
|
345
|
+
},
|
|
346
|
+
{
|
|
347
|
+
"name": "geoLocationStabilityScore",
|
|
348
|
+
"type": "number",
|
|
349
|
+
"unit": "score",
|
|
350
|
+
"range": [0, 1],
|
|
351
|
+
"description": "Residential stability: share of nights spent at the primary home anchor over the observation window. 1 = every night at home (summary instance only)."
|
|
352
|
+
},
|
|
353
|
+
{
|
|
354
|
+
"name": "geoCommuteRegularityRatio",
|
|
355
|
+
"type": "number",
|
|
356
|
+
"unit": "ratio",
|
|
357
|
+
"range": [0, 1],
|
|
358
|
+
"description": "Consistency of the weekday home->work->home rhythm: fraction of weekdays matching the dominant commute pattern within an hour's tolerance (summary instance only)."
|
|
359
|
+
},
|
|
360
|
+
{
|
|
361
|
+
"name": "geoVacationDays90d",
|
|
362
|
+
"type": "number",
|
|
363
|
+
"unit": "days",
|
|
364
|
+
"range": [0, 90],
|
|
365
|
+
"description": "Days in the last 90 spent fully away from both home and work anchors (contiguous travel windows; summary instance only)."
|
|
366
|
+
},
|
|
367
|
+
{
|
|
368
|
+
"name": "geoHotspotDwellRatio",
|
|
369
|
+
"type": "number",
|
|
370
|
+
"unit": "ratio",
|
|
371
|
+
"range": [0, 1],
|
|
372
|
+
"description": "Share of observed buckets spent inside operator-flagged hotspot zones (known fraud / illicit-activity locations supplied to the adapter). Non-zero values warrant review, not automatic decline (summary instance only)."
|
|
373
|
+
},
|
|
374
|
+
{
|
|
375
|
+
"name": "geoPrimaryStateCode",
|
|
376
|
+
"type": "string",
|
|
377
|
+
"description": "Malaysian state / federal-territory code of the primary home anchor, e.g. PNG, KUL, JHR (summary instance only)."
|
|
378
|
+
},
|
|
379
|
+
{
|
|
380
|
+
"name": "geoAddressMatchScore",
|
|
381
|
+
"type": "number",
|
|
382
|
+
"unit": "score",
|
|
383
|
+
"range": [0, 1],
|
|
384
|
+
"description": "Agreement between the inferred home anchor and the applicant's registered residential address. 1 = same premises, 0 = different state (summary instance only)."
|
|
385
|
+
}
|
|
386
|
+
]
|
|
154
387
|
}
|
|
155
388
|
]
|
|
156
389
|
}
|