@kensio/simnaril 0.0.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/LICENSE +201 -0
- package/README.md +37 -0
- package/dist/api.d.ts +24 -0
- package/dist/api.d.ts.map +1 -0
- package/dist/api.js +66 -0
- package/dist/api.js.map +1 -0
- package/dist/duplicate-entity-error.d.ts +7 -0
- package/dist/duplicate-entity-error.d.ts.map +1 -0
- package/dist/duplicate-entity-error.js +14 -0
- package/dist/duplicate-entity-error.js.map +1 -0
- package/dist/entity-not-found-error.d.ts +7 -0
- package/dist/entity-not-found-error.d.ts.map +1 -0
- package/dist/entity-not-found-error.js +13 -0
- package/dist/entity-not-found-error.js.map +1 -0
- package/dist/environment.d.ts +21 -0
- package/dist/environment.d.ts.map +1 -0
- package/dist/environment.js +65 -0
- package/dist/environment.js.map +1 -0
- package/dist/http/interception.d.ts +13 -0
- package/dist/http/interception.d.ts.map +1 -0
- package/dist/http/interception.js +56 -0
- package/dist/http/interception.js.map +1 -0
- package/dist/http/operation-pipeline.d.ts +7 -0
- package/dist/http/operation-pipeline.d.ts.map +1 -0
- package/dist/http/operation-pipeline.js +24 -0
- package/dist/http/operation-pipeline.js.map +1 -0
- package/dist/http/operation-router.d.ts +9 -0
- package/dist/http/operation-router.d.ts.map +1 -0
- package/dist/http/operation-router.js +63 -0
- package/dist/http/operation-router.js.map +1 -0
- package/dist/http/operation.d.ts +51 -0
- package/dist/http/operation.d.ts.map +1 -0
- package/dist/http/operation.js +43 -0
- package/dist/http/operation.js.map +1 -0
- package/dist/http/resource-operation-registry.d.ts +13 -0
- package/dist/http/resource-operation-registry.d.ts.map +1 -0
- package/dist/http/resource-operation-registry.js +46 -0
- package/dist/http/resource-operation-registry.js.map +1 -0
- package/dist/http/resource-operation.d.ts +9 -0
- package/dist/http/resource-operation.d.ts.map +1 -0
- package/dist/http/resource-operation.js +25 -0
- package/dist/http/resource-operation.js.map +1 -0
- package/dist/http/rest-resource-operations.d.ts +9 -0
- package/dist/http/rest-resource-operations.d.ts.map +1 -0
- package/dist/http/rest-resource-operations.js +97 -0
- package/dist/http/rest-resource-operations.js.map +1 -0
- package/dist/http/route.d.ts +14 -0
- package/dist/http/route.d.ts.map +1 -0
- package/dist/http/route.js +77 -0
- package/dist/http/route.js.map +1 -0
- package/dist/http/semantic-http-operation.d.ts +16 -0
- package/dist/http/semantic-http-operation.d.ts.map +1 -0
- package/dist/http/semantic-http-operation.js +20 -0
- package/dist/http/semantic-http-operation.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/resource.d.ts +29 -0
- package/dist/resource.d.ts.map +1 -0
- package/dist/resource.js +78 -0
- package/dist/resource.js.map +1 -0
- package/dist/rest-resource-operation.d.ts +29 -0
- package/dist/rest-resource-operation.d.ts.map +1 -0
- package/dist/rest-resource-operation.js +2 -0
- package/dist/rest-resource-operation.js.map +1 -0
- package/dist/rest-resource.d.ts +37 -0
- package/dist/rest-resource.d.ts.map +1 -0
- package/dist/rest-resource.js +63 -0
- package/dist/rest-resource.js.map +1 -0
- package/dist/unclaimed-origin-error.d.ts +8 -0
- package/dist/unclaimed-origin-error.d.ts.map +1 -0
- package/dist/unclaimed-origin-error.js +16 -0
- package/dist/unclaimed-origin-error.js.map +1 -0
- package/dist/unimplemented-route-error.d.ts +8 -0
- package/dist/unimplemented-route-error.d.ts.map +1 -0
- package/dist/unimplemented-route-error.js +16 -0
- package/dist/unimplemented-route-error.js.map +1 -0
- package/package.json +74 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/** Configures the state and domain behaviour for one simulated resource. */
|
|
2
|
+
export interface SimResourceProps<T extends object> {
|
|
3
|
+
create?: (input: Partial<T>) => T;
|
|
4
|
+
identify?: (entity: T) => string;
|
|
5
|
+
name?: string;
|
|
6
|
+
}
|
|
7
|
+
/** Owns the in-memory state and domain operations for one entity type. */
|
|
8
|
+
export declare class SimResource<T extends object> {
|
|
9
|
+
#private;
|
|
10
|
+
readonly name: string | undefined;
|
|
11
|
+
constructor(props: SimResourceProps<T>);
|
|
12
|
+
/** Stores an exact entity for simulation arrangement. */
|
|
13
|
+
seed(entity: T): T;
|
|
14
|
+
/** Runs the resource's creation behaviour and stores its result. */
|
|
15
|
+
create(input: Partial<T>): T;
|
|
16
|
+
/** Returns an entity or throws when its identity is absent. */
|
|
17
|
+
get(identity: string): T;
|
|
18
|
+
/** Returns an entity when its identity exists. */
|
|
19
|
+
find(identity: string): T | undefined;
|
|
20
|
+
/** Returns every entity in insertion order. */
|
|
21
|
+
list(): T[];
|
|
22
|
+
/** Merges changes into an existing entity. */
|
|
23
|
+
update(identity: string, changes: Partial<T>): T;
|
|
24
|
+
/** Deletes an existing entity and returns it. */
|
|
25
|
+
delete(identity: string): T;
|
|
26
|
+
/** Deletes every entity from this resource. */
|
|
27
|
+
clear(): void;
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=resource.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resource.d.ts","sourceRoot":"","sources":["../src/resource.ts"],"names":[],"mappings":"AAeA,4EAA4E;AAC5E,MAAM,WAAW,gBAAgB,CAAC,CAAC,SAAS,MAAM;IAChD,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;IAClC,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,MAAM,CAAC;IACjC,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,0EAA0E;AAC1E,qBAAa,WAAW,CAAC,CAAC,SAAS,MAAM;;IACvC,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;IAKlC,YAAY,KAAK,EAAE,gBAAgB,CAAC,CAAC,CAAC,EAIrC;IAED,yDAAyD;IACzD,IAAI,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAEjB;IAED,oEAAoE;IACpE,MAAM,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAE3B;IAED,+DAA+D;IAC/D,GAAG,CAAC,QAAQ,EAAE,MAAM,GAAG,CAAC,CAQvB;IAED,kDAAkD;IAClD,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS,CAEpC;IAED,+CAA+C;IAC/C,IAAI,IAAI,CAAC,EAAE,CAEV;IAED,8CAA8C;IAC9C,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAe/C;IAED,iDAAiD;IACjD,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,CAAC,CAI1B;IAED,+CAA+C;IAC/C,KAAK,IAAI,IAAI,CAEZ;CAYF"}
|
package/dist/resource.js
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { DuplicateEntityError } from "./duplicate-entity-error.js";
|
|
2
|
+
import { EntityNotFoundError } from "./entity-not-found-error.js";
|
|
3
|
+
function identifyById(entity) {
|
|
4
|
+
const identity = entity.id;
|
|
5
|
+
if (typeof identity !== "string") {
|
|
6
|
+
throw new TypeError("The conventional SimResource identity requires a string id. Provide identify for another entity shape.");
|
|
7
|
+
}
|
|
8
|
+
return identity;
|
|
9
|
+
}
|
|
10
|
+
/** Owns the in-memory state and domain operations for one entity type. */
|
|
11
|
+
export class SimResource {
|
|
12
|
+
name;
|
|
13
|
+
#createEntity;
|
|
14
|
+
#entities = new Map();
|
|
15
|
+
#identify;
|
|
16
|
+
constructor(props) {
|
|
17
|
+
this.name = props.name;
|
|
18
|
+
this.#createEntity = props.create ?? ((input) => input);
|
|
19
|
+
this.#identify = props.identify ?? identifyById;
|
|
20
|
+
}
|
|
21
|
+
/** Stores an exact entity for simulation arrangement. */
|
|
22
|
+
seed(entity) {
|
|
23
|
+
return this.#insert(entity);
|
|
24
|
+
}
|
|
25
|
+
/** Runs the resource's creation behaviour and stores its result. */
|
|
26
|
+
create(input) {
|
|
27
|
+
return this.#insert(this.#createEntity(input));
|
|
28
|
+
}
|
|
29
|
+
/** Returns an entity or throws when its identity is absent. */
|
|
30
|
+
get(identity) {
|
|
31
|
+
const entity = this.#entities.get(identity);
|
|
32
|
+
if (entity === undefined) {
|
|
33
|
+
throw new EntityNotFoundError(identity, this.name);
|
|
34
|
+
}
|
|
35
|
+
return entity;
|
|
36
|
+
}
|
|
37
|
+
/** Returns an entity when its identity exists. */
|
|
38
|
+
find(identity) {
|
|
39
|
+
return this.#entities.get(identity);
|
|
40
|
+
}
|
|
41
|
+
/** Returns every entity in insertion order. */
|
|
42
|
+
list() {
|
|
43
|
+
return [...this.#entities.values()];
|
|
44
|
+
}
|
|
45
|
+
/** Merges changes into an existing entity. */
|
|
46
|
+
update(identity, changes) {
|
|
47
|
+
const existing = this.get(identity);
|
|
48
|
+
const updated = { ...existing, ...changes };
|
|
49
|
+
const updatedIdentity = this.#identify(updated);
|
|
50
|
+
if (updatedIdentity !== identity && this.#entities.has(updatedIdentity)) {
|
|
51
|
+
throw new DuplicateEntityError(updatedIdentity, this.name);
|
|
52
|
+
}
|
|
53
|
+
if (updatedIdentity !== identity) {
|
|
54
|
+
this.#entities.delete(identity);
|
|
55
|
+
}
|
|
56
|
+
this.#entities.set(updatedIdentity, updated);
|
|
57
|
+
return updated;
|
|
58
|
+
}
|
|
59
|
+
/** Deletes an existing entity and returns it. */
|
|
60
|
+
delete(identity) {
|
|
61
|
+
const entity = this.get(identity);
|
|
62
|
+
this.#entities.delete(identity);
|
|
63
|
+
return entity;
|
|
64
|
+
}
|
|
65
|
+
/** Deletes every entity from this resource. */
|
|
66
|
+
clear() {
|
|
67
|
+
this.#entities.clear();
|
|
68
|
+
}
|
|
69
|
+
#insert(entity) {
|
|
70
|
+
const identity = this.#identify(entity);
|
|
71
|
+
if (this.#entities.has(identity)) {
|
|
72
|
+
throw new DuplicateEntityError(identity, this.name);
|
|
73
|
+
}
|
|
74
|
+
this.#entities.set(identity, entity);
|
|
75
|
+
return entity;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=resource.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resource.js","sourceRoot":"","sources":["../src/resource.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { SemanticOperation, SemanticOperationContext } from "./http/operation.js";
|
|
2
|
+
import type { RestResource } from "./rest-resource.js";
|
|
3
|
+
/** Changes the route of one supplied resource operation. */
|
|
4
|
+
export interface RestResourceOperationConfiguration {
|
|
5
|
+
method?: string;
|
|
6
|
+
path?: string;
|
|
7
|
+
}
|
|
8
|
+
/** Configures the HTTP path and supplied operations for a simulated resource. */
|
|
9
|
+
export interface RestResourceProps {
|
|
10
|
+
operations?: Partial<Record<RestResourceOperationName, RestResourceOperationConfiguration>>;
|
|
11
|
+
path: string;
|
|
12
|
+
}
|
|
13
|
+
/** Names the supplied resource behaviours. */
|
|
14
|
+
export type RestResourceOperationName = "list" | "create" | "get" | "update" | "delete";
|
|
15
|
+
/** Supplied semantic operations for one REST resource. */
|
|
16
|
+
export interface RestResourceOperations<T extends object> {
|
|
17
|
+
create: SemanticOperation<Partial<T>, T, RestResource<T>>;
|
|
18
|
+
delete: SemanticOperation<unknown, T, RestResource<T>>;
|
|
19
|
+
get: SemanticOperation<unknown, T, RestResource<T>>;
|
|
20
|
+
list: SemanticOperation<unknown, T[], RestResource<T>>;
|
|
21
|
+
update: SemanticOperation<Partial<T>, T, RestResource<T>>;
|
|
22
|
+
}
|
|
23
|
+
/** Configures a domain action under a resource path. */
|
|
24
|
+
export interface ResourceOperationProps<T extends object, TInput, TOutput> {
|
|
25
|
+
handle: (context: SemanticOperationContext<TInput, RestResource<T>>) => Promise<TOutput> | TOutput;
|
|
26
|
+
method: string;
|
|
27
|
+
path: string;
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=rest-resource-operation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rest-resource-operation.d.ts","sourceRoot":"","sources":["../src/rest-resource-operation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,iBAAiB,EACjB,wBAAwB,EACzB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEvD,4DAA4D;AAC5D,MAAM,WAAW,kCAAkC;IACjD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,iFAAiF;AACjF,MAAM,WAAW,iBAAiB;IAChC,UAAU,CAAC,EAAE,OAAO,CAClB,MAAM,CAAC,yBAAyB,EAAE,kCAAkC,CAAC,CACtE,CAAC;IACF,IAAI,EAAE,MAAM,CAAC;CACd;AAED,8CAA8C;AAC9C,MAAM,MAAM,yBAAyB,GACjC,MAAM,GACN,QAAQ,GACR,KAAK,GACL,QAAQ,GACR,QAAQ,CAAC;AAEb,0DAA0D;AAC1D,MAAM,WAAW,sBAAsB,CAAC,CAAC,SAAS,MAAM;IACtD,MAAM,EAAE,iBAAiB,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1D,MAAM,EAAE,iBAAiB,CAAC,OAAO,EAAE,CAAC,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC;IACvD,GAAG,EAAE,iBAAiB,CAAC,OAAO,EAAE,CAAC,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC;IACpD,IAAI,EAAE,iBAAiB,CAAC,OAAO,EAAE,CAAC,EAAE,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC;IACvD,MAAM,EAAE,iBAAiB,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC;CAC3D;AAED,wDAAwD;AACxD,MAAM,WAAW,sBAAsB,CAAC,CAAC,SAAS,MAAM,EAAE,MAAM,EAAE,OAAO;IACvE,MAAM,EAAE,CACN,OAAO,EAAE,wBAAwB,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC,KACvD,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rest-resource-operation.js","sourceRoot":"","sources":["../src/rest-resource-operation.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { HttpMiddleware, SemanticOperation } from "./http/operation.js";
|
|
2
|
+
import { ResourceOperationRegistry } from "./http/resource-operation-registry.js";
|
|
3
|
+
import type { SimResource } from "./resource.js";
|
|
4
|
+
import type { ResourceOperationProps, RestResourceOperations, RestResourceProps } from "./rest-resource-operation.js";
|
|
5
|
+
declare const attachResource: unique symbol;
|
|
6
|
+
/** Adds conventional HTTP exposure to simulated resource state. */
|
|
7
|
+
export declare class RestResource<T extends object> {
|
|
8
|
+
#private;
|
|
9
|
+
readonly operations: RestResourceOperations<T>;
|
|
10
|
+
readonly path: string;
|
|
11
|
+
readonly state: SimResource<T>;
|
|
12
|
+
constructor(state: SimResource<T>, props: RestResourceProps);
|
|
13
|
+
/** Adds middleware around every operation owned by this resource. */
|
|
14
|
+
use(middleware: HttpMiddleware): this;
|
|
15
|
+
/** Adds a named domain action under this resource's collection path. */
|
|
16
|
+
operation<TInput = unknown, TOutput = unknown>(name: string, props: ResourceOperationProps<T, TInput, TOutput>): SemanticOperation<TInput, TOutput, RestResource<T>>;
|
|
17
|
+
[attachResource](registerOperation: Parameters<ResourceOperationRegistry<T>["attach"]>[0]): void;
|
|
18
|
+
/** Stores an exact entity for simulation arrangement. */
|
|
19
|
+
seed(entity: T): T;
|
|
20
|
+
/** Runs the resource's creation behaviour and stores its result. */
|
|
21
|
+
create(input: Partial<T>): T;
|
|
22
|
+
/** Returns an entity or throws when its identity is absent. */
|
|
23
|
+
get(identity: string): T;
|
|
24
|
+
/** Returns an entity when its identity exists. */
|
|
25
|
+
find(identity: string): T | undefined;
|
|
26
|
+
/** Returns every entity in insertion order. */
|
|
27
|
+
list(): T[];
|
|
28
|
+
/** Merges changes into an existing entity. */
|
|
29
|
+
update(identity: string, changes: Partial<T>): T;
|
|
30
|
+
/** Deletes an existing entity and returns it. */
|
|
31
|
+
delete(identity: string): T;
|
|
32
|
+
/** Deletes every entity from this resource. */
|
|
33
|
+
clear(): void;
|
|
34
|
+
}
|
|
35
|
+
export declare function attachRestResource<T extends object>(resource: RestResource<T>, registerOperation: Parameters<ResourceOperationRegistry<T>["attach"]>[0]): void;
|
|
36
|
+
export {};
|
|
37
|
+
//# sourceMappingURL=rest-resource.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rest-resource.d.ts","sourceRoot":"","sources":["../src/rest-resource.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAC7E,OAAO,EAAE,yBAAyB,EAAE,MAAM,uCAAuC,CAAC;AAClF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,KAAK,EACV,sBAAsB,EACtB,sBAAsB,EACtB,iBAAiB,EAClB,MAAM,8BAA8B,CAAC;AAEtC,QAAA,MAAM,cAAc,eAAiC,CAAC;AAEtD,mEAAmE;AACnE,qBAAa,YAAY,CAAC,CAAC,SAAS,MAAM;;IACxC,QAAQ,CAAC,UAAU,EAAE,sBAAsB,CAAC,CAAC,CAAC,CAAC;IAC/C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC;IAG/B,YAAY,KAAK,EAAE,WAAW,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,iBAAiB,EAQ1D;IAED,qEAAqE;IACrE,GAAG,CAAC,UAAU,EAAE,cAAc,GAAG,IAAI,CAGpC;IAED,wEAAwE;IACxE,SAAS,CAAC,MAAM,GAAG,OAAO,EAAE,OAAO,GAAG,OAAO,EAC3C,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,sBAAsB,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,GAChD,iBAAiB,CAAC,MAAM,EAAE,OAAO,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC,CAErD;IAED,CAAC,cAAc,CAAC,CACd,iBAAiB,EAAE,UAAU,CAAC,yBAAyB,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,GACvE,IAAI,CAEN;IAED,yDAAyD;IACzD,IAAI,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAEjB;IAED,oEAAoE;IACpE,MAAM,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAE3B;IAED,+DAA+D;IAC/D,GAAG,CAAC,QAAQ,EAAE,MAAM,GAAG,CAAC,CAEvB;IAED,kDAAkD;IAClD,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS,CAEpC;IAED,+CAA+C;IAC/C,IAAI,IAAI,CAAC,EAAE,CAEV;IAED,8CAA8C;IAC9C,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAE/C;IAED,iDAAiD;IACjD,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,CAAC,CAE1B;IAED,+CAA+C;IAC/C,KAAK,IAAI,IAAI,CAEZ;CACF;AAED,wBAAgB,kBAAkB,CAAC,CAAC,SAAS,MAAM,EACjD,QAAQ,EAAE,YAAY,CAAC,CAAC,CAAC,EACzB,iBAAiB,EAAE,UAAU,CAAC,yBAAyB,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,GACvE,IAAI,CAEN"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { ResourceOperationRegistry } from "./http/resource-operation-registry.js";
|
|
2
|
+
const attachResource = Symbol("attach REST resource");
|
|
3
|
+
/** Adds conventional HTTP exposure to simulated resource state. */
|
|
4
|
+
export class RestResource {
|
|
5
|
+
operations;
|
|
6
|
+
path;
|
|
7
|
+
state;
|
|
8
|
+
#operationRegistry;
|
|
9
|
+
constructor(state, props) {
|
|
10
|
+
this.state = state;
|
|
11
|
+
this.path = props.path;
|
|
12
|
+
this.#operationRegistry = new ResourceOperationRegistry(this, props.operations);
|
|
13
|
+
this.operations = this.#operationRegistry.operations;
|
|
14
|
+
}
|
|
15
|
+
/** Adds middleware around every operation owned by this resource. */
|
|
16
|
+
use(middleware) {
|
|
17
|
+
this.#operationRegistry.use(middleware);
|
|
18
|
+
return this;
|
|
19
|
+
}
|
|
20
|
+
/** Adds a named domain action under this resource's collection path. */
|
|
21
|
+
operation(name, props) {
|
|
22
|
+
return this.#operationRegistry.add(name, props);
|
|
23
|
+
}
|
|
24
|
+
[attachResource](registerOperation) {
|
|
25
|
+
this.#operationRegistry.attach(registerOperation);
|
|
26
|
+
}
|
|
27
|
+
/** Stores an exact entity for simulation arrangement. */
|
|
28
|
+
seed(entity) {
|
|
29
|
+
return this.state.seed(entity);
|
|
30
|
+
}
|
|
31
|
+
/** Runs the resource's creation behaviour and stores its result. */
|
|
32
|
+
create(input) {
|
|
33
|
+
return this.state.create(input);
|
|
34
|
+
}
|
|
35
|
+
/** Returns an entity or throws when its identity is absent. */
|
|
36
|
+
get(identity) {
|
|
37
|
+
return this.state.get(identity);
|
|
38
|
+
}
|
|
39
|
+
/** Returns an entity when its identity exists. */
|
|
40
|
+
find(identity) {
|
|
41
|
+
return this.state.find(identity);
|
|
42
|
+
}
|
|
43
|
+
/** Returns every entity in insertion order. */
|
|
44
|
+
list() {
|
|
45
|
+
return this.state.list();
|
|
46
|
+
}
|
|
47
|
+
/** Merges changes into an existing entity. */
|
|
48
|
+
update(identity, changes) {
|
|
49
|
+
return this.state.update(identity, changes);
|
|
50
|
+
}
|
|
51
|
+
/** Deletes an existing entity and returns it. */
|
|
52
|
+
delete(identity) {
|
|
53
|
+
return this.state.delete(identity);
|
|
54
|
+
}
|
|
55
|
+
/** Deletes every entity from this resource. */
|
|
56
|
+
clear() {
|
|
57
|
+
this.state.clear();
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
export function attachRestResource(resource, registerOperation) {
|
|
61
|
+
resource[attachResource](registerOperation);
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=rest-resource.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rest-resource.js","sourceRoot":"","sources":["../src/rest-resource.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,yBAAyB,EAAE,MAAM,uCAAuC,CAAC;AAQlF,MAAM,cAAc,GAAG,MAAM,CAAC,sBAAsB,CAAC,CAAC;AAEtD,mEAAmE;AACnE,MAAM,OAAO,YAAY;IACd,UAAU,CAA4B;IACtC,IAAI,CAAS;IACb,KAAK,CAAiB;IACtB,kBAAkB,CAA+B;IAE1D,YAAY,KAAqB,EAAE,KAAwB;QACzD,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC;QACvB,IAAI,CAAC,kBAAkB,GAAG,IAAI,yBAAyB,CACrD,IAAI,EACJ,KAAK,CAAC,UAAU,CACjB,CAAC;QACF,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,kBAAkB,CAAC,UAAU,CAAC;IACvD,CAAC;IAED,qEAAqE;IACrE,GAAG,CAAC,UAA0B;QAC5B,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QACxC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,wEAAwE;IACxE,SAAS,CACP,IAAY,EACZ,KAAiD;QAEjD,OAAO,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IAClD,CAAC;IAED,CAAC,cAAc,CAAC,CACd,iBAAwE;QAExE,IAAI,CAAC,kBAAkB,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC;IACpD,CAAC;IAED,yDAAyD;IACzD,IAAI,CAAC,MAAS;QACZ,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACjC,CAAC;IAED,oEAAoE;IACpE,MAAM,CAAC,KAAiB;QACtB,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAClC,CAAC;IAED,+DAA+D;IAC/D,GAAG,CAAC,QAAgB;QAClB,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IAClC,CAAC;IAED,kDAAkD;IAClD,IAAI,CAAC,QAAgB;QACnB,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACnC,CAAC;IAED,+CAA+C;IAC/C,IAAI;QACF,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;IAC3B,CAAC;IAED,8CAA8C;IAC9C,MAAM,CAAC,QAAgB,EAAE,OAAmB;QAC1C,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAC9C,CAAC;IAED,iDAAiD;IACjD,MAAM,CAAC,QAAgB;QACrB,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IACrC,CAAC;IAED,+CAA+C;IAC/C,KAAK;QACH,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;IACrB,CAAC;CACF;AAED,MAAM,UAAU,kBAAkB,CAChC,QAAyB,EACzB,iBAAwE;IAExE,QAAQ,CAAC,cAAc,CAAC,CAAC,iBAAiB,CAAC,CAAC;AAC9C,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/** Reports a request whose origin has no registered simulated service. */
|
|
2
|
+
export declare class UnclaimedOriginError extends Error {
|
|
3
|
+
readonly method: string;
|
|
4
|
+
readonly origin: string;
|
|
5
|
+
readonly url: string;
|
|
6
|
+
constructor(request: Request);
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=unclaimed-origin-error.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unclaimed-origin-error.d.ts","sourceRoot":"","sources":["../src/unclaimed-origin-error.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,qBAAa,oBAAqB,SAAQ,KAAK;IAC7C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IAErB,YAAY,OAAO,EAAE,OAAO,EAW3B;CACF"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/** Reports a request whose origin has no registered simulated service. */
|
|
2
|
+
export class UnclaimedOriginError extends Error {
|
|
3
|
+
method;
|
|
4
|
+
origin;
|
|
5
|
+
url;
|
|
6
|
+
constructor(request) {
|
|
7
|
+
const url = new URL(request.url);
|
|
8
|
+
const method = request.method.toUpperCase();
|
|
9
|
+
super(`${method} ${request.url} reached SimEnvironment, but no simulated service is registered for origin ${url.origin}.`);
|
|
10
|
+
this.name = "UnclaimedOriginError";
|
|
11
|
+
this.method = method;
|
|
12
|
+
this.origin = url.origin;
|
|
13
|
+
this.url = request.url;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=unclaimed-origin-error.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unclaimed-origin-error.js","sourceRoot":"","sources":["../src/unclaimed-origin-error.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,MAAM,OAAO,oBAAqB,SAAQ,KAAK;IACpC,MAAM,CAAS;IACf,MAAM,CAAS;IACf,GAAG,CAAS;IAErB,YAAY,OAAgB;QAC1B,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACjC,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC;QAE5C,KAAK,CACH,GAAG,MAAM,IAAI,OAAO,CAAC,GAAG,8EAA8E,GAAG,CAAC,MAAM,GAAG,CACpH,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,sBAAsB,CAAC;QACnC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC;QACzB,IAAI,CAAC,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC;IACzB,CAAC;CACF"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/** Reports a request for which a simulated API has no operation. */
|
|
2
|
+
export declare class UnimplementedRouteError extends Error {
|
|
3
|
+
readonly method: string;
|
|
4
|
+
readonly pathname: string;
|
|
5
|
+
readonly url: string;
|
|
6
|
+
constructor(request: Request);
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=unimplemented-route-error.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unimplemented-route-error.d.ts","sourceRoot":"","sources":["../src/unimplemented-route-error.ts"],"names":[],"mappings":"AAAA,oEAAoE;AACpE,qBAAa,uBAAwB,SAAQ,KAAK;IAChD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IAErB,YAAY,OAAO,EAAE,OAAO,EAW3B;CACF"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/** Reports a request for which a simulated API has no operation. */
|
|
2
|
+
export class UnimplementedRouteError extends Error {
|
|
3
|
+
method;
|
|
4
|
+
pathname;
|
|
5
|
+
url;
|
|
6
|
+
constructor(request) {
|
|
7
|
+
const url = new URL(request.url);
|
|
8
|
+
const method = request.method.toUpperCase();
|
|
9
|
+
super(`${method} ${request.url} reached SimApi, but SimApi has no handler for ${method} ${url.pathname}.`);
|
|
10
|
+
this.name = "UnimplementedRouteError";
|
|
11
|
+
this.method = method;
|
|
12
|
+
this.pathname = url.pathname;
|
|
13
|
+
this.url = request.url;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=unimplemented-route-error.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unimplemented-route-error.js","sourceRoot":"","sources":["../src/unimplemented-route-error.ts"],"names":[],"mappings":"AAAA,oEAAoE;AACpE,MAAM,OAAO,uBAAwB,SAAQ,KAAK;IACvC,MAAM,CAAS;IACf,QAAQ,CAAS;IACjB,GAAG,CAAS;IAErB,YAAY,OAAgB;QAC1B,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACjC,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC;QAE5C,KAAK,CACH,GAAG,MAAM,IAAI,OAAO,CAAC,GAAG,kDAAkD,MAAM,IAAI,GAAG,CAAC,QAAQ,GAAG,CACpG,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,yBAAyB,CAAC;QACtC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,QAAQ,GAAG,GAAG,CAAC,QAAQ,CAAC;QAC7B,IAAI,CAAC,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC;IACzB,CAAC;CACF"}
|
package/package.json
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@kensio/simnaril",
|
|
3
|
+
"version": "0.0.0",
|
|
4
|
+
"description": "In-process simulation of third-party HTTP services",
|
|
5
|
+
"repository": "https://github.com/KensioSoftware/simnaril",
|
|
6
|
+
"bugs": "https://github.com/KensioSoftware/simnaril/issues",
|
|
7
|
+
"main": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js"
|
|
13
|
+
},
|
|
14
|
+
"./package.json": "./package.json"
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist",
|
|
18
|
+
"README.md",
|
|
19
|
+
"LICENSE"
|
|
20
|
+
],
|
|
21
|
+
"sideEffects": false,
|
|
22
|
+
"imports": {
|
|
23
|
+
"#test/*": "./test/*"
|
|
24
|
+
},
|
|
25
|
+
"packageManager": "pnpm@11.21.0+sha512.521705bce689924eac72f5a3587122f362689ef6571e55ba80076fd637c11132ecffada26fad4ea79c485bfddbfd3d5a2a5b05805a77e893de71ec8a6cca3bb1",
|
|
26
|
+
"engines": {
|
|
27
|
+
"node": ">=24.0.0"
|
|
28
|
+
},
|
|
29
|
+
"scripts": {
|
|
30
|
+
"build": "rm -rf dist && tsc -p tsconfig.build.json",
|
|
31
|
+
"prepack": "pnpm build",
|
|
32
|
+
"build:check": "tsc -p tsconfig.json --noEmit",
|
|
33
|
+
"fmt": "oxlint --fix . && oxfmt .",
|
|
34
|
+
"lint": "oxlint . && oxfmt --check .",
|
|
35
|
+
"lint:ci": "oxlint --format=github . && oxfmt --check .",
|
|
36
|
+
"fta": "./scripts/sh/fta.sh",
|
|
37
|
+
"test": "vitest run",
|
|
38
|
+
"test:coverage": "vitest run --coverage",
|
|
39
|
+
"pack:check": "./scripts/sh/pack-check.sh",
|
|
40
|
+
"check": "pnpm fmt && pnpm fta && pnpm build:check && pnpm pack:check && pnpm test:coverage"
|
|
41
|
+
},
|
|
42
|
+
"devDependencies": {
|
|
43
|
+
"@faker-js/faker": "^10.6.0",
|
|
44
|
+
"@kensio/part-factory": "^1.10.1",
|
|
45
|
+
"@kensio/smartass": "^1.37.6",
|
|
46
|
+
"@semantic-release/exec": "7.1.0",
|
|
47
|
+
"@types/node": "^26.1.2",
|
|
48
|
+
"@typescript/native": "npm:typescript@^7.0.2",
|
|
49
|
+
"@vitest/coverage-v8": "^4.1.11",
|
|
50
|
+
"conventional-changelog-conventionalcommits": "9.3.1",
|
|
51
|
+
"fta-cli": "^3.0.0",
|
|
52
|
+
"oxfmt": "^0.65.0",
|
|
53
|
+
"oxlint": "^1.80.0",
|
|
54
|
+
"oxlint-tsgolint": "^7.0.2001",
|
|
55
|
+
"semantic-release": "25.0.9",
|
|
56
|
+
"typescript": "npm:@typescript/typescript6@^6.0.2",
|
|
57
|
+
"vitest": "^4.1.11"
|
|
58
|
+
},
|
|
59
|
+
"keywords": [
|
|
60
|
+
"simulation",
|
|
61
|
+
"testing",
|
|
62
|
+
"http",
|
|
63
|
+
"in-process"
|
|
64
|
+
],
|
|
65
|
+
"publishConfig": {
|
|
66
|
+
"access": "public"
|
|
67
|
+
},
|
|
68
|
+
"author": "Kensio Software",
|
|
69
|
+
"license": "Apache-2.0",
|
|
70
|
+
"type": "module",
|
|
71
|
+
"dependencies": {
|
|
72
|
+
"@mswjs/interceptors": "^0.42.3"
|
|
73
|
+
}
|
|
74
|
+
}
|