alepha 0.14.3 → 0.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (317) hide show
  1. package/README.md +2 -5
  2. package/dist/api/audits/index.d.ts +620 -811
  3. package/dist/api/audits/index.d.ts.map +1 -1
  4. package/dist/api/files/index.d.ts +185 -377
  5. package/dist/api/files/index.d.ts.map +1 -1
  6. package/dist/api/files/index.js +0 -1
  7. package/dist/api/files/index.js.map +1 -1
  8. package/dist/api/jobs/index.d.ts +245 -435
  9. package/dist/api/jobs/index.d.ts.map +1 -1
  10. package/dist/api/notifications/index.d.ts +238 -429
  11. package/dist/api/notifications/index.d.ts.map +1 -1
  12. package/dist/api/parameters/index.d.ts +236 -427
  13. package/dist/api/parameters/index.d.ts.map +1 -1
  14. package/dist/api/users/index.browser.js +1 -2
  15. package/dist/api/users/index.browser.js.map +1 -1
  16. package/dist/api/users/index.d.ts +1010 -1196
  17. package/dist/api/users/index.d.ts.map +1 -1
  18. package/dist/api/users/index.js +178 -151
  19. package/dist/api/users/index.js.map +1 -1
  20. package/dist/api/verifications/index.d.ts +17 -17
  21. package/dist/api/verifications/index.d.ts.map +1 -1
  22. package/dist/batch/index.d.ts +122 -122
  23. package/dist/batch/index.d.ts.map +1 -1
  24. package/dist/batch/index.js +1 -2
  25. package/dist/batch/index.js.map +1 -1
  26. package/dist/bucket/index.d.ts +163 -163
  27. package/dist/bucket/index.d.ts.map +1 -1
  28. package/dist/cache/core/index.d.ts +46 -46
  29. package/dist/cache/core/index.d.ts.map +1 -1
  30. package/dist/cache/redis/index.d.ts.map +1 -1
  31. package/dist/cli/index.d.ts +384 -285
  32. package/dist/cli/index.d.ts.map +1 -1
  33. package/dist/cli/index.js +1113 -623
  34. package/dist/cli/index.js.map +1 -1
  35. package/dist/command/index.d.ts +299 -300
  36. package/dist/command/index.d.ts.map +1 -1
  37. package/dist/command/index.js +13 -9
  38. package/dist/command/index.js.map +1 -1
  39. package/dist/core/index.browser.js +445 -103
  40. package/dist/core/index.browser.js.map +1 -1
  41. package/dist/core/index.d.ts +733 -625
  42. package/dist/core/index.d.ts.map +1 -1
  43. package/dist/core/index.js +446 -103
  44. package/dist/core/index.js.map +1 -1
  45. package/dist/core/index.native.js +445 -103
  46. package/dist/core/index.native.js.map +1 -1
  47. package/dist/datetime/index.d.ts +44 -44
  48. package/dist/datetime/index.d.ts.map +1 -1
  49. package/dist/datetime/index.js +4 -4
  50. package/dist/datetime/index.js.map +1 -1
  51. package/dist/email/index.d.ts +97 -50
  52. package/dist/email/index.d.ts.map +1 -1
  53. package/dist/email/index.js +129 -33
  54. package/dist/email/index.js.map +1 -1
  55. package/dist/fake/index.d.ts +7981 -14
  56. package/dist/fake/index.d.ts.map +1 -1
  57. package/dist/file/index.d.ts +523 -390
  58. package/dist/file/index.d.ts.map +1 -1
  59. package/dist/file/index.js +253 -1
  60. package/dist/file/index.js.map +1 -1
  61. package/dist/lock/core/index.d.ts +208 -208
  62. package/dist/lock/core/index.d.ts.map +1 -1
  63. package/dist/lock/redis/index.d.ts.map +1 -1
  64. package/dist/logger/index.d.ts +25 -26
  65. package/dist/logger/index.d.ts.map +1 -1
  66. package/dist/logger/index.js +12 -2
  67. package/dist/logger/index.js.map +1 -1
  68. package/dist/mcp/index.d.ts +197 -197
  69. package/dist/mcp/index.d.ts.map +1 -1
  70. package/dist/mcp/index.js +1 -1
  71. package/dist/mcp/index.js.map +1 -1
  72. package/dist/orm/chunk-DtkW-qnP.js +38 -0
  73. package/dist/orm/index.browser.js.map +1 -1
  74. package/dist/orm/index.bun.js +2814 -0
  75. package/dist/orm/index.bun.js.map +1 -0
  76. package/dist/orm/index.d.ts +1228 -1216
  77. package/dist/orm/index.d.ts.map +1 -1
  78. package/dist/orm/index.js +2041 -1967
  79. package/dist/orm/index.js.map +1 -1
  80. package/dist/queue/core/index.d.ts +248 -248
  81. package/dist/queue/core/index.d.ts.map +1 -1
  82. package/dist/queue/redis/index.d.ts.map +1 -1
  83. package/dist/redis/index.bun.js +285 -0
  84. package/dist/redis/index.bun.js.map +1 -0
  85. package/dist/redis/index.d.ts +118 -136
  86. package/dist/redis/index.d.ts.map +1 -1
  87. package/dist/redis/index.js +18 -38
  88. package/dist/redis/index.js.map +1 -1
  89. package/dist/retry/index.d.ts +69 -69
  90. package/dist/retry/index.d.ts.map +1 -1
  91. package/dist/router/index.d.ts +6 -6
  92. package/dist/router/index.d.ts.map +1 -1
  93. package/dist/scheduler/index.d.ts +25 -25
  94. package/dist/scheduler/index.d.ts.map +1 -1
  95. package/dist/security/index.browser.js +5 -1
  96. package/dist/security/index.browser.js.map +1 -1
  97. package/dist/security/index.d.ts +417 -254
  98. package/dist/security/index.d.ts.map +1 -1
  99. package/dist/security/index.js +386 -86
  100. package/dist/security/index.js.map +1 -1
  101. package/dist/server/auth/index.d.ts +110 -110
  102. package/dist/server/auth/index.d.ts.map +1 -1
  103. package/dist/server/auth/index.js +20 -20
  104. package/dist/server/auth/index.js.map +1 -1
  105. package/dist/server/cache/index.d.ts +62 -47
  106. package/dist/server/cache/index.d.ts.map +1 -1
  107. package/dist/server/cache/index.js +56 -3
  108. package/dist/server/cache/index.js.map +1 -1
  109. package/dist/server/compress/index.d.ts +6 -0
  110. package/dist/server/compress/index.d.ts.map +1 -1
  111. package/dist/server/compress/index.js +36 -1
  112. package/dist/server/compress/index.js.map +1 -1
  113. package/dist/server/cookies/index.d.ts +6 -6
  114. package/dist/server/cookies/index.d.ts.map +1 -1
  115. package/dist/server/cookies/index.js +3 -3
  116. package/dist/server/cookies/index.js.map +1 -1
  117. package/dist/server/core/index.browser.js +2 -2
  118. package/dist/server/core/index.browser.js.map +1 -1
  119. package/dist/server/core/index.d.ts +242 -150
  120. package/dist/server/core/index.d.ts.map +1 -1
  121. package/dist/server/core/index.js +294 -125
  122. package/dist/server/core/index.js.map +1 -1
  123. package/dist/server/cors/index.d.ts +11 -12
  124. package/dist/server/cors/index.d.ts.map +1 -1
  125. package/dist/server/health/index.d.ts +0 -1
  126. package/dist/server/health/index.d.ts.map +1 -1
  127. package/dist/server/helmet/index.d.ts +2 -2
  128. package/dist/server/helmet/index.d.ts.map +1 -1
  129. package/dist/server/links/index.browser.js.map +1 -1
  130. package/dist/server/links/index.d.ts +123 -124
  131. package/dist/server/links/index.d.ts.map +1 -1
  132. package/dist/server/links/index.js +1 -2
  133. package/dist/server/links/index.js.map +1 -1
  134. package/dist/server/metrics/index.d.ts.map +1 -1
  135. package/dist/server/multipart/index.d.ts +6 -6
  136. package/dist/server/multipart/index.d.ts.map +1 -1
  137. package/dist/server/proxy/index.d.ts +102 -103
  138. package/dist/server/proxy/index.d.ts.map +1 -1
  139. package/dist/server/rate-limit/index.d.ts +16 -16
  140. package/dist/server/rate-limit/index.d.ts.map +1 -1
  141. package/dist/server/static/index.d.ts +44 -44
  142. package/dist/server/static/index.d.ts.map +1 -1
  143. package/dist/server/static/index.js +4 -0
  144. package/dist/server/static/index.js.map +1 -1
  145. package/dist/server/swagger/index.d.ts +48 -49
  146. package/dist/server/swagger/index.d.ts.map +1 -1
  147. package/dist/server/swagger/index.js +3 -5
  148. package/dist/server/swagger/index.js.map +1 -1
  149. package/dist/sms/index.d.ts +13 -11
  150. package/dist/sms/index.d.ts.map +1 -1
  151. package/dist/sms/index.js +7 -7
  152. package/dist/sms/index.js.map +1 -1
  153. package/dist/thread/index.d.ts +71 -72
  154. package/dist/thread/index.d.ts.map +1 -1
  155. package/dist/topic/core/index.d.ts +318 -318
  156. package/dist/topic/core/index.d.ts.map +1 -1
  157. package/dist/topic/redis/index.d.ts +6 -6
  158. package/dist/topic/redis/index.d.ts.map +1 -1
  159. package/dist/vite/index.d.ts +5805 -249
  160. package/dist/vite/index.d.ts.map +1 -1
  161. package/dist/vite/index.js +599 -513
  162. package/dist/vite/index.js.map +1 -1
  163. package/dist/websocket/index.browser.js +6 -6
  164. package/dist/websocket/index.browser.js.map +1 -1
  165. package/dist/websocket/index.d.ts +247 -247
  166. package/dist/websocket/index.d.ts.map +1 -1
  167. package/dist/websocket/index.js +6 -6
  168. package/dist/websocket/index.js.map +1 -1
  169. package/package.json +9 -14
  170. package/src/api/files/controllers/AdminFileStatsController.ts +0 -1
  171. package/src/api/users/atoms/realmAuthSettingsAtom.ts +5 -0
  172. package/src/api/users/controllers/{UserRealmController.ts → RealmController.ts} +11 -11
  173. package/src/api/users/entities/users.ts +1 -1
  174. package/src/api/users/index.ts +8 -8
  175. package/src/api/users/primitives/{$userRealm.ts → $realm.ts} +17 -19
  176. package/src/api/users/providers/{UserRealmProvider.ts → RealmProvider.ts} +26 -30
  177. package/src/api/users/schemas/{userRealmConfigSchema.ts → realmConfigSchema.ts} +2 -2
  178. package/src/api/users/services/CredentialService.ts +7 -7
  179. package/src/api/users/services/IdentityService.ts +4 -4
  180. package/src/api/users/services/RegistrationService.spec.ts +25 -27
  181. package/src/api/users/services/RegistrationService.ts +38 -27
  182. package/src/api/users/services/SessionCrudService.ts +3 -3
  183. package/src/api/users/services/SessionService.spec.ts +3 -3
  184. package/src/api/users/services/SessionService.ts +28 -9
  185. package/src/api/users/services/UserService.ts +7 -7
  186. package/src/batch/providers/BatchProvider.ts +1 -2
  187. package/src/cli/apps/AlephaCli.ts +0 -2
  188. package/src/cli/apps/AlephaPackageBuilderCli.ts +38 -19
  189. package/src/cli/assets/apiHelloControllerTs.ts +18 -0
  190. package/src/cli/assets/apiIndexTs.ts +16 -0
  191. package/src/cli/assets/claudeMd.ts +303 -0
  192. package/src/cli/assets/mainBrowserTs.ts +2 -2
  193. package/src/cli/assets/mainServerTs.ts +24 -0
  194. package/src/cli/assets/webAppRouterTs.ts +15 -0
  195. package/src/cli/assets/webHelloComponentTsx.ts +16 -0
  196. package/src/cli/assets/webIndexTs.ts +16 -0
  197. package/src/cli/atoms/buildOptions.ts +88 -0
  198. package/src/cli/commands/build.ts +70 -87
  199. package/src/cli/commands/db.ts +21 -22
  200. package/src/cli/commands/deploy.ts +17 -5
  201. package/src/cli/commands/dev.ts +22 -14
  202. package/src/cli/commands/format.ts +8 -2
  203. package/src/cli/commands/gen/env.ts +53 -0
  204. package/src/cli/commands/gen/openapi.ts +1 -1
  205. package/src/cli/commands/gen/resource.ts +15 -0
  206. package/src/cli/commands/gen.ts +7 -1
  207. package/src/cli/commands/init.ts +74 -30
  208. package/src/cli/commands/lint.ts +8 -2
  209. package/src/cli/commands/test.ts +8 -3
  210. package/src/cli/commands/typecheck.ts +5 -1
  211. package/src/cli/commands/verify.ts +5 -3
  212. package/src/cli/defineConfig.ts +49 -7
  213. package/src/cli/index.ts +0 -1
  214. package/src/cli/services/AlephaCliUtils.ts +39 -589
  215. package/src/cli/services/PackageManagerUtils.ts +301 -0
  216. package/src/cli/services/ProjectScaffolder.ts +306 -0
  217. package/src/command/helpers/Runner.spec.ts +2 -2
  218. package/src/command/helpers/Runner.ts +16 -4
  219. package/src/command/primitives/$command.ts +0 -6
  220. package/src/command/providers/CliProvider.ts +1 -3
  221. package/src/core/Alepha.ts +42 -0
  222. package/src/core/__tests__/Alepha-graph.spec.ts +4 -0
  223. package/src/core/index.shared.ts +1 -0
  224. package/src/core/index.ts +2 -0
  225. package/src/core/primitives/$hook.ts +6 -2
  226. package/src/core/primitives/$module.spec.ts +4 -0
  227. package/src/core/providers/AlsProvider.ts +1 -1
  228. package/src/core/providers/CodecManager.spec.ts +12 -6
  229. package/src/core/providers/CodecManager.ts +26 -6
  230. package/src/core/providers/EventManager.ts +169 -13
  231. package/src/core/providers/KeylessJsonSchemaCodec.spec.ts +621 -0
  232. package/src/core/providers/KeylessJsonSchemaCodec.ts +407 -0
  233. package/src/core/providers/StateManager.spec.ts +27 -16
  234. package/src/email/providers/LocalEmailProvider.spec.ts +111 -87
  235. package/src/email/providers/LocalEmailProvider.ts +52 -15
  236. package/src/email/providers/NodemailerEmailProvider.ts +167 -56
  237. package/src/file/errors/FileError.ts +7 -0
  238. package/src/file/index.ts +9 -1
  239. package/src/file/providers/MemoryFileSystemProvider.ts +393 -0
  240. package/src/logger/index.ts +15 -3
  241. package/src/mcp/transports/StdioMcpTransport.ts +1 -1
  242. package/src/orm/index.browser.ts +1 -19
  243. package/src/orm/index.bun.ts +77 -0
  244. package/src/orm/index.shared-server.ts +22 -0
  245. package/src/orm/index.shared.ts +15 -0
  246. package/src/orm/index.ts +13 -39
  247. package/src/orm/providers/drivers/BunPostgresProvider.ts +3 -5
  248. package/src/orm/providers/drivers/BunSqliteProvider.ts +1 -1
  249. package/src/orm/providers/drivers/CloudflareD1Provider.ts +4 -0
  250. package/src/orm/providers/drivers/DatabaseProvider.ts +4 -0
  251. package/src/orm/providers/drivers/PglitePostgresProvider.ts +4 -0
  252. package/src/orm/services/Repository.ts +8 -0
  253. package/src/queue/core/providers/WorkerProvider.spec.ts +48 -32
  254. package/src/redis/index.bun.ts +35 -0
  255. package/src/redis/providers/BunRedisProvider.ts +12 -43
  256. package/src/redis/providers/BunRedisSubscriberProvider.ts +2 -3
  257. package/src/redis/providers/NodeRedisProvider.ts +16 -34
  258. package/src/{server/security → security}/__tests__/BasicAuth.spec.ts +11 -11
  259. package/src/{server/security → security}/__tests__/ServerSecurityProvider-realm.spec.ts +21 -16
  260. package/src/{server/security/providers → security/__tests__}/ServerSecurityProvider.spec.ts +5 -5
  261. package/src/security/index.browser.ts +5 -0
  262. package/src/security/index.ts +90 -7
  263. package/src/security/primitives/{$realm.spec.ts → $issuer.spec.ts} +11 -11
  264. package/src/security/primitives/{$realm.ts → $issuer.ts} +20 -17
  265. package/src/security/primitives/$role.ts +5 -5
  266. package/src/security/primitives/$serviceAccount.spec.ts +5 -5
  267. package/src/security/primitives/$serviceAccount.ts +3 -3
  268. package/src/{server/security → security}/providers/ServerSecurityProvider.ts +5 -7
  269. package/src/server/auth/primitives/$auth.ts +10 -10
  270. package/src/server/auth/primitives/$authCredentials.ts +3 -3
  271. package/src/server/auth/primitives/$authGithub.ts +3 -3
  272. package/src/server/auth/primitives/$authGoogle.ts +3 -3
  273. package/src/server/auth/providers/ServerAuthProvider.ts +13 -13
  274. package/src/server/cache/providers/ServerCacheProvider.spec.ts +183 -0
  275. package/src/server/cache/providers/ServerCacheProvider.ts +95 -10
  276. package/src/server/compress/providers/ServerCompressProvider.ts +61 -2
  277. package/src/server/cookies/providers/ServerCookiesProvider.ts +3 -3
  278. package/src/server/core/helpers/ServerReply.ts +2 -2
  279. package/src/server/core/providers/NodeHttpServerProvider.ts +25 -6
  280. package/src/server/core/providers/ServerBodyParserProvider.ts +19 -23
  281. package/src/server/core/providers/ServerLoggerProvider.ts +23 -19
  282. package/src/server/core/providers/ServerProvider.ts +155 -22
  283. package/src/server/core/providers/ServerRouterProvider.ts +259 -115
  284. package/src/server/core/providers/ServerTimingProvider.ts +2 -2
  285. package/src/server/links/index.ts +1 -1
  286. package/src/server/links/providers/LinkProvider.ts +1 -1
  287. package/src/server/static/providers/ServerStaticProvider.ts +10 -0
  288. package/src/server/swagger/index.ts +1 -1
  289. package/src/server/swagger/providers/ServerSwaggerProvider.ts +5 -8
  290. package/src/sms/providers/LocalSmsProvider.spec.ts +153 -111
  291. package/src/sms/providers/LocalSmsProvider.ts +8 -7
  292. package/src/vite/helpers/boot.ts +28 -17
  293. package/src/vite/helpers/importViteReact.ts +13 -0
  294. package/src/vite/index.ts +1 -21
  295. package/src/vite/plugins/viteAlephaDev.ts +16 -1
  296. package/src/vite/plugins/viteAlephaSsrPreload.ts +222 -0
  297. package/src/vite/tasks/buildClient.ts +11 -0
  298. package/src/vite/tasks/buildServer.ts +59 -4
  299. package/src/vite/tasks/devServer.ts +71 -0
  300. package/src/vite/tasks/generateCloudflare.ts +7 -0
  301. package/src/vite/tasks/index.ts +2 -1
  302. package/dist/server/security/index.browser.js +0 -13
  303. package/dist/server/security/index.browser.js.map +0 -1
  304. package/dist/server/security/index.d.ts +0 -173
  305. package/dist/server/security/index.d.ts.map +0 -1
  306. package/dist/server/security/index.js +0 -311
  307. package/dist/server/security/index.js.map +0 -1
  308. package/src/cli/assets/appRouterTs.ts +0 -9
  309. package/src/cli/assets/mainTs.ts +0 -13
  310. package/src/cli/assets/viteConfigTs.ts +0 -14
  311. package/src/cli/commands/run.ts +0 -24
  312. package/src/server/security/index.browser.ts +0 -10
  313. package/src/server/security/index.ts +0 -94
  314. package/src/vite/plugins/viteAlepha.ts +0 -37
  315. package/src/vite/plugins/viteAlephaBuild.ts +0 -281
  316. /package/src/{server/security → security}/primitives/$basicAuth.ts +0 -0
  317. /package/src/{server/security → security}/providers/ServerBasicAuthProvider.ts +0 -0
