@raybase/record-mount 0.0.2 → 0.3.3
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 +21 -0
- package/README.md +432 -2
- package/dist/body.d.ts +165 -0
- package/dist/body.d.ts.map +1 -0
- package/dist/body.js +538 -0
- package/dist/body.js.map +1 -0
- package/dist/client.d.ts +132 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +376 -0
- package/dist/client.js.map +1 -0
- package/dist/contract.d.ts +261 -0
- package/dist/contract.d.ts.map +1 -0
- package/dist/contract.js +83 -0
- package/dist/contract.js.map +1 -0
- package/dist/errors.d.ts +41 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +81 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -0
- package/dist/mount.d.ts +219 -0
- package/dist/mount.d.ts.map +1 -0
- package/dist/mount.js +372 -0
- package/dist/mount.js.map +1 -0
- package/dist/testing.d.ts +149 -0
- package/dist/testing.d.ts.map +1 -0
- package/dist/testing.js +764 -0
- package/dist/testing.js.map +1 -0
- package/package.json +34 -8
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A contract-conformant, in-memory record door — the dev-time half.
|
|
3
|
+
*
|
|
4
|
+
* It exists so that this package's own suite drives the real client
|
|
5
|
+
* against something that answers the wire contract's shapes, and so that a
|
|
6
|
+
* consuming app's tests can exercise its mount without a deployed Worker,
|
|
7
|
+
* a service binding, or a network. It is exported for exactly that.
|
|
8
|
+
*
|
|
9
|
+
* **What it is honest about.** It implements the contract's *shapes* — the
|
|
10
|
+
* result envelope, the closed taxonomy, the Row projection, `version()`,
|
|
11
|
+
* keyset paging, append idempotency by content hash, the ordering rule
|
|
12
|
+
* that `forbidden` outranks `not_found`. It is generic: no family, no id
|
|
13
|
+
* prefix and no lifecycle vocabulary is baked in, and every one of those
|
|
14
|
+
* is a hook with a documented generic default.
|
|
15
|
+
*
|
|
16
|
+
* **What it is not.** It is not the door. Bytes that this double accepts
|
|
17
|
+
* are not thereby proven acceptable to a deployed door — its frontmatter
|
|
18
|
+
* reader is this package's own, written to this package's own dialect, so
|
|
19
|
+
* a suite green against it is a builder-authored oracle for wire
|
|
20
|
+
* acceptance and nothing more. The real-door cross-check is a consumer-side
|
|
21
|
+
* act against the running door itself, and this double does not stand in
|
|
22
|
+
* for it. Its materialize path layout is its own invention (`family/id`),
|
|
23
|
+
* because the real one belongs to the consumer's substrate.
|
|
24
|
+
*
|
|
25
|
+
* ## Seam fidelity: why the default is a Proxy
|
|
26
|
+
*
|
|
27
|
+
* The double used to hand back a plain object that simply OMITTED
|
|
28
|
+
* `append`/`transition` for a read door. That is not how the production seam
|
|
29
|
+
* behaves, and the difference cost a real defect: a Cloudflare RPC
|
|
30
|
+
* service-binding stub answers EVERY property access with a callable, so
|
|
31
|
+
* every property-presence check the client made read `true` against a
|
|
32
|
+
* deployed read door while reading `false` against this fixture. The suite
|
|
33
|
+
* was green on a shape that does not exist in production — a self-authored
|
|
34
|
+
* oracle in its purest form.
|
|
35
|
+
*
|
|
36
|
+
* So by default the double presents as an RPC-faithful stub: a Proxy whose
|
|
37
|
+
* every property is a function, where calling one the underlying door does
|
|
38
|
+
* not carry rejects with a `TypeError` imitating the runtime's method-missing
|
|
39
|
+
* shape. Pass `rpc: false` for the plain object, which is the honest fixture
|
|
40
|
+
* for an in-process mount that really does hold a plain implementation.
|
|
41
|
+
*
|
|
42
|
+
* The imitation is an imitation, but its SHAPE is load-bearing: the client
|
|
43
|
+
* translates a `TypeError` only when its message carries the observed
|
|
44
|
+
* method-missing form — `does not implement` naming the verb — so the double
|
|
45
|
+
* reproduces that form. Do not pin the full string in a test as if it were
|
|
46
|
+
* workerd's contract; the wording is workerd's to change, and when it changes
|
|
47
|
+
* the client deliberately stops translating rather than guessing.
|
|
48
|
+
*/
|
|
49
|
+
import type { RecordDoorStub, RecordEnvelope, RecordErrorCode, RecordId } from "./contract.js";
|
|
50
|
+
export type RecordDoorDoubleOptions = {
|
|
51
|
+
/** What `version()` serves. Set it to something else to drive the
|
|
52
|
+
* client's fail-closed contract pin. */
|
|
53
|
+
contract?: string;
|
|
54
|
+
deployment?: string;
|
|
55
|
+
/** A read door has no `append`/`transition` at all. Default true. */
|
|
56
|
+
writable?: boolean;
|
|
57
|
+
/**
|
|
58
|
+
* Present as a Cloudflare RPC service-binding stub: a Proxy answering
|
|
59
|
+
* EVERY property access with a callable, where a verb this door does not
|
|
60
|
+
* carry rejects with a method-missing `TypeError` rather than being
|
|
61
|
+
* absent. **Default true** — this is what the production seam does, and a
|
|
62
|
+
* fixture that omits methods tests a shape no deployment has.
|
|
63
|
+
*
|
|
64
|
+
* Pass `false` for the plain object: the honest fixture for an in-process
|
|
65
|
+
* mount over a real implementation, where absence really is absence.
|
|
66
|
+
*/
|
|
67
|
+
rpc?: boolean;
|
|
68
|
+
/**
|
|
69
|
+
* What `version()` declares in its `writes` field.
|
|
70
|
+
*
|
|
71
|
+
* Defaults to whatever `writable` says, which is what a door built after
|
|
72
|
+
* the field existed does. Pass `"omit"` to simulate an OLDER door that
|
|
73
|
+
* predates the declaration — the case where the client must stay
|
|
74
|
+
* `"unknown"` and translate whatever the runtime says instead.
|
|
75
|
+
*/
|
|
76
|
+
declaredWrites?: boolean | "omit";
|
|
77
|
+
/**
|
|
78
|
+
* Answer every verb but `version()` with `invalid_binding`, as a door
|
|
79
|
+
* whose caller's props name no usable actor or namespace does.
|
|
80
|
+
* `version()` is the deliberate carve-out: the client's pin calls it
|
|
81
|
+
* before the contract is known, so it must answer on a props-less
|
|
82
|
+
* binding.
|
|
83
|
+
*/
|
|
84
|
+
invalidBinding?: {
|
|
85
|
+
missing?: string[];
|
|
86
|
+
actor?: string;
|
|
87
|
+
served?: string[];
|
|
88
|
+
};
|
|
89
|
+
/** A handle built without a serializer refuses `transition` structurally. */
|
|
90
|
+
serializer?: boolean;
|
|
91
|
+
/**
|
|
92
|
+
* Family from an id — the real door's prefix-to-family map.
|
|
93
|
+
*
|
|
94
|
+
* Supply it and the double enforces that a body's `type` field equals the
|
|
95
|
+
* family its id's prefix names, exactly as the door does. Omit it and the
|
|
96
|
+
* double takes the family from the body's own `type`, falling back to the
|
|
97
|
+
* id's prefix.
|
|
98
|
+
*
|
|
99
|
+
* The default is deliberately NOT "prefix equals family": in a real
|
|
100
|
+
* corpus a prefix and a family name are different strings (`dec` names
|
|
101
|
+
* `decision`), so a default that demanded equality would refuse every
|
|
102
|
+
* realistic body and teach consumers to work around their own fixture.
|
|
103
|
+
*/
|
|
104
|
+
familyOfId?: (id: string) => string | null;
|
|
105
|
+
/** The id shape. Default: `<prefix>-<yyyy-mm-dd>-<slug>`. */
|
|
106
|
+
idPattern?: RegExp;
|
|
107
|
+
/** The lifecycle frontmatter key per family, or null for a family that
|
|
108
|
+
* is final at filing. Default: `"status"` for every family. */
|
|
109
|
+
lifecycleField?: (family: string) => string | null;
|
|
110
|
+
/** Whether an edge is legal. Default: every edge between non-empty
|
|
111
|
+
* values is legal. A note (`expected === next`) never asks. */
|
|
112
|
+
isLegalTransition?: (family: string, from: string, to: string) => boolean;
|
|
113
|
+
/** The write grant. Default: every write is granted. */
|
|
114
|
+
canWrite?: (input: {
|
|
115
|
+
verb: "append" | "transition";
|
|
116
|
+
family: string;
|
|
117
|
+
id: RecordId;
|
|
118
|
+
}) => boolean;
|
|
119
|
+
/** How a Row's headline derives. Default: the body's first `# ` H1,
|
|
120
|
+
* else its first non-blank prose line, else the id's slug. */
|
|
121
|
+
headline?: (input: {
|
|
122
|
+
envelope: RecordEnvelope;
|
|
123
|
+
body: string;
|
|
124
|
+
}) => string;
|
|
125
|
+
/** The refs edge. Default: the `refs` list field plus a scalar `ref`. */
|
|
126
|
+
refsOf?: (fields: Record<string, unknown>) => string[];
|
|
127
|
+
/** Entries per `materialize` page. Default 500, as the contract's. */
|
|
128
|
+
materializePageEntries?: number;
|
|
129
|
+
};
|
|
130
|
+
export type RecordDoorDouble = RecordDoorStub & {
|
|
131
|
+
/**
|
|
132
|
+
* Make the next call of one verb refuse with a code the double cannot
|
|
133
|
+
* reach on its own — `unavailable` when storage fails, `corrupt` when
|
|
134
|
+
* an integrity violation is discovered. One shot, consumed on use.
|
|
135
|
+
*/
|
|
136
|
+
failNext(verb: keyof RecordDoorStub, error: {
|
|
137
|
+
code: RecordErrorCode;
|
|
138
|
+
detail?: Record<string, unknown>;
|
|
139
|
+
message?: string;
|
|
140
|
+
}): void;
|
|
141
|
+
/** Every id the double holds, in insertion order. */
|
|
142
|
+
ids(): RecordId[];
|
|
143
|
+
};
|
|
144
|
+
/** Build the door double. */
|
|
145
|
+
export declare function createRecordDoorDouble(options?: RecordDoorDoubleOptions): RecordDoorDouble;
|
|
146
|
+
/** An `env`-shaped object carrying the double under a binding name — what
|
|
147
|
+
* `openRecordDoor({ env, binding })` reads. */
|
|
148
|
+
export declare function recordDoorEnv<Name extends string>(binding: Name, door: RecordDoorStub): Record<Name, RecordDoorStub>;
|
|
149
|
+
//# sourceMappingURL=testing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"testing.d.ts","sourceRoot":"","sources":["../src/testing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AASH,OAAO,KAAK,EAGV,cAAc,EACd,cAAc,EACd,eAAe,EAEf,QAAQ,EAMT,MAAM,eAAe,CAAC;AAYvB,MAAM,MAAM,uBAAuB,GAAG;IACpC;6CACyC;IACzC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,qEAAqE;IACrE,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;;;;;;;OASG;IACH,GAAG,CAAC,EAAE,OAAO,CAAC;IACd;;;;;;;OAOG;IACH,cAAc,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IAClC;;;;;;OAMG;IACH,cAAc,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IAC3E,6EAA6E;IAC7E,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;;;;;;;;;;OAYG;IACH,UAAU,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;IAC3C,6DAA6D;IAC7D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;oEACgE;IAChE,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;IACnD;oEACgE;IAChE,iBAAiB,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC;IAC1E,wDAAwD;IACxD,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE;QACjB,IAAI,EAAE,QAAQ,GAAG,YAAY,CAAC;QAC9B,MAAM,EAAE,MAAM,CAAC;QACf,EAAE,EAAE,QAAQ,CAAC;KACd,KAAK,OAAO,CAAC;IACd;mEAC+D;IAC/D,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE;QAAE,QAAQ,EAAE,cAAc,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,KAAK,MAAM,CAAC;IACzE,yEAAyE;IACzE,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,MAAM,EAAE,CAAC;IACvD,sEAAsE;IACtE,sBAAsB,CAAC,EAAE,MAAM,CAAC;CACjC,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG,cAAc,GAAG;IAC9C;;;;OAIG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,cAAc,EAAE,KAAK,EAAE;QAAE,IAAI,EAAE,eAAe,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IACjI,qDAAqD;IACrD,GAAG,IAAI,QAAQ,EAAE,CAAC;CACnB,CAAC;AAQF,6BAA6B;AAC7B,wBAAgB,sBAAsB,CACpC,OAAO,GAAE,uBAA4B,GACpC,gBAAgB,CAgXlB;AAuED;gDACgD;AAChD,wBAAgB,aAAa,CAAC,IAAI,SAAS,MAAM,EAC/C,OAAO,EAAE,IAAI,EACb,IAAI,EAAE,cAAc,GACnB,MAAM,CAAC,IAAI,EAAE,cAAc,CAAC,CAE9B"}
|