@substrat-run/kernel 0.1.0 → 0.2.1
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 +2 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/scope-host.d.ts +102 -10
- package/dist/scope-host.d.ts.map +1 -1
- package/dist/ulid.d.ts.map +1 -1
- package/dist/ulid.js +44 -5
- package/dist/ulid.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -9,6 +9,8 @@ imports no platform APIs — Cloudflare specifics live only in adapters, and eve
|
|
|
9
9
|
adapter must pass the same conformance suite
|
|
10
10
|
([`@substrat-run/contract-tests`](https://npmjs.com/package/@substrat-run/contract-tests)).
|
|
11
11
|
|
|
12
|
+
**Full documentation: https://substrat.ahlstrand.es/reference/kernel**
|
|
13
|
+
|
|
12
14
|
## The scope-host contract
|
|
13
15
|
|
|
14
16
|
A *scope* is one isolation domain (a BRF, a filial, a brand) with its own SQLite
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type { ConsumerHandler, HostAdmin, ModuleRegistration, OperationContext, OperationHandler, ProvisionScopeInput, ScopedSql, ScopeHost, ScopeStub, SqlMigration, SqlValue, } from './scope-host.js';
|
|
1
|
+
export type { ConsumerHandler, GuardPredicate, HostAdmin, ModuleRegistration, OperationContext, OperationHandler, ProvisionScopeInput, ScopedSql, ScopeHost, ScopeStub, SqlMigration, SqlValue, } from './scope-host.js';
|
|
2
2
|
export { assertAllowed, denyAllChecker, PermissionDenied, UNSAFE_allowAllChecker, } from './permission-checker.js';
|
|
3
3
|
export type { PermissionChecker } from './permission-checker.js';
|
|
4
4
|
export { ulid } from './ulid.js';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,eAAe,EACf,SAAS,EACT,kBAAkB,EAClB,gBAAgB,EAChB,gBAAgB,EAChB,mBAAmB,EACnB,SAAS,EACT,SAAS,EACT,SAAS,EACT,YAAY,EACZ,QAAQ,GACT,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,aAAa,EACb,cAAc,EACd,gBAAgB,EAChB,sBAAsB,GACvB,MAAM,yBAAyB,CAAC;AACjC,YAAY,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AACjE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,eAAe,EACf,cAAc,EACd,SAAS,EACT,kBAAkB,EAClB,gBAAgB,EAChB,gBAAgB,EAChB,mBAAmB,EACnB,SAAS,EACT,SAAS,EACT,SAAS,EACT,YAAY,EACZ,QAAQ,GACT,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,aAAa,EACb,cAAc,EACd,gBAAgB,EAChB,sBAAsB,GACvB,MAAM,yBAAyB,CAAC;AACjC,YAAY,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AACjE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC"}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAcA,OAAO,EACL,aAAa,EACb,cAAc,EACd,gBAAgB,EAChB,sBAAsB,GACvB,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC"}
|
package/dist/scope-host.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { CapabilityGrant, Decision, DomainEvent, DomainEventInput, EntityRef, Jurisdiction, ModuleManifest, Node, PermissionKey, PrincipalId, RoleAssignment, RoleDefinition, ScopeId, StorageShape, TenantId } from '@substrat-run/contracts';
|
|
1
|
+
import type { AdminLogEntry, CapabilityGrant, CreateTenantInput, Decision, DomainEvent, DomainEventInput, EntityRef, IdentityLink, Jurisdiction, ModuleManifest, Node, PermissionKey, PlatformActorId, PrincipalId, ResolvedIdentity, RoleAssignment, RoleDefinition, ScopeId, StorageShape, Tenant, TenantId, TenantStatus } from '@substrat-run/contracts';
|
|
2
2
|
/**
|
|
3
3
|
* The scope-host contract — the adapter seam (§5.1 of the design doc).
|
|
4
4
|
*
|
|
@@ -65,24 +65,111 @@ export interface SqlMigration {
|
|
|
65
65
|
* idempotent. Ordering is guaranteed only within (scope, module) — K-11.
|
|
66
66
|
*/
|
|
67
67
|
export type ConsumerHandler = (ctx: OperationContext, event: DomainEvent) => void | Promise<void>;
|
|
68
|
+
/**
|
|
69
|
+
* A named, manifest-wired pre-condition on an operation (K-17; engine-protocol
|
|
70
|
+
* §6, open question 11). One module CONTRIBUTES a predicate under a name; a
|
|
71
|
+
* (usually different) module's manifest WIRES it to an operation via
|
|
72
|
+
* `guards: [{ before, predicate, config }]`. The kernel runs it inside the
|
|
73
|
+
* guarded operation's own transaction, immediately before the handler:
|
|
74
|
+
*
|
|
75
|
+
* throw → the operation is BLOCKED and the transaction rolls back (fail closed)
|
|
76
|
+
* return → the handler runs
|
|
77
|
+
*
|
|
78
|
+
* `config` is the manifest's config object, opaque to the kernel and parsed by
|
|
79
|
+
* the predicate itself; `input` is the (already structured-cloned) operation
|
|
80
|
+
* input. A predicate is a READ: it must not mutate — it is a gate, not a hook.
|
|
81
|
+
* Star topology holds — the guarded engine knows nothing of the guarding one.
|
|
82
|
+
*/
|
|
83
|
+
export type GuardPredicate = (ctx: OperationContext, config: Record<string, unknown>, input: unknown) => void | Promise<void>;
|
|
68
84
|
export interface ModuleRegistration {
|
|
69
85
|
manifest: ModuleManifest;
|
|
70
86
|
migrations?: SqlMigration[];
|
|
71
87
|
operations?: Record<string, OperationHandler<never, unknown>>;
|
|
72
88
|
/** eventType → handler; the types must appear in manifest.events.consumes. */
|
|
73
89
|
consumers?: Record<string, ConsumerHandler>;
|
|
90
|
+
/**
|
|
91
|
+
* Named guard predicates this module contributes to the host — the code half
|
|
92
|
+
* of `manifest.guards`. Names are module-namespaced like operations
|
|
93
|
+
* ('protocol/all-signed'). Predicate names are global: two modules may not
|
|
94
|
+
* contribute the same name.
|
|
95
|
+
*/
|
|
96
|
+
predicates?: Record<string, GuardPredicate>;
|
|
74
97
|
}
|
|
75
98
|
/**
|
|
76
|
-
* Admin surface for enforcement input (design doc §4;
|
|
77
|
-
*
|
|
99
|
+
* Admin surface for enforcement input (design doc §4; control-plane.md §4.4).
|
|
100
|
+
*
|
|
101
|
+
* Every mutation is a control-plane action: it takes a `PlatformActorId` — the
|
|
102
|
+
* authenticated staff subject, typed distinctly from a tenant `PrincipalId` so
|
|
103
|
+
* the compiler refuses to confuse them — and writes an append-only audit row
|
|
104
|
+
* stamped platform-side (actor, action, target, before/after, timestamp). The
|
|
105
|
+
* actor is never a principal in any tenant, and the record is never supplied by
|
|
106
|
+
* the caller. This is the one surface that must not be retrofitted (K-20): a
|
|
107
|
+
* surface that can act without a durable record of who acted is worse than none.
|
|
108
|
+
*
|
|
109
|
+
* Locally the actor is a dev stub (control-plane.md §6); real staff auth (SSO,
|
|
110
|
+
* MFA) gates EXPOSING this surface, not building it — D-16 cashed in.
|
|
111
|
+
*
|
|
112
|
+
* The whole surface is ASYNCHRONOUS (every method returns a Promise) because a
|
|
113
|
+
* durable/remote control plane — e.g. a Cloudflare Durable Object — cannot be
|
|
114
|
+
* backed synchronously: reads may cross an RPC boundary and writes must await a
|
|
115
|
+
* durable record before returning. The second adapter surfaced this (D-14); a
|
|
116
|
+
* synchronous admin interface could not be honoured by anything but an in-memory
|
|
117
|
+
* store, so the contract is async everywhere. (`registerModule`/`defineOperation`
|
|
118
|
+
* stay sync — they are code-time bookkeeping, not control-plane state.)
|
|
78
119
|
*/
|
|
79
120
|
export interface HostAdmin {
|
|
80
|
-
defineRole(tenantId: TenantId, role: RoleDefinition): void
|
|
81
|
-
assignRole(assignment: RoleAssignment): void
|
|
82
|
-
grant(grant: CapabilityGrant): void
|
|
121
|
+
defineRole(actor: PlatformActorId, tenantId: TenantId, role: RoleDefinition): Promise<void>;
|
|
122
|
+
assignRole(actor: PlatformActorId, assignment: RoleAssignment): Promise<void>;
|
|
123
|
+
grant(actor: PlatformActorId, grant: CapabilityGrant): Promise<void>;
|
|
83
124
|
/** Grant to an organization (portal customers); members reach it via membership tuples. */
|
|
84
|
-
grantToOrg(orgId: string, permission: PermissionKey, node: Node, entity?: EntityRef): void
|
|
85
|
-
addMember(tenantId: TenantId, principal: PrincipalId, orgId: string): void
|
|
125
|
+
grantToOrg(actor: PlatformActorId, orgId: string, permission: PermissionKey, node: Node, entity?: EntityRef): Promise<void>;
|
|
126
|
+
addMember(actor: PlatformActorId, tenantId: TenantId, principal: PrincipalId, orgId: string): Promise<void>;
|
|
127
|
+
/**
|
|
128
|
+
* Persist a tenant. Idempotent on the id — re-creating an existing tenant is a
|
|
129
|
+
* no-op, not an error (control-plane.md §4.1). `status` starts `active` and
|
|
130
|
+
* `createdAt` is stamped host-side. This is what replaces "a tenant is a ULID
|
|
131
|
+
* nobody used before" with a real record.
|
|
132
|
+
*/
|
|
133
|
+
createTenant(actor: PlatformActorId, input: CreateTenantInput): Promise<void>;
|
|
134
|
+
/**
|
|
135
|
+
* Transition a tenant's status. `suspended` fails `getScope` closed for every
|
|
136
|
+
* scope under the tenant (K-3's path) — the containment lever for non-payment
|
|
137
|
+
* or an incident, reversible without deleting anything.
|
|
138
|
+
*/
|
|
139
|
+
setTenantStatus(actor: PlatformActorId, tenantId: TenantId, status: TenantStatus): Promise<void>;
|
|
140
|
+
/** The tenant registry — the directory's inventory (control-plane.md §4.5 console item 1). */
|
|
141
|
+
listTenants(): Promise<Tenant[]>;
|
|
142
|
+
getTenant(tenantId: TenantId): Promise<Tenant | undefined>;
|
|
143
|
+
/** active → suspended. Reversible containment (incident, dispute). */
|
|
144
|
+
suspendScope(actor: PlatformActorId, tenantId: TenantId, scopeId: ScopeId): Promise<void>;
|
|
145
|
+
/** suspended → active. */
|
|
146
|
+
unsuspendScope(actor: PlatformActorId, tenantId: TenantId, scopeId: ScopeId): Promise<void>;
|
|
147
|
+
/** active|suspended → archived. Stops the active-scope meter (§9). */
|
|
148
|
+
archiveScope(actor: PlatformActorId, tenantId: TenantId, scopeId: ScopeId): Promise<void>;
|
|
149
|
+
/**
|
|
150
|
+
* archived → active. A RESTORE, never a flag flip (control-plane.md §4.2):
|
|
151
|
+
* §9's meter can only charge on "active scope" if un-archiving is a deliberate,
|
|
152
|
+
* audited act. Jurisdiction is untouched — it is fixed at provisioning (K-7).
|
|
153
|
+
*/
|
|
154
|
+
unarchiveScope(actor: PlatformActorId, tenantId: TenantId, scopeId: ScopeId): Promise<void>;
|
|
155
|
+
/** Turn a SKU flag on for a tenant. Idempotent; audited. */
|
|
156
|
+
grantEntitlement(actor: PlatformActorId, tenantId: TenantId, entitlementKey: string): Promise<void>;
|
|
157
|
+
/** Turn it off. A tenant's scopes lose access to that module's operations. */
|
|
158
|
+
revokeEntitlement(actor: PlatformActorId, tenantId: TenantId, entitlementKey: string): Promise<void>;
|
|
159
|
+
/** The tenant's held SKU flags (control-plane.md §5 meter 2). */
|
|
160
|
+
listEntitlements(tenantId: TenantId): Promise<string[]>;
|
|
161
|
+
/** Bind an external identity to a principal + home node. Idempotent on (provider, externalId); audited. */
|
|
162
|
+
linkIdentity(actor: PlatformActorId, input: IdentityLink): Promise<void>;
|
|
163
|
+
/** Resolve an external identity to its principal + home node — the auth adapter's read path. */
|
|
164
|
+
resolveIdentity(provider: string, externalId: string): Promise<ResolvedIdentity | undefined>;
|
|
165
|
+
/**
|
|
166
|
+
* The append-only admin audit trail, newest-comparable last (ULID order is
|
|
167
|
+
* chronological). Read path for the console history and the permission-diff
|
|
168
|
+
* human checkpoint (control-plane.md §4.5).
|
|
169
|
+
*/
|
|
170
|
+
auditLog(filter?: {
|
|
171
|
+
tenantId?: TenantId;
|
|
172
|
+
}): Promise<AdminLogEntry[]>;
|
|
86
173
|
}
|
|
87
174
|
export interface ProvisionScopeInput {
|
|
88
175
|
tenantId: TenantId;
|
|
@@ -97,8 +184,13 @@ export interface ScopeHost {
|
|
|
97
184
|
* resolves to another tenant's scope.
|
|
98
185
|
*/
|
|
99
186
|
getScope(principal: PrincipalId, tenantId: TenantId, scopeId: ScopeId): Promise<ScopeStub>;
|
|
100
|
-
/**
|
|
101
|
-
|
|
187
|
+
/**
|
|
188
|
+
* The entry scope-lifecycle transition (control-plane.md §4.2): idempotent,
|
|
189
|
+
* journaled, audited. Requires an existing ACTIVE tenant — a scope with no
|
|
190
|
+
* tenant record is the "tenant is an FK string" hole §4.1 closes, so it fails
|
|
191
|
+
* closed. Jurisdiction is fixed here forever (K-7).
|
|
192
|
+
*/
|
|
193
|
+
provisionScope(actor: PlatformActorId, input: ProvisionScopeInput): Promise<void>;
|
|
102
194
|
/** Enforcement-input writes: roles, assignments, grants, membership. */
|
|
103
195
|
readonly admin: HostAdmin;
|
|
104
196
|
/** Register a module: validates the manifest, applies migrations lazily per scope. */
|
package/dist/scope-host.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scope-host.d.ts","sourceRoot":"","sources":["../src/scope-host.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,eAAe,EACf,QAAQ,EACR,WAAW,EACX,gBAAgB,EAChB,SAAS,EACT,YAAY,EACZ,cAAc,EACd,IAAI,EACJ,aAAa,EACb,WAAW,EACX,cAAc,EACd,cAAc,EACd,OAAO,EACP,YAAY,EACZ,QAAQ,
|
|
1
|
+
{"version":3,"file":"scope-host.d.ts","sourceRoot":"","sources":["../src/scope-host.ts"],"names":[],"mappings":"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"}
|
package/dist/ulid.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ulid.d.ts","sourceRoot":"","sources":["../src/ulid.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ulid.d.ts","sourceRoot":"","sources":["../src/ulid.ts"],"names":[],"mappings":"AAqCA,wBAAgB,IAAI,CAAC,GAAG,GAAE,MAAmB,GAAG,MAAM,CAwBrD"}
|
package/dist/ulid.js
CHANGED
|
@@ -1,17 +1,56 @@
|
|
|
1
|
-
// Minimal ULID: 48-bit timestamp + 80 random
|
|
1
|
+
// Minimal ULID: 48-bit timestamp + 80-bit random, Crockford base32.
|
|
2
2
|
// Kept dependency-free; kernel IDs must be sortable and opaque.
|
|
3
|
+
//
|
|
4
|
+
// MONOTONIC within a process (the ULID spec's monotonic factory): two IDs minted
|
|
5
|
+
// in the same millisecond still sort in creation order — the low bits increment
|
|
6
|
+
// instead of being re-randomized. This is load-bearing: the audit log and the
|
|
7
|
+
// event outbox both document "ULID order is chronological" and order by id, so a
|
|
8
|
+
// non-monotonic id would make same-millisecond rows sort randomly.
|
|
3
9
|
const B32 = '0123456789ABCDEFGHJKMNPQRSTVWXYZ';
|
|
10
|
+
// Monotonic state (per process/isolate — exactly the scope where a single writer
|
|
11
|
+
// orders its own rows). The random part is held as 16 base32 digits (0–31).
|
|
12
|
+
let lastTime = -1;
|
|
13
|
+
const lastRand = new Array(16).fill(0);
|
|
14
|
+
function freshRandom() {
|
|
15
|
+
const bytes = crypto.getRandomValues(new Uint8Array(16));
|
|
16
|
+
for (let i = 0; i < 16; i++)
|
|
17
|
+
lastRand[i] = bytes[i] % 32; // 256 % 32 === 0 → uniform
|
|
18
|
+
}
|
|
19
|
+
/** Step the 80-bit random part by one, with carry. Returns false on overflow. */
|
|
20
|
+
function incrementRandom() {
|
|
21
|
+
for (let i = 15; i >= 0; i--) {
|
|
22
|
+
if (lastRand[i] < 31) {
|
|
23
|
+
lastRand[i]++;
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
lastRand[i] = 0;
|
|
27
|
+
}
|
|
28
|
+
return false; // all digits were 31 — overflowed (astronomically rare)
|
|
29
|
+
}
|
|
4
30
|
export function ulid(now = Date.now()) {
|
|
31
|
+
let time = now;
|
|
32
|
+
if (time <= lastTime) {
|
|
33
|
+
// Same or backwards clock: keep the last timestamp and step the random part
|
|
34
|
+
// so the id still increases. On the (impossible) overflow, bump the ms.
|
|
35
|
+
time = lastTime;
|
|
36
|
+
if (!incrementRandom()) {
|
|
37
|
+
time = lastTime + 1;
|
|
38
|
+
freshRandom();
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
freshRandom();
|
|
43
|
+
}
|
|
44
|
+
lastTime = time;
|
|
5
45
|
let ts = '';
|
|
6
|
-
let t =
|
|
46
|
+
let t = time;
|
|
7
47
|
for (let i = 0; i < 10; i++) {
|
|
8
48
|
ts = B32[t % 32] + ts;
|
|
9
49
|
t = Math.floor(t / 32);
|
|
10
50
|
}
|
|
11
|
-
const rand = crypto.getRandomValues(new Uint8Array(16));
|
|
12
51
|
let r = '';
|
|
13
|
-
for (const
|
|
14
|
-
r += B32[
|
|
52
|
+
for (const d of lastRand)
|
|
53
|
+
r += B32[d];
|
|
15
54
|
return ts + r;
|
|
16
55
|
}
|
|
17
56
|
//# sourceMappingURL=ulid.js.map
|
package/dist/ulid.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ulid.js","sourceRoot":"","sources":["../src/ulid.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"ulid.js","sourceRoot":"","sources":["../src/ulid.ts"],"names":[],"mappings":"AAAA,oEAAoE;AACpE,gEAAgE;AAChE,EAAE;AACF,iFAAiF;AACjF,gFAAgF;AAChF,8EAA8E;AAC9E,iFAAiF;AACjF,mEAAmE;AAMnE,MAAM,GAAG,GAAG,kCAAkC,CAAC;AAE/C,iFAAiF;AACjF,4EAA4E;AAC5E,IAAI,QAAQ,GAAG,CAAC,CAAC,CAAC;AAClB,MAAM,QAAQ,GAAa,IAAI,KAAK,CAAS,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAEzD,SAAS,WAAW;IAClB,MAAM,KAAK,GAAG,MAAM,CAAC,eAAe,CAAC,IAAI,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC;IACzD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE;QAAE,QAAQ,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAE,GAAG,EAAE,CAAC,CAAC,2BAA2B;AACxF,CAAC;AAED,iFAAiF;AACjF,SAAS,eAAe;IACtB,KAAK,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAC7B,IAAI,QAAQ,CAAC,CAAC,CAAE,GAAG,EAAE,EAAE,CAAC;YACtB,QAAQ,CAAC,CAAC,CAAE,EAAE,CAAC;YACf,OAAO,IAAI,CAAC;QACd,CAAC;QACD,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IAClB,CAAC;IACD,OAAO,KAAK,CAAC,CAAC,wDAAwD;AACxE,CAAC;AAED,MAAM,UAAU,IAAI,CAAC,MAAc,IAAI,CAAC,GAAG,EAAE;IAC3C,IAAI,IAAI,GAAG,GAAG,CAAC;IACf,IAAI,IAAI,IAAI,QAAQ,EAAE,CAAC;QACrB,4EAA4E;QAC5E,wEAAwE;QACxE,IAAI,GAAG,QAAQ,CAAC;QAChB,IAAI,CAAC,eAAe,EAAE,EAAE,CAAC;YACvB,IAAI,GAAG,QAAQ,GAAG,CAAC,CAAC;YACpB,WAAW,EAAE,CAAC;QAChB,CAAC;IACH,CAAC;SAAM,CAAC;QACN,WAAW,EAAE,CAAC;IAChB,CAAC;IACD,QAAQ,GAAG,IAAI,CAAC;IAEhB,IAAI,EAAE,GAAG,EAAE,CAAC;IACZ,IAAI,CAAC,GAAG,IAAI,CAAC;IACb,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC;QAC5B,EAAE,GAAG,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC,GAAG,EAAE,CAAC;QACtB,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;IACzB,CAAC;IACD,IAAI,CAAC,GAAG,EAAE,CAAC;IACX,KAAK,MAAM,CAAC,IAAI,QAAQ;QAAE,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC;IACtC,OAAO,EAAE,GAAG,CAAC,CAAC;AAChB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@substrat-run/kernel",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "Substrat kernel contracts and services — pure TypeScript, no platform imports (D-14)",
|
|
5
5
|
"license": "AGPL-3.0-only",
|
|
6
6
|
"repository": {
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"dist"
|
|
23
23
|
],
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@substrat-run/contracts": "^0.1
|
|
25
|
+
"@substrat-run/contracts": "^0.2.1"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
28
|
"typescript": "^5.6.0"
|