@farthershore/backend 0.17.0 → 0.18.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/CHANGELOG.md CHANGED
@@ -4,6 +4,22 @@ All notable changes to the runtime backend SDK are documented here. This SDK
4
4
  versions independently from the frontend and business SDKs. Pre-1.0: minor
5
5
  versions may include breaking changes.
6
6
 
7
+ ## [0.18.0]
8
+
9
+ ### Added
10
+
11
+ - `createExpressMiddleware` accepts `onVerificationError`, called when
12
+ verification REJECTS a request with the diagnostic detail the response body
13
+ deliberately withholds (`{ code, message, status, method, path }`).
14
+
15
+ The wire body stays `{ error: <code> }` — several distinct causes share one
16
+ code (`route_mismatch` covers a business mismatch, a backend mismatch, AND an
17
+ unserved route id) and the specifics must not leak to an unauthenticated
18
+ caller. Previously they were discarded entirely, leaving the operator no way
19
+ to tell which cause fired even in their own logs. Defaults to a one-line
20
+ `console.warn`; pass a function to route it into a structured logger, or
21
+ `() => {}` to silence it. A throwing reporter cannot turn a 401 into a 500.
22
+
7
23
  ## [0.17.0]
8
24
 
9
25
  ### Changed — BREAKING
package/README.md CHANGED
@@ -12,7 +12,7 @@ graceful lifecycle (health + shutdown). Everything else — your business, backe
12
12
  and environment ids, the verification keys, and the metering endpoint — is
13
13
  fetched automatically from the token at startup.
14
14
 
15
- > **Status: `0.17.0`.** Pre-1.0: minor releases may include breaking changes, so
15
+ > **Status: `0.18.0`.** Pre-1.0: minor releases may include breaking changes, so
16
16
  > pin this package to an exact version (or a patch-only range) and upgrade
17
17
  > deliberately.
18
18
 
@@ -85,15 +85,27 @@ async function runMiddleware(fs, options, req, res, next) {
85
85
  stripFartherShoreHeaders(req);
86
86
  next();
87
87
  } catch (error) {
88
- fail(res, error);
88
+ fail(res, error, options, req);
89
89
  }
90
90
  }
