@supacloud/elysia 0.7.0 → 0.8.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 +16 -0
- package/dist/feature.d.ts +15 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +33 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -116,6 +116,15 @@ once is rejected.
|
|
|
116
116
|
Executes a compiler-emitted Job descriptor with its static aspect list and
|
|
117
117
|
compiler-generated job scope.
|
|
118
118
|
|
|
119
|
+
### `assertFeatureTransition(spec, state, event)`
|
|
120
|
+
|
|
121
|
+
Checks a declared feature transition against an authoritative state and returns
|
|
122
|
+
the destination state. Unknown events, stale/illegal states and inherited object
|
|
123
|
+
members fail with HTTP 409 / `FEATURE_TRANSITION_CONFLICT`; malformed destinations
|
|
124
|
+
fail with `FEATURE_SPEC_INVALID`. The helper is a matrix assertion, not a workflow
|
|
125
|
+
engine, persistence or authorization layer. Call it inside the application's
|
|
126
|
+
transaction and persist with a row lock or expected-version check.
|
|
127
|
+
|
|
119
128
|
### `ApplicationError`
|
|
120
129
|
|
|
121
130
|
Lightweight error class carrying HTTP `status`, machine-readable `code`, and
|
|
@@ -134,3 +143,10 @@ adapters. The memory harness is limited to deterministic HTTP, key-value
|
|
|
134
143
|
transaction and object-storage contract tests.
|
|
135
144
|
`policy` supplies explicit permission grants/revocations and idempotency claims;
|
|
136
145
|
`storage.failNext()` makes storage failure paths deterministic.
|
|
146
|
+
|
|
147
|
+
Set `memoryGovernance: true` to enable test-only authorization, transaction,
|
|
148
|
+
idempotency and audit adapters; permissions still require explicit grants.
|
|
149
|
+
HTTP receipt fingerprints include route, body, params, query and business
|
|
150
|
+
headers, not mutable request scopes/services or identity/tracing transport.
|
|
151
|
+
Authorization runs again on a replay. Use durable application-owned adapters
|
|
152
|
+
for production receipts, transactions and audits.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/** Structural contract: the runtime does not import the compiler or discover metadata. */
|
|
2
|
+
export interface FeatureTransitionSpec {
|
|
3
|
+
name: string;
|
|
4
|
+
states: readonly string[];
|
|
5
|
+
transitions: Readonly<Record<string, {
|
|
6
|
+
from: string;
|
|
7
|
+
to: string;
|
|
8
|
+
}>>;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Check a declared transition against an authoritative state read by the caller.
|
|
12
|
+
* This is a matrix assertion, not persistence, authorization, or an FSM engine.
|
|
13
|
+
* Call inside the application's transaction and persist with a version check.
|
|
14
|
+
*/
|
|
15
|
+
export declare function assertFeatureTransition<Spec extends FeatureTransitionSpec>(spec: Spec, state: string, event: string): Spec["states"][number];
|
package/dist/index.d.ts
CHANGED
|
@@ -90,6 +90,8 @@ export interface CommandInvocation {
|
|
|
90
90
|
services: Record<string, unknown>;
|
|
91
91
|
}
|
|
92
92
|
export type CommandExecutor = (invocation: CommandInvocation, next: () => unknown | Promise<unknown>) => unknown | Promise<unknown>;
|
|
93
|
+
export { assertFeatureTransition } from "./feature";
|
|
94
|
+
export type { FeatureTransitionSpec } from "./feature";
|
|
93
95
|
export interface ApplicationAspectContext {
|
|
94
96
|
kind: "route" | "command" | "job";
|
|
95
97
|
name: string;
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,22 @@
|
|
|
1
1
|
// src/index.ts
|
|
2
2
|
import { Elysia } from "elysia";
|
|
3
3
|
|
|
4
|
+
// src/feature.ts
|
|
5
|
+
function assertFeatureTransition(spec, state, event) {
|
|
6
|
+
const transition = Object.hasOwn(spec.transitions, event) ? spec.transitions[event] : undefined;
|
|
7
|
+
if (!transition || !spec.states.includes(state) || transition.from !== state) {
|
|
8
|
+
throw new ApplicationError("Feature transition is not allowed", {
|
|
9
|
+
status: 409,
|
|
10
|
+
code: "FEATURE_TRANSITION_CONFLICT"
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
if (!spec.states.includes(transition.to)) {
|
|
14
|
+
throw new ApplicationError("Feature transition references an undeclared state", {
|
|
15
|
+
code: "FEATURE_SPEC_INVALID"
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
return transition.to;
|
|
19
|
+
}
|
|
4
20
|
// src/memory.ts
|
|
5
21
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
6
22
|
|
|
@@ -240,7 +256,7 @@ function createMemorySandbox(options = {}) {
|
|
|
240
256
|
}
|
|
241
257
|
},
|
|
242
258
|
idempotency(invocation, next) {
|
|
243
|
-
return policy.runOnce(policy.subject(invocation.requestContext), invocation.command.name, requireIdempotencyKey(invocation), invocation
|
|
259
|
+
return policy.runOnce(policy.subject(invocation.requestContext), invocation.command.name, requireIdempotencyKey(invocation), memoryCommandInput(invocation), next);
|
|
244
260
|
},
|
|
245
261
|
transaction(_invocation, next) {
|
|
246
262
|
const count = audit.length;
|
|
@@ -297,6 +313,21 @@ function createMemorySandbox(options = {}) {
|
|
|
297
313
|
}
|
|
298
314
|
};
|
|
299
315
|
}
|
|
316
|
+
function memoryCommandInput(invocation) {
|
|
317
|
+
const input = invocation.input;
|
|
318
|
+
if (typeof input !== "object" || input === null)
|
|
319
|
+
return input;
|
|
320
|
+
const ignoredHeaders = new Set(["authorization", "idempotency-key", "x-request-id", "traceparent", "tracestate"]);
|
|
321
|
+
const headers = Object.fromEntries([...invocation.request.headers.entries()].filter(([name]) => !ignoredHeaders.has(name)));
|
|
322
|
+
return {
|
|
323
|
+
method: invocation.request.method,
|
|
324
|
+
path: new URL(invocation.request.url).pathname,
|
|
325
|
+
body: "body" in input ? input.body : undefined,
|
|
326
|
+
params: "params" in input ? input.params : undefined,
|
|
327
|
+
query: "query" in input ? input.query : undefined,
|
|
328
|
+
headers
|
|
329
|
+
};
|
|
330
|
+
}
|
|
300
331
|
function storageKey(bucket, key) {
|
|
301
332
|
return JSON.stringify([bucket, key]);
|
|
302
333
|
}
|
|
@@ -756,6 +787,7 @@ export {
|
|
|
756
787
|
EXECUTION_ID_HEADER,
|
|
757
788
|
IDEMPOTENCY_KEY_HEADER,
|
|
758
789
|
VERIFIED_JWT_SUBJECT_HEADER,
|
|
790
|
+
assertFeatureTransition,
|
|
759
791
|
composeAspects,
|
|
760
792
|
composeCommandExecutors,
|
|
761
793
|
createApplication,
|
package/package.json
CHANGED