@mcp-abap-adt/auth-broker 3.0.0 → 3.0.2

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/CHANGELOG.md CHANGED
@@ -11,6 +11,33 @@ Thank you to all contributors! See [CONTRIBUTORS.md](CONTRIBUTORS.md) for the co
11
11
 
12
12
  ## [Unreleased]
13
13
 
14
+ ## [3.0.2] - 2026-09-27
15
+
16
+ ### Changed
17
+
18
+ - **Node.js 26 is supported**: `engines` is `"^22 || ^24 || ^26"`. Under Node 26 npm skipped every release whose `engines` did not admit it and installed the newest one that did — silently an older major, for this package one without the restriction. Measured: `npm i -g @mcp-abap-adt/proxy` on Node 26.7.0 installed 4.2.0 while 5.0.1 was `latest`. The release build runs on Node 22 (it was 18, below `engines`).
19
+
20
+ ## [3.0.1] - 2026-09-26
21
+
22
+ ### Fixed
23
+
24
+ - **A store failure other than a missing file reaches the caller as raised.**
25
+ The broker answered every store error as absence — logged, then `null` — so
26
+ a service key that is there but not valid JSON, or a file the process may
27
+ not read, surfaced only as its consequence: "Session for destination … is
28
+ missing required field 'serviceUrl'", which sends users to create a file
29
+ that already exists. Absence is still `null` or `FILE_NOT_FOUND`, and the
30
+ flow goes on to the next source; anything else is thrown unchanged — before
31
+ the provider is asked when it comes from the reads that precede the token,
32
+ and after the provider answered and the token was written when it comes
33
+ from the reads that save the refresh token.
34
+
35
+ Measured on auth-stores 1.2.3: the service key stores throw on an invalid or
36
+ unreadable file (`Invalid JSON in file …`, `EACCES`), so this change is what
37
+ a broker user sees. The session stores answer an unreadable or unparsable
38
+ file with `null` themselves; that is theirs to change, and this release does
39
+ not see it.
40
+
14
41
  ## [3.0.0] - 2026-09-26
15
42
 
16
43
  ### Security
