pombus 0.0.0-stage → 0.1.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.
@@ -0,0 +1,117 @@
1
+ // Test doubles — a fake core (a FetchLike that records every request and returns programmed replies)
2
+ // and a captured-request shape the tests assert against. Not a *.test.ts, so the test runner does not
3
+ // execute it as a suite. All fixtures are written from scratch (AGENTS.md §9): invented ids, no real
4
+ // data.
5
+ export class FakeCore {
6
+ requests = [];
7
+ routes = [];
8
+ /** Register a route. Routes are matched in order; the first match wins. */
9
+ on(method, match, reply) {
10
+ this.routes.push({ method, match, reply });
11
+ return this;
12
+ }
13
+ /** A FetchLike bound to this fake. Records the request, then returns the first matching route's
14
+ * reply, or a 404 when nothing matches (so an unexpected call fails closed, like the real core). */
15
+ fetch = async (rawUrl, init) => {
16
+ const url = new URL(rawUrl);
17
+ const headers = lowerHeaders(init.headers);
18
+ let body;
19
+ if (typeof init.body === "string" && init.body.length > 0) {
20
+ try {
21
+ body = JSON.parse(init.body);
22
+ }
23
+ catch {
24
+ body = init.body;
25
+ }
26
+ }
27
+ const captured = { method: init.method ?? "GET", url: rawUrl, headers, body };
28
+ this.requests.push(captured);
29
+ const route = this.routes.find((r) => r.method === captured.method && r.match(url));
30
+ const reply = route
31
+ ? typeof route.reply === "function"
32
+ ? route.reply(captured, url)
33
+ : route.reply
34
+ : { status: 404, json: { code: "not_found" } };
35
+ return makeResponse(reply);
36
+ };
37
+ }
38
+ function lowerHeaders(h) {
39
+ const out = {};
40
+ if (!h)
41
+ return out;
42
+ if (h instanceof Headers) {
43
+ h.forEach((v, k) => (out[k.toLowerCase()] = v));
44
+ }
45
+ else if (Array.isArray(h)) {
46
+ for (const pair of h) {
47
+ const k = pair[0];
48
+ const v = pair[1];
49
+ if (k !== undefined && v !== undefined)
50
+ out[k.toLowerCase()] = v;
51
+ }
52
+ }
53
+ else {
54
+ for (const [k, v] of Object.entries(h))
55
+ out[k.toLowerCase()] = String(v);
56
+ }
57
+ return out;
58
+ }
59
+ function makeResponse(reply) {
60
+ const status = reply.status ?? 200;
61
+ const hasBody = reply.json !== undefined;
62
+ // A 204/205 MUST have a null body (undici throws on any body, even ""), matching the real core's
63
+ // no-content replies (e.g. a DELETE).
64
+ const nullBodyStatus = status === 204 || status === 205 || status === 304;
65
+ const body = hasBody ? JSON.stringify(reply.json) : nullBodyStatus ? null : "";
66
+ return new Response(body, {
67
+ status,
68
+ headers: hasBody ? { "content-type": "application/json" } : {},
69
+ });
70
+ }
71
+ /** An /auth/me reply for an inbox-scoped key (single implied inbox). */
72
+ export function authMeInbox(inboxId) {
73
+ return {
74
+ json: {
75
+ scope_type: "inbox",
76
+ scope_id: inboxId,
77
+ organization_id: "org_test",
78
+ pod_id: "pod_test",
79
+ inbox_id: inboxId,
80
+ api_key_id: "key_test",
81
+ permissions: null,
82
+ },
83
+ };
84
+ }
85
+ /** An /auth/me reply for a pod-scoped key (reaches many inboxes). */
86
+ export function authMePod() {
87
+ return {
88
+ json: {
89
+ scope_type: "pod",
90
+ scope_id: "pod_test",
91
+ organization_id: "org_test",
92
+ pod_id: "pod_test",
93
+ inbox_id: null,
94
+ api_key_id: "key_test",
95
+ permissions: null,
96
+ },
97
+ };
98
+ }
99
+ /** A POST /v0/inboxes reply (the shape the core returns: inbox_id + email). Invented ids only (§9). */
100
+ export function createdInbox(inboxId, email) {
101
+ return { json: { inbox_id: inboxId, email } };
102
+ }
103
+ /** An /auth/me reply for a SCOPED pod key — a real permissions object drives the catalog gate. Pass
104
+ * the permissions the human granted the key; everything else uses invented ids (§9). */
105
+ export function authMeScoped(permissions, overrides = {}) {
106
+ return {
107
+ json: {
108
+ scope_type: overrides.scope_type ?? "pod",
109
+ scope_id: "pod_test",
110
+ organization_id: "org_test",
111
+ pod_id: overrides.pod_id === undefined ? "pod_test" : overrides.pod_id,
112
+ inbox_id: overrides.inbox_id ?? null,
113
+ api_key_id: "key_test",
114
+ permissions,
115
+ },
116
+ };
117
+ }