@@ -0,0 +1,621 @@
1
+ import { Alepha, t } from "alepha";
2
+ import { describe, test } from "vitest";
3
+
4
+ describe("KeylessJsonSchemaCodec", () => {
5
+ describe("Basic types", () => {
6
+ test("should encode and decode primitive types", async ({ expect }) => {
7
+ const alepha = Alepha.create();
8
+
9
+ const userSchema = t.object({
10
+ name: t.text(),
11
+ age: t.integer(),
12
+ active: t.boolean(),
13
+ score: t.number(),
14
+ });
15
+
16
+ const data = {
17
+ name: "Alice",
18
+ age: 30,
19
+ active: true,
20
+ score: 98.5,
21
+ };
22
+
23
+ const encoded = alepha.codec.encode(userSchema, data, {
24
+ as: "string",
25
+ encoder: "keyless",
26
+ });
27
+
28
+ // Keyless format is an array
29
+ expect(encoded).toBe('["Alice",30,true,98.5]');
30
+
31
+ const decoded = alepha.codec.decode(userSchema, encoded, {
32
+ encoder: "keyless",
33
+ });
34
+
35
+ expect(decoded).toEqual(data);
36
+ });
37
+
38
+ test("should produce smaller output than JSON", async ({ expect }) => {
39
+ const alepha = Alepha.create();
40
+
41
+ const userSchema = t.object({
42
+ username: t.text(),
43
+ email: t.text(),
44
+ age: t.integer(),
45
+ isVerified: t.boolean(),
46
+ });
47
+
48
+ const data = {
49
+ username: "john_doe",
50
+ email: "john@example.com",
51
+ age: 25,
52
+ isVerified: true,
53
+ };
54
+
55
+ const jsonEncoded = alepha.codec.encode(userSchema, data, {
56
+ as: "string",
57
+ encoder: "json",
58
+ });
59
+
60
+ const keylessEncoded = alepha.codec.encode(userSchema, data, {
61
+ as: "string",
62
+ encoder: "keyless",
63
+ });
64
+
65
+ // Keyless should be smaller (no keys)
66
+ expect(keylessEncoded.length).toBeLessThan(jsonEncoded.length);
67
+
68
+ // Both should decode to same data
69
+ const jsonDecoded = alepha.codec.decode(userSchema, jsonEncoded, {
70
+ encoder: "json",
71
+ });
72
+ const keylessDecoded = alepha.codec.decode(userSchema, keylessEncoded, {
73
+ encoder: "keyless",
74
+ });
75
+
76
+ expect(jsonDecoded).toEqual(data);
77
+ expect(keylessDecoded).toEqual(data);
78
+ });
79
+
80
+ test("should handle bigint values as strings", async ({ expect }) => {
81
+ const alepha = Alepha.create();
82
+
83
+ // In Alepha, t.bigint() is a string type with format "bigint"
84
+ // It represents large integers as strings to avoid precision loss
85
+ const schema = t.object({
86
+ id: t.bigint(),
87
+ name: t.text(),
88
+ });
89
+
90
+ const data = {
91
+ id: "9007199254740993",
92
+ name: "Test",
93
+ };
94
+
95
+ const encoded = alepha.codec.encode(schema, data, {
96
+ as: "string",
97
+ encoder: "keyless",
98
+ });
99
+
100
+ // BigInt in Alepha is stored as a string
101
+ expect(encoded).toBe('["9007199254740993","Test"]');
102
+
103
+ const decoded = alepha.codec.decode(schema, encoded, {
104
+ encoder: "keyless",
105
+ });
106
+
107
+ expect(decoded.id).toBe("9007199254740993");
108
+ expect(decoded.name).toBe("Test");
109
+ });
110
+ });
111
+
112
+ describe("Nested objects", () => {
113
+ test("should handle nested objects", async ({ expect }) => {
114
+ const alepha = Alepha.create();
115
+
116
+ const schema = t.object({
117
+ user: t.object({
118
+ name: t.text(),
119
+ profile: t.object({
120
+ bio: t.text(),
121
+ age: t.integer(),
122
+ }),
123
+ }),
124
+ });
125
+
126
+ const data = {
127
+ user: {
128
+ name: "Alice",
129
+ profile: {
130
+ bio: "Developer",
131
+ age: 30,
132
+ },
133
+ },
134
+ };
135
+
136
+ const encoded = alepha.codec.encode(schema, data, {
137
+ as: "string",
138
+ encoder: "keyless",
139
+ });
140
+
141
+ // Nested objects become nested arrays
142
+ expect(encoded).toBe('[["Alice",["Developer",30]]]');
143
+
144
+ const decoded = alepha.codec.decode(schema, encoded, {
145
+ encoder: "keyless",
146
+ });
147
+
148
+ expect(decoded).toEqual(data);
149
+ });
150
+ });
151
+
152
+ describe("Arrays", () => {
153
+ test("should handle arrays of primitives", async ({ expect }) => {
154
+ const alepha = Alepha.create();
155
+
156
+ const schema = t.object({
157
+ tags: t.array(t.text()),
158
+ scores: t.array(t.number()),
159
+ });
160
+
161
+ const data = {
162
+ tags: ["typescript", "nodejs"],
163
+ scores: [95.5, 88.0, 92.3],
164
+ };
165
+
166
+ const encoded = alepha.codec.encode(schema, data, {
167
+ as: "string",
168
+ encoder: "keyless",
169
+ });
170
+
171
+ const decoded = alepha.codec.decode(schema, encoded, {
172
+ encoder: "keyless",
173
+ });
174
+
175
+ expect(decoded).toEqual(data);
176
+ });
177
+
178
+ test("should handle arrays of objects", async ({ expect }) => {
179
+ const alepha = Alepha.create();
180
+
181
+ const schema = t.object({
182
+ users: t.array(
183
+ t.object({
184
+ name: t.text(),
185
+ age: t.integer(),
186
+ }),
187
+ ),
188
+ socialProfiles: t.array(
189
+ t.object({
190
+ platform: t.text(),
191
+ username: t.text(),
192
+ }),
193
+ ),
194
+ });
195
+
196
+ const data = {
197
+ users: [
198
+ { name: "Alice", age: 30 },
199
+ { name: "Bob", age: 25 },
200
+ ],
201
+ socialProfiles: [
202
+ { platform: "twitter", username: "alice" },
203
+ { platform: "github", username: "alice123" },
204
+ ],
205
+ };
206
+
207
+ const encoded = alepha.codec.encode(schema, data, {
208
+ as: "string",
209
+ encoder: "keyless",
210
+ });
211
+
212
+ // Arrays of objects should be encoded as nested arrays
213
+ expect(encoded).toBe(
214
+ '[[["Alice",30],["Bob",25]],[["twitter","alice"],["github","alice123"]]]',
215
+ );
216
+
217
+ const decoded = alepha.codec.decode(schema, encoded, {
218
+ encoder: "keyless",
219
+ });
220
+
221
+ expect(decoded).toEqual(data);
222
+ });
223
+ });
224
+
225
+ describe("Optional and nullable types", () => {
226
+ test("should handle optional fields", async ({ expect }) => {
227
+ const alepha = Alepha.create();
228
+
229
+ const schema = t.object({
230
+ name: t.text(),
231
+ bio: t.optional(t.text()),
232
+ });
233
+
234
+ const dataWithBio = {
235
+ name: "Alice",
236
+ bio: "Developer",
237
+ };
238
+
239
+ const dataWithoutBio = {
240
+ name: "Bob",
241
+ };
242
+
243
+ // With optional field present
244
+ const encodedWith = alepha.codec.encode(schema, dataWithBio, {
245
+ as: "string",
246
+ encoder: "keyless",
247
+ });
248
+ const decodedWith = alepha.codec.decode(schema, encodedWith, {
249
+ encoder: "keyless",
250
+ });
251
+ expect(decodedWith).toEqual(dataWithBio);
252
+
253
+ // With optional field missing
254
+ const encodedWithout = alepha.codec.encode(schema, dataWithoutBio, {
255
+ as: "string",
256
+ encoder: "keyless",
257
+ });
258
+ const decodedWithout = alepha.codec.decode(schema, encodedWithout, {
259
+ encoder: "keyless",
260
+ });
261
+ expect(decodedWithout.name).toBe("Bob");
262
+ expect(decodedWithout.bio).toBeUndefined();
263
+ });
264
+
265
+ test("should handle nullable fields", async ({ expect }) => {
266
+ const alepha = Alepha.create();
267
+
268
+ const schema = t.object({
269
+ name: t.text(),
270
+ deletedAt: t.nullable(t.datetime()),
271
+ });
272
+
273
+ const activeUser = {
274
+ name: "Alice",
275
+ deletedAt: null,
276
+ };
277
+
278
+ const deletedUser = {
279
+ name: "Bob",
280
+ deletedAt: "2024-01-15T10:00:00Z",
281
+ };
282
+
283
+ // Active user (null deletedAt)
284
+ const encodedActive = alepha.codec.encode(schema, activeUser, {
285
+ as: "string",
286
+ encoder: "keyless",
287
+ });
288
+ const decodedActive = alepha.codec.decode(schema, encodedActive, {
289
+ encoder: "keyless",
290
+ });
291
+ expect(decodedActive.name).toBe("Alice");
292
+ expect(decodedActive.deletedAt).toBeNull();
293
+
294
+ // Deleted user (non-null deletedAt)
295
+ const encodedDeleted = alepha.codec.encode(schema, deletedUser, {
296
+ as: "string",
297
+ encoder: "keyless",
298
+ });
299
+ const decodedDeleted = alepha.codec.decode(schema, encodedDeleted, {
300
+ encoder: "keyless",
301
+ });
302
+ expect(decodedDeleted).toEqual(deletedUser);
303
+ });
304
+ });
305
+
306
+ describe("Enums", () => {
307
+ test("should handle enum values", async ({ expect }) => {
308
+ const alepha = Alepha.create();
309
+
310
+ const schema = t.object({
311
+ status: t.enum(["ACTIVE", "INACTIVE", "PENDING"]),
312
+ name: t.text(),
313
+ });
314
+
315
+ const data = {
316
+ status: "ACTIVE",
317
+ name: "Test",
318
+ };
319
+
320
+ const encoded = alepha.codec.encode(schema, data, {
321
+ as: "string",
322
+ encoder: "keyless",
323
+ });
324
+
325
+ const decoded = alepha.codec.decode(schema, encoded, {
326
+ encoder: "keyless",
327
+ });
328
+
329
+ expect(decoded).toEqual(data);
330
+ });
331
+ });
332
+
333
+ describe("Binary encoding", () => {
334
+ test("should encode and decode binary format", async ({ expect }) => {
335
+ const alepha = Alepha.create();
336
+
337
+ const schema = t.object({
338
+ name: t.text(),
339
+ age: t.integer(),
340
+ });
341
+
342
+ const data = {
343
+ name: "Alice",
344
+ age: 30,
345
+ };
346
+
347
+ const binary = alepha.codec.encode(schema, data, {
348
+ as: "binary",
349
+ encoder: "keyless",
350
+ });
351
+
352
+ expect(binary).toBeInstanceOf(Uint8Array);
353
+
354
+ const decoded = alepha.codec.decode(schema, binary, {
355
+ encoder: "keyless",
356
+ });
357
+
358
+ expect(decoded).toEqual(data);
359
+ });
360
+ });
361
+
362
+ describe("Complex schemas", () => {
363
+ test("should handle complex nested structures", async ({ expect }) => {
364
+ const alepha = Alepha.create();
365
+
366
+ const schema = t.object({
367
+ user: t.object({
368
+ id: t.text(),
369
+ profile: t.object({
370
+ name: t.text(),
371
+ age: t.nullable(t.integer()),
372
+ tags: t.array(t.text()),
373
+ }),
374
+ }),
375
+ status: t.enum(["ACTIVE", "INACTIVE"]),
376
+ });
377
+
378
+ const data = {
379
+ user: {
380
+ id: "123",
381
+ profile: {
382
+ name: "Alice",
383
+ age: 30,
384
+ tags: ["developer", "typescript"],
385
+ },
386
+ },
387
+ status: "ACTIVE",
388
+ };
389
+
390
+ const encoded = alepha.codec.encode(schema, data, {
391
+ as: "string",
392
+ encoder: "keyless",
393
+ });
394
+
395
+ const decoded = alepha.codec.decode(schema, encoded, {
396
+ encoder: "keyless",
397
+ });
398
+
399
+ expect(decoded).toEqual(data);
400
+ });
401
+
402
+ test("should handle comprehensive schema with all types", async ({
403
+ expect,
404
+ }) => {
405
+ const alepha = Alepha.create();
406
+
407
+ // Comprehensive schema with all supported types
408
+ const comprehensiveSchema = t.object({
409
+ // Primitive types
410
+ id: t.integer(),
411
+ uuid: t.uuid(),
412
+ name: t.text(),
413
+ email: t.text(),
414
+ score: t.number(),
415
+ isActive: t.boolean(),
416
+ bigNumber: t.bigint(),
417
+
418
+ // Date/time types (stored as strings)
419
+ createdAt: t.datetime(),
420
+ updatedAt: t.datetime(),
421
+
422
+ // Enum type
423
+ status: t.enum(["ACTIVE", "INACTIVE", "PENDING"]),
424
+ role: t.enum(["USER", "ADMIN", "MODERATOR"]),
425
+
426
+ // Optional fields
427
+ nickname: t.optional(t.text()),
428
+ bio: t.optional(t.text()),
429
+
430
+ // Nullable fields
431
+ deletedAt: t.nullable(t.datetime()),
432
+ lastLoginAt: t.nullable(t.datetime()),
433
+
434
+ // Arrays of primitives
435
+ tags: t.array(t.text()),
436
+ scores: t.array(t.number()),
437
+ flags: t.array(t.boolean()),
438
+
439
+ // Nested object
440
+ profile: t.object({
441
+ firstName: t.text(),
442
+ lastName: t.text(),
443
+ age: t.integer(),
444
+ }),
445
+
446
+ // Deeply nested objects
447
+ settings: t.object({
448
+ theme: t.text(),
449
+ preferences: t.object({
450
+ notifications: t.boolean(),
451
+ emailAlerts: t.boolean(),
452
+ language: t.text(),
453
+ }),
454
+ }),
455
+
456
+ // Arrays of objects
457
+ contacts: t.array(
458
+ t.object({
459
+ type: t.text(),
460
+ value: t.text(),
461
+ }),
462
+ ),
463
+
464
+ // Nested arrays of objects
465
+ socialProfiles: t.array(
466
+ t.object({
467
+ platform: t.text(),
468
+ username: t.text(),
469
+ verified: t.boolean(),
470
+ }),
471
+ ),
472
+
473
+ // Optional nested object
474
+ address: t.optional(
475
+ t.object({
476
+ street: t.text(),
477
+ city: t.text(),
478
+ country: t.text(),
479
+ postalCode: t.text(),
480
+ }),
481
+ ),
482
+
483
+ // Nullable nested object
484
+ company: t.nullable(
485
+ t.object({
486
+ name: t.text(),
487
+ position: t.text(),
488
+ }),
489
+ ),
490
+ });
491
+
492
+ const fullData = {
493
+ id: 12345,
494
+ uuid: "550e8400-e29b-41d4-a716-446655440000",
495
+ name: "John Doe",
496
+ email: "john.doe@example.com",
497
+ score: 98.75,
498
+ isActive: true,
499
+ bigNumber: "9007199254740993",
500
+ createdAt: "2023-01-15T10:30:00Z",
501
+ updatedAt: "2024-06-20T14:45:30Z",
502
+ status: "ACTIVE",
503
+ role: "ADMIN",
504
+ nickname: "johnny",
505
+ bio: "Software developer and tech enthusiast",
506
+ deletedAt: null,
507
+ lastLoginAt: "2024-06-20T14:00:00Z",
508
+ tags: ["developer", "typescript", "nodejs", "premium"],
509
+ scores: [95.5, 88.0, 92.3, 100.0],
510
+ flags: [true, false, true, true],
511
+ profile: {
512
+ firstName: "John",
513
+ lastName: "Doe",
514
+ age: 35,
515
+ },
516
+ settings: {
517
+ theme: "dark",
518
+ preferences: {
519
+ notifications: true,
520
+ emailAlerts: false,
521
+ language: "en-US",
522
+ },
523
+ },
524
+ contacts: [
525
+ { type: "phone", value: "+1234567890" },
526
+ { type: "fax", value: "+0987654321" },
527
+ ],
528
+ socialProfiles: [
529
+ { platform: "twitter", username: "johndoe", verified: true },
530
+ { platform: "github", username: "johndoe123", verified: false },
531
+ { platform: "linkedin", username: "john-doe", verified: true },
532
+ ],
533
+ address: {
534
+ street: "123 Main Street",
535
+ city: "San Francisco",
536
+ country: "USA",
537
+ postalCode: "94102",
538
+ },
539
+ company: {
540
+ name: "Tech Corp",
541
+ position: "Senior Developer",
542
+ },
543
+ };
544
+
545
+ const encoded = alepha.codec.encode(comprehensiveSchema, fullData, {
546
+ as: "string",
547
+ encoder: "keyless",
548
+ });
549
+
550
+ const decoded = alepha.codec.decode(comprehensiveSchema, encoded, {
551
+ encoder: "keyless",
552
+ });
553
+
554
+ expect(decoded).toEqual(fullData);
555
+
556
+ // Test with missing optional fields
557
+ const partialData = {
558
+ id: 12345,
559
+ uuid: "550e8400-e29b-41d4-a716-446655440000",
560
+ name: "Jane Doe",
561
+ email: "jane.doe@example.com",
562
+ score: 85.5,
563
+ isActive: false,
564
+ bigNumber: "123456789",
565
+ createdAt: "2023-02-20T08:00:00Z",
566
+ updatedAt: "2024-05-15T12:30:00Z",
567
+ status: "PENDING",
568
+ role: "USER",
569
+ // nickname and bio are omitted (optional)
570
+ deletedAt: "2024-01-01T00:00:00Z", // not null this time
571
+ lastLoginAt: null,
572
+ tags: [],
573
+ scores: [75.0],
574
+ flags: [false],
575
+ profile: {
576
+ firstName: "Jane",
577
+ lastName: "Doe",
578
+ age: 28,
579
+ },
580
+ settings: {
581
+ theme: "light",
582
+ preferences: {
583
+ notifications: false,
584
+ emailAlerts: true,
585
+ language: "fr-FR",
586
+ },
587
+ },
588
+ contacts: [],
589
+ socialProfiles: [
590
+ { platform: "instagram", username: "janedoe", verified: false },
591
+ ],
592
+ // address is omitted (optional)
593
+ company: null, // nullable field set to null
594
+ };
595
+
596
+ const encodedPartial = alepha.codec.encode(
597
+ comprehensiveSchema,
598
+ partialData,
599
+ {
600
+ as: "string",
601
+ encoder: "keyless",
602
+ },
603
+ );
604
+
605
+ const decodedPartial = alepha.codec.decode(
606
+ comprehensiveSchema,
607
+ encodedPartial,
608
+ {
609
+ encoder: "keyless",
610
+ },
611
+ );
612
+
613
+ expect(decodedPartial).toEqual(partialData);
614
+
615
+ // Verify size reduction
616
+ const jsonSize = JSON.stringify(fullData).length;
617
+ const keylessSize = encoded.length;
618
+ expect(keylessSize).toBeLessThan(jsonSize);
619
+ });
620
+ });
621
+ });