91
- function fail(res, error) {
92
- if (error instanceof FartherShoreError) {
93
- res.status(error.status).json({ error: error.code });
94
- return;
91
+ function fail(res, error, options, req) {
92
+ const code = error instanceof FartherShoreError ? error.code : "bad_signature";
93
+ const status = error instanceof FartherShoreError ? error.status : 401;
94
+ const message = error instanceof Error && error.message ? error.message : code;
95
+ const report = options.onVerificationError ?? ((d) => {
96
+ console.warn(`[farthershore] request rejected (${d.code}): ${d.message}`);
97
+ });
98
+ try {
99
+ report({
100
+ code,
101
+ message,
102
+ status,
103
+ method: req.method ?? "",
104
+ path: req.url ?? ""
105
+ });
106
+ } catch {
95
107
  }
96
- res.status(401).json({ error: "bad_signature" });
108
+ res.status(status).json({ error: code });
97
109
  }
98
110
  function stripFartherShoreHeaders(req) {
99
111
  const headers = req.headers;
package/dist/index.js CHANGED
@@ -1918,7 +1918,7 @@ function headerGetter(headers) {
1918
1918
 
1919
1919
  // src/core/runtime.ts
1920
1920
  var DEFAULT_CORE_URL = "https://core.farthershore.com";
1921
- var SDK_VERSION = "0.17.0".length > 0 ? "0.17.0" : "0.0.0-dev";
1921
+ var SDK_VERSION = "0.18.0".length > 0 ? "0.18.0" : "0.0.0-dev";
1922
1922
  var FartherShore = class {
1923
1923
  bootstrapClient;
1924
1924
  fetchImpl;
@@ -2276,15 +2276,27 @@ async function runMiddleware(fs, options, req, res, next) {
2276
2276
  stripFartherShoreHeaders(req);
2277
2277
  next();
2278
2278
  } catch (error) {
2279
- fail(res, error);
2279
+ fail(res, error, options, req);
2280
2280
  }
2281
2281
  }
2282
- function fail(res, error) {
2283
- if (error instanceof FartherShoreError) {
2284
- res.status(error.status).json({ error: error.code });
2285
- return;
2282
+ function fail(res, error, options, req) {
2283
+ const code = error instanceof FartherShoreError ? error.code : "bad_signature";
2284
+ const status = error instanceof FartherShoreError ? error.status : 401;
2285
+ const message = error instanceof Error && error.message ? error.message : code;
2286
+ const report = options.onVerificationError ?? ((d) => {
2287
+ console.warn(`[farthershore] request rejected (${d.code}): ${d.message}`);
2288
+ });
2289
+ try {
2290
+ report({
2291
+ code,
2292
+ message,
2293
+ status,
2294
+ method: req.method ?? "",
2295
+ path: req.url ?? ""
2296
+ });
2297
+ } catch {
2286
2298
  }
2287
- res.status(401).json({ error: "bad_signature" });
2299
+ res.status(status).json({ error: code });
2288
2300
  }
2289
2301
  function stripFartherShoreHeaders(req) {
2290
2302
  const headers = req.headers;
@@ -2149,7 +2149,7 @@ function headerGetter(headers) {
2149
2149
 
2150
2150
  // src/core/runtime.ts
2151
2151
  var DEFAULT_CORE_URL = "https://core.farthershore.com";
2152
- var SDK_VERSION = "0.17.0".length > 0 ? "0.17.0" : "0.0.0-dev";
2152
+ var SDK_VERSION = "0.18.0".length > 0 ? "0.18.0" : "0.0.0-dev";
2153
2153
  var FartherShore = class {
2154
2154
  bootstrapClient;
2155
2155
  fetchImpl;
@@ -2502,15 +2502,27 @@ async function runMiddleware(fs, options, req, res, next) {
2502
2502
  stripFartherShoreHeaders(req);
2503
2503
  next();
2504
2504
  } catch (error) {
2505
- fail(res, error);
2505
+ fail(res, error, options, req);
2506
2506
  }
2507
2507
  }
2508
- function fail(res, error) {
2509
- if (error instanceof FartherShoreError) {
2510
- res.status(error.status).json({ error: error.code });
2511
- return;
2508
+ function fail(res, error, options, req) {
2509
+ const code = error instanceof FartherShoreError ? error.code : "bad_signature";
2510
+ const status = error instanceof FartherShoreError ? error.status : 401;
2511
+ const message = error instanceof Error && error.message ? error.message : code;
2512
+ const report = options.onVerificationError ?? ((d) => {
2513
+ console.warn(`[farthershore] request rejected (${d.code}): ${d.message}`);
2514
+ });
2515
+ try {
2516
+ report({
2517
+ code,
2518
+ message,
2519
+ status,
2520
+ method: req.method ?? "",
2521
+ path: req.url ?? ""
2522
+ });
2523
+ } catch {
2512
2524
  }
2513
- res.status(401).json({ error: "bad_signature" });
2525
+ res.status(status).json({ error: code });
2514
2526
  }
2515
2527
  function stripFartherShoreHeaders(req) {
2516
2528
  const headers = req.headers;
@@ -36,6 +36,27 @@ export type MiddlewareOptions = {
36
36
  * consumes no identity; the secure default is strict.
37
37
  */
38
38
  always?: boolean;
39
+ /**
40
+ * Called when verification REJECTS a request, with the diagnostic detail that
41
+ * is deliberately withheld from the response body.
42
+ *
43
+ * The wire response is only `{ error: <code> }` — several distinct causes
44
+ * share one code (`route_mismatch` covers a business mismatch, a backend
45
+ * mismatch, AND an unserved route id), and the specifics must not leak to an
46
+ * unauthenticated caller. But discarding them entirely leaves the operator
47
+ * with no way to tell which cause fired, in their OWN logs, for their OWN
48
+ * server. That is what this hook restores.
49
+ *
50
+ * Defaults to a one-line `console.warn`. Pass a function to route it into a
51
+ * structured logger, or `() => {}` to silence it.
52
+ */
53
+ onVerificationError?: (detail: {
54
+ code: string;
55
+ message: string;
56
+ status: number;
57
+ method: string;
58
+ path: string;
59
+ }) => void;
39
60
  };
40
61
  /**
41
62
  * A verified request context whose {@link ConsumerPrincipal} is GUARANTEED
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@farthershore/backend",
3
- "version": "0.17.0",
3
+ "version": "0.18.0",
4
4
  "description": "Farther Shore backend SDK for builder upstreams: signed response usage, fail-closed gateway request verification, health, and lifecycle from FS_RUNTIME_TOKEN",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -39,8 +39,8 @@
39
39
  "optionalDependencies": {
40
40
  "@farthershore/cloudflared-linux-x64": "0.0.0",
41
41
  "@farthershore/cloudflared-linux-arm64": "0.0.0",
42
- "@farthershore/cloudflared-darwin-x64": "0.0.0",
43
- "@farthershore/cloudflared-darwin-arm64": "0.0.0"
42
+ "@farthershore/cloudflared-darwin-arm64": "0.0.0",
43
+ "@farthershore/cloudflared-darwin-x64": "0.0.0"
44
44
  },
45
45
  "peerDependencies": {
46
46
  "express": "^4.0.0 || ^5.0.0"