bonescript-compiler 0.6.0 → 0.6.1

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/dist/cli.js CHANGED
@@ -94,7 +94,7 @@ function main() {
94
94
  }
95
95
  }
96
96
  function showHelp() {
97
- console.log("BoneScript compiler v0.6.0");
97
+ console.log("BoneScript compiler v0.6.1");
98
98
  console.log("");
99
99
  console.log("Usage:");
100
100
  console.log(" bonec compile <file> [--target <target>] Compile to runnable project");
@@ -415,44 +415,44 @@ function emitNakamaReadme(system) {
415
415
  }
416
416
  }
417
417
  const realtimeMods = system.modules.filter(m => m.kind === "realtime_service");
418
- return `# ${system.name} — Nakama Backend
419
-
420
- Generated by BoneScript compiler (target: nakama). Source hash: ${system.source_hash}
421
-
422
- ## Quick Start
423
-
424
- \`\`\`bash
425
- # Install deps
426
- npm install
427
-
428
- # Build TypeScript -> JS
429
- npm run build
430
-
431
- # Start Nakama with this module
432
- docker run --rm -v $(pwd)/build:/nakama/data/modules \\
433
- heroiclabs/nakama:latest
434
- \`\`\`
435
-
436
- ## RPC Endpoints
437
-
438
- Call these from any Nakama client SDK:
439
-
440
- ${rpcs.join("\n")}
441
-
442
- ## Match Handlers
443
-
418
+ return `# ${system.name} — Nakama Backend
419
+
420
+ Generated by BoneScript compiler (target: nakama). Source hash: ${system.source_hash}
421
+
422
+ ## Quick Start
423
+
424
+ \`\`\`bash
425
+ # Install deps
426
+ npm install
427
+
428
+ # Build TypeScript -> JS
429
+ npm run build
430
+
431
+ # Start Nakama with this module
432
+ docker run --rm -v $(pwd)/build:/nakama/data/modules \\
433
+ heroiclabs/nakama:latest
434
+ \`\`\`
435
+
436
+ ## RPC Endpoints
437
+
438
+ Call these from any Nakama client SDK:
439
+
440
+ ${rpcs.join("\n")}
441
+
442
+ ## Match Handlers
443
+
444
444
  ${realtimeMods.length > 0
445
445
  ? realtimeMods.map(m => `- \`${toSnakeCase(m.name)}\` (tick rate: ${m.config["tick_rate"] ?? 10}/s)`).join("\n")
