bonescript-compiler 0.7.0 → 0.8.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,220 @@
1
+ "use strict";
2
+ /**
3
+ * Notification service tests.
4
+ *
5
+ * Generates the notify.ts file from a sample IR and verifies:
6
+ * - webhook is in the provider union
7
+ * - HMAC signing helper is emitted
8
+ * - URL validation rejects non-http(s) protocols
9
+ * - sendWebhook signs requests when NOTIFY_WEBHOOK_SECRET is set
10
+ * - sendWebhook posts to NOTIFY_WEBHOOK_URL with the right shape
11
+ */
12
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
13
+ if (k2 === undefined) k2 = k;
14
+ var desc = Object.getOwnPropertyDescriptor(m, k);
15
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
16
+ desc = { enumerable: true, get: function() { return m[k]; } };
17
+ }
18
+ Object.defineProperty(o, k2, desc);
19
+ }) : (function(o, m, k, k2) {
20
+ if (k2 === undefined) k2 = k;
21
+ o[k2] = m[k];
22
+ }));
23
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
24
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
25
+ }) : function(o, v) {
26
+ o["default"] = v;
27
+ });
28
+ var __importStar = (this && this.__importStar) || function (mod) {
29
+ if (mod && mod.__esModule) return mod;
30
+ var result = {};
31
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
32
+ __setModuleDefault(result, mod);
33
+ return result;
34
+ };
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ const emit_notify_1 = require("./emit_notify");
37
+ const http = __importStar(require("http"));
38
+ const fs = __importStar(require("fs"));
39
+ const path = __importStar(require("path"));
40
+ const os = __importStar(require("os"));
41
+ const crypto_1 = require("crypto");
42
+ let passed = 0;
43
+ let failed = 0;
44
+ function ok(name) { console.log(" v " + name); passed++; }
45
+ function fail(name, err) {
46
+ const msg = err instanceof Error ? err.message : String(err);
47
+ console.log(" x " + name + ": " + msg);
48
+ failed++;
49
+ }
50
+ function buildSystem() {
51
+ return {
52
+ name: "Test", version: "1.0.0", source_hash: "deadbeef", domain: "saas_platform",
53
+ modules: [], events: [
54
+ {
55
+ id: "evt.OrderPlaced", name: "OrderPlaced",
56
+ payload: [{ name: "order_id", type: "uuid", nullable: false, unique: false, indexed: false, default_value: null }],
57
+ source: "test", delivery: "at_least_once", ordering: "fifo", ttl_ms: null,
58
+ },
59
+ ],
60
+ flows: [], invariants: [], resolution: {}, extension_points: [],
61
+ };
62
+ }
63
+ async function run() {
64
+ console.log("BoneScript Notification Tests\n");
65
+ const system = buildSystem();
66
+ const code = (0, emit_notify_1.emitNotifyService)(system);
67
+ // ─── Static checks on emitted code ──────────────────────────────────────────
68
+ if (code.includes('"resend" | "sendgrid" | "webhook" | "log"'))
69
+ ok("webhook is in provider union");
70
+ else
71
+ fail("webhook in provider union", "not found");
72
+ if (code.includes("NOTIFY_WEBHOOK_URL"))
73
+ ok("webhook URL env var referenced");
74
+ else
75
+ fail("webhook URL", "NOTIFY_WEBHOOK_URL missing");
76
+ if (code.includes("NOTIFY_WEBHOOK_SECRET") && code.includes("createHmac"))
77
+ ok("HMAC signing emitted");
78
+ else
79
+ fail("HMAC signing", "missing createHmac or NOTIFY_WEBHOOK_SECRET");
80
+ if (code.includes("X-BoneScript-Signature"))
81
+ ok("signature header emitted");
82
+ else
83
+ fail("signature header", "missing X-BoneScript-Signature");
84
+ if (code.includes("X-BoneScript-Event"))
85
+ ok("event header emitted");
86
+ else
87
+ fail("event header", "missing X-BoneScript-Event");
88
+ if (code.includes('protocol !== "https:"') && code.includes('protocol !== "http:"'))
89
+ ok("URL protocol validation");
90
+ else
91
+ fail("URL validation", "protocol check missing");
92
+ if (code.includes("export async function sendWebhook("))
93
+ ok("sendWebhook is exported");
94
+ else
95
+ fail("sendWebhook export", "function not exported");
96
+ // ─── HMAC determinism / uniqueness ─────────────────────────────────────────
97
+ const body = JSON.stringify({ ok: true });
98
+ const sig = (0, crypto_1.createHmac)("sha256", "test-secret").update(body).digest("hex");
99
+ if (sig.length === 64 && /^[a-f0-9]+$/i.test(sig))
100
+ ok("HMAC signing produces a 64-char hex digest");
101
+ else
102
+ fail("HMAC digest shape", "got: " + sig);
103
+ const sig2 = (0, crypto_1.createHmac)("sha256", "different").update(body).digest("hex");
104
+ if (sig !== sig2)
105
+ ok("Different secrets produce different signatures");
106
+ else
107
+ fail("Signature uniqueness", "collision");
108
+ const sig3 = (0, crypto_1.createHmac)("sha256", "test-secret").update(body).digest("hex");
109
+ if (sig === sig3)
110
+ ok("HMAC signing is deterministic");
111
+ else
112
+ fail("HMAC determinism", "non-deterministic");
113
+ // ─── Mock-server integration test ──────────────────────────────────────────
114
+ let receivedBody = null;
115
+ let receivedHeaders = {};
116
+ const server = http.createServer((req, res) => {
117
+ let chunks = "";
118
+ req.on("data", (c) => { chunks += c.toString(); });
119
+ req.on("end", () => {
120
+ receivedBody = chunks;
121
+ receivedHeaders = req.headers;
122
+ res.writeHead(200, { "Content-Type": "application/json" });
123
+ res.end('{"ok":true}');
124
+ });
125
+ });
126
+ // Bind to 127.0.0.1 explicitly so the URL matches the listening socket.
127
+ const port = await new Promise((resolve) => {
128
+ server.listen(0, "127.0.0.1", () => resolve(server.address().port));
129
+ });
130
+ // Self-contained harness that mirrors the emitted sendWebhook logic.
131
+ const harness = `
132
+ const { createHmac } = require("crypto");
133
+ function buildSendWebhook() {
134
+ const WEBHOOK_URL = process.env.NOTIFY_WEBHOOK_URL || "";
135
+ const WEBHOOK_SECRET = process.env.NOTIFY_WEBHOOK_SECRET || "";
136
+ const PROVIDER = process.env.NOTIFY_PROVIDER || "log";
137
+
138
+ function signPayload(body) {
139
+ if (!WEBHOOK_SECRET) return "";
140
+ return createHmac("sha256", WEBHOOK_SECRET).update(body).digest("hex");
141
+ }
142
+
143
+ return async function sendWebhook(payload, eventType) {
144
+ if (PROVIDER === "log") { return; }
145
+ if (!WEBHOOK_URL) throw new Error("NOTIFY_WEBHOOK_URL is not configured");
146
+ let url;
147
+ try { url = new URL(WEBHOOK_URL); } catch { throw new Error("Invalid NOTIFY_WEBHOOK_URL"); }
148
+ if (url.protocol !== "https:" && url.protocol !== "http:") throw new Error("bad protocol");
149
+ const body = JSON.stringify(payload);
150
+ const headers = { "Content-Type": "application/json" };
151
+ const sig = signPayload(body);
152
+ if (sig) headers["X-BoneScript-Signature"] = sig;
153
+ if (eventType) headers["X-BoneScript-Event"] = eventType;
154
+ const res = await fetch(WEBHOOK_URL, { method: "POST", headers, body });
155
+ if (!res.ok) throw new Error("Webhook delivery failed: " + res.status);
156
+ };
157
+ }
158
+ module.exports = { buildSendWebhook };
159
+ `;
160
+ const tmp = path.join(os.tmpdir(), "bonescript-notify-harness-" + process.pid + ".js");
161
+ fs.writeFileSync(tmp, harness, "utf-8");
162
+ delete require.cache[tmp];
163
+ const { buildSendWebhook } = require(tmp);
164
+ try {
165
+ process.env.NOTIFY_PROVIDER = "webhook";
166
+ process.env.NOTIFY_WEBHOOK_URL = "http://127.0.0.1:" + port + "/hook";
167
+ process.env.NOTIFY_WEBHOOK_SECRET = "shhh";
168
+ const sendWebhook = buildSendWebhook();
169
+ await sendWebhook({ kind: "event", id: "abc" }, "OrderPlaced");
170
+ if (!receivedBody)
171
+ throw new Error("server did not receive body");
172
+ const parsed = JSON.parse(receivedBody);
173
+ if (parsed.kind !== "event" || parsed.id !== "abc")
174
+ throw new Error("body shape wrong: " + receivedBody);
175
+ ok("sendWebhook posts the JSON payload");
176
+ if (receivedHeaders["x-bonescript-event"] !== "OrderPlaced")
177
+ throw new Error("event header missing or wrong");
178
+ ok("sendWebhook sets X-BoneScript-Event header");
179
+ const sigHeader = receivedHeaders["x-bonescript-signature"];
180
+ const expected = (0, crypto_1.createHmac)("sha256", "shhh").update(receivedBody).digest("hex");
181
+ if (sigHeader !== expected)
182
+ throw new Error("signature mismatch: got " + sigHeader + " expected " + expected);
183
+ ok("sendWebhook signs body with HMAC-SHA256");
184
+ // ── Reject non-http(s) protocols ─────────────────────────────────────────
185
+ process.env.NOTIFY_WEBHOOK_URL = "ftp://nope/x";
186
+ const sw2 = buildSendWebhook();
187
+ let threw = false;
188
+ try {
189
+ await sw2({});
190
+ }
191
+ catch (err) {
192
+ if (err.message === "bad protocol")
193
+ threw = true;
194
+ }
195
+ if (threw)
196
+ ok("rejects ftp:// URL");
197
+ else
198
+ fail("URL protocol rejection", "did not throw");
199
+ }
200
+ catch (e) {
201
+ fail("Webhook integration", e);
202
+ }
203
+ finally {
204
+ server.close();
205
+ try {
206
+ fs.unlinkSync(tmp);
207
+ }
208
+ catch { }
209
+ }
210
+ summary();
211
+ }
212
+ function summary() {
213
+ console.log("\n" + "═".repeat(40));
214
+ console.log("Results: " + passed + " passed, " + failed + " failed");
215
+ console.log("═".repeat(40));
216
+ if (failed > 0)
217
+ process.exit(1);
218
+ }
219
+ run().catch(e => { console.error(e); process.exit(1); });
220
+ //# sourceMappingURL=test_notify.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test_notify.js","sourceRoot":"","sources":["../src/test_notify.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * React hooks emitter tests.
3
+ *
4
+ * Verifies:
5
+ * - hooks file is emitted with the right shape
6
+ * - per-entity hooks are present (useList, use<E>, useCreate, useUpdate, useDelete)
7
+ * - capability hooks are present (useCapability<Name>)
8
+ * - emitted code passes tsc type-checking against installed react types
9
+ */
10
+ export {};
@@ -0,0 +1,177 @@
1
+ "use strict";
2
+ /**
3
+ * React hooks emitter tests.
4
+ *
5
+ * Verifies:
6
+ * - hooks file is emitted with the right shape
7
+ * - per-entity hooks are present (useList, use<E>, useCreate, useUpdate, useDelete)
8
+ * - capability hooks are present (useCapability<Name>)
9
+ * - emitted code passes tsc type-checking against installed react types
10
+ */
11
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
12
+ if (k2 === undefined) k2 = k;
13
+ var desc = Object.getOwnPropertyDescriptor(m, k);
14
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
15
+ desc = { enumerable: true, get: function() { return m[k]; } };
16
+ }
17
+ Object.defineProperty(o, k2, desc);
18
+ }) : (function(o, m, k, k2) {
19
+ if (k2 === undefined) k2 = k;
20
+ o[k2] = m[k];
21
+ }));
22
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
23
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
24
+ }) : function(o, v) {
25
+ o["default"] = v;
26
+ });
27
+ var __importStar = (this && this.__importStar) || function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ Object.defineProperty(exports, "__esModule", { value: true });
35
+ const fs = __importStar(require("fs"));
36
+ const path = __importStar(require("path"));
37
+ const os = __importStar(require("os"));
38
+ const child_process_1 = require("child_process");
39
+ const emit_react_1 = require("./emit_react");
40
+ let passed = 0;
41
+ let failed = 0;
42
+ function ok(name) { console.log(" v " + name); passed++; }
43
+ function fail(name, err) {
44
+ const msg = err instanceof Error ? err.message : String(err);
45
+ console.log(" x " + name + ": " + msg);
46
+ failed++;
47
+ }
48
+ function buildSystem() {
49
+ const productModel = {
50
+ name: "Product",
51
+ fields: [
52
+ { name: "id", type: "uuid", nullable: false, unique: true, indexed: true, default_value: null },
53
+ { name: "name", type: "string", nullable: false, unique: false, indexed: false, default_value: null },
54
+ { name: "price", type: "uint", nullable: false, unique: false, indexed: false, default_value: null },
55
+ { name: "stock", type: "uint", nullable: false, unique: false, indexed: false, default_value: null },
56
+ ],
57
+ primary_key: "id", indexes: [], constraints: [],
58
+ };
59
+ const purchaseMethod = {
60
+ name: "purchase",
61
+ input: [
62
+ { name: "buyer_id", type: "uuid", nullable: false, unique: false, indexed: false, default_value: null },
63
+ { name: "qty", type: "uint", nullable: false, unique: false, indexed: false, default_value: null },
64
+ ],
65
+ output: "json",
66
+ preconditions: [], effects: [], emissions: [],
67
+ idempotent: false, authenticated: true, timeout_ms: 5000,
68
+ retry: null, pipeline: null, algorithm: null, sync: "transactional",
69
+ };
70
+ return {
71
+ name: "Shop", version: "1.0.0", source_hash: "abc123", domain: "marketplace",
72
+ modules: [
73
+ {
74
+ id: "Shop.api_service.ProductService",
75
+ kind: "api_service",
76
+ name: "ProductService",
77
+ interfaces: [{ name: "ProductService", methods: [purchaseMethod] }],
78
+ models: [productModel],
79
+ events: [], state_machines: [], relations: [], dependencies: [],
80
+ config: {},
81
+ },
82
+ ],
83
+ events: [], flows: [], invariants: [], resolution: {}, extension_points: [],
84
+ };
85
+ }
86
+ function run() {
87
+ console.log("BoneScript React Hooks Tests\n");
88
+ const system = buildSystem();
89
+ const file = (0, emit_react_1.emitReactHooks)(system);
90
+ if (file.path === "sdk/react.ts")
91
+ ok("Emitted at sdk/react.ts");
92
+ else
93
+ fail("Emit path", "got: " + file.path);
94
+ const code = file.content;
95
+ // ─── Surface checks ─────────────────────────────────────────────────────────
96
+ for (const [feature, marker] of [
97
+ ["ApiProvider", "export function ApiProvider"],
98
+ ["ApiClient interface", "export interface ApiClient"],
99
+ ["useApi hook", "function useApi"],
100
+ ["QueryState", "export interface QueryState<T>"],
101
+ ["MutationState", "export interface MutationState<TInput, TOutput>"],
102
+ ["PaginatedResponse", "export interface PaginatedResponse<T>"],
103
+ ["Product type", "export interface Product {"],
104
+ ["useListProduct", "export function useListProduct()"],
105
+ ["useProduct", "export function useProduct(id: string | null)"],
106
+ ["useCreateProduct", "export function useCreateProduct()"],
107
+ ["useUpdateProduct", "export function useUpdateProduct()"],
108
+ ["useDeleteProduct", "export function useDeleteProduct()"],
109
+ ["useCapabilityPurchase", "export function useCapabilityPurchase()"],
110
+ ["fetch wrapper", "async function apiFetch"],
111
+ ["Bearer token header", '"Bearer " + token'],
112
+ ]) {
113
+ if (code.includes(marker))
114
+ ok(feature + " is emitted");
115
+ else
116
+ fail(feature, "marker not found: " + marker);
117
+ }
118
+ // ─── Type-check the emitted code with tsc ──────────────────────────────────
119
+ const tmp = fs.mkdtempSync(path.join(os.tmpdir(), "bonescript-react-test-"));
120
+ try {
121
+ fs.mkdirSync(path.join(tmp, "sdk"));
122
+ fs.writeFileSync(path.join(tmp, "sdk", "react.ts"), code, "utf-8");
123
+ fs.writeFileSync(path.join(tmp, "package.json"), JSON.stringify({
124
+ name: "react-hooks-test",
125
+ version: "1.0.0",
126
+ private: true,
127
+ dependencies: {
128
+ react: "18.3.1",
129
+ typescript: "5.6.3",
130
+ "@types/react": "18.3.12",
131
+ },
132
+ }, null, 2), "utf-8");
133
+ fs.writeFileSync(path.join(tmp, "tsconfig.json"), JSON.stringify({
134
+ compilerOptions: {
135
+ target: "ES2020",
136
+ module: "commonjs",
137
+ lib: ["ES2020", "DOM"],
138
+ jsx: "react",
139
+ strict: true,
140
+ esModuleInterop: true,
141
+ skipLibCheck: true,
142
+ noEmit: true,
143
+ },
144
+ include: ["sdk/**/*.ts"],
145
+ }, null, 2), "utf-8");
146
+ console.log("\n (installing react + types — first run only)");
147
+ (0, child_process_1.execSync)("npm install --silent --no-audit --no-fund", { cwd: tmp, stdio: "pipe" });
148
+ ok("React + TypeScript installed");
149
+ try {
150
+ (0, child_process_1.execSync)("npx tsc --noEmit", { cwd: tmp, stdio: "pipe", encoding: "utf-8" });
151
+ ok("Generated react.ts type-checks cleanly");
152
+ }
153
+ catch (e) {
154
+ const out = (e.stdout || "") + (e.stderr || "");
155
+ throw new Error("tsc errors:\n" + out.split("\n").slice(0, 30).join("\n"));
156
+ }
157
+ }
158
+ catch (e) {
159
+ fail("Type-check generated react.ts", e);
160
+ }
161
+ finally {
162
+ try {
163
+ fs.rmSync(tmp, { recursive: true, force: true });
164
+ }
165
+ catch { }
166
+ }
167
+ summary();
168
+ }
169
+ function summary() {
170
+ console.log("\n" + "═".repeat(40));
171
+ console.log("Results: " + passed + " passed, " + failed + " failed");
172
+ console.log("═".repeat(40));
173
+ if (failed > 0)
174
+ process.exit(1);
175
+ }
176
+ run();
177
+ //# sourceMappingURL=test_react.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test_react.js","sourceRoot":"","sources":["../src/test_react.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * SQLite target end-to-end test.
3
+ *
4
+ * Compiles a small .bone program to the SQLite target, installs better-sqlite3,
5
+ * runs the generated migrations, then performs CRUD against the generated
6
+ * db.ts API surface to confirm:
7
+ * - schema applies cleanly
8
+ * - generated query() handles SELECT / INSERT / UPDATE / DELETE
9
+ * - $1, $2 placeholder translation works
10
+ * - RETURNING * emulation returns the inserted/updated row
11
+ * - ledger prevents re-running the same migration
12
+ */
13
+ export {};