@eco-foundation/api-schemas 0.12.0 → 0.13.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/README.md +68 -13
- package/dist/generated/build-digest.json +1 -1
- package/dist/v1/errors/catalog.d.ts +7 -0
- package/dist/v1/errors/catalog.js +1 -0
- package/dist/v1/errors/catalog.js.map +1 -1
- package/dist/v1/index.d.ts +1 -0
- package/dist/v1/index.js +1 -0
- package/dist/v1/index.js.map +1 -1
- package/dist/v1/maintenance/schema.d.ts +30 -0
- package/dist/v1/maintenance/schema.js +65 -0
- package/dist/v1/maintenance/schema.js.map +1 -0
- package/errors/catalog.lock.json +5 -0
- package/fixtures/maintenance-boundaries.json +405 -0
- package/openapi/v1.json +8 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@ Zod-first schemas, error catalog, golden fixtures, and generated OpenAPI 3.1 for
|
|
|
4
4
|
API. The Zod schemas are the source of truth; everything else (OpenAPI, fixtures, plain types)
|
|
5
5
|
is generated from or gated against them.
|
|
6
6
|
|
|
7
|
-
Today the package covers **13 endpoints across 12 paths**, **
|
|
7
|
+
Today the package covers **13 endpoints across 12 paths**, **40 error codes** (51 namespaced
|
|
8
8
|
legacy references), and **21 golden fixtures**.
|
|
9
9
|
|
|
10
10
|
## Install
|
|
@@ -14,13 +14,13 @@ While the package is 0.x, pin the patch range or the exact version:
|
|
|
14
14
|
```json
|
|
15
15
|
{
|
|
16
16
|
"dependencies": {
|
|
17
|
-
"@eco-foundation/api-schemas": "~0.
|
|
17
|
+
"@eco-foundation/api-schemas": "~0.13.0"
|
|
18
18
|
}
|
|
19
19
|
}
|
|
20
20
|
```
|
|
21
21
|
|
|
22
22
|
**Never write `^0`.** npm resolves `^0.x` as `>=0.0.0 <1.0.0`, so it silently accepts every
|
|
23
|
-
future breaking `0.y` — it is not a pin at all. Use `~0.
|
|
23
|
+
future breaking `0.y` — it is not a pin at all. Use `~0.13.0` or the exact `0.13.0`.
|
|
24
24
|
|
|
25
25
|
A matching version string is not evidence of a matching artifact: also compare
|
|
26
26
|
`V1_SCHEMA_DIGEST` (see [Invariants](#invariants-enforced-in-ci)). Two builds both called
|
|
@@ -30,6 +30,55 @@ A matching version string is not evidence of a matching artifact: also compare
|
|
|
30
30
|
zod-bearing entry point. Which case you are in is decided entirely by your imports; see
|
|
31
31
|
[Consumers](#consumers).
|
|
32
32
|
|
|
33
|
+
## Migrating 0.12.0 -> 0.13.0
|
|
34
|
+
|
|
35
|
+
**BREAKING under 0.x semver only for exhaustive handling of `V1ErrorCode`.** Nothing on the wire
|
|
36
|
+
that `0.12.0` accepted is rejected and no response shape changes. The release adds one error code,
|
|
37
|
+
one config schema, and one fixture file for scheduled maintenance windows (PER-673).
|
|
38
|
+
|
|
39
|
+
**`V1_SCHEMA_DIGEST` MOVES** to
|
|
40
|
+
`e5a684f678f80135ddf7241029d965d2a206b3b573a9969ad1352610d1b4abc9`, because both digest inputs
|
|
41
|
+
changed (`errors/catalog.lock.json` gained one code and `openapi/v1.json` its `x-error-catalog`
|
|
42
|
+
entry). Every consumer running `assertNoSkew` moves in the same rollout.
|
|
43
|
+
|
|
44
|
+
**1. New error code `maintenance` (503, audience `all`, no legacy codes).** It is a planned stop,
|
|
45
|
+
distinct from `service-unavailable` (an outage). eco-router, eco-quotes and deposit-addresses
|
|
46
|
+
return it from every quote-creating and address-creating endpoint while a configured window is
|
|
47
|
+
active, with `startsAt`/`endsAt` in the body and a `Retry-After` header. `V1ProblemSchema` now
|
|
48
|
+
checks a `maintenance` body's `status`/`type` against the catalog, and an exhaustive `switch`
|
|
49
|
+
over `V1ErrorCode` stops compiling until it handles the new member. That is the breaking item.
|
|
50
|
+
|
|
51
|
+
**2. New config schemas `MaintenanceWindowSchema` and `MaintenanceConfigSchema`** (on the `v1`
|
|
52
|
+
namespace, with types `MaintenanceWindow`, `MaintenanceConfig`, `MaintenanceConfigInput`). A
|
|
53
|
+
window is `{ startsAt, endsAt, message }`: `startsAt` inclusive, `endsAt` exclusive, both
|
|
54
|
+
ISO-8601 UTC strings ending in `Z` with at most three fractional digits (offsets and impossible
|
|
55
|
+
dates such as `2026-02-30` are rejected), `message` 1-200 characters and not blank (whitespace-only
|
|
56
|
+
is rejected — it is echoed verbatim to partners), and `endsAt` must be after `startsAt`. `windows`
|
|
57
|
+
defaults to `[]`. Both schemas reject any key not in their shape (e.g. a `window` typo for
|
|
58
|
+
`windows`) at parse time, naming the key — this is scoped to the raw input's own enumerable
|
|
59
|
+
properties, so a config object read through node-config (whose hidden, non-enumerable `get`/`has`/
|
|
60
|
+
`util` helpers are unaffected) still parses. Overlapping windows are allowed; past windows are valid
|
|
61
|
+
(services drop them at boot). **Quote the timestamps in YAML**: an unquoted
|
|
62
|
+
`2026-10-04T02:00:00Z` is loaded as a `Date` and fails with "quote it in YAML". There is no
|
|
63
|
+
`./v1/maintenance` subpath, because the schemas need zod anyway, so import them from the root
|
|
64
|
+
`v1` namespace.
|
|
65
|
+
|
|
66
|
+
**3. New fixture `fixtures/maintenance-boundaries.json`** (served by the existing `./fixtures/*`
|
|
67
|
+
subpath). Each entry service implements its own resolver (the package deliberately ships none)
|
|
68
|
+
and asserts it against every vector: active when `startsAt <= now < endsAt`; with several
|
|
69
|
+
active, the latest `endsAt` wins and a tie goes to the first in the list;
|
|
70
|
+
`retryAfterSeconds = max(1, ceil((endsAt - now) / 1000))`.
|
|
71
|
+
|
|
72
|
+
**4. Consumers** pin `~0.13.0` (never `^0`) and re-run `assertNoSkew`. No golden fixture under
|
|
73
|
+
`src/fixtures/v1` changed.
|
|
74
|
+
|
|
75
|
+
**5. The `zod` peer range rises to `^4.4.0`** (from `^4.3.0`), still optional. The maintenance
|
|
76
|
+
schemas' exported types (`MaintenanceWindowSchema`, `MaintenanceConfigSchema`) use
|
|
77
|
+
`z.ZodPreprocess`, which zod only exports from 4.4 — on zod 4.3.x those `.d.ts` types silently
|
|
78
|
+
collapse to `any` under `skipLibCheck` (and fail `TS2724` without it). A consumer that imports
|
|
79
|
+
zod-bearing entry points must upgrade to zod `^4.4.0`+ before adopting `0.13.0`; the two
|
|
80
|
+
zod-free subpaths (`./v1/signature`, `./v1/types`) are unaffected.
|
|
81
|
+
|
|
33
82
|
## Migrating 0.11.0 -> 0.12.0
|
|
34
83
|
|
|
35
84
|
**Non-breaking for callers, a new version for consumers.** `GET /v1/intents/status` now accepts
|
|
@@ -989,7 +1038,7 @@ must: it is the artifact identity, not the version string.
|
|
|
989
1038
|
declared optional (`peerDependenciesMeta: { zod: { optional: true } }`), because for two of the
|
|
990
1039
|
published entry points it is genuinely not needed:
|
|
991
1040
|
|
|
992
|
-
- **Needs `zod` (`^4.
|
|
1041
|
+
- **Needs `zod` (`^4.4.0`):** the bare package name `.`, `./testing`, and anything reached
|
|
993
1042
|
through the `v1` namespace on either. These load schema modules, and their `.d.ts` names zod
|
|
994
1043
|
types.
|
|
995
1044
|
- **Needs NO `zod`:** `./v1/signature` (runtime code importing `@noble/hashes` and nothing else)
|
|
@@ -998,8 +1047,8 @@ published entry points it is genuinely not needed:
|
|
|
998
1047
|
|
|
999
1048
|
Read `optional` narrowly: it says zod **may be absent**, not that any zod version works. pnpm
|
|
1000
1049
|
suppresses the unmet-peer warning only when zod is MISSING (verified against pnpm 10.16); a
|
|
1001
|
-
consumer that HAS a zod outside `^4.
|
|
1002
|
-
`unmet peer zod@^4.
|
|
1050
|
+
consumer that HAS a zod outside `^4.4.0` — solver-v2, on zod 3 — still sees
|
|
1051
|
+
`unmet peer zod@^4.4.0: found <version>`, since that is a version mismatch rather than a missing
|
|
1003
1052
|
peer. Suppressing that one is the consumer's own call
|
|
1004
1053
|
(`pnpm.peerDependencyRules.allowedVersions`), and it is safe exactly while its imports are
|
|
1005
1054
|
limited to the two zod-free subpaths above. The range itself cannot be widened — the schemas
|
|
@@ -1007,14 +1056,16 @@ require Zod 4.
|
|
|
1007
1056
|
|
|
1008
1057
|
Zod-major compatibility is the reason there are two interfaces, not one:
|
|
1009
1058
|
|
|
1010
|
-
- **Zod-4 consumers** (eco-router `^4.4.3
|
|
1011
|
-
|
|
1059
|
+
- **Zod-4 consumers** (eco-router `^4.4.3`) import the schemas directly. Since `0.2.0`, `zod` is
|
|
1060
|
+
a **`peerDependency` with a range (`^4.4.0` since `0.13.0`, raised from `^4.3.0`)** — optional
|
|
1012
1061
|
since `0.3.1` — not a hard-pinned dependency: the consumer's own single copy satisfies it. For
|
|
1013
|
-
these consumers optional changes nothing; they must still install zod.
|
|
1014
|
-
|
|
1015
|
-
|
|
1062
|
+
these consumers optional changes nothing; they must still install zod. deposit-addresses'
|
|
1063
|
+
prior `^4.3.5` install is now below the floor and must upgrade to `^4.4.0`+ to consume `0.13.0`
|
|
1064
|
+
— see [Migrating 0.12.0 -> 0.13.0](#migrating-0120---0130). The previous exact `dependencies`
|
|
1065
|
+
pin at `4.4.3` materialised a SECOND nested zod for every consumer not on that exact version,
|
|
1066
|
+
and two zod instances in one type graph is the documented failure — `TS2345` on
|
|
1016
1067
|
`_zod.version.minor` when a package schema is passed to a local `z.ZodType<T>`, and `tsc`
|
|
1017
|
-
OOMing at 4 GB with no message. A consumer therefore installs zod itself (any `4.
|
|
1068
|
+
OOMing at 4 GB with no message. A consumer therefore installs zod itself (any `4.4.x`+ `4.x`);
|
|
1018
1069
|
the package keeps an exact `4.4.3` **devDependency** so its own build and its generated
|
|
1019
1070
|
OpenAPI stay byte-stable.
|
|
1020
1071
|
- **solver-v2 is on Zod 3 and must never be forced to Zod 4.** It consumes the zod-free
|
|
@@ -1041,6 +1092,7 @@ Zod-major compatibility is the reason there are two interfaces, not one:
|
|
|
1041
1092
|
| `./openapi/v1.json` | the generated OpenAPI 3.1 document |
|
|
1042
1093
|
| `./fixtures/signature-hash/vectors.json` | cross-repo `signatureHash` vectors |
|
|
1043
1094
|
| `./fixtures/quote-signature/vector-*.json` | cross-repo F3 quote-signature (EIP-712) vectors |
|
|
1095
|
+
| `./fixtures/maintenance-boundaries.json` | cross-repo maintenance-window (PER-673) resolver boundary vectors |
|
|
1044
1096
|
|
|
1045
1097
|
## Fixtures
|
|
1046
1098
|
|
|
@@ -1057,7 +1109,10 @@ There are two fixture locations and they serve different jobs — do not conflat
|
|
|
1057
1109
|
`fixtures/signature-hash/vectors.json` (the `signatureHash` canonicalization contract) and
|
|
1058
1110
|
`fixtures/quote-signature/vector-*.json` (the F3 EIP-712 `EcoQuoteV1` vectors, each with its
|
|
1059
1111
|
`digest`, `signature`, and `signer`; the signing key is derived from a public domain string,
|
|
1060
|
-
so this repo ships no private-key bytes).
|
|
1112
|
+
so this repo ships no private-key bytes), and `fixtures/maintenance-boundaries.json` (the
|
|
1113
|
+
PER-673 maintenance-window boundary vectors: `{ name, windows, nowIso, expected }`, which each
|
|
1114
|
+
entry service's local resolver asserts; this package's own suite checks every vector against a
|
|
1115
|
+
reference resolver kept in the spec file, so a wrong `expected` fails here first).
|
|
1061
1116
|
|
|
1062
1117
|
`routes.list` is the one fixture tagged `stability: 'draft'`. A live-replay consumer skips it
|
|
1063
1118
|
with the reason `draft endpoint (x-stability: draft) — not served at launch` instead of
|
|
@@ -280,6 +280,13 @@ export declare const V1_ERROR_CATALOG: readonly [{
|
|
|
280
280
|
readonly type: string;
|
|
281
281
|
readonly audience: "read" | "write" | "all";
|
|
282
282
|
readonly legacyCodes: readonly LegacyCodeRef[];
|
|
283
|
+
}, {
|
|
284
|
+
readonly code: "maintenance";
|
|
285
|
+
readonly status: number;
|
|
286
|
+
readonly title: string;
|
|
287
|
+
readonly type: string;
|
|
288
|
+
readonly audience: "read" | "write" | "all";
|
|
289
|
+
readonly legacyCodes: readonly LegacyCodeRef[];
|
|
283
290
|
}];
|
|
284
291
|
export type V1ErrorCode = (typeof V1_ERROR_CATALOG)[number]['code'];
|
|
285
292
|
export declare function getErrorDefinition(code: V1ErrorCode): V1ErrorDefinition;
|
|
@@ -109,6 +109,7 @@ exports.V1_ERROR_CATALOG = [
|
|
|
109
109
|
]),
|
|
110
110
|
define('solver-error', 502, 'An upstream solver rejected or failed the quote request', 'all'),
|
|
111
111
|
define('service-unavailable', 503, 'Service temporarily unavailable', 'all'),
|
|
112
|
+
define('maintenance', 503, 'Scheduled maintenance: new quotes and deposit addresses are paused until the window ends', 'all'),
|
|
112
113
|
];
|
|
113
114
|
const BY_CODE = new Map(exports.V1_ERROR_CATALOG.map((e) => [e.code, e]));
|
|
114
115
|
function getErrorDefinition(code) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"catalog.js","sourceRoot":"","sources":["../../../src/v1/errors/catalog.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"catalog.js","sourceRoot":"","sources":["../../../src/v1/errors/catalog.ts"],"names":[],"mappings":"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"}
|
package/dist/v1/index.d.ts
CHANGED
|
@@ -9,6 +9,7 @@ export * from './endpoints/tokens';
|
|
|
9
9
|
export * from './enums';
|
|
10
10
|
export * from './errors/catalog';
|
|
11
11
|
export * from './errors/problem';
|
|
12
|
+
export * from './maintenance/schema';
|
|
12
13
|
export * from './primitives';
|
|
13
14
|
export * from './signature';
|
|
14
15
|
export declare const V1_API_VERSION: "v1";
|
package/dist/v1/index.js
CHANGED
|
@@ -26,6 +26,7 @@ __exportStar(require("./endpoints/tokens"), exports);
|
|
|
26
26
|
__exportStar(require("./enums"), exports);
|
|
27
27
|
__exportStar(require("./errors/catalog"), exports);
|
|
28
28
|
__exportStar(require("./errors/problem"), exports);
|
|
29
|
+
__exportStar(require("./maintenance/schema"), exports);
|
|
29
30
|
__exportStar(require("./primitives"), exports);
|
|
30
31
|
__exportStar(require("./signature"), exports);
|
|
31
32
|
exports.V1_API_VERSION = 'v1';
|
package/dist/v1/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/v1/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAAA,qDAAmC;AACnC,gEAA8C;AAC9C,qDAAmC;AACnC,uDAAqC;AACrC,qDAAmC;AACnC,qDAAmC;AACnC,qDAAmC;AACnC,qDAAmC;AACnC,0CAAwB;AACxB,mDAAiC;AACjC,mDAAiC;AACjC,+CAA6B;AAC7B,8CAA4B;AAEf,QAAA,cAAc,GAAG,IAAa,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/v1/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAAA,qDAAmC;AACnC,gEAA8C;AAC9C,qDAAmC;AACnC,uDAAqC;AACrC,qDAAmC;AACnC,qDAAmC;AACnC,qDAAmC;AACnC,qDAAmC;AACnC,0CAAwB;AACxB,mDAAiC;AACjC,mDAAiC;AACjC,uDAAqC;AACrC,+CAA6B;AAC7B,8CAA4B;AAEf,QAAA,cAAc,GAAG,IAAa,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const MAINTENANCE_MESSAGE_MAX_LENGTH = 200;
|
|
3
|
+
declare const MaintenanceWindowShape: z.ZodObject<{
|
|
4
|
+
startsAt: z.ZodString;
|
|
5
|
+
endsAt: z.ZodString;
|
|
6
|
+
message: z.ZodString;
|
|
7
|
+
}, z.core.$strip>;
|
|
8
|
+
export declare const MaintenanceWindowSchema: z.ZodPreprocess<z.ZodObject<{
|
|
9
|
+
startsAt: z.ZodString;
|
|
10
|
+
endsAt: z.ZodString;
|
|
11
|
+
message: z.ZodString;
|
|
12
|
+
}, z.core.$strip>>;
|
|
13
|
+
export type MaintenanceWindow = z.infer<typeof MaintenanceWindowShape>;
|
|
14
|
+
declare const MaintenanceConfigShape: z.ZodObject<{
|
|
15
|
+
windows: z.ZodDefault<z.ZodArray<z.ZodPreprocess<z.ZodObject<{
|
|
16
|
+
startsAt: z.ZodString;
|
|
17
|
+
endsAt: z.ZodString;
|
|
18
|
+
message: z.ZodString;
|
|
19
|
+
}, z.core.$strip>>>>;
|
|
20
|
+
}, z.core.$strip>;
|
|
21
|
+
export declare const MaintenanceConfigSchema: z.ZodPreprocess<z.ZodObject<{
|
|
22
|
+
windows: z.ZodDefault<z.ZodArray<z.ZodPreprocess<z.ZodObject<{
|
|
23
|
+
startsAt: z.ZodString;
|
|
24
|
+
endsAt: z.ZodString;
|
|
25
|
+
message: z.ZodString;
|
|
26
|
+
}, z.core.$strip>>>>;
|
|
27
|
+
}, z.core.$strip>>;
|
|
28
|
+
export type MaintenanceConfig = z.infer<typeof MaintenanceConfigShape>;
|
|
29
|
+
export type MaintenanceConfigInput = z.input<typeof MaintenanceConfigShape>;
|
|
30
|
+
export {};
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MaintenanceConfigSchema = exports.MaintenanceWindowSchema = exports.MAINTENANCE_MESSAGE_MAX_LENGTH = void 0;
|
|
4
|
+
const zod_1 = require("zod");
|
|
5
|
+
const ISO_UTC_PATTERN = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d{1,3})?Z$/;
|
|
6
|
+
function isRealUtcInstant(value) {
|
|
7
|
+
const ms = Date.parse(value);
|
|
8
|
+
if (!Number.isFinite(ms))
|
|
9
|
+
return false;
|
|
10
|
+
return new Date(ms).toISOString().slice(0, 19) === value.slice(0, 19);
|
|
11
|
+
}
|
|
12
|
+
function utcMillis(value) {
|
|
13
|
+
return ISO_UTC_PATTERN.test(value) && isRealUtcInstant(value) ? Date.parse(value) : undefined;
|
|
14
|
+
}
|
|
15
|
+
const IsoUtcTimestamp = zod_1.z
|
|
16
|
+
.string({
|
|
17
|
+
error: 'must be an ISO-8601 UTC timestamp string; quote it in YAML',
|
|
18
|
+
})
|
|
19
|
+
.regex(ISO_UTC_PATTERN, 'must be an ISO-8601 UTC timestamp ending in Z, e.g. 2026-10-04T02:00:00Z')
|
|
20
|
+
.refine((value) => !ISO_UTC_PATTERN.test(value) || utcMillis(value) !== undefined, 'is not a real calendar instant');
|
|
21
|
+
exports.MAINTENANCE_MESSAGE_MAX_LENGTH = 200;
|
|
22
|
+
function rejectUnknownKeys(allowedKeys) {
|
|
23
|
+
const allowed = new Set(allowedKeys);
|
|
24
|
+
return (raw, ctx) => {
|
|
25
|
+
if (raw === null || typeof raw !== 'object' || Array.isArray(raw))
|
|
26
|
+
return raw;
|
|
27
|
+
const extra = Object.keys(raw).filter((key) => !allowed.has(key));
|
|
28
|
+
if (extra.length === 0)
|
|
29
|
+
return raw;
|
|
30
|
+
const quoted = extra.map((key) => `"${key}"`).join(', ');
|
|
31
|
+
ctx.addIssue({
|
|
32
|
+
code: 'custom',
|
|
33
|
+
message: extra.length === 1 ? `Unrecognized key: ${quoted}` : `Unrecognized keys: ${quoted}`,
|
|
34
|
+
});
|
|
35
|
+
return raw;
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
const MaintenanceWindowShape = zod_1.z
|
|
39
|
+
.object({
|
|
40
|
+
startsAt: IsoUtcTimestamp,
|
|
41
|
+
endsAt: IsoUtcTimestamp,
|
|
42
|
+
message: zod_1.z
|
|
43
|
+
.string()
|
|
44
|
+
.max(exports.MAINTENANCE_MESSAGE_MAX_LENGTH)
|
|
45
|
+
.refine((value) => value.trim().length > 0, 'must not be blank'),
|
|
46
|
+
})
|
|
47
|
+
.superRefine((window, ctx) => {
|
|
48
|
+
const startsMs = utcMillis(window.startsAt);
|
|
49
|
+
const endsMs = utcMillis(window.endsAt);
|
|
50
|
+
if (startsMs === undefined || endsMs === undefined)
|
|
51
|
+
return;
|
|
52
|
+
if (endsMs <= startsMs) {
|
|
53
|
+
ctx.addIssue({
|
|
54
|
+
code: 'custom',
|
|
55
|
+
path: ['endsAt'],
|
|
56
|
+
message: `endsAt ${window.endsAt} must be after startsAt ${window.startsAt}`,
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
exports.MaintenanceWindowSchema = zod_1.z.preprocess(rejectUnknownKeys(['startsAt', 'endsAt', 'message']), MaintenanceWindowShape);
|
|
61
|
+
const MaintenanceConfigShape = zod_1.z.object({
|
|
62
|
+
windows: zod_1.z.array(exports.MaintenanceWindowSchema).default([]),
|
|
63
|
+
});
|
|
64
|
+
exports.MaintenanceConfigSchema = zod_1.z.preprocess(rejectUnknownKeys(['windows']), MaintenanceConfigShape);
|
|
65
|
+
//# sourceMappingURL=schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../../../src/v1/maintenance/schema.ts"],"names":[],"mappings":"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"}
|
package/errors/catalog.lock.json
CHANGED
|
@@ -0,0 +1,405 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"name": "empty window list",
|
|
4
|
+
"windows": [],
|
|
5
|
+
"nowIso": "2026-10-04T03:00:00.000Z",
|
|
6
|
+
"expected": {
|
|
7
|
+
"active": false
|
|
8
|
+
}
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
"name": "one millisecond before startsAt",
|
|
12
|
+
"windows": [
|
|
13
|
+
{
|
|
14
|
+
"startsAt": "2026-10-04T02:00:00Z",
|
|
15
|
+
"endsAt": "2026-10-04T04:00:00Z",
|
|
16
|
+
"message": "Scheduled maintenance: database upgrade"
|
|
17
|
+
}
|
|
18
|
+
],
|
|
19
|
+
"nowIso": "2026-10-04T01:59:59.999Z",
|
|
20
|
+
"expected": {
|
|
21
|
+
"active": false
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"name": "exactly startsAt (start is inclusive)",
|
|
26
|
+
"windows": [
|
|
27
|
+
{
|
|
28
|
+
"startsAt": "2026-10-04T02:00:00Z",
|
|
29
|
+
"endsAt": "2026-10-04T04:00:00Z",
|
|
30
|
+
"message": "Scheduled maintenance: database upgrade"
|
|
31
|
+
}
|
|
32
|
+
],
|
|
33
|
+
"nowIso": "2026-10-04T02:00:00.000Z",
|
|
34
|
+
"expected": {
|
|
35
|
+
"active": true,
|
|
36
|
+
"startsAt": "2026-10-04T02:00:00Z",
|
|
37
|
+
"endsAt": "2026-10-04T04:00:00Z",
|
|
38
|
+
"message": "Scheduled maintenance: database upgrade",
|
|
39
|
+
"retryAfterSeconds": 7200
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"name": "mid-window",
|
|
44
|
+
"windows": [
|
|
45
|
+
{
|
|
46
|
+
"startsAt": "2026-10-04T02:00:00Z",
|
|
47
|
+
"endsAt": "2026-10-04T04:00:00Z",
|
|
48
|
+
"message": "Scheduled maintenance: database upgrade"
|
|
49
|
+
}
|
|
50
|
+
],
|
|
51
|
+
"nowIso": "2026-10-04T03:00:00.000Z",
|
|
52
|
+
"expected": {
|
|
53
|
+
"active": true,
|
|
54
|
+
"startsAt": "2026-10-04T02:00:00Z",
|
|
55
|
+
"endsAt": "2026-10-04T04:00:00Z",
|
|
56
|
+
"message": "Scheduled maintenance: database upgrade",
|
|
57
|
+
"retryAfterSeconds": 3600
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
"name": "one millisecond before endsAt",
|
|
62
|
+
"windows": [
|
|
63
|
+
{
|
|
64
|
+
"startsAt": "2026-10-04T02:00:00Z",
|
|
65
|
+
"endsAt": "2026-10-04T04:00:00Z",
|
|
66
|
+
"message": "Scheduled maintenance: database upgrade"
|
|
67
|
+
}
|
|
68
|
+
],
|
|
69
|
+
"nowIso": "2026-10-04T03:59:59.999Z",
|
|
70
|
+
"expected": {
|
|
71
|
+
"active": true,
|
|
72
|
+
"startsAt": "2026-10-04T02:00:00Z",
|
|
73
|
+
"endsAt": "2026-10-04T04:00:00Z",
|
|
74
|
+
"message": "Scheduled maintenance: database upgrade",
|
|
75
|
+
"retryAfterSeconds": 1
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
"name": "exactly endsAt (end is exclusive)",
|
|
80
|
+
"windows": [
|
|
81
|
+
{
|
|
82
|
+
"startsAt": "2026-10-04T02:00:00Z",
|
|
83
|
+
"endsAt": "2026-10-04T04:00:00Z",
|
|
84
|
+
"message": "Scheduled maintenance: database upgrade"
|
|
85
|
+
}
|
|
86
|
+
],
|
|
87
|
+
"nowIso": "2026-10-04T04:00:00.000Z",
|
|
88
|
+
"expected": {
|
|
89
|
+
"active": false
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
"name": "fractional remainder rounds up: 1.5 s before endsAt",
|
|
94
|
+
"windows": [
|
|
95
|
+
{
|
|
96
|
+
"startsAt": "2026-10-04T02:00:00Z",
|
|
97
|
+
"endsAt": "2026-10-04T04:00:00Z",
|
|
98
|
+
"message": "Scheduled maintenance: database upgrade"
|
|
99
|
+
}
|
|
100
|
+
],
|
|
101
|
+
"nowIso": "2026-10-04T03:59:58.500Z",
|
|
102
|
+
"expected": {
|
|
103
|
+
"active": true,
|
|
104
|
+
"startsAt": "2026-10-04T02:00:00Z",
|
|
105
|
+
"endsAt": "2026-10-04T04:00:00Z",
|
|
106
|
+
"message": "Scheduled maintenance: database upgrade",
|
|
107
|
+
"retryAfterSeconds": 2
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
"name": "whole-second remainder does not round up: 2 s before endsAt",
|
|
112
|
+
"windows": [
|
|
113
|
+
{
|
|
114
|
+
"startsAt": "2026-10-04T02:00:00Z",
|
|
115
|
+
"endsAt": "2026-10-04T04:00:00Z",
|
|
116
|
+
"message": "Scheduled maintenance: database upgrade"
|
|
117
|
+
}
|
|
118
|
+
],
|
|
119
|
+
"nowIso": "2026-10-04T03:59:58.000Z",
|
|
120
|
+
"expected": {
|
|
121
|
+
"active": true,
|
|
122
|
+
"startsAt": "2026-10-04T02:00:00Z",
|
|
123
|
+
"endsAt": "2026-10-04T04:00:00Z",
|
|
124
|
+
"message": "Scheduled maintenance: database upgrade",
|
|
125
|
+
"retryAfterSeconds": 2
|
|
126
|
+
}
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
"name": "past-only window",
|
|
130
|
+
"windows": [
|
|
131
|
+
{
|
|
132
|
+
"startsAt": "2026-10-01T02:00:00Z",
|
|
133
|
+
"endsAt": "2026-10-01T04:00:00Z",
|
|
134
|
+
"message": "Last week's maintenance"
|
|
135
|
+
}
|
|
136
|
+
],
|
|
137
|
+
"nowIso": "2026-10-04T03:00:00.000Z",
|
|
138
|
+
"expected": {
|
|
139
|
+
"active": false
|
|
140
|
+
}
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
"name": "future-only window",
|
|
144
|
+
"windows": [
|
|
145
|
+
{
|
|
146
|
+
"startsAt": "2026-10-11T02:00:00Z",
|
|
147
|
+
"endsAt": "2026-10-11T04:00:00Z",
|
|
148
|
+
"message": "Next week's maintenance"
|
|
149
|
+
}
|
|
150
|
+
],
|
|
151
|
+
"nowIso": "2026-10-04T03:00:00.000Z",
|
|
152
|
+
"expected": {
|
|
153
|
+
"active": false
|
|
154
|
+
}
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
"name": "past and future windows, now between them",
|
|
158
|
+
"windows": [
|
|
159
|
+
{
|
|
160
|
+
"startsAt": "2026-10-01T02:00:00Z",
|
|
161
|
+
"endsAt": "2026-10-01T04:00:00Z",
|
|
162
|
+
"message": "Last week's maintenance"
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
"startsAt": "2026-10-11T02:00:00Z",
|
|
166
|
+
"endsAt": "2026-10-11T04:00:00Z",
|
|
167
|
+
"message": "Next week's maintenance"
|
|
168
|
+
}
|
|
169
|
+
],
|
|
170
|
+
"nowIso": "2026-10-04T03:00:00.000Z",
|
|
171
|
+
"expected": {
|
|
172
|
+
"active": false
|
|
173
|
+
}
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
"name": "overlapping windows, only the first active",
|
|
177
|
+
"windows": [
|
|
178
|
+
{
|
|
179
|
+
"startsAt": "2026-10-04T02:00:00Z",
|
|
180
|
+
"endsAt": "2026-10-04T04:00:00Z",
|
|
181
|
+
"message": "A: database upgrade"
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
"startsAt": "2026-10-04T03:00:00Z",
|
|
185
|
+
"endsAt": "2026-10-04T05:00:00Z",
|
|
186
|
+
"message": "B: key rotation"
|
|
187
|
+
}
|
|
188
|
+
],
|
|
189
|
+
"nowIso": "2026-10-04T02:30:00.000Z",
|
|
190
|
+
"expected": {
|
|
191
|
+
"active": true,
|
|
192
|
+
"startsAt": "2026-10-04T02:00:00Z",
|
|
193
|
+
"endsAt": "2026-10-04T04:00:00Z",
|
|
194
|
+
"message": "A: database upgrade",
|
|
195
|
+
"retryAfterSeconds": 5400
|
|
196
|
+
}
|
|
197
|
+
},
|
|
198
|
+
{
|
|
199
|
+
"name": "overlapping windows, both active: latest endsAt wins",
|
|
200
|
+
"windows": [
|
|
201
|
+
{
|
|
202
|
+
"startsAt": "2026-10-04T02:00:00Z",
|
|
203
|
+
"endsAt": "2026-10-04T04:00:00Z",
|
|
204
|
+
"message": "A: database upgrade"
|
|
205
|
+
},
|
|
206
|
+
{
|
|
207
|
+
"startsAt": "2026-10-04T03:00:00Z",
|
|
208
|
+
"endsAt": "2026-10-04T05:00:00Z",
|
|
209
|
+
"message": "B: key rotation"
|
|
210
|
+
}
|
|
211
|
+
],
|
|
212
|
+
"nowIso": "2026-10-04T03:30:00.000Z",
|
|
213
|
+
"expected": {
|
|
214
|
+
"active": true,
|
|
215
|
+
"startsAt": "2026-10-04T03:00:00Z",
|
|
216
|
+
"endsAt": "2026-10-04T05:00:00Z",
|
|
217
|
+
"message": "B: key rotation",
|
|
218
|
+
"retryAfterSeconds": 5400
|
|
219
|
+
}
|
|
220
|
+
},
|
|
221
|
+
{
|
|
222
|
+
"name": "overlapping windows, both active, list reversed: latest endsAt still wins",
|
|
223
|
+
"windows": [
|
|
224
|
+
{
|
|
225
|
+
"startsAt": "2026-10-04T03:00:00Z",
|
|
226
|
+
"endsAt": "2026-10-04T05:00:00Z",
|
|
227
|
+
"message": "B: key rotation"
|
|
228
|
+
},
|
|
229
|
+
{
|
|
230
|
+
"startsAt": "2026-10-04T02:00:00Z",
|
|
231
|
+
"endsAt": "2026-10-04T04:00:00Z",
|
|
232
|
+
"message": "A: database upgrade"
|
|
233
|
+
}
|
|
234
|
+
],
|
|
235
|
+
"nowIso": "2026-10-04T03:30:00.000Z",
|
|
236
|
+
"expected": {
|
|
237
|
+
"active": true,
|
|
238
|
+
"startsAt": "2026-10-04T03:00:00Z",
|
|
239
|
+
"endsAt": "2026-10-04T05:00:00Z",
|
|
240
|
+
"message": "B: key rotation",
|
|
241
|
+
"retryAfterSeconds": 5400
|
|
242
|
+
}
|
|
243
|
+
},
|
|
244
|
+
{
|
|
245
|
+
"name": "overlapping windows, after the first ends",
|
|
246
|
+
"windows": [
|
|
247
|
+
{
|
|
248
|
+
"startsAt": "2026-10-04T02:00:00Z",
|
|
249
|
+
"endsAt": "2026-10-04T04:00:00Z",
|
|
250
|
+
"message": "A: database upgrade"
|
|
251
|
+
},
|
|
252
|
+
{
|
|
253
|
+
"startsAt": "2026-10-04T03:00:00Z",
|
|
254
|
+
"endsAt": "2026-10-04T05:00:00Z",
|
|
255
|
+
"message": "B: key rotation"
|
|
256
|
+
}
|
|
257
|
+
],
|
|
258
|
+
"nowIso": "2026-10-04T04:00:00.000Z",
|
|
259
|
+
"expected": {
|
|
260
|
+
"active": true,
|
|
261
|
+
"startsAt": "2026-10-04T03:00:00Z",
|
|
262
|
+
"endsAt": "2026-10-04T05:00:00Z",
|
|
263
|
+
"message": "B: key rotation",
|
|
264
|
+
"retryAfterSeconds": 3600
|
|
265
|
+
}
|
|
266
|
+
},
|
|
267
|
+
{
|
|
268
|
+
"name": "overlapping windows with equal endsAt: first in list wins",
|
|
269
|
+
"windows": [
|
|
270
|
+
{
|
|
271
|
+
"startsAt": "2026-10-04T02:00:00Z",
|
|
272
|
+
"endsAt": "2026-10-04T04:00:00Z",
|
|
273
|
+
"message": "A: database upgrade"
|
|
274
|
+
},
|
|
275
|
+
{
|
|
276
|
+
"startsAt": "2026-10-04T03:00:00Z",
|
|
277
|
+
"endsAt": "2026-10-04T04:00:00Z",
|
|
278
|
+
"message": "B: key rotation"
|
|
279
|
+
}
|
|
280
|
+
],
|
|
281
|
+
"nowIso": "2026-10-04T03:30:00.000Z",
|
|
282
|
+
"expected": {
|
|
283
|
+
"active": true,
|
|
284
|
+
"startsAt": "2026-10-04T02:00:00Z",
|
|
285
|
+
"endsAt": "2026-10-04T04:00:00Z",
|
|
286
|
+
"message": "A: database upgrade",
|
|
287
|
+
"retryAfterSeconds": 1800
|
|
288
|
+
}
|
|
289
|
+
},
|
|
290
|
+
{
|
|
291
|
+
"name": "overlapping windows with equal endsAt, list reversed: first in list wins",
|
|
292
|
+
"windows": [
|
|
293
|
+
{
|
|
294
|
+
"startsAt": "2026-10-04T03:00:00Z",
|
|
295
|
+
"endsAt": "2026-10-04T04:00:00Z",
|
|
296
|
+
"message": "B: key rotation"
|
|
297
|
+
},
|
|
298
|
+
{
|
|
299
|
+
"startsAt": "2026-10-04T02:00:00Z",
|
|
300
|
+
"endsAt": "2026-10-04T04:00:00Z",
|
|
301
|
+
"message": "A: database upgrade"
|
|
302
|
+
}
|
|
303
|
+
],
|
|
304
|
+
"nowIso": "2026-10-04T03:30:00.000Z",
|
|
305
|
+
"expected": {
|
|
306
|
+
"active": true,
|
|
307
|
+
"startsAt": "2026-10-04T03:00:00Z",
|
|
308
|
+
"endsAt": "2026-10-04T04:00:00Z",
|
|
309
|
+
"message": "B: key rotation",
|
|
310
|
+
"retryAfterSeconds": 1800
|
|
311
|
+
}
|
|
312
|
+
},
|
|
313
|
+
{
|
|
314
|
+
"name": "adjacent windows, one millisecond before the handoff",
|
|
315
|
+
"windows": [
|
|
316
|
+
{
|
|
317
|
+
"startsAt": "2026-10-04T02:00:00Z",
|
|
318
|
+
"endsAt": "2026-10-04T03:00:00Z",
|
|
319
|
+
"message": "A: database upgrade"
|
|
320
|
+
},
|
|
321
|
+
{
|
|
322
|
+
"startsAt": "2026-10-04T03:00:00Z",
|
|
323
|
+
"endsAt": "2026-10-04T04:00:00Z",
|
|
324
|
+
"message": "B: key rotation"
|
|
325
|
+
}
|
|
326
|
+
],
|
|
327
|
+
"nowIso": "2026-10-04T02:59:59.999Z",
|
|
328
|
+
"expected": {
|
|
329
|
+
"active": true,
|
|
330
|
+
"startsAt": "2026-10-04T02:00:00Z",
|
|
331
|
+
"endsAt": "2026-10-04T03:00:00Z",
|
|
332
|
+
"message": "A: database upgrade",
|
|
333
|
+
"retryAfterSeconds": 1
|
|
334
|
+
}
|
|
335
|
+
},
|
|
336
|
+
{
|
|
337
|
+
"name": "adjacent windows at the handoff instant: the second window",
|
|
338
|
+
"windows": [
|
|
339
|
+
{
|
|
340
|
+
"startsAt": "2026-10-04T02:00:00Z",
|
|
341
|
+
"endsAt": "2026-10-04T03:00:00Z",
|
|
342
|
+
"message": "A: database upgrade"
|
|
343
|
+
},
|
|
344
|
+
{
|
|
345
|
+
"startsAt": "2026-10-04T03:00:00Z",
|
|
346
|
+
"endsAt": "2026-10-04T04:00:00Z",
|
|
347
|
+
"message": "B: key rotation"
|
|
348
|
+
}
|
|
349
|
+
],
|
|
350
|
+
"nowIso": "2026-10-04T03:00:00.000Z",
|
|
351
|
+
"expected": {
|
|
352
|
+
"active": true,
|
|
353
|
+
"startsAt": "2026-10-04T03:00:00Z",
|
|
354
|
+
"endsAt": "2026-10-04T04:00:00Z",
|
|
355
|
+
"message": "B: key rotation",
|
|
356
|
+
"retryAfterSeconds": 3600
|
|
357
|
+
}
|
|
358
|
+
},
|
|
359
|
+
{
|
|
360
|
+
"name": "sub-second bounds, one millisecond before startsAt",
|
|
361
|
+
"windows": [
|
|
362
|
+
{
|
|
363
|
+
"startsAt": "2026-10-04T02:00:00.250Z",
|
|
364
|
+
"endsAt": "2026-10-04T02:00:01.750Z",
|
|
365
|
+
"message": "Sub-second window"
|
|
366
|
+
}
|
|
367
|
+
],
|
|
368
|
+
"nowIso": "2026-10-04T02:00:00.249Z",
|
|
369
|
+
"expected": {
|
|
370
|
+
"active": false
|
|
371
|
+
}
|
|
372
|
+
},
|
|
373
|
+
{
|
|
374
|
+
"name": "sub-second bounds, exactly startsAt",
|
|
375
|
+
"windows": [
|
|
376
|
+
{
|
|
377
|
+
"startsAt": "2026-10-04T02:00:00.250Z",
|
|
378
|
+
"endsAt": "2026-10-04T02:00:01.750Z",
|
|
379
|
+
"message": "Sub-second window"
|
|
380
|
+
}
|
|
381
|
+
],
|
|
382
|
+
"nowIso": "2026-10-04T02:00:00.250Z",
|
|
383
|
+
"expected": {
|
|
384
|
+
"active": true,
|
|
385
|
+
"startsAt": "2026-10-04T02:00:00.250Z",
|
|
386
|
+
"endsAt": "2026-10-04T02:00:01.750Z",
|
|
387
|
+
"message": "Sub-second window",
|
|
388
|
+
"retryAfterSeconds": 2
|
|
389
|
+
}
|
|
390
|
+
},
|
|
391
|
+
{
|
|
392
|
+
"name": "sub-second bounds, exactly endsAt",
|
|
393
|
+
"windows": [
|
|
394
|
+
{
|
|
395
|
+
"startsAt": "2026-10-04T02:00:00.250Z",
|
|
396
|
+
"endsAt": "2026-10-04T02:00:01.750Z",
|
|
397
|
+
"message": "Sub-second window"
|
|
398
|
+
}
|
|
399
|
+
],
|
|
400
|
+
"nowIso": "2026-10-04T02:00:01.750Z",
|
|
401
|
+
"expected": {
|
|
402
|
+
"active": false
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
]
|
package/openapi/v1.json
CHANGED
|
@@ -6465,6 +6465,14 @@
|
|
|
6465
6465
|
"type": "https://api.eco.com/v1/errors/service-unavailable",
|
|
6466
6466
|
"audience": "all",
|
|
6467
6467
|
"legacyCodes": []
|
|
6468
|
+
},
|
|
6469
|
+
{
|
|
6470
|
+
"code": "maintenance",
|
|
6471
|
+
"status": 503,
|
|
6472
|
+
"title": "Scheduled maintenance: new quotes and deposit addresses are paused until the window ends",
|
|
6473
|
+
"type": "https://api.eco.com/v1/errors/maintenance",
|
|
6474
|
+
"audience": "all",
|
|
6475
|
+
"legacyCodes": []
|
|
6468
6476
|
}
|
|
6469
6477
|
]
|
|
6470
6478
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@eco-foundation/api-schemas",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0",
|
|
4
4
|
"description": "Zod-first schemas, error catalog, golden fixtures, and generated OpenAPI 3.1 for the Eco /v1 API",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -63,7 +63,7 @@
|
|
|
63
63
|
"@scure/base": "^1.2.6"
|
|
64
64
|
},
|
|
65
65
|
"peerDependencies": {
|
|
66
|
-
"zod": "^4.
|
|
66
|
+
"zod": "^4.4.0"
|
|
67
67
|
},
|
|
68
68
|
"peerDependenciesMeta": {
|
|
69
69
|
"zod": {
|