446
- : "_No realtime channels declared._"}
447
-
448
- ## Storage Collections
449
-
450
- ${system.modules.flatMap(m => m.models).map(m => `- \`${toSnakeCase(m.name)}s\``).join("\n") || "_No entities declared._"}
451
-
452
- ## Auth
453
-
454
- All authenticated RPCs require a valid Nakama session token.
455
- Use any Nakama client SDK to authenticate before calling RPCs.
446
+ : "_No realtime channels declared._"}
447
+
448
+ ## Storage Collections
449
+
450
+ ${system.modules.flatMap(m => m.models).map(m => `- \`${toSnakeCase(m.name)}s\``).join("\n") || "_No entities declared._"}
451
+
452
+ ## Auth
453
+
454
+ All authenticated RPCs require a valid Nakama session token.
455
+ Use any Nakama client SDK to authenticate before calling RPCs.
456
456
  `;
457
457
  }
458
458
  class NakamaEmitter {
@@ -29,7 +29,32 @@ function emitNotifyService(system) {
29
29
  lines.push(` body: string;`);
30
30
  lines.push(`}`);
31
31
  lines.push(``);
32
+ // HTML-escape helper. Used to render arbitrary event payload data inside an
33
+ // HTML email body without enabling HTML/JS injection in clients that render
34
+ // it. Subject lines are also escaped for consistency.
35
+ lines.push(`function escapeHtml(s: string): string {`);
36
+ lines.push(` return s`);
37
+ lines.push(` .replace(/&/g, "&amp;")`);
38
+ lines.push(` .replace(/</g, "&lt;")`);
39
+ lines.push(` .replace(/>/g, "&gt;")`);
40
+ lines.push(` .replace(/"/g, "&quot;")`);
41
+ lines.push(` .replace(/'/g, "&#39;");`);
42
+ lines.push(`}`);
43
+ lines.push(``);
44
+ // Conservative email validation. Rejects empty input, multiple addresses,
45
+ // and CRLF that would let a caller inject extra headers into the request body
46
+ // sent to Resend / SendGrid.
47
+ lines.push(`const __EMAIL_RE = /^[A-Za-z0-9._%+\\-]+@[A-Za-z0-9.\\-]+\\.[A-Za-z]{2,}$/;`);
48
+ lines.push(`function isValidEmail(addr: string): boolean {`);
49
+ lines.push(` if (!addr || addr.length > 254) return false;`);
50
+ lines.push(` if (/[\\r\\n]/.test(addr)) return false;`);
51
+ lines.push(` return __EMAIL_RE.test(addr);`);
52
+ lines.push(`}`);
53
+ lines.push(``);
32
54
  lines.push(`async function sendEmail(msg: NotifyMessage): Promise<void> {`);
55
+ lines.push(` if (!isValidEmail(msg.to)) {`);
56
+ lines.push(" throw new Error(`Invalid recipient address: ${msg.to.slice(0, 64)}`);");
57
+ lines.push(` }`);
33
58
  lines.push(` if (PROVIDER === "log") {`);
34
59
  lines.push(` console.log(\`[notify] \${msg.subject} → \${msg.to}\`);`);
35
60
  lines.push(` return;`);
@@ -54,15 +79,18 @@ function emitNotifyService(system) {
54
79
  lines.push(` }`);
55
80
  lines.push(`}`);
56
81
  lines.push(``);
57
- // Per-event handlers
82
+ // Per-event handlers — payload is JSON-stringified and HTML-escaped before
83
+ // being placed inside <pre> so payload values like "<script>..." can't break
84
+ // out of the body.
58
85
  for (const event of system.events) {
59
86
  const eventName = toPascalCase(event.name);
60
87
  lines.push(`// Handler for ${eventName}`);
61
88
  lines.push(`export async function notify${eventName}(event: SystemEvent, recipientEmail: string): Promise<void> {`);
89
+ lines.push(` const __payload = escapeHtml(JSON.stringify(event.payload, null, 2));`);
62
90
  lines.push(` await sendEmail({`);
63
91
  lines.push(` to: recipientEmail,`);
64
92
  lines.push(` subject: "${eventName} notification",`);
65
- lines.push(` body: \`<p>Event <strong>${eventName}</strong> occurred.</p><pre>\${JSON.stringify(event.payload, null, 2)}</pre>\`,`);
93
+ lines.push(" body: `<p>Event <strong>${escapeHtml(\"" + eventName + "\")}</strong> occurred.</p><pre>${__payload}</pre>`,");
66
94
  lines.push(` });`);
67
95
  lines.push(`}`);
68
96
  lines.push(``);
@@ -1 +1 @@
1
- {"version":3,"file":"emit_notify.js","sourceRoot":"","sources":["../src/emit_notify.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"emit_notify.js","sourceRoot":"","sources":["../src/emit_notify.ts"],"names":[],"mappings":"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"}
@@ -140,86 +140,86 @@ function emitDbClient(system) {
140
140
  }
141
141
  exports.emitDbClient = emitDbClient;
142
142
  function emitAuthMiddleware(system) {
143
- return `// Generated by BoneScript compiler. DO NOT EDIT.
144
- import { Request, Response, NextFunction } from "express";
145
- import jwt from "jsonwebtoken";
146
- import { v4 as uuid } from "uuid";
147
-
148
- // JWT_SECRET must be set in production. The server will refuse to start without it
149
- // when NODE_ENV is "production" to prevent accidental use of a weak fallback.
150
- const JWT_SECRET = (() => {
151
- const secret = process.env.JWT_SECRET;
152
- if (!secret) {
153
- if (process.env.NODE_ENV === "production") {
154
- console.error("[FATAL] JWT_SECRET environment variable is not set. Refusing to start in production.");
155
- process.exit(1);
156
- }
157
- console.warn("[WARN] JWT_SECRET is not set. Using insecure default — do not use in production.");
158
- return "bonescript-dev-secret-do-not-use-in-production";
159
- }
160
- if (secret.length < 32) {
161
- console.warn("[WARN] JWT_SECRET is shorter than 32 characters. Use a longer secret in production.");
162
- }
163
- return secret;
164
- })();
165
-
166
- export interface AuthContext {
167
- authenticated: boolean;
168
- actor_id: string | null;
169
- trace_id: string;
170
- }
171
-
172
- // Trace IDs are server-generated. We accept a client-supplied X-Trace-Id only
173
- // if it parses as a UUID, so callers can correlate their own logs without
174
- // being able to forge correlation IDs in audit / event records.
175
- const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
176
- function resolveTraceId(req: Request): string {
177
- const supplied = req.headers["x-trace-id"];
178
- if (typeof supplied === "string" && UUID_RE.test(supplied)) return supplied;
179
- return uuid();
180
- }
181
-
182
- export function authMiddleware(req: Request, res: Response, next: NextFunction): void {
183
- const header = req.headers.authorization;
184
- const traceId = resolveTraceId(req);
185
- if (!header || !header.startsWith("Bearer ")) {
186
- (req as any).auth = { authenticated: false, actor_id: null, trace_id: traceId };
187
- next();
188
- return;
189
- }
190
- try {
191
- const token = header.slice(7);
192
- // Pin algorithms to HS256 and require an expiration. Without pinning,
193
- // jsonwebtoken would accept any algorithm including RS/HS confusion attacks.
194
- // maxAge is a safety net even if exp is set far in the future.
195
- const decoded = jwt.verify(token, JWT_SECRET, {
196
- algorithms: ["HS256"],
197
- maxAge: process.env.JWT_MAX_AGE || "1h",
198
- }) as { sub?: unknown };
199
- if (typeof decoded.sub !== "string" || decoded.sub.length === 0) {
200
- (req as any).auth = { authenticated: false, actor_id: null, trace_id: traceId };
201
- next();
202
- return;
203
- }
204
- (req as any).auth = {
205
- authenticated: true,
206
- actor_id: decoded.sub,
207
- trace_id: traceId,
208
- };
209
- } catch {
210
- (req as any).auth = { authenticated: false, actor_id: null, trace_id: traceId };
211
- }
212
- next();
213
- }
214
-
215
- export function requireAuth(req: Request, res: Response, next: NextFunction): void {
216
- const auth: AuthContext = (req as any).auth;
217
- if (!auth || !auth.authenticated) {
218
- res.status(401).json({ error: { code: "UNAUTHORIZED", message: "Authentication required" } });
219
- return;
220
- }
221
- next();
222
- }
143
+ return `// Generated by BoneScript compiler. DO NOT EDIT.
144
+ import { Request, Response, NextFunction } from "express";
145
+ import jwt from "jsonwebtoken";
146
+ import { v4 as uuid } from "uuid";
147
+
148
+ // JWT_SECRET must be set in production. The server will refuse to start without it
149
+ // when NODE_ENV is "production" to prevent accidental use of a weak fallback.
150
+ const JWT_SECRET = (() => {
151
+ const secret = process.env.JWT_SECRET;
152
+ if (!secret) {
153
+ if (process.env.NODE_ENV === "production") {
154
+ console.error("[FATAL] JWT_SECRET environment variable is not set. Refusing to start in production.");
155
+ process.exit(1);
156
+ }
157
+ console.warn("[WARN] JWT_SECRET is not set. Using insecure default — do not use in production.");
158
+ return "bonescript-dev-secret-do-not-use-in-production";
159
+ }
160
+ if (secret.length < 32) {
161
+ console.warn("[WARN] JWT_SECRET is shorter than 32 characters. Use a longer secret in production.");
162
+ }
163
+ return secret;
164
+ })();
165
+
166
+ export interface AuthContext {
167
+ authenticated: boolean;
168
+ actor_id: string | null;
169
+ trace_id: string;
170
+ }
171
+
172
+ // Trace IDs are server-generated. We accept a client-supplied X-Trace-Id only
173
+ // if it parses as a UUID, so callers can correlate their own logs without
174
+ // being able to forge correlation IDs in audit / event records.
175
+ const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
176
+ function resolveTraceId(req: Request): string {
177
+ const supplied = req.headers["x-trace-id"];
178
+ if (typeof supplied === "string" && UUID_RE.test(supplied)) return supplied;
179
+ return uuid();
180
+ }
181
+
182
+ export function authMiddleware(req: Request, res: Response, next: NextFunction): void {
183
+ const header = req.headers.authorization;
184
+ const traceId = resolveTraceId(req);
185
+ if (!header || !header.startsWith("Bearer ")) {
186
+ (req as any).auth = { authenticated: false, actor_id: null, trace_id: traceId };
187
+ next();
188
+ return;
189
+ }
190
+ try {
191
+ const token = header.slice(7);
192
+ // Pin algorithms to HS256 and require an expiration. Without pinning,
193
+ // jsonwebtoken would accept any algorithm including RS/HS confusion attacks.
194
+ // maxAge is a safety net even if exp is set far in the future.
195
+ const decoded = jwt.verify(token, JWT_SECRET, {
196
+ algorithms: ["HS256"],
197
+ maxAge: process.env.JWT_MAX_AGE || "1h",
198
+ }) as { sub?: unknown };
199
+ if (typeof decoded.sub !== "string" || decoded.sub.length === 0) {
200
+ (req as any).auth = { authenticated: false, actor_id: null, trace_id: traceId };
201
+ next();
202
+ return;
203
+ }
204
+ (req as any).auth = {
205
+ authenticated: true,
206
+ actor_id: decoded.sub,
207
+ trace_id: traceId,
208
+ };
209
+ } catch {
210
+ (req as any).auth = { authenticated: false, actor_id: null, trace_id: traceId };
211
+ }
212
+ next();
213
+ }
214
+
215
+ export function requireAuth(req: Request, res: Response, next: NextFunction): void {
216
+ const auth: AuthContext = (req as any).auth;
217
+ if (!auth || !auth.authenticated) {
218
+ res.status(401).json({ error: { code: "UNAUTHORIZED", message: "Authentication required" } });
219
+ return;
220
+ }
221
+ next();
222
+ }
223
223
  `;
224
224
  }
225
225
  exports.emitAuthMiddleware = emitAuthMiddleware;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bonescript-compiler",
3
- "version": "0.6.0",
3
+ "version": "0.6.1",
4
4
  "description": "BoneScript compiler — compile .bone system descriptions into complete, runnable Node.js backends",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
package/src/cli.ts CHANGED
@@ -75,7 +75,7 @@ function main() {
75
75
  }
76
76
 
77
77
  function showHelp() {
78
- console.log("BoneScript compiler v0.6.0");
78
+ console.log("BoneScript compiler v0.6.1");
79
79
  console.log("");
80
80
  console.log("Usage:");
81
81
  console.log(" bonec compile <file> [--target <target>] Compile to runnable project");