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.
Files changed (86) hide show
  1. package/README.md +6 -4
  2. package/dist/adt/abapgit.d.ts +39 -0
  3. package/dist/adt/abapgit.d.ts.map +1 -0
  4. package/dist/adt/abapgit.js +333 -0
  5. package/dist/adt/abapgit.js.map +1 -0
  6. package/dist/adt/config.d.ts +1 -0
  7. package/dist/adt/config.d.ts.map +1 -1
  8. package/dist/adt/config.js +1 -0
  9. package/dist/adt/config.js.map +1 -1
  10. package/dist/adt/crud.d.ts.map +1 -1
  11. package/dist/adt/crud.js +42 -3
  12. package/dist/adt/crud.js.map +1 -1
  13. package/dist/adt/errors.d.ts +22 -1
  14. package/dist/adt/errors.d.ts.map +1 -1
  15. package/dist/adt/errors.js +71 -2
  16. package/dist/adt/errors.js.map +1 -1
  17. package/dist/adt/features.d.ts.map +1 -1
  18. package/dist/adt/features.js +3 -0
  19. package/dist/adt/features.js.map +1 -1
  20. package/dist/adt/gcts.d.ts +68 -0
  21. package/dist/adt/gcts.d.ts.map +1 -0
  22. package/dist/adt/gcts.js +239 -0
  23. package/dist/adt/gcts.js.map +1 -0
  24. package/dist/adt/safety.d.ts +3 -0
  25. package/dist/adt/safety.d.ts.map +1 -1
  26. package/dist/adt/safety.js +9 -0
  27. package/dist/adt/safety.js.map +1 -1
  28. package/dist/adt/transport.d.ts.map +1 -1
  29. package/dist/adt/transport.js +4 -1
  30. package/dist/adt/transport.js.map +1 -1
  31. package/dist/adt/types.d.ts +137 -0
  32. package/dist/adt/types.d.ts.map +1 -1
  33. package/dist/adt/xml-parser.d.ts +2 -0
  34. package/dist/adt/xml-parser.d.ts.map +1 -1
  35. package/dist/adt/xml-parser.js +2 -0
  36. package/dist/adt/xml-parser.js.map +1 -1
  37. package/dist/handlers/intent.d.ts.map +1 -1
  38. package/dist/handlers/intent.js +235 -0
  39. package/dist/handlers/intent.js.map +1 -1
  40. package/dist/handlers/schemas.d.ts +45 -1
  41. package/dist/handlers/schemas.d.ts.map +1 -1
  42. package/dist/handlers/schemas.js +46 -0
  43. package/dist/handlers/schemas.js.map +1 -1
  44. package/dist/handlers/tools.d.ts +4 -3
  45. package/dist/handlers/tools.d.ts.map +1 -1
  46. package/dist/handlers/tools.js +115 -3
  47. package/dist/handlers/tools.js.map +1 -1
  48. package/dist/probe/catalog.d.ts +30 -0
  49. package/dist/probe/catalog.d.ts.map +1 -0
  50. package/dist/probe/catalog.js +196 -0
  51. package/dist/probe/catalog.js.map +1 -0
  52. package/dist/probe/fixtures.d.ts +54 -0
  53. package/dist/probe/fixtures.d.ts.map +1 -0
  54. package/dist/probe/fixtures.js +94 -0
  55. package/dist/probe/fixtures.js.map +1 -0
  56. package/dist/probe/format.d.ts +10 -0
  57. package/dist/probe/format.d.ts.map +1 -0
  58. package/dist/probe/format.js +114 -0
  59. package/dist/probe/format.js.map +1 -0
  60. package/dist/probe/quality.d.ts +13 -0
  61. package/dist/probe/quality.d.ts.map +1 -0
  62. package/dist/probe/quality.js +50 -0
  63. package/dist/probe/quality.js.map +1 -0
  64. package/dist/probe/runner.d.ts +48 -0
  65. package/dist/probe/runner.d.ts.map +1 -0
  66. package/dist/probe/runner.js +211 -0
  67. package/dist/probe/runner.js.map +1 -0
  68. package/dist/probe/types.d.ts +159 -0
  69. package/dist/probe/types.d.ts.map +1 -0
  70. package/dist/probe/types.js +11 -0
  71. package/dist/probe/types.js.map +1 -0
  72. package/dist/server/audit.d.ts.map +1 -1
  73. package/dist/server/audit.js +12 -1
  74. package/dist/server/audit.js.map +1 -1
  75. package/dist/server/config.d.ts.map +1 -1
  76. package/dist/server/config.js +15 -2
  77. package/dist/server/config.js.map +1 -1
  78. package/dist/server/server.d.ts +2 -2
  79. package/dist/server/server.d.ts.map +1 -1
  80. package/dist/server/server.js +5 -3
  81. package/dist/server/server.js.map +1 -1
  82. package/dist/server/types.d.ts +3 -1
  83. package/dist/server/types.d.ts.map +1 -1
  84. package/dist/server/types.js +2 -0
  85. package/dist/server/types.js.map +1 -1
  86. 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"}