alepha 0.14.4 → 0.15.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.
Files changed (322) hide show
  1. package/README.md +44 -102
  2. package/dist/api/audits/index.d.ts +331 -443
  3. package/dist/api/audits/index.d.ts.map +1 -1
  4. package/dist/api/audits/index.js +2 -2
  5. package/dist/api/audits/index.js.map +1 -1
  6. package/dist/api/files/index.d.ts +0 -113
  7. package/dist/api/files/index.d.ts.map +1 -1
  8. package/dist/api/files/index.js +2 -3
  9. package/dist/api/files/index.js.map +1 -1
  10. package/dist/api/jobs/index.d.ts +151 -262
  11. package/dist/api/jobs/index.d.ts.map +1 -1
  12. package/dist/api/notifications/index.browser.js +4 -4
  13. package/dist/api/notifications/index.browser.js.map +1 -1
  14. package/dist/api/notifications/index.d.ts +164 -276
  15. package/dist/api/notifications/index.d.ts.map +1 -1
  16. package/dist/api/notifications/index.js +4 -4
  17. package/dist/api/notifications/index.js.map +1 -1
  18. package/dist/api/parameters/index.d.ts +265 -377
  19. package/dist/api/parameters/index.d.ts.map +1 -1
  20. package/dist/api/users/index.browser.js +1 -2
  21. package/dist/api/users/index.browser.js.map +1 -1
  22. package/dist/api/users/index.d.ts +195 -301
  23. package/dist/api/users/index.d.ts.map +1 -1
  24. package/dist/api/users/index.js +203 -184
  25. package/dist/api/users/index.js.map +1 -1
  26. package/dist/api/verifications/index.d.ts.map +1 -1
  27. package/dist/batch/index.d.ts.map +1 -1
  28. package/dist/batch/index.js +1 -2
  29. package/dist/batch/index.js.map +1 -1
  30. package/dist/bucket/index.d.ts.map +1 -1
  31. package/dist/cache/core/index.d.ts.map +1 -1
  32. package/dist/cache/redis/index.d.ts.map +1 -1
  33. package/dist/cache/redis/index.js +2 -2
  34. package/dist/cache/redis/index.js.map +1 -1
  35. package/dist/cli/index.d.ts +5900 -165
  36. package/dist/cli/index.d.ts.map +1 -1
  37. package/dist/cli/index.js +1481 -639
  38. package/dist/cli/index.js.map +1 -1
  39. package/dist/command/index.d.ts +8 -4
  40. package/dist/command/index.d.ts.map +1 -1
  41. package/dist/command/index.js +29 -25
  42. package/dist/command/index.js.map +1 -1
  43. package/dist/core/index.browser.js +563 -54
  44. package/dist/core/index.browser.js.map +1 -1
  45. package/dist/core/index.d.ts +175 -8
  46. package/dist/core/index.d.ts.map +1 -1
  47. package/dist/core/index.js +564 -54
  48. package/dist/core/index.js.map +1 -1
  49. package/dist/core/index.native.js +563 -54
  50. package/dist/core/index.native.js.map +1 -1
  51. package/dist/datetime/index.d.ts.map +1 -1
  52. package/dist/datetime/index.js +4 -4
  53. package/dist/datetime/index.js.map +1 -1
  54. package/dist/email/index.d.ts +89 -42
  55. package/dist/email/index.d.ts.map +1 -1
  56. package/dist/email/index.js +129 -33
  57. package/dist/email/index.js.map +1 -1
  58. package/dist/fake/index.d.ts +7969 -2
  59. package/dist/fake/index.d.ts.map +1 -1
  60. package/dist/fake/index.js +22 -22
  61. package/dist/fake/index.js.map +1 -1
  62. package/dist/file/index.d.ts +134 -1
  63. package/dist/file/index.d.ts.map +1 -1
  64. package/dist/file/index.js +253 -1
  65. package/dist/file/index.js.map +1 -1
  66. package/dist/lock/core/index.d.ts.map +1 -1
  67. package/dist/lock/redis/index.d.ts.map +1 -1
  68. package/dist/logger/index.d.ts +1 -2
  69. package/dist/logger/index.d.ts.map +1 -1
  70. package/dist/logger/index.js +1 -5
  71. package/dist/logger/index.js.map +1 -1
  72. package/dist/mcp/index.d.ts +19 -1
  73. package/dist/mcp/index.d.ts.map +1 -1
  74. package/dist/mcp/index.js +28 -4
  75. package/dist/mcp/index.js.map +1 -1
  76. package/dist/orm/chunk-DH6iiROE.js +38 -0
  77. package/dist/orm/index.browser.js +9 -9
  78. package/dist/orm/index.browser.js.map +1 -1
  79. package/dist/orm/index.bun.js +2821 -0
  80. package/dist/orm/index.bun.js.map +1 -0
  81. package/dist/orm/index.d.ts +318 -169
  82. package/dist/orm/index.d.ts.map +1 -1
  83. package/dist/orm/index.js +2086 -1776
  84. package/dist/orm/index.js.map +1 -1
  85. package/dist/queue/core/index.d.ts +4 -4
  86. package/dist/queue/core/index.d.ts.map +1 -1
  87. package/dist/queue/redis/index.d.ts.map +1 -1
  88. package/dist/redis/index.bun.js +285 -0
  89. package/dist/redis/index.bun.js.map +1 -0
  90. package/dist/redis/index.d.ts +13 -31
  91. package/dist/redis/index.d.ts.map +1 -1
  92. package/dist/redis/index.js +18 -38
  93. package/dist/redis/index.js.map +1 -1
  94. package/dist/retry/index.d.ts.map +1 -1
  95. package/dist/router/index.d.ts.map +1 -1
  96. package/dist/scheduler/index.d.ts +83 -1
  97. package/dist/scheduler/index.d.ts.map +1 -1
  98. package/dist/scheduler/index.js +393 -1
  99. package/dist/scheduler/index.js.map +1 -1
  100. package/dist/security/index.browser.js +5 -1
  101. package/dist/security/index.browser.js.map +1 -1
  102. package/dist/security/index.d.ts +598 -112
  103. package/dist/security/index.d.ts.map +1 -1
  104. package/dist/security/index.js +1808 -97
  105. package/dist/security/index.js.map +1 -1
  106. package/dist/server/auth/index.d.ts +1200 -175
  107. package/dist/server/auth/index.d.ts.map +1 -1
  108. package/dist/server/auth/index.js +1268 -37
  109. package/dist/server/auth/index.js.map +1 -1
  110. package/dist/server/cache/index.d.ts +6 -3
  111. package/dist/server/cache/index.d.ts.map +1 -1
  112. package/dist/server/cache/index.js +1 -1
  113. package/dist/server/cache/index.js.map +1 -1
  114. package/dist/server/compress/index.d.ts.map +1 -1
  115. package/dist/server/cookies/index.d.ts.map +1 -1
  116. package/dist/server/cookies/index.js +3 -3
  117. package/dist/server/cookies/index.js.map +1 -1
  118. package/dist/server/core/index.d.ts +115 -13
  119. package/dist/server/core/index.d.ts.map +1 -1
  120. package/dist/server/core/index.js +321 -139
  121. package/dist/server/core/index.js.map +1 -1
  122. package/dist/server/cors/index.d.ts +0 -1
  123. package/dist/server/cors/index.d.ts.map +1 -1
  124. package/dist/server/health/index.d.ts +0 -1
  125. package/dist/server/health/index.d.ts.map +1 -1
  126. package/dist/server/helmet/index.d.ts.map +1 -1
  127. package/dist/server/links/index.browser.js +9 -1
  128. package/dist/server/links/index.browser.js.map +1 -1
  129. package/dist/server/links/index.d.ts +1 -2
  130. package/dist/server/links/index.d.ts.map +1 -1
  131. package/dist/server/links/index.js +14 -7
  132. package/dist/server/links/index.js.map +1 -1
  133. package/dist/server/metrics/index.d.ts +514 -1
  134. package/dist/server/metrics/index.d.ts.map +1 -1
  135. package/dist/server/metrics/index.js +4462 -4
  136. package/dist/server/metrics/index.js.map +1 -1
  137. package/dist/server/multipart/index.d.ts.map +1 -1
  138. package/dist/server/proxy/index.d.ts +0 -1
  139. package/dist/server/proxy/index.d.ts.map +1 -1
  140. package/dist/server/rate-limit/index.d.ts.map +1 -1
  141. package/dist/server/static/index.d.ts.map +1 -1
  142. package/dist/server/swagger/index.d.ts +1 -2
  143. package/dist/server/swagger/index.d.ts.map +1 -1
  144. package/dist/server/swagger/index.js +1 -2
  145. package/dist/server/swagger/index.js.map +1 -1
  146. package/dist/sms/index.d.ts +3 -1
  147. package/dist/sms/index.d.ts.map +1 -1
  148. package/dist/sms/index.js +10 -10
  149. package/dist/sms/index.js.map +1 -1
  150. package/dist/thread/index.d.ts +0 -1
  151. package/dist/thread/index.d.ts.map +1 -1
  152. package/dist/thread/index.js +2 -2
  153. package/dist/thread/index.js.map +1 -1
  154. package/dist/topic/core/index.d.ts.map +1 -1
  155. package/dist/topic/redis/index.d.ts.map +1 -1
  156. package/dist/vite/index.d.ts +6315 -149
  157. package/dist/vite/index.d.ts.map +1 -1
  158. package/dist/vite/index.js +140 -469
  159. package/dist/vite/index.js.map +1 -1
  160. package/dist/websocket/index.browser.js +9 -9
  161. package/dist/websocket/index.browser.js.map +1 -1
  162. package/dist/websocket/index.d.ts +28 -28
  163. package/dist/websocket/index.d.ts.map +1 -1
  164. package/dist/websocket/index.js +9 -9
  165. package/dist/websocket/index.js.map +1 -1
  166. package/package.json +13 -18
  167. package/src/api/files/controllers/AdminFileStatsController.ts +0 -1
  168. package/src/api/users/atoms/realmAuthSettingsAtom.ts +5 -0
  169. package/src/api/users/controllers/{UserRealmController.ts → RealmController.ts} +11 -11
  170. package/src/api/users/entities/users.ts +1 -1
  171. package/src/api/users/index.ts +8 -8
  172. package/src/api/users/primitives/{$userRealm.ts → $realm.ts} +17 -19
  173. package/src/api/users/providers/{UserRealmProvider.ts → RealmProvider.ts} +26 -30
  174. package/src/api/users/schemas/{userRealmConfigSchema.ts → realmConfigSchema.ts} +2 -2
  175. package/src/api/users/services/CredentialService.ts +7 -7
  176. package/src/api/users/services/IdentityService.ts +4 -4
  177. package/src/api/users/services/RegistrationService.spec.ts +25 -27
  178. package/src/api/users/services/RegistrationService.ts +38 -27
  179. package/src/api/users/services/SessionCrudService.ts +3 -3
  180. package/src/api/users/services/SessionService.spec.ts +3 -3
  181. package/src/api/users/services/SessionService.ts +27 -18
  182. package/src/api/users/services/UserService.ts +7 -7
  183. package/src/batch/providers/BatchProvider.ts +1 -2
  184. package/src/cli/apps/AlephaCli.ts +2 -2
  185. package/src/cli/apps/AlephaPackageBuilderCli.ts +47 -20
  186. package/src/cli/assets/apiHelloControllerTs.ts +19 -0
  187. package/src/cli/assets/apiIndexTs.ts +16 -0
  188. package/src/cli/assets/biomeJson.ts +2 -1
  189. package/src/cli/assets/claudeMd.ts +308 -0
  190. package/src/cli/assets/dummySpecTs.ts +2 -1
  191. package/src/cli/assets/editorconfig.ts +2 -1
  192. package/src/cli/assets/mainBrowserTs.ts +4 -3
  193. package/src/cli/assets/mainCss.ts +24 -0
  194. package/src/cli/assets/mainServerTs.ts +24 -0
  195. package/src/cli/assets/tsconfigJson.ts +2 -1
  196. package/src/cli/assets/webAppRouterTs.ts +16 -0
  197. package/src/cli/assets/webHelloComponentTsx.ts +20 -0
  198. package/src/cli/assets/webIndexTs.ts +16 -0
  199. package/src/cli/atoms/appEntryOptions.ts +13 -0
  200. package/src/cli/atoms/buildOptions.ts +1 -1
  201. package/src/cli/atoms/changelogOptions.ts +1 -1
  202. package/src/cli/commands/build.ts +97 -61
  203. package/src/cli/commands/db.ts +21 -18
  204. package/src/cli/commands/deploy.ts +17 -5
  205. package/src/cli/commands/dev.ts +26 -47
  206. package/src/cli/commands/gen/env.ts +1 -1
  207. package/src/cli/commands/init.ts +79 -25
  208. package/src/cli/commands/lint.ts +9 -3
  209. package/src/cli/commands/test.ts +8 -2
  210. package/src/cli/commands/typecheck.ts +5 -1
  211. package/src/cli/commands/verify.ts +4 -2
  212. package/src/cli/defineConfig.ts +9 -0
  213. package/src/cli/index.ts +2 -1
  214. package/src/cli/providers/AppEntryProvider.ts +131 -0
  215. package/src/cli/providers/ViteBuildProvider.ts +82 -0
  216. package/src/cli/providers/ViteDevServerProvider.ts +350 -0
  217. package/src/cli/providers/ViteTemplateProvider.ts +27 -0
  218. package/src/cli/services/AlephaCliUtils.ts +72 -602
  219. package/src/cli/services/PackageManagerUtils.ts +308 -0
  220. package/src/cli/services/ProjectScaffolder.ts +329 -0
  221. package/src/command/helpers/Runner.ts +15 -3
  222. package/src/core/Alepha.ts +2 -8
  223. package/src/core/__tests__/Alepha-graph.spec.ts +4 -0
  224. package/src/core/index.shared.ts +1 -0
  225. package/src/core/index.ts +2 -0
  226. package/src/core/primitives/$hook.ts +6 -2
  227. package/src/core/primitives/$module.spec.ts +4 -0
  228. package/src/core/primitives/$module.ts +12 -0
  229. package/src/core/providers/AlsProvider.ts +1 -1
  230. package/src/core/providers/CodecManager.spec.ts +12 -6
  231. package/src/core/providers/CodecManager.ts +26 -6
  232. package/src/core/providers/EventManager.ts +169 -13
  233. package/src/core/providers/KeylessJsonSchemaCodec.spec.ts +878 -0
  234. package/src/core/providers/KeylessJsonSchemaCodec.ts +789 -0
  235. package/src/core/providers/SchemaValidator.spec.ts +236 -0
  236. package/src/core/providers/StateManager.spec.ts +27 -16
  237. package/src/email/providers/LocalEmailProvider.spec.ts +111 -87
  238. package/src/email/providers/LocalEmailProvider.ts +52 -15
  239. package/src/email/providers/NodemailerEmailProvider.ts +167 -56
  240. package/src/file/errors/FileError.ts +7 -0
  241. package/src/file/index.ts +9 -1
  242. package/src/file/providers/MemoryFileSystemProvider.ts +393 -0
  243. package/src/logger/providers/PrettyFormatterProvider.ts +0 -9
  244. package/src/mcp/errors/McpError.ts +30 -0
  245. package/src/mcp/index.ts +3 -0
  246. package/src/mcp/transports/SseMcpTransport.ts +16 -6
  247. package/src/orm/index.browser.ts +1 -19
  248. package/src/orm/index.bun.ts +77 -0
  249. package/src/orm/index.shared-server.ts +22 -0
  250. package/src/orm/index.shared.ts +15 -0
  251. package/src/orm/index.ts +19 -39
  252. package/src/orm/providers/DrizzleKitProvider.ts +3 -5
  253. package/src/orm/providers/drivers/BunPostgresProvider.ts +3 -5
  254. package/src/orm/providers/drivers/BunSqliteProvider.ts +1 -1
  255. package/src/orm/providers/drivers/CloudflareD1Provider.ts +4 -0
  256. package/src/orm/providers/drivers/DatabaseProvider.ts +4 -0
  257. package/src/orm/providers/drivers/PglitePostgresProvider.ts +4 -0
  258. package/src/orm/services/Repository.ts +19 -0
  259. package/src/redis/index.bun.ts +35 -0
  260. package/src/redis/providers/BunRedisProvider.ts +12 -43
  261. package/src/redis/providers/BunRedisSubscriberProvider.ts +2 -3
  262. package/src/redis/providers/NodeRedisProvider.ts +16 -34
  263. package/src/{server/security → security}/__tests__/BasicAuth.spec.ts +11 -11
  264. package/src/{server/security → security}/__tests__/ServerSecurityProvider-realm.spec.ts +21 -16
  265. package/src/{server/security/providers → security/__tests__}/ServerSecurityProvider.spec.ts +5 -5
  266. package/src/security/index.browser.ts +5 -0
  267. package/src/security/index.ts +90 -7
  268. package/src/security/primitives/{$realm.spec.ts → $issuer.spec.ts} +11 -11
  269. package/src/security/primitives/{$realm.ts → $issuer.ts} +20 -17
  270. package/src/security/primitives/$role.ts +5 -5
  271. package/src/security/primitives/$serviceAccount.spec.ts +5 -5
  272. package/src/security/primitives/$serviceAccount.ts +3 -3
  273. package/src/{server/security → security}/providers/ServerSecurityProvider.ts +5 -7
  274. package/src/server/auth/primitives/$auth.ts +10 -10
  275. package/src/server/auth/primitives/$authCredentials.ts +3 -3
  276. package/src/server/auth/primitives/$authGithub.ts +3 -3
  277. package/src/server/auth/primitives/$authGoogle.ts +3 -3
  278. package/src/server/auth/providers/ServerAuthProvider.ts +13 -13
  279. package/src/server/cache/providers/ServerCacheProvider.ts +1 -1
  280. package/src/server/cookies/providers/ServerCookiesProvider.ts +3 -3
  281. package/src/server/core/index.ts +1 -1
  282. package/src/server/core/providers/BunHttpServerProvider.ts +1 -1
  283. package/src/server/core/providers/NodeHttpServerProvider.spec.ts +125 -0
  284. package/src/server/core/providers/NodeHttpServerProvider.ts +92 -24
  285. package/src/server/core/providers/ServerBodyParserProvider.ts +19 -23
  286. package/src/server/core/providers/ServerLoggerProvider.ts +23 -19
  287. package/src/server/core/providers/ServerProvider.ts +144 -24
  288. package/src/server/core/providers/ServerRouterProvider.ts +259 -115
  289. package/src/server/core/providers/ServerTimingProvider.ts +2 -2
  290. package/src/server/links/atoms/apiLinksAtom.ts +7 -0
  291. package/src/server/links/index.browser.ts +2 -0
  292. package/src/server/links/index.ts +3 -1
  293. package/src/server/links/providers/LinkProvider.ts +1 -1
  294. package/src/server/swagger/index.ts +1 -1
  295. package/src/sms/providers/LocalSmsProvider.spec.ts +153 -111
  296. package/src/sms/providers/LocalSmsProvider.ts +8 -7
  297. package/src/vite/index.ts +3 -2
  298. package/src/vite/tasks/buildClient.ts +0 -1
  299. package/src/vite/tasks/buildServer.ts +80 -22
  300. package/src/vite/tasks/copyAssets.ts +5 -4
  301. package/src/vite/tasks/generateCloudflare.ts +7 -0
  302. package/src/vite/tasks/generateSitemap.ts +64 -23
  303. package/src/vite/tasks/index.ts +0 -2
  304. package/src/vite/tasks/prerenderPages.ts +49 -24
  305. package/dist/server/security/index.browser.js +0 -13
  306. package/dist/server/security/index.browser.js.map +0 -1
  307. package/dist/server/security/index.d.ts +0 -173
  308. package/dist/server/security/index.d.ts.map +0 -1
  309. package/dist/server/security/index.js +0 -311
  310. package/dist/server/security/index.js.map +0 -1
  311. package/src/cli/assets/appRouterTs.ts +0 -9
  312. package/src/cli/assets/indexHtml.ts +0 -15
  313. package/src/cli/assets/mainTs.ts +0 -13
  314. package/src/cli/commands/format.ts +0 -17
  315. package/src/server/security/index.browser.ts +0 -10
  316. package/src/server/security/index.ts +0 -94
  317. package/src/vite/helpers/boot.ts +0 -106
  318. package/src/vite/plugins/viteAlephaDev.ts +0 -177
  319. package/src/vite/tasks/devServer.ts +0 -69
  320. package/src/vite/tasks/runAlepha.ts +0 -270
  321. /package/src/{server/security → security}/primitives/$basicAuth.ts +0 -0
  322. /package/src/{server/security → security}/providers/ServerBasicAuthProvider.ts +0 -0
