@iveri/contracts 0.1.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 +63 -0
- package/dist/cjs/enum/error-code.enum.d.ts +48 -0
- package/dist/cjs/enum/error-code.enum.d.ts.map +1 -0
- package/dist/cjs/enum/error-code.enum.js +60 -0
- package/dist/cjs/enum/error-code.enum.js.map +1 -0
- package/dist/cjs/enum/index.d.ts +2 -0
- package/dist/cjs/enum/index.d.ts.map +1 -0
- package/dist/cjs/enum/index.js +18 -0
- package/dist/cjs/enum/index.js.map +1 -0
- package/dist/cjs/index.d.ts +3 -0
- package/dist/cjs/index.d.ts.map +1 -0
- package/dist/cjs/index.js +19 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/package.json +3 -0
- package/dist/cjs/type/api-response.type.d.ts +63 -0
- package/dist/cjs/type/api-response.type.d.ts.map +1 -0
- package/dist/cjs/type/api-response.type.js +3 -0
- package/dist/cjs/type/api-response.type.js.map +1 -0
- package/dist/cjs/type/cursor-page.type.d.ts +27 -0
- package/dist/cjs/type/cursor-page.type.d.ts.map +1 -0
- package/dist/cjs/type/cursor-page.type.js +3 -0
- package/dist/cjs/type/cursor-page.type.js.map +1 -0
- package/dist/cjs/type/index.d.ts +6 -0
- package/dist/cjs/type/index.d.ts.map +1 -0
- package/dist/cjs/type/index.js +22 -0
- package/dist/cjs/type/index.js.map +1 -0
- package/dist/cjs/type/nil.type.d.ts +23 -0
- package/dist/cjs/type/nil.type.d.ts.map +1 -0
- package/dist/cjs/type/nil.type.js +3 -0
- package/dist/cjs/type/nil.type.js.map +1 -0
- package/dist/cjs/type/paginated.type.d.ts +21 -0
- package/dist/cjs/type/paginated.type.d.ts.map +1 -0
- package/dist/cjs/type/paginated.type.js +3 -0
- package/dist/cjs/type/paginated.type.js.map +1 -0
- package/dist/cjs/type/uuid.type.d.ts +13 -0
- package/dist/cjs/type/uuid.type.d.ts.map +1 -0
- package/dist/cjs/type/uuid.type.js +3 -0
- package/dist/cjs/type/uuid.type.js.map +1 -0
- package/dist/esm/enum/error-code.enum.d.ts +48 -0
- package/dist/esm/enum/error-code.enum.d.ts.map +1 -0
- package/dist/esm/enum/error-code.enum.js +57 -0
- package/dist/esm/enum/error-code.enum.js.map +1 -0
- package/dist/esm/enum/index.d.ts +2 -0
- package/dist/esm/enum/index.d.ts.map +1 -0
- package/dist/esm/enum/index.js +2 -0
- package/dist/esm/enum/index.js.map +1 -0
- package/dist/esm/index.d.ts +3 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +3 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/package.json +3 -0
- package/dist/esm/type/api-response.type.d.ts +63 -0
- package/dist/esm/type/api-response.type.d.ts.map +1 -0
- package/dist/esm/type/api-response.type.js +2 -0
- package/dist/esm/type/api-response.type.js.map +1 -0
- package/dist/esm/type/cursor-page.type.d.ts +27 -0
- package/dist/esm/type/cursor-page.type.d.ts.map +1 -0
- package/dist/esm/type/cursor-page.type.js +2 -0
- package/dist/esm/type/cursor-page.type.js.map +1 -0
- package/dist/esm/type/index.d.ts +6 -0
- package/dist/esm/type/index.d.ts.map +1 -0
- package/dist/esm/type/index.js +6 -0
- package/dist/esm/type/index.js.map +1 -0
- package/dist/esm/type/nil.type.d.ts +23 -0
- package/dist/esm/type/nil.type.d.ts.map +1 -0
- package/dist/esm/type/nil.type.js +2 -0
- package/dist/esm/type/nil.type.js.map +1 -0
- package/dist/esm/type/paginated.type.d.ts +21 -0
- package/dist/esm/type/paginated.type.d.ts.map +1 -0
- package/dist/esm/type/paginated.type.js +2 -0
- package/dist/esm/type/paginated.type.js.map +1 -0
- package/dist/esm/type/uuid.type.d.ts +13 -0
- package/dist/esm/type/uuid.type.d.ts.map +1 -0
- package/dist/esm/type/uuid.type.js +2 -0
- package/dist/esm/type/uuid.type.js.map +1 -0
- package/package.json +57 -0
package/README.md
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# @iveri/contracts
|
|
2
|
+
|
|
3
|
+
The wire contract every Iveri service and frontend compiles against: shared types and plain
|
|
4
|
+
enums, and nothing else.
|
|
5
|
+
|
|
6
|
+
```bash
|
|
7
|
+
pnpm add @iveri/contracts
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
```ts
|
|
11
|
+
import { ApiResponse, CursorPage, ErrorCode, Maybe, Paginated, UUID } from '@iveri/contracts';
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Import from the root barrel only — never `@iveri/contracts/dist/...`.
|
|
15
|
+
|
|
16
|
+
## Zero runtime dependencies — the rule that defines this package
|
|
17
|
+
|
|
18
|
+
This package ends up inside browser bundles, so it declares **no** `dependencies`,
|
|
19
|
+
`peerDependencies` or `optionalDependencies`, and its compiled output imports nothing outside
|
|
20
|
+
itself. Nothing from `@nestjs/*`, `typeorm`, `class-validator`, or `node:*` may ever appear
|
|
21
|
+
here — not even as a type-only import.
|
|
22
|
+
|
|
23
|
+
That is why it is a separate package from `@iveri/nest-sdk` rather than a folder inside it.
|
|
24
|
+
It is enforced by `scripts/verify-zero-runtime-deps.mjs`, which runs as part of `build`: CI
|
|
25
|
+
fails on the PR that adds a dependency, not on a frontend build weeks later.
|
|
26
|
+
|
|
27
|
+
Anything needing a dependency belongs in `@iveri/nest-sdk` (backend) or `@iveri/react-kit`
|
|
28
|
+
(frontend).
|
|
29
|
+
|
|
30
|
+
## What is here
|
|
31
|
+
|
|
32
|
+
### `type/`
|
|
33
|
+
|
|
34
|
+
| Type | Use |
|
|
35
|
+
| ----------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------- |
|
|
36
|
+
| `Nil`, `Maybe<T>`, `Nullable<T>` | absent values. `Nullable` for anything crossing the wire — `JSON.stringify` drops `undefined` |
|
|
37
|
+
| `UUID` | template-literal shape hint; validation stays at the edge with `@IsUUID()` |
|
|
38
|
+
| `Paginated<T>` | offset paging, where the client needs a total or arbitrary page jumps |
|
|
39
|
+
| `CursorPage<T>` | cursor paging — the default for lists that grow while being read |
|
|
40
|
+
| `ApiSuccessResponse<T>`, `ApiErrorResponse`, `ApiErrorBody`, `ApiResponse<T>` | the response envelope |
|
|
41
|
+
|
|
42
|
+
### `enum/`
|
|
43
|
+
|
|
44
|
+
`ErrorCode` — the stable, machine-readable error classification carried in every error
|
|
45
|
+
response. Clients branch on `code`; `message` is for humans and may change at any time.
|
|
46
|
+
|
|
47
|
+
## What is deliberately **not** here yet
|
|
48
|
+
|
|
49
|
+
`event/` (domain event envelope, topics) and `api/` (per-service request/response shapes) are
|
|
50
|
+
in the plan but unwritten: no service defines them yet. They get added when a real consumer
|
|
51
|
+
needs them, per the second-consumer rule — not in anticipation.
|
|
52
|
+
|
|
53
|
+
## Adding to the contract
|
|
54
|
+
|
|
55
|
+
- A new `ErrorCode` member is a **minor** version. Changing what an existing member means, or
|
|
56
|
+
removing one, is **major** — clients branch on these.
|
|
57
|
+
- Widening a type is minor; narrowing it is major.
|
|
58
|
+
- Breaking changes get a migration note in `CHANGELOG.md`. Services upgrade deliberately.
|
|
59
|
+
|
|
60
|
+
## Build output
|
|
61
|
+
|
|
62
|
+
Dual ESM + CJS (`dist/esm`, `dist/cjs`) behind an `exports` map, so NestJS `require`s it and
|
|
63
|
+
Vite tree-shakes it. `sideEffects: false`.
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stable, machine-readable error classification carried in every
|
|
3
|
+
* {@link ApiErrorResponse}.
|
|
4
|
+
*
|
|
5
|
+
* A code is a **contract**: clients branch on it, so a member's meaning never
|
|
6
|
+
* changes and a member is never removed once published. Adding one is a minor
|
|
7
|
+
* version; repurposing one is a breaking change.
|
|
8
|
+
*
|
|
9
|
+
* Codes are deliberately coarser than HTTP status. Two different 404s that a
|
|
10
|
+
* client must handle differently deserve two codes; two that it handles
|
|
11
|
+
* identically share one.
|
|
12
|
+
*/
|
|
13
|
+
export declare enum ErrorCode {
|
|
14
|
+
/** Request body or query failed DTO validation. `details` lists the fields. */
|
|
15
|
+
VALIDATION_FAILED = "VALIDATION_FAILED",
|
|
16
|
+
/** Body could not be parsed at all — bad JSON, wrong content type. */
|
|
17
|
+
MALFORMED_REQUEST = "MALFORMED_REQUEST",
|
|
18
|
+
/** No credentials presented, or the token could not be verified. */
|
|
19
|
+
UNAUTHENTICATED = "UNAUTHENTICATED",
|
|
20
|
+
/** Credentials were well-formed but wrong. Never distinguishes unknown user from bad password. */
|
|
21
|
+
INVALID_CREDENTIALS = "INVALID_CREDENTIALS",
|
|
22
|
+
/** Token parsed and verified, but its expiry has passed. The client should refresh and retry. */
|
|
23
|
+
TOKEN_EXPIRED = "TOKEN_EXPIRED",
|
|
24
|
+
/** Authenticated, but the action is not permitted for this principal. */
|
|
25
|
+
FORBIDDEN = "FORBIDDEN",
|
|
26
|
+
/** Authenticated, but the principal's role lacks the required permission. */
|
|
27
|
+
INSUFFICIENT_PERMISSION = "INSUFFICIENT_PERMISSION",
|
|
28
|
+
/** The resource belongs to another tenant. Emitted instead of leaking its existence. */
|
|
29
|
+
TENANT_MISMATCH = "TENANT_MISMATCH",
|
|
30
|
+
RESOURCE_NOT_FOUND = "RESOURCE_NOT_FOUND",
|
|
31
|
+
/** The request contradicts current state — a stale version, a closed aggregate. */
|
|
32
|
+
RESOURCE_CONFLICT = "RESOURCE_CONFLICT",
|
|
33
|
+
/** A uniqueness constraint would be violated. */
|
|
34
|
+
RESOURCE_ALREADY_EXISTS = "RESOURCE_ALREADY_EXISTS",
|
|
35
|
+
PAYLOAD_TOO_LARGE = "PAYLOAD_TOO_LARGE",
|
|
36
|
+
/** Syntactically valid and well-formed, but rejected by a business rule. */
|
|
37
|
+
UNPROCESSABLE_ENTITY = "UNPROCESSABLE_ENTITY",
|
|
38
|
+
RATE_LIMIT_EXCEEDED = "RATE_LIMIT_EXCEEDED",
|
|
39
|
+
/** Catch-all for an unhandled failure. Details are logged, never returned. */
|
|
40
|
+
INTERNAL_ERROR = "INTERNAL_ERROR",
|
|
41
|
+
/** A third-party or downstream service returned an error we could not recover from. */
|
|
42
|
+
EXTERNAL_SERVICE_ERROR = "EXTERNAL_SERVICE_ERROR",
|
|
43
|
+
/** A dependency is unreachable or the service is shutting down. Retryable. */
|
|
44
|
+
SERVICE_UNAVAILABLE = "SERVICE_UNAVAILABLE",
|
|
45
|
+
/** A downstream call exceeded its deadline. Retryable. */
|
|
46
|
+
DEPENDENCY_TIMEOUT = "DEPENDENCY_TIMEOUT"
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=error-code.enum.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error-code.enum.d.ts","sourceRoot":"","sources":["../../../src/enum/error-code.enum.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,oBAAY,SAAS;IAEjB,+EAA+E;IAC/E,iBAAiB,sBAAsB;IACvC,sEAAsE;IACtE,iBAAiB,sBAAsB;IAGvC,oEAAoE;IACpE,eAAe,oBAAoB;IACnC,kGAAkG;IAClG,mBAAmB,wBAAwB;IAC3C,iGAAiG;IACjG,aAAa,kBAAkB;IAG/B,yEAAyE;IACzE,SAAS,cAAc;IACvB,6EAA6E;IAC7E,uBAAuB,4BAA4B;IACnD,wFAAwF;IACxF,eAAe,oBAAoB;IAGnC,kBAAkB,uBAAuB;IAGzC,mFAAmF;IACnF,iBAAiB,sBAAsB;IACvC,iDAAiD;IACjD,uBAAuB,4BAA4B;IAGnD,iBAAiB,sBAAsB;IACvC,4EAA4E;IAC5E,oBAAoB,yBAAyB;IAG7C,mBAAmB,wBAAwB;IAG3C,8EAA8E;IAC9E,cAAc,mBAAmB;IACjC,uFAAuF;IACvF,sBAAsB,2BAA2B;IACjD,8EAA8E;IAC9E,mBAAmB,wBAAwB;IAC3C,0DAA0D;IAC1D,kBAAkB,uBAAuB;CAC5C"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ErrorCode = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Stable, machine-readable error classification carried in every
|
|
6
|
+
* {@link ApiErrorResponse}.
|
|
7
|
+
*
|
|
8
|
+
* A code is a **contract**: clients branch on it, so a member's meaning never
|
|
9
|
+
* changes and a member is never removed once published. Adding one is a minor
|
|
10
|
+
* version; repurposing one is a breaking change.
|
|
11
|
+
*
|
|
12
|
+
* Codes are deliberately coarser than HTTP status. Two different 404s that a
|
|
13
|
+
* client must handle differently deserve two codes; two that it handles
|
|
14
|
+
* identically share one.
|
|
15
|
+
*/
|
|
16
|
+
var ErrorCode;
|
|
17
|
+
(function (ErrorCode) {
|
|
18
|
+
// ── 400 Bad Request ─────────────────────────────────────────────────────
|
|
19
|
+
/** Request body or query failed DTO validation. `details` lists the fields. */
|
|
20
|
+
ErrorCode["VALIDATION_FAILED"] = "VALIDATION_FAILED";
|
|
21
|
+
/** Body could not be parsed at all — bad JSON, wrong content type. */
|
|
22
|
+
ErrorCode["MALFORMED_REQUEST"] = "MALFORMED_REQUEST";
|
|
23
|
+
// ── 401 Unauthorized ────────────────────────────────────────────────────
|
|
24
|
+
/** No credentials presented, or the token could not be verified. */
|
|
25
|
+
ErrorCode["UNAUTHENTICATED"] = "UNAUTHENTICATED";
|
|
26
|
+
/** Credentials were well-formed but wrong. Never distinguishes unknown user from bad password. */
|
|
27
|
+
ErrorCode["INVALID_CREDENTIALS"] = "INVALID_CREDENTIALS";
|
|
28
|
+
/** Token parsed and verified, but its expiry has passed. The client should refresh and retry. */
|
|
29
|
+
ErrorCode["TOKEN_EXPIRED"] = "TOKEN_EXPIRED";
|
|
30
|
+
// ── 403 Forbidden ───────────────────────────────────────────────────────
|
|
31
|
+
/** Authenticated, but the action is not permitted for this principal. */
|
|
32
|
+
ErrorCode["FORBIDDEN"] = "FORBIDDEN";
|
|
33
|
+
/** Authenticated, but the principal's role lacks the required permission. */
|
|
34
|
+
ErrorCode["INSUFFICIENT_PERMISSION"] = "INSUFFICIENT_PERMISSION";
|
|
35
|
+
/** The resource belongs to another tenant. Emitted instead of leaking its existence. */
|
|
36
|
+
ErrorCode["TENANT_MISMATCH"] = "TENANT_MISMATCH";
|
|
37
|
+
// ── 404 Not Found ───────────────────────────────────────────────────────
|
|
38
|
+
ErrorCode["RESOURCE_NOT_FOUND"] = "RESOURCE_NOT_FOUND";
|
|
39
|
+
// ── 409 Conflict ────────────────────────────────────────────────────────
|
|
40
|
+
/** The request contradicts current state — a stale version, a closed aggregate. */
|
|
41
|
+
ErrorCode["RESOURCE_CONFLICT"] = "RESOURCE_CONFLICT";
|
|
42
|
+
/** A uniqueness constraint would be violated. */
|
|
43
|
+
ErrorCode["RESOURCE_ALREADY_EXISTS"] = "RESOURCE_ALREADY_EXISTS";
|
|
44
|
+
// ── 413 / 422 ───────────────────────────────────────────────────────────
|
|
45
|
+
ErrorCode["PAYLOAD_TOO_LARGE"] = "PAYLOAD_TOO_LARGE";
|
|
46
|
+
/** Syntactically valid and well-formed, but rejected by a business rule. */
|
|
47
|
+
ErrorCode["UNPROCESSABLE_ENTITY"] = "UNPROCESSABLE_ENTITY";
|
|
48
|
+
// ── 429 Too Many Requests ───────────────────────────────────────────────
|
|
49
|
+
ErrorCode["RATE_LIMIT_EXCEEDED"] = "RATE_LIMIT_EXCEEDED";
|
|
50
|
+
// ── 5xx ─────────────────────────────────────────────────────────────────
|
|
51
|
+
/** Catch-all for an unhandled failure. Details are logged, never returned. */
|
|
52
|
+
ErrorCode["INTERNAL_ERROR"] = "INTERNAL_ERROR";
|
|
53
|
+
/** A third-party or downstream service returned an error we could not recover from. */
|
|
54
|
+
ErrorCode["EXTERNAL_SERVICE_ERROR"] = "EXTERNAL_SERVICE_ERROR";
|
|
55
|
+
/** A dependency is unreachable or the service is shutting down. Retryable. */
|
|
56
|
+
ErrorCode["SERVICE_UNAVAILABLE"] = "SERVICE_UNAVAILABLE";
|
|
57
|
+
/** A downstream call exceeded its deadline. Retryable. */
|
|
58
|
+
ErrorCode["DEPENDENCY_TIMEOUT"] = "DEPENDENCY_TIMEOUT";
|
|
59
|
+
})(ErrorCode || (exports.ErrorCode = ErrorCode = {}));
|
|
60
|
+
//# sourceMappingURL=error-code.enum.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error-code.enum.js","sourceRoot":"","sources":["../../../src/enum/error-code.enum.ts"],"names":[],"mappings":";;;AAAA;;;;;;;;;;;GAWG;AACH,IAAY,SAiDX;AAjDD,WAAY,SAAS;IACjB,2EAA2E;IAC3E,+EAA+E;IAC/E,oDAAuC,CAAA;IACvC,sEAAsE;IACtE,oDAAuC,CAAA;IAEvC,2EAA2E;IAC3E,oEAAoE;IACpE,gDAAmC,CAAA;IACnC,kGAAkG;IAClG,wDAA2C,CAAA;IAC3C,iGAAiG;IACjG,4CAA+B,CAAA;IAE/B,2EAA2E;IAC3E,yEAAyE;IACzE,oCAAuB,CAAA;IACvB,6EAA6E;IAC7E,gEAAmD,CAAA;IACnD,wFAAwF;IACxF,gDAAmC,CAAA;IAEnC,2EAA2E;IAC3E,sDAAyC,CAAA;IAEzC,2EAA2E;IAC3E,mFAAmF;IACnF,oDAAuC,CAAA;IACvC,iDAAiD;IACjD,gEAAmD,CAAA;IAEnD,2EAA2E;IAC3E,oDAAuC,CAAA;IACvC,4EAA4E;IAC5E,0DAA6C,CAAA;IAE7C,2EAA2E;IAC3E,wDAA2C,CAAA;IAE3C,2EAA2E;IAC3E,8EAA8E;IAC9E,8CAAiC,CAAA;IACjC,uFAAuF;IACvF,8DAAiD,CAAA;IACjD,8EAA8E;IAC9E,wDAA2C,CAAA;IAC3C,0DAA0D;IAC1D,sDAAyC,CAAA;AAC7C,CAAC,EAjDW,SAAS,yBAAT,SAAS,QAiDpB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/enum/index.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./error-code.enum.js"), exports);
|
|
18
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/enum/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,uDAAqC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./enum/index.js"), exports);
|
|
18
|
+
__exportStar(require("./type/index.js"), exports);
|
|
19
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,kDAAgC;AAChC,kDAAgC"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import type { ErrorCode } from '../enum/error-code.enum.js';
|
|
2
|
+
import type { Maybe } from './nil.type.js';
|
|
3
|
+
/**
|
|
4
|
+
* Envelope for a successful HTTP response.
|
|
5
|
+
*
|
|
6
|
+
* Every service wraps its payload in this shape, so a client can branch on
|
|
7
|
+
* `success` before touching anything else and never has to guess whether a
|
|
8
|
+
* 200 body is data or an error report.
|
|
9
|
+
*
|
|
10
|
+
* @typeParam T - the response payload type.
|
|
11
|
+
*/
|
|
12
|
+
export interface ApiSuccessResponse<T> {
|
|
13
|
+
success: true;
|
|
14
|
+
data: T;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* The error half of {@link ApiErrorResponse}.
|
|
18
|
+
*
|
|
19
|
+
* `message` is for humans and may change at any time — clients branch on
|
|
20
|
+
* `code`, never on message text.
|
|
21
|
+
*/
|
|
22
|
+
export interface ApiErrorBody {
|
|
23
|
+
/** Stable, machine-readable classification. The only field safe to branch on. */
|
|
24
|
+
code: ErrorCode;
|
|
25
|
+
/** Human-readable summary. Safe to surface to a developer, not to an end user. */
|
|
26
|
+
message: string;
|
|
27
|
+
/**
|
|
28
|
+
* Structured context — which field failed validation, which constraint was
|
|
29
|
+
* violated. Never contains secrets, tokens, or raw upstream payloads.
|
|
30
|
+
*/
|
|
31
|
+
details?: Maybe<Record<string, unknown>>;
|
|
32
|
+
/**
|
|
33
|
+
* The request's correlation id, echoed so a user can quote it in a support
|
|
34
|
+
* ticket and the whole request can be pulled out of the logs.
|
|
35
|
+
*/
|
|
36
|
+
correlationId?: Maybe<string>;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Envelope for a failed HTTP response, emitted by the SDK's global exception
|
|
40
|
+
* filter for every non-2xx status.
|
|
41
|
+
*/
|
|
42
|
+
export interface ApiErrorResponse {
|
|
43
|
+
success: false;
|
|
44
|
+
error: ApiErrorBody;
|
|
45
|
+
/** ISO-8601 timestamp of when the error was rendered. */
|
|
46
|
+
timestamp: string;
|
|
47
|
+
/** Request path that produced the error, without the query string. */
|
|
48
|
+
path: string;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Discriminated union of both envelopes. Narrow on `success`:
|
|
52
|
+
*
|
|
53
|
+
* ```ts
|
|
54
|
+
* if (!response.success) {
|
|
55
|
+
* return handle(response.error.code);
|
|
56
|
+
* }
|
|
57
|
+
* use(response.data);
|
|
58
|
+
* ```
|
|
59
|
+
*
|
|
60
|
+
* @typeParam T - the payload type on the success branch.
|
|
61
|
+
*/
|
|
62
|
+
export type ApiResponse<T> = ApiSuccessResponse<T> | ApiErrorResponse;
|
|
63
|
+
//# sourceMappingURL=api-response.type.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-response.type.d.ts","sourceRoot":"","sources":["../../../src/type/api-response.type.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AAE5D,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAE3C;;;;;;;;GAQG;AACH,MAAM,WAAW,kBAAkB,CAAC,CAAC;IACjC,OAAO,EAAE,IAAI,CAAC;IACd,IAAI,EAAE,CAAC,CAAC;CACX;AAED;;;;;GAKG;AACH,MAAM,WAAW,YAAY;IACzB,iFAAiF;IACjF,IAAI,EAAE,SAAS,CAAC;IAEhB,kFAAkF;IAClF,OAAO,EAAE,MAAM,CAAC;IAEhB;;;OAGG;IACH,OAAO,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAEzC;;;OAGG;IACH,aAAa,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;CACjC;AAED;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC7B,OAAO,EAAE,KAAK,CAAC;IACf,KAAK,EAAE,YAAY,CAAC;IAEpB,yDAAyD;IACzD,SAAS,EAAE,MAAM,CAAC;IAElB,sEAAsE;IACtE,IAAI,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,WAAW,CAAC,CAAC,IAAI,kBAAkB,CAAC,CAAC,CAAC,GAAG,gBAAgB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-response.type.js","sourceRoot":"","sources":["../../../src/type/api-response.type.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { Nullable } from './nil.type.js';
|
|
2
|
+
/**
|
|
3
|
+
* A cursor-paginated slice of a collection.
|
|
4
|
+
*
|
|
5
|
+
* The default for anything that grows while it is being read — delivery logs,
|
|
6
|
+
* captures, conversation messages. A cursor is anchored to a row rather than a
|
|
7
|
+
* position, so inserts during paging cannot make the reader skip or repeat.
|
|
8
|
+
*
|
|
9
|
+
* The cursor is an **opaque** string. Callers pass it back verbatim and never
|
|
10
|
+
* parse it; its encoding is an implementation detail of the service that issued
|
|
11
|
+
* it and may change without a version bump.
|
|
12
|
+
*
|
|
13
|
+
* @typeParam T - the element type of a single row.
|
|
14
|
+
*/
|
|
15
|
+
export interface CursorPage<T> {
|
|
16
|
+
/** The rows for this page, in the requested order. */
|
|
17
|
+
items: T[];
|
|
18
|
+
/** Cursor to pass as `after` for the next page, or `null` when the end is reached. */
|
|
19
|
+
nextCursor: Nullable<string>;
|
|
20
|
+
/**
|
|
21
|
+
* Whether another page exists. Equivalent to `nextCursor !== null`, exposed
|
|
22
|
+
* separately so UI code can render a "load more" affordance without
|
|
23
|
+
* reasoning about the cursor at all.
|
|
24
|
+
*/
|
|
25
|
+
hasMore: boolean;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=cursor-page.type.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cursor-page.type.d.ts","sourceRoot":"","sources":["../../../src/type/cursor-page.type.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAE9C;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,UAAU,CAAC,CAAC;IACzB,sDAAsD;IACtD,KAAK,EAAE,CAAC,EAAE,CAAC;IAEX,sFAAsF;IACtF,UAAU,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IAE7B;;;;OAIG;IACH,OAAO,EAAE,OAAO,CAAC;CACpB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cursor-page.type.js","sourceRoot":"","sources":["../../../src/type/cursor-page.type.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/type/index.ts"],"names":[],"mappings":"AAAA,cAAc,wBAAwB,CAAC;AACvC,cAAc,uBAAuB,CAAC;AACtC,cAAc,eAAe,CAAC;AAC9B,cAAc,qBAAqB,CAAC;AACpC,cAAc,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./api-response.type.js"), exports);
|
|
18
|
+
__exportStar(require("./cursor-page.type.js"), exports);
|
|
19
|
+
__exportStar(require("./nil.type.js"), exports);
|
|
20
|
+
__exportStar(require("./paginated.type.js"), exports);
|
|
21
|
+
__exportStar(require("./uuid.type.js"), exports);
|
|
22
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/type/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,yDAAuC;AACvC,wDAAsC;AACtC,gDAA8B;AAC9B,sDAAoC;AACpC,iDAA+B"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Represents a value that is either `null` or `undefined`.
|
|
3
|
+
*
|
|
4
|
+
* Useful for excluding nullish values from union types via `Exclude<T, Nil>`
|
|
5
|
+
* or for explicitly modelling absent values.
|
|
6
|
+
*/
|
|
7
|
+
export type Nil = null | undefined;
|
|
8
|
+
/**
|
|
9
|
+
* A value that may be `T` or absent (`null` / `undefined`).
|
|
10
|
+
*
|
|
11
|
+
* Prefer `Maybe<T>` over inline `T | null | undefined` for consistency
|
|
12
|
+
* across services.
|
|
13
|
+
*/
|
|
14
|
+
export type Maybe<T> = T | Nil;
|
|
15
|
+
/**
|
|
16
|
+
* A value that may be `T` or `null` (but never `undefined`).
|
|
17
|
+
*
|
|
18
|
+
* Use this for anything that crosses the wire: `JSON.stringify` drops
|
|
19
|
+
* `undefined` properties, so a nullable API field must be `null` to survive
|
|
20
|
+
* serialization.
|
|
21
|
+
*/
|
|
22
|
+
export type Nullable<T> = T | null;
|
|
23
|
+
//# sourceMappingURL=nil.type.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nil.type.d.ts","sourceRoot":"","sources":["../../../src/type/nil.type.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,MAAM,GAAG,GAAG,IAAI,GAAG,SAAS,CAAC;AAEnC;;;;;GAKG;AACH,MAAM,MAAM,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC;AAE/B;;;;;;GAMG;AACH,MAAM,MAAM,QAAQ,CAAC,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nil.type.js","sourceRoot":"","sources":["../../../src/type/nil.type.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* An offset-paginated slice of a collection.
|
|
3
|
+
*
|
|
4
|
+
* Use this where the client needs to jump to an arbitrary page or show a total
|
|
5
|
+
* count. Where the collection is large, append-only, or mutating under the
|
|
6
|
+
* reader (delivery logs, captures, messages), prefer `CursorPage<T>` — offset
|
|
7
|
+
* paging over a moving list skips and repeats rows.
|
|
8
|
+
*
|
|
9
|
+
* @typeParam T - the element type of a single row.
|
|
10
|
+
*/
|
|
11
|
+
export interface Paginated<T> {
|
|
12
|
+
/** The rows for the requested page, in the requested order. */
|
|
13
|
+
items: T[];
|
|
14
|
+
/** Total rows matching the query across every page, ignoring `limit`/`offset`. */
|
|
15
|
+
total: number;
|
|
16
|
+
/** Maximum rows the caller asked for. `items.length` may be smaller on the last page. */
|
|
17
|
+
limit: number;
|
|
18
|
+
/** Rows skipped before this page. Zero-based. */
|
|
19
|
+
offset: number;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=paginated.type.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paginated.type.d.ts","sourceRoot":"","sources":["../../../src/type/paginated.type.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,MAAM,WAAW,SAAS,CAAC,CAAC;IACxB,+DAA+D;IAC/D,KAAK,EAAE,CAAC,EAAE,CAAC;IAEX,kFAAkF;IAClF,KAAK,EAAE,MAAM,CAAC;IAEd,yFAAyF;IACzF,KAAK,EAAE,MAAM,CAAC;IAEd,iDAAiD;IACjD,MAAM,EAAE,MAAM,CAAC;CAClB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paginated.type.js","sourceRoot":"","sources":["../../../src/type/paginated.type.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A UUID string value.
|
|
3
|
+
*
|
|
4
|
+
* Structurally identical to the `UUID` type from `node:crypto`, but declared
|
|
5
|
+
* here rather than re-exported: `@iveri/contracts` compiles into browser
|
|
6
|
+
* bundles, and importing from `node:crypto` — even type-only — would force
|
|
7
|
+
* every frontend to depend on `@types/node`.
|
|
8
|
+
*
|
|
9
|
+
* This is a shape hint, not a guarantee. Validation happens at the edge with
|
|
10
|
+
* `@IsUUID()` on the request DTO.
|
|
11
|
+
*/
|
|
12
|
+
export type UUID = `${string}-${string}-${string}-${string}-${string}`;
|
|
13
|
+
//# sourceMappingURL=uuid.type.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"uuid.type.d.ts","sourceRoot":"","sources":["../../../src/type/uuid.type.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,MAAM,MAAM,IAAI,GAAG,GAAG,MAAM,IAAI,MAAM,IAAI,MAAM,IAAI,MAAM,IAAI,MAAM,EAAE,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"uuid.type.js","sourceRoot":"","sources":["../../../src/type/uuid.type.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stable, machine-readable error classification carried in every
|
|
3
|
+
* {@link ApiErrorResponse}.
|
|
4
|
+
*
|
|
5
|
+
* A code is a **contract**: clients branch on it, so a member's meaning never
|
|
6
|
+
* changes and a member is never removed once published. Adding one is a minor
|
|
7
|
+
* version; repurposing one is a breaking change.
|
|
8
|
+
*
|
|
9
|
+
* Codes are deliberately coarser than HTTP status. Two different 404s that a
|
|
10
|
+
* client must handle differently deserve two codes; two that it handles
|
|
11
|
+
* identically share one.
|
|
12
|
+
*/
|
|
13
|
+
export declare enum ErrorCode {
|
|
14
|
+
/** Request body or query failed DTO validation. `details` lists the fields. */
|
|
15
|
+
VALIDATION_FAILED = "VALIDATION_FAILED",
|
|
16
|
+
/** Body could not be parsed at all — bad JSON, wrong content type. */
|
|
17
|
+
MALFORMED_REQUEST = "MALFORMED_REQUEST",
|
|
18
|
+
/** No credentials presented, or the token could not be verified. */
|
|
19
|
+
UNAUTHENTICATED = "UNAUTHENTICATED",
|
|
20
|
+
/** Credentials were well-formed but wrong. Never distinguishes unknown user from bad password. */
|
|
21
|
+
INVALID_CREDENTIALS = "INVALID_CREDENTIALS",
|
|
22
|
+
/** Token parsed and verified, but its expiry has passed. The client should refresh and retry. */
|
|
23
|
+
TOKEN_EXPIRED = "TOKEN_EXPIRED",
|
|
24
|
+
/** Authenticated, but the action is not permitted for this principal. */
|
|
25
|
+
FORBIDDEN = "FORBIDDEN",
|
|
26
|
+
/** Authenticated, but the principal's role lacks the required permission. */
|
|
27
|
+
INSUFFICIENT_PERMISSION = "INSUFFICIENT_PERMISSION",
|
|
28
|
+
/** The resource belongs to another tenant. Emitted instead of leaking its existence. */
|
|
29
|
+
TENANT_MISMATCH = "TENANT_MISMATCH",
|
|
30
|
+
RESOURCE_NOT_FOUND = "RESOURCE_NOT_FOUND",
|
|
31
|
+
/** The request contradicts current state — a stale version, a closed aggregate. */
|
|
32
|
+
RESOURCE_CONFLICT = "RESOURCE_CONFLICT",
|
|
33
|
+
/** A uniqueness constraint would be violated. */
|
|
34
|
+
RESOURCE_ALREADY_EXISTS = "RESOURCE_ALREADY_EXISTS",
|
|
35
|
+
PAYLOAD_TOO_LARGE = "PAYLOAD_TOO_LARGE",
|
|
36
|
+
/** Syntactically valid and well-formed, but rejected by a business rule. */
|
|
37
|
+
UNPROCESSABLE_ENTITY = "UNPROCESSABLE_ENTITY",
|
|
38
|
+
RATE_LIMIT_EXCEEDED = "RATE_LIMIT_EXCEEDED",
|
|
39
|
+
/** Catch-all for an unhandled failure. Details are logged, never returned. */
|
|
40
|
+
INTERNAL_ERROR = "INTERNAL_ERROR",
|
|
41
|
+
/** A third-party or downstream service returned an error we could not recover from. */
|
|
42
|
+
EXTERNAL_SERVICE_ERROR = "EXTERNAL_SERVICE_ERROR",
|
|
43
|
+
/** A dependency is unreachable or the service is shutting down. Retryable. */
|
|
44
|
+
SERVICE_UNAVAILABLE = "SERVICE_UNAVAILABLE",
|
|
45
|
+
/** A downstream call exceeded its deadline. Retryable. */
|
|
46
|
+
DEPENDENCY_TIMEOUT = "DEPENDENCY_TIMEOUT"
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=error-code.enum.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error-code.enum.d.ts","sourceRoot":"","sources":["../../../src/enum/error-code.enum.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,oBAAY,SAAS;IAEjB,+EAA+E;IAC/E,iBAAiB,sBAAsB;IACvC,sEAAsE;IACtE,iBAAiB,sBAAsB;IAGvC,oEAAoE;IACpE,eAAe,oBAAoB;IACnC,kGAAkG;IAClG,mBAAmB,wBAAwB;IAC3C,iGAAiG;IACjG,aAAa,kBAAkB;IAG/B,yEAAyE;IACzE,SAAS,cAAc;IACvB,6EAA6E;IAC7E,uBAAuB,4BAA4B;IACnD,wFAAwF;IACxF,eAAe,oBAAoB;IAGnC,kBAAkB,uBAAuB;IAGzC,mFAAmF;IACnF,iBAAiB,sBAAsB;IACvC,iDAAiD;IACjD,uBAAuB,4BAA4B;IAGnD,iBAAiB,sBAAsB;IACvC,4EAA4E;IAC5E,oBAAoB,yBAAyB;IAG7C,mBAAmB,wBAAwB;IAG3C,8EAA8E;IAC9E,cAAc,mBAAmB;IACjC,uFAAuF;IACvF,sBAAsB,2BAA2B;IACjD,8EAA8E;IAC9E,mBAAmB,wBAAwB;IAC3C,0DAA0D;IAC1D,kBAAkB,uBAAuB;CAC5C"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stable, machine-readable error classification carried in every
|
|
3
|
+
* {@link ApiErrorResponse}.
|
|
4
|
+
*
|
|
5
|
+
* A code is a **contract**: clients branch on it, so a member's meaning never
|
|
6
|
+
* changes and a member is never removed once published. Adding one is a minor
|
|
7
|
+
* version; repurposing one is a breaking change.
|
|
8
|
+
*
|
|
9
|
+
* Codes are deliberately coarser than HTTP status. Two different 404s that a
|
|
10
|
+
* client must handle differently deserve two codes; two that it handles
|
|
11
|
+
* identically share one.
|
|
12
|
+
*/
|
|
13
|
+
export var ErrorCode;
|
|
14
|
+
(function (ErrorCode) {
|
|
15
|
+
// ── 400 Bad Request ─────────────────────────────────────────────────────
|
|
16
|
+
/** Request body or query failed DTO validation. `details` lists the fields. */
|
|
17
|
+
ErrorCode["VALIDATION_FAILED"] = "VALIDATION_FAILED";
|
|
18
|
+
/** Body could not be parsed at all — bad JSON, wrong content type. */
|
|
19
|
+
ErrorCode["MALFORMED_REQUEST"] = "MALFORMED_REQUEST";
|
|
20
|
+
// ── 401 Unauthorized ────────────────────────────────────────────────────
|
|
21
|
+
/** No credentials presented, or the token could not be verified. */
|
|
22
|
+
ErrorCode["UNAUTHENTICATED"] = "UNAUTHENTICATED";
|
|
23
|
+
/** Credentials were well-formed but wrong. Never distinguishes unknown user from bad password. */
|
|
24
|
+
ErrorCode["INVALID_CREDENTIALS"] = "INVALID_CREDENTIALS";
|
|
25
|
+
/** Token parsed and verified, but its expiry has passed. The client should refresh and retry. */
|
|
26
|
+
ErrorCode["TOKEN_EXPIRED"] = "TOKEN_EXPIRED";
|
|
27
|
+
// ── 403 Forbidden ───────────────────────────────────────────────────────
|
|
28
|
+
/** Authenticated, but the action is not permitted for this principal. */
|
|
29
|
+
ErrorCode["FORBIDDEN"] = "FORBIDDEN";
|
|
30
|
+
/** Authenticated, but the principal's role lacks the required permission. */
|
|
31
|
+
ErrorCode["INSUFFICIENT_PERMISSION"] = "INSUFFICIENT_PERMISSION";
|
|
32
|
+
/** The resource belongs to another tenant. Emitted instead of leaking its existence. */
|
|
33
|
+
ErrorCode["TENANT_MISMATCH"] = "TENANT_MISMATCH";
|
|
34
|
+
// ── 404 Not Found ───────────────────────────────────────────────────────
|
|
35
|
+
ErrorCode["RESOURCE_NOT_FOUND"] = "RESOURCE_NOT_FOUND";
|
|
36
|
+
// ── 409 Conflict ────────────────────────────────────────────────────────
|
|
37
|
+
/** The request contradicts current state — a stale version, a closed aggregate. */
|
|
38
|
+
ErrorCode["RESOURCE_CONFLICT"] = "RESOURCE_CONFLICT";
|
|
39
|
+
/** A uniqueness constraint would be violated. */
|
|
40
|
+
ErrorCode["RESOURCE_ALREADY_EXISTS"] = "RESOURCE_ALREADY_EXISTS";
|
|
41
|
+
// ── 413 / 422 ───────────────────────────────────────────────────────────
|
|
42
|
+
ErrorCode["PAYLOAD_TOO_LARGE"] = "PAYLOAD_TOO_LARGE";
|
|
43
|
+
/** Syntactically valid and well-formed, but rejected by a business rule. */
|
|
44
|
+
ErrorCode["UNPROCESSABLE_ENTITY"] = "UNPROCESSABLE_ENTITY";
|
|
45
|
+
// ── 429 Too Many Requests ───────────────────────────────────────────────
|
|
46
|
+
ErrorCode["RATE_LIMIT_EXCEEDED"] = "RATE_LIMIT_EXCEEDED";
|
|
47
|
+
// ── 5xx ─────────────────────────────────────────────────────────────────
|
|
48
|
+
/** Catch-all for an unhandled failure. Details are logged, never returned. */
|
|
49
|
+
ErrorCode["INTERNAL_ERROR"] = "INTERNAL_ERROR";
|
|
50
|
+
/** A third-party or downstream service returned an error we could not recover from. */
|
|
51
|
+
ErrorCode["EXTERNAL_SERVICE_ERROR"] = "EXTERNAL_SERVICE_ERROR";
|
|
52
|
+
/** A dependency is unreachable or the service is shutting down. Retryable. */
|
|
53
|
+
ErrorCode["SERVICE_UNAVAILABLE"] = "SERVICE_UNAVAILABLE";
|
|
54
|
+
/** A downstream call exceeded its deadline. Retryable. */
|
|
55
|
+
ErrorCode["DEPENDENCY_TIMEOUT"] = "DEPENDENCY_TIMEOUT";
|
|
56
|
+
})(ErrorCode || (ErrorCode = {}));
|
|
57
|
+
//# sourceMappingURL=error-code.enum.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error-code.enum.js","sourceRoot":"","sources":["../../../src/enum/error-code.enum.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,MAAM,CAAN,IAAY,SAiDX;AAjDD,WAAY,SAAS;IACjB,2EAA2E;IAC3E,+EAA+E;IAC/E,oDAAuC,CAAA;IACvC,sEAAsE;IACtE,oDAAuC,CAAA;IAEvC,2EAA2E;IAC3E,oEAAoE;IACpE,gDAAmC,CAAA;IACnC,kGAAkG;IAClG,wDAA2C,CAAA;IAC3C,iGAAiG;IACjG,4CAA+B,CAAA;IAE/B,2EAA2E;IAC3E,yEAAyE;IACzE,oCAAuB,CAAA;IACvB,6EAA6E;IAC7E,gEAAmD,CAAA;IACnD,wFAAwF;IACxF,gDAAmC,CAAA;IAEnC,2EAA2E;IAC3E,sDAAyC,CAAA;IAEzC,2EAA2E;IAC3E,mFAAmF;IACnF,oDAAuC,CAAA;IACvC,iDAAiD;IACjD,gEAAmD,CAAA;IAEnD,2EAA2E;IAC3E,oDAAuC,CAAA;IACvC,4EAA4E;IAC5E,0DAA6C,CAAA;IAE7C,2EAA2E;IAC3E,wDAA2C,CAAA;IAE3C,2EAA2E;IAC3E,8EAA8E;IAC9E,8CAAiC,CAAA;IACjC,uFAAuF;IACvF,8DAAiD,CAAA;IACjD,8EAA8E;IAC9E,wDAA2C,CAAA;IAC3C,0DAA0D;IAC1D,sDAAyC,CAAA;AAC7C,CAAC,EAjDW,SAAS,KAAT,SAAS,QAiDpB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/enum/index.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/enum/index.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import type { ErrorCode } from '../enum/error-code.enum.js';
|
|
2
|
+
import type { Maybe } from './nil.type.js';
|
|
3
|
+
/**
|
|
4
|
+
* Envelope for a successful HTTP response.
|
|
5
|
+
*
|
|
6
|
+
* Every service wraps its payload in this shape, so a client can branch on
|
|
7
|
+
* `success` before touching anything else and never has to guess whether a
|
|
8
|
+
* 200 body is data or an error report.
|
|
9
|
+
*
|
|
10
|
+
* @typeParam T - the response payload type.
|
|
11
|
+
*/
|
|
12
|
+
export interface ApiSuccessResponse<T> {
|
|
13
|
+
success: true;
|
|
14
|
+
data: T;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* The error half of {@link ApiErrorResponse}.
|
|
18
|
+
*
|
|
19
|
+
* `message` is for humans and may change at any time — clients branch on
|
|
20
|
+
* `code`, never on message text.
|
|
21
|
+
*/
|
|
22
|
+
export interface ApiErrorBody {
|
|
23
|
+
/** Stable, machine-readable classification. The only field safe to branch on. */
|
|
24
|
+
code: ErrorCode;
|
|
25
|
+
/** Human-readable summary. Safe to surface to a developer, not to an end user. */
|
|
26
|
+
message: string;
|
|
27
|
+
/**
|
|
28
|
+
* Structured context — which field failed validation, which constraint was
|
|
29
|
+
* violated. Never contains secrets, tokens, or raw upstream payloads.
|
|
30
|
+
*/
|
|
31
|
+
details?: Maybe<Record<string, unknown>>;
|
|
32
|
+
/**
|
|
33
|
+
* The request's correlation id, echoed so a user can quote it in a support
|
|
34
|
+
* ticket and the whole request can be pulled out of the logs.
|
|
35
|
+
*/
|
|
36
|
+
correlationId?: Maybe<string>;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Envelope for a failed HTTP response, emitted by the SDK's global exception
|
|
40
|
+
* filter for every non-2xx status.
|
|
41
|
+
*/
|
|
42
|
+
export interface ApiErrorResponse {
|
|
43
|
+
success: false;
|
|
44
|
+
error: ApiErrorBody;
|
|
45
|
+
/** ISO-8601 timestamp of when the error was rendered. */
|
|
46
|
+
timestamp: string;
|
|
47
|
+
/** Request path that produced the error, without the query string. */
|
|
48
|
+
path: string;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Discriminated union of both envelopes. Narrow on `success`:
|
|
52
|
+
*
|
|
53
|
+
* ```ts
|
|
54
|
+
* if (!response.success) {
|
|
55
|
+
* return handle(response.error.code);
|
|
56
|
+
* }
|
|
57
|
+
* use(response.data);
|
|
58
|
+
* ```
|
|
59
|
+
*
|
|
60
|
+
* @typeParam T - the payload type on the success branch.
|
|
61
|
+
*/
|
|
62
|
+
export type ApiResponse<T> = ApiSuccessResponse<T> | ApiErrorResponse;
|
|
63
|
+
//# sourceMappingURL=api-response.type.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-response.type.d.ts","sourceRoot":"","sources":["../../../src/type/api-response.type.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AAE5D,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAE3C;;;;;;;;GAQG;AACH,MAAM,WAAW,kBAAkB,CAAC,CAAC;IACjC,OAAO,EAAE,IAAI,CAAC;IACd,IAAI,EAAE,CAAC,CAAC;CACX;AAED;;;;;GAKG;AACH,MAAM,WAAW,YAAY;IACzB,iFAAiF;IACjF,IAAI,EAAE,SAAS,CAAC;IAEhB,kFAAkF;IAClF,OAAO,EAAE,MAAM,CAAC;IAEhB;;;OAGG;IACH,OAAO,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAEzC;;;OAGG;IACH,aAAa,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;CACjC;AAED;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC7B,OAAO,EAAE,KAAK,CAAC;IACf,KAAK,EAAE,YAAY,CAAC;IAEpB,yDAAyD;IACzD,SAAS,EAAE,MAAM,CAAC;IAElB,sEAAsE;IACtE,IAAI,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,WAAW,CAAC,CAAC,IAAI,kBAAkB,CAAC,CAAC,CAAC,GAAG,gBAAgB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-response.type.js","sourceRoot":"","sources":["../../../src/type/api-response.type.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { Nullable } from './nil.type.js';
|
|
2
|
+
/**
|
|
3
|
+
* A cursor-paginated slice of a collection.
|
|
4
|
+
*
|
|
5
|
+
* The default for anything that grows while it is being read — delivery logs,
|
|
6
|
+
* captures, conversation messages. A cursor is anchored to a row rather than a
|
|
7
|
+
* position, so inserts during paging cannot make the reader skip or repeat.
|
|
8
|
+
*
|
|
9
|
+
* The cursor is an **opaque** string. Callers pass it back verbatim and never
|
|
10
|
+
* parse it; its encoding is an implementation detail of the service that issued
|
|
11
|
+
* it and may change without a version bump.
|
|
12
|
+
*
|
|
13
|
+
* @typeParam T - the element type of a single row.
|
|
14
|
+
*/
|
|
15
|
+
export interface CursorPage<T> {
|
|
16
|
+
/** The rows for this page, in the requested order. */
|
|
17
|
+
items: T[];
|
|
18
|
+
/** Cursor to pass as `after` for the next page, or `null` when the end is reached. */
|
|
19
|
+
nextCursor: Nullable<string>;
|
|
20
|
+
/**
|
|
21
|
+
* Whether another page exists. Equivalent to `nextCursor !== null`, exposed
|
|
22
|
+
* separately so UI code can render a "load more" affordance without
|
|
23
|
+
* reasoning about the cursor at all.
|
|
24
|
+
*/
|
|
25
|
+
hasMore: boolean;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=cursor-page.type.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cursor-page.type.d.ts","sourceRoot":"","sources":["../../../src/type/cursor-page.type.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAE9C;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,UAAU,CAAC,CAAC;IACzB,sDAAsD;IACtD,KAAK,EAAE,CAAC,EAAE,CAAC;IAEX,sFAAsF;IACtF,UAAU,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IAE7B;;;;OAIG;IACH,OAAO,EAAE,OAAO,CAAC;CACpB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cursor-page.type.js","sourceRoot":"","sources":["../../../src/type/cursor-page.type.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/type/index.ts"],"names":[],"mappings":"AAAA,cAAc,wBAAwB,CAAC;AACvC,cAAc,uBAAuB,CAAC;AACtC,cAAc,eAAe,CAAC;AAC9B,cAAc,qBAAqB,CAAC;AACpC,cAAc,gBAAgB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/type/index.ts"],"names":[],"mappings":"AAAA,cAAc,wBAAwB,CAAC;AACvC,cAAc,uBAAuB,CAAC;AACtC,cAAc,eAAe,CAAC;AAC9B,cAAc,qBAAqB,CAAC;AACpC,cAAc,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Represents a value that is either `null` or `undefined`.
|
|
3
|
+
*
|
|
4
|
+
* Useful for excluding nullish values from union types via `Exclude<T, Nil>`
|
|
5
|
+
* or for explicitly modelling absent values.
|
|
6
|
+
*/
|
|
7
|
+
export type Nil = null | undefined;
|
|
8
|
+
/**
|
|
9
|
+
* A value that may be `T` or absent (`null` / `undefined`).
|
|
10
|
+
*
|
|
11
|
+
* Prefer `Maybe<T>` over inline `T | null | undefined` for consistency
|
|
12
|
+
* across services.
|
|
13
|
+
*/
|
|
14
|
+
export type Maybe<T> = T | Nil;
|
|
15
|
+
/**
|
|
16
|
+
* A value that may be `T` or `null` (but never `undefined`).
|
|
17
|
+
*
|
|
18
|
+
* Use this for anything that crosses the wire: `JSON.stringify` drops
|
|
19
|
+
* `undefined` properties, so a nullable API field must be `null` to survive
|
|
20
|
+
* serialization.
|
|
21
|
+
*/
|
|
22
|
+
export type Nullable<T> = T | null;
|
|
23
|
+
//# sourceMappingURL=nil.type.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nil.type.d.ts","sourceRoot":"","sources":["../../../src/type/nil.type.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,MAAM,GAAG,GAAG,IAAI,GAAG,SAAS,CAAC;AAEnC;;;;;GAKG;AACH,MAAM,MAAM,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC;AAE/B;;;;;;GAMG;AACH,MAAM,MAAM,QAAQ,CAAC,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nil.type.js","sourceRoot":"","sources":["../../../src/type/nil.type.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* An offset-paginated slice of a collection.
|
|
3
|
+
*
|
|
4
|
+
* Use this where the client needs to jump to an arbitrary page or show a total
|
|
5
|
+
* count. Where the collection is large, append-only, or mutating under the
|
|
6
|
+
* reader (delivery logs, captures, messages), prefer `CursorPage<T>` — offset
|
|
7
|
+
* paging over a moving list skips and repeats rows.
|
|
8
|
+
*
|
|
9
|
+
* @typeParam T - the element type of a single row.
|
|
10
|
+
*/
|
|
11
|
+
export interface Paginated<T> {
|
|
12
|
+
/** The rows for the requested page, in the requested order. */
|
|
13
|
+
items: T[];
|
|
14
|
+
/** Total rows matching the query across every page, ignoring `limit`/`offset`. */
|
|
15
|
+
total: number;
|
|
16
|
+
/** Maximum rows the caller asked for. `items.length` may be smaller on the last page. */
|
|
17
|
+
limit: number;
|
|
18
|
+
/** Rows skipped before this page. Zero-based. */
|
|
19
|
+
offset: number;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=paginated.type.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paginated.type.d.ts","sourceRoot":"","sources":["../../../src/type/paginated.type.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,MAAM,WAAW,SAAS,CAAC,CAAC;IACxB,+DAA+D;IAC/D,KAAK,EAAE,CAAC,EAAE,CAAC;IAEX,kFAAkF;IAClF,KAAK,EAAE,MAAM,CAAC;IAEd,yFAAyF;IACzF,KAAK,EAAE,MAAM,CAAC;IAEd,iDAAiD;IACjD,MAAM,EAAE,MAAM,CAAC;CAClB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paginated.type.js","sourceRoot":"","sources":["../../../src/type/paginated.type.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A UUID string value.
|
|
3
|
+
*
|
|
4
|
+
* Structurally identical to the `UUID` type from `node:crypto`, but declared
|
|
5
|
+
* here rather than re-exported: `@iveri/contracts` compiles into browser
|
|
6
|
+
* bundles, and importing from `node:crypto` — even type-only — would force
|
|
7
|
+
* every frontend to depend on `@types/node`.
|
|
8
|
+
*
|
|
9
|
+
* This is a shape hint, not a guarantee. Validation happens at the edge with
|
|
10
|
+
* `@IsUUID()` on the request DTO.
|
|
11
|
+
*/
|
|
12
|
+
export type UUID = `${string}-${string}-${string}-${string}-${string}`;
|
|
13
|
+
//# sourceMappingURL=uuid.type.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"uuid.type.d.ts","sourceRoot":"","sources":["../../../src/type/uuid.type.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,MAAM,MAAM,IAAI,GAAG,GAAG,MAAM,IAAI,MAAM,IAAI,MAAM,IAAI,MAAM,IAAI,MAAM,EAAE,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"uuid.type.js","sourceRoot":"","sources":["../../../src/type/uuid.type.ts"],"names":[],"mappings":""}
|
package/package.json
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@iveri/contracts",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Wire contracts shared by every Iveri backend and frontend. Zero runtime dependencies.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/iverihq/iveri-contracts.git"
|
|
9
|
+
},
|
|
10
|
+
"publishConfig": {
|
|
11
|
+
"access": "public"
|
|
12
|
+
},
|
|
13
|
+
"engines": {
|
|
14
|
+
"node": ">=22"
|
|
15
|
+
},
|
|
16
|
+
"packageManager": "pnpm@9.12.0",
|
|
17
|
+
"type": "commonjs",
|
|
18
|
+
"main": "./dist/cjs/index.js",
|
|
19
|
+
"module": "./dist/esm/index.js",
|
|
20
|
+
"types": "./dist/cjs/index.d.ts",
|
|
21
|
+
"exports": {
|
|
22
|
+
".": {
|
|
23
|
+
"types": "./dist/cjs/index.d.ts",
|
|
24
|
+
"import": "./dist/esm/index.js",
|
|
25
|
+
"require": "./dist/cjs/index.js"
|
|
26
|
+
},
|
|
27
|
+
"./package.json": "./package.json"
|
|
28
|
+
},
|
|
29
|
+
"sideEffects": false,
|
|
30
|
+
"files": [
|
|
31
|
+
"dist",
|
|
32
|
+
"README.md"
|
|
33
|
+
],
|
|
34
|
+
"scripts": {
|
|
35
|
+
"clean": "rimraf dist tsconfig.*.tsbuildinfo",
|
|
36
|
+
"build": "pnpm clean && tsc -p tsconfig.cjs.json && tsc -p tsconfig.esm.json && node ./scripts/write-dist-package-json.mjs && node ./scripts/verify-zero-runtime-deps.mjs",
|
|
37
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
38
|
+
"test": "jest",
|
|
39
|
+
"lint": "eslint .",
|
|
40
|
+
"format": "prettier --write .",
|
|
41
|
+
"format:check": "prettier --check ."
|
|
42
|
+
},
|
|
43
|
+
"prettier": "@iveri/prettier-config",
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"@iveri/eslint-config": "^0.1.0",
|
|
46
|
+
"@iveri/prettier-config": "^0.1.0",
|
|
47
|
+
"@iveri/tsconfig": "^0.1.0",
|
|
48
|
+
"@types/jest": "^29.5.14",
|
|
49
|
+
"@types/node": "^22.10.7",
|
|
50
|
+
"eslint": "^9.18.0",
|
|
51
|
+
"jest": "^29.7.0",
|
|
52
|
+
"prettier": "^3.4.2",
|
|
53
|
+
"rimraf": "^6.0.1",
|
|
54
|
+
"ts-jest": "^29.2.5",
|
|
55
|
+
"typescript": "^5.7.3"
|
|
56
|
+
}
|
|
57
|
+
}
|