arc-1 0.6.9 → 0.6.10
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 +6 -4
- package/dist/adt/abapgit.d.ts +39 -0
- package/dist/adt/abapgit.d.ts.map +1 -0
- package/dist/adt/abapgit.js +333 -0
- package/dist/adt/abapgit.js.map +1 -0
- package/dist/adt/config.d.ts +1 -0
- package/dist/adt/config.d.ts.map +1 -1
- package/dist/adt/config.js +1 -0
- package/dist/adt/config.js.map +1 -1
- package/dist/adt/crud.d.ts.map +1 -1
- package/dist/adt/crud.js +42 -3
- package/dist/adt/crud.js.map +1 -1
- package/dist/adt/errors.d.ts +22 -1
- package/dist/adt/errors.d.ts.map +1 -1
- package/dist/adt/errors.js +71 -2
- package/dist/adt/errors.js.map +1 -1
- package/dist/adt/features.d.ts.map +1 -1
- package/dist/adt/features.js +3 -0
- package/dist/adt/features.js.map +1 -1
- package/dist/adt/gcts.d.ts +68 -0
- package/dist/adt/gcts.d.ts.map +1 -0
- package/dist/adt/gcts.js +239 -0
- package/dist/adt/gcts.js.map +1 -0
- package/dist/adt/safety.d.ts +3 -0
- package/dist/adt/safety.d.ts.map +1 -1
- package/dist/adt/safety.js +9 -0
- package/dist/adt/safety.js.map +1 -1
- package/dist/adt/transport.d.ts.map +1 -1
- package/dist/adt/transport.js +4 -1
- package/dist/adt/transport.js.map +1 -1
- package/dist/adt/types.d.ts +137 -0
- package/dist/adt/types.d.ts.map +1 -1
- package/dist/adt/xml-parser.d.ts +2 -0
- package/dist/adt/xml-parser.d.ts.map +1 -1
- package/dist/adt/xml-parser.js +2 -0
- package/dist/adt/xml-parser.js.map +1 -1
- package/dist/handlers/intent.d.ts.map +1 -1
- package/dist/handlers/intent.js +235 -0
- package/dist/handlers/intent.js.map +1 -1
- package/dist/handlers/schemas.d.ts +45 -1
- package/dist/handlers/schemas.d.ts.map +1 -1
- package/dist/handlers/schemas.js +46 -0
- package/dist/handlers/schemas.js.map +1 -1
- package/dist/handlers/tools.d.ts +4 -3
- package/dist/handlers/tools.d.ts.map +1 -1
- package/dist/handlers/tools.js +115 -3
- package/dist/handlers/tools.js.map +1 -1
- package/dist/probe/catalog.d.ts +30 -0
- package/dist/probe/catalog.d.ts.map +1 -0
- package/dist/probe/catalog.js +196 -0
- package/dist/probe/catalog.js.map +1 -0
- package/dist/probe/fixtures.d.ts +54 -0
- package/dist/probe/fixtures.d.ts.map +1 -0
- package/dist/probe/fixtures.js +94 -0
- package/dist/probe/fixtures.js.map +1 -0
- package/dist/probe/format.d.ts +10 -0
- package/dist/probe/format.d.ts.map +1 -0
- package/dist/probe/format.js +114 -0
- package/dist/probe/format.js.map +1 -0
- package/dist/probe/quality.d.ts +13 -0
- package/dist/probe/quality.d.ts.map +1 -0
- package/dist/probe/quality.js +50 -0
- package/dist/probe/quality.js.map +1 -0
- package/dist/probe/runner.d.ts +48 -0
- package/dist/probe/runner.d.ts.map +1 -0
- package/dist/probe/runner.js +211 -0
- package/dist/probe/runner.js.map +1 -0
- package/dist/probe/types.d.ts +159 -0
- package/dist/probe/types.d.ts.map +1 -0
- package/dist/probe/types.js +11 -0
- package/dist/probe/types.js.map +1 -0
- package/dist/server/audit.d.ts.map +1 -1
- package/dist/server/audit.js +12 -1
- package/dist/server/audit.js.map +1 -1
- package/dist/server/config.d.ts.map +1 -1
- package/dist/server/config.js +15 -2
- package/dist/server/config.js.map +1 -1
- package/dist/server/server.d.ts +2 -2
- package/dist/server/server.d.ts.map +1 -1
- package/dist/server/server.js +5 -3
- package/dist/server/server.js.map +1 -1
- package/dist/server/types.d.ts +3 -1
- package/dist/server/types.d.ts.map +1 -1
- package/dist/server/types.js +2 -0
- package/dist/server/types.js.map +1 -1
- package/package.json +4 -1
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Catalog of ADT object types that the probe checks.
|
|
3
|
+
*
|
|
4
|
+
* For each type we record:
|
|
5
|
+
* - the collection URL (what /discovery lists)
|
|
6
|
+
* - an object-level URL template for the "known-object" authoritative probe
|
|
7
|
+
* - one or more SAP-shipped objects that should exist on any healthy system
|
|
8
|
+
* - a release floor, derived from public SAP documentation
|
|
9
|
+
*
|
|
10
|
+
* Release floors are deliberately conservative ("this type is known to work
|
|
11
|
+
* at this release or higher") and are used only as a weak tie-breaker signal —
|
|
12
|
+
* they never alone mark a type unavailable. They exist mostly so the
|
|
13
|
+
* `release-below-floor` branch can upgrade a "likely unavailable" verdict
|
|
14
|
+
* to "high confidence", not to invent negatives.
|
|
15
|
+
*
|
|
16
|
+
* Known-object lists: these are SAP-shipped objects the probe reads without
|
|
17
|
+
* side effects. Some types (BDEF, SRVD, DDLX, DCLS) have no universally-shipped
|
|
18
|
+
* object, which is exactly the blind spot the quality metrics surface.
|
|
19
|
+
*/
|
|
20
|
+
/** Build the object URL from a template, url-encoding the name safely. */
|
|
21
|
+
export function buildObjectUrl(template, name) {
|
|
22
|
+
return template.replace('{name}', encodeURIComponent(name));
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Probe catalog. Order matters only for the report display order.
|
|
26
|
+
* Keep grouped by category for reviewability.
|
|
27
|
+
*/
|
|
28
|
+
export const CATALOG = [
|
|
29
|
+
// ─── Core ABAP (available on every release) ─────────────────────────
|
|
30
|
+
{
|
|
31
|
+
type: 'PROG',
|
|
32
|
+
collectionUrl: '/sap/bc/adt/programs/programs',
|
|
33
|
+
objectUrlTemplate: '/sap/bc/adt/programs/programs/{name}/source/main',
|
|
34
|
+
knownObjects: ['SAPMSSY0', 'SAPMSSY1', 'RSPARAM'],
|
|
35
|
+
minRelease: 700,
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
type: 'CLAS',
|
|
39
|
+
collectionUrl: '/sap/bc/adt/oo/classes',
|
|
40
|
+
objectUrlTemplate: '/sap/bc/adt/oo/classes/{name}',
|
|
41
|
+
knownObjects: ['CL_ABAP_TYPEDESCR', 'CL_GUI_FRONTEND_SERVICES'],
|
|
42
|
+
minRelease: 700,
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
type: 'INTF',
|
|
46
|
+
collectionUrl: '/sap/bc/adt/oo/interfaces',
|
|
47
|
+
objectUrlTemplate: '/sap/bc/adt/oo/interfaces/{name}/source/main',
|
|
48
|
+
knownObjects: ['IF_SERIALIZABLE_OBJECT', 'IF_MESSAGE'],
|
|
49
|
+
minRelease: 700,
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
type: 'FUGR',
|
|
53
|
+
collectionUrl: '/sap/bc/adt/functions/groups',
|
|
54
|
+
objectUrlTemplate: '/sap/bc/adt/functions/groups/{name}',
|
|
55
|
+
knownObjects: ['SPOP', 'SUNI'],
|
|
56
|
+
minRelease: 700,
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
type: 'INCL',
|
|
60
|
+
collectionUrl: '/sap/bc/adt/programs/includes',
|
|
61
|
+
objectUrlTemplate: '/sap/bc/adt/programs/includes/{name}/source/main',
|
|
62
|
+
// LSLOGTOP ships on NW 7.50 kernels where RSDBCPRE is not always present
|
|
63
|
+
// (contributed from #162 probe run against SAP_BASIS 750 SP 0031).
|
|
64
|
+
knownObjects: ['RSDBCPRE', 'LSLOGTOP'],
|
|
65
|
+
minRelease: 700,
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
type: 'MSAG',
|
|
69
|
+
collectionUrl: '/sap/bc/adt/messageclass',
|
|
70
|
+
objectUrlTemplate: '/sap/bc/adt/messageclass/{name}',
|
|
71
|
+
knownObjects: ['00', 'SY'],
|
|
72
|
+
minRelease: 700,
|
|
73
|
+
},
|
|
74
|
+
// ─── DDIC (domains/data elements/tables) ────────────────────────────
|
|
75
|
+
{
|
|
76
|
+
type: 'TABL',
|
|
77
|
+
collectionUrl: '/sap/bc/adt/ddic/tables',
|
|
78
|
+
objectUrlTemplate: '/sap/bc/adt/ddic/tables/{name}/source/main',
|
|
79
|
+
knownObjects: ['T000', 'USR01'],
|
|
80
|
+
minRelease: 700,
|
|
81
|
+
note: 'Source endpoint may require SAP_BASIS >= 7.52 on some systems',
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
type: 'VIEW',
|
|
85
|
+
collectionUrl: '/sap/bc/adt/ddic/views',
|
|
86
|
+
objectUrlTemplate: '/sap/bc/adt/ddic/views/{name}/source/main',
|
|
87
|
+
knownObjects: ['V_USR_NAME'],
|
|
88
|
+
minRelease: 700,
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
type: 'STRU',
|
|
92
|
+
collectionUrl: '/sap/bc/adt/ddic/structures',
|
|
93
|
+
objectUrlTemplate: '/sap/bc/adt/ddic/structures/{name}/source/main',
|
|
94
|
+
knownObjects: ['SYST'],
|
|
95
|
+
minRelease: 700,
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
type: 'DOMA',
|
|
99
|
+
collectionUrl: '/sap/bc/adt/ddic/domains',
|
|
100
|
+
objectUrlTemplate: '/sap/bc/adt/ddic/domains/{name}',
|
|
101
|
+
knownObjects: ['ABAP_BOOL', 'MANDT', 'XFELD'],
|
|
102
|
+
minRelease: 700,
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
type: 'DTEL',
|
|
106
|
+
collectionUrl: '/sap/bc/adt/ddic/dataelements',
|
|
107
|
+
objectUrlTemplate: '/sap/bc/adt/ddic/dataelements/{name}',
|
|
108
|
+
knownObjects: ['MANDT', 'SPRAS', 'ERDAT'],
|
|
109
|
+
minRelease: 700,
|
|
110
|
+
},
|
|
111
|
+
// ─── CDS / RAP ──────────────────────────────────────────────────────
|
|
112
|
+
{
|
|
113
|
+
type: 'DDLS',
|
|
114
|
+
collectionUrl: '/sap/bc/adt/ddic/ddl/sources',
|
|
115
|
+
objectUrlTemplate: '/sap/bc/adt/ddic/ddl/sources/{name}/source/main',
|
|
116
|
+
// I_LANGUAGE is SAP-shipped on every release with CDS support (contributed
|
|
117
|
+
// from #162 probe run — fills what was previously a known blind spot).
|
|
118
|
+
knownObjects: ['I_LANGUAGE'],
|
|
119
|
+
minRelease: 740,
|
|
120
|
+
note: 'CDS introduced in 7.40 SP05; full ADT read support from 7.50+',
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
type: 'DCLS',
|
|
124
|
+
collectionUrl: '/sap/bc/adt/acm/dcl/sources',
|
|
125
|
+
objectUrlTemplate: '/sap/bc/adt/acm/dcl/sources/{name}/source/main',
|
|
126
|
+
// P_USER002 is SAP-shipped on NW 7.50+ (contributed from #162 probe run
|
|
127
|
+
// against SAP_BASIS 750 SP 0031). DCLS is available on 750 with a more
|
|
128
|
+
// limited CDS syntax — floor lowered from 751 accordingly.
|
|
129
|
+
knownObjects: ['P_USER002'],
|
|
130
|
+
minRelease: 750,
|
|
131
|
+
note: 'CDS access controls — available on NW 7.50+ with limited syntax vs. newer releases',
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
type: 'DDLX',
|
|
135
|
+
collectionUrl: '/sap/bc/adt/ddic/ddlx/sources',
|
|
136
|
+
objectUrlTemplate: '/sap/bc/adt/ddic/ddlx/sources/{name}/source/main',
|
|
137
|
+
knownObjects: [],
|
|
138
|
+
minRelease: 751,
|
|
139
|
+
note: 'Metadata extensions — no universally-shipped DDLX',
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
type: 'BDEF',
|
|
143
|
+
collectionUrl: '/sap/bc/adt/bo/behaviordefinitions',
|
|
144
|
+
objectUrlTemplate: '/sap/bc/adt/bo/behaviordefinitions/{name}/source/main',
|
|
145
|
+
knownObjects: [],
|
|
146
|
+
minRelease: 754,
|
|
147
|
+
note: 'RAP behavior definitions — no universally-shipped BDEF',
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
type: 'SRVD',
|
|
151
|
+
collectionUrl: '/sap/bc/adt/ddic/srvd/sources',
|
|
152
|
+
objectUrlTemplate: '/sap/bc/adt/ddic/srvd/sources/{name}/source/main',
|
|
153
|
+
knownObjects: [],
|
|
154
|
+
minRelease: 754,
|
|
155
|
+
note: 'Service definitions — no universally-shipped SRVD',
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
type: 'SRVB',
|
|
159
|
+
collectionUrl: '/sap/bc/adt/businessservices/bindings',
|
|
160
|
+
objectUrlTemplate: '/sap/bc/adt/businessservices/bindings/{name}',
|
|
161
|
+
knownObjects: [],
|
|
162
|
+
minRelease: 754,
|
|
163
|
+
note: 'Service bindings — collection URL differs from /ddic/srvb',
|
|
164
|
+
},
|
|
165
|
+
// ─── Authorization & Switch Framework ───────────────────────────────
|
|
166
|
+
{
|
|
167
|
+
type: 'AUTH',
|
|
168
|
+
collectionUrl: '/sap/bc/adt/aps/iam/auth',
|
|
169
|
+
objectUrlTemplate: '/sap/bc/adt/aps/iam/auth/{name}',
|
|
170
|
+
knownObjects: ['ACTVT', 'MANDT'],
|
|
171
|
+
minRelease: 751,
|
|
172
|
+
note: 'Authorization field read — may require newer ICF activation',
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
type: 'FTG2',
|
|
176
|
+
collectionUrl: '/sap/bc/adt/sfw/featuretoggles',
|
|
177
|
+
objectUrlTemplate: '/sap/bc/adt/sfw/featuretoggles/{name}/states',
|
|
178
|
+
knownObjects: [],
|
|
179
|
+
minRelease: 752,
|
|
180
|
+
note: 'Switch Framework feature toggles — no universally-shipped toggle',
|
|
181
|
+
},
|
|
182
|
+
{
|
|
183
|
+
type: 'ENHO',
|
|
184
|
+
collectionUrl: '/sap/bc/adt/enhancements/enhoxhb',
|
|
185
|
+
objectUrlTemplate: '/sap/bc/adt/enhancements/enhoxhb/{name}',
|
|
186
|
+
knownObjects: [],
|
|
187
|
+
minRelease: 702,
|
|
188
|
+
note: 'Enhancement implementations — no universally-shipped ENHO',
|
|
189
|
+
},
|
|
190
|
+
];
|
|
191
|
+
/** Get a catalog entry by type code (case-insensitive). */
|
|
192
|
+
export function getCatalogEntry(type) {
|
|
193
|
+
const upper = type.toUpperCase();
|
|
194
|
+
return CATALOG.find((e) => e.type === upper);
|
|
195
|
+
}
|
|
196
|
+
//# sourceMappingURL=catalog.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"catalog.js","sourceRoot":"","sources":["../../src/probe/catalog.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fixture save / replay infrastructure.
|
|
3
|
+
*
|
|
4
|
+
* The probe's signal classification is pure (src/probe/runner.ts), so we can
|
|
5
|
+
* unit-test every branch by replaying recorded HTTP responses instead of
|
|
6
|
+
* hitting a live system. That also gives users a way to contribute probe
|
|
7
|
+
* results from their own SAP landscape: run `--save-fixtures <dir>`, commit
|
|
8
|
+
* the directory, and CI gains a regression-proof corpus.
|
|
9
|
+
*/
|
|
10
|
+
import type { HttpProbeFn } from './runner.js';
|
|
11
|
+
import type { InstalledProduct } from './types.js';
|
|
12
|
+
/** A single recorded HTTP request/response, stored as JSON on disk. */
|
|
13
|
+
export interface RecordedResponse {
|
|
14
|
+
url: string;
|
|
15
|
+
method: 'GET' | 'HEAD';
|
|
16
|
+
statusCode?: number;
|
|
17
|
+
body?: string;
|
|
18
|
+
networkError?: boolean;
|
|
19
|
+
errorMessage?: string;
|
|
20
|
+
durationMs: number;
|
|
21
|
+
}
|
|
22
|
+
/** Top-level metadata, written once per fixture directory. */
|
|
23
|
+
export interface FixtureMeta {
|
|
24
|
+
baseUrl: string;
|
|
25
|
+
client?: string;
|
|
26
|
+
abapRelease?: string;
|
|
27
|
+
systemType?: 'onprem' | 'btp' | 'unknown';
|
|
28
|
+
/**
|
|
29
|
+
* Full installed-components list. Captured so a replay-test reader can tell
|
|
30
|
+
* apart e.g. plain NW 7.58 from S/4HANA 2023 — SAP_BASIS alone isn't enough.
|
|
31
|
+
* Optional for backward compatibility with earlier fixture files.
|
|
32
|
+
*/
|
|
33
|
+
products?: InstalledProduct[];
|
|
34
|
+
discoveryMapKeys: string[];
|
|
35
|
+
probedAt: string;
|
|
36
|
+
note?: string;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Wrap an existing `HttpProbeFn` so that every request+response is persisted
|
|
40
|
+
* to `<dir>/responses/`. Call `meta.write()` at the end of the probe run to
|
|
41
|
+
* emit the top-level metadata file.
|
|
42
|
+
*/
|
|
43
|
+
export declare function createRecordingFetcher(inner: HttpProbeFn, dir: string): {
|
|
44
|
+
fetcher: HttpProbeFn;
|
|
45
|
+
writeMeta: (meta: FixtureMeta) => void;
|
|
46
|
+
};
|
|
47
|
+
/** Build a replay fetcher that serves from a fixture directory. */
|
|
48
|
+
export declare function createReplayFetcher(dir: string): {
|
|
49
|
+
fetcher: HttpProbeFn;
|
|
50
|
+
meta: FixtureMeta;
|
|
51
|
+
};
|
|
52
|
+
/** Build a discovery-map equivalent from the fixture meta (for runner input). */
|
|
53
|
+
export declare function discoveryMapFromMeta(meta: FixtureMeta): Map<string, string[]>;
|
|
54
|
+
//# sourceMappingURL=fixtures.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fixtures.d.ts","sourceRoot":"","sources":["../../src/probe/fixtures.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,OAAO,KAAK,EAAE,WAAW,EAAoB,MAAM,aAAa,CAAC;AACjE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEnD,uEAAuE;AACvE,MAAM,WAAW,gBAAgB;IAC/B,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,KAAK,GAAG,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,8DAA8D;AAC9D,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,QAAQ,GAAG,KAAK,GAAG,SAAS,CAAC;IAC1C;;;;OAIG;IACH,QAAQ,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAC9B,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAYD;;;;GAIG;AACH,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,WAAW,EAClB,GAAG,EAAE,MAAM,GACV;IAAE,OAAO,EAAE,WAAW,CAAC;IAAC,SAAS,EAAE,CAAC,IAAI,EAAE,WAAW,KAAK,IAAI,CAAA;CAAE,CAwBlE;AAED,mEAAmE;AACnE,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG;IAAE,OAAO,EAAE,WAAW,CAAC;IAAC,IAAI,EAAE,WAAW,CAAA;CAAE,CAuC5F;AAED,iFAAiF;AACjF,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,WAAW,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAI7E"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fixture save / replay infrastructure.
|
|
3
|
+
*
|
|
4
|
+
* The probe's signal classification is pure (src/probe/runner.ts), so we can
|
|
5
|
+
* unit-test every branch by replaying recorded HTTP responses instead of
|
|
6
|
+
* hitting a live system. That also gives users a way to contribute probe
|
|
7
|
+
* results from their own SAP landscape: run `--save-fixtures <dir>`, commit
|
|
8
|
+
* the directory, and CI gains a regression-proof corpus.
|
|
9
|
+
*/
|
|
10
|
+
import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
11
|
+
import { join } from 'node:path';
|
|
12
|
+
/** Build a filesystem-safe filename from method+URL. */
|
|
13
|
+
function fixtureFilename(method, url) {
|
|
14
|
+
const slug = url
|
|
15
|
+
.replace(/^https?:\/\/[^/]+/, '') // strip protocol+host
|
|
16
|
+
.replace(/[^a-zA-Z0-9._-]/g, '_')
|
|
17
|
+
.replace(/_+/g, '_')
|
|
18
|
+
.replace(/^_+|_+$/g, '');
|
|
19
|
+
return `${method}__${slug || 'root'}.json`;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Wrap an existing `HttpProbeFn` so that every request+response is persisted
|
|
23
|
+
* to `<dir>/responses/`. Call `meta.write()` at the end of the probe run to
|
|
24
|
+
* emit the top-level metadata file.
|
|
25
|
+
*/
|
|
26
|
+
export function createRecordingFetcher(inner, dir) {
|
|
27
|
+
const responsesDir = join(dir, 'responses');
|
|
28
|
+
mkdirSync(responsesDir, { recursive: true });
|
|
29
|
+
const fetcher = async (url, method) => {
|
|
30
|
+
const result = await inner(url, method);
|
|
31
|
+
const record = {
|
|
32
|
+
url,
|
|
33
|
+
method,
|
|
34
|
+
statusCode: result.statusCode,
|
|
35
|
+
body: result.body,
|
|
36
|
+
networkError: result.networkError,
|
|
37
|
+
errorMessage: result.errorMessage,
|
|
38
|
+
durationMs: result.durationMs,
|
|
39
|
+
};
|
|
40
|
+
writeFileSync(join(responsesDir, fixtureFilename(method, url)), JSON.stringify(record, null, 2));
|
|
41
|
+
return result;
|
|
42
|
+
};
|
|
43
|
+
const writeMeta = (meta) => {
|
|
44
|
+
writeFileSync(join(dir, 'meta.json'), JSON.stringify(meta, null, 2));
|
|
45
|
+
};
|
|
46
|
+
return { fetcher, writeMeta };
|
|
47
|
+
}
|
|
48
|
+
/** Build a replay fetcher that serves from a fixture directory. */
|
|
49
|
+
export function createReplayFetcher(dir) {
|
|
50
|
+
const metaPath = join(dir, 'meta.json');
|
|
51
|
+
if (!existsSync(metaPath)) {
|
|
52
|
+
throw new Error(`Fixture directory ${dir} missing meta.json`);
|
|
53
|
+
}
|
|
54
|
+
const meta = JSON.parse(readFileSync(metaPath, 'utf-8'));
|
|
55
|
+
const responsesDir = join(dir, 'responses');
|
|
56
|
+
const recorded = new Map();
|
|
57
|
+
if (existsSync(responsesDir)) {
|
|
58
|
+
for (const file of readdirSync(responsesDir)) {
|
|
59
|
+
if (!file.endsWith('.json'))
|
|
60
|
+
continue;
|
|
61
|
+
const data = JSON.parse(readFileSync(join(responsesDir, file), 'utf-8'));
|
|
62
|
+
recorded.set(`${data.method} ${data.url}`, data);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
const fetcher = async (url, method) => {
|
|
66
|
+
const hit = recorded.get(`${method} ${url}`);
|
|
67
|
+
if (!hit) {
|
|
68
|
+
// Returning a synthetic network error is honest: the replay corpus
|
|
69
|
+
// simply doesn't know about this URL. Tests that care can assert this.
|
|
70
|
+
const missing = {
|
|
71
|
+
networkError: true,
|
|
72
|
+
errorMessage: `no recorded response for ${method} ${url}`,
|
|
73
|
+
durationMs: 0,
|
|
74
|
+
};
|
|
75
|
+
return missing;
|
|
76
|
+
}
|
|
77
|
+
return {
|
|
78
|
+
statusCode: hit.statusCode,
|
|
79
|
+
body: hit.body,
|
|
80
|
+
networkError: hit.networkError,
|
|
81
|
+
errorMessage: hit.errorMessage,
|
|
82
|
+
durationMs: hit.durationMs,
|
|
83
|
+
};
|
|
84
|
+
};
|
|
85
|
+
return { fetcher, meta };
|
|
86
|
+
}
|
|
87
|
+
/** Build a discovery-map equivalent from the fixture meta (for runner input). */
|
|
88
|
+
export function discoveryMapFromMeta(meta) {
|
|
89
|
+
const map = new Map();
|
|
90
|
+
for (const key of meta.discoveryMapKeys)
|
|
91
|
+
map.set(key, []); // values not needed by runner
|
|
92
|
+
return map;
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=fixtures.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fixtures.js","sourceRoot":"","sources":["../../src/probe/fixtures.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Human-readable formatters for probe reports.
|
|
3
|
+
*
|
|
4
|
+
* Kept separate from the runner so the runner stays pure and JSON-serializable,
|
|
5
|
+
* and so the CLI can opt between `--format table` and `--format json`.
|
|
6
|
+
*/
|
|
7
|
+
import type { ProbeReport } from './types.js';
|
|
8
|
+
/** Render the full report as a plain-text block (for terminal output). */
|
|
9
|
+
export declare function formatTable(report: ProbeReport): string;
|
|
10
|
+
//# sourceMappingURL=format.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../src/probe/format.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAuB,MAAM,YAAY,CAAC;AA2CnE,0EAA0E;AAC1E,wBAAgB,WAAW,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CA8EvD"}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Human-readable formatters for probe reports.
|
|
3
|
+
*
|
|
4
|
+
* Kept separate from the runner so the runner stays pure and JSON-serializable,
|
|
5
|
+
* and so the CLI can opt between `--format table` and `--format json`.
|
|
6
|
+
*/
|
|
7
|
+
const VERDICT_LABEL = {
|
|
8
|
+
'available-high': 'AVAILABLE (high)',
|
|
9
|
+
'available-medium': 'AVAILABLE (medium)',
|
|
10
|
+
'unavailable-high': 'UNAVAILABLE (high)',
|
|
11
|
+
'unavailable-likely': 'UNAVAILABLE (likely)',
|
|
12
|
+
'auth-blocked': 'AUTH BLOCKED',
|
|
13
|
+
ambiguous: 'AMBIGUOUS',
|
|
14
|
+
};
|
|
15
|
+
const DISCOVERY_SHORT = { discovered: 'Y', 'not-discovered': 'N', 'no-discovery-map': '-' };
|
|
16
|
+
function signalShortForKnown(k) {
|
|
17
|
+
switch (k.kind) {
|
|
18
|
+
case 'ok':
|
|
19
|
+
return `OK(${k.objectName})`;
|
|
20
|
+
case 'all-missing':
|
|
21
|
+
return `404×${k.attempted.length}`;
|
|
22
|
+
case 'auth-blocked':
|
|
23
|
+
return '401/403';
|
|
24
|
+
case 'error':
|
|
25
|
+
return 'ERR';
|
|
26
|
+
case 'not-tested':
|
|
27
|
+
return '—';
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
function signalShortForRelease(r) {
|
|
31
|
+
switch (r.kind) {
|
|
32
|
+
case 'ok':
|
|
33
|
+
return `${r.detected}>=${r.floor || '?'}`;
|
|
34
|
+
case 'below-floor':
|
|
35
|
+
return `${r.detected}<${r.floor}`;
|
|
36
|
+
case 'unknown':
|
|
37
|
+
return '?';
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
function padRight(s, n) {
|
|
41
|
+
return s.length >= n ? s : s + ' '.repeat(n - s.length);
|
|
42
|
+
}
|
|
43
|
+
/** Render the full report as a plain-text block (for terminal output). */
|
|
44
|
+
export function formatTable(report) {
|
|
45
|
+
const lines = [];
|
|
46
|
+
lines.push(`SAP system: ${report.system.baseUrl}`);
|
|
47
|
+
lines.push(`SAP_BASIS: ${report.system.abapRelease ?? '(unknown)'}`);
|
|
48
|
+
lines.push(`System type: ${report.system.systemType ?? 'unknown'}`);
|
|
49
|
+
lines.push(`SAP client: ${report.system.client ?? '(default)'}`);
|
|
50
|
+
lines.push(`Discovery size: ${report.system.discoveryMapSize} collections`);
|
|
51
|
+
lines.push(`Probed at: ${report.system.probedAt}`);
|
|
52
|
+
if (report.system.products && report.system.products.length > 0) {
|
|
53
|
+
// Surface the product-line markers that matter for "which SAP is this really".
|
|
54
|
+
const markers = ['SAP_BASIS', 'SAP_ABA', 'S4FND', 'S4CORE', 'SAP_CLOUD', 'SAP_UI'];
|
|
55
|
+
const shown = report.system.products.filter((p) => markers.includes(p.name.toUpperCase()));
|
|
56
|
+
if (shown.length > 0) {
|
|
57
|
+
const joined = shown.map((p) => `${p.name} ${p.release}${p.spLevel ? ` SP${p.spLevel}` : ''}`).join(', ');
|
|
58
|
+
lines.push(`Key components: ${joined}`);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
lines.push('');
|
|
62
|
+
const header = [
|
|
63
|
+
padRight('TYPE', 6),
|
|
64
|
+
padRight('VERDICT', 21),
|
|
65
|
+
padRight('DISCO', 5),
|
|
66
|
+
padRight('COLLECTION', 22),
|
|
67
|
+
padRight('KNOWN', 14),
|
|
68
|
+
padRight('RELEASE', 11),
|
|
69
|
+
'REASON',
|
|
70
|
+
].join(' ');
|
|
71
|
+
lines.push(header);
|
|
72
|
+
lines.push('-'.repeat(header.length));
|
|
73
|
+
for (const r of report.results) {
|
|
74
|
+
const statusFragment = r.signals.collection.statusCode
|
|
75
|
+
? `${r.signals.collection.classification} ${r.signals.collection.statusCode}`
|
|
76
|
+
: r.signals.collection.classification;
|
|
77
|
+
lines.push([
|
|
78
|
+
padRight(r.type, 6),
|
|
79
|
+
padRight(VERDICT_LABEL[r.verdict], 21),
|
|
80
|
+
padRight(DISCOVERY_SHORT[r.signals.discovery], 5),
|
|
81
|
+
padRight(statusFragment, 22),
|
|
82
|
+
padRight(signalShortForKnown(r.signals.knownObject), 14),
|
|
83
|
+
padRight(signalShortForRelease(r.signals.release), 11),
|
|
84
|
+
r.reason,
|
|
85
|
+
].join(' '));
|
|
86
|
+
}
|
|
87
|
+
lines.push('');
|
|
88
|
+
lines.push('Quality metrics');
|
|
89
|
+
lines.push('---------------');
|
|
90
|
+
const q = report.quality;
|
|
91
|
+
const pct = (n) => `${(n * 100).toFixed(0)}%`;
|
|
92
|
+
lines.push(` Coverage — discovery: ${pct(q.coverage.discovery)}`);
|
|
93
|
+
lines.push(` Coverage — collection: ${pct(q.coverage.collection)}`);
|
|
94
|
+
lines.push(` Coverage — known-object: ${pct(q.coverage.knownObject)}`);
|
|
95
|
+
lines.push(` Coverage — release: ${pct(q.coverage.release)}`);
|
|
96
|
+
lines.push(` Discovery vs known-object: ${q.discoveryAccuracyVsKnownObject === null
|
|
97
|
+
? 'n/a (no known-object positives)'
|
|
98
|
+
: pct(q.discoveryAccuracyVsKnownObject)}`);
|
|
99
|
+
lines.push('');
|
|
100
|
+
lines.push(' Verdicts:');
|
|
101
|
+
for (const [k, v] of Object.entries(q.verdictHistogram)) {
|
|
102
|
+
lines.push(` ${padRight(k, 20)} ${v}`);
|
|
103
|
+
}
|
|
104
|
+
if (q.ambiguousTypes.length > 0) {
|
|
105
|
+
lines.push('');
|
|
106
|
+
lines.push(` Ambiguous (signals disagree — review): ${q.ambiguousTypes.join(', ')}`);
|
|
107
|
+
}
|
|
108
|
+
if (q.uncoveredByKnownObject.length > 0) {
|
|
109
|
+
lines.push('');
|
|
110
|
+
lines.push(` No known-object fixture (probe blind spot): ${q.uncoveredByKnownObject.join(', ')}`);
|
|
111
|
+
}
|
|
112
|
+
return lines.join('\n');
|
|
113
|
+
}
|
|
114
|
+
//# sourceMappingURL=format.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format.js","sourceRoot":"","sources":["../../src/probe/format.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Quality-of-probe metrics.
|
|
3
|
+
*
|
|
4
|
+
* The probe's outputs are only as trustworthy as the signals it gathered.
|
|
5
|
+
* These aggregate metrics tell a reader at a glance:
|
|
6
|
+
* - how many types each signal could answer
|
|
7
|
+
* - which types were flagged ambiguous (the danger zone)
|
|
8
|
+
* - whether the discovery map lines up with the authoritative known-object
|
|
9
|
+
* signal on this system (if not, discovery is unreliable here)
|
|
10
|
+
*/
|
|
11
|
+
import type { QualityMetrics, TypeResult } from './types.js';
|
|
12
|
+
export declare function computeQuality(results: TypeResult[]): QualityMetrics;
|
|
13
|
+
//# sourceMappingURL=quality.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"quality.d.ts","sourceRoot":"","sources":["../../src/probe/quality.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAW,MAAM,YAAY,CAAC;AAWtE,wBAAgB,cAAc,CAAC,OAAO,EAAE,UAAU,EAAE,GAAG,cAAc,CAkCpE"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Quality-of-probe metrics.
|
|
3
|
+
*
|
|
4
|
+
* The probe's outputs are only as trustworthy as the signals it gathered.
|
|
5
|
+
* These aggregate metrics tell a reader at a glance:
|
|
6
|
+
* - how many types each signal could answer
|
|
7
|
+
* - which types were flagged ambiguous (the danger zone)
|
|
8
|
+
* - whether the discovery map lines up with the authoritative known-object
|
|
9
|
+
* signal on this system (if not, discovery is unreliable here)
|
|
10
|
+
*/
|
|
11
|
+
import { CATALOG } from './catalog.js';
|
|
12
|
+
const ALL_VERDICTS = [
|
|
13
|
+
'available-high',
|
|
14
|
+
'available-medium',
|
|
15
|
+
'unavailable-high',
|
|
16
|
+
'unavailable-likely',
|
|
17
|
+
'auth-blocked',
|
|
18
|
+
'ambiguous',
|
|
19
|
+
];
|
|
20
|
+
export function computeQuality(results) {
|
|
21
|
+
const total = results.length || 1; // avoid div-by-zero on empty catalog
|
|
22
|
+
const discoveryDefinitive = results.filter((r) => r.signals.discovery !== 'no-discovery-map').length;
|
|
23
|
+
const collectionDefinitive = results.filter((r) => r.signals.collection.classification !== 'network-error').length;
|
|
24
|
+
const knownObjectTested = results.filter((r) => r.signals.knownObject.kind !== 'not-tested').length;
|
|
25
|
+
const releaseKnown = results.filter((r) => r.signals.release.kind !== 'unknown').length;
|
|
26
|
+
// discoveryAccuracyVsKnownObject: of types where known-object confirmed
|
|
27
|
+
// availability, how many did discovery also list?
|
|
28
|
+
const knownOk = results.filter((r) => r.signals.knownObject.kind === 'ok');
|
|
29
|
+
const discoveryAccuracyVsKnownObject = knownOk.length === 0 ? null : knownOk.filter((r) => r.signals.discovery === 'discovered').length / knownOk.length;
|
|
30
|
+
const verdictHistogram = {};
|
|
31
|
+
for (const v of ALL_VERDICTS)
|
|
32
|
+
verdictHistogram[v] = 0;
|
|
33
|
+
for (const r of results)
|
|
34
|
+
verdictHistogram[r.verdict] += 1;
|
|
35
|
+
const ambiguousTypes = results.filter((r) => r.verdict === 'ambiguous').map((r) => r.type);
|
|
36
|
+
const uncoveredByKnownObject = CATALOG.filter((e) => (e.knownObjects?.length ?? 0) === 0).map((e) => e.type);
|
|
37
|
+
return {
|
|
38
|
+
coverage: {
|
|
39
|
+
discovery: discoveryDefinitive / total,
|
|
40
|
+
collection: collectionDefinitive / total,
|
|
41
|
+
knownObject: knownObjectTested / total,
|
|
42
|
+
release: releaseKnown / total,
|
|
43
|
+
},
|
|
44
|
+
discoveryAccuracyVsKnownObject,
|
|
45
|
+
verdictHistogram,
|
|
46
|
+
ambiguousTypes,
|
|
47
|
+
uncoveredByKnownObject,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=quality.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"quality.js","sourceRoot":"","sources":["../../src/probe/quality.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAGvC,MAAM,YAAY,GAAc;IAC9B,gBAAgB;IAChB,kBAAkB;IAClB,kBAAkB;IAClB,oBAAoB;IACpB,cAAc;IACd,WAAW;CACZ,CAAC;AAEF,MAAM,UAAU,cAAc,CAAC,OAAqB;IAClD,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC,qCAAqC;IAExE,MAAM,mBAAmB,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,KAAK,kBAAkB,CAAC,CAAC,MAAM,CAAC;IACrG,MAAM,oBAAoB,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,cAAc,KAAK,eAAe,CAAC,CAAC,MAAM,CAAC;IACnH,MAAM,iBAAiB,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,IAAI,KAAK,YAAY,CAAC,CAAC,MAAM,CAAC;IACpG,MAAM,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,MAAM,CAAC;IAExF,wEAAwE;IACxE,kDAAkD;IAClD,MAAM,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;IAC3E,MAAM,8BAA8B,GAClC,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,KAAK,YAAY,CAAC,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAEpH,MAAM,gBAAgB,GAAG,EAA6B,CAAC;IACvD,KAAK,MAAM,CAAC,IAAI,YAAY;QAAE,gBAAgB,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IACtD,KAAK,MAAM,CAAC,IAAI,OAAO;QAAE,gBAAgB,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAE1D,MAAM,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,WAAW,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IAE3F,MAAM,sBAAsB,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,YAAY,EAAE,MAAM,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IAE7G,OAAO;QACL,QAAQ,EAAE;YACR,SAAS,EAAE,mBAAmB,GAAG,KAAK;YACtC,UAAU,EAAE,oBAAoB,GAAG,KAAK;YACxC,WAAW,EAAE,iBAAiB,GAAG,KAAK;YACtC,OAAO,EAAE,YAAY,GAAG,KAAK;SAC9B;QACD,8BAA8B;QAC9B,gBAAgB;QAChB,cAAc;QACd,sBAAsB;KACvB,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Probe runner — classifies each ADT type against four independent signals:
|
|
3
|
+
*
|
|
4
|
+
* 1. Discovery map presence (free; from the already-fetched /discovery doc)
|
|
5
|
+
* 2. Collection-URL GET (tolerates 400/403/405 as "endpoint exists" — the
|
|
6
|
+
* #94/#95 lesson: only 404 is a hard negative)
|
|
7
|
+
* 3. Known-object GET on an SAP-shipped fixture (authoritative when available)
|
|
8
|
+
* 4. SAP_BASIS release vs. a hand-curated floor (weak tie-breaker only)
|
|
9
|
+
*
|
|
10
|
+
* The runner is deliberately pure: it takes a simple `HttpProbeFn` that never
|
|
11
|
+
* throws and returns a neutral shape. This makes it trivially testable by
|
|
12
|
+
* replaying recorded SAP responses from fixtures.
|
|
13
|
+
*/
|
|
14
|
+
import type { CatalogEntry, DiscoverySignal, HttpClassification, HttpProbe, KnownObjectOutcome, TypeResult, TypeSignals, Verdict } from './types.js';
|
|
15
|
+
/** Neutral HTTP-result shape the runner consumes. Never throws. */
|
|
16
|
+
export interface ProbeFetchResult {
|
|
17
|
+
statusCode?: number;
|
|
18
|
+
body?: string;
|
|
19
|
+
/** True when no HTTP response was obtained at all (connection refused, DNS, TLS). */
|
|
20
|
+
networkError?: boolean;
|
|
21
|
+
errorMessage?: string;
|
|
22
|
+
durationMs: number;
|
|
23
|
+
}
|
|
24
|
+
/** Function the runner calls to probe one URL. Implementations must not throw. */
|
|
25
|
+
export type HttpProbeFn = (url: string, method: 'GET' | 'HEAD') => Promise<ProbeFetchResult>;
|
|
26
|
+
/** Parse SAP_BASIS release string like "750", "7.57", "sap_btp" to a number, or null. */
|
|
27
|
+
export declare function parseRelease(release: string | undefined): number | null;
|
|
28
|
+
/** Classify an HTTP response code into a discrete bucket. */
|
|
29
|
+
export declare function classifyHttp(result: ProbeFetchResult): HttpClassification;
|
|
30
|
+
/** Run the collection-URL probe. Normalized, never throws. */
|
|
31
|
+
export declare function probeCollection(fetchFn: HttpProbeFn, collectionUrl: string): Promise<HttpProbe>;
|
|
32
|
+
/**
|
|
33
|
+
* Try each known object in order and classify the outcome.
|
|
34
|
+
* We stop at the first 2xx; if all fail, we aggregate the attempted list.
|
|
35
|
+
*/
|
|
36
|
+
export declare function probeKnownObject(fetchFn: HttpProbeFn, entry: CatalogEntry): Promise<KnownObjectOutcome>;
|
|
37
|
+
/** Classify the release signal. */
|
|
38
|
+
export declare function classifyRelease(detectedRelease: string | undefined, floor: number | undefined): TypeSignals['release'];
|
|
39
|
+
/** Collapse the four signals into a final verdict + one-line reason. */
|
|
40
|
+
export declare function classifyVerdict(signals: TypeSignals): {
|
|
41
|
+
verdict: Verdict;
|
|
42
|
+
reason: string;
|
|
43
|
+
};
|
|
44
|
+
/** Compute a discovery-map lookup for a collection URL. */
|
|
45
|
+
export declare function resolveDiscovery(discoveryMap: Map<string, string[]> | undefined, collectionUrl: string): DiscoverySignal;
|
|
46
|
+
/** Probe one catalog entry end-to-end. */
|
|
47
|
+
export declare function probeType(fetchFn: HttpProbeFn, entry: CatalogEntry, discoveryMap: Map<string, string[]> | undefined, detectedRelease: string | undefined): Promise<TypeResult>;
|
|
48
|
+
//# sourceMappingURL=runner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../src/probe/runner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,KAAK,EACV,YAAY,EACZ,eAAe,EACf,kBAAkB,EAClB,SAAS,EACT,kBAAkB,EAClB,UAAU,EACV,WAAW,EACX,OAAO,EACR,MAAM,YAAY,CAAC;AAEpB,mEAAmE;AACnE,MAAM,WAAW,gBAAgB;IAC/B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,qFAAqF;IACrF,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,kFAAkF;AAClF,MAAM,MAAM,WAAW,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,GAAG,MAAM,KAAK,OAAO,CAAC,gBAAgB,CAAC,CAAC;AAE7F,yFAAyF;AACzF,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAMvE;AAED,6DAA6D;AAC7D,wBAAgB,YAAY,CAAC,MAAM,EAAE,gBAAgB,GAAG,kBAAkB,CAWzE;AASD,8DAA8D;AAC9D,wBAAsB,eAAe,CAAC,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CAUrG;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,kBAAkB,CAAC,CA6B7G;AAED,mCAAmC;AACnC,wBAAgB,eAAe,CAC7B,eAAe,EAAE,MAAM,GAAG,SAAS,EACnC,KAAK,EAAE,MAAM,GAAG,SAAS,GACxB,WAAW,CAAC,SAAS,CAAC,CAMxB;AAED,wEAAwE;AACxE,wBAAgB,eAAe,CAAC,OAAO,EAAE,WAAW,GAAG;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAkF1F;AAED,2DAA2D;AAC3D,wBAAgB,gBAAgB,CAC9B,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,GAAG,SAAS,EAC/C,aAAa,EAAE,MAAM,GACpB,eAAe,CAKjB;AAED,0CAA0C;AAC1C,wBAAsB,SAAS,CAC7B,OAAO,EAAE,WAAW,EACpB,KAAK,EAAE,YAAY,EACnB,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,GAAG,SAAS,EAC/C,eAAe,EAAE,MAAM,GAAG,SAAS,GAClC,OAAO,CAAC,UAAU,CAAC,CAarB"}
|