@crouter/api 0.3.396 → 0.3.397

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.
@@ -5,7 +5,8 @@ export type { ErrorBody } from './errors.js';
5
5
  export { errorCodes } from './error-codes.js';
6
6
  export type { ErrorCode, ErrorEnvelope, ErrorOrigin, ErrorType } from './error-codes.js';
7
7
  export { API_VERSION, routes } from './routes.js';
8
- export { RUNTIME_VERSION_HEADER, compareReleaseVersions } from './runtime-version.js';
8
+ export { RUNTIME_VERSION_HEADER, MINIMUM_RUNTIME_VERSION_HEADER, compareReleaseVersions, minimumRuntimeRefusal } from './runtime-version.js';
9
+ export type { MinimumRuntimeRefusal } from './runtime-version.js';
9
10
  export * from '../shared/generated-context.js';
10
11
  export * from './dto/common.js';
11
12
  export * from './dto/health.js';
package/dist/api/index.js CHANGED
@@ -5,7 +5,7 @@ export { CrtrClient, waitForDaemonAvailability } from './client.js';
5
5
  export { APIError, ApiError, isErrorBody } from './errors.js';
6
6
  export { errorCodes } from './error-codes.js';
7
7
  export { API_VERSION, routes } from './routes.js';
8
- export { RUNTIME_VERSION_HEADER, compareReleaseVersions } from './runtime-version.js';
8
+ export { RUNTIME_VERSION_HEADER, MINIMUM_RUNTIME_VERSION_HEADER, compareReleaseVersions, minimumRuntimeRefusal } from './runtime-version.js';
9
9
  export * from '../shared/generated-context.js';
10
10
  export * from './dto/common.js';
11
11
  export * from './dto/health.js';
@@ -4,3 +4,28 @@ export declare const RUNTIME_VERSION_HEADER = "Crouter-Runtime-Version";
4
4
  * suffix is ignored). Negative when `a` is older, zero when equal, positive when
5
5
  * newer. A version that does not parse sorts below every version that does. */
6
6
  export declare function compareReleaseVersions(a: string, b: string): number;
7
+ /** Request header naming the oldest runtime release the caller accepts, e.g. `0.3.396`. The SDK sends its own
8
+ * version on every request except `/healthz`. Optional: absent means no check. The router in front of a hosted
9
+ * runtime and the runtime itself each refuse a request that names a newer release than the runtime's, before any
10
+ * handler runs (so nothing is accepted and no idempotency key is recorded). */
11
+ export declare const MINIMUM_RUNTIME_VERSION_HEADER = "Crouter-Minimum-Runtime-Version";
12
+ /** The refusal a runtime answers instead of handling a request, or `null` when the request may be handled.
13
+ * - `required` absent: handled.
14
+ * - `required` not `major.minor.patch` (optional `v`, optional suffix): 400 `invalid_request`.
15
+ * - `runtimeVersion` older than `required`, or not a release version: 426 `runtime_version_unsupported`
16
+ * (details `{sdk_version, runtime_version}`, the SDK's `RuntimeVersionDetails`). */
17
+ export type MinimumRuntimeRefusal = {
18
+ status: 400;
19
+ code: 'invalid_request';
20
+ message: string;
21
+ param: string;
22
+ } | {
23
+ status: 426;
24
+ code: 'runtime_version_unsupported';
25
+ message: string;
26
+ details: {
27
+ sdk_version: string;
28
+ runtime_version: string | null;
29
+ };
30
+ };
31
+ export declare function minimumRuntimeRefusal(required: string | undefined, runtimeVersion: string | null): MinimumRuntimeRefusal | null;
@@ -26,3 +26,25 @@ function parseRelease(version) {
26
26
  const match = /^v?(\d+)\.(\d+)\.(\d+)(?:[-+].*)?$/.exec(version.trim());
27
27
  return match === null ? null : [Number(match[1]), Number(match[2]), Number(match[3])];
28
28
  }
29
+ /** Request header naming the oldest runtime release the caller accepts, e.g. `0.3.396`. The SDK sends its own
30
+ * version on every request except `/healthz`. Optional: absent means no check. The router in front of a hosted
31
+ * runtime and the runtime itself each refuse a request that names a newer release than the runtime's, before any
32
+ * handler runs (so nothing is accepted and no idempotency key is recorded). */
33
+ export const MINIMUM_RUNTIME_VERSION_HEADER = 'Crouter-Minimum-Runtime-Version';
34
+ export function minimumRuntimeRefusal(required, runtimeVersion) {
35
+ if (required === undefined)
36
+ return null;
37
+ if (parseRelease(required) === null) {
38
+ return { status: 400, code: 'invalid_request', param: MINIMUM_RUNTIME_VERSION_HEADER, message: `${MINIMUM_RUNTIME_VERSION_HEADER} must be a release version like 0.3.396.` };
39
+ }
40
+ if (runtimeVersion !== null && parseRelease(runtimeVersion) !== null && compareReleaseVersions(runtimeVersion, required) >= 0)
41
+ return null;
42
+ const sdkVersion = required.trim();
43
+ return {
44
+ status: 426, code: 'runtime_version_unsupported',
45
+ message: runtimeVersion === null
46
+ ? `The runtime did not name its version; the caller requires a runtime at ${sdkVersion} or later. Roll the runtime forward.`
47
+ : `The runtime is ${runtimeVersion}; the caller requires a runtime at ${sdkVersion} or later. Roll the runtime forward.`,
48
+ details: { sdk_version: sdkVersion, runtime_version: runtimeVersion },
49
+ };
50
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crouter/api",
3
- "version": "0.3.396",
3
+ "version": "0.3.397",
4
4
  "description": "Typed crtrd /v1 API contract — DTOs, route builders, the error contract, the CrtrClient, and the command-plugin manifest format. Zero runtime dependencies.",
5
5
  "type": "module",
6
6
  "main": "./dist/api/index.js",