@sincpro/client-framework 0.6.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 +324 -345
- package/dist/client/{memory.d.ts → adapters/memory.d.ts} +1 -1
- package/dist/client/{memory.js → adapters/memory.js} +2 -2
- package/dist/{adapters → client/adapters}/parquet.d.ts +1 -1
- package/dist/client/{rest.d.ts → adapters/rest.d.ts} +1 -1
- package/dist/client/{rest.js → adapters/rest.js} +2 -2
- package/dist/client/{entity.d.ts → domain/entity.d.ts} +6 -10
- 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} +5 -21
- package/dist/client/{retry.js → services/retry.js} +1 -1
- package/dist/codegen/{metamodel.d.ts → domain/metamodel.d.ts} +17 -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} +9 -1
- package/dist/codegen/services/domain.d.ts +20 -0
- package/dist/codegen/{domain.js → services/domain.js} +82 -25
- package/dist/codegen/{entities.d.ts → services/entities.d.ts} +4 -3
- package/dist/codegen/{entities.js → services/entities.js} +18 -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/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 -38
- package/dist/index.js +16 -38
- 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 +16 -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 -76
- /package/dist/{adapters → client/adapters}/parquet.js +0 -0
- /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/{entity.js → domain/entity.js} +0 -0
- /package/dist/client/{transport.d.ts → domain/transport.d.ts} +0 -0
- /package/dist/client/{transport.js → domain/transport.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.d.ts → domain/meta.d.ts} +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
package/AGENTS.md
CHANGED
|
@@ -20,18 +20,22 @@ it says what this package is responsible for and what it is not. This file is ho
|
|
|
20
20
|
|
|
21
21
|
## Where things go
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
|
29
|
-
|
|
|
30
|
-
| `src/
|
|
31
|
-
| `src/
|
|
32
|
-
| `src/
|
|
33
|
-
| `src/
|
|
34
|
-
| `
|
|
23
|
+
Each module is laid out as sincpro_framework's are: `domain/` (ports, types and rules),
|
|
24
|
+
`adapters/` (implementations of the ports), `services/` (what uses them), `infrastructure/`
|
|
25
|
+
(the process's state and technical support) and `entrypoint/` (the doors a caller uses). A
|
|
26
|
+
module has only the layers it needs, and says what it offers in its own `index.ts`.
|
|
27
|
+
|
|
28
|
+
| Folder | What |
|
|
29
|
+
| -------------------- | ---------------------------------------------------------------------------------------------- |
|
|
30
|
+
| `src/common/` | The values of the wire: ids, a day and an instant, `Decimal`, `Money`, `valuesOf` / `rebuilt` |
|
|
31
|
+
| `src/context/` | `ContextStore`, codec, `Execution` (domain); memory and plain codec; `Context`; the process's |
|
|
32
|
+
| `src/observability/` | Tracer/ErrorReporter/Logger ports; console, memory, OpenTelemetry, Sentry; loggers, reporting |
|
|
33
|
+
| `src/client/` | `Transport`, `entity()`, the contract (domain); REST, memory, Parquet; discovery, propagation |
|
|
34
|
+
| `src/model/` | Model definitions: `defineMeta`, from a JSON Schema, the store of known ones |
|
|
35
|
+
| `src/core/` | DTOs, bus, Feature/ApplicationService, error handlers; pipeline; `BoundedContext`; the process |
|
|
36
|
+
| `src/codegen/` | The generator and its CLI (`sincpro-client generate`) — the only place Node is allowed |
|
|
37
|
+
| `src/testing/` | The public entry of the in-memory observability adapters |
|
|
38
|
+
| `tests/` | vitest in Node, one folder per module; `tests/support/` holds fakes and forge's contracts |
|
|
35
39
|
|
|
36
40
|
## Hard rules (the build enforces them — `make doctor`)
|
|
37
41
|
|
|
@@ -42,6 +46,11 @@ it says what this package is responsible for and what it is not. This file is ho
|
|
|
42
46
|
and nowhere else; nothing an application runs imports `codegen/`.
|
|
43
47
|
- **Self-imports, no extensions.** Inside `src/`, import `@sincpro/client-framework/<path>` —
|
|
44
48
|
never a relative path, never `.ts`.
|
|
49
|
+
- **Domain inward.** A `domain/` folder imports only other `domain/` folders: no adapter,
|
|
50
|
+
service, infrastructure or entrypoint.
|
|
51
|
+
- **Vendors in their entry.** A vendor's SDK is imported only in its optional entry
|
|
52
|
+
(`observability/adapters/opentelemetry.ts`, `observability/adapters/sentry.ts`,
|
|
53
|
+
`client/adapters/parquet.ts`), and nothing in `src/` imports one.
|
|
45
54
|
|
|
46
55
|
## Conventions
|
|
47
56
|
|
|
@@ -55,17 +64,19 @@ it says what this package is responsible for and what it is not. This file is ho
|
|
|
55
64
|
## Known traps
|
|
56
65
|
|
|
57
66
|
- **A run sees the instance through a view of its own.** Inside a method, each dependency
|
|
58
|
-
(`this.client`), `this.context` and `this.
|
|
67
|
+
(`this.client`), `this.context` and `this.featureBus` are that run's — bound to its execution. So a
|
|
59
68
|
service declares no `#private` fields (they refuse the view); use TypeScript's `private`.
|
|
60
|
-
- **A service is a singleton of its
|
|
61
|
-
instance, shared by the next call, the call beside it and every `
|
|
69
|
+
- **A service is a singleton of its generation.** What a method writes on `this` lands on the
|
|
70
|
+
instance, shared by the next call, the call beside it and every `scoped` variant — as in
|
|
62
71
|
sincpro_framework. What belongs to one request goes in its arguments or its context.
|
|
63
|
-
- **A span
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
72
|
+
- **A span uses stable service metadata, not constructor.name.** `serviceName = "Cancel"` gives
|
|
73
|
+
`project/Cancel`, identity `project.Cancel`. Commands route by exact constructor identity.
|
|
74
|
+
- **Dependency declarations do not register anything.** Service bases declare typed attributes
|
|
75
|
+
from a shared dependency interface. Only `addDependency` supplies runtime values; a missing
|
|
76
|
+
dependency fails explicitly.
|
|
77
|
+
- **Decorators are optional.** Function registration must work without any decorator
|
|
78
|
+
transform. Standard and legacy (`experimentalDecorators`) fixtures are compiled explicitly in
|
|
79
|
+
tests; do not claim Metro (Babel) or web bundler support without testing those configurations.
|
|
69
80
|
- **The trace reaches the wire through the dependencies.** A dependency is bound to the run when it
|
|
70
81
|
is a `Transport` or carries `BIND` (every generated client does, through `bindable`); anything
|
|
71
82
|
else is handed as it is. A client built elsewhere and closed over sends no trace.
|
|
@@ -76,20 +87,38 @@ it says what this package is responsible for and what it is not. This file is ho
|
|
|
76
87
|
- **A store's `load` may answer a new object each time** (one that parses JSON does): `Context`
|
|
77
88
|
keeps one object per `version`, so a screen can hand `values` to `useSyncExternalStore`. A store
|
|
78
89
|
that changes without moving the version is a broken store.
|
|
90
|
+
- **What is generated is types, never classes.** A generated DTO is the remote contract: a
|
|
91
|
+
class extending `Command` could be registered on the local bus, which is what keeps a remote
|
|
92
|
+
operation and a local use case apart. Runtime knowledge goes in data (`operations`, `events`);
|
|
93
|
+
validating or converting what arrives would be a generated reader, not a class.
|
|
94
|
+
- **Events come only from the contract.** The generator writes event types and `DomainEvent`
|
|
95
|
+
only when the backend exported its contract with `--events`; a contract without them writes
|
|
96
|
+
the same bytes as before.
|
|
79
97
|
- **What the generator writes is compared byte for byte** (`tests/support/forge-contract/`, out
|
|
80
98
|
of prettier and eslint). After changing the generator on purpose, run `make codegen-fixtures`
|
|
81
99
|
and read the diff.
|
|
82
|
-
- **A module name the generator writes is built in parts** (`codegen/names.ts`, `FRAMEWORK`): the
|
|
100
|
+
- **A module name the generator writes is built in parts** (`codegen/domain/names.ts`, `FRAMEWORK`): the
|
|
83
101
|
build's `tsc-alias` rewrites this package's specifiers inside strings too.
|
|
84
102
|
- **An adapter wraps what the application built, never builds it.** `openTelemetryTracer` takes
|
|
85
103
|
the app's tracer, `sentryReporter` the app's client: no `register()`, no `Sentry.init()`, no
|
|
86
104
|
endpoint or DSN here, nothing read from the environment. A vendor's SDK is imported only in
|
|
87
|
-
|
|
105
|
+
its optional entry, and nothing else imports one (`make doctor`).
|
|
88
106
|
- **A span nothing records claims no trace.** OpenTelemetry's API with no provider answers an
|
|
89
107
|
all-zeros span: the adapter gives no ids, so no `traceparent` of zeros reaches the server.
|
|
90
108
|
- **Reported means unexpected.** A `TransportError` the server answered with a 4xx is `refused`,
|
|
91
|
-
an `AbortError` is `aborted`; neither is reported (`outcomeOf`).
|
|
92
|
-
`
|
|
109
|
+
an `AbortError` is `aborted`; neither is reported (`outcomeOf`). A bounded context adds its own
|
|
110
|
+
with `expectErrors(...)`; a process replaces the rule with `ProcessOptions.outcomeOf`. Never
|
|
111
|
+
catch in a Feature to hide a failure.
|
|
112
|
+
- **An error handler answers; it does not observe.** The failure is recorded where it happened —
|
|
113
|
+
span, log line, report — before the layer's handlers run, as in sincpro_framework. A handler
|
|
114
|
+
returns the answer or throws to the next; the global chain wraps only `execute` and `scoped`.
|
|
115
|
+
- **The application layer imports no logger.** A bounded context has `project.logger`; a run
|
|
116
|
+
hands `this.logger`, bound to its execution. Only `logger` (infrastructure, the global one) and
|
|
117
|
+
`loggerAdapter` are predefined; injected as a dependency they bind to the run (`BIND`), imported
|
|
118
|
+
at module level they do not. No logger is predefined for an application layer. Console is the
|
|
119
|
+
default engine; `configureProcess({ logger })` and `configureLogger(...)` take the same
|
|
120
|
+
`LoggerConfiguration`. The host chooses production explicitly. Never log DTOs, results, full
|
|
121
|
+
session context or raw errors automatically.
|
|
93
122
|
|
|
94
123
|
- **Only what is transversal comes here.** A value's wire form (a decimal as text, a day never
|
|
95
124
|
an instant, a money with its currency) is the backend's contract, the same on every platform,
|
package/MANIFESTO.md
CHANGED
|
@@ -25,27 +25,28 @@ server-side render, in a script and in a test, unchanged.**
|
|
|
25
25
|
|
|
26
26
|
## What it is responsible for
|
|
27
27
|
|
|
28
|
-
1. **Services.** A `Feature`
|
|
29
|
-
|
|
30
|
-
ApplicationService.
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
with its trace id; what the server already explained (a validation, a conflict) not reported.
|
|
28
|
+
1. **Services.** A `Feature` executes a registered Command through `execute(dto)`;
|
|
29
|
+
an `ApplicationService` composes its context's Features through `featureBus`, never another
|
|
30
|
+
ApplicationService. Dependencies are typed attributes supplied by the bounded context.
|
|
31
|
+
2. **Execution.** Every command enters one internal execution pipeline. Context, tracing,
|
|
32
|
+
outcomes and error reporting are supplied there, not handwritten by each service.
|
|
33
|
+
3. **Observability, as ports.** `Tracer`, `ErrorReporter` and `Logger` are the contracts: one span per use
|
|
34
|
+
case, named `<bounded context>/<serviceName>`; the unexpected reported
|
|
35
|
+
with its trace id; what the server already explained (a validation, a conflict), or what a
|
|
36
|
+
bounded context declares expected, not reported.
|
|
38
37
|
The platform plugs the implementation — OpenTelemetry, GlitchTip, a queue on the phone, memory
|
|
39
|
-
in a test — once, for the process (`configureProcess`).
|
|
38
|
+
in a test — once, for the process (`configureProcess`). Structured logs are tagged by layer
|
|
39
|
+
(infrastructure, adapter, bounded context, ApplicationService, Feature) and by execution;
|
|
40
|
+
console filtering never controls another sink's delivery.
|
|
40
41
|
4. **Context.** The levels a call sees — the process, its bounded context, a scope — read once
|
|
41
42
|
where a gesture starts and inherited by everything it runs, and what travels to the server with
|
|
42
43
|
it (`traceparent`, `sincpro-context`). Where the values live is a port (`ContextStore`) each
|
|
43
44
|
platform implements with its own technology; the execution is carried by each call, never kept
|
|
44
45
|
in a global stack: two calls at once never mix their parents.
|
|
45
46
|
5. **Bounded contexts.** Set up like the backend's — its dependencies (`addDependency`), its
|
|
46
|
-
Features and ApplicationServices, registered
|
|
47
|
-
`project.
|
|
48
|
-
never import each other's insides.
|
|
47
|
+
Features and ApplicationServices, registered for class DTOs — and called as
|
|
48
|
+
`project.execute(new Command(...))`. The bounded context is the bus. An application is the set
|
|
49
|
+
of bounded contexts it loads; they never import each other's insides.
|
|
49
50
|
6. **The client.** The `Transport` port and its implementations (REST, memory), `entity()` with
|
|
50
51
|
typed commands and answers, the service's client contract, model definitions read once from
|
|
51
52
|
the server and the server's `Problem`.
|
|
@@ -54,9 +55,16 @@ server-side render, in a script and in a test, unchanged.**
|
|
|
54
55
|
and the exact arithmetic a client needs on them (`Decimal`, `Money`). Only the wire form and
|
|
55
56
|
what follows from it: showing a value to a person is each platform's.
|
|
56
57
|
8. **The generator.** From a service's client contract to each domain's types, client and
|
|
57
|
-
entities —
|
|
58
|
+
entities — and its domain events when the contract carries them —, generated as types,
|
|
59
|
+
never edited, and as platform-neutral as everything else here.
|
|
58
60
|
9. **Testing.** An in-memory transport, tracer and reporter, so a use case is proven in Node with
|
|
59
61
|
nothing else.
|
|
62
|
+
10. **The command core (`./core`).** The single model matching the backend's application
|
|
63
|
+
abstractions: class DTOs and Responses, a bounded context that is a bus, Features and
|
|
64
|
+
ApplicationServices registered for DTO classes, attribute-injected dependencies and a
|
|
65
|
+
feature bus for composition, and the backend's error handlers — global, feature and
|
|
66
|
+
application service — with the errors a bounded context expects. The internal engine uses
|
|
67
|
+
the injected process ports. Remote clients and mapping remain distinct.
|
|
60
68
|
|
|
61
69
|
## What it is not
|
|
62
70
|
|
|
@@ -73,9 +81,11 @@ server-side render, in a script and in a test, unchanged.**
|
|
|
73
81
|
application built — its provider, its client, with its endpoint and its DSN. It initialises
|
|
74
82
|
nothing and registers nothing global; an application that does not import them installs
|
|
75
83
|
nothing and ships nothing, and without a tracer or a reporter everything runs the same.
|
|
76
|
-
- **Not where business rules live.** The
|
|
77
|
-
|
|
78
|
-
|
|
84
|
+
- **Not where application-specific business rules live.** The package supplies execution
|
|
85
|
+
abstractions; a registered use case may delegate to a server or use a local domain. A remote
|
|
86
|
+
adapter does not authorize reimplementing the server's rules.
|
|
87
|
+
- **Not an event delivery system.** The command dispatcher in `./core` executes use cases.
|
|
88
|
+
An event contract does not supply a publisher, queue, outbox, broker or synchronization engine.
|
|
79
89
|
|
|
80
90
|
## What we believe
|
|
81
91
|
|
|
@@ -85,17 +95,18 @@ server-side render, in a script and in a test, unchanged.**
|
|
|
85
95
|
2. **The backend's words.** Bounded context, Feature, ApplicationService, dependencies, context,
|
|
86
96
|
process, the span name — the same as sincpro_framework, so whoever knows the backend already
|
|
87
97
|
knows the client.
|
|
88
|
-
3. **Nothing escapes
|
|
89
|
-
context
|
|
90
|
-
|
|
98
|
+
3. **Nothing escapes execution.** Reusing a use case means dispatching its Command through the
|
|
99
|
+
bounded context or feature bus. Directly constructing and calling a service bypasses its
|
|
100
|
+
execution context and instrumentation.
|
|
91
101
|
4. **Context travels with the call.** Never in a global stack: clients run many things at once.
|
|
92
102
|
5. **A port where there are two implementations, a class where there is one.** `Transport` has
|
|
93
103
|
REST and memory; `Tracer` has a platform's and a test's; `ContextStore` has the browser's, the
|
|
94
104
|
phone's and memory.
|
|
95
105
|
6. **Generated, never edited.** Applications extend by composition; regenerating never loses
|
|
96
106
|
work.
|
|
97
|
-
7. **
|
|
98
|
-
|
|
107
|
+
7. **Authority is explicit.** A generated client reads the server's model and refusal and never
|
|
108
|
+
authorizes duplicating server rules. A local domain can own local rules; synchronization and
|
|
109
|
+
conflict policy are separate from command delivery.
|
|
99
110
|
8. **Small, and paid for only when used.** No side effects at import, tree-shakable, and no
|
|
100
111
|
dependency it can avoid.
|
|
101
112
|
9. **Grow by evidence.** Nothing before its second use; every change ships with a test that fails
|
|
@@ -107,8 +118,8 @@ server-side render, in a script and in a test, unchanged.**
|
|
|
107
118
|
@sincpro/criteria the contract with the server: Criteria, Meta, Page, Problem
|
|
108
119
|
▲
|
|
109
120
|
@sincpro/client-framework this package — platform-neutral
|
|
110
|
-
│
|
|
111
|
-
│ the process · the context · Tracer, ErrorReporter and ContextStore ports
|
|
121
|
+
│ BoundedContext · Command · Feature · ApplicationService · execution
|
|
122
|
+
│ the process · the context · Tracer, ErrorReporter, Logger and ContextStore ports
|
|
112
123
|
│ Transport · entity() · client contract · model definitions · ids
|
|
113
124
|
│ the generator · in-memory doubles for tests
|
|
114
125
|
▲
|
|
@@ -121,20 +132,29 @@ Dependencies point down only. This package knows nothing above it.
|
|
|
121
132
|
|
|
122
133
|
## Where it stands
|
|
123
134
|
|
|
124
|
-
**The
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
**
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
**
|
|
137
|
-
|
|
135
|
+
**The application layer is the backend's.** A bounded context executes class Commands through
|
|
136
|
+
one pipeline — context, span, log lines, outcome, report — with its dependencies injected,
|
|
137
|
+
its ApplicationServices composing Features through `featureBus`, and the backend's error
|
|
138
|
+
handlers: a failure is observed where it happened, then answered or handed on. Screen requests
|
|
139
|
+
and scaffolded applications run through the same pipeline.
|
|
140
|
+
|
|
141
|
+
**Observability is ports, plugged once.** Tracing, error reporting and logging are ports the
|
|
142
|
+
process configures; the console is the default log engine, OpenTelemetry and Sentry optional
|
|
143
|
+
entries that wrap what the application built. The application layer imports no logger: a
|
|
144
|
+
bounded context has its own, and a run hands `this.logger`, bound to its execution; only the
|
|
145
|
+
infrastructure and the adapters have a predefined one.
|
|
146
|
+
|
|
147
|
+
**The client and the generator read the backend's contract.** Types per model, operation and —
|
|
148
|
+
when the contract is exported with them — domain event; a client per wire REST reaches; the
|
|
149
|
+
entities screens use. What is generated is types, never classes: the remote contract describes
|
|
150
|
+
the wire and never reaches the local bus.
|
|
151
|
+
|
|
152
|
+
**Each module is laid out as the backend's.** `domain/`, `adapters/`, `services/`,
|
|
153
|
+
`infrastructure/`, `entrypoint/`, only those a module needs; `domain/` depends only on `domain/`.
|
|
154
|
+
|
|
155
|
+
**Next:** web and mobile adopt it in their own releases; generated readers that validate and
|
|
156
|
+
convert what arrives, when a use needs them; durable delivery, designed apart from
|
|
157
|
+
instrumentation.
|
|
138
158
|
|
|
139
159
|
## How we decide
|
|
140
160
|
|