alepha 0.14.4 → 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.
- package/README.md +1 -4
- package/dist/api/audits/index.d.ts +619 -731
- package/dist/api/audits/index.d.ts.map +1 -1
- package/dist/api/files/index.d.ts +185 -298
- package/dist/api/files/index.d.ts.map +1 -1
- package/dist/api/files/index.js +0 -1
- package/dist/api/files/index.js.map +1 -1
- package/dist/api/jobs/index.d.ts +245 -356
- package/dist/api/jobs/index.d.ts.map +1 -1
- package/dist/api/notifications/index.d.ts +238 -350
- package/dist/api/notifications/index.d.ts.map +1 -1
- package/dist/api/parameters/index.d.ts +499 -611
- package/dist/api/parameters/index.d.ts.map +1 -1
- package/dist/api/users/index.browser.js +1 -2
- package/dist/api/users/index.browser.js.map +1 -1
- package/dist/api/users/index.d.ts +1697 -1804
- package/dist/api/users/index.d.ts.map +1 -1
- package/dist/api/users/index.js +178 -151
- package/dist/api/users/index.js.map +1 -1
- package/dist/api/verifications/index.d.ts +132 -132
- package/dist/api/verifications/index.d.ts.map +1 -1
- package/dist/batch/index.d.ts +122 -122
- package/dist/batch/index.d.ts.map +1 -1
- package/dist/batch/index.js +1 -2
- package/dist/batch/index.js.map +1 -1
- package/dist/bucket/index.d.ts +163 -163
- package/dist/bucket/index.d.ts.map +1 -1
- package/dist/cache/core/index.d.ts +46 -46
- package/dist/cache/core/index.d.ts.map +1 -1
- package/dist/cache/redis/index.d.ts.map +1 -1
- package/dist/cli/index.d.ts +302 -299
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +966 -564
- package/dist/cli/index.js.map +1 -1
- package/dist/command/index.d.ts +303 -299
- package/dist/command/index.d.ts.map +1 -1
- package/dist/command/index.js +11 -7
- package/dist/command/index.js.map +1 -1
- package/dist/core/index.browser.js +419 -99
- package/dist/core/index.browser.js.map +1 -1
- package/dist/core/index.d.ts +718 -625
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +420 -99
- package/dist/core/index.js.map +1 -1
- package/dist/core/index.native.js +419 -99
- package/dist/core/index.native.js.map +1 -1
- package/dist/datetime/index.d.ts +44 -44
- package/dist/datetime/index.d.ts.map +1 -1
- package/dist/datetime/index.js +4 -4
- package/dist/datetime/index.js.map +1 -1
- package/dist/email/index.d.ts +97 -50
- package/dist/email/index.d.ts.map +1 -1
- package/dist/email/index.js +129 -33
- package/dist/email/index.js.map +1 -1
- package/dist/fake/index.d.ts +7981 -14
- package/dist/fake/index.d.ts.map +1 -1
- package/dist/file/index.d.ts +523 -390
- package/dist/file/index.d.ts.map +1 -1
- package/dist/file/index.js +253 -1
- package/dist/file/index.js.map +1 -1
- package/dist/lock/core/index.d.ts +208 -208
- package/dist/lock/core/index.d.ts.map +1 -1
- package/dist/lock/redis/index.d.ts.map +1 -1
- package/dist/logger/index.d.ts +25 -26
- package/dist/logger/index.d.ts.map +1 -1
- package/dist/mcp/index.d.ts +197 -197
- package/dist/mcp/index.d.ts.map +1 -1
- package/dist/orm/chunk-DtkW-qnP.js +38 -0
- package/dist/orm/index.browser.js.map +1 -1
- package/dist/orm/index.bun.js +2814 -0
- package/dist/orm/index.bun.js.map +1 -0
- package/dist/orm/index.d.ts +1205 -1057
- package/dist/orm/index.d.ts.map +1 -1
- package/dist/orm/index.js +2056 -1753
- package/dist/orm/index.js.map +1 -1
- package/dist/queue/core/index.d.ts +248 -248
- package/dist/queue/core/index.d.ts.map +1 -1
- package/dist/queue/redis/index.d.ts.map +1 -1
- package/dist/redis/index.bun.js +285 -0
- package/dist/redis/index.bun.js.map +1 -0
- package/dist/redis/index.d.ts +118 -136
- package/dist/redis/index.d.ts.map +1 -1
- package/dist/redis/index.js +18 -38
- package/dist/redis/index.js.map +1 -1
- package/dist/retry/index.d.ts +69 -69
- package/dist/retry/index.d.ts.map +1 -1
- package/dist/router/index.d.ts +6 -6
- package/dist/router/index.d.ts.map +1 -1
- package/dist/scheduler/index.d.ts +25 -25
- package/dist/scheduler/index.d.ts.map +1 -1
- package/dist/security/index.browser.js +5 -1
- package/dist/security/index.browser.js.map +1 -1
- package/dist/security/index.d.ts +417 -254
- package/dist/security/index.d.ts.map +1 -1
- package/dist/security/index.js +386 -86
- package/dist/security/index.js.map +1 -1
- package/dist/server/auth/index.d.ts +277 -277
- package/dist/server/auth/index.d.ts.map +1 -1
- package/dist/server/auth/index.js +20 -20
- package/dist/server/auth/index.js.map +1 -1
- package/dist/server/cache/index.d.ts +60 -57
- package/dist/server/cache/index.d.ts.map +1 -1
- package/dist/server/cache/index.js +1 -1
- package/dist/server/cache/index.js.map +1 -1
- package/dist/server/compress/index.d.ts +3 -3
- package/dist/server/compress/index.d.ts.map +1 -1
- package/dist/server/cookies/index.d.ts +6 -6
- package/dist/server/cookies/index.d.ts.map +1 -1
- package/dist/server/cookies/index.js +3 -3
- package/dist/server/cookies/index.js.map +1 -1
- package/dist/server/core/index.d.ts +242 -150
- package/dist/server/core/index.d.ts.map +1 -1
- package/dist/server/core/index.js +288 -122
- package/dist/server/core/index.js.map +1 -1
- package/dist/server/cors/index.d.ts +11 -12
- package/dist/server/cors/index.d.ts.map +1 -1
- package/dist/server/health/index.d.ts +0 -1
- package/dist/server/health/index.d.ts.map +1 -1
- package/dist/server/helmet/index.d.ts +2 -2
- package/dist/server/helmet/index.d.ts.map +1 -1
- package/dist/server/links/index.browser.js.map +1 -1
- package/dist/server/links/index.d.ts +84 -85
- package/dist/server/links/index.d.ts.map +1 -1
- package/dist/server/links/index.js +1 -2
- package/dist/server/links/index.js.map +1 -1
- package/dist/server/metrics/index.d.ts.map +1 -1
- package/dist/server/multipart/index.d.ts +6 -6
- package/dist/server/multipart/index.d.ts.map +1 -1
- package/dist/server/proxy/index.d.ts +102 -103
- package/dist/server/proxy/index.d.ts.map +1 -1
- package/dist/server/rate-limit/index.d.ts +16 -16
- package/dist/server/rate-limit/index.d.ts.map +1 -1
- package/dist/server/static/index.d.ts +44 -44
- package/dist/server/static/index.d.ts.map +1 -1
- package/dist/server/swagger/index.d.ts +48 -49
- package/dist/server/swagger/index.d.ts.map +1 -1
- package/dist/server/swagger/index.js +1 -2
- package/dist/server/swagger/index.js.map +1 -1
- package/dist/sms/index.d.ts +13 -11
- package/dist/sms/index.d.ts.map +1 -1
- package/dist/sms/index.js +7 -7
- package/dist/sms/index.js.map +1 -1
- package/dist/thread/index.d.ts +71 -72
- package/dist/thread/index.d.ts.map +1 -1
- package/dist/topic/core/index.d.ts +318 -318
- package/dist/topic/core/index.d.ts.map +1 -1
- package/dist/topic/redis/index.d.ts +6 -6
- package/dist/topic/redis/index.d.ts.map +1 -1
- package/dist/vite/index.d.ts +5720 -159
- package/dist/vite/index.d.ts.map +1 -1
- package/dist/vite/index.js +41 -18
- package/dist/vite/index.js.map +1 -1
- package/dist/websocket/index.browser.js +6 -6
- package/dist/websocket/index.browser.js.map +1 -1
- package/dist/websocket/index.d.ts +247 -247
- package/dist/websocket/index.d.ts.map +1 -1
- package/dist/websocket/index.js +6 -6
- package/dist/websocket/index.js.map +1 -1
- package/package.json +9 -14
- package/src/api/files/controllers/AdminFileStatsController.ts +0 -1
- package/src/api/users/atoms/realmAuthSettingsAtom.ts +5 -0
- package/src/api/users/controllers/{UserRealmController.ts → RealmController.ts} +11 -11
- package/src/api/users/entities/users.ts +1 -1
- package/src/api/users/index.ts +8 -8
- package/src/api/users/primitives/{$userRealm.ts → $realm.ts} +17 -19
- package/src/api/users/providers/{UserRealmProvider.ts → RealmProvider.ts} +26 -30
- package/src/api/users/schemas/{userRealmConfigSchema.ts → realmConfigSchema.ts} +2 -2
- package/src/api/users/services/CredentialService.ts +7 -7
- package/src/api/users/services/IdentityService.ts +4 -4
- package/src/api/users/services/RegistrationService.spec.ts +25 -27
- package/src/api/users/services/RegistrationService.ts +38 -27
- package/src/api/users/services/SessionCrudService.ts +3 -3
- package/src/api/users/services/SessionService.spec.ts +3 -3
- package/src/api/users/services/SessionService.ts +28 -9
- package/src/api/users/services/UserService.ts +7 -7
- package/src/batch/providers/BatchProvider.ts +1 -2
- package/src/cli/apps/AlephaPackageBuilderCli.ts +38 -19
- package/src/cli/assets/apiHelloControllerTs.ts +18 -0
- package/src/cli/assets/apiIndexTs.ts +16 -0
- package/src/cli/assets/claudeMd.ts +303 -0
- package/src/cli/assets/mainBrowserTs.ts +2 -2
- package/src/cli/assets/mainServerTs.ts +24 -0
- package/src/cli/assets/webAppRouterTs.ts +15 -0
- package/src/cli/assets/webHelloComponentTsx.ts +16 -0
- package/src/cli/assets/webIndexTs.ts +16 -0
- package/src/cli/commands/build.ts +41 -21
- package/src/cli/commands/db.ts +21 -18
- package/src/cli/commands/deploy.ts +17 -5
- package/src/cli/commands/dev.ts +13 -17
- package/src/cli/commands/format.ts +8 -2
- package/src/cli/commands/init.ts +74 -29
- package/src/cli/commands/lint.ts +8 -2
- package/src/cli/commands/test.ts +8 -2
- package/src/cli/commands/typecheck.ts +5 -1
- package/src/cli/commands/verify.ts +4 -2
- package/src/cli/services/AlephaCliUtils.ts +39 -600
- package/src/cli/services/PackageManagerUtils.ts +301 -0
- package/src/cli/services/ProjectScaffolder.ts +306 -0
- package/src/command/helpers/Runner.ts +15 -3
- package/src/core/__tests__/Alepha-graph.spec.ts +4 -0
- package/src/core/index.shared.ts +1 -0
- package/src/core/index.ts +2 -0
- package/src/core/primitives/$hook.ts +6 -2
- package/src/core/primitives/$module.spec.ts +4 -0
- package/src/core/providers/AlsProvider.ts +1 -1
- package/src/core/providers/CodecManager.spec.ts +12 -6
- package/src/core/providers/CodecManager.ts +26 -6
- package/src/core/providers/EventManager.ts +169 -13
- package/src/core/providers/KeylessJsonSchemaCodec.spec.ts +621 -0
- package/src/core/providers/KeylessJsonSchemaCodec.ts +407 -0
- package/src/core/providers/StateManager.spec.ts +27 -16
- package/src/email/providers/LocalEmailProvider.spec.ts +111 -87
- package/src/email/providers/LocalEmailProvider.ts +52 -15
- package/src/email/providers/NodemailerEmailProvider.ts +167 -56
- package/src/file/errors/FileError.ts +7 -0
- package/src/file/index.ts +9 -1
- package/src/file/providers/MemoryFileSystemProvider.ts +393 -0
- package/src/orm/index.browser.ts +1 -19
- package/src/orm/index.bun.ts +77 -0
- package/src/orm/index.shared-server.ts +22 -0
- package/src/orm/index.shared.ts +15 -0
- package/src/orm/index.ts +19 -39
- package/src/orm/providers/drivers/BunPostgresProvider.ts +3 -5
- package/src/orm/providers/drivers/BunSqliteProvider.ts +1 -1
- package/src/orm/providers/drivers/CloudflareD1Provider.ts +4 -0
- package/src/orm/providers/drivers/DatabaseProvider.ts +4 -0
- package/src/orm/providers/drivers/PglitePostgresProvider.ts +4 -0
- package/src/orm/services/Repository.ts +8 -0
- package/src/redis/index.bun.ts +35 -0
- package/src/redis/providers/BunRedisProvider.ts +12 -43
- package/src/redis/providers/BunRedisSubscriberProvider.ts +2 -3
- package/src/redis/providers/NodeRedisProvider.ts +16 -34
- package/src/{server/security → security}/__tests__/BasicAuth.spec.ts +11 -11
- package/src/{server/security → security}/__tests__/ServerSecurityProvider-realm.spec.ts +21 -16
- package/src/{server/security/providers → security/__tests__}/ServerSecurityProvider.spec.ts +5 -5
- package/src/security/index.browser.ts +5 -0
- package/src/security/index.ts +90 -7
- package/src/security/primitives/{$realm.spec.ts → $issuer.spec.ts} +11 -11
- package/src/security/primitives/{$realm.ts → $issuer.ts} +20 -17
- package/src/security/primitives/$role.ts +5 -5
- package/src/security/primitives/$serviceAccount.spec.ts +5 -5
- package/src/security/primitives/$serviceAccount.ts +3 -3
- package/src/{server/security → security}/providers/ServerSecurityProvider.ts +5 -7
- package/src/server/auth/primitives/$auth.ts +10 -10
- package/src/server/auth/primitives/$authCredentials.ts +3 -3
- package/src/server/auth/primitives/$authGithub.ts +3 -3
- package/src/server/auth/primitives/$authGoogle.ts +3 -3
- package/src/server/auth/providers/ServerAuthProvider.ts +13 -13
- package/src/server/cache/providers/ServerCacheProvider.ts +1 -1
- package/src/server/cookies/providers/ServerCookiesProvider.ts +3 -3
- package/src/server/core/providers/NodeHttpServerProvider.ts +25 -6
- package/src/server/core/providers/ServerBodyParserProvider.ts +19 -23
- package/src/server/core/providers/ServerLoggerProvider.ts +23 -19
- package/src/server/core/providers/ServerProvider.ts +144 -21
- package/src/server/core/providers/ServerRouterProvider.ts +259 -115
- package/src/server/core/providers/ServerTimingProvider.ts +2 -2
- package/src/server/links/index.ts +1 -1
- package/src/server/links/providers/LinkProvider.ts +1 -1
- package/src/server/swagger/index.ts +1 -1
- package/src/sms/providers/LocalSmsProvider.spec.ts +153 -111
- package/src/sms/providers/LocalSmsProvider.ts +8 -7
- package/src/vite/helpers/boot.ts +28 -17
- package/src/vite/tasks/buildServer.ts +12 -1
- package/src/vite/tasks/devServer.ts +3 -1
- package/src/vite/tasks/generateCloudflare.ts +7 -0
- package/dist/server/security/index.browser.js +0 -13
- package/dist/server/security/index.browser.js.map +0 -1
- package/dist/server/security/index.d.ts +0 -173
- package/dist/server/security/index.d.ts.map +0 -1
- package/dist/server/security/index.js +0 -311
- package/dist/server/security/index.js.map +0 -1
- package/src/cli/assets/appRouterTs.ts +0 -9
- package/src/cli/assets/mainTs.ts +0 -13
- package/src/server/security/index.browser.ts +0 -10
- package/src/server/security/index.ts +0 -94
- /package/src/{server/security → security}/primitives/$basicAuth.ts +0 -0
- /package/src/{server/security → security}/providers/ServerBasicAuthProvider.ts +0 -0
|
@@ -0,0 +1,407 @@
|
|
|
1
|
+
import type { TArray, TObject, TSchema, TUnion } from "typebox";
|
|
2
|
+
import { SchemaCodec } from "./SchemaCodec.ts";
|
|
3
|
+
import { type Static, t } from "./TypeProvider.ts";
|
|
4
|
+
|
|
5
|
+
// =============================================================================
|
|
6
|
+
// Keyless JSON Codec
|
|
7
|
+
// =============================================================================
|
|
8
|
+
// Schema-driven JSON encoding without keys:
|
|
9
|
+
// - Schema defines field order → no keys needed in output
|
|
10
|
+
// - Uses native JSON.stringify on arrays (fast!)
|
|
11
|
+
// - Uses native JSON.parse for decoding (blazing fast)
|
|
12
|
+
// - 50-56% smaller than JSON, decode 1.7-2x faster
|
|
13
|
+
//
|
|
14
|
+
// Example:
|
|
15
|
+
// JSON: {"name":"Alice","age":30,"active":true} (39 bytes)
|
|
16
|
+
// Keyless: ["Alice",30,true] (17 bytes)
|
|
17
|
+
// =============================================================================
|
|
18
|
+
|
|
19
|
+
export interface KeylessCodec<T = any> {
|
|
20
|
+
encode: (value: T) => string;
|
|
21
|
+
decode: (str: string) => T;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* KeylessJsonSchemaCodec provides schema-driven JSON encoding without keys.
|
|
26
|
+
*
|
|
27
|
+
* It uses the schema to determine field order, allowing the encoded output
|
|
28
|
+
* to be a simple JSON array instead of an object with keys.
|
|
29
|
+
*
|
|
30
|
+
* Performance characteristics:
|
|
31
|
+
* - Encode: 0.94-1.53x vs JSON.stringify (faster for complex objects)
|
|
32
|
+
* - Decode: 1.76-2.00x vs JSON.parse
|
|
33
|
+
* - Size: 50-56% smaller than JSON
|
|
34
|
+
*/
|
|
35
|
+
export class KeylessJsonSchemaCodec extends SchemaCodec {
|
|
36
|
+
protected readonly cache = new Map<TSchema, KeylessCodec>();
|
|
37
|
+
protected readonly encoder = new TextEncoder();
|
|
38
|
+
protected readonly decoder = new TextDecoder();
|
|
39
|
+
protected varCounter = 0;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Encode value to a keyless JSON string.
|
|
43
|
+
*/
|
|
44
|
+
public encodeToString<T extends TSchema>(
|
|
45
|
+
schema: T,
|
|
46
|
+
value: Static<T>,
|
|
47
|
+
): string {
|
|
48
|
+
return this.getCodec(schema).encode(value);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Encode value to binary (UTF-8 encoded keyless JSON).
|
|
53
|
+
*/
|
|
54
|
+
public encodeToBinary<T extends TSchema>(
|
|
55
|
+
schema: T,
|
|
56
|
+
value: Static<T>,
|
|
57
|
+
): Uint8Array {
|
|
58
|
+
return this.encoder.encode(this.encodeToString(schema, value));
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Decode keyless JSON string or binary to value.
|
|
63
|
+
*/
|
|
64
|
+
public decode<T>(schema: TSchema, value: unknown): T {
|
|
65
|
+
if (value instanceof Uint8Array) {
|
|
66
|
+
const text = this.decoder.decode(value);
|
|
67
|
+
return this.getCodec(schema).decode(text) as T;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (typeof value === "string") {
|
|
71
|
+
return this.getCodec(schema).decode(value) as T;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// If already an array (parsed JSON), reconstruct object
|
|
75
|
+
if (Array.isArray(value)) {
|
|
76
|
+
return this.reconstructObject(schema, value) as T;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return value as T;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// ===========================================================================
|
|
83
|
+
// Codec Compilation
|
|
84
|
+
// ===========================================================================
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Get a compiled codec for the given schema.
|
|
88
|
+
* Codecs are cached for reuse.
|
|
89
|
+
*/
|
|
90
|
+
protected getCodec<T>(schema: TSchema): KeylessCodec<T> {
|
|
91
|
+
let c = this.cache.get(schema);
|
|
92
|
+
if (!c) {
|
|
93
|
+
c = this.compile(schema);
|
|
94
|
+
this.cache.set(schema, c);
|
|
95
|
+
}
|
|
96
|
+
return c as KeylessCodec<T>;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
protected nextVar(): string {
|
|
100
|
+
return `_${this.varCounter++}`;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
protected compile(schema: TSchema): KeylessCodec {
|
|
104
|
+
this.varCounter = 0;
|
|
105
|
+
const encBody = this.genEnc(schema, "v");
|
|
106
|
+
|
|
107
|
+
this.varCounter = 0;
|
|
108
|
+
const decBody = this.genDec(schema);
|
|
109
|
+
|
|
110
|
+
const encoder = new Function("v", `return JSON.stringify(${encBody});`) as (
|
|
111
|
+
value: any,
|
|
112
|
+
) => string;
|
|
113
|
+
|
|
114
|
+
const decoder = new Function(
|
|
115
|
+
"s",
|
|
116
|
+
`const a=JSON.parse(s);let i=0;${decBody.code}return ${decBody.result};`,
|
|
117
|
+
) as (str: string) => any;
|
|
118
|
+
|
|
119
|
+
return { encode: encoder, decode: decoder };
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// ===========================================================================
|
|
123
|
+
// Encoder - generates code that returns an array representation
|
|
124
|
+
// ===========================================================================
|
|
125
|
+
|
|
126
|
+
protected genEnc(schema: TSchema, ve: string): string {
|
|
127
|
+
if (
|
|
128
|
+
t.schema.isString(schema) ||
|
|
129
|
+
t.schema.isNumber(schema) ||
|
|
130
|
+
t.schema.isInteger(schema) ||
|
|
131
|
+
t.schema.isBoolean(schema) ||
|
|
132
|
+
this.isEnum(schema)
|
|
133
|
+
) {
|
|
134
|
+
return ve;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if (t.schema.isBigInt(schema)) {
|
|
138
|
+
return `${ve}+'n'`;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
if (t.schema.isArray(schema)) {
|
|
142
|
+
const arrSchema = schema as TArray;
|
|
143
|
+
const itemEnc = this.genEnc(arrSchema.items, "e");
|
|
144
|
+
if (
|
|
145
|
+
t.schema.isString(arrSchema.items) ||
|
|
146
|
+
t.schema.isNumber(arrSchema.items) ||
|
|
147
|
+
t.schema.isInteger(arrSchema.items) ||
|
|
148
|
+
t.schema.isBoolean(arrSchema.items)
|
|
149
|
+
) {
|
|
150
|
+
return ve;
|
|
151
|
+
}
|
|
152
|
+
return `${ve}.map(e=>${itemEnc})`;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
if (t.schema.isObject(schema)) {
|
|
156
|
+
const objSchema = schema as TObject;
|
|
157
|
+
const props = objSchema.properties as Record<string, TSchema>;
|
|
158
|
+
const keys = Object.keys(props);
|
|
159
|
+
const req = new Set((objSchema.required as string[]) || []);
|
|
160
|
+
|
|
161
|
+
const parts: string[] = [];
|
|
162
|
+
for (const k of keys) {
|
|
163
|
+
const ps = props[k];
|
|
164
|
+
const isOpt = !req.has(k) || t.schema.isOptional(ps);
|
|
165
|
+
const isNullable = this.isNullable(ps);
|
|
166
|
+
const inner = this.unwrap(ps);
|
|
167
|
+
const innerEnc = this.genEnc(inner, `${ve}.${k}`);
|
|
168
|
+
|
|
169
|
+
if (isOpt) {
|
|
170
|
+
parts.push(`${ve}.${k}!==undefined?${innerEnc}:null`);
|
|
171
|
+
} else if (isNullable) {
|
|
172
|
+
parts.push(`${ve}.${k}!==null?${innerEnc}:null`);
|
|
173
|
+
} else {
|
|
174
|
+
parts.push(innerEnc);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
return `[${parts.join(",")}]`;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
if (t.schema.isOptional(schema) || t.schema.isUnion(schema)) {
|
|
182
|
+
const inner = this.unwrap(schema);
|
|
183
|
+
const innerEnc = this.genEnc(inner, ve);
|
|
184
|
+
if (this.isNullable(schema)) {
|
|
185
|
+
return `${ve}!==null?${innerEnc}:null`;
|
|
186
|
+
}
|
|
187
|
+
return `${ve}!==undefined?${innerEnc}:null`;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
return ve;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// ===========================================================================
|
|
194
|
+
// Decoder - generates code to reconstruct object from parsed array
|
|
195
|
+
// ===========================================================================
|
|
196
|
+
|
|
197
|
+
protected genDec(schema: TSchema): { code: string; result: string } {
|
|
198
|
+
const v = this.nextVar();
|
|
199
|
+
|
|
200
|
+
if (
|
|
201
|
+
t.schema.isString(schema) ||
|
|
202
|
+
t.schema.isNumber(schema) ||
|
|
203
|
+
t.schema.isInteger(schema) ||
|
|
204
|
+
t.schema.isBoolean(schema) ||
|
|
205
|
+
this.isEnum(schema)
|
|
206
|
+
) {
|
|
207
|
+
return { code: "", result: "a[i++]" };
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
if (t.schema.isBigInt(schema)) {
|
|
211
|
+
return { code: "", result: "BigInt(a[i++].slice(0,-1))" };
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
if (t.schema.isArray(schema)) {
|
|
215
|
+
const arrSchema = schema as TArray;
|
|
216
|
+
// Check if array items need transformation (objects)
|
|
217
|
+
if (t.schema.isObject(arrSchema.items)) {
|
|
218
|
+
const itemTransform = this.genDecFromValue(arrSchema.items, "e");
|
|
219
|
+
return { code: "", result: `a[i++].map(e=>${itemTransform})` };
|
|
220
|
+
}
|
|
221
|
+
return { code: "", result: "a[i++]" };
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
if (t.schema.isObject(schema)) {
|
|
225
|
+
const objSchema = schema as TObject;
|
|
226
|
+
const props = objSchema.properties as Record<string, TSchema>;
|
|
227
|
+
const keys = Object.keys(props);
|
|
228
|
+
const req = new Set((objSchema.required as string[]) || []);
|
|
229
|
+
|
|
230
|
+
// Check if simple (all required primitives)
|
|
231
|
+
let simple = true;
|
|
232
|
+
for (const k of keys) {
|
|
233
|
+
const ps = props[k];
|
|
234
|
+
const isOpt = !req.has(k) || t.schema.isOptional(ps);
|
|
235
|
+
const isNullable = this.isNullable(ps);
|
|
236
|
+
const inner = this.unwrap(ps);
|
|
237
|
+
if (
|
|
238
|
+
isOpt ||
|
|
239
|
+
isNullable ||
|
|
240
|
+
t.schema.isObject(inner) ||
|
|
241
|
+
t.schema.isArray(inner)
|
|
242
|
+
) {
|
|
243
|
+
simple = false;
|
|
244
|
+
break;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
if (simple) {
|
|
249
|
+
const fields = keys.map((k) => `${k}:a[i++]`);
|
|
250
|
+
return { code: "", result: `{${fields.join(",")}}` };
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
let code = `const ${v}={};`;
|
|
254
|
+
for (const k of keys) {
|
|
255
|
+
const ps = props[k];
|
|
256
|
+
const isOpt = !req.has(k) || t.schema.isOptional(ps);
|
|
257
|
+
const isNullable = this.isNullable(ps);
|
|
258
|
+
const inner = this.unwrap(ps);
|
|
259
|
+
|
|
260
|
+
if (isOpt) {
|
|
261
|
+
const nested = this.genDecFromValue(inner, "t");
|
|
262
|
+
code += `{const t=a[i++];if(t!==null){${v}.${k}=${nested};}}`;
|
|
263
|
+
} else if (isNullable) {
|
|
264
|
+
const nested = this.genDecFromValue(inner, "t");
|
|
265
|
+
code += `{const t=a[i++];if(t===null){${v}.${k}=null;}else{${v}.${k}=${nested};}}`;
|
|
266
|
+
} else if (t.schema.isObject(inner)) {
|
|
267
|
+
const nested = this.genDecFromValue(inner, "a[i++]");
|
|
268
|
+
code += `${v}.${k}=${nested};`;
|
|
269
|
+
} else if (t.schema.isArray(inner)) {
|
|
270
|
+
// Handle arrays - check if items need transformation
|
|
271
|
+
const arrSchema = inner as TArray;
|
|
272
|
+
if (t.schema.isObject(arrSchema.items)) {
|
|
273
|
+
const itemTransform = this.genDecFromValue(arrSchema.items, "e");
|
|
274
|
+
code += `${v}.${k}=a[i++].map(e=>${itemTransform});`;
|
|
275
|
+
} else {
|
|
276
|
+
code += `${v}.${k}=a[i++];`;
|
|
277
|
+
}
|
|
278
|
+
} else {
|
|
279
|
+
code += `${v}.${k}=a[i++];`;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
return { code, result: v };
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
if (t.schema.isOptional(schema) || t.schema.isUnion(schema)) {
|
|
287
|
+
const inner = this.unwrap(schema);
|
|
288
|
+
const innerDec = this.genDec(inner);
|
|
289
|
+
const nullVal = this.isNullable(schema) ? "null" : "undefined";
|
|
290
|
+
return {
|
|
291
|
+
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`)};}`,
|
|
292
|
+
result: v,
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
return { code: "", result: "a[i++]" };
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
protected genDecFromValue(schema: TSchema, expr: string): string {
|
|
300
|
+
if (
|
|
301
|
+
t.schema.isString(schema) ||
|
|
302
|
+
t.schema.isNumber(schema) ||
|
|
303
|
+
t.schema.isInteger(schema) ||
|
|
304
|
+
t.schema.isBoolean(schema) ||
|
|
305
|
+
this.isEnum(schema)
|
|
306
|
+
) {
|
|
307
|
+
return expr;
|
|
308
|
+
}
|
|
309
|
+
if (t.schema.isBigInt(schema)) {
|
|
310
|
+
return `BigInt(${expr}.slice(0,-1))`;
|
|
311
|
+
}
|
|
312
|
+
if (t.schema.isArray(schema)) {
|
|
313
|
+
return expr;
|
|
314
|
+
}
|
|
315
|
+
if (t.schema.isObject(schema)) {
|
|
316
|
+
const objSchema = schema as TObject;
|
|
317
|
+
const props = objSchema.properties as Record<string, TSchema>;
|
|
318
|
+
const keys = Object.keys(props);
|
|
319
|
+
const v = this.nextVar();
|
|
320
|
+
const fields = keys.map((k, idx) => {
|
|
321
|
+
const inner = this.unwrap(props[k]);
|
|
322
|
+
const innerExpr = `${v}[${idx}]`;
|
|
323
|
+
if (t.schema.isObject(inner)) {
|
|
324
|
+
return `${k}:${this.genDecFromValue(inner, innerExpr)}`;
|
|
325
|
+
}
|
|
326
|
+
if (t.schema.isBigInt(inner)) {
|
|
327
|
+
return `${k}:BigInt(${innerExpr}.slice(0,-1))`;
|
|
328
|
+
}
|
|
329
|
+
return `${k}:${innerExpr}`;
|
|
330
|
+
});
|
|
331
|
+
return `((${v}=${expr})=>({${fields.join(",")}}))()`;
|
|
332
|
+
}
|
|
333
|
+
return expr;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
// ===========================================================================
|
|
337
|
+
// Helpers
|
|
338
|
+
// ===========================================================================
|
|
339
|
+
|
|
340
|
+
protected isEnum(schema: TSchema): boolean {
|
|
341
|
+
return (
|
|
342
|
+
"enum" in schema &&
|
|
343
|
+
Array.isArray((schema as { enum?: unknown[] }).enum) &&
|
|
344
|
+
((schema as { enum?: unknown[] }).enum?.length ?? 0) > 0
|
|
345
|
+
);
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
protected isNullable(schema: TSchema): boolean {
|
|
349
|
+
if (!t.schema.isUnion(schema)) return false;
|
|
350
|
+
const unionSchema = schema as TUnion;
|
|
351
|
+
return unionSchema.anyOf?.some((s: TSchema) => t.schema.isNull(s)) ?? false;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
protected unwrap(schema: TSchema): TSchema {
|
|
355
|
+
if ("anyOf" in schema && Array.isArray((schema as TUnion).anyOf)) {
|
|
356
|
+
const unionSchema = schema as TUnion;
|
|
357
|
+
return (
|
|
358
|
+
unionSchema.anyOf.find((s: TSchema) => !t.schema.isNull(s)) || schema
|
|
359
|
+
);
|
|
360
|
+
}
|
|
361
|
+
return schema;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
/**
|
|
365
|
+
* Reconstruct an object from a parsed array (for when input is already parsed).
|
|
366
|
+
*/
|
|
367
|
+
protected reconstructObject(schema: TSchema, arr: any[]): any {
|
|
368
|
+
if (!t.schema.isObject(schema)) {
|
|
369
|
+
return arr;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
const objSchema = schema as TObject;
|
|
373
|
+
const props = objSchema.properties as Record<string, TSchema>;
|
|
374
|
+
const keys = Object.keys(props);
|
|
375
|
+
const result: Record<string, any> = {};
|
|
376
|
+
let i = 0;
|
|
377
|
+
|
|
378
|
+
for (const k of keys) {
|
|
379
|
+
const ps = props[k];
|
|
380
|
+
const isOpt = t.schema.isOptional(ps);
|
|
381
|
+
const isNullable = this.isNullable(ps);
|
|
382
|
+
const inner = this.unwrap(ps);
|
|
383
|
+
const val = arr[i++];
|
|
384
|
+
|
|
385
|
+
if (isOpt) {
|
|
386
|
+
if (val !== null) {
|
|
387
|
+
result[k] = t.schema.isObject(inner)
|
|
388
|
+
? this.reconstructObject(inner, val)
|
|
389
|
+
: val;
|
|
390
|
+
}
|
|
391
|
+
} else if (isNullable) {
|
|
392
|
+
result[k] =
|
|
393
|
+
val === null
|
|
394
|
+
? null
|
|
395
|
+
: t.schema.isObject(inner)
|
|
396
|
+
? this.reconstructObject(inner, val)
|
|
397
|
+
: val;
|
|
398
|
+
} else {
|
|
399
|
+
result[k] = t.schema.isObject(inner)
|
|
400
|
+
? this.reconstructObject(inner, val)
|
|
401
|
+
: val;
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
return result;
|
|
406
|
+
}
|
|
407
|
+
}
|
|
@@ -209,12 +209,16 @@ describe("StateManager", () => {
|
|
|
209
209
|
});
|
|
210
210
|
|
|
211
211
|
it("should set values in ALS when context exists", async () => {
|
|
212
|
-
|
|
213
|
-
alepha.context.run(
|
|
214
|
-
|
|
215
|
-
|
|
212
|
+
// Note: AlsProvider spreads the store object, so we check values inside the callback
|
|
213
|
+
const result = alepha.context.run(
|
|
214
|
+
() => {
|
|
215
|
+
stateManager.set("name", "ALS Value");
|
|
216
|
+
return stateManager.get("name");
|
|
217
|
+
},
|
|
218
|
+
{ context: "test-context" },
|
|
219
|
+
);
|
|
216
220
|
|
|
217
|
-
expect(
|
|
221
|
+
expect(result).toBe("ALS Value");
|
|
218
222
|
});
|
|
219
223
|
|
|
220
224
|
it("should set values in local store when no ALS context", () => {
|
|
@@ -267,14 +271,16 @@ describe("StateManager", () => {
|
|
|
267
271
|
stateManager.set("name", "Local Value");
|
|
268
272
|
|
|
269
273
|
// In ALS context, ALS values should take priority
|
|
270
|
-
|
|
271
|
-
const result = alepha.context.run(
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
274
|
+
// Note: AlsProvider spreads the store object, so we check values inside the callback
|
|
275
|
+
const result = alepha.context.run(
|
|
276
|
+
() => {
|
|
277
|
+
stateManager.set("name", "ALS Priority");
|
|
278
|
+
return stateManager.get("name");
|
|
279
|
+
},
|
|
280
|
+
{ context: "test-context" },
|
|
281
|
+
);
|
|
275
282
|
|
|
276
283
|
expect(result).toBe("ALS Priority");
|
|
277
|
-
expect(store.name).toBe("ALS Priority");
|
|
278
284
|
});
|
|
279
285
|
|
|
280
286
|
it("should not skip event emission when values are the same", async () => {
|
|
@@ -291,12 +297,17 @@ describe("StateManager", () => {
|
|
|
291
297
|
});
|
|
292
298
|
|
|
293
299
|
it("should delete values from ALS when context exists", async () => {
|
|
294
|
-
|
|
295
|
-
alepha.context.run(
|
|
296
|
-
|
|
297
|
-
|
|
300
|
+
// Note: AlsProvider spreads the store object, so we check values inside the callback
|
|
301
|
+
const result = alepha.context.run(
|
|
302
|
+
() => {
|
|
303
|
+
stateManager.set("name", "To Delete");
|
|
304
|
+
stateManager.del("name");
|
|
305
|
+
return stateManager.get("name");
|
|
306
|
+
},
|
|
307
|
+
{ context: "test-context" },
|
|
308
|
+
);
|
|
298
309
|
|
|
299
|
-
expect(
|
|
310
|
+
expect(result).toBeUndefined();
|
|
300
311
|
});
|
|
301
312
|
|
|
302
313
|
it("should clear only local store, not ALS", async () => {
|