@@ -0,0 +1,789 @@
1
+ import type { TArray, TObject, TSchema, TUnion } from "typebox";
2
+ import { AlephaError } from "../errors/AlephaError.ts";
3
+ import { $hook } from "../primitives/$hook.ts";
4
+ import { SchemaCodec } from "./SchemaCodec.ts";
5
+ import { type Static, t } from "./TypeProvider.ts";
6
+
7
+ // =============================================================================
8
+ // Keyless JSON Codec
9
+ // =============================================================================
10
+ // Schema-driven JSON encoding without keys:
11
+ // - Schema defines field order → no keys needed in output
12
+ // - Uses native JSON.stringify on arrays (fast!)
13
+ // - Uses native JSON.parse for decoding (blazing fast)
14
+ // - 50-56% smaller than JSON, decode 1.7-2x faster
15
+ //
16
+ // Example:
17
+ // JSON: {"name":"Alice","age":30,"active":true} (39 bytes)
18
+ // Keyless: ["Alice",30,true] (17 bytes)
19
+ // =============================================================================
20
+
21
+ // Security: Keys that could enable prototype pollution attacks
22
+ const UNSAFE_KEYS = new Set(["__proto__", "constructor", "prototype"]);
23
+
24
+ export interface KeylessCodec<T = any> {
25
+ encode: (value: T) => string;
26
+ decode: (str: string) => T;
27
+ }
28
+
29
+ export interface KeylessCodecOptions {
30
+ /**
31
+ * Whether to use `new Function()` for code compilation.
32
+ * When false, uses an interpreter-based approach (safer but slower).
33
+ *
34
+ * @default Auto-detected: false in browser (CSP compatibility), true on server
35
+ */
36
+ useFunctionCompilation?: boolean;
37
+
38
+ /**
39
+ * Maximum allowed array length during encoding/decoding.
40
+ * Prevents DoS attacks via large arrays.
41
+ *
42
+ * @default 10000
43
+ */
44
+ maxArrayLength?: number;
45
+
46
+ /**
47
+ * Maximum allowed string length during encoding/decoding.
48
+ * Prevents DoS attacks via large strings.
49
+ *
50
+ * @default 1000000 (1MB)
51
+ */
52
+ maxStringLength?: number;
53
+
54
+ /**
55
+ * Maximum recursion depth for nested objects.
56
+ * Prevents stack overflow attacks.
57
+ *
58
+ * @default 50
59
+ */
60
+ maxDepth?: number;
61
+ }
62
+
63
+ /**
64
+ * KeylessJsonSchemaCodec provides schema-driven JSON encoding without keys.
65
+ *
66
+ * It uses the schema to determine field order, allowing the encoded output
67
+ * to be a simple JSON array instead of an object with keys.
68
+ */
69
+ export class KeylessJsonSchemaCodec extends SchemaCodec {
70
+ protected readonly cache = new Map<TSchema, KeylessCodec>();
71
+ protected readonly textEncoder = new TextEncoder();
72
+ protected readonly textDecoder = new TextDecoder();
73
+ protected varCounter = 0;
74
+
75
+ // Options with defaults
76
+ protected useFunctionCompilation = true;
77
+ protected maxArrayLength = 10000;
78
+ protected maxStringLength = 1000000;
79
+ protected maxDepth = 50;
80
+
81
+ /**
82
+ * Configure codec options.
83
+ */
84
+ public configure(options: KeylessCodecOptions): this {
85
+ if (options.useFunctionCompilation !== undefined) {
86
+ this.useFunctionCompilation = options.useFunctionCompilation;
87
+ this.cache.clear(); // Clear cache when compilation mode changes
88
+ }
89
+ if (options.maxArrayLength !== undefined) {
90
+ this.maxArrayLength = options.maxArrayLength;
91
+ }
92
+ if (options.maxStringLength !== undefined) {
93
+ this.maxStringLength = options.maxStringLength;
94
+ }
95
+ if (options.maxDepth !== undefined) {
96
+ this.maxDepth = options.maxDepth;
97
+ }
98
+ return this;
99
+ }
100
+
101
+ /**
102
+ * Hook to auto-detect safe mode on configure.
103
+ * Disables function compilation in browser by default.
104
+ */
105
+ protected onConfigure = $hook({
106
+ on: "configure",
107
+ handler: () => {
108
+ // Auto-detect: disable function compilation in browser (CSP compatibility)
109
+ // and test if eval/Function is available
110
+ this.useFunctionCompilation = this.canUseFunction();
111
+ },
112
+ });
113
+
114
+ /**
115
+ * Encode value to a keyless JSON string.
116
+ */
117
+ public encodeToString<T extends TSchema>(
118
+ schema: T,
119
+ value: Static<T>,
120
+ ): string {
121
+ return this.getCodec(schema).encode(value);
122
+ }
123
+
124
+ /**
125
+ * Encode value to binary (UTF-8 encoded keyless JSON).
126
+ */
127
+ public encodeToBinary<T extends TSchema>(
128
+ schema: T,
129
+ value: Static<T>,
130
+ ): Uint8Array {
131
+ return this.textEncoder.encode(this.encodeToString(schema, value));
132
+ }
133
+
134
+ /**
135
+ * Decode keyless JSON string or binary to value.
136
+ */
137
+ public decode<T>(schema: TSchema, value: unknown): T {
138
+ if (value instanceof Uint8Array) {
139
+ const text = this.textDecoder.decode(value);
140
+ return this.getCodec(schema).decode(text) as T;
141
+ }
142
+
143
+ if (typeof value === "string") {
144
+ return this.getCodec(schema).decode(value) as T;
145
+ }
146
+
147
+ // If already an array (parsed JSON), reconstruct object
148
+ if (Array.isArray(value)) {
149
+ return this.reconstructObject(schema, value) as T;
150
+ }
151
+
152
+ return value as T;
153
+ }
154
+
155
+ // ===========================================================================
156
+ // Security Validation
157
+ // ===========================================================================
158
+
159
+ /**
160
+ * Test if `new Function()` is available (not blocked by CSP).
161
+ */
162
+ protected canUseFunction(): boolean {
163
+ try {
164
+ const fn = new Function("return true");
165
+ return fn() === true;
166
+ } catch {
167
+ return false;
168
+ }
169
+ }
170
+
171
+ /**
172
+ * Validate schema keys for prototype pollution.
173
+ * Uses a visited set to avoid infinite recursion on recursive schemas.
174
+ */
175
+ protected validateSchemaKeys(
176
+ schema: TSchema,
177
+ depth = 0,
178
+ visited = new Set<TSchema>(),
179
+ ): void {
180
+ // Avoid infinite recursion on recursive schemas
181
+ if (visited.has(schema)) {
182
+ return;
183
+ }
184
+ visited.add(schema);
185
+
186
+ if (depth > this.maxDepth) {
187
+ throw new AlephaError(
188
+ `Schema depth exceeds maximum allowed (${this.maxDepth})`,
189
+ );
190
+ }
191
+
192
+ if (t.schema.isObject(schema)) {
193
+ const objSchema = schema as TObject;
194
+ const props = objSchema.properties as Record<string, TSchema>;
195
+
196
+ for (const key of Object.keys(props)) {
197
+ if (UNSAFE_KEYS.has(key)) {
198
+ throw new AlephaError(
199
+ `Unsafe schema key "${key}" detected. This key is blocked to prevent prototype pollution.`,
200
+ );
201
+ }
202
+ // Depth increases for object properties
203
+ this.validateSchemaKeys(props[key], depth + 1, visited);
204
+ }
205
+ } else if (t.schema.isArray(schema)) {
206
+ const arrSchema = schema as TArray;
207
+ // Depth increases for array items
208
+ this.validateSchemaKeys(arrSchema.items, depth + 1, visited);
209
+ } else if (t.schema.isUnion(schema) || t.schema.isOptional(schema)) {
210
+ // Optional/union wrappers don't increase depth - they're type modifiers
211
+ this.validateSchemaKeys(this.unwrap(schema), depth, visited);
212
+ }
213
+ }
214
+
215
+ /**
216
+ * Validate array length.
217
+ */
218
+ protected validateArrayLength(arr: unknown[]): void {
219
+ if (arr.length > this.maxArrayLength) {
220
+ throw new AlephaError(
221
+ `Array length (${arr.length}) exceeds maximum allowed (${this.maxArrayLength})`,
222
+ );
223
+ }
224
+ }
225
+
226
+ /**
227
+ * Validate string length.
228
+ */
229
+ protected validateStringLength(str: string): void {
230
+ if (str.length > this.maxStringLength) {
231
+ throw new AlephaError(
232
+ `String length (${str.length}) exceeds maximum allowed (${this.maxStringLength})`,
233
+ );
234
+ }
235
+ }
236
+
237
+ // ===========================================================================
238
+ // Codec Compilation
239
+ // ===========================================================================
240
+
241
+ /**
242
+ * Get a compiled codec for the given schema.
243
+ * Codecs are cached for reuse.
244
+ */
245
+ protected getCodec<T>(schema: TSchema): KeylessCodec<T> {
246
+ let c = this.cache.get(schema);
247
+ if (!c) {
248
+ c = this.useFunctionCompilation
249
+ ? this.compileWithFunction(schema)
250
+ : this.compileInterpreted(schema);
251
+ this.cache.set(schema, c);
252
+ }
253
+ return c as KeylessCodec<T>;
254
+ }
255
+
256
+ protected nextVar(): string {
257
+ return `_${this.varCounter++}`;
258
+ }
259
+
260
+ /**
261
+ * Compile codec using `new Function()` for maximum performance.
262
+ * Only used when CSP allows and useFunctionCompilation is true.
263
+ */
264
+ protected compileWithFunction(schema: TSchema): KeylessCodec {
265
+ this.varCounter = 0;
266
+ const encBody = this.genEnc(schema, "v");
267
+
268
+ this.varCounter = 0;
269
+ const decBody = this.genDec(schema);
270
+
271
+ const encoder = new Function("v", `return JSON.stringify(${encBody});`) as (
272
+ value: any,
273
+ ) => string;
274
+
275
+ const decoder = new Function(
276
+ "s",
277
+ `const a=JSON.parse(s);let i=0;${decBody.code}return ${decBody.result};`,
278
+ ) as (str: string) => any;
279
+
280
+ return { encode: encoder, decode: decoder };
281
+ }
282
+
283
+ /**
284
+ * Compile codec using interpreter-based approach.
285
+ * Safer (no eval/Function) but slower. Used in browser by default.
286
+ */
287
+ protected compileInterpreted(schema: TSchema): KeylessCodec {
288
+ const self = this;
289
+
290
+ return {
291
+ encode(value: any): string {
292
+ return JSON.stringify(self.interpretEncode(schema, value));
293
+ },
294
+ decode(str: string): any {
295
+ const ctx = { arr: JSON.parse(str), i: 0 };
296
+ return self.interpretDecode(schema, ctx);
297
+ },
298
+ };
299
+ }
300
+
301
+ // ===========================================================================
302
+ // Interpreter-based Encoding (Safe Mode)
303
+ // ===========================================================================
304
+
305
+ protected interpretEncode(schema: TSchema, value: any): any {
306
+ if (
307
+ t.schema.isString(schema) ||
308
+ t.schema.isNumber(schema) ||
309
+ t.schema.isInteger(schema) ||
310
+ t.schema.isBoolean(schema) ||
311
+ this.isEnum(schema)
312
+ ) {
313
+ return value;
314
+ }
315
+
316
+ if (t.schema.isBigInt(schema)) {
317
+ return `${value}n`;
318
+ }
319
+
320
+ if (t.schema.isArray(schema)) {
321
+ const arrSchema = schema as TArray;
322
+ if (!Array.isArray(value)) return value;
323
+
324
+ if (
325
+ t.schema.isString(arrSchema.items) ||
326
+ t.schema.isNumber(arrSchema.items) ||
327
+ t.schema.isInteger(arrSchema.items) ||
328
+ t.schema.isBoolean(arrSchema.items)
329
+ ) {
330
+ return value;
331
+ }
332
+ return value.map((e) => this.interpretEncode(arrSchema.items, e));
333
+ }
334
+
335
+ if (t.schema.isObject(schema)) {
336
+ const objSchema = schema as TObject;
337
+ const props = objSchema.properties as Record<string, TSchema>;
338
+ const keys = Object.keys(props);
339
+ const req = new Set((objSchema.required as string[]) || []);
340
+
341
+ const result: any[] = [];
342
+ for (const k of keys) {
343
+ const ps = props[k];
344
+ const isOpt = !req.has(k) || t.schema.isOptional(ps);
345
+ const isNullable = this.isNullable(ps);
346
+ const inner = this.unwrap(ps);
347
+ const v = value[k];
348
+
349
+ if (isOpt) {
350
+ result.push(v !== undefined ? this.interpretEncode(inner, v) : null);
351
+ } else if (isNullable) {
352
+ result.push(v !== null ? this.interpretEncode(inner, v) : null);
353
+ } else {
354
+ result.push(this.interpretEncode(inner, v));
355
+ }
356
+ }
357
+ return result;
358
+ }
359
+
360
+ if (t.schema.isOptional(schema) || t.schema.isUnion(schema)) {
361
+ const inner = this.unwrap(schema);
362
+ if (this.isNullable(schema)) {
363
+ return value !== null ? this.interpretEncode(inner, value) : null;
364
+ }
365
+ return value !== undefined ? this.interpretEncode(inner, value) : null;
366
+ }
367
+
368
+ return value;
369
+ }
370
+
371
+ // ===========================================================================
372
+ // Interpreter-based Decoding (Safe Mode)
373
+ // ===========================================================================
374
+
375
+ protected interpretDecode(
376
+ schema: TSchema,
377
+ ctx: { arr: any[]; i: number },
378
+ ): any {
379
+ if (
380
+ t.schema.isString(schema) ||
381
+ t.schema.isNumber(schema) ||
382
+ t.schema.isInteger(schema) ||
383
+ t.schema.isBoolean(schema) ||
384
+ this.isEnum(schema)
385
+ ) {
386
+ return ctx.arr[ctx.i++];
387
+ }
388
+
389
+ if (t.schema.isBigInt(schema)) {
390
+ return BigInt(ctx.arr[ctx.i++].slice(0, -1));
391
+ }
392
+
393
+ if (t.schema.isArray(schema)) {
394
+ const arrSchema = schema as TArray;
395
+ const arr = ctx.arr[ctx.i++];
396
+ if (!Array.isArray(arr)) return arr;
397
+
398
+ if (t.schema.isObject(arrSchema.items)) {
399
+ return arr.map((e) =>
400
+ this.interpretDecodeFromValue(arrSchema.items, e),
401
+ );
402
+ }
403
+ return arr;
404
+ }
405
+
406
+ if (t.schema.isObject(schema)) {
407
+ const objSchema = schema as TObject;
408
+ const props = objSchema.properties as Record<string, TSchema>;
409
+ const keys = Object.keys(props);
410
+ const req = new Set((objSchema.required as string[]) || []);
411
+
412
+ const result: Record<string, any> = {};
413
+
414
+ for (const k of keys) {
415
+ const ps = props[k];
416
+ const isOpt = !req.has(k) || t.schema.isOptional(ps);
417
+ const isNullable = this.isNullable(ps);
418
+ const inner = this.unwrap(ps);
419
+ const val = ctx.arr[ctx.i++];
420
+
421
+ if (isOpt) {
422
+ if (val !== null) {
423
+ result[k] = this.interpretDecodeFromValue(inner, val);
424
+ }
425
+ } else if (isNullable) {
426
+ result[k] =
427
+ val === null ? null : this.interpretDecodeFromValue(inner, val);
428
+ } else {
429
+ result[k] = this.interpretDecodeFromValue(inner, val);
430
+ }
431
+ }
432
+
433
+ return result;
434
+ }
435
+
436
+ if (t.schema.isOptional(schema) || t.schema.isUnion(schema)) {
437
+ const inner = this.unwrap(schema);
438
+ const val = ctx.arr[ctx.i++];
439
+
440
+ if (val === null) {
441
+ return this.isNullable(schema) ? null : undefined;
442
+ }
443
+
444
+ if (t.schema.isObject(inner) || t.schema.isArray(inner)) {
445
+ return this.interpretDecodeFromValue(inner, val);
446
+ }
447
+
448
+ return val;
449
+ }
450
+
451
+ return ctx.arr[ctx.i++];
452
+ }
453
+
454
+ protected interpretDecodeFromValue(schema: TSchema, value: any): any {
455
+ if (
456
+ t.schema.isString(schema) ||
457
+ t.schema.isNumber(schema) ||
458
+ t.schema.isInteger(schema) ||
459
+ t.schema.isBoolean(schema) ||
460
+ this.isEnum(schema)
461
+ ) {
462
+ return value;
463
+ }
464
+
465
+ if (t.schema.isBigInt(schema)) {
466
+ return BigInt(value.slice(0, -1));
467
+ }
468
+
469
+ if (t.schema.isArray(schema)) {
470
+ if (!Array.isArray(value)) return value;
471
+ const arrSchema = schema as TArray;
472
+ if (t.schema.isObject(arrSchema.items)) {
473
+ return value.map((e) =>
474
+ this.interpretDecodeFromValue(arrSchema.items, e),
475
+ );
476
+ }
477
+ return value;
478
+ }
479
+
480
+ if (t.schema.isObject(schema)) {
481
+ const objSchema = schema as TObject;
482
+ const props = objSchema.properties as Record<string, TSchema>;
483
+ const keys = Object.keys(props);
484
+ const result: Record<string, any> = {};
485
+
486
+ for (let idx = 0; idx < keys.length; idx++) {
487
+ const k = keys[idx];
488
+ const inner = this.unwrap(props[k]);
489
+ const v = value[idx];
490
+
491
+ if (t.schema.isObject(inner)) {
492
+ result[k] = this.interpretDecodeFromValue(inner, v);
493
+ } else if (t.schema.isBigInt(inner)) {
494
+ result[k] = BigInt(v.slice(0, -1));
495
+ } else {
496
+ result[k] = v;
497
+ }
498
+ }
499
+
500
+ return result;
501
+ }
502
+
503
+ return value;
504
+ }
505
+
506
+ // ===========================================================================
507
+ // Encoder - generates code that returns an array representation
508
+ // ===========================================================================
509
+
510
+ protected genEnc(schema: TSchema, ve: string): string {
511
+ if (
512
+ t.schema.isString(schema) ||
513
+ t.schema.isNumber(schema) ||
514
+ t.schema.isInteger(schema) ||
515
+ t.schema.isBoolean(schema) ||
516
+ this.isEnum(schema)
517
+ ) {
518
+ return ve;
519
+ }
520
+
521
+ if (t.schema.isBigInt(schema)) {
522
+ return `${ve}+'n'`;
523
+ }
524
+
525
+ if (t.schema.isArray(schema)) {
526
+ const arrSchema = schema as TArray;
527
+ const itemEnc = this.genEnc(arrSchema.items, "e");
528
+ if (
529
+ t.schema.isString(arrSchema.items) ||
530
+ t.schema.isNumber(arrSchema.items) ||
531
+ t.schema.isInteger(arrSchema.items) ||
532
+ t.schema.isBoolean(arrSchema.items)
533
+ ) {
534
+ return ve;
535
+ }
536
+ return `${ve}.map(e=>${itemEnc})`;
537
+ }
538
+
539
+ if (t.schema.isObject(schema)) {
540
+ const objSchema = schema as TObject;
541
+ const props = objSchema.properties as Record<string, TSchema>;
542
+ const keys = Object.keys(props);
543
+ const req = new Set((objSchema.required as string[]) || []);
544
+
545
+ const parts: string[] = [];
546
+ for (const k of keys) {
547
+ const ps = props[k];
548
+ const isOpt = !req.has(k) || t.schema.isOptional(ps);
549
+ const isNullable = this.isNullable(ps);
550
+ const inner = this.unwrap(ps);
551
+ const innerEnc = this.genEnc(inner, `${ve}.${k}`);
552
+
553
+ if (isOpt) {
554
+ parts.push(`${ve}.${k}!==undefined?${innerEnc}:null`);
555
+ } else if (isNullable) {
556
+ parts.push(`${ve}.${k}!==null?${innerEnc}:null`);
557
+ } else {
558
+ parts.push(innerEnc);
559
+ }
560
+ }
561
+
562
+ return `[${parts.join(",")}]`;
563
+ }
564
+
565
+ if (t.schema.isOptional(schema) || t.schema.isUnion(schema)) {
566
+ const inner = this.unwrap(schema);
567
+ const innerEnc = this.genEnc(inner, ve);
568
+ if (this.isNullable(schema)) {
569
+ return `${ve}!==null?${innerEnc}:null`;
570
+ }
571
+ return `${ve}!==undefined?${innerEnc}:null`;
572
+ }
573
+
574
+ return ve;
575
+ }
576
+
577
+ // ===========================================================================
578
+ // Decoder - generates code to reconstruct object from parsed array
579
+ // ===========================================================================
580
+
581
+ protected genDec(schema: TSchema): { code: string; result: string } {
582
+ const v = this.nextVar();
583
+
584
+ if (
585
+ t.schema.isString(schema) ||
586
+ t.schema.isNumber(schema) ||
587
+ t.schema.isInteger(schema) ||
588
+ t.schema.isBoolean(schema) ||
589
+ this.isEnum(schema)
590
+ ) {
591
+ return { code: "", result: "a[i++]" };
592
+ }
593
+
594
+ if (t.schema.isBigInt(schema)) {
595
+ return { code: "", result: "BigInt(a[i++].slice(0,-1))" };
596
+ }
597
+
598
+ if (t.schema.isArray(schema)) {
599
+ const arrSchema = schema as TArray;
600
+ // Check if array items need transformation (objects)
601
+ if (t.schema.isObject(arrSchema.items)) {
602
+ const itemTransform = this.genDecFromValue(arrSchema.items, "e");
603
+ return { code: "", result: `a[i++].map(e=>${itemTransform})` };
604
+ }
605
+ return { code: "", result: "a[i++]" };
606
+ }
607
+
608
+ if (t.schema.isObject(schema)) {
609
+ const objSchema = schema as TObject;
610
+ const props = objSchema.properties as Record<string, TSchema>;
611
+ const keys = Object.keys(props);
612
+ const req = new Set((objSchema.required as string[]) || []);
613
+
614
+ // Check if simple (all required primitives)
615
+ let simple = true;
616
+ for (const k of keys) {
617
+ const ps = props[k];
618
+ const isOpt = !req.has(k) || t.schema.isOptional(ps);
619
+ const isNullable = this.isNullable(ps);
620
+ const inner = this.unwrap(ps);
621
+ if (
622
+ isOpt ||
623
+ isNullable ||
624
+ t.schema.isObject(inner) ||
625
+ t.schema.isArray(inner)
626
+ ) {
627
+ simple = false;
628
+ break;
629
+ }
630
+ }
631
+
632
+ if (simple) {
633
+ const fields = keys.map((k) => `${k}:a[i++]`);
634
+ return { code: "", result: `{${fields.join(",")}}` };
635
+ }
636
+
637
+ let code = `const ${v}={};`;
638
+ for (const k of keys) {
639
+ const ps = props[k];
640
+ const isOpt = !req.has(k) || t.schema.isOptional(ps);
641
+ const isNullable = this.isNullable(ps);
642
+ const inner = this.unwrap(ps);
643
+
644
+ if (isOpt) {
645
+ const nested = this.genDecFromValue(inner, "t");
646
+ code += `{const t=a[i++];if(t!==null){${v}.${k}=${nested};}}`;
647
+ } else if (isNullable) {
648
+ const nested = this.genDecFromValue(inner, "t");
649
+ code += `{const t=a[i++];if(t===null){${v}.${k}=null;}else{${v}.${k}=${nested};}}`;
650
+ } else if (t.schema.isObject(inner)) {
651
+ const nested = this.genDecFromValue(inner, "a[i++]");
652
+ code += `${v}.${k}=${nested};`;
653
+ } else if (t.schema.isArray(inner)) {
654
+ // Handle arrays - check if items need transformation
655
+ const arrSchema = inner as TArray;
656
+ if (t.schema.isObject(arrSchema.items)) {
657
+ const itemTransform = this.genDecFromValue(arrSchema.items, "e");
658
+ code += `${v}.${k}=a[i++].map(e=>${itemTransform});`;
659
+ } else {
660
+ code += `${v}.${k}=a[i++];`;
661
+ }
662
+ } else {
663
+ code += `${v}.${k}=a[i++];`;
664
+ }
665
+ }
666
+
667
+ return { code, result: v };
668
+ }
669
+
670
+ if (t.schema.isOptional(schema) || t.schema.isUnion(schema)) {
671
+ const inner = this.unwrap(schema);
672
+ const innerDec = this.genDec(inner);
673
+ const nullVal = this.isNullable(schema) ? "null" : "undefined";
674
+ return {
675
+ code: `const ${v}t=a[i++];let ${v};if(${v}t===null){${v}=${nullVal};}else{${innerDec.code.replace(/a\[i\+\+\]/g, `${v}t`)}${v}=${innerDec.result.replace(/a\[i\+\+\]/g, `${v}t`)};}`,
676
+ result: v,
677
+ };
678
+ }
679
+
680
+ return { code: "", result: "a[i++]" };
681
+ }
682
+
683
+ protected genDecFromValue(schema: TSchema, expr: string): string {
684
+ if (
685
+ t.schema.isString(schema) ||
686
+ t.schema.isNumber(schema) ||
687
+ t.schema.isInteger(schema) ||
688
+ t.schema.isBoolean(schema) ||
689
+ this.isEnum(schema)
690
+ ) {
691
+ return expr;
692
+ }
693
+ if (t.schema.isBigInt(schema)) {
694
+ return `BigInt(${expr}.slice(0,-1))`;
695
+ }
696
+ if (t.schema.isArray(schema)) {
697
+ return expr;
698
+ }
699
+ if (t.schema.isObject(schema)) {
700
+ const objSchema = schema as TObject;
701
+ const props = objSchema.properties as Record<string, TSchema>;
702
+ const keys = Object.keys(props);
703
+ const v = this.nextVar();
704
+ const fields = keys.map((k, idx) => {
705
+ const inner = this.unwrap(props[k]);
706
+ const innerExpr = `${v}[${idx}]`;
707
+ if (t.schema.isObject(inner)) {
708
+ return `${k}:${this.genDecFromValue(inner, innerExpr)}`;
709
+ }
710
+ if (t.schema.isBigInt(inner)) {
711
+ return `${k}:BigInt(${innerExpr}.slice(0,-1))`;
712
+ }
713
+ return `${k}:${innerExpr}`;
714
+ });
715
+ return `((${v}=${expr})=>({${fields.join(",")}}))()`;
716
+ }
717
+ return expr;
718
+ }
719
+
720
+ // ===========================================================================
721
+ // Helpers
722
+ // ===========================================================================
723
+
724
+ protected isEnum(schema: TSchema): boolean {
725
+ return (
726
+ "enum" in schema &&
727
+ Array.isArray((schema as { enum?: unknown[] }).enum) &&
728
+ ((schema as { enum?: unknown[] }).enum?.length ?? 0) > 0
729
+ );
730
+ }
731
+
732
+ protected isNullable(schema: TSchema): boolean {
733
+ if (!t.schema.isUnion(schema)) return false;
734
+ const unionSchema = schema as TUnion;
735
+ return unionSchema.anyOf?.some((s: TSchema) => t.schema.isNull(s)) ?? false;
736
+ }
737
+
738
+ protected unwrap(schema: TSchema): TSchema {
739
+ if ("anyOf" in schema && Array.isArray((schema as TUnion).anyOf)) {
740
+ const unionSchema = schema as TUnion;
741
+ return (
742
+ unionSchema.anyOf.find((s: TSchema) => !t.schema.isNull(s)) || schema
743
+ );
744
+ }
745
+ return schema;
746
+ }
747
+
748
+ /**
749
+ * Reconstruct an object from a parsed array (for when input is already parsed).
750
+ */
751
+ protected reconstructObject(schema: TSchema, arr: any[]): any {
752
+ if (!t.schema.isObject(schema)) return arr;
753
+
754
+ const objSchema = schema as TObject;
755
+ const props = objSchema.properties as Record<string, TSchema>;
756
+ const keys = Object.keys(props);
757
+ const result: Record<string, any> = {};
758
+ let i = 0;
759
+
760
+ for (const k of keys) {
761
+ const ps = props[k];
762
+ const isOpt = t.schema.isOptional(ps);
763
+ const isNullable = this.isNullable(ps);
764
+ const inner = this.unwrap(ps);
765
+ const val = arr[i++];
766
+
767
+ if (isOpt) {
768
+ if (val !== null) {
769
+ result[k] = t.schema.isObject(inner)
770
+ ? this.reconstructObject(inner, val)
771
+ : val;
772
+ }
773
+ } else if (isNullable) {
774
+ result[k] =
775
+ val === null
776
+ ? null
777
+ : t.schema.isObject(inner)
778
+ ? this.reconstructObject(inner, val)
779
+ : val;
780
+ } else {
781
+ result[k] = t.schema.isObject(inner)
782
+ ? this.reconstructObject(inner, val)
783
+ : val;
784
+ }
785
+ }
786
+
787
+ return result;
788
+ }
789
+ }