@cosmicdrift/kumiko-types 0.166.0 → 0.167.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 +5 -4
- package/package.json +4 -8
- package/src/event-store-types.ts +8 -0
- package/src/handlers.ts +1 -1
- package/src/kms-adapter-types.ts +0 -21
- package/src/secrets-types.ts +8 -3
- package/src/event-store-errors.ts +0 -54
package/README.md
CHANGED
|
@@ -7,9 +7,10 @@ Framework type definitions for Kumiko — `FeatureDefinition`, boot-check types,
|
|
|
7
7
|
and the pure engine types. Lets downstream consumers build against the type
|
|
8
8
|
contracts without importing the whole framework package.
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
`
|
|
12
|
-
`kumiko-bundled-features` declare
|
|
13
|
-
|
|
10
|
+
Carries no identity-sensitive runtime values: no classes, and brand symbols use
|
|
11
|
+
`Symbol.for`. Resolving two copies of this package is therefore harmless, so
|
|
12
|
+
`kumiko-framework`/`kumiko-bundled-features` declare it as a plain dependency.
|
|
13
|
+
The error classes callers branch on with `instanceof` live in `kumiko-framework`
|
|
14
|
+
(`/event-store`, `/crypto`), which stays a single copy.
|
|
14
15
|
|
|
15
16
|
See the [monorepo root README](../../README.md) for the broader pitch.
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cosmicdrift/kumiko-types",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Framework-Type-Definitions für Kumiko — FeatureDefinition, BootCheck-Types und die reinen Engine-Types. Erlaubt Downstream-Konsumenten, gegen die Type-Contracts zu bauen, ohne das ganze Framework-Package zu importieren. Enthaelt
|
|
3
|
+
"version": "0.167.0",
|
|
4
|
+
"description": "Framework-Type-Definitions für Kumiko — FeatureDefinition, BootCheck-Types und die reinen Engine-Types. Erlaubt Downstream-Konsumenten, gegen die Type-Contracts zu bauen, ohne das ganze Framework-Package zu importieren. Enthaelt keine identitaets-sensitiven Runtime-Werte mehr (Error-Klassen leben seit #1629 in kumiko-framework, Brand-Symbole nutzen Symbol.for) und ist deshalb eine plain dependency, keine peerDependency.",
|
|
5
5
|
"license": "BUSL-1.1",
|
|
6
6
|
"author": "Marc Frost <marc@cosmicdriftgamestudio.com>",
|
|
7
7
|
"repository": {
|
|
@@ -206,10 +206,6 @@
|
|
|
206
206
|
"types": "./src/secrets-types.ts",
|
|
207
207
|
"default": "./src/secrets-types.ts"
|
|
208
208
|
},
|
|
209
|
-
"./event-store-errors": {
|
|
210
|
-
"types": "./src/event-store-errors.ts",
|
|
211
|
-
"default": "./src/event-store-errors.ts"
|
|
212
|
-
},
|
|
213
209
|
"./kms-adapter-types": {
|
|
214
210
|
"types": "./src/kms-adapter-types.ts",
|
|
215
211
|
"default": "./src/kms-adapter-types.ts"
|
|
@@ -228,12 +224,12 @@
|
|
|
228
224
|
}
|
|
229
225
|
},
|
|
230
226
|
"devDependencies": {
|
|
231
|
-
"hono": "^4.12.
|
|
227
|
+
"hono": "^4.12.27",
|
|
232
228
|
"postgres": "^3.4.9",
|
|
233
229
|
"temporal-polyfill": "^0.3.2"
|
|
234
230
|
},
|
|
235
231
|
"peerDependencies": {
|
|
236
|
-
"hono": "^4.12.
|
|
232
|
+
"hono": "^4.12.27",
|
|
237
233
|
"postgres": "^3.4.9",
|
|
238
234
|
"temporal-polyfill": "^0.3.2"
|
|
239
235
|
},
|
package/src/event-store-types.ts
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
import type { TenantId } from "./identifiers";
|
|
2
2
|
|
|
3
|
+
// Structural shape of kumiko-framework's VersionConflictError. The class
|
|
4
|
+
// itself cannot live here (#1629) — this package must stay free of
|
|
5
|
+
// identity-sensitive runtime values so it can be a plain dependency.
|
|
6
|
+
export interface VersionConflict extends Error {
|
|
7
|
+
readonly aggregateId: string;
|
|
8
|
+
readonly expectedVersion: number;
|
|
9
|
+
}
|
|
10
|
+
|
|
3
11
|
export type EventMetadata = {
|
|
4
12
|
readonly userId: string;
|
|
5
13
|
readonly requestId?: string;
|
package/src/handlers.ts
CHANGED
|
@@ -689,7 +689,7 @@ export type UnsafeAppendEventFn = (args: AppendEventArgs) => Promise<void>;
|
|
|
689
689
|
// entire enclosing transaction.
|
|
690
690
|
export type TryAppendEventResult =
|
|
691
691
|
| { readonly ok: true; readonly event: import("./event-store-types").StoredEvent }
|
|
692
|
-
| { readonly ok: false; readonly conflict: import("./event-store-
|
|
692
|
+
| { readonly ok: false; readonly conflict: import("./event-store-types").VersionConflict };
|
|
693
693
|
|
|
694
694
|
export type TryAppendEventFn = (args: AppendEventArgs) => Promise<TryAppendEventResult>;
|
|
695
695
|
|
package/src/kms-adapter-types.ts
CHANGED
|
@@ -95,24 +95,3 @@ export type KmsAdapter = LocalKeyKmsAdapter | RemoteCryptoKmsAdapter;
|
|
|
95
95
|
export function isLocalKeyKmsAdapter(adapter: KmsAdapter): adapter is LocalKeyKmsAdapter {
|
|
96
96
|
return adapter.capabilities.mode === "local-key";
|
|
97
97
|
}
|
|
98
|
-
|
|
99
|
-
export class KeyErasedError extends Error {
|
|
100
|
-
constructor(public readonly subject: SubjectId) {
|
|
101
|
-
super(`Subject key erased: ${subjectIdToKey(subject)}`);
|
|
102
|
-
this.name = "KeyErasedError";
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
export class KeyNotFoundError extends Error {
|
|
107
|
-
constructor(public readonly subject: SubjectId) {
|
|
108
|
-
super(`Subject key not found: ${subjectIdToKey(subject)}`);
|
|
109
|
-
this.name = "KeyNotFoundError";
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
export class KeyAlreadyExistsError extends Error {
|
|
114
|
-
constructor(public readonly subject: SubjectId) {
|
|
115
|
-
super(`Subject key already exists: ${subjectIdToKey(subject)}`);
|
|
116
|
-
this.name = "KeyAlreadyExistsError";
|
|
117
|
-
}
|
|
118
|
-
}
|
package/src/secrets-types.ts
CHANGED
|
@@ -10,9 +10,14 @@ import type { TenantId } from "./identifiers";
|
|
|
10
10
|
// intentional. Framework code that sees `Secret<string>` knows the caller
|
|
11
11
|
// has already gone through the audited ctx.secrets.get path.
|
|
12
12
|
//
|
|
13
|
-
//
|
|
14
|
-
//
|
|
15
|
-
|
|
13
|
+
// Registered symbol, matching KUMIKO_*_SYMBOL in schema-table-types.ts. A
|
|
14
|
+
// plain Symbol() is per-copy: two resolved copies of this package brand with
|
|
15
|
+
// two different symbols, so createSecret() from one and isSecret() from the
|
|
16
|
+
// other disagree — and isSecret() is the ONLY thing assertNoSecretLeak has,
|
|
17
|
+
// so a false there serializes the plaintext into the response. The namespaced
|
|
18
|
+
// key makes accidental user-land collision implausible; a deliberate forge
|
|
19
|
+
// would only over-trigger the guard, which fails safe.
|
|
20
|
+
const SecretBrand: unique symbol = Symbol.for("kumiko.secret");
|
|
16
21
|
|
|
17
22
|
export type Secret<T = string> = {
|
|
18
23
|
readonly [SecretBrand]: true;
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
// Failure modes of the event-store's append() path. Surfaced as typed
|
|
2
|
-
// errors so the executor layer can map them to the framework's
|
|
3
|
-
// WriteResult error contract (version_conflict).
|
|
4
|
-
|
|
5
|
-
export class VersionConflictError extends Error {
|
|
6
|
-
public readonly aggregateId: string;
|
|
7
|
-
public readonly expectedVersion: number;
|
|
8
|
-
constructor(aggregateId: string, expectedVersion: number) {
|
|
9
|
-
super(
|
|
10
|
-
`Version conflict on aggregate ${aggregateId}: expected predecessor version ${expectedVersion}`,
|
|
11
|
-
);
|
|
12
|
-
this.name = "VersionConflictError";
|
|
13
|
-
this.aggregateId = aggregateId;
|
|
14
|
-
this.expectedVersion = expectedVersion;
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
// Thrown when append() collides on the partial unique index over
|
|
19
|
-
// metadata.idempotencyKey (tenant-scoped). Distinct from VersionConflictError:
|
|
20
|
-
// a version conflict means two writers raced the same predecessor; this
|
|
21
|
-
// means the same idempotency key was used twice, which is a caller-side
|
|
22
|
-
// retry that must have already appended once. Callers that set
|
|
23
|
-
// idempotencyKey should treat this as "already applied" rather than retry.
|
|
24
|
-
export class IdempotentAppendConflictError extends Error {
|
|
25
|
-
public readonly tenantId: string;
|
|
26
|
-
public readonly idempotencyKey: string;
|
|
27
|
-
constructor(tenantId: string, idempotencyKey: string) {
|
|
28
|
-
super(
|
|
29
|
-
`Idempotency conflict on tenant ${tenantId}: an event with idempotencyKey "${idempotencyKey}" was already appended.`,
|
|
30
|
-
);
|
|
31
|
-
this.name = "IdempotentAppendConflictError";
|
|
32
|
-
this.tenantId = tenantId;
|
|
33
|
-
this.idempotencyKey = idempotencyKey;
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// Thrown when ctx.appendEvent targets an archived stream. Archived aggregates
|
|
38
|
-
// are read-only — restoreStream() makes them writable again. The archive
|
|
39
|
-
// state is not carried on the events themselves; it lives on the sparse
|
|
40
|
-
// kumiko_archived_streams table. Handlers that need to branch on archive
|
|
41
|
-
// state should call ctx.isStreamArchived(id) first.
|
|
42
|
-
export class ArchivedStreamError extends Error {
|
|
43
|
-
public readonly tenantId: string;
|
|
44
|
-
public readonly aggregateId: string;
|
|
45
|
-
constructor(tenantId: string, aggregateId: string) {
|
|
46
|
-
super(
|
|
47
|
-
`Aggregate ${aggregateId} on tenant ${tenantId} is archived — appendEvent is blocked. ` +
|
|
48
|
-
`Call restoreStream() to re-open the stream before writing.`,
|
|
49
|
-
);
|
|
50
|
-
this.name = "ArchivedStreamError";
|
|
51
|
-
this.tenantId = tenantId;
|
|
52
|
-
this.aggregateId = aggregateId;
|
|
53
|
-
}
|
|
54
|
-
}
|