@whooshbang/contract-mock 1.0.0-rc.16
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/CHANGELOG.md +141 -0
- package/LICENSE +21 -0
- package/README.md +173 -0
- package/dist/app.d.ts +8 -0
- package/dist/app.js +16 -0
- package/dist/app.js.map +1 -0
- package/dist/cli.d.ts +26 -0
- package/dist/cli.js +249 -0
- package/dist/cli.js.map +1 -0
- package/dist/control-surface.d.ts +13 -0
- package/dist/control-surface.js +158 -0
- package/dist/control-surface.js.map +1 -0
- package/dist/core.d.ts +33 -0
- package/dist/core.js +3459 -0
- package/dist/core.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/interaction-control.d.ts +6 -0
- package/dist/interaction-control.js +76 -0
- package/dist/interaction-control.js.map +1 -0
- package/dist/scenarios.d.ts +14 -0
- package/dist/scenarios.js +73 -0
- package/dist/scenarios.js.map +1 -0
- package/dist/types.d.ts +203 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/worker.d.ts +9 -0
- package/dist/worker.js +10 -0
- package/dist/worker.js.map +1 -0
- package/package.json +67 -0
- package/scenarios/v1/manifest.json +31 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to the deterministic WhooshBang contract mock are
|
|
4
|
+
recorded here.
|
|
5
|
+
|
|
6
|
+
## 1.0.0-rc.16
|
|
7
|
+
|
|
8
|
+
- Publish the unchanged deterministic mock as the first public npm candidate,
|
|
9
|
+
with explicit public package metadata and a package-local MIT license.
|
|
10
|
+
- Reissue against contracts `1.0.0-rc.13` and SDK `1.0.0-rc.14`; runtime
|
|
11
|
+
behavior and scenario semantics are unchanged, and `1.0.0-rc.15` remains
|
|
12
|
+
immutable.
|
|
13
|
+
|
|
14
|
+
## 1.0.0-rc.15
|
|
15
|
+
|
|
16
|
+
- Exclude already-acknowledged events from machine polls, including
|
|
17
|
+
acknowledgements recorded beyond an earlier cursor gap.
|
|
18
|
+
- Report a repeated successful acknowledgement as `existing` with the current
|
|
19
|
+
committed cursor instead of replaying the first response body.
|
|
20
|
+
- Reissue against contracts `1.0.0-rc.12`, SDK `1.0.0-rc.13`, and MCP
|
|
21
|
+
`1.0.0-rc.4`; the published schemas and fixture semantics are unchanged and
|
|
22
|
+
`1.0.0-rc.14` remains immutable.
|
|
23
|
+
|
|
24
|
+
## 1.0.0-rc.14
|
|
25
|
+
|
|
26
|
+
- Reissue the mock against `@whooshbang/contracts@1.0.0-rc.11` and
|
|
27
|
+
`@whooshbang/sdk@1.0.0-rc.12` for the combined replay-refusal and
|
|
28
|
+
machine-answer-retention contract.
|
|
29
|
+
- Publish `answer_retained: true` on every retained `interaction.received`
|
|
30
|
+
event the mock creates or seeds; consumers may also validate the contract's
|
|
31
|
+
redacted false-without-response shape.
|
|
32
|
+
- Include the new closed `replay_unavailable` Problem code through the public
|
|
33
|
+
contract vocabulary. `1.0.0-rc.13` remains immutable.
|
|
34
|
+
|
|
35
|
+
## 1.0.0-rc.12
|
|
36
|
+
|
|
37
|
+
- Exercise the WhooshBang MCP tools against the mock over both the stdio and
|
|
38
|
+
the OAuth-secured remote transport, so the coding-agent surface is proven
|
|
39
|
+
against the published contract rather than against a stub.
|
|
40
|
+
- Runtime behaviour, scenarios, fixtures, and the published contract are
|
|
41
|
+
unchanged; only the package's development dependencies and its test suite
|
|
42
|
+
moved.
|
|
43
|
+
- Keep `@whooshbang/contracts@1.0.0-rc.9` immutable.
|
|
44
|
+
|
|
45
|
+
## 1.0.0-rc.11
|
|
46
|
+
|
|
47
|
+
- Add the deterministic customer-endpoint lifecycle: create with a one-time
|
|
48
|
+
secret reveal, verify, bounded-overlap rotation with a rotation conflict,
|
|
49
|
+
pause, resume, disable, attempt inspection, and cross-environment refusal.
|
|
50
|
+
- Authenticate a locally generated C0-03 machine bearer against its registered
|
|
51
|
+
digest, so digest-only bootstrap, rotation, and revocation are provable end
|
|
52
|
+
to end without the service ever seeing the secret.
|
|
53
|
+
- Default the loopback CLI to the system clock so a caller can send an
|
|
54
|
+
interaction whose expiry is computed from real time; `--clock fixed` restores
|
|
55
|
+
the frozen clock, and the programmatic factory stays frozen.
|
|
56
|
+
- Keep `@whooshbang/contracts@1.0.0-rc.9` immutable.
|
|
57
|
+
|
|
58
|
+
## 1.0.0-rc.10
|
|
59
|
+
|
|
60
|
+
- Add deterministic per-message and per-interaction response inspection,
|
|
61
|
+
including bounded wait, wake, timeout, and machine-ownership behavior for
|
|
62
|
+
`@whooshbang/contracts@1.0.0-rc.9`.
|
|
63
|
+
- Keep polling side-effect free and `1.0.0-rc.9` immutable.
|
|
64
|
+
|
|
65
|
+
## 1.0.0-rc.9
|
|
66
|
+
|
|
67
|
+
- Reissue the deterministic mock and SDK compatibility boundary against
|
|
68
|
+
`@whooshbang/contracts@1.0.0-rc.8` without adding endpoint behavior.
|
|
69
|
+
- Keep `1.0.0-rc.8` immutable.
|
|
70
|
+
|
|
71
|
+
## 1.0.0-rc.8
|
|
72
|
+
|
|
73
|
+
- Reissue the deterministic mock against `@whooshbang/contracts@1.0.0-rc.7`
|
|
74
|
+
with explicit retained/redacted answered-interaction summaries.
|
|
75
|
+
- Keep `1.0.0-rc.7` immutable.
|
|
76
|
+
|
|
77
|
+
## 1.0.0-rc.7
|
|
78
|
+
|
|
79
|
+
- Reissue the deterministic mock with Hono 4.12.34 to address
|
|
80
|
+
`GHSA-8j4g-w8fx-2239`; contract behavior and fixtures are unchanged.
|
|
81
|
+
- Keep `1.0.0-rc.6` immutable.
|
|
82
|
+
|
|
83
|
+
## 1.0.0-rc.6
|
|
84
|
+
|
|
85
|
+
- Reissue the deterministic mock and SDK against
|
|
86
|
+
`@whooshbang/contracts@1.0.0-rc.6` after moving the generated production API
|
|
87
|
+
server origin to `https://api.whooshbang.com`.
|
|
88
|
+
- Keep `1.0.0-rc.5` immutable; runtime behavior and pinned V1 Problem Details
|
|
89
|
+
and schema identifiers are unchanged.
|
|
90
|
+
|
|
91
|
+
## 1.0.0-rc.5
|
|
92
|
+
|
|
93
|
+
- Reissue the deterministic mock against
|
|
94
|
+
`@whooshbang/contracts@1.0.0-rc.5`, including the restored paused binding
|
|
95
|
+
state and paused/revoked subscription fixtures.
|
|
96
|
+
- Keep `1.0.0-rc.4` immutable; no compatibility alias or migration is needed
|
|
97
|
+
for the unpublished, undeployed candidate.
|
|
98
|
+
|
|
99
|
+
## 1.0.0-rc.4
|
|
100
|
+
|
|
101
|
+
- Rename the unused pre-launch package, CLI, public exports, control header,
|
|
102
|
+
Problem Details origin, fixtures, and examples to the canonical WhooshBang
|
|
103
|
+
identity with no compatibility aliases.
|
|
104
|
+
|
|
105
|
+
## 1.0.0-rc.3
|
|
106
|
+
|
|
107
|
+
- Add executable API credential create/list/rotate/revoke behavior for the
|
|
108
|
+
approved N1-03 contract amendment, including one-time reveal, safe
|
|
109
|
+
inspection, last-used updates, bounded overlap, and terminal revocation.
|
|
110
|
+
- Reissue the mock and its deterministic scenarios under a new immutable
|
|
111
|
+
candidate identity; `1.0.0-rc.2` remains unchanged.
|
|
112
|
+
|
|
113
|
+
## 1.0.0-rc.2
|
|
114
|
+
|
|
115
|
+
- Add deterministic human-session fixtures and executable account/project
|
|
116
|
+
administration routes for the N1-02 contract.
|
|
117
|
+
- Cover atomic test/live/default-notifier bootstrap, account-scoped
|
|
118
|
+
idempotency, pagination, slug conflict, and non-enumerating cross-account
|
|
119
|
+
reads under a new immutable candidate identity.
|
|
120
|
+
|
|
121
|
+
## 1.0.0-rc.1
|
|
122
|
+
|
|
123
|
+
- Promote the exact reviewed Wave 0/C0 mock from `1.0.0-draft.1` without a
|
|
124
|
+
behavioral change.
|
|
125
|
+
- Retain the packaged C0SEC-002 cross-machine answer-origin regression and
|
|
126
|
+
bounded npm/pnpm consumer proofs at the release-candidate version.
|
|
127
|
+
- Keep the mock repository-local, deterministic, and free of live provider,
|
|
128
|
+
account, deployment, or production control dependencies.
|
|
129
|
+
|
|
130
|
+
## 1.0.0-draft.1
|
|
131
|
+
|
|
132
|
+
- Correct machine interaction-answer routing to enqueue an event only for the
|
|
133
|
+
exact machine client recorded when the message was created.
|
|
134
|
+
- Fail safely without rerouting when that originating client is absent,
|
|
135
|
+
revoked, or no longer matches the message binding.
|
|
136
|
+
- Add permanent cross-machine and unavailable-origin regression coverage for
|
|
137
|
+
C0SEC-002. The canonical WhooshBang contract and JavaScript SDK are
|
|
138
|
+
unchanged.
|
|
139
|
+
- Add the packaged `cross-machine-answer-origin` malicious scenario and execute
|
|
140
|
+
its same-binding, absent-origin, revoked-origin, and mismatched-origin cases
|
|
141
|
+
in both npm and pnpm tarball consumers.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 FlowXO LLC
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
# `@whooshbang/contract-mock`
|
|
2
|
+
|
|
3
|
+
Deterministic, in-memory WhooshBang V1 mock for local contract tests.
|
|
4
|
+
It implements the WhooshBang-owned release candidate without a cloud
|
|
5
|
+
account, network service, database, or production provider.
|
|
6
|
+
|
|
7
|
+
Run the current release candidate directly from the public npm registry:
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
npx @whooshbang/contract-mock@next --port 8787
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Programmatic and Worker-compatible use
|
|
14
|
+
|
|
15
|
+
Each factory call owns isolated state:
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
import {
|
|
19
|
+
CONTRACT_MOCK_FIXTURE_CREDENTIALS,
|
|
20
|
+
createWhooshBangContractMock,
|
|
21
|
+
} from "@whooshbang/contract-mock";
|
|
22
|
+
|
|
23
|
+
const mock = createWhooshBangContractMock({ scenario: "nominal" });
|
|
24
|
+
const response = await mock.fetch(
|
|
25
|
+
new Request("https://api.mock.whooshbang.test/v1/capabilities", {
|
|
26
|
+
headers: {
|
|
27
|
+
authorization:
|
|
28
|
+
`Bearer ${CONTRACT_MOCK_FIXTURE_CREDENTIALS.projectTest}`,
|
|
29
|
+
},
|
|
30
|
+
}),
|
|
31
|
+
);
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
The mock also executes the account-scoped administration contract. Use
|
|
35
|
+
`humanSession` (or `otherHumanSession` for isolation tests) with
|
|
36
|
+
`GET /v1/account`, `GET/POST /v1/projects`, and
|
|
37
|
+
`GET /v1/projects/{project_id}`. Project creation atomically returns synthetic
|
|
38
|
+
`test` and `live` environments and one `Default` notifier for each.
|
|
39
|
+
|
|
40
|
+
The same human session can execute the environment credential lifecycle:
|
|
41
|
+
`GET/POST /v1/projects/{project_id}/environments/{environment_id}/credentials`
|
|
42
|
+
and the nested `rotate` and `revoke` actions. The mock emits a deterministic
|
|
43
|
+
synthetic `wb_pc1` bearer only from create/rotate, stores it outside the
|
|
44
|
+
inspection snapshot, models bounded overlap, updates safe last-used metadata
|
|
45
|
+
on authentication, and returns `credential_invalid` after revocation. These
|
|
46
|
+
values are local fixtures, not production credential material.
|
|
47
|
+
|
|
48
|
+
Project credentials also execute the customer-endpoint lifecycle under
|
|
49
|
+
`/v1/projects/{project_id}/environments/{environment_id}/customer-endpoints`:
|
|
50
|
+
create with a one-time secret reveal, verify, bounded-overlap rotation, pause,
|
|
51
|
+
resume, disable, and attempt inspection. Environment-scoped paths need an
|
|
52
|
+
environment identifier the bearer does not carry, so
|
|
53
|
+
`CONTRACT_MOCK_FIXTURE_ENVIRONMENTS` publishes the synthetic project and
|
|
54
|
+
environment identifiers the fixture credentials authenticate against. A path
|
|
55
|
+
naming another project or environment is refused as `resource_not_found`.
|
|
56
|
+
|
|
57
|
+
A machine bearer the caller generated locally authenticates once its digest is
|
|
58
|
+
registered through `POST /v1/machine-clients/{id}/credentials`. The mock hashes
|
|
59
|
+
the presented bearer and compares, exactly as the service does, so digest-only
|
|
60
|
+
bootstrap, rotation, and revocation are provable without the mock ever holding
|
|
61
|
+
a readable machine secret.
|
|
62
|
+
|
|
63
|
+
The fetch-only entry point is structurally compatible with a Worker module and
|
|
64
|
+
does not expose the test control API:
|
|
65
|
+
|
|
66
|
+
```ts
|
|
67
|
+
import {
|
|
68
|
+
createWhooshBangContractMockWorker,
|
|
69
|
+
} from "@whooshbang/contract-mock/worker";
|
|
70
|
+
|
|
71
|
+
export default createWhooshBangContractMockWorker({
|
|
72
|
+
scenario: "nominal",
|
|
73
|
+
});
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
This package deliberately includes no Wrangler configuration or deployment
|
|
77
|
+
workflow. The Worker-compatible entry is for runtime-neutral contract tests,
|
|
78
|
+
not a hosted or production WhooshBang service.
|
|
79
|
+
|
|
80
|
+
## Loopback CLI
|
|
81
|
+
|
|
82
|
+
After building or installing the package:
|
|
83
|
+
|
|
84
|
+
```sh
|
|
85
|
+
whooshbang-contract-mock --port 8787 --scenario nominal
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Defaults are `--host 127.0.0.1`, `--port 0` (an ephemeral port),
|
|
89
|
+
`--scenario nominal`, `--clock system`, and no HTTP control surface. Supported
|
|
90
|
+
flags are `--host`, `--port`, `--scenario`, `--clock`, and `--control-token`.
|
|
91
|
+
Supplying a control token restricts the listener to `127.0.0.1`, `::1`, or
|
|
92
|
+
`localhost`; the token must contain 8-4096 visible ASCII characters.
|
|
93
|
+
|
|
94
|
+
The listener is a running service, so its clock advances with the host by
|
|
95
|
+
default: a frozen clock would reject every interaction whose expiry a caller
|
|
96
|
+
computes from the real time. Pass `--clock fixed` for byte-identical
|
|
97
|
+
timestamps. The programmatic factory stays frozen either way.
|
|
98
|
+
|
|
99
|
+
## Fixtures and scenarios
|
|
100
|
+
|
|
101
|
+
All credentials are synthetic local fixtures:
|
|
102
|
+
|
|
103
|
+
| Exported key | Bearer token | Identity |
|
|
104
|
+
| --- | --- | --- |
|
|
105
|
+
| `humanSession` | `human-session-token` | default account administrator |
|
|
106
|
+
| `otherHumanSession` | `human-other-session-token` | isolated account administrator |
|
|
107
|
+
| `projectTest` | `project-test-token` | default test project |
|
|
108
|
+
| `liveProject` | `project-live-token` | default live project |
|
|
109
|
+
| `projectA` | `project-a-token` | isolated test project A |
|
|
110
|
+
| `projectB` | `project-b-token` | isolated test project B |
|
|
111
|
+
| `readOnly` | `project-read-only-token` | read-only default project |
|
|
112
|
+
| `machineA` | `machine-a-token` | machine stream A |
|
|
113
|
+
| `machineB` | `machine-b-token` | machine stream B |
|
|
114
|
+
|
|
115
|
+
`CONTRACT_MOCK_SCENARIOS` is the typed scenario catalog. The same 25 names are
|
|
116
|
+
available in the exported JSON subpath
|
|
117
|
+
`@whooshbang/contract-mock/scenarios/v1/manifest.json`:
|
|
118
|
+
|
|
119
|
+
```text
|
|
120
|
+
nominal
|
|
121
|
+
repeated-idempotent-message
|
|
122
|
+
idempotency-conflict
|
|
123
|
+
unbound-subscriber
|
|
124
|
+
retryable-provider-failure
|
|
125
|
+
terminal-provider-rejection
|
|
126
|
+
ambiguous-provider-outcome
|
|
127
|
+
cancellation-before-send
|
|
128
|
+
cancellation-too-late
|
|
129
|
+
interaction-confirm
|
|
130
|
+
interaction-select
|
|
131
|
+
interaction-input
|
|
132
|
+
interaction-duplicate
|
|
133
|
+
interaction-stale
|
|
134
|
+
interaction-expired
|
|
135
|
+
interaction-unauthorized
|
|
136
|
+
machine-event-replay
|
|
137
|
+
machine-cursor-contiguous
|
|
138
|
+
machine-poison-quarantine
|
|
139
|
+
cross-machine-rejection
|
|
140
|
+
cross-machine-answer-origin
|
|
141
|
+
signed-webhook-success
|
|
142
|
+
signed-webhook-retry
|
|
143
|
+
signed-webhook-terminal
|
|
144
|
+
rate-limited
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
`cross-machine-answer-origin` is the executable C0SEC-002 fixture. Supply
|
|
148
|
+
synthetic same-binding machine credentials through the mock options, create an
|
|
149
|
+
interactive message as machine B, and submit its answer through
|
|
150
|
+
`mock.control.submitInteraction`. Only B may receive the resulting machine
|
|
151
|
+
event. If B's recorded client is absent, revoked, or no longer matches the
|
|
152
|
+
message binding, the interaction still resolves for the customer event while
|
|
153
|
+
the machine event fails closed instead of rerouting to machine A or another
|
|
154
|
+
same-binding peer.
|
|
155
|
+
|
|
156
|
+
## Explicit test control
|
|
157
|
+
|
|
158
|
+
The programmatic factory exposes `mock.control` directly. HTTP control routes
|
|
159
|
+
exist only in the loopback CLI when `--control-token` is supplied. Every request
|
|
160
|
+
must send that exact token in `WhooshBang-Contract-Mock-Token`.
|
|
161
|
+
|
|
162
|
+
| Route | Purpose |
|
|
163
|
+
| --- | --- |
|
|
164
|
+
| `GET /__contract-mock/snapshot` | inspect redacted deterministic state |
|
|
165
|
+
| `POST /__contract-mock/reset` | reset to a named scenario |
|
|
166
|
+
| `POST /__contract-mock/provider-outcomes` | replace provider outcomes |
|
|
167
|
+
| `POST /__contract-mock/webhook-responses` | replace receiver responses |
|
|
168
|
+
| `POST /__contract-mock/interactions` | submit a synthetic interaction |
|
|
169
|
+
| `POST /__contract-mock/run-pending` | run pending provider work |
|
|
170
|
+
|
|
171
|
+
Control routes are absent from OpenAPI and from the Worker-compatible entry.
|
|
172
|
+
Never expose the CLI control listener or fixture credentials as a production
|
|
173
|
+
service.
|
package/dist/app.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { WhooshBangContractMock, WhooshBangContractMockOptions } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Creates one isolated, in-memory WhooshBang contract mock.
|
|
4
|
+
*
|
|
5
|
+
* The returned programmatic control is test-only and has no HTTP route. The
|
|
6
|
+
* separate Node CLI is the only module that can mount the token guard.
|
|
7
|
+
*/
|
|
8
|
+
export declare function createWhooshBangContractMock(options?: WhooshBangContractMockOptions): WhooshBangContractMock;
|
package/dist/app.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { createWhooshBangContractMockCore } from "./core.js";
|
|
2
|
+
/**
|
|
3
|
+
* Creates one isolated, in-memory WhooshBang contract mock.
|
|
4
|
+
*
|
|
5
|
+
* The returned programmatic control is test-only and has no HTTP route. The
|
|
6
|
+
* separate Node CLI is the only module that can mount the token guard.
|
|
7
|
+
*/
|
|
8
|
+
export function createWhooshBangContractMock(options = {}) {
|
|
9
|
+
const mock = createWhooshBangContractMockCore(options);
|
|
10
|
+
return {
|
|
11
|
+
control: mock.control,
|
|
12
|
+
fetch: (request) => mock.fetch(request),
|
|
13
|
+
inspect: () => mock.inspect(),
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=app.js.map
|
package/dist/app.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app.js","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gCAAgC,EAAE,MAAM,WAAW,CAAC;AAO7D;;;;;GAKG;AACH,MAAM,UAAU,4BAA4B,CAC1C,UAAyC,EAAE;IAE3C,MAAM,IAAI,GAAG,gCAAgC,CAAC,OAAO,CAAC,CAAC;IACvD,OAAO;QACL,OAAO,EAAE,IAAI,CAAC,OAAO;QACrB,KAAK,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC;QACvC,OAAO,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE;KAC9B,CAAC;AACJ,CAAC"}
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import type { Server } from "node:http";
|
|
3
|
+
import type { ContractMockScenarioName } from "./types.js";
|
|
4
|
+
export interface ContractMockCliOptions {
|
|
5
|
+
/**
|
|
6
|
+
* `system` advances timestamps with the host clock; `fixed` freezes them.
|
|
7
|
+
*
|
|
8
|
+
* The loopback listener is a running service, so it defaults to `system`:
|
|
9
|
+
* a frozen clock rejects every interaction whose expiry a caller computes
|
|
10
|
+
* from the real time. The programmatic factory stays frozen for contract
|
|
11
|
+
* tests that need byte-identical output.
|
|
12
|
+
*/
|
|
13
|
+
readonly clock?: "fixed" | "system";
|
|
14
|
+
readonly controlToken?: string;
|
|
15
|
+
readonly host: string;
|
|
16
|
+
readonly port: number;
|
|
17
|
+
readonly scenario: ContractMockScenarioName;
|
|
18
|
+
}
|
|
19
|
+
export interface RunningContractMock {
|
|
20
|
+
readonly host: string;
|
|
21
|
+
readonly port: number;
|
|
22
|
+
readonly server: Server;
|
|
23
|
+
close(): Promise<void>;
|
|
24
|
+
}
|
|
25
|
+
export declare function parseContractMockCliArgs(args: readonly string[]): ContractMockCliOptions;
|
|
26
|
+
export declare function startContractMockCli(options: ContractMockCliOptions): Promise<RunningContractMock>;
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { realpathSync } from "node:fs";
|
|
3
|
+
import { createServer } from "node:http";
|
|
4
|
+
import { pathToFileURL } from "node:url";
|
|
5
|
+
import { validateProblem } from "@whooshbang/contracts";
|
|
6
|
+
import { mountContractMockControlSurface } from "./control-surface.js";
|
|
7
|
+
import { createWhooshBangContractMockCore } from "./core.js";
|
|
8
|
+
import { isContractMockScenarioName } from "./scenarios.js";
|
|
9
|
+
const MAX_ADAPTER_REQUEST_BYTES = 1024 * 1024;
|
|
10
|
+
const MAX_ADAPTER_DIAGNOSTIC_SEQUENCE = 999_999_999;
|
|
11
|
+
function isLoopbackHost(value) {
|
|
12
|
+
return (value === "127.0.0.1" ||
|
|
13
|
+
value === "::1" ||
|
|
14
|
+
value.toLowerCase() === "localhost");
|
|
15
|
+
}
|
|
16
|
+
function optionValue(args, index) {
|
|
17
|
+
const value = args[index + 1];
|
|
18
|
+
if (value === undefined || value.startsWith("--")) {
|
|
19
|
+
throw new RangeError(`Missing value for ${args[index] ?? "option"}.`);
|
|
20
|
+
}
|
|
21
|
+
return value;
|
|
22
|
+
}
|
|
23
|
+
export function parseContractMockCliArgs(args) {
|
|
24
|
+
let clock = "system";
|
|
25
|
+
let controlToken;
|
|
26
|
+
let host = "127.0.0.1";
|
|
27
|
+
let port = 0;
|
|
28
|
+
let scenario = "nominal";
|
|
29
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
30
|
+
const argument = args[index];
|
|
31
|
+
if (argument === "--port") {
|
|
32
|
+
const value = optionValue(args, index);
|
|
33
|
+
if (!/^\d+$/u.test(value)) {
|
|
34
|
+
throw new RangeError("--port must be an integer from 0 through 65535.");
|
|
35
|
+
}
|
|
36
|
+
port = Number(value);
|
|
37
|
+
if (port < 0 || port > 65_535) {
|
|
38
|
+
throw new RangeError("--port must be an integer from 0 through 65535.");
|
|
39
|
+
}
|
|
40
|
+
index += 1;
|
|
41
|
+
}
|
|
42
|
+
else if (argument === "--scenario") {
|
|
43
|
+
const value = optionValue(args, index);
|
|
44
|
+
if (!isContractMockScenarioName(value)) {
|
|
45
|
+
throw new RangeError("Unknown contract-mock scenario.");
|
|
46
|
+
}
|
|
47
|
+
scenario = value;
|
|
48
|
+
index += 1;
|
|
49
|
+
}
|
|
50
|
+
else if (argument === "--control-token") {
|
|
51
|
+
controlToken = optionValue(args, index);
|
|
52
|
+
index += 1;
|
|
53
|
+
}
|
|
54
|
+
else if (argument === "--host") {
|
|
55
|
+
host = optionValue(args, index);
|
|
56
|
+
index += 1;
|
|
57
|
+
}
|
|
58
|
+
else if (argument === "--clock") {
|
|
59
|
+
const value = optionValue(args, index);
|
|
60
|
+
if (value !== "fixed" && value !== "system") {
|
|
61
|
+
throw new RangeError("--clock must be system or fixed.");
|
|
62
|
+
}
|
|
63
|
+
clock = value;
|
|
64
|
+
index += 1;
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
throw new RangeError("Unknown contract-mock CLI option.");
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
if (controlToken !== undefined && !isLoopbackHost(host)) {
|
|
71
|
+
throw new RangeError("Control mode may only bind to an explicit loopback address.");
|
|
72
|
+
}
|
|
73
|
+
return {
|
|
74
|
+
clock,
|
|
75
|
+
...(controlToken === undefined ? {} : { controlToken }),
|
|
76
|
+
host,
|
|
77
|
+
port,
|
|
78
|
+
scenario,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
async function readNodeRequest(request) {
|
|
82
|
+
if (request.method === "GET" || request.method === "HEAD") {
|
|
83
|
+
return undefined;
|
|
84
|
+
}
|
|
85
|
+
const chunks = [];
|
|
86
|
+
let length = 0;
|
|
87
|
+
for await (const incomingChunk of request) {
|
|
88
|
+
const chunk = incomingChunk;
|
|
89
|
+
const bytes = typeof chunk === "string"
|
|
90
|
+
? new TextEncoder().encode(chunk)
|
|
91
|
+
: chunk instanceof Uint8Array
|
|
92
|
+
? Uint8Array.from(chunk)
|
|
93
|
+
: undefined;
|
|
94
|
+
if (bytes === undefined) {
|
|
95
|
+
throw new TypeError("The local adapter received an invalid body chunk.");
|
|
96
|
+
}
|
|
97
|
+
length += bytes.byteLength;
|
|
98
|
+
if (length > MAX_ADAPTER_REQUEST_BYTES) {
|
|
99
|
+
throw new RangeError("Request exceeded the local adapter limit.");
|
|
100
|
+
}
|
|
101
|
+
chunks.push(bytes);
|
|
102
|
+
}
|
|
103
|
+
const body = new Uint8Array(length);
|
|
104
|
+
let offset = 0;
|
|
105
|
+
for (const chunk of chunks) {
|
|
106
|
+
body.set(chunk, offset);
|
|
107
|
+
offset += chunk.byteLength;
|
|
108
|
+
}
|
|
109
|
+
return body;
|
|
110
|
+
}
|
|
111
|
+
function requestHeaders(request) {
|
|
112
|
+
const headers = new Headers();
|
|
113
|
+
for (let index = 0; index < request.rawHeaders.length; index += 2) {
|
|
114
|
+
const name = request.rawHeaders[index];
|
|
115
|
+
const value = request.rawHeaders[index + 1];
|
|
116
|
+
if (name !== undefined && value !== undefined) {
|
|
117
|
+
headers.append(name, value);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return headers;
|
|
121
|
+
}
|
|
122
|
+
function createAdapterDiagnosticIdGenerator() {
|
|
123
|
+
let sequence = 0;
|
|
124
|
+
return () => {
|
|
125
|
+
if (sequence >= MAX_ADAPTER_DIAGNOSTIC_SEQUENCE) {
|
|
126
|
+
throw new Error("The local adapter diagnostic sequence is exhausted.");
|
|
127
|
+
}
|
|
128
|
+
sequence += 1;
|
|
129
|
+
return `diag_adapter_${String(sequence).padStart(9, "0")}`;
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
function adapterProblem(diagnosticId) {
|
|
133
|
+
const value = {
|
|
134
|
+
code: "request_invalid",
|
|
135
|
+
detail: "The local mock request could not be processed.",
|
|
136
|
+
diagnostic_id: diagnosticId,
|
|
137
|
+
retryable: false,
|
|
138
|
+
status: 400,
|
|
139
|
+
title: "Request invalid",
|
|
140
|
+
type: "https://whooshbang.flowxo.com/problems/request_invalid",
|
|
141
|
+
};
|
|
142
|
+
if (!validateProblem(value)) {
|
|
143
|
+
throw new Error("The local adapter Problem is not contract-valid.");
|
|
144
|
+
}
|
|
145
|
+
return value;
|
|
146
|
+
}
|
|
147
|
+
function writeAdapterProblem(outgoing, diagnosticId) {
|
|
148
|
+
const problem = adapterProblem(diagnosticId);
|
|
149
|
+
outgoing.statusCode = problem.status;
|
|
150
|
+
outgoing.setHeader("content-type", "application/problem+json");
|
|
151
|
+
outgoing.setHeader("whooshbang-diagnostic-id", problem.diagnostic_id);
|
|
152
|
+
outgoing.end(JSON.stringify(problem));
|
|
153
|
+
}
|
|
154
|
+
export async function startContractMockCli(options) {
|
|
155
|
+
if (options.controlToken !== undefined && !isLoopbackHost(options.host)) {
|
|
156
|
+
throw new RangeError("Control mode may only bind to an explicit loopback address.");
|
|
157
|
+
}
|
|
158
|
+
const mock = createWhooshBangContractMockCore({
|
|
159
|
+
...(options.clock === "fixed"
|
|
160
|
+
? {}
|
|
161
|
+
: { clock: { now: () => new Date() } }),
|
|
162
|
+
scenario: options.scenario,
|
|
163
|
+
});
|
|
164
|
+
if (options.controlToken !== undefined) {
|
|
165
|
+
mountContractMockControlSurface(mock, options.controlToken);
|
|
166
|
+
}
|
|
167
|
+
const nextAdapterDiagnosticId = createAdapterDiagnosticIdGenerator();
|
|
168
|
+
const server = createServer((incoming, outgoing) => {
|
|
169
|
+
void (async () => {
|
|
170
|
+
try {
|
|
171
|
+
const body = await readNodeRequest(incoming);
|
|
172
|
+
const requestBody = body === undefined ? undefined : Uint8Array.from(body).buffer;
|
|
173
|
+
const request = new Request(new URL(incoming.url ?? "/", `http://${incoming.headers.host ?? `${options.host}:${options.port}`}`), {
|
|
174
|
+
...(requestBody === undefined ? {} : { body: requestBody }),
|
|
175
|
+
headers: requestHeaders(incoming),
|
|
176
|
+
method: incoming.method ?? "GET",
|
|
177
|
+
});
|
|
178
|
+
const response = await mock.fetch(request);
|
|
179
|
+
outgoing.statusCode = response.status;
|
|
180
|
+
response.headers.forEach((value, name) => {
|
|
181
|
+
outgoing.setHeader(name, value);
|
|
182
|
+
});
|
|
183
|
+
outgoing.end(new Uint8Array(await response.arrayBuffer()));
|
|
184
|
+
}
|
|
185
|
+
catch {
|
|
186
|
+
writeAdapterProblem(outgoing, nextAdapterDiagnosticId());
|
|
187
|
+
}
|
|
188
|
+
})();
|
|
189
|
+
});
|
|
190
|
+
await new Promise((resolve, reject) => {
|
|
191
|
+
server.once("error", reject);
|
|
192
|
+
server.listen(options.port, options.host, () => {
|
|
193
|
+
server.off("error", reject);
|
|
194
|
+
resolve();
|
|
195
|
+
});
|
|
196
|
+
});
|
|
197
|
+
const address = server.address();
|
|
198
|
+
return {
|
|
199
|
+
close: () => new Promise((resolve, reject) => {
|
|
200
|
+
server.close((error) => {
|
|
201
|
+
if (error === undefined) {
|
|
202
|
+
resolve();
|
|
203
|
+
}
|
|
204
|
+
else {
|
|
205
|
+
reject(error);
|
|
206
|
+
}
|
|
207
|
+
});
|
|
208
|
+
}),
|
|
209
|
+
host: options.host,
|
|
210
|
+
port: address.port,
|
|
211
|
+
server,
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
async function main() {
|
|
215
|
+
const options = parseContractMockCliArgs(process.argv.slice(2));
|
|
216
|
+
const running = await startContractMockCli(options);
|
|
217
|
+
process.stdout.write(`${JSON.stringify({
|
|
218
|
+
clock: options.clock ?? "system",
|
|
219
|
+
control_enabled: options.controlToken !== undefined,
|
|
220
|
+
event: "contract_mock_started",
|
|
221
|
+
host: running.host,
|
|
222
|
+
port: running.port,
|
|
223
|
+
scenario: options.scenario,
|
|
224
|
+
})}\n`);
|
|
225
|
+
const close = () => {
|
|
226
|
+
void running.close().finally(() => process.exit(0));
|
|
227
|
+
};
|
|
228
|
+
process.once("SIGINT", close);
|
|
229
|
+
process.once("SIGTERM", close);
|
|
230
|
+
}
|
|
231
|
+
function isMainModule() {
|
|
232
|
+
const entryPath = process.argv[1];
|
|
233
|
+
if (entryPath === undefined) {
|
|
234
|
+
return false;
|
|
235
|
+
}
|
|
236
|
+
try {
|
|
237
|
+
return import.meta.url === pathToFileURL(realpathSync(entryPath)).href;
|
|
238
|
+
}
|
|
239
|
+
catch {
|
|
240
|
+
return false;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
if (isMainModule()) {
|
|
244
|
+
void main().catch(() => {
|
|
245
|
+
process.stderr.write("The contract mock could not start safely.\n");
|
|
246
|
+
process.exitCode = 1;
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Hono } from "hono";
|
|
2
|
+
import type { ContractMockControl, ContractMockSnapshot } from "./types.js";
|
|
3
|
+
interface ControlSurfaceTarget {
|
|
4
|
+
readonly app: Hono;
|
|
5
|
+
readonly control: ContractMockControl;
|
|
6
|
+
inspect(): ContractMockSnapshot;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Mounts the CLI-only, test-only HTTP control surface. This module is not
|
|
10
|
+
* imported by either public package entry point or the Worker entry point.
|
|
11
|
+
*/
|
|
12
|
+
export declare function mountContractMockControlSurface(target: ControlSurfaceTarget, token: string): void;
|
|
13
|
+
export {};
|