@farthershore/backend 0.15.0 → 0.17.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 +83 -0
- package/README.md +1 -1
- package/dist/adapters/express.js +66 -2
- package/dist/generated/runtime-contract.js +11 -5
- package/dist/index.js +325 -154
- package/dist/testing/index.js +272 -142
- package/dist/types/adapters/express.d.ts +55 -5
- package/dist/types/core/errors.d.ts +4 -1
- 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 -31
- package/dist/types/core/subject.d.ts +45 -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 +7 -3
- package/dist/types/index.d.ts +17 -8
- 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 +12 -11
- package/dist/types/testing/devRuntime.d.ts +3 -1
- package/dist/types/testing/signers.d.ts +12 -4
- package/package.json +5 -4
package/dist/types/index.d.ts
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import { FartherShore, type FartherShoreInitOptions } 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
|
export { FartherShore } from "./core/runtime.js";
|
|
4
4
|
export type { FartherShoreInitOptions } from "./core/runtime.js";
|
|
5
5
|
export { FartherShoreError, statusForCode } from "./core/errors.js";
|
|
6
6
|
export { verifyRequest, type VerifyRequestInput, type VerifyRequestDeps, type FartherShoreRequestContext, type HeadersLike, } from "./core/verifyRequest.js";
|
|
7
|
-
export { verifyContext } from "./core/verifyContext.js";
|
|
8
|
-
export type { FartherShoreSignedContext } from "./core/verifyContext.js";
|
|
9
|
-
export {
|
|
7
|
+
export { verifyContext, decodeContextClaims, principalFromContextClaims, } from "./core/verifyContext.js";
|
|
8
|
+
export type { FartherShoreSignedContext, ConsumerPrincipal, } from "./core/verifyContext.js";
|
|
9
|
+
export { requireMember, requireService, credentialKind, isPortalSession, type MemberSubject, type ServiceSubject, type PrincipalCarrier, } from "./core/subject.js";
|
|
10
|
+
export { hasPermission, requirePermission, permissionGrants, permissionSatisfies, FartherShorePermissionError, type PermissionCarrier, } from "./core/permissions.js";
|
|
10
11
|
export { JwksClient, type Jwk, type JwksClientOptions } from "./core/jwks.js";
|
|
11
|
-
export { NonceCache, type NonceCacheOptions } from "./core/nonceCache.js";
|
|
12
|
+
export { NonceCache, type NonceCacheOptions, type NonceStore, } from "./core/nonceCache.js";
|
|
12
13
|
export { BootstrapClient, type BootstrapClientOptions, } from "./core/bootstrap.js";
|
|
13
14
|
export { MeteringClient, type MeteringClientOptions, type MeterOptions, } from "./core/metering.js";
|
|
14
15
|
export { PostStreamUsageClient, type PostStreamUsageClientOptions, type ReportUsageInput, type RequestScopedReportUsageInput, type ReportUsageResult, } from "./core/post-stream-usage.js";
|
|
@@ -16,8 +17,8 @@ export { buildHealthReport, reportHealth, type HealthSnapshot, type HealthStatus
|
|
|
16
17
|
export { ShutdownManager, type ShutdownHook } from "./core/shutdown.js";
|
|
17
18
|
export { CloudflaredSupervisor, nodeSpawn, REDACTED_TOKEN, type SpawnFn, type SpawnedTunnelProcess, type CloudflaredSupervisorOptions, type TunnelState, type TunnelStatus, } from "./core/tunnel.js";
|
|
18
19
|
export type { FartherShoreTunnelOptions } from "./core/runtime.js";
|
|
19
|
-
export { createExpressMiddleware, type ExpressMiddleware, type ExpressRequestLike, type ExpressResponseLike, type ExpressNext, type MiddlewareOptions, } from "./adapters/express.js";
|
|
20
|
-
export { FS_RUNTIME_TOKEN_ENV, RUNTIME_TOKEN_PREFIXES,
|
|
20
|
+
export { createExpressMiddleware, createExpressHandler, type ExpressMiddleware, type ExpressRequestLike, type ExpressResponseLike, type ExpressNext, type MiddlewareOptions, type VerifiedExpressHandler, type VerifiedPrincipalContext, } from "./adapters/express.js";
|
|
21
|
+
export { FS_RUNTIME_TOKEN_ENV, RUNTIME_TOKEN_PREFIXES, RUNTIME_TOKEN_OPERATIONS, RUNTIME_HEADER_NAMES, RUNTIME_CLOCK_SKEW_SECONDS, RUNTIME_REPLAY_WINDOW_SECONDS, EMPTY_BODY_SHA256, STREAMING_EXEMPT_BODY_HASH, MAX_BODY_BYTES, type RuntimeErrorCode, type RuntimeTokenOperation, type CanonicalSigningInput, type RuntimeBootstrapResponse, type RuntimeMeteringEvent, type RuntimeHealthReport, type TransportMode, RUNTIME_ERROR_CODE_TO_ERROR_CODE, runtimeErrorToErrorCode, type LimitDescriptor, type RuntimeMappedErrorCode, } from "./runtime-types.js";
|
|
21
22
|
export { RUNTIME_ERROR_CODES } from "./generated/runtime-contract.js";
|
|
22
23
|
export { hashBody, buildCanonicalSigningString, canonicalizeQuery, signCanonicalString, verifyCanonicalSignature, runtimeTokenKind, } from "./runtime-signing.js";
|
|
23
24
|
export { createUsage, withUsage, computeMeteringHeaders, MeteringError, METERING_PAYLOAD_HEADER, METERING_SIGNATURE_HEADER, METERING_TOKEN_HEADER, DEFAULT_TOKEN_ENV, type UsageMap, type UsageReporter, type MeteringOptions, type MeteringHeaders, type ComputeMeteringOptions, type ResponseMeteringUsagePayload, } from "./response-metering.js";
|
|
@@ -27,8 +28,16 @@ export { createUsage, withUsage, computeMeteringHeaders, MeteringError, METERING
|
|
|
27
28
|
* (the Express adapter) bound to itself.
|
|
28
29
|
*/
|
|
29
30
|
export type FartherShoreInstance = FartherShore & {
|
|
30
|
-
/** Express middleware: fail-closed verify → req.fartherShore. */
|
|
31
|
+
/** Express middleware: strict fail-closed verify → req.fartherShore (+ strip x-fs-*). */
|
|
31
32
|
middleware(options?: MiddlewareOptions): ExpressMiddleware;
|
|
33
|
+
/**
|
|
34
|
+
* Wrap a route handler so it runs only with a GUARANTEED verified PRINCIPAL —
|
|
35
|
+
* the handler's first argument is a {@link VerifiedPrincipalContext} whose
|
|
36
|
+
* `principal` is NON-OPTIONAL. Fails closed (401 `context_unverified` when the
|
|
37
|
+
* context is absent, `principal_required` when it is identity-less) before the
|
|
38
|
+
* callback runs. Pairs with the strict `middleware()`.
|
|
39
|
+
*/
|
|
40
|
+
handler<Req extends ExpressRequestLike = ExpressRequestLike, Res extends ExpressResponseLike = ExpressResponseLike>(handler: VerifiedExpressHandler<Req, Res>): ExpressMiddleware;
|
|
32
41
|
};
|
|
33
42
|
export declare const fartherShore: {
|
|
34
43
|
/** Derive everything from FS_RUNTIME_TOKEN via bootstrap. */
|
|
@@ -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
|
|
@@ -119,8 +119,8 @@ export declare const RUNTIME_TOKEN_PREFIXES: {
|
|
|
119
119
|
readonly test: "fsrt_test_";
|
|
120
120
|
};
|
|
121
121
|
export type RuntimeTokenKind = keyof typeof RUNTIME_TOKEN_PREFIXES;
|
|
122
|
-
export declare const
|
|
123
|
-
export type
|
|
122
|
+
export declare const RUNTIME_TOKEN_OPERATIONS: readonly ["gateway_verification", "metering", "health", "tunnel", "drift_report"];
|
|
123
|
+
export type RuntimeTokenOperation = (typeof RUNTIME_TOKEN_OPERATIONS)[number];
|
|
124
124
|
export declare const RUNTIME_HEADER_NAMES: {
|
|
125
125
|
readonly signature: "x-fs-signature";
|
|
126
126
|
readonly keyId: "x-fs-key-id";
|
|
@@ -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";
|
|
@@ -234,7 +237,7 @@ export type RuntimeBootstrapResponse = {
|
|
|
234
237
|
id: string | null;
|
|
235
238
|
kind: RuntimeEnvironmentKind;
|
|
236
239
|
};
|
|
237
|
-
|
|
240
|
+
operations: RuntimeTokenOperation[];
|
|
238
241
|
verification: RuntimeVerificationConfig;
|
|
239
242
|
metering: RuntimeMeteringConfig;
|
|
240
243
|
transport: RuntimeTransportConfig;
|
|
@@ -270,8 +273,6 @@ export type RuntimePostStreamUsageEvent = {
|
|
|
270
273
|
measureContext?: Record<string, unknown>;
|
|
271
274
|
signature: string;
|
|
272
275
|
};
|
|
273
|
-
export declare const RUNTIME_READINESS_STATES: readonly ["UNKNOWN", "WAITING", "READY", "DEGRADED", "OFFLINE"];
|
|
274
|
-
export type RuntimeReadinessState = (typeof RUNTIME_READINESS_STATES)[number];
|
|
275
276
|
export type RuntimeHealthReport = {
|
|
276
277
|
runtimeToken: boolean;
|
|
277
278
|
bootstrap: boolean;
|
|
@@ -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.17.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"
|