@farthershore/backend 0.15.0 → 0.16.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 +68 -0
- package/README.md +1 -1
- package/dist/adapters/express.js +63 -1
- package/dist/generated/runtime-contract.js +10 -5
- package/dist/index.js +303 -148
- package/dist/testing/index.js +266 -140
- package/dist/types/adapters/express.d.ts +55 -5
- package/dist/types/core/nonceCache.d.ts +25 -4
- package/dist/types/core/permissions.d.ts +14 -25
- package/dist/types/core/runtime.d.ts +23 -30
- package/dist/types/core/subject.d.ts +25 -0
- package/dist/types/core/verifyContext.d.ts +96 -19
- package/dist/types/core/verifyRequest.d.ts +34 -24
- package/dist/types/generated/runtime-contract.d.ts +6 -3
- package/dist/types/index.d.ts +16 -7
- package/dist/types/response-metering.d.ts +7 -0
- package/dist/types/runtime-signing.d.ts +7 -0
- package/dist/types/runtime-types.d.ts +9 -6
- package/dist/types/testing/devRuntime.d.ts +3 -1
- package/dist/types/testing/signers.d.ts +12 -4
- package/package.json +5 -4
|
@@ -48,6 +48,13 @@ export type BillableUsageMap = UsageMap;
|
|
|
48
48
|
export type MeteringOptions = {
|
|
49
49
|
token?: string;
|
|
50
50
|
env?: Record<string, string | undefined>;
|
|
51
|
+
/**
|
|
52
|
+
* Gateway request id for dev-mode trace/usage association (never signed).
|
|
53
|
+
* Thread the VERIFIED `ctx.requestId` here — the strict middleware strips the
|
|
54
|
+
* inbound `x-fs-request-id` header, so the request object no longer carries it.
|
|
55
|
+
* Falls back to the request's `x-fs-request-id` header when unset.
|
|
56
|
+
*/
|
|
57
|
+
requestId?: string;
|
|
51
58
|
measureContext?: Record<string, unknown>;
|
|
52
59
|
creditUnitsConsumed?: BillableUsageMap;
|
|
53
60
|
/** Gateway-validated operation identity hint. The SDK signs and transports it
|
|
@@ -14,6 +14,13 @@ export declare const canonicalizeQuery: (query: string) => string;
|
|
|
14
14
|
* dependence on JSON key order or Node Buffer serialization.
|
|
15
15
|
*/
|
|
16
16
|
export declare const buildCanonicalSigningString: (input: CanonicalSigningInput) => string;
|
|
17
|
+
/**
|
|
18
|
+
* SHA-256 hex of the presented `X-Fs-Context` JWT string (identity-context
|
|
19
|
+
* binding). A missing/empty context hashes the EMPTY string, so signer and
|
|
20
|
+
* verifier agree byte-for-byte when there is no identity context. The value
|
|
21
|
+
* feeds {@link CanonicalSigningInput.contextHash}.
|
|
22
|
+
*/
|
|
23
|
+
export declare const hashContextToken: (token: string | null | undefined) => Promise<string>;
|
|
17
24
|
/** Sign the canonical string with an Ed25519 private JWK → base64url signature. */
|
|
18
25
|
export declare const signCanonicalString: (canonical: string, privateJwk: JsonWebKey) => Promise<string>;
|
|
19
26
|
/** Verify a base64url Ed25519 signature over the canonical string. */
|
|
@@ -99,7 +99,7 @@ export declare const DENY_ENVELOPE_FIELDS: {
|
|
|
99
99
|
* the subset its bridge produces. Each is a verbatim core `ErrorCode` string —
|
|
100
100
|
* the drift guard asserts membership in the canonical enum.
|
|
101
101
|
*/
|
|
102
|
-
export type RuntimeMappedErrorCode = "UNAUTHORIZED" | "SERVICE_UNAVAILABLE" | "VALIDATION_ERROR" | "INTERNAL_ERROR";
|
|
102
|
+
export type RuntimeMappedErrorCode = "UNAUTHORIZED" | "FORBIDDEN" | "SERVICE_UNAVAILABLE" | "VALIDATION_ERROR" | "INTERNAL_ERROR";
|
|
103
103
|
/**
|
|
104
104
|
* C-2 — map every canonical {@link RuntimeErrorCode} (wire snake_case value) to
|
|
105
105
|
* the core `ErrorCode` it belongs to. Total over `RuntimeErrorCode` (the
|
|
@@ -133,11 +133,6 @@ export declare const RUNTIME_HEADER_NAMES: {
|
|
|
133
133
|
readonly bodyHash: "x-fs-body-hash";
|
|
134
134
|
};
|
|
135
135
|
export type RuntimeHeaderName = (typeof RUNTIME_HEADER_NAMES)[keyof typeof RUNTIME_HEADER_NAMES];
|
|
136
|
-
export declare const RUNTIME_IDENTITY_HEADER_NAMES: {
|
|
137
|
-
readonly permissions: "x-fs-permissions";
|
|
138
|
-
readonly roles: "x-fs-roles";
|
|
139
|
-
};
|
|
140
|
-
export type RuntimeIdentityHeaderName = (typeof RUNTIME_IDENTITY_HEADER_NAMES)[keyof typeof RUNTIME_IDENTITY_HEADER_NAMES];
|
|
141
136
|
/** Mirrors SERVICE_JWT_CLOCK_SKEW_SECONDS — the per-request signer reuses the
|
|
142
137
|
* same Ed25519/JWKS infra so the skew allowance is kept identical. */
|
|
143
138
|
export declare const RUNTIME_CLOCK_SKEW_SECONDS = 5;
|
|
@@ -171,6 +166,14 @@ export type CanonicalSigningInput = {
|
|
|
171
166
|
/** Resolved route id; "" when unresolved. */
|
|
172
167
|
routeId: string;
|
|
173
168
|
policyVersion: string;
|
|
169
|
+
/**
|
|
170
|
+
* Consumer-principal wave (D3) — SHA-256 hex of the presented `X-Fs-Context`
|
|
171
|
+
* JWT string, or the SHA-256 of the EMPTY string when context signing is off.
|
|
172
|
+
* Bound into the canonical string so one request-signature verification
|
|
173
|
+
* covers both the request and the identity context. Compute via
|
|
174
|
+
* {@link hashContextToken}.
|
|
175
|
+
*/
|
|
176
|
+
contextHash: string;
|
|
174
177
|
};
|
|
175
178
|
export type RuntimeEnvironmentKind = RuntimeTokenKind;
|
|
176
179
|
export type TransportMode = "direct" | "tunnel";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { FartherShore } from "../core/runtime.js";
|
|
2
|
-
import { type ExpressMiddleware, type MiddlewareOptions } from "../adapters/express.js";
|
|
2
|
+
import { type ExpressMiddleware, type ExpressRequestLike, type ExpressResponseLike, type MiddlewareOptions, type VerifiedExpressHandler } from "../adapters/express.js";
|
|
3
3
|
import { type PermissionCarrier } from "../core/permissions.js";
|
|
4
4
|
import { type DevGateway } from "./devGateway.js";
|
|
5
5
|
import { DevUsageSink } from "./usageSink.js";
|
|
@@ -13,6 +13,8 @@ export type TracedCarrier = PermissionCarrier & {
|
|
|
13
13
|
/** The FartherShore instance augmented with a bound Express middleware. */
|
|
14
14
|
export type FartherShoreDevInstance = FartherShore & {
|
|
15
15
|
middleware(options?: MiddlewareOptions): ExpressMiddleware;
|
|
16
|
+
/** Strict-context handler wrapper (guaranteed non-optional ctx). */
|
|
17
|
+
handler<Req extends ExpressRequestLike = ExpressRequestLike, Res extends ExpressResponseLike = ExpressResponseLike>(handler: VerifiedExpressHandler<Req, Res>): ExpressMiddleware;
|
|
16
18
|
/** The dev harness attached to this runtime. */
|
|
17
19
|
dev: DevRuntime;
|
|
18
20
|
};
|
|
@@ -38,6 +38,13 @@ export type SignedRequestSpec = {
|
|
|
38
38
|
privateJwk?: JsonWebKey;
|
|
39
39
|
/** Key id stamped into `x-fs-key-id`. Defaults to {@link TEST_KID}. */
|
|
40
40
|
kid?: string;
|
|
41
|
+
/**
|
|
42
|
+
* Consumer-principal wave (D3) — the signed `X-Fs-Context` JWT to bind into
|
|
43
|
+
* the request signature (and stamp as the `x-fs-context` header). Its SHA-256
|
|
44
|
+
* is appended to the canonical string, exactly as the gateway signer does. A
|
|
45
|
+
* missing token binds the empty-string hash (identity-less request).
|
|
46
|
+
*/
|
|
47
|
+
contextToken?: string;
|
|
41
48
|
};
|
|
42
49
|
/**
|
|
43
50
|
* Produce a valid signed claim + the X-FS-* header bag. Returns both the verify
|
|
@@ -63,10 +70,11 @@ export declare function unreachableJwks(): JwksClient;
|
|
|
63
70
|
/**
|
|
64
71
|
* Mint an HS256-signed `X-Fs-Context` token — the exact INVERSE of
|
|
65
72
|
* `verifyContext.ts`. The header is `{alg:"HS256",typ:"JWT",kid}` and the
|
|
66
|
-
* payload is the
|
|
67
|
-
* /
|
|
68
|
-
*
|
|
69
|
-
* (`contextSecrets` /
|
|
73
|
+
* payload is the cv=2 `ConsumerContextClaims` shape (sub / client_id? / act? /
|
|
74
|
+
* subjectKind / org / businessId / compiledPlanId / subscriptionId /
|
|
75
|
+
* subscriberId / environmentId / subjectKey plus optional permissions / roles).
|
|
76
|
+
* Signs with the same secret the SDK would verify against (`contextSecrets` /
|
|
77
|
+
* `FS_CONTEXT_SECRETS`).
|
|
70
78
|
*/
|
|
71
79
|
export declare function signContextToken(claim: FartherShoreSignedContext, secret?: string, kid?: string): Promise<string>;
|
|
72
80
|
export type DevSignerKeys = {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@farthershore/backend",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.16.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",
|
|
@@ -30,16 +30,17 @@
|
|
|
30
30
|
},
|
|
31
31
|
"files": [
|
|
32
32
|
"dist",
|
|
33
|
-
"README.md"
|
|
33
|
+
"README.md",
|
|
34
|
+
"CHANGELOG.md"
|
|
34
35
|
],
|
|
35
36
|
"publishConfig": {
|
|
36
37
|
"access": "public"
|
|
37
38
|
},
|
|
38
39
|
"optionalDependencies": {
|
|
39
40
|
"@farthershore/cloudflared-linux-x64": "0.0.0",
|
|
40
|
-
"@farthershore/cloudflared-darwin-arm64": "0.0.0",
|
|
41
41
|
"@farthershore/cloudflared-linux-arm64": "0.0.0",
|
|
42
|
-
"@farthershore/cloudflared-darwin-x64": "0.0.0"
|
|
42
|
+
"@farthershore/cloudflared-darwin-x64": "0.0.0",
|
|
43
|
+
"@farthershore/cloudflared-darwin-arm64": "0.0.0"
|
|
43
44
|
},
|
|
44
45
|
"peerDependencies": {
|
|
45
46
|
"express": "^4.0.0 || ^5.0.0"
|