package/README.md CHANGED
@@ -26,8 +26,9 @@ authorization code or client credentials) and `mcp-sso` (OIDC and SAML single si
26
26
  npm install @mcp-abap-adt/auth-broker
27
27
  ```
28
28
 
29
- Requires Node.js 22 or 24 (`engines: "^22 || ^24"`), the versions SAP BTP's Cloud Foundry
30
- Node.js buildpack offers.
29
+ Requires Node.js 22, 24 or 26 (`engines: "^22 || ^24 || ^26"`): 22 and 24 are
30
+ the versions SAP BTP's Cloud Foundry Node.js buildpack offers, and 26 is
31
+ supported as well.
31
32
 
32
33
  ## Usage
33
34
 
@@ -206,7 +207,7 @@ const connection = new JwtAbapConnection(config, tokenRefresher);
206
207
  5. The broker no longer writes the client secret into the session store. Read
207
208
  it from the service key store if you relied on finding it in the session.
208
209
  6. `refreshToken()` now forces a new token; it used to return `getToken()`'s.
209
- 7. Node.js 22 or 24; SAML runs need the IdP trust (see *Migrating `mcp-sso`
210
+ 7. Node.js 22, 24 or 26; SAML runs need the IdP trust (see *Migrating `mcp-sso`
210
211
  SAML runs from 2.2.0*).
211
212
 
212
213
  ## Configuration
@@ -513,13 +514,20 @@ The session's configuration, else the service key's, else `null`.
513
514
 
514
515
  - **Provider errors propagate unchanged** — the same object, with its class,
515
516
  `code`, `missingFields` and `cause`: auth-providers' `ValidationError`,
516
- `RefreshError`, `AssertionValidationError`, network errors (`ECONNREFUSED`,
517
+ `BrowserAuthError`, `AssertionValidationError`, network errors (`ECONNREFUSED`,
517
518
  `ETIMEDOUT`, `ENOTFOUND`), and whatever your authorization strategy throws.
518
519
  The broker does not retry a failed call.
519
- - **Store reads do not stop the flow**: a missing (`FILE_NOT_FOUND`, logged at
520
- debug) or unreadable entry (logged as a warning) is treated as absent, and
521
- whatever needed it fails later with its own message — for instance the
522
- missing `serviceUrl`.
520
+ - **Store reads: absence is an answer, a failure is not.** A store that answers
521
+ `null`, or fails with `FILE_NOT_FOUND` (logged at debug), means "nothing
522
+ here", and the broker goes on to the next source. Any other store failure —
523
+ a service key that is not valid JSON, a file the process may not read — is
524
+ thrown unchanged. A failure in the reads that come before the token (the
525
+ session's connection config, the service key) stops the call before the
526
+ provider is asked; one in the reads that save it (the session's
527
+ authorization config, the session) arrives after the provider answered and
528
+ the new token was written. (The session stores of
529
+ auth-stores answer an unreadable session file with `null` themselves, so it
530
+ reads as absent before the broker sees it.)
523
531
  - **Store writes propagate**: a token that cannot be saved is an error.
524
532
  - **A provider result without a token** is an error.
525
533
 
@@ -850,7 +858,7 @@ With 4.x every `mcp-sso` SAML run (`bearer`, `saml2 --flow pure`, and `mcp-auth
850
858
  `--assertion-flow manual`. For any other `--assertion` from an SP-initiated login:
851
859
  `--authn-request-id`.
852
860
 
853
- Node.js 22 or 24 is required.
861
+ Node.js 22, 24 or 26 is required.
854
862
 
855
863
  ### Utility Script
856
864
 
@@ -89,9 +89,15 @@ export declare class AuthBroker {
89
89
  */
90
90
  private persist;
91
91
  /**
92
- * A store read that does not stop the flow: a missing or unreadable entry is
93
- * logged and answered as absent, and whatever needed it fails with its own
94
- * message later.
92
+ * A store read where absence is an answer and anything else is not.
93
+ *
94
+ * A store says "nothing here" with `null`, or with `FILE_NOT_FOUND`, and the
95
+ * flow goes on to the next source. Any other failure — a service key that is
96
+ * not valid JSON, a file the process may not read — is a different problem
97
+ * with a different fix, and reaches the caller as the store raised it. It
98
+ * used to be logged and answered as absent, so the caller saw only the
99
+ * consequence ("missing required field 'serviceUrl'") and went looking for a
100
+ * file that was there.
95
101
  */
96
102
  private read;
97
103
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"AuthBroker.d.ts","sourceRoot":"","sources":["../src/AuthBroker.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EACV,yBAAyB,EACzB,eAAe,EAEhB,MAAM,+BAA+B,CAAC;AAEvC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gCAAgC,CAAC;AAC9D,OAAO,KAAK,EACV,oBAAoB,EACpB,iBAAiB,EACjB,gBAAgB,EAChB,aAAa,EACd,MAAM,qBAAqB,CAAC;AAS7B;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,oBAAoB,GAAG,CACjC,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,oBAAoB,GAAG,IAAI,EACvC,UAAU,EAAE,iBAAiB,KAC1B,yBAAyB,CAAC;AAE/B;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,6EAA6E;IAC7E,YAAY,EAAE,aAAa,CAAC;IAC5B,yEAAyE;IACzE,eAAe,CAAC,EAAE,gBAAgB,CAAC;IACnC;;;;;OAKG;IACH,QAAQ,EAAE,yBAAyB,GAAG,oBAAoB,CAAC;CAC5D;AAcD;;GAEG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAU;IACjC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAA+B;IAC/D,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAgB;IAC7C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAmD;IAC5E,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAgD;IAE1E;;;OAGG;gBACS,MAAM,EAAE,gBAAgB,EAAE,MAAM,CAAC,EAAE,OAAO;IA2DtD;;;;;;OAMG;IACG,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAIpD;;;;OAIG;IACG,YAAY,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;YAI1C,MAAM;YA2BN,WAAW;IA4BzB;;;;;;OAMG;YACW,0BAA0B;YAiC1B,iBAAiB;IAuB/B;;;;;;;OAOG;YACW,OAAO;IAoDrB;;;;OAIG;YACW,IAAI;IAoBlB;;;OAGG;IACG,sBAAsB,CAC1B,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC;IAkBvC;;;OAGG;IACG,mBAAmB,CACvB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC;IAkBpC;;;;OAIG;IACH,oBAAoB,CAAC,WAAW,EAAE,MAAM,GAAG,eAAe;CAM3D"}
1
+ {"version":3,"file":"AuthBroker.d.ts","sourceRoot":"","sources":["../src/AuthBroker.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EACV,yBAAyB,EACzB,eAAe,EAEhB,MAAM,+BAA+B,CAAC;AAEvC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gCAAgC,CAAC;AAC9D,OAAO,KAAK,EACV,oBAAoB,EACpB,iBAAiB,EACjB,gBAAgB,EAChB,aAAa,EACd,MAAM,qBAAqB,CAAC;AAS7B;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,oBAAoB,GAAG,CACjC,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,oBAAoB,GAAG,IAAI,EACvC,UAAU,EAAE,iBAAiB,KAC1B,yBAAyB,CAAC;AAE/B;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,6EAA6E;IAC7E,YAAY,EAAE,aAAa,CAAC;IAC5B,yEAAyE;IACzE,eAAe,CAAC,EAAE,gBAAgB,CAAC;IACnC;;;;;OAKG;IACH,QAAQ,EAAE,yBAAyB,GAAG,oBAAoB,CAAC;CAC5D;AAUD;;GAEG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAU;IACjC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAA+B;IAC/D,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAgB;IAC7C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAmD;IAC5E,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAgD;IAE1E;;;OAGG;gBACS,MAAM,EAAE,gBAAgB,EAAE,MAAM,CAAC,EAAE,OAAO;IA2DtD;;;;;;OAMG;IACG,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAIpD;;;;OAIG;IACG,YAAY,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;YAI1C,MAAM;YA2BN,WAAW;IA4BzB;;;;;;OAMG;YACW,0BAA0B;YAiC1B,iBAAiB;IAuB/B;;;;;;;OAOG;YACW,OAAO;IAoDrB;;;;;;;;;;OAUG;YACW,IAAI;IAgBlB;;;OAGG;IACG,sBAAsB,CAC1B,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC;IAkBvC;;;OAGG;IACG,mBAAmB,CACvB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC;IAkBpC;;;;OAIG;IACH,oBAAoB,CAAC,WAAW,EAAE,MAAM,GAAG,eAAe;CAM3D"}
@@ -18,9 +18,6 @@ const noOpLogger = {
18
18
  warn: () => { },
19
19
  debug: () => { },
20
20
  };
21
- function errorMessage(error) {
22
- return error instanceof Error ? error.message : String(error);
23
- }
24
21
  function errorCode(error) {
25
22
  if (error !== null && typeof error === 'object' && 'code' in error) {
26
23
  const code = error.code;
@@ -232,23 +229,26 @@ class AuthBroker {
232
229
  });
233
230
  }
234
231
  /**
235
- * A store read that does not stop the flow: a missing or unreadable entry is
236
- * logged and answered as absent, and whatever needed it fails with its own
237
- * message later.
232
+ * A store read where absence is an answer and anything else is not.
233
+ *
234
+ * A store says "nothing here" with `null`, or with `FILE_NOT_FOUND`, and the
235
+ * flow goes on to the next source. Any other failure — a service key that is
236
+ * not valid JSON, a file the process may not read — is a different problem
237
+ * with a different fix, and reaches the caller as the store raised it. It
238
+ * used to be logged and answered as absent, so the caller saw only the
239
+ * consequence ("missing required field 'serviceUrl'") and went looking for a
240
+ * file that was there.
238
241
  */
239
242
  async read(destination, what, fn) {
240
243
  try {
241
244
  return await fn();
242
245
  }
243
246
  catch (error) {
244
- const code = errorCode(error);
245
- if (code === interfaces_auth_1.STORE_ERROR_CODES.FILE_NOT_FOUND) {
247
+ if (errorCode(error) === interfaces_auth_1.STORE_ERROR_CODES.FILE_NOT_FOUND) {
246
248
  this.logger.debug(`No ${what} for ${destination}: file not found`);
249
+ return null;
247
250
  }
248
- else {
249
- this.logger.warn(`Failed to read ${what} for ${destination}: ${errorMessage(error)}`);
250
- }
251
- return null;
251
+ throw error;
252
252
  }
253
253
  }
254
254
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mcp-abap-adt/auth-broker",
3
- "version": "3.0.0",
3
+ "version": "3.0.2",
4
4
  "description": "Per-destination token broker for SAP BTP and ABAP: sessions and service keys from stores, tokens from an injected provider, results persisted - plus the mcp-auth and mcp-sso CLIs",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -64,7 +64,7 @@
64
64
  "mcp-sso": "./dist/bin/mcp-sso.js"
65
65
  },
66
66
  "engines": {
67
- "node": "^22 || ^24"
67
+ "node": "^22 || ^24 || ^26"
68
68
  },
69
69
  "dependencies": {
70
70
  "@mcp-abap-adt/auth-providers": "^4.2.0",