bonescript-compiler 0.5.3 → 0.5.5

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.
Files changed (201) hide show
  1. package/LICENSE +21 -21
  2. package/dist/algorithm_catalog.js +166 -166
  3. package/dist/cli.d.ts +1 -2
  4. package/dist/cli.js +617 -75
  5. package/dist/cli.js.map +1 -1
  6. package/dist/emit_capability.d.ts +0 -13
  7. package/dist/emit_capability.js +134 -296
  8. package/dist/emit_capability.js.map +1 -1
  9. package/dist/emit_composition.js +3 -37
  10. package/dist/emit_composition.js.map +1 -1
  11. package/dist/emit_deploy.js +167 -165
  12. package/dist/emit_deploy.js.map +1 -1
  13. package/dist/emit_events.d.ts +0 -1
  14. package/dist/emit_events.js +275 -325
  15. package/dist/emit_events.js.map +1 -1
  16. package/dist/emit_extras.js +5 -3
  17. package/dist/emit_extras.js.map +1 -1
  18. package/dist/emit_full.js +112 -272
  19. package/dist/emit_full.js.map +1 -1
  20. package/dist/emit_maintenance.js +249 -249
  21. package/dist/emit_nakama.d.ts +23 -0
  22. package/dist/emit_nakama.js +510 -0
  23. package/dist/emit_nakama.js.map +1 -0
  24. package/dist/emit_runtime.d.ts +11 -17
  25. package/dist/emit_runtime.js +688 -29
  26. package/dist/emit_runtime.js.map +1 -1
  27. package/dist/emit_sourcemap.js +66 -66
  28. package/dist/emit_tests.js +12 -47
  29. package/dist/emit_tests.js.map +1 -1
  30. package/dist/emit_websocket.js +3 -0
  31. package/dist/emit_websocket.js.map +1 -1
  32. package/dist/emitter.js +49 -94
  33. package/dist/emitter.js.map +1 -1
  34. package/dist/extension_manager.d.ts +2 -2
  35. package/dist/extension_manager.js +20 -9
  36. package/dist/extension_manager.js.map +1 -1
  37. package/dist/index.d.ts +2 -0
  38. package/dist/index.js +3 -1
  39. package/dist/index.js.map +1 -1
  40. package/dist/ir.d.ts +0 -4
  41. package/dist/lowering.d.ts +14 -5
  42. package/dist/lowering.js +417 -66
  43. package/dist/lowering.js.map +1 -1
  44. package/dist/module_loader.d.ts +2 -2
  45. package/dist/module_loader.js +23 -20
  46. package/dist/module_loader.js.map +1 -1
  47. package/dist/optimizer.js +3 -6
  48. package/dist/optimizer.js.map +1 -1
  49. package/dist/scaffold.d.ts +2 -2
  50. package/dist/scaffold.js +319 -315
  51. package/dist/scaffold.js.map +1 -1
  52. package/dist/solver.js +1 -1
  53. package/dist/solver.js.map +1 -1
  54. package/dist/source_map.js.map +1 -0
  55. package/dist/test.js.map +1 -0
  56. package/dist/test_typechecker.d.ts +5 -0
  57. package/dist/test_typechecker.js +126 -0
  58. package/dist/test_typechecker.js.map +1 -0
  59. package/dist/typechecker.d.ts +0 -7
  60. package/dist/typechecker.js +16 -103
  61. package/dist/typechecker.js.map +1 -1
  62. package/dist/verifier.d.ts +1 -5
  63. package/dist/verifier.js +38 -142
  64. package/dist/verifier.js.map +1 -1
  65. package/package.json +53 -62
  66. package/src/algorithm_catalog.ts +345 -345
  67. package/src/ast.d.ts +244 -0
  68. package/src/ast.ts +334 -334
  69. package/src/cli.ts +704 -98
  70. package/src/emit_batch.ts +140 -140
  71. package/src/emit_capability.ts +436 -613
  72. package/src/emit_composition.ts +196 -229
  73. package/src/emit_deploy.ts +190 -187
  74. package/src/emit_events.ts +307 -362
  75. package/src/emit_extras.ts +240 -237
  76. package/src/emit_full.ts +309 -472
  77. package/src/emit_maintenance.ts +459 -459
  78. package/src/emit_nakama.ts +576 -0
  79. package/src/emit_runtime.ts +730 -17
  80. package/src/emit_sourcemap.ts +140 -140
  81. package/src/emit_tests.ts +205 -243
  82. package/src/emit_websocket.ts +229 -226
  83. package/src/emitter.ts +578 -626
  84. package/src/extension_manager.ts +187 -177
  85. package/src/formatter.ts +297 -297
  86. package/src/index.ts +90 -88
  87. package/src/ir.ts +215 -216
  88. package/src/lexer.d.ts +195 -0
  89. package/src/lexer.ts +630 -630
  90. package/src/lowering.ts +556 -168
  91. package/src/module_loader.ts +114 -112
  92. package/src/optimizer.ts +196 -199
  93. package/src/parse_decls.d.ts +13 -0
  94. package/src/parse_decls.ts +409 -409
  95. package/src/parse_decls2.d.ts +13 -0
  96. package/src/parse_decls2.ts +244 -244
  97. package/src/parse_expr.d.ts +7 -0
  98. package/src/parse_expr.ts +197 -197
  99. package/src/parse_types.d.ts +6 -0
  100. package/src/parse_types.ts +54 -54
  101. package/src/parser.d.ts +10 -0
  102. package/src/parser.ts +1 -1
  103. package/src/parser_base.d.ts +19 -0
  104. package/src/parser_base.ts +57 -57
  105. package/src/parser_recovery.ts +153 -153
  106. package/src/scaffold.ts +375 -371
  107. package/src/solver.ts +330 -330
  108. package/src/typechecker.d.ts +52 -0
  109. package/src/typechecker.ts +591 -700
  110. package/src/types.d.ts +38 -0
  111. package/src/types.ts +122 -122
  112. package/src/verifier.ts +49 -154
  113. package/README.md +0 -382
  114. package/dist/commands/check.d.ts +0 -5
  115. package/dist/commands/check.js +0 -34
  116. package/dist/commands/check.js.map +0 -1
  117. package/dist/commands/compile.d.ts +0 -5
  118. package/dist/commands/compile.js +0 -215
  119. package/dist/commands/compile.js.map +0 -1
  120. package/dist/commands/debug.d.ts +0 -5
  121. package/dist/commands/debug.js +0 -59
  122. package/dist/commands/debug.js.map +0 -1
  123. package/dist/commands/diff.d.ts +0 -5
  124. package/dist/commands/diff.js +0 -123
  125. package/dist/commands/diff.js.map +0 -1
  126. package/dist/commands/fmt.d.ts +0 -5
  127. package/dist/commands/fmt.js +0 -49
  128. package/dist/commands/fmt.js.map +0 -1
  129. package/dist/commands/init.d.ts +0 -5
  130. package/dist/commands/init.js +0 -96
  131. package/dist/commands/init.js.map +0 -1
  132. package/dist/commands/ir.d.ts +0 -5
  133. package/dist/commands/ir.js +0 -27
  134. package/dist/commands/ir.js.map +0 -1
  135. package/dist/commands/lex.d.ts +0 -5
  136. package/dist/commands/lex.js +0 -21
  137. package/dist/commands/lex.js.map +0 -1
  138. package/dist/commands/parse.d.ts +0 -5
  139. package/dist/commands/parse.js +0 -30
  140. package/dist/commands/parse.js.map +0 -1
  141. package/dist/commands/test.d.ts +0 -5
  142. package/dist/commands/test.js +0 -61
  143. package/dist/commands/test.js.map +0 -1
  144. package/dist/commands/verify_determinism.d.ts +0 -5
  145. package/dist/commands/verify_determinism.js +0 -64
  146. package/dist/commands/verify_determinism.js.map +0 -1
  147. package/dist/commands/watch.d.ts +0 -5
  148. package/dist/commands/watch.js +0 -50
  149. package/dist/commands/watch.js.map +0 -1
  150. package/dist/emit_auth.d.ts +0 -18
  151. package/dist/emit_auth.js +0 -507
  152. package/dist/emit_auth.js.map +0 -1
  153. package/dist/emit_database.d.ts +0 -7
  154. package/dist/emit_database.js +0 -72
  155. package/dist/emit_database.js.map +0 -1
  156. package/dist/emit_index.d.ts +0 -6
  157. package/dist/emit_index.js +0 -202
  158. package/dist/emit_index.js.map +0 -1
  159. package/dist/emit_models.d.ts +0 -12
  160. package/dist/emit_models.js +0 -171
  161. package/dist/emit_models.js.map +0 -1
  162. package/dist/emit_openapi.d.ts +0 -9
  163. package/dist/emit_openapi.js +0 -306
  164. package/dist/emit_openapi.js.map +0 -1
  165. package/dist/emit_package.d.ts +0 -7
  166. package/dist/emit_package.js +0 -68
  167. package/dist/emit_package.js.map +0 -1
  168. package/dist/emit_router.d.ts +0 -12
  169. package/dist/emit_router.js +0 -389
  170. package/dist/emit_router.js.map +0 -1
  171. package/dist/lowering_channels.d.ts +0 -11
  172. package/dist/lowering_channels.js +0 -103
  173. package/dist/lowering_channels.js.map +0 -1
  174. package/dist/lowering_entities.d.ts +0 -11
  175. package/dist/lowering_entities.js +0 -232
  176. package/dist/lowering_entities.js.map +0 -1
  177. package/dist/lowering_helpers.d.ts +0 -13
  178. package/dist/lowering_helpers.js +0 -76
  179. package/dist/lowering_helpers.js.map +0 -1
  180. package/src/commands/check.ts +0 -33
  181. package/src/commands/compile.ts +0 -191
  182. package/src/commands/debug.ts +0 -33
  183. package/src/commands/diff.ts +0 -105
  184. package/src/commands/fmt.ts +0 -22
  185. package/src/commands/init.ts +0 -72
  186. package/src/commands/ir.ts +0 -23
  187. package/src/commands/lex.ts +0 -17
  188. package/src/commands/parse.ts +0 -24
  189. package/src/commands/test.ts +0 -36
  190. package/src/commands/verify_determinism.ts +0 -66
  191. package/src/commands/watch.ts +0 -25
  192. package/src/emit_auth.ts +0 -513
  193. package/src/emit_database.ts +0 -72
  194. package/src/emit_index.ts +0 -210
  195. package/src/emit_models.ts +0 -176
  196. package/src/emit_openapi.ts +0 -315
  197. package/src/emit_package.ts +0 -66
  198. package/src/emit_router.ts +0 -408
  199. package/src/lowering_channels.ts +0 -108
  200. package/src/lowering_entities.ts +0 -258
  201. package/src/lowering_helpers.ts +0 -75
@@ -1,50 +0,0 @@
1
- "use strict";
2
- /**
3
- * bonec watch <file>
4
- * Recompile on every save.
5
- */
6
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
7
- if (k2 === undefined) k2 = k;
8
- var desc = Object.getOwnPropertyDescriptor(m, k);
9
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
10
- desc = { enumerable: true, get: function() { return m[k]; } };
11
- }
12
- Object.defineProperty(o, k2, desc);
13
- }) : (function(o, m, k, k2) {
14
- if (k2 === undefined) k2 = k;
15
- o[k2] = m[k];
16
- }));
17
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
18
- Object.defineProperty(o, "default", { enumerable: true, value: v });
19
- }) : function(o, v) {
20
- o["default"] = v;
21
- });
22
- var __importStar = (this && this.__importStar) || function (mod) {
23
- if (mod && mod.__esModule) return mod;
24
- var result = {};
25
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
26
- __setModuleDefault(result, mod);
27
- return result;
28
- };
29
- Object.defineProperty(exports, "__esModule", { value: true });
30
- exports.runWatch = void 0;
31
- const fs = __importStar(require("fs"));
32
- const compile_1 = require("./compile");
33
- function runWatch(_source, resolved) {
34
- console.log(`Watching ${resolved}...`);
35
- const compile = () => {
36
- fs.promises.readFile(resolved, "utf-8")
37
- .then(fresh => {
38
- console.log(`\n[${new Date().toLocaleTimeString()}] Compiling...`);
39
- return (0, compile_1.runCompile)(fresh, resolved);
40
- })
41
- .catch((e) => console.error(`x ${e.message}`));
42
- };
43
- compile();
44
- fs.watchFile(resolved, { interval: 500 }, (curr, prev) => {
45
- if (curr.mtimeMs !== prev.mtimeMs)
46
- compile();
47
- });
48
- }
49
- exports.runWatch = runWatch;
50
- //# sourceMappingURL=watch.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"watch.js","sourceRoot":"","sources":["../../src/commands/watch.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;;;;;;;;;;;;;;;;;;;;;;;;AAEH,uCAAyB;AACzB,uCAAuC;AAEvC,SAAgB,QAAQ,CAAC,OAAe,EAAE,QAAgB;IACxD,OAAO,CAAC,GAAG,CAAC,YAAY,QAAQ,KAAK,CAAC,CAAC;IAEvC,MAAM,OAAO,GAAG,GAAG,EAAE;QACnB,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;aACpC,IAAI,CAAC,KAAK,CAAC,EAAE;YACZ,OAAO,CAAC,GAAG,CAAC,MAAM,IAAI,IAAI,EAAE,CAAC,kBAAkB,EAAE,gBAAgB,CAAC,CAAC;YACnE,OAAO,IAAA,oBAAU,EAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;QACrC,CAAC,CAAC;aACD,KAAK,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;IACxD,CAAC,CAAC;IAEF,OAAO,EAAE,CAAC;IACV,EAAE,CAAC,SAAS,CAAC,QAAQ,EAAE,EAAE,QAAQ,EAAE,GAAG,EAAE,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE;QACvD,IAAI,IAAI,CAAC,OAAO,KAAK,IAAI,CAAC,OAAO;YAAE,OAAO,EAAE,CAAC;IAC/C,CAAC,CAAC,CAAC;AACL,CAAC;AAhBD,4BAgBC"}
@@ -1,18 +0,0 @@
1
- /**
2
- * BoneScript Auth Emitter
3
- * Generates auth.ts — JWT, OAuth2, or API key middleware depending on the
4
- * resolved auth_method in the system's constraint resolution map.
5
- *
6
- * Auth method selection (in priority order):
7
- * 1. system.resolution["implied.auth_method"] — set by constraint solver
8
- * 2. Any api_service module's config.auth_method
9
- * 3. Fallback: jwt
10
- *
11
- * Generated strategies:
12
- * jwt — Bearer token verification via jsonwebtoken
13
- * oauth2 — Authorization Code flow: /auth/login redirect + /auth/callback
14
- * token exchange + refresh token rotation
15
- * apikey — X-API-Key header lookup against hashed keys in the database
16
- */
17
- import * as IR from "./ir";
18
- export declare function emitAuthMiddleware(system: IR.IRSystem): string;
package/dist/emit_auth.js DELETED
@@ -1,507 +0,0 @@
1
- "use strict";
2
- /**
3
- * BoneScript Auth Emitter
4
- * Generates auth.ts — JWT, OAuth2, or API key middleware depending on the
5
- * resolved auth_method in the system's constraint resolution map.
6
- *
7
- * Auth method selection (in priority order):
8
- * 1. system.resolution["implied.auth_method"] — set by constraint solver
9
- * 2. Any api_service module's config.auth_method
10
- * 3. Fallback: jwt
11
- *
12
- * Generated strategies:
13
- * jwt — Bearer token verification via jsonwebtoken
14
- * oauth2 — Authorization Code flow: /auth/login redirect + /auth/callback
15
- * token exchange + refresh token rotation
16
- * apikey — X-API-Key header lookup against hashed keys in the database
17
- */
18
- Object.defineProperty(exports, "__esModule", { value: true });
19
- exports.emitAuthMiddleware = void 0;
20
- /** Resolve the auth method for the system. */
21
- function resolveAuthMethod(system) {
22
- // Check resolution map first (set by constraint solver)
23
- // The solver writes keys like "UserService.auth_method" for each api_service module.
24
- // Also check the implied.auth_method key (set by domain defaults propagation).
25
- const resolved = system.resolution["implied.auth_method"]
26
- || system.resolution["system.auth_method"];
27
- if (resolved === "oauth2" || resolved === "apikey" || resolved === "jwt") {
28
- return resolved;
29
- }
30
- // Check per-module resolution keys written by the solver
31
- for (const [key, val] of Object.entries(system.resolution)) {
32
- if (key.endsWith(".auth_method") && (val === "oauth2" || val === "apikey" || val === "jwt")) {
33
- return val;
34
- }
35
- }
36
- // Fall back to any api_service module config
37
- for (const mod of system.modules) {
38
- const m = mod.config["auth_method"];
39
- if (m === "oauth2" || m === "apikey" || m === "jwt")
40
- return m;
41
- }
42
- return "jwt";
43
- }
44
- function emitAuthMiddleware(system) {
45
- const method = resolveAuthMethod(system);
46
- switch (method) {
47
- case "oauth2": return emitOAuth2Auth();
48
- case "apikey": return emitApiKeyAuth();
49
- default: return emitJwtAuth();
50
- }
51
- }
52
- exports.emitAuthMiddleware = emitAuthMiddleware;
53
- // ─── JWT ──────────────────────────────────────────────────────────────────────
54
- function emitJwtAuth() {
55
- return `// Generated by BoneScript compiler. DO NOT EDIT.
56
- // Auth strategy: JWT (Bearer token)
57
- import { Request, Response, NextFunction } from "express";
58
- import jwt from "jsonwebtoken";
59
-
60
- // JWT_SECRET must be set in production. The server will refuse to start without it
61
- // when NODE_ENV is "production" to prevent accidental use of a weak fallback.
62
- const JWT_SECRET = (() => {
63
- const secret = process.env.JWT_SECRET;
64
- if (!secret) {
65
- if (process.env.NODE_ENV === "production") {
66
- console.error("[FATAL] JWT_SECRET environment variable is not set. Refusing to start in production.");
67
- process.exit(1);
68
- }
69
- console.warn("[WARN] JWT_SECRET is not set. Using insecure default — do not use in production.");
70
- return "bonescript-dev-secret-do-not-use-in-production";
71
- }
72
- if (secret.length < 32) {
73
- console.warn("[WARN] JWT_SECRET is shorter than 32 characters. Use a longer secret in production.");
74
- }
75
- return secret;
76
- })();
77
-
78
- export interface AuthContext {
79
- authenticated: boolean;
80
- actor_id: string | null;
81
- trace_id: string;
82
- }
83
-
84
- export function authMiddleware(req: Request, res: Response, next: NextFunction): void {
85
- const header = req.headers.authorization;
86
- if (!header || !header.startsWith("Bearer ")) {
87
- (req as any).auth = { authenticated: false, actor_id: null, trace_id: req.headers["x-trace-id"] as string || "" };
88
- next();
89
- return;
90
- }
91
- try {
92
- const token = header.slice(7);
93
- const decoded = jwt.verify(token, JWT_SECRET) as { sub: string };
94
- (req as any).auth = {
95
- authenticated: true,
96
- actor_id: decoded.sub,
97
- trace_id: req.headers["x-trace-id"] as string || "",
98
- };
99
- } catch {
100
- (req as any).auth = { authenticated: false, actor_id: null, trace_id: req.headers["x-trace-id"] as string || "" };
101
- }
102
- next();
103
- }
104
-
105
- export function requireAuth(req: Request, res: Response, next: NextFunction): void {
106
- const auth: AuthContext = (req as any).auth;
107
- if (!auth || !auth.authenticated) {
108
- res.status(401).json({ error: { code: "UNAUTHORIZED", message: "Authentication required" } });
109
- return;
110
- }
111
- next();
112
- }
113
-
114
- /** Issue a signed JWT for a given actor. Used by login/register routes. */
115
- export function issueToken(actorId: string, expiresIn: string = "24h"): string {
116
- return jwt.sign({ sub: actorId }, JWT_SECRET, { expiresIn } as any);
117
- }
118
- `;
119
- }
120
- // ─── OAuth2 ───────────────────────────────────────────────────────────────────
121
- function emitOAuth2Auth() {
122
- return `// Generated by BoneScript compiler. DO NOT EDIT.
123
- // Auth strategy: OAuth2 Authorization Code Flow with PKCE + refresh token rotation
124
- import { Request, Response, NextFunction, Router } from "express";
125
- import crypto from "crypto";
126
- import jwt from "jsonwebtoken";
127
-
128
- // ─── Configuration ────────────────────────────────────────────────────────────
129
-
130
- const OAUTH2_CLIENT_ID = process.env.OAUTH2_CLIENT_ID || "";
131
- const OAUTH2_CLIENT_SECRET = process.env.OAUTH2_CLIENT_SECRET || "";
132
- const OAUTH2_AUTH_URL = process.env.OAUTH2_AUTH_URL || "";
133
- const OAUTH2_TOKEN_URL = process.env.OAUTH2_TOKEN_URL || "";
134
- const OAUTH2_REDIRECT_URI = process.env.OAUTH2_REDIRECT_URI || "http://localhost:3000/auth/callback";
135
- const OAUTH2_SCOPES = (process.env.OAUTH2_SCOPES || "openid profile email").split(" ");
136
-
137
- const JWT_SECRET = (() => {
138
- const secret = process.env.JWT_SECRET;
139
- if (!secret) {
140
- if (process.env.NODE_ENV === "production") {
141
- console.error("[FATAL] JWT_SECRET environment variable is not set. Refusing to start in production.");
142
- process.exit(1);
143
- }
144
- console.warn("[WARN] JWT_SECRET is not set. Using insecure default — do not use in production.");
145
- return "bonescript-dev-secret-do-not-use-in-production";
146
- }
147
- return secret;
148
- })();
149
-
150
- if (process.env.NODE_ENV === "production") {
151
- if (!OAUTH2_CLIENT_ID || !OAUTH2_CLIENT_SECRET || !OAUTH2_AUTH_URL || !OAUTH2_TOKEN_URL) {
152
- console.error("[FATAL] OAuth2 configuration incomplete. Set OAUTH2_CLIENT_ID, OAUTH2_CLIENT_SECRET, OAUTH2_AUTH_URL, OAUTH2_TOKEN_URL.");
153
- process.exit(1);
154
- }
155
- }
156
-
157
- // ─── PKCE helpers ─────────────────────────────────────────────────────────────
158
-
159
- function generateCodeVerifier(): string {
160
- return crypto.randomBytes(32).toString("base64url");
161
- }
162
-
163
- function generateCodeChallenge(verifier: string): string {
164
- return crypto.createHash("sha256").update(verifier).digest("base64url");
165
- }
166
-
167
- // ─── In-memory state store (replace with Redis in production) ─────────────────
168
-
169
- const pendingStates = new Map<string, { verifier: string; createdAt: number }>();
170
-
171
- // Clean up stale states every 5 minutes
172
- setInterval(() => {
173
- const cutoff = Date.now() - 10 * 60 * 1000; // 10 min TTL
174
- for (const [k, v] of pendingStates) {
175
- if (v.createdAt < cutoff) pendingStates.delete(k);
176
- }
177
- }, 5 * 60 * 1000);
178
-
179
- // ─── Auth context ─────────────────────────────────────────────────────────────
180
-
181
- export interface AuthContext {
182
- authenticated: boolean;
183
- actor_id: string | null;
184
- trace_id: string;
185
- }
186
-
187
- // ─── Middleware ───────────────────────────────────────────────────────────────
188
-
189
- export function authMiddleware(req: Request, res: Response, next: NextFunction): void {
190
- const header = req.headers.authorization;
191
- if (!header || !header.startsWith("Bearer ")) {
192
- (req as any).auth = { authenticated: false, actor_id: null, trace_id: req.headers["x-trace-id"] as string || "" };
193
- next();
194
- return;
195
- }
196
- try {
197
- const token = header.slice(7);
198
- const decoded = jwt.verify(token, JWT_SECRET) as { sub: string };
199
- (req as any).auth = {
200
- authenticated: true,
201
- actor_id: decoded.sub,
202
- trace_id: req.headers["x-trace-id"] as string || "",
203
- };
204
- } catch {
205
- (req as any).auth = { authenticated: false, actor_id: null, trace_id: req.headers["x-trace-id"] as string || "" };
206
- }
207
- next();
208
- }
209
-
210
- export function requireAuth(req: Request, res: Response, next: NextFunction): void {
211
- const auth: AuthContext = (req as any).auth;
212
- if (!auth || !auth.authenticated) {
213
- res.status(401).json({ error: { code: "UNAUTHORIZED", message: "Authentication required" } });
214
- return;
215
- }
216
- next();
217
- }
218
-
219
- // ─── OAuth2 Routes ────────────────────────────────────────────────────────────
220
-
221
- export const authRouter = Router();
222
-
223
- /** GET /auth/login — redirect to OAuth2 provider */
224
- authRouter.get("/login", (_req: Request, res: Response) => {
225
- const state = crypto.randomBytes(16).toString("hex");
226
- const verifier = generateCodeVerifier();
227
- const challenge = generateCodeChallenge(verifier);
228
- pendingStates.set(state, { verifier, createdAt: Date.now() });
229
-
230
- const params = new URLSearchParams({
231
- response_type: "code",
232
- client_id: OAUTH2_CLIENT_ID,
233
- redirect_uri: OAUTH2_REDIRECT_URI,
234
- scope: OAUTH2_SCOPES.join(" "),
235
- state,
236
- code_challenge: challenge,
237
- code_challenge_method: "S256",
238
- });
239
- res.redirect(\`\${OAUTH2_AUTH_URL}?\${params}\`);
240
- });
241
-
242
- /** GET /auth/callback — exchange code for tokens, issue internal JWT */
243
- authRouter.get("/callback", async (req: Request, res: Response) => {
244
- const { code, state, error } = req.query as Record<string, string>;
245
-
246
- if (error) {
247
- return res.status(400).json({ error: { code: "OAUTH2_ERROR", message: error } });
248
- }
249
- if (!code || !state) {
250
- return res.status(400).json({ error: { code: "MISSING_PARAMS", message: "code and state are required" } });
251
- }
252
-
253
- const pending = pendingStates.get(state);
254
- if (!pending) {
255
- return res.status(400).json({ error: { code: "INVALID_STATE", message: "Unknown or expired state parameter" } });
256
- }
257
- pendingStates.delete(state);
258
-
259
- try {
260
- // Exchange authorization code for tokens
261
- const tokenRes = await fetch(OAUTH2_TOKEN_URL, {
262
- method: "POST",
263
- headers: { "Content-Type": "application/x-www-form-urlencoded" },
264
- body: new URLSearchParams({
265
- grant_type: "authorization_code",
266
- code,
267
- redirect_uri: OAUTH2_REDIRECT_URI,
268
- client_id: OAUTH2_CLIENT_ID,
269
- client_secret: OAUTH2_CLIENT_SECRET,
270
- code_verifier: pending.verifier,
271
- }),
272
- });
273
-
274
- if (!tokenRes.ok) {
275
- const body = await tokenRes.text();
276
- console.error("[OAuth2] Token exchange failed:", body);
277
- return res.status(502).json({ error: { code: "TOKEN_EXCHANGE_FAILED", message: "Failed to exchange authorization code" } });
278
- }
279
-
280
- const tokens = await tokenRes.json() as {
281
- access_token: string;
282
- id_token?: string;
283
- refresh_token?: string;
284
- expires_in?: number;
285
- };
286
-
287
- // Extract subject from id_token or access_token
288
- let actorId: string;
289
- try {
290
- const payload = JSON.parse(Buffer.from((tokens.id_token || tokens.access_token).split(".")[1], "base64url").toString());
291
- actorId = payload.sub || payload.email || payload.preferred_username || "unknown";
292
- } catch {
293
- actorId = "unknown";
294
- }
295
-
296
- // Issue internal JWT (short-lived)
297
- const internalToken = jwt.sign({ sub: actorId }, JWT_SECRET, { expiresIn: "1h" } as any);
298
-
299
- res.json({
300
- token: internalToken,
301
- actor_id: actorId,
302
- expires_in: 3600,
303
- });
304
- } catch (err: any) {
305
- console.error("[OAuth2] Callback error:", err.message);
306
- res.status(500).json({ error: { code: "INTERNAL_ERROR", message: "OAuth2 callback failed" } });
307
- }
308
- });
309
-
310
- /** POST /auth/refresh — refresh an expired internal JWT */
311
- authRouter.post("/refresh", (req: Request, res: Response) => {
312
- const { token } = req.body as { token?: string };
313
- if (!token) {
314
- return res.status(400).json({ error: { code: "MISSING_TOKEN", message: "token is required" } });
315
- }
316
- try {
317
- // Allow expired tokens for refresh (ignoreExpiration)
318
- const decoded = jwt.verify(token, JWT_SECRET, { ignoreExpiration: true }) as { sub: string };
319
- const newToken = jwt.sign({ sub: decoded.sub }, JWT_SECRET, { expiresIn: "1h" } as any);
320
- res.json({ token: newToken, expires_in: 3600 });
321
- } catch {
322
- res.status(401).json({ error: { code: "INVALID_TOKEN", message: "Cannot refresh: token is invalid" } });
323
- }
324
- });
325
-
326
- /** POST /auth/logout — client-side only (stateless JWT); invalidation requires a denylist */
327
- authRouter.post("/logout", (_req: Request, res: Response) => {
328
- res.json({ ok: true, message: "Logged out. Discard the token on the client." });
329
- });
330
- `;
331
- }
332
- // ─── API Key ──────────────────────────────────────────────────────────────────
333
- function emitApiKeyAuth() {
334
- return `// Generated by BoneScript compiler. DO NOT EDIT.
335
- // Auth strategy: API Key (X-API-Key header, hashed keys stored in database)
336
- import { Request, Response, NextFunction, Router } from "express";
337
- import crypto from "crypto";
338
- import { query } from "./db";
339
-
340
- // ─── Auth context ─────────────────────────────────────────────────────────────
341
-
342
- export interface AuthContext {
343
- authenticated: boolean;
344
- actor_id: string | null;
345
- trace_id: string;
346
- }
347
-
348
- // ─── Key hashing ──────────────────────────────────────────────────────────────
349
-
350
- /** Hash an API key with SHA-256 for safe storage. Never store raw keys. */
351
- function hashApiKey(key: string): string {
352
- return crypto.createHash("sha256").update(key).digest("hex");
353
- }
354
-
355
- /** Generate a new API key. Returns the raw key (shown once) and its hash. */
356
- export function generateApiKey(): { key: string; hash: string; prefix: string } {
357
- const raw = "bsk_" + crypto.randomBytes(32).toString("base64url");
358
- return { key: raw, hash: hashApiKey(raw), prefix: raw.slice(0, 12) };
359
- }
360
-
361
- // ─── In-memory LRU cache (avoids a DB hit on every request) ──────────────────
362
-
363
- const KEY_CACHE_TTL_MS = 60_000; // 1 minute
364
- const keyCache = new Map<string, { actorId: string; expiresAt: number }>();
365
-
366
- function getCached(hash: string): string | null {
367
- const entry = keyCache.get(hash);
368
- if (!entry) return null;
369
- if (Date.now() > entry.expiresAt) { keyCache.delete(hash); return null; }
370
- return entry.actorId;
371
- }
372
-
373
- function setCached(hash: string, actorId: string): void {
374
- // Evict oldest entry if cache is too large
375
- if (keyCache.size >= 1000) {
376
- const oldest = [...keyCache.entries()].sort((a, b) => a[1].expiresAt - b[1].expiresAt)[0];
377
- if (oldest) keyCache.delete(oldest[0]);
378
- }
379
- keyCache.set(hash, { actorId, expiresAt: Date.now() + KEY_CACHE_TTL_MS });
380
- }
381
-
382
- // ─── Middleware ───────────────────────────────────────────────────────────────
383
-
384
- export async function authMiddleware(req: Request, res: Response, next: NextFunction): Promise<void> {
385
- const rawKey = req.headers["x-api-key"] as string | undefined;
386
- const traceId = req.headers["x-trace-id"] as string || "";
387
-
388
- if (!rawKey) {
389
- (req as any).auth = { authenticated: false, actor_id: null, trace_id: traceId };
390
- next();
391
- return;
392
- }
393
-
394
- const hash = hashApiKey(rawKey);
395
-
396
- // Check cache first
397
- const cached = getCached(hash);
398
- if (cached) {
399
- (req as any).auth = { authenticated: true, actor_id: cached, trace_id: traceId };
400
- next();
401
- return;
402
- }
403
-
404
- try {
405
- // Look up in database — api_keys table (see migration below)
406
- const rows = await query<{ actor_id: string; revoked: boolean }>(
407
- \`SELECT actor_id, revoked FROM api_keys WHERE key_hash = $1 AND expires_at > NOW()\`,
408
- [hash]
409
- );
410
- if (rows.length === 0 || rows[0].revoked) {
411
- (req as any).auth = { authenticated: false, actor_id: null, trace_id: traceId };
412
- next();
413
- return;
414
- }
415
- const actorId = rows[0].actor_id;
416
- setCached(hash, actorId);
417
- (req as any).auth = { authenticated: true, actor_id: actorId, trace_id: traceId };
418
- } catch (err: any) {
419
- console.error("[ApiKey] Auth lookup failed:", err.message);
420
- (req as any).auth = { authenticated: false, actor_id: null, trace_id: traceId };
421
- }
422
- next();
423
- }
424
-
425
- export function requireAuth(req: Request, res: Response, next: NextFunction): void {
426
- const auth: AuthContext = (req as any).auth;
427
- if (!auth || !auth.authenticated) {
428
- res.status(401).json({ error: { code: "UNAUTHORIZED", message: "Valid API key required (X-API-Key header)" } });
429
- return;
430
- }
431
- next();
432
- }
433
-
434
- // ─── Key Management Routes ────────────────────────────────────────────────────
435
-
436
- export const authRouter = Router();
437
-
438
- /** POST /auth/keys — create a new API key for the authenticated actor */
439
- authRouter.post("/keys", requireAuth, async (req: Request, res: Response) => {
440
- const auth: AuthContext = (req as any).auth;
441
- const { name, expires_in_days = 365 } = req.body as { name?: string; expires_in_days?: number };
442
-
443
- const { key, hash, prefix } = generateApiKey();
444
- const expiresAt = new Date(Date.now() + expires_in_days * 86_400_000);
445
-
446
- try {
447
- await query(
448
- \`INSERT INTO api_keys (actor_id, key_hash, key_prefix, name, expires_at) VALUES ($1, $2, $3, $4, $5)\`,
449
- [auth.actor_id, hash, prefix, name || "default", expiresAt]
450
- );
451
- // Return the raw key ONCE — it cannot be retrieved again
452
- res.status(201).json({ key, prefix, expires_at: expiresAt });
453
- } catch (err: any) {
454
- res.status(500).json({ error: { code: "KEY_CREATE_FAILED", message: err.message } });
455
- }
456
- });
457
-
458
- /** GET /auth/keys — list API keys for the authenticated actor (no raw keys) */
459
- authRouter.get("/keys", requireAuth, async (req: Request, res: Response) => {
460
- const auth: AuthContext = (req as any).auth;
461
- try {
462
- const rows = await query(
463
- \`SELECT id, key_prefix, name, created_at, expires_at, revoked FROM api_keys WHERE actor_id = $1 ORDER BY created_at DESC\`,
464
- [auth.actor_id]
465
- );
466
- res.json({ keys: rows });
467
- } catch (err: any) {
468
- res.status(500).json({ error: { code: "KEY_LIST_FAILED", message: err.message } });
469
- }
470
- });
471
-
472
- /** DELETE /auth/keys/:id — revoke an API key */
473
- authRouter.delete("/keys/:id", requireAuth, async (req: Request, res: Response) => {
474
- const auth: AuthContext = (req as any).auth;
475
- try {
476
- const result = await query(
477
- \`UPDATE api_keys SET revoked = true WHERE id = $1 AND actor_id = $2 RETURNING id\`,
478
- [req.params.id, auth.actor_id]
479
- );
480
- if (result.length === 0) {
481
- return res.status(404).json({ error: { code: "NOT_FOUND", message: "API key not found" } });
482
- }
483
- res.json({ ok: true });
484
- } catch (err: any) {
485
- res.status(500).json({ error: { code: "KEY_REVOKE_FAILED", message: err.message } });
486
- }
487
- });
488
-
489
- /*
490
- * Required migration — add to your migrations directory:
491
- *
492
- * CREATE TABLE IF NOT EXISTS api_keys (
493
- * id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
494
- * actor_id UUID NOT NULL,
495
- * key_hash VARCHAR(64) NOT NULL UNIQUE,
496
- * key_prefix VARCHAR(16) NOT NULL,
497
- * name VARCHAR(255) NOT NULL DEFAULT 'default',
498
- * created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
499
- * expires_at TIMESTAMPTZ NOT NULL,
500
- * revoked BOOLEAN NOT NULL DEFAULT false
501
- * );
502
- * CREATE INDEX IF NOT EXISTS idx_api_keys_actor ON api_keys (actor_id);
503
- * CREATE INDEX IF NOT EXISTS idx_api_keys_hash ON api_keys (key_hash);
504
- */
505
- `;
506
- }
507
- //# sourceMappingURL=emit_auth.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"emit_auth.js","sourceRoot":"","sources":["../src/emit_auth.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;GAeG;;;AAIH,8CAA8C;AAC9C,SAAS,iBAAiB,CAAC,MAAmB;IAC5C,wDAAwD;IACxD,qFAAqF;IACrF,+EAA+E;IAC/E,MAAM,QAAQ,GAAG,MAAM,CAAC,UAAU,CAAC,qBAAqB,CAAC;WACpD,MAAM,CAAC,UAAU,CAAC,oBAAoB,CAAC,CAAC;IAC7C,IAAI,QAAQ,KAAK,QAAQ,IAAI,QAAQ,KAAK,QAAQ,IAAI,QAAQ,KAAK,KAAK,EAAE,CAAC;QACzE,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,yDAAyD;IACzD,KAAK,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,CAAC;QAC3D,IAAI,GAAG,CAAC,QAAQ,CAAC,cAAc,CAAC,IAAI,CAAC,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,KAAK,CAAC,EAAE,CAAC;YAC5F,OAAO,GAAkC,CAAC;QAC5C,CAAC;IACH,CAAC;IAED,6CAA6C;IAC7C,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;QACjC,MAAM,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC,aAAa,CAAuB,CAAC;QAC1D,IAAI,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,KAAK;YAAE,OAAO,CAAC,CAAC;IAChE,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAgB,kBAAkB,CAAC,MAAmB;IACpD,MAAM,MAAM,GAAG,iBAAiB,CAAC,MAAM,CAAC,CAAC;IACzC,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,QAAQ,CAAC,CAAE,OAAO,cAAc,EAAE,CAAC;QACxC,KAAK,QAAQ,CAAC,CAAE,OAAO,cAAc,EAAE,CAAC;QACxC,OAAO,CAAC,CAAQ,OAAO,WAAW,EAAE,CAAC;IACvC,CAAC;AACH,CAAC;AAPD,gDAOC;AAED,iFAAiF;AAEjF,SAAS,WAAW;IAClB,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+DR,CAAC;AACF,CAAC;AAED,iFAAiF;AAEjF,SAAS,cAAc;IACrB,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgNR,CAAC;AACF,CAAC;AAED,iFAAiF;AAEjF,SAAS,cAAc;IACrB,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2KR,CAAC;AACF,CAAC"}
@@ -1,7 +0,0 @@
1
- /**
2
- * BoneScript Database Emitter
3
- * Generates db.ts (connection pool) and migrate.ts (migration runner).
4
- */
5
- import * as IR from "./ir";
6
- export declare function emitDbClient(system: IR.IRSystem): string;
7
- export declare function emitMigration(system: IR.IRSystem, schemas: string[]): string;
@@ -1,72 +0,0 @@
1
- "use strict";
2
- /**
3
- * BoneScript Database Emitter
4
- * Generates db.ts (connection pool) and migrate.ts (migration runner).
5
- */
6
- Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.emitMigration = exports.emitDbClient = void 0;
8
- const lowering_helpers_1 = require("./lowering_helpers");
9
- function emitDbClient(system) {
10
- const name = (0, lowering_helpers_1.toSnakeCase)(system.name);
11
- return [
12
- "// Generated by BoneScript compiler. DO NOT EDIT.",
13
- `import { Pool, PoolClient } from "pg";`,
14
- "",
15
- "// Lazy pool — created on first use so DATABASE_URL is read after dotenv loads",
16
- "let _pool: Pool | null = null;",
17
- "function getPool(): Pool {",
18
- " if (!_pool) {",
19
- ` _pool = new Pool({ connectionString: process.env.DATABASE_URL || "postgresql://localhost:5432/${name}", max: 20 });`,
20
- ` _pool.on("error", (err: Error) => console.error("[DB] Pool error (non-fatal):", err.message));`,
21
- " }",
22
- " return _pool;",
23
- "}",
24
- "export const pool = new Proxy({} as Pool, { get(_t: any, p: any) { return (getPool() as any)[p]; } });",
25
- "",
26
- "export async function query<T = any>(text: string, params?: any[]): Promise<T[]> {",
27
- " try { const result = await pool.query(text, params); return result.rows as T[]; }",
28
- " catch (e: any) { throw new Error(`DB query failed: ${e.message}`); }",
29
- "}",
30
- "export async function queryOne<T = any>(text: string, params?: any[]): Promise<T | null> {",
31
- " try { const rows = await query<T>(text, params); return rows[0] || null; }",
32
- " catch (e: any) { throw new Error(`DB query failed: ${e.message}`); }",
33
- "}",
34
- "export async function execute(text: string, params?: any[]): Promise<number> {",
35
- " try { const result = await pool.query(text, params); return result.rowCount || 0; }",
36
- " catch (e: any) { throw new Error(`DB execute failed: ${e.message}`); }",
37
- "}",
38
- "export async function transaction<T>(fn: (client: PoolClient) => Promise<T>): Promise<T> {",
39
- " const client = await pool.connect();",
40
- ` try { await client.query("BEGIN"); const result = await fn(client); await client.query("COMMIT"); return result; }`,
41
- ` catch (e) { await client.query("ROLLBACK"); throw e; }`,
42
- " finally { client.release(); }",
43
- "}",
44
- ].join("\n");
45
- }
46
- exports.emitDbClient = emitDbClient;
47
- function emitMigration(system, schemas) {
48
- const lines = [];
49
- lines.push(`// Generated by BoneScript compiler. DO NOT EDIT.`);
50
- lines.push(`require("dotenv").config();`);
51
- lines.push(`import { pool } from "./db";`);
52
- lines.push(``);
53
- lines.push(`async function migrate() {`);
54
- lines.push(` console.log("Running migrations...");`);
55
- lines.push(` const client = await pool.connect();`);
56
- lines.push(` try {`);
57
- for (const schema of schemas) {
58
- const escaped = schema.replace(/`/g, "\\`").replace(/\$/g, "\\$");
59
- lines.push(` await client.query(\`${escaped}\`);`);
60
- }
61
- lines.push(` console.log("Migrations complete.");`);
62
- lines.push(` } finally {`);
63
- lines.push(` client.release();`);
64
- lines.push(` await pool.end();`);
65
- lines.push(` }`);
66
- lines.push(`}`);
67
- lines.push(``);
68
- lines.push(`migrate().catch(e => { console.error(e); process.exit(1); });`);
69
- return lines.join("\n");
70
- }
71
- exports.emitMigration = emitMigration;
72
- //# sourceMappingURL=emit_database.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"emit_database.js","sourceRoot":"","sources":["../src/emit_database.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAGH,yDAAiD;AAEjD,SAAgB,YAAY,CAAC,MAAmB;IAC9C,MAAM,IAAI,GAAG,IAAA,8BAAW,EAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACtC,OAAO;QACL,mDAAmD;QACnD,wCAAwC;QACxC,EAAE;QACF,gFAAgF;QAChF,gCAAgC;QAChC,4BAA4B;QAC5B,iBAAiB;QACjB,qGAAqG,IAAI,gBAAgB;QACzH,oGAAoG;QACpG,KAAK;QACL,iBAAiB;QACjB,GAAG;QACH,wGAAwG;QACxG,EAAE;QACF,oFAAoF;QACpF,qFAAqF;QACrF,wEAAwE;QACxE,GAAG;QACH,4FAA4F;QAC5F,8EAA8E;QAC9E,wEAAwE;QACxE,GAAG;QACH,gFAAgF;QAChF,uFAAuF;QACvF,0EAA0E;QAC1E,GAAG;QACH,4FAA4F;QAC5F,wCAAwC;QACxC,sHAAsH;QACtH,0DAA0D;QAC1D,iCAAiC;QACjC,GAAG;KACJ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC;AApCD,oCAoCC;AAED,SAAgB,aAAa,CAAC,MAAmB,EAAE,OAAiB;IAClE,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,CAAC,IAAI,CAAC,mDAAmD,CAAC,CAAC;IAChE,KAAK,CAAC,IAAI,CAAC,6BAA6B,CAAC,CAAC;IAC1C,KAAK,CAAC,IAAI,CAAC,8BAA8B,CAAC,CAAC;IAC3C,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,4BAA4B,CAAC,CAAC;IACzC,KAAK,CAAC,IAAI,CAAC,yCAAyC,CAAC,CAAC;IACtD,KAAK,CAAC,IAAI,CAAC,wCAAwC,CAAC,CAAC;IACrD,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAEtB,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;QAClE,KAAK,CAAC,IAAI,CAAC,4BAA4B,OAAO,MAAM,CAAC,CAAC;IACxD,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,0CAA0C,CAAC,CAAC;IACvD,KAAK,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;IAC5B,KAAK,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC;IACpC,KAAK,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC;IACpC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAClB,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAChB,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,+DAA+D,CAAC,CAAC;IAC5E,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAzBD,sCAyBC"}