@sincpro/client-framework 0.5.0 → 1.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/AGENTS.md +54 -25
- package/MANIFESTO.md +59 -39
- package/README.md +329 -328
- package/dist/client/{memory.d.ts → adapters/memory.d.ts} +1 -1
- package/dist/client/{memory.js → adapters/memory.js} +7 -5
- package/dist/client/adapters/parquet.d.ts +50 -0
- package/dist/client/adapters/parquet.js +151 -0
- package/dist/client/{rest.d.ts → adapters/rest.d.ts} +7 -1
- package/dist/client/{rest.js → adapters/rest.js} +48 -3
- package/dist/client/{entity.d.ts → domain/entity.d.ts} +22 -11
- package/dist/client/{entity.js → domain/entity.js} +16 -1
- package/dist/client/{transport.d.ts → domain/transport.d.ts} +37 -1
- package/dist/client/{transport.js → domain/transport.js} +6 -0
- package/dist/client/index.d.ts +16 -0
- package/dist/client/index.js +16 -0
- package/dist/client/services/propagation.d.ts +32 -0
- package/dist/{services/execution.js → client/services/propagation.js} +8 -21
- package/dist/client/{retry.js → services/retry.js} +1 -1
- package/dist/codegen/{metamodel.d.ts → domain/metamodel.d.ts} +21 -2
- package/dist/codegen/{names.d.ts → domain/names.d.ts} +2 -2
- package/dist/codegen/{names.js → domain/names.js} +3 -3
- package/dist/codegen/{cli.js → entrypoint/cli.js} +9 -8
- package/dist/codegen/index.d.ts +7 -7
- package/dist/codegen/index.js +5 -10
- package/dist/codegen/{client.d.ts → services/client.d.ts} +3 -1
- package/dist/codegen/{client.js → services/client.js} +34 -5
- package/dist/codegen/services/domain.d.ts +20 -0
- package/dist/codegen/{domain.js → services/domain.js} +121 -23
- package/dist/codegen/{entities.d.ts → services/entities.d.ts} +4 -2
- package/dist/codegen/{entities.js → services/entities.js} +34 -4
- package/dist/codegen/{rest.d.ts → services/rest.d.ts} +1 -1
- package/dist/codegen/{scaffold.d.ts → services/scaffold.d.ts} +2 -2
- package/dist/codegen/{scaffold.js → services/scaffold.js} +31 -36
- package/dist/common/collection.d.ts +110 -0
- package/dist/common/collection.js +169 -0
- package/dist/common/index.d.ts +10 -0
- package/dist/common/index.js +10 -0
- package/dist/context/adapters/memory.d.ts +6 -0
- package/dist/context/adapters/memory.js +34 -0
- package/dist/context/adapters/plain-codec.d.ts +3 -0
- package/dist/context/adapters/plain-codec.js +16 -0
- package/dist/context/{codec.d.ts → domain/codec.d.ts} +0 -1
- package/dist/context/{codec.js → domain/codec.js} +0 -14
- package/dist/context/domain/execution.d.ts +33 -0
- package/dist/context/domain/execution.js +11 -0
- package/dist/context/{store.d.ts → domain/store.d.ts} +0 -5
- package/dist/context/{store.js → domain/store.js} +1 -34
- package/dist/context/{context.d.ts → entrypoint/context.d.ts} +1 -1
- package/dist/context/index.d.ts +17 -0
- package/dist/context/index.js +15 -0
- package/dist/context/infrastructure/process.d.ts +13 -0
- package/dist/context/infrastructure/process.js +35 -0
- package/dist/core/domain/bus.d.ts +18 -0
- package/dist/core/domain/bus.js +18 -0
- package/dist/core/domain/dto.d.ts +32 -0
- package/dist/core/domain/dto.js +20 -0
- package/dist/core/domain/errors.d.ts +18 -0
- package/dist/core/domain/errors.js +1 -0
- package/dist/core/domain/services.d.ts +37 -0
- package/dist/core/domain/services.js +28 -0
- package/dist/core/entrypoint/bounded-context.d.ts +70 -0
- package/dist/core/entrypoint/bounded-context.js +252 -0
- package/dist/core/entrypoint/screens.d.ts +6 -0
- package/dist/core/entrypoint/screens.js +136 -0
- package/dist/core/index.d.ts +17 -0
- package/dist/core/index.js +16 -0
- package/dist/core/infrastructure/process.d.ts +56 -0
- package/dist/core/infrastructure/process.js +35 -0
- package/dist/core/services/binding.d.ts +6 -0
- package/dist/core/services/binding.js +13 -0
- package/dist/core/services/error-handlers.d.ts +11 -0
- package/dist/core/services/error-handlers.js +21 -0
- package/dist/core/services/execution.d.ts +35 -0
- package/dist/core/services/execution.js +137 -0
- package/dist/index.d.ts +16 -36
- package/dist/index.js +16 -36
- package/dist/model/{meta.d.ts → domain/meta.d.ts} +1 -0
- package/dist/model/index.d.ts +10 -0
- package/dist/model/index.js +10 -0
- package/dist/model/{metas.d.ts → infrastructure/metas.d.ts} +1 -1
- package/dist/model/{schema.d.ts → services/schema.d.ts} +1 -1
- package/dist/model/{schema.js → services/schema.js} +1 -1
- package/dist/observability/adapters/console.d.ts +12 -0
- package/dist/observability/adapters/console.js +35 -0
- package/dist/observability/adapters/memory.d.ts +41 -0
- package/dist/observability/adapters/memory.js +49 -0
- package/dist/{adapters → observability/adapters}/opentelemetry.d.ts +1 -1
- package/dist/{adapters → observability/adapters}/sentry.d.ts +1 -1
- package/dist/observability/domain/errors.d.ts +23 -0
- package/dist/observability/domain/errors.js +8 -0
- package/dist/observability/domain/logging.d.ts +42 -0
- package/dist/observability/domain/logging.js +1 -0
- package/dist/observability/domain/tracing.d.ts +49 -0
- package/dist/observability/domain/tracing.js +20 -0
- package/dist/observability/index.d.ts +16 -0
- package/dist/observability/index.js +4 -0
- package/dist/observability/infrastructure/registry.d.ts +21 -0
- package/dist/observability/infrastructure/registry.js +18 -0
- package/dist/observability/services/logging.d.ts +27 -0
- package/dist/observability/services/logging.js +105 -0
- package/dist/observability/services/outcome.d.ts +12 -0
- package/dist/observability/services/outcome.js +20 -0
- package/dist/{services/report.js → observability/services/reporting.js} +4 -3
- package/dist/testing/index.d.ts +3 -33
- package/dist/testing/index.js +5 -37
- package/package.json +25 -8
- package/dist/codegen/domain.d.ts +0 -15
- package/dist/observability/ports.d.ts +0 -65
- package/dist/observability/ports.js +0 -21
- package/dist/services/bounded-context.d.ts +0 -79
- package/dist/services/bounded-context.js +0 -261
- package/dist/services/execution.d.ts +0 -63
- package/dist/services/feature.d.ts +0 -85
- package/dist/services/feature.js +0 -86
- package/dist/services/process.d.ts +0 -60
- package/dist/services/process.js +0 -57
- package/dist/services/screens.d.ts +0 -2
- package/dist/services/screens.js +0 -67
- /package/dist/client/{contract.d.ts → domain/contract.d.ts} +0 -0
- /package/dist/client/{contract.js → domain/contract.js} +0 -0
- /package/dist/client/{discovery.d.ts → services/discovery.d.ts} +0 -0
- /package/dist/client/{discovery.js → services/discovery.js} +0 -0
- /package/dist/client/{retry.d.ts → services/retry.d.ts} +0 -0
- /package/dist/codegen/{metamodel.js → domain/metamodel.js} +0 -0
- /package/dist/codegen/{cli.d.ts → entrypoint/cli.d.ts} +0 -0
- /package/dist/codegen/{check.d.ts → services/check.d.ts} +0 -0
- /package/dist/codegen/{check.js → services/check.js} +0 -0
- /package/dist/codegen/{rest.js → services/rest.js} +0 -0
- /package/dist/context/{context.js → entrypoint/context.js} +0 -0
- /package/dist/model/{meta.js → domain/meta.js} +0 -0
- /package/dist/model/{metas.js → infrastructure/metas.js} +0 -0
- /package/dist/{adapters → observability/adapters}/opentelemetry.js +0 -0
- /package/dist/{adapters → observability/adapters}/sentry.js +0 -0
- /package/dist/{services/report.d.ts → observability/services/reporting.d.ts} +0 -0
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
import type { ContextValues } from "../context/store.js";
|
|
2
|
-
import type { Span } from "../observability/ports.js";
|
|
3
|
-
/**
|
|
4
|
-
* `Feature` and `ApplicationService`: the two kinds of service a bounded context holds, as in
|
|
5
|
-
* sincpro_framework. Each bounded context gives them its dependencies once, in its own base:
|
|
6
|
-
*
|
|
7
|
-
* // domains/project/infrastructure/bounded_context.ts
|
|
8
|
-
* export class Feature extends BaseFeature<ProjectDependencies> {}
|
|
9
|
-
* export class ApplicationService extends BaseApplicationService<ProjectDependencies, ProjectFeatures> {}
|
|
10
|
-
*
|
|
11
|
-
* // domains/project/services/issues.ts
|
|
12
|
-
* export class Issues extends Feature {
|
|
13
|
-
* close(input: dto.CommandCloseIssue) {
|
|
14
|
-
* this.session.require(); // each dependency is a property — typed
|
|
15
|
-
* return this.client.closeIssue(input);
|
|
16
|
-
* }
|
|
17
|
-
* }
|
|
18
|
-
*
|
|
19
|
-
* // domains/project/services/close_and_notify.ts
|
|
20
|
-
* export class CloseAndNotify extends ApplicationService {
|
|
21
|
-
* async execute(input: dto.CommandCloseIssue) {
|
|
22
|
-
* await this.feature.Issues.close(input); // a child of this run, on the same trace
|
|
23
|
-
* return this.feature.Notices.tell(input);
|
|
24
|
-
* }
|
|
25
|
-
* }
|
|
26
|
-
*
|
|
27
|
-
* Context: a Feature is a facade — the operations of one part of the domain, each a public
|
|
28
|
-
* method; an ApplicationService composes the Features of its own bounded context and never
|
|
29
|
-
* another ApplicationService (sincpro_framework's rule). Neither writes a span nor catches an
|
|
30
|
-
* error to report it: the bounded context runs every public method inside its own execution
|
|
31
|
-
* (`UseBoundedContext`).
|
|
32
|
-
*
|
|
33
|
-
* The dependencies are typed, not declared: `BaseFeature<ProjectDependencies>` types
|
|
34
|
-
* `this.client` and `this.session` from the bounded context's dependency type — sincpro_framework's
|
|
35
|
-
* `DependencyContextType` — and the bounded context hands them in on each run. So a service
|
|
36
|
-
* constructs with nothing, keeps no dependency on `this`, and declares no `#private` field: a run
|
|
37
|
-
* sees the instance through a view of its own (its dependencies bound to its trace), and
|
|
38
|
-
* `#private` refuses views. TypeScript's `private` is the same promise without that.
|
|
39
|
-
*/
|
|
40
|
-
declare class FeatureCore {
|
|
41
|
-
}
|
|
42
|
-
declare class ApplicationServiceCore extends FeatureCore {
|
|
43
|
-
}
|
|
44
|
-
/** What every service sees on `this` inside a method. */
|
|
45
|
-
type Within<D extends object, C extends object> = Readonly<D> & {
|
|
46
|
-
/**
|
|
47
|
-
* What this run executes with: the process's context, its bounded context's, its scope's —
|
|
48
|
-
* read once where the gesture started and the same for every Feature it runs.
|
|
49
|
-
*/
|
|
50
|
-
readonly context: Readonly<Partial<C>>;
|
|
51
|
-
/** This run's span: a use case says more about what it ran on (`this.span.set({ … })`). */
|
|
52
|
-
readonly span: Span;
|
|
53
|
-
};
|
|
54
|
-
/** Service classes by the name a bounded context gives them: `{ Issues, Notices }`. */
|
|
55
|
-
export type ServiceClasses = Readonly<Record<string, new () => object>>;
|
|
56
|
-
/**
|
|
57
|
-
* What a service offers to whoever holds it — `project.Issues`, `this.feature.Issues`: its public
|
|
58
|
-
* methods, without its dependencies, its context or its `_` helpers.
|
|
59
|
-
*/
|
|
60
|
-
export type ServiceMethods<I, D> = {
|
|
61
|
-
readonly [M in keyof I as M extends keyof D | "context" | "feature" | "span" | `_${string}` ? never : I[M] extends (...args: never[]) => unknown ? M : never]: I[M];
|
|
62
|
-
};
|
|
63
|
-
/** The services of a set of classes, by their names. */
|
|
64
|
-
export type Services<S extends ServiceClasses, D> = {
|
|
65
|
-
readonly [K in keyof S]: ServiceMethods<InstanceType<S[K]>, D>;
|
|
66
|
-
};
|
|
67
|
-
type FeatureClass = abstract new <D extends object = Record<never, never>, C extends object = ContextValues>() => FeatureCore & Within<D, C>;
|
|
68
|
-
type ApplicationServiceClass = abstract new <D extends object = Record<never, never>, F extends ServiceClasses = Record<never, never>, C extends object = ContextValues>() => ApplicationServiceCore & Within<D, C> & {
|
|
69
|
-
/** The Features of this bounded context, each run a child of this one. */
|
|
70
|
-
readonly feature: Services<F, D>;
|
|
71
|
-
};
|
|
72
|
-
/** The base of a bounded context's Features: `class Feature extends BaseFeature<Deps> {}`. */
|
|
73
|
-
export declare const Feature: FeatureClass;
|
|
74
|
-
/**
|
|
75
|
-
* The base of a bounded context's ApplicationServices:
|
|
76
|
-
* `class ApplicationService extends BaseApplicationService<Deps, typeof features> {}`.
|
|
77
|
-
*/
|
|
78
|
-
export declare const ApplicationService: ApplicationServiceClass;
|
|
79
|
-
/** Whether a class is a Feature — and not an ApplicationService. */
|
|
80
|
-
export declare function isFeatureClass(service: new () => object): boolean;
|
|
81
|
-
export declare function isApplicationServiceClass(service: new () => object): boolean;
|
|
82
|
-
/** Whether a service composes Features — an ApplicationService. */
|
|
83
|
-
export declare function composes(service: object): boolean;
|
|
84
|
-
export declare function methodsOf(service: object): ReadonlySet<string>;
|
|
85
|
-
export {};
|
package/dist/services/feature.js
DELETED
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `Feature` and `ApplicationService`: the two kinds of service a bounded context holds, as in
|
|
3
|
-
* sincpro_framework. Each bounded context gives them its dependencies once, in its own base:
|
|
4
|
-
*
|
|
5
|
-
* // domains/project/infrastructure/bounded_context.ts
|
|
6
|
-
* export class Feature extends BaseFeature<ProjectDependencies> {}
|
|
7
|
-
* export class ApplicationService extends BaseApplicationService<ProjectDependencies, ProjectFeatures> {}
|
|
8
|
-
*
|
|
9
|
-
* // domains/project/services/issues.ts
|
|
10
|
-
* export class Issues extends Feature {
|
|
11
|
-
* close(input: dto.CommandCloseIssue) {
|
|
12
|
-
* this.session.require(); // each dependency is a property — typed
|
|
13
|
-
* return this.client.closeIssue(input);
|
|
14
|
-
* }
|
|
15
|
-
* }
|
|
16
|
-
*
|
|
17
|
-
* // domains/project/services/close_and_notify.ts
|
|
18
|
-
* export class CloseAndNotify extends ApplicationService {
|
|
19
|
-
* async execute(input: dto.CommandCloseIssue) {
|
|
20
|
-
* await this.feature.Issues.close(input); // a child of this run, on the same trace
|
|
21
|
-
* return this.feature.Notices.tell(input);
|
|
22
|
-
* }
|
|
23
|
-
* }
|
|
24
|
-
*
|
|
25
|
-
* Context: a Feature is a facade — the operations of one part of the domain, each a public
|
|
26
|
-
* method; an ApplicationService composes the Features of its own bounded context and never
|
|
27
|
-
* another ApplicationService (sincpro_framework's rule). Neither writes a span nor catches an
|
|
28
|
-
* error to report it: the bounded context runs every public method inside its own execution
|
|
29
|
-
* (`UseBoundedContext`).
|
|
30
|
-
*
|
|
31
|
-
* The dependencies are typed, not declared: `BaseFeature<ProjectDependencies>` types
|
|
32
|
-
* `this.client` and `this.session` from the bounded context's dependency type — sincpro_framework's
|
|
33
|
-
* `DependencyContextType` — and the bounded context hands them in on each run. So a service
|
|
34
|
-
* constructs with nothing, keeps no dependency on `this`, and declares no `#private` field: a run
|
|
35
|
-
* sees the instance through a view of its own (its dependencies bound to its trace), and
|
|
36
|
-
* `#private` refuses views. TypeScript's `private` is the same promise without that.
|
|
37
|
-
*/
|
|
38
|
-
class FeatureCore {
|
|
39
|
-
}
|
|
40
|
-
class ApplicationServiceCore extends FeatureCore {
|
|
41
|
-
}
|
|
42
|
-
/** The base of a bounded context's Features: `class Feature extends BaseFeature<Deps> {}`. */
|
|
43
|
-
export const Feature = FeatureCore;
|
|
44
|
-
/**
|
|
45
|
-
* The base of a bounded context's ApplicationServices:
|
|
46
|
-
* `class ApplicationService extends BaseApplicationService<Deps, typeof features> {}`.
|
|
47
|
-
*/
|
|
48
|
-
export const ApplicationService = ApplicationServiceCore;
|
|
49
|
-
/** Whether a class is a Feature — and not an ApplicationService. */
|
|
50
|
-
export function isFeatureClass(service) {
|
|
51
|
-
return (service.prototype instanceof FeatureCore &&
|
|
52
|
-
!(service.prototype instanceof ApplicationServiceCore));
|
|
53
|
-
}
|
|
54
|
-
export function isApplicationServiceClass(service) {
|
|
55
|
-
return service.prototype instanceof ApplicationServiceCore;
|
|
56
|
-
}
|
|
57
|
-
/** Whether a service composes Features — an ApplicationService. */
|
|
58
|
-
export function composes(service) {
|
|
59
|
-
return service instanceof ApplicationServiceCore;
|
|
60
|
-
}
|
|
61
|
-
/**
|
|
62
|
-
* The methods a class adds over its base — what is traced — read once per class: every public
|
|
63
|
-
* method of the class and its parents up to `Feature`, but `constructor` and a name that starts
|
|
64
|
-
* with `_`.
|
|
65
|
-
*/
|
|
66
|
-
const METHODS = new WeakMap();
|
|
67
|
-
export function methodsOf(service) {
|
|
68
|
-
const prototype = Object.getPrototypeOf(service);
|
|
69
|
-
const known = METHODS.get(prototype);
|
|
70
|
-
if (known !== undefined)
|
|
71
|
-
return known;
|
|
72
|
-
const names = new Set();
|
|
73
|
-
for (let level = prototype; level !== null &&
|
|
74
|
-
level !== ApplicationServiceCore.prototype &&
|
|
75
|
-
level !== FeatureCore.prototype &&
|
|
76
|
-
level !== Object.prototype; level = Object.getPrototypeOf(level))
|
|
77
|
-
for (const name of Object.getOwnPropertyNames(level)) {
|
|
78
|
-
const descriptor = Object.getOwnPropertyDescriptor(level, name);
|
|
79
|
-
if (name !== "constructor" &&
|
|
80
|
-
!name.startsWith("_") &&
|
|
81
|
-
typeof descriptor?.value === "function")
|
|
82
|
-
names.add(name);
|
|
83
|
-
}
|
|
84
|
-
METHODS.set(prototype, names);
|
|
85
|
-
return names;
|
|
86
|
-
}
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
import { type Context, type StoreSource } from "../context/context.js";
|
|
2
|
-
import { type ContextStore } from "../context/store.js";
|
|
3
|
-
import { type ErrorReporter, type Outcome, type Tracer } from "../observability/ports.js";
|
|
4
|
-
/**
|
|
5
|
-
* What every bounded context of this process runs with — set once, in `main`, the way
|
|
6
|
-
* sincpro_framework's process is: who traces, who reports, where the context lives.
|
|
7
|
-
*
|
|
8
|
-
* // entrypoints/main.tsx — the platform's pieces, built from the application's settings
|
|
9
|
-
* configureProcess({
|
|
10
|
-
* tracer: browserTracer({ endpoint: settings.otlp, service: "forge-web" }),
|
|
11
|
-
* reporter: glitchtipReporter({ dsn: settings.glitchtip }),
|
|
12
|
-
* context: memoryContexts(),
|
|
13
|
-
* });
|
|
14
|
-
*
|
|
15
|
-
* Context: everything is optional, and nothing breaks without it. A process that never configures
|
|
16
|
-
* runs every use case untraced, unreported, with its context in memory — so a bounded context is
|
|
17
|
-
* usable the moment it is imported, and `main` adds what it watches with. The bounded contexts
|
|
18
|
-
* read the process on every call, never at import: `project` may be defined before `main` runs.
|
|
19
|
-
*
|
|
20
|
-
* It replaces everything at once: what is not given goes back to its default — a test calls it
|
|
21
|
-
* with its own tracer and starts from a clean context.
|
|
22
|
-
*/
|
|
23
|
-
export type ProcessOptions = {
|
|
24
|
-
/** The platform's (OpenTelemetry in a browser, a queue on a phone, memory in a test). */
|
|
25
|
-
tracer?: Tracer;
|
|
26
|
-
/** The platform's (GlitchTip, Sentry, memory in a test). Only what nobody expected reaches it. */
|
|
27
|
-
reporter?: ErrorReporter;
|
|
28
|
-
/** Where the context lives (`memoryContexts()` by default). */
|
|
29
|
-
context?: ContextStore;
|
|
30
|
-
/** How an error ended a use case (`outcomeOf` by default). Only `failed` is reported. */
|
|
31
|
-
outcomeOf?: (error: unknown) => Outcome;
|
|
32
|
-
};
|
|
33
|
-
/** The process as a use case reads it. Not public: `configureProcess` is the way in. */
|
|
34
|
-
export type Process = {
|
|
35
|
-
readonly tracer: Tracer;
|
|
36
|
-
readonly reporter: ErrorReporter | undefined;
|
|
37
|
-
readonly store: ContextStore;
|
|
38
|
-
readonly outcomeOf: (error: unknown) => Outcome;
|
|
39
|
-
};
|
|
40
|
-
export declare function configureProcess(options?: ProcessOptions): void;
|
|
41
|
-
/** The process's store as every level of the context reads it — the process's and each bounded context's. */
|
|
42
|
-
export declare const processStore: StoreSource;
|
|
43
|
-
/** What the process runs with now. */
|
|
44
|
-
export declare function processNow(): Process;
|
|
45
|
-
/**
|
|
46
|
-
* The process's level of the context: what every use case of every bounded context runs with —
|
|
47
|
-
* the tenant, the company, the language.
|
|
48
|
-
*
|
|
49
|
-
* processContext.set({ tenant_id: "acme" });
|
|
50
|
-
*/
|
|
51
|
-
export declare const processContext: Context;
|
|
52
|
-
/**
|
|
53
|
-
* How an error ended a use case, by default.
|
|
54
|
-
*
|
|
55
|
-
* Context: the backend reports what nobody expected and only that — a refusal it explained is
|
|
56
|
-
* the business answering, not a fault. Here the same: a `TransportError` the server answered
|
|
57
|
-
* with a 4xx is `refused`; a request the caller stopped waiting for is `aborted`; everything
|
|
58
|
-
* else — a bug, a 5xx, a server nobody could reach — is `failed`, and reported.
|
|
59
|
-
*/
|
|
60
|
-
export declare function outcomeOf(error: unknown): Outcome;
|
package/dist/services/process.js
DELETED
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import { TransportError } from "../client/transport.js";
|
|
2
|
-
import { contextAt, } from "../context/context.js";
|
|
3
|
-
import { memoryContexts } from "../context/store.js";
|
|
4
|
-
import { NO_TRACER, } from "../observability/ports.js";
|
|
5
|
-
function settled(options) {
|
|
6
|
-
return {
|
|
7
|
-
tracer: options.tracer ?? NO_TRACER,
|
|
8
|
-
reporter: options.reporter,
|
|
9
|
-
store: options.context ?? memoryContexts(),
|
|
10
|
-
outcomeOf: options.outcomeOf ?? outcomeOf,
|
|
11
|
-
};
|
|
12
|
-
}
|
|
13
|
-
let current = settled({});
|
|
14
|
-
const replacing = new Set();
|
|
15
|
-
export function configureProcess(options = {}) {
|
|
16
|
-
const before = current.store;
|
|
17
|
-
current = settled(options);
|
|
18
|
-
if (current.store !== before)
|
|
19
|
-
for (const listener of [...replacing])
|
|
20
|
-
listener();
|
|
21
|
-
}
|
|
22
|
-
/** The process's store as every level of the context reads it — the process's and each bounded context's. */
|
|
23
|
-
export const processStore = {
|
|
24
|
-
current: () => current.store,
|
|
25
|
-
replaced(listener) {
|
|
26
|
-
replacing.add(listener);
|
|
27
|
-
return () => void replacing.delete(listener);
|
|
28
|
-
},
|
|
29
|
-
};
|
|
30
|
-
/** What the process runs with now. */
|
|
31
|
-
export function processNow() {
|
|
32
|
-
return current;
|
|
33
|
-
}
|
|
34
|
-
/**
|
|
35
|
-
* The process's level of the context: what every use case of every bounded context runs with —
|
|
36
|
-
* the tenant, the company, the language.
|
|
37
|
-
*
|
|
38
|
-
* processContext.set({ tenant_id: "acme" });
|
|
39
|
-
*/
|
|
40
|
-
export const processContext = contextAt("process", processStore);
|
|
41
|
-
/**
|
|
42
|
-
* How an error ended a use case, by default.
|
|
43
|
-
*
|
|
44
|
-
* Context: the backend reports what nobody expected and only that — a refusal it explained is
|
|
45
|
-
* the business answering, not a fault. Here the same: a `TransportError` the server answered
|
|
46
|
-
* with a 4xx is `refused`; a request the caller stopped waiting for is `aborted`; everything
|
|
47
|
-
* else — a bug, a 5xx, a server nobody could reach — is `failed`, and reported.
|
|
48
|
-
*/
|
|
49
|
-
export function outcomeOf(error) {
|
|
50
|
-
if (error instanceof TransportError && error.status !== null)
|
|
51
|
-
return error.status >= 400 && error.status < 500 ? "refused" : "failed";
|
|
52
|
-
if (error !== null &&
|
|
53
|
-
typeof error === "object" &&
|
|
54
|
-
error.name === "AbortError")
|
|
55
|
-
return "aborted";
|
|
56
|
-
return "failed";
|
|
57
|
-
}
|
package/dist/services/screens.js
DELETED
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
import { UseBoundedContext } from "./bounded-context.js";
|
|
2
|
-
import { Feature } from "./feature.js";
|
|
3
|
-
/**
|
|
4
|
-
* What a screen reads of an entity — a page, a record, a read of its own: sincpro_framework's
|
|
5
|
-
* built-in `EntityReads`, on the client.
|
|
6
|
-
*/
|
|
7
|
-
class EntityReads extends Feature {
|
|
8
|
-
list(route, criteria, signal, options) {
|
|
9
|
-
this.span.set({ "http.route": route });
|
|
10
|
-
return this.transport.list(route, criteria, signal, options);
|
|
11
|
-
}
|
|
12
|
-
one(route, signal, options) {
|
|
13
|
-
this.span.set({ "http.route": route });
|
|
14
|
-
return this.transport.one(route, signal, options);
|
|
15
|
-
}
|
|
16
|
-
read(route, signal, options) {
|
|
17
|
-
this.span.set({ "http.route": route });
|
|
18
|
-
const read = this.transport.read;
|
|
19
|
-
if (read === undefined)
|
|
20
|
-
return Promise.reject(new Error(`this transport cannot read ${route}: it has no read()`));
|
|
21
|
-
return read.call(this.transport, route, signal, options);
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
/** What a screen writes — a save, a draft, a preview, a Command: each request a use case. */
|
|
25
|
-
class EntityWrites extends Feature {
|
|
26
|
-
send(method, route, body, signal, options) {
|
|
27
|
-
this.span.set({ "http.method": method, "http.route": route });
|
|
28
|
-
return this.transport.send(method, route, body, signal, options);
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
/**
|
|
32
|
-
* The transport, every call a use case of a bounded context of its own — `screens` unless named:
|
|
33
|
-
* what a platform hands the screens it draws.
|
|
34
|
-
*
|
|
35
|
-
* const screens = screensTransport(restTransport({ base: "/v1" }));
|
|
36
|
-
* await screens.list("/facturas", criteria); // span screens/EntityReads.list
|
|
37
|
-
*
|
|
38
|
-
* Context: a use case is traced, carries its context and reports what nobody expected; a list a
|
|
39
|
-
* screen reads through the transport was none of that — no span, no `traceparent` (the backend's
|
|
40
|
-
* trace started there, with no client in it), no company, and a 500 reported to nobody. Here
|
|
41
|
-
* each read and write runs as a use case of `screens` — `EntityReads.list`, `.one`, `.read`,
|
|
42
|
-
* `EntityWrites.send` —, so it gets all three the way any other does: the span (its route said
|
|
43
|
-
* on it), the trace and the process's context on the request, and a report only when it failed
|
|
44
|
-
* (a 4xx the server explained is the screen's to show). A bounded context's own dependencies are
|
|
45
|
-
* never given this: there its use case is the one that runs.
|
|
46
|
-
*/
|
|
47
|
-
/** The transports this made: given one again, it is answered as it is — wrapped twice, each
|
|
48
|
-
* request would be two unrelated use cases, and the server would see only the outer's trace. */
|
|
49
|
-
const MADE = new WeakSet();
|
|
50
|
-
export function screensTransport(transport, name = "screens") {
|
|
51
|
-
if (MADE.has(transport))
|
|
52
|
-
return transport;
|
|
53
|
-
const screens = new UseBoundedContext(name)
|
|
54
|
-
.addDependency("transport", transport)
|
|
55
|
-
.register({ features: { EntityReads, EntityWrites } });
|
|
56
|
-
const reads = screens.EntityReads;
|
|
57
|
-
const writes = screens.EntityWrites;
|
|
58
|
-
const through = {
|
|
59
|
-
list: (route, criteria, signal, options) => reads.list(route, criteria, signal, options),
|
|
60
|
-
one: (route, signal, options) => reads.one(route, signal, options),
|
|
61
|
-
send: (method, route, body, signal, options) => writes.send(method, route, body, signal, options),
|
|
62
|
-
};
|
|
63
|
-
if (transport.read !== undefined)
|
|
64
|
-
through.read = (route, signal, options) => reads.read(route, signal, options);
|
|
65
|
-
MADE.add(through);
|
|
66
|
-
return through;
|
|
67
|
-
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|