akanjs 2.2.7 → 2.2.9
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/CHANGELOG.md +11 -2
- package/client/clientRuntime.ts +3 -0
- package/client/csrTypes.ts +1 -0
- package/client/makePageProto.tsx +5 -2
- package/client/translator.ts +7 -4
- package/common/fileUpload.ts +1 -1
- package/common/index.ts +5 -1
- package/constant/getDefault.ts +1 -1
- package/dictionary/base.dictionary.ts +0 -1
- package/fetch/client/fetchClient.ts +21 -24
- package/fetch/client/wsClient.ts +8 -0
- package/fetch/serializer/fetch.serializer.ts +1 -0
- package/package.json +1 -5
- package/server/hmr/devHmrController.ts +1 -0
- package/server/routeTreeBuilder.ts +1 -0
- package/server/ssrFromRscRenderer.tsx +34 -12
- package/server/ssrTypes.ts +5 -6
- package/service/base.service.ts +0 -4
- package/service/injectInfo.ts +49 -12
- package/service/predefinedAdaptor/cache.adaptor.ts +13 -0
- package/service/predefinedAdaptor/database.adaptor.ts +74 -16
- package/service/predefinedAdaptor/solidCache.adaptor.ts +23 -0
- package/signal/base.signal.ts +0 -5
- package/signal/serializer/fetch.serializer.ts +1 -0
- package/signal/types.ts +3 -0
- package/store/action.ts +15 -3
- package/store/storeInstance.ts +50 -3
- package/types/client/csrTypes.d.ts +1 -0
- package/types/client/translator.d.ts +1 -0
- package/types/common/fileUpload.d.ts +1 -1
- package/types/common/index.d.ts +1 -1
- package/types/server/ssrTypes.d.ts +5 -6
- package/types/service/base.service.d.ts +0 -1
- package/types/service/injectInfo.d.ts +8 -2
- package/types/service/predefinedAdaptor/cache.adaptor.d.ts +6 -0
- package/types/service/predefinedAdaptor/database.adaptor.d.ts +3 -1
- package/types/service/predefinedAdaptor/solidCache.adaptor.d.ts +3 -0
- package/types/signal/base.signal.d.ts +0 -3
- package/types/signal/types.d.ts +3 -0
- package/types/ui/Dialog/Modal.d.ts +1 -1
- package/types/ui/Dialog/index.d.ts +1 -1
- package/types/ui/Modal.d.ts +1 -12
- package/types/ui/System/CSR.d.ts +2 -2
- package/types/ui/System/Client.d.ts +5 -4
- package/types/ui/System/Common.d.ts +2 -0
- package/types/ui/System/SSR.d.ts +2 -2
- package/ui/Dialog/Modal.tsx +181 -70
- package/ui/Dialog/Provider.tsx +3 -6
- package/ui/Modal.tsx +0 -44
- package/ui/System/CSR.tsx +9 -1
- package/ui/System/Client.tsx +27 -62
- package/ui/System/Common.tsx +2 -0
- package/ui/System/SSR.tsx +9 -1
- package/webkit/bootCsr.tsx +1 -0
|
@@ -4,7 +4,7 @@ import { mkdir } from "node:fs/promises";
|
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import type { InArgs, InValue, Client as LibsqlClient } from "@libsql/client";
|
|
6
6
|
import { type BaseEnv, dayjs, FIELD_META, type PromiseOrObject } from "akanjs/base";
|
|
7
|
-
import type
|
|
7
|
+
import { type ConstantModel, getDefault } from "akanjs/constant";
|
|
8
8
|
import {
|
|
9
9
|
createDocumentId,
|
|
10
10
|
type DatabaseModel,
|
|
@@ -300,6 +300,13 @@ const jsonPath = (path: string) =>
|
|
|
300
300
|
.map((part) => part.replaceAll('"', '\\"'))
|
|
301
301
|
.join(".")}`;
|
|
302
302
|
const encodeSqlValue = (value: unknown) => encodeDocumentValue(value);
|
|
303
|
+
|
|
304
|
+
const decodeDateValue = (value: unknown) => {
|
|
305
|
+
if (value === null || value === undefined) return value;
|
|
306
|
+
if (typeof value === "number") return dayjs(value);
|
|
307
|
+
const epoch = Number(value);
|
|
308
|
+
return Number.isNaN(epoch) ? dayjs(value as never) : dayjs(epoch);
|
|
309
|
+
};
|
|
303
310
|
const QUERY_OPERATOR_KEYS = new Set([
|
|
304
311
|
"eq",
|
|
305
312
|
"ne",
|
|
@@ -773,6 +780,9 @@ export class SqliteDocumentStore {
|
|
|
773
780
|
} else {
|
|
774
781
|
doc[key] = value;
|
|
775
782
|
}
|
|
783
|
+
if (doc[key] !== undefined && doc[key] !== null) {
|
|
784
|
+
doc[key] = this.normalizeWriteValue(doc[key], props);
|
|
785
|
+
}
|
|
776
786
|
if (props.enum && doc[key] !== undefined && doc[key] !== null) {
|
|
777
787
|
const values = Array.isArray(doc[key]) ? doc[key] : [doc[key]];
|
|
778
788
|
const fieldEnum = props.enum as { has: (value: unknown) => boolean } | undefined;
|
|
@@ -958,12 +968,28 @@ export class SqliteDocumentStore {
|
|
|
958
968
|
|
|
959
969
|
private decodeDocumentPayload(payload: Record<string, unknown>) {
|
|
960
970
|
const fields = this.database.doc[FIELD_META] as unknown as FieldMap;
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
971
|
+
const result: Record<string, unknown> = {};
|
|
972
|
+
for (const [key, fieldMeta] of Object.entries(fields)) {
|
|
973
|
+
if (BASE_COLUMNS.has(key)) continue;
|
|
974
|
+
const props = fieldMeta.getProps();
|
|
975
|
+
const value = payload[key];
|
|
976
|
+
if (value === undefined) {
|
|
977
|
+
const def = props.default;
|
|
978
|
+
if (def !== undefined && def !== null) {
|
|
979
|
+
result[key] = typeof def === "function" ? (def as (data: unknown) => unknown)(payload) : def;
|
|
980
|
+
} else if (props.nullable) {
|
|
981
|
+
result[key] = null;
|
|
982
|
+
}
|
|
983
|
+
} else {
|
|
984
|
+
result[key] = this.decodeFieldValue(value, props);
|
|
985
|
+
}
|
|
986
|
+
}
|
|
987
|
+
for (const [key, value] of Object.entries(payload)) {
|
|
988
|
+
if (key in result || BASE_COLUMNS.has(key)) continue;
|
|
989
|
+
const props = fields[key]?.getProps?.();
|
|
990
|
+
result[key] = props ? this.decodeFieldValue(value, props) : value;
|
|
991
|
+
}
|
|
992
|
+
return result;
|
|
967
993
|
}
|
|
968
994
|
|
|
969
995
|
private decodeFieldValue(value: unknown, props: Record<string, unknown>): unknown {
|
|
@@ -973,8 +999,8 @@ export class SqliteDocumentStore {
|
|
|
973
999
|
return new Map(entries.map(([key, item]) => [key, this.decodeMapValue(item, props)]));
|
|
974
1000
|
}
|
|
975
1001
|
if (props.modelRef === Date) {
|
|
976
|
-
if (Array.isArray(value)) return value.map((item) => (item === null ? item :
|
|
977
|
-
return
|
|
1002
|
+
if (Array.isArray(value)) return value.map((item) => (item === null ? item : decodeDateValue(item)));
|
|
1003
|
+
return decodeDateValue(value);
|
|
978
1004
|
}
|
|
979
1005
|
if (Array.isArray(value)) return value.map((item) => this.decodeNestedValue(item, props));
|
|
980
1006
|
return this.decodeNestedValue(value, props);
|
|
@@ -982,7 +1008,7 @@ export class SqliteDocumentStore {
|
|
|
982
1008
|
|
|
983
1009
|
private decodeMapValue(value: unknown, props: Record<string, unknown>) {
|
|
984
1010
|
if (value === undefined || value === null) return value;
|
|
985
|
-
if (props.of === Date) return
|
|
1011
|
+
if (props.of === Date) return decodeDateValue(value);
|
|
986
1012
|
return value;
|
|
987
1013
|
}
|
|
988
1014
|
|
|
@@ -991,12 +1017,44 @@ export class SqliteDocumentStore {
|
|
|
991
1017
|
if (!props.isClass || !props.isScalar) return value;
|
|
992
1018
|
const scalarFields = (props.modelRef as { [FIELD_META]?: FieldMap } | undefined)?.[FIELD_META];
|
|
993
1019
|
if (!scalarFields) return value;
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1020
|
+
const source = value as Record<string, unknown>;
|
|
1021
|
+
const defaults = getDefault(scalarFields as never) as Record<string, unknown>;
|
|
1022
|
+
const result: Record<string, unknown> = {};
|
|
1023
|
+
for (const [key, fieldMeta] of Object.entries(scalarFields)) {
|
|
1024
|
+
const nestedProps = fieldMeta.getProps();
|
|
1025
|
+
const nested = source[key];
|
|
1026
|
+
result[key] = nested === undefined ? defaults[key] : this.decodeFieldValue(nested, nestedProps);
|
|
1027
|
+
}
|
|
1028
|
+
for (const [key, nested] of Object.entries(source)) {
|
|
1029
|
+
if (!(key in result)) result[key] = nested;
|
|
1030
|
+
}
|
|
1031
|
+
return result;
|
|
1032
|
+
}
|
|
1033
|
+
|
|
1034
|
+
private normalizeWriteValue(value: unknown, props: Record<string, unknown>): unknown {
|
|
1035
|
+
if (value === undefined || value === null) return value;
|
|
1036
|
+
if (props.modelRef === Date) {
|
|
1037
|
+
if (Array.isArray(value))
|
|
1038
|
+
return value.map((item) => (item === null || item === undefined ? item : dayjs(item as never)));
|
|
1039
|
+
return dayjs(value as never);
|
|
1040
|
+
}
|
|
1041
|
+
if (!props.isClass || !props.isScalar) return value;
|
|
1042
|
+
if (Array.isArray(value)) return value.map((item) => this.fillScalarDefaults(item, props));
|
|
1043
|
+
return this.fillScalarDefaults(value, props);
|
|
1044
|
+
}
|
|
1045
|
+
|
|
1046
|
+
private fillScalarDefaults(value: unknown, props: Record<string, unknown>): unknown {
|
|
1047
|
+
if (!value || typeof value !== "object") return value;
|
|
1048
|
+
const scalarFields = (props.modelRef as { [FIELD_META]?: FieldMap } | undefined)?.[FIELD_META];
|
|
1049
|
+
if (!scalarFields) return value;
|
|
1050
|
+
const defaults = getDefault(scalarFields as never) as Record<string, unknown>;
|
|
1051
|
+
const result = { ...(value as Record<string, unknown>) };
|
|
1052
|
+
for (const [key, fieldMeta] of Object.entries(scalarFields)) {
|
|
1053
|
+
const nestedProps = fieldMeta.getProps();
|
|
1054
|
+
if (result[key] === undefined) result[key] = defaults[key];
|
|
1055
|
+
else result[key] = this.normalizeWriteValue(result[key], nestedProps);
|
|
1056
|
+
}
|
|
1057
|
+
return result;
|
|
1000
1058
|
}
|
|
1001
1059
|
|
|
1002
1060
|
hydrate(data: DocumentRecord, originalData: DocumentRecord = data) {
|
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
} from "./solidSqlite";
|
|
15
15
|
|
|
16
16
|
type CacheRow = { value: string | Buffer | null; valueType: SolidValueType; expiresAt: number | null };
|
|
17
|
+
type CacheEntryRow = CacheRow & { subKey: string };
|
|
17
18
|
|
|
18
19
|
export class SolidCache
|
|
19
20
|
extends adapt("solidCache", ({ env }) => ({
|
|
@@ -135,6 +136,28 @@ export class SolidCache
|
|
|
135
136
|
.run(topic, key, subKey);
|
|
136
137
|
}
|
|
137
138
|
|
|
139
|
+
async hkeys(topic: string, key: string): Promise<string[]> {
|
|
140
|
+
this.#cleanup();
|
|
141
|
+
const rows = this.#db
|
|
142
|
+
.query(`SELECT "subKey" FROM "_akan_solid_cache_hash" WHERE "topic" = ? AND "key" = ? ORDER BY "subKey" ASC`)
|
|
143
|
+
.all(topic, key) as { subKey: string }[];
|
|
144
|
+
return rows.map((row) => row.subKey);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
async hentries<T extends string | number | Buffer>(topic: string, key: string): Promise<[string, T][]> {
|
|
148
|
+
this.#cleanup();
|
|
149
|
+
const rows = this.#db
|
|
150
|
+
.query(
|
|
151
|
+
`SELECT "subKey", "value", "valueType", "expiresAt" FROM "_akan_solid_cache_hash" WHERE "topic" = ? AND "key" = ? ORDER BY "subKey" ASC`,
|
|
152
|
+
)
|
|
153
|
+
.all(topic, key) as CacheEntryRow[];
|
|
154
|
+
return rows.map((row) => [row.subKey, decodeSolidValue<T>(row.valueType, row.value) as T]);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
async hclear(topic: string, key: string): Promise<void> {
|
|
158
|
+
this.#db.query(`DELETE FROM "_akan_solid_cache_hash" WHERE "topic" = ? AND "key" = ?`).run(topic, key);
|
|
159
|
+
}
|
|
160
|
+
|
|
138
161
|
#cleanup() {
|
|
139
162
|
const now = Date.now();
|
|
140
163
|
this.#db.query(`DELETE FROM "_akan_solid_cache" WHERE "expiresAt" IS NOT NULL AND "expiresAt" <= ?`).run(now);
|
package/signal/base.signal.ts
CHANGED
|
@@ -18,11 +18,6 @@ export class BaseEndpoint extends endpoint(srv.base, ({ query, mutation, message
|
|
|
18
18
|
pingQuery: query(String, { nullable: true })
|
|
19
19
|
.search("id", String)
|
|
20
20
|
.exec((id) => `pingQuery: ${id}`),
|
|
21
|
-
cleanup: mutation(Boolean).exec(async function () {
|
|
22
|
-
if (process.env.NODE_ENV !== "test") throw new Error("cleanup is only available in test environment");
|
|
23
|
-
await this.baseService.cleanup();
|
|
24
|
-
return true;
|
|
25
|
-
}),
|
|
26
21
|
wsPing: message(String)
|
|
27
22
|
.msg("data", String, { nullable: true })
|
|
28
23
|
.exec((data) => `wsPing: ${data}`),
|
|
@@ -64,6 +64,7 @@ export class FetchSerializer {
|
|
|
64
64
|
args: endpointInfo.args.map(FetchSerializer.#serializeArg),
|
|
65
65
|
returns: FetchSerializer.#serializeReturns(endpointInfo),
|
|
66
66
|
...(endpointInfo.signalOption.path ? { path: endpointInfo.signalOption.path } : {}),
|
|
67
|
+
...(endpointInfo.signalOption.fileUpload ? { fileUpload: true } : {}),
|
|
67
68
|
...(guards?.length ? { guards } : {}),
|
|
68
69
|
};
|
|
69
70
|
}
|
package/signal/types.ts
CHANGED
|
@@ -70,6 +70,8 @@ export interface SignalOption<Response = any, Nullable extends boolean = false,
|
|
|
70
70
|
middlewares?: MiddlewareCls[];
|
|
71
71
|
prefix?: false | string;
|
|
72
72
|
globalPrefix?: false;
|
|
73
|
+
/** Marks this mutation as the framework file-upload endpoint (see resolveFileUploadCapability). */
|
|
74
|
+
fileUpload?: boolean;
|
|
73
75
|
|
|
74
76
|
scheduleType?: "init" | "destroy" | "cron" | "interval" | "timeout";
|
|
75
77
|
scheduleCron?: string;
|
|
@@ -84,6 +86,7 @@ interface SerializedSignalOption {
|
|
|
84
86
|
prefix?: false | string;
|
|
85
87
|
globalPrefix?: false;
|
|
86
88
|
guards?: string[];
|
|
89
|
+
fileUpload?: boolean;
|
|
87
90
|
}
|
|
88
91
|
export interface SerializedSlice extends SerializedSignalOption {}
|
|
89
92
|
|
package/store/action.ts
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
import { DataList, type Dayjs, FIELD_META, type GetStateObject, type SLICE_META } from "akanjs/base";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
capitalize,
|
|
4
|
+
deepObjectify,
|
|
5
|
+
type FetchPolicy,
|
|
6
|
+
isQueryEqual,
|
|
7
|
+
Logger,
|
|
8
|
+
lowerlize,
|
|
9
|
+
pathSet,
|
|
10
|
+
resolveFileUploadCapability,
|
|
11
|
+
} from "akanjs/common";
|
|
3
12
|
import {
|
|
4
13
|
type BaseInsight,
|
|
5
14
|
type BaseObject,
|
|
@@ -277,6 +286,7 @@ export const makeFormSetter = (refName: string, fetch: FetchProxy<any>) => {
|
|
|
277
286
|
type Light = BaseObject;
|
|
278
287
|
const [fieldName, className] = [refName, capitalize(refName)];
|
|
279
288
|
const modelRef = ConstantRegistry.getDatabase(refName).full;
|
|
289
|
+
const fileUploadRefName = resolveFileUploadCapability(fetch.serializedSignal)?.refName;
|
|
280
290
|
|
|
281
291
|
const names = {
|
|
282
292
|
model: fieldName,
|
|
@@ -356,7 +366,7 @@ export const makeFormSetter = (refName: string, fetch: FetchProxy<any>) => {
|
|
|
356
366
|
},
|
|
357
367
|
}
|
|
358
368
|
: {}),
|
|
359
|
-
...(field.isClass && ConstantRegistry.getRefName(field.modelRef) ===
|
|
369
|
+
...(field.isClass && !!fileUploadRefName && ConstantRegistry.getRefName(field.modelRef) === fileUploadRefName
|
|
360
370
|
? {
|
|
361
371
|
[namesOfField.uploadFieldOnModel]: async function (this: SetGet, fileList: FileList, index?: number) {
|
|
362
372
|
const form = (this.get() as { [key: string]: any })[names.modelForm] as { [key: string]: any };
|
|
@@ -383,7 +393,9 @@ export const makeFormSetter = (refName: string, fetch: FetchProxy<any>) => {
|
|
|
383
393
|
const intervalKey = setInterval(() => {
|
|
384
394
|
void (async () => {
|
|
385
395
|
const currentFile = await (
|
|
386
|
-
(fetch as { [key: string]: any })
|
|
396
|
+
(fetch as { [key: string]: any })[fileUploadRefName as string] as (
|
|
397
|
+
id: string,
|
|
398
|
+
) => Promise<ProtoFile>
|
|
387
399
|
)(file.id);
|
|
388
400
|
if (field.isArray)
|
|
389
401
|
this.set((state: { [key: string]: { [key: string]: ProtoFile[] } }) => {
|
package/store/storeInstance.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { ACTION_META, STATE_DERIVED_META, STATE_INIT_META } from "akanjs/base";
|
|
2
|
-
import {
|
|
2
|
+
import { Translator } from "akanjs/client/translator";
|
|
3
|
+
import { capitalize, Logger, parseAkanI18nEnv } from "akanjs/common";
|
|
3
4
|
import { produce } from "immer";
|
|
4
5
|
import type { RefObject } from "react";
|
|
5
6
|
import { useEffect, useRef, useSyncExternalStore } from "./hooks";
|
|
@@ -9,6 +10,7 @@ import { evaluateInitializers, type SearchParamsState, type StateDerivedMeta } f
|
|
|
9
10
|
|
|
10
11
|
type StoreStateRecord = Record<string, unknown>;
|
|
11
12
|
type StoreAction = (...args: unknown[]) => unknown;
|
|
13
|
+
type TranslationParam = Record<string, string | number>;
|
|
12
14
|
|
|
13
15
|
type SliceActionKey =
|
|
14
16
|
| "initModel"
|
|
@@ -20,6 +22,27 @@ type SliceActionKey =
|
|
|
20
22
|
| "setQueryArgsOfModel"
|
|
21
23
|
| "setSortOfModel";
|
|
22
24
|
|
|
25
|
+
const isRecord = (value: unknown): value is Record<string, unknown> =>
|
|
26
|
+
Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
27
|
+
|
|
28
|
+
const getActionErrorKey = (error: unknown) => {
|
|
29
|
+
if (typeof error === "string") return error;
|
|
30
|
+
if (!isRecord(error)) return String(error);
|
|
31
|
+
if (typeof error.error === "string") return error.error;
|
|
32
|
+
if (typeof error.message === "string") return error.message;
|
|
33
|
+
return String(error);
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const getActionErrorData = (error: unknown): TranslationParam | undefined => {
|
|
37
|
+
if (!isRecord(error) || !isRecord(error.data)) return undefined;
|
|
38
|
+
const data = Object.fromEntries(
|
|
39
|
+
Object.entries(error.data).filter((entry): entry is [string, string | number] =>
|
|
40
|
+
["string", "number"].includes(typeof entry[1]),
|
|
41
|
+
),
|
|
42
|
+
);
|
|
43
|
+
return Object.keys(data).length ? data : undefined;
|
|
44
|
+
};
|
|
45
|
+
|
|
23
46
|
export type ReactAPI = {
|
|
24
47
|
useSyncExternalStore: <T>(
|
|
25
48
|
subscribe: (onStoreChange: () => void) => () => void,
|
|
@@ -190,12 +213,36 @@ export class StoreInstance {
|
|
|
190
213
|
this.do[k] = async (...args: unknown[]) => {
|
|
191
214
|
Logger.verbose(`${k} action loading...`);
|
|
192
215
|
const start = Date.now();
|
|
193
|
-
|
|
194
|
-
|
|
216
|
+
try {
|
|
217
|
+
const result = await (this.#ctx[k] as StoreAction)(...args);
|
|
218
|
+
Logger.verbose(`=> ${k} action dispatched (${Date.now() - start}ms)`);
|
|
219
|
+
return result;
|
|
220
|
+
} catch (error) {
|
|
221
|
+
this.#showActionErrorMessage(k, error);
|
|
222
|
+
Logger.error(`${k} action error return: ${error instanceof Error ? error.message : String(error)}`);
|
|
223
|
+
throw error;
|
|
224
|
+
}
|
|
195
225
|
};
|
|
196
226
|
}
|
|
197
227
|
}
|
|
198
228
|
|
|
229
|
+
#showActionErrorMessage(actionKey: string, error: unknown) {
|
|
230
|
+
const showMessage = this.#ctx.showMessage;
|
|
231
|
+
if (typeof showMessage !== "function") return;
|
|
232
|
+
try {
|
|
233
|
+
const lang = Translator.getActiveLocale() ?? parseAkanI18nEnv().defaultLocale;
|
|
234
|
+
const errorKey = getActionErrorKey(error);
|
|
235
|
+
const content = Translator.translateByLocale(lang, errorKey, getActionErrorData(error));
|
|
236
|
+
showMessage({ type: "error", key: actionKey, duration: 3, content });
|
|
237
|
+
} catch (messageError) {
|
|
238
|
+
Logger.warn(
|
|
239
|
+
`Failed to show ${actionKey} action error message: ${
|
|
240
|
+
messageError instanceof Error ? messageError.message : String(messageError)
|
|
241
|
+
}`,
|
|
242
|
+
);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
199
246
|
#buildSlices(store: RootStoreCls) {
|
|
200
247
|
Object.entries(store.slice).forEach(([refName, sliceObj]) => {
|
|
201
248
|
Object.entries(sliceObj).forEach(([suffix, serializedSlice]) => {
|
|
@@ -11,6 +11,7 @@ export declare class Translator {
|
|
|
11
11
|
hasDictionary(lang: string): boolean;
|
|
12
12
|
static setActiveLocale(lang: string | undefined): void;
|
|
13
13
|
static getActiveLocale(): string | undefined;
|
|
14
|
+
static translateByLocale(lang: string, key: string, param?: Record<string, string | number>): string;
|
|
14
15
|
static seed(lang: string, dict: Dictionary | undefined): void;
|
|
15
16
|
translate(lang: string, key: string, param?: Record<string, string | number>): string;
|
|
16
17
|
getDictionary(lang: string): Promise<Dictionary>;
|
package/types/common/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { applyMixins } from "./applyMixins.d.ts";
|
|
2
2
|
export { capitalize } from "./capitalize.d.ts";
|
|
3
3
|
export { deepObjectify } from "./deepObjectify.d.ts";
|
|
4
|
-
export
|
|
4
|
+
export { type FileUploadCapability, fileUploadContract, resolveFileUploadCapability, } from "./fileUpload.d.ts";
|
|
5
5
|
export { formatNumber } from "./formatNumber.d.ts";
|
|
6
6
|
export { formatPhone } from "./formatPhone.d.ts";
|
|
7
7
|
export { getAllPropertyDescriptors } from "./getAllPropertyDescriptors.d.ts";
|
|
@@ -34,12 +34,11 @@ export interface SsrFromRscInput {
|
|
|
34
34
|
* guaranteeing one React instance across rscClient and every route
|
|
35
35
|
* chunk.
|
|
36
36
|
*
|
|
37
|
-
* Injection happens via a stream transform, not React children, because
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
* modulepreload.
|
|
37
|
+
* Injection happens via a stream transform, not React children, because the
|
|
38
|
+
* spec is strict: import maps must be acquired before any module script fetch
|
|
39
|
+
* starts, including modulepreload. Akan writes bootstrap module preloads
|
|
40
|
+
* directly after this importmap and delays the executable module script until
|
|
41
|
+
* the Fizz HTML stream has completed.
|
|
43
42
|
*/
|
|
44
43
|
importmap?: Record<string, string>;
|
|
45
44
|
theme?: AkanTheme;
|
|
@@ -8,7 +8,6 @@ declare const BaseService_base: import("./serve.d.ts").ServiceCls<"base", {}, {
|
|
|
8
8
|
}>;
|
|
9
9
|
export declare class BaseService extends BaseService_base {
|
|
10
10
|
publishPing(): void;
|
|
11
|
-
cleanup(): Promise<void>;
|
|
12
11
|
}
|
|
13
12
|
export declare const srv: {
|
|
14
13
|
base: ServiceModel<typeof BaseService, any, any, {
|
|
@@ -76,9 +76,15 @@ export declare const injectionBuilder: (parentRefName: string) => {
|
|
|
76
76
|
get?: GetFn;
|
|
77
77
|
set?: (value: ReturnType<GetFn>) => GetFieldValue<ValueRef, ExplicitType>;
|
|
78
78
|
}) => InjectInfo<"memory", Local extends true ? MapConstructor extends ValueRef ? Map<string, FieldToValue<MapValue>> : (DefaultValue extends never ? true : false) extends true ? (never extends GetFn ? GetFieldValue<ValueRef, ExplicitType, MapValue> : ReturnType<GetFn>) | null : never extends GetFn ? GetFieldValue<ValueRef, ExplicitType, MapValue> : ReturnType<GetFn> : MapConstructor extends ValueRef ? {
|
|
79
|
-
get: (key: string) => Promise<FieldToValue<MapValue
|
|
80
|
-
set: (key: string, value: FieldToValue<MapValue>) => Promise<void>;
|
|
79
|
+
get: (key: string) => Promise<(never extends GetFn ? FieldToValue<MapValue> : ReturnType<GetFn>) | undefined>;
|
|
80
|
+
set: (key: string, value: never extends GetFn ? FieldToValue<MapValue> : ReturnType<GetFn>) => Promise<void>;
|
|
81
81
|
delete: (key: string) => Promise<void>;
|
|
82
|
+
getOrInsert: (key: string, value: never extends GetFn ? FieldToValue<MapValue> : ReturnType<GetFn>) => Promise<never extends GetFn ? FieldToValue<MapValue> : ReturnType<GetFn>>;
|
|
83
|
+
getOrInsertComputed: (key: string, compute: (key: string) => (never extends GetFn ? FieldToValue<MapValue> : ReturnType<GetFn>) | Promise<never extends GetFn ? FieldToValue<MapValue> : ReturnType<GetFn>>) => Promise<never extends GetFn ? FieldToValue<MapValue> : ReturnType<GetFn>>;
|
|
84
|
+
keys: () => Promise<string[]>;
|
|
85
|
+
entries: () => Promise<[string, never extends GetFn ? FieldToValue<MapValue> : ReturnType<GetFn>][]>;
|
|
86
|
+
forEach: (callback: (value: never extends GetFn ? FieldToValue<MapValue> : ReturnType<GetFn>, key: string) => void | Promise<void>) => Promise<void>;
|
|
87
|
+
clear: () => Promise<void>;
|
|
82
88
|
} : {
|
|
83
89
|
get: () => Promise<(DefaultValue extends never ? true : false) extends true ? (never extends GetFn ? GetFieldValue<ValueRef, ExplicitType, MapValue> : ReturnType<GetFn>) | null : never extends GetFn ? GetFieldValue<ValueRef, ExplicitType, MapValue> : ReturnType<GetFn>>;
|
|
84
90
|
set: (value: (DefaultValue extends never ? true : false) extends true ? (never extends GetFn ? GetFieldValue<ValueRef, ExplicitType, MapValue> : ReturnType<GetFn>) | null : never extends GetFn ? GetFieldValue<ValueRef, ExplicitType, MapValue> : ReturnType<GetFn>) => Promise<void>;
|
|
@@ -12,6 +12,9 @@ export interface CacheAdaptor {
|
|
|
12
12
|
}): Promise<void>;
|
|
13
13
|
hget<T extends string | number | Buffer>(topic: string, key: string, subKey: string): Promise<T | undefined>;
|
|
14
14
|
hdelete(topic: string, key: string, subKey: string): Promise<void>;
|
|
15
|
+
hkeys(topic: string, key: string): Promise<string[]>;
|
|
16
|
+
hentries<T extends string | number | Buffer>(topic: string, key: string): Promise<[string, T][]>;
|
|
17
|
+
hclear(topic: string, key: string): Promise<void>;
|
|
15
18
|
}
|
|
16
19
|
interface RedisEnv extends BaseEnv {
|
|
17
20
|
redis?: {
|
|
@@ -34,6 +37,9 @@ export declare class RedisCache extends RedisCache_base implements CacheAdaptor
|
|
|
34
37
|
}): Promise<void>;
|
|
35
38
|
hget<T extends string | number | Buffer>(topic: string, key: string, subKey: string): Promise<T | undefined>;
|
|
36
39
|
hdelete(topic: string, key: string, subKey: string): Promise<void>;
|
|
40
|
+
hkeys(topic: string, key: string): Promise<string[]>;
|
|
41
|
+
hentries<T extends string | number | Buffer>(topic: string, key: string): Promise<[string, T][]>;
|
|
42
|
+
hclear(topic: string, key: string): Promise<void>;
|
|
37
43
|
getClient(): Redis;
|
|
38
44
|
onDestroy(): Promise<void>;
|
|
39
45
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Database } from "bun:sqlite";
|
|
2
2
|
import type { Client as LibsqlClient } from "@libsql/client";
|
|
3
3
|
import { type BaseEnv, type PromiseOrObject } from "akanjs/base";
|
|
4
|
-
import type
|
|
4
|
+
import { type ConstantModel } from "akanjs/constant";
|
|
5
5
|
import { type DatabaseModel, type DocumentQuery, type DocumentSchema, type DocumentUpdate, type DocumentUpdateOptions, type SchemaOf } from "akanjs/document";
|
|
6
6
|
import type { Sql } from "postgres";
|
|
7
7
|
export interface SqliteDatabaseConfig {
|
|
@@ -256,6 +256,8 @@ export declare class SqliteDocumentStore {
|
|
|
256
256
|
private decodeFieldValue;
|
|
257
257
|
private decodeMapValue;
|
|
258
258
|
private decodeNestedValue;
|
|
259
|
+
private normalizeWriteValue;
|
|
260
|
+
private fillScalarDefaults;
|
|
259
261
|
hydrate(data: DocumentRecord, originalData?: DocumentRecord): any;
|
|
260
262
|
private runHooks;
|
|
261
263
|
private insertStmt;
|
|
@@ -18,5 +18,8 @@ export declare class SolidCache extends SolidCache_base implements CacheAdaptor
|
|
|
18
18
|
}): Promise<void>;
|
|
19
19
|
hget<T extends string | number | Buffer>(topic: string, key: string, subKey: string): Promise<T | undefined>;
|
|
20
20
|
hdelete(topic: string, key: string, subKey: string): Promise<void>;
|
|
21
|
+
hkeys(topic: string, key: string): Promise<string[]>;
|
|
22
|
+
hentries<T extends string | number | Buffer>(topic: string, key: string): Promise<[string, T][]>;
|
|
23
|
+
hclear(topic: string, key: string): Promise<void>;
|
|
21
24
|
}
|
|
22
25
|
export {};
|
|
@@ -18,9 +18,6 @@ declare const BaseEndpoint_base: import("./endpoint.d.ts").EndpointCls<import("a
|
|
|
18
18
|
pingQuery: import("./endpointInfo.d.ts").EndpointInfo<"query", {
|
|
19
19
|
baseService: import("akanjs/service").BaseService;
|
|
20
20
|
}, [string], [arg?: string | null | undefined], [], [arg: string | undefined], StringConstructor, string, string, true>;
|
|
21
|
-
cleanup: import("./endpointInfo.d.ts").EndpointInfo<"mutation", {
|
|
22
|
-
baseService: import("akanjs/service").BaseService;
|
|
23
|
-
}, [], [], [], [], BooleanConstructor, boolean, Promise<boolean>, false>;
|
|
24
21
|
wsPing: import("./endpointInfo.d.ts").EndpointInfo<"message", {
|
|
25
22
|
baseService: import("akanjs/service").BaseService;
|
|
26
23
|
}, [string], [arg?: string | null | undefined], [], [arg: string | undefined], StringConstructor, string, string, false>;
|
package/types/signal/types.d.ts
CHANGED
|
@@ -60,6 +60,8 @@ export interface SignalOption<Response = any, Nullable extends boolean = false,
|
|
|
60
60
|
middlewares?: MiddlewareCls[];
|
|
61
61
|
prefix?: false | string;
|
|
62
62
|
globalPrefix?: false;
|
|
63
|
+
/** Marks this mutation as the framework file-upload endpoint (see resolveFileUploadCapability). */
|
|
64
|
+
fileUpload?: boolean;
|
|
63
65
|
scheduleType?: "init" | "destroy" | "cron" | "interval" | "timeout";
|
|
64
66
|
scheduleCron?: string;
|
|
65
67
|
scheduleTime?: number;
|
|
@@ -72,6 +74,7 @@ interface SerializedSignalOption {
|
|
|
72
74
|
prefix?: false | string;
|
|
73
75
|
globalPrefix?: false;
|
|
74
76
|
guards?: string[];
|
|
77
|
+
fileUpload?: boolean;
|
|
75
78
|
}
|
|
76
79
|
export interface SerializedSlice extends SerializedSignalOption {
|
|
77
80
|
}
|
|
@@ -6,4 +6,4 @@ export interface ModalProps {
|
|
|
6
6
|
children?: ReactNode;
|
|
7
7
|
onCancel?: () => void;
|
|
8
8
|
}
|
|
9
|
-
export declare const Modal: ({ className, bodyClassName, confirmClose, children, onCancel }: ModalProps) => import("react
|
|
9
|
+
export declare const Modal: ({ className, bodyClassName, confirmClose, children, onCancel }: ModalProps) => import("react").ReactPortal | null;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type ProviderProps } from "./Provider.d.ts";
|
|
2
2
|
export declare const Dialog: {
|
|
3
3
|
({ children, ...props }: ProviderProps): import("react/jsx-runtime").JSX.Element;
|
|
4
|
-
Modal: ({ className, bodyClassName, confirmClose, children, onCancel }: import("./Modal.d.ts").ModalProps) => import("react
|
|
4
|
+
Modal: ({ className, bodyClassName, confirmClose, children, onCancel }: import("./Modal.d.ts").ModalProps) => import("react").ReactPortal | null;
|
|
5
5
|
Title: ({ children }: import("./Title.d.ts").TitleProps) => null;
|
|
6
6
|
Action: ({ children }: import("./Action.d.ts").ActionProps) => null;
|
|
7
7
|
Trigger: ({ className, children }: import("./Trigger.d.ts").TriggerProps) => import("react/jsx-runtime").JSX.Element;
|
package/types/ui/Modal.d.ts
CHANGED
|
@@ -16,15 +16,4 @@ export interface ModalProps {
|
|
|
16
16
|
/** Ask for close confirmation before dismissing. */
|
|
17
17
|
confirmClose?: boolean;
|
|
18
18
|
}
|
|
19
|
-
export declare const Modal: {
|
|
20
|
-
({ className, title, action, open, onCancel, bodyClassName, children, confirmClose, }: ModalProps): import("react/jsx-runtime").JSX.Element;
|
|
21
|
-
Window: ({ open, onCancel, title, children }: WindowProps) => import("react/jsx-runtime").JSX.Element | null;
|
|
22
|
-
};
|
|
23
|
-
interface WindowProps {
|
|
24
|
-
open: boolean;
|
|
25
|
-
onCancel: () => void;
|
|
26
|
-
title: ReactNode;
|
|
27
|
-
children: ReactNode;
|
|
28
|
-
}
|
|
29
|
-
export declare const Window: ({ open, onCancel, title, children }: WindowProps) => import("react/jsx-runtime").JSX.Element | null;
|
|
30
|
-
export {};
|
|
19
|
+
export declare const Modal: ({ className, title, action, open, onCancel, bodyClassName, children, confirmClose, }: ModalProps) => import("react/jsx-runtime").JSX.Element;
|
package/types/ui/System/CSR.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ export declare const CSR: {
|
|
|
5
5
|
({ children }: {
|
|
6
6
|
children: ReactNode;
|
|
7
7
|
}): import("react/jsx-runtime").JSX.Element;
|
|
8
|
-
Provider: ({ className, appName, params, head, manifest, env, theme, prefix, children, gaTrackingId, fonts, layoutStyle, reconnect, of, }: CSRProviderProps) => import("react/jsx-runtime").JSX.Element;
|
|
8
|
+
Provider: ({ className, appName, params, head, manifest, env, theme, prefix, children, gaTrackingId, fonts, layoutStyle, reconnect, wsConnect, of, }: CSRProviderProps) => import("react/jsx-runtime").JSX.Element;
|
|
9
9
|
Wrapper: ({ children, lang, head, manifest, fonts, appName, className, prefix, layoutStyle, }: CSRWrapperProps) => import("react/jsx-runtime").JSX.Element;
|
|
10
10
|
Inner: () => import("react/jsx-runtime").JSX.Element;
|
|
11
11
|
Bridge: ({ lang, prefix }: CSRBridgeProps) => null;
|
|
@@ -13,7 +13,7 @@ export declare const CSR: {
|
|
|
13
13
|
export type CSRProviderProps = ProviderProps & {
|
|
14
14
|
fonts: ReactFont[];
|
|
15
15
|
};
|
|
16
|
-
declare const CSRProvider: ({ className, appName, params, head, manifest, env, theme, prefix, children, gaTrackingId, fonts, layoutStyle, reconnect, of, }: CSRProviderProps) => import("react/jsx-runtime").JSX.Element;
|
|
16
|
+
declare const CSRProvider: ({ className, appName, params, head, manifest, env, theme, prefix, children, gaTrackingId, fonts, layoutStyle, reconnect, wsConnect, of, }: CSRProviderProps) => import("react/jsx-runtime").JSX.Element;
|
|
17
17
|
interface CSRWrapperProps {
|
|
18
18
|
className?: string;
|
|
19
19
|
appName: string;
|
|
@@ -6,9 +6,9 @@ import { type HTMLAttributes, type ReactNode, type RefObject } from "react";
|
|
|
6
6
|
export declare const Client: {
|
|
7
7
|
(): import("react/jsx-runtime").JSX.Element;
|
|
8
8
|
Wrapper: ({ children, theme, lang, dictionary, signals, reconnect, }: ClientWrapperProps) => import("react/jsx-runtime").JSX.Element;
|
|
9
|
-
Bridge: ({ env, lang, theme, prefix, gaTrackingId, }: ClientBridgeProps) => "" | import("react/jsx-runtime").JSX.Element | undefined;
|
|
9
|
+
Bridge: ({ env, lang, theme, prefix, gaTrackingId, wsConnect }: ClientBridgeProps) => "" | import("react/jsx-runtime").JSX.Element | undefined;
|
|
10
10
|
Inner: () => import("react/jsx-runtime").JSX.Element;
|
|
11
|
-
SsrBridge: ({ lang, prefix
|
|
11
|
+
SsrBridge: ({ lang, prefix }: ClientSsrBridgeProps) => null;
|
|
12
12
|
};
|
|
13
13
|
interface ClientWrapperProps {
|
|
14
14
|
children: ReactNode;
|
|
@@ -36,12 +36,13 @@ interface ClientBridgeProps {
|
|
|
36
36
|
theme?: AkanTheme;
|
|
37
37
|
prefix?: string;
|
|
38
38
|
gaTrackingId?: string;
|
|
39
|
+
wsConnect?: boolean;
|
|
39
40
|
}
|
|
40
|
-
export declare const ClientBridge: ({ env, lang, theme, prefix, gaTrackingId, }: ClientBridgeProps) => "" | import("react/jsx-runtime").JSX.Element | undefined;
|
|
41
|
+
export declare const ClientBridge: ({ env, lang, theme, prefix, gaTrackingId, wsConnect }: ClientBridgeProps) => "" | import("react/jsx-runtime").JSX.Element | undefined;
|
|
41
42
|
export declare const ClientInner: () => import("react/jsx-runtime").JSX.Element;
|
|
42
43
|
interface ClientSsrBridgeProps {
|
|
43
44
|
lang: string;
|
|
44
45
|
prefix?: string;
|
|
45
46
|
}
|
|
46
|
-
export declare const ClientSsrBridge: ({ lang, prefix
|
|
47
|
+
export declare const ClientSsrBridge: ({ lang, prefix }: ClientSsrBridgeProps) => null;
|
|
47
48
|
export {};
|
|
@@ -28,6 +28,8 @@ export interface ProviderProps {
|
|
|
28
28
|
layoutStyle?: "mobile" | "web";
|
|
29
29
|
/** Enable reconnect helper. Defaults to local operation mode in CSR. */
|
|
30
30
|
reconnect?: boolean;
|
|
31
|
+
/** Connect the client WebSocket runtime after the browser loads. */
|
|
32
|
+
wsConnect?: boolean;
|
|
31
33
|
/** Active-locale dictionary injected by the server (SSR only) to seed the client Translator. */
|
|
32
34
|
dictionary?: Record<string, Record<string, unknown>>;
|
|
33
35
|
/**
|
package/types/ui/System/SSR.d.ts
CHANGED
|
@@ -3,13 +3,13 @@ import { type ReactNode } from "react";
|
|
|
3
3
|
import { type ProviderProps } from "./Common.d.ts";
|
|
4
4
|
export declare const SSR: {
|
|
5
5
|
(): import("react/jsx-runtime").JSX.Element;
|
|
6
|
-
Provider: ({ className, appName, params, head, manifest, env, gaTrackingId, children, theme, prefix, fonts, layoutStyle, reconnect, dictionary, allDictionary, of, }: SSRProviderProps) => import("react/jsx-runtime").JSX.Element;
|
|
6
|
+
Provider: ({ className, appName, params, head, manifest, env, gaTrackingId, children, theme, prefix, fonts, layoutStyle, reconnect, wsConnect, dictionary, allDictionary, of, }: SSRProviderProps) => import("react/jsx-runtime").JSX.Element;
|
|
7
7
|
Wrapper: ({ children, head, manifest, fonts, className, prefix, layoutStyle, }: SSRWrapperProps) => import("react/jsx-runtime").JSX.Element;
|
|
8
8
|
};
|
|
9
9
|
export type SSRProviderProps = ProviderProps & {
|
|
10
10
|
fonts?: ReactFont[];
|
|
11
11
|
};
|
|
12
|
-
declare const SSRProvider: ({ className, appName, params, head, manifest, env, gaTrackingId, children, theme, prefix, fonts, layoutStyle, reconnect, dictionary, allDictionary, of, }: SSRProviderProps) => import("react/jsx-runtime").JSX.Element;
|
|
12
|
+
declare const SSRProvider: ({ className, appName, params, head, manifest, env, gaTrackingId, children, theme, prefix, fonts, layoutStyle, reconnect, wsConnect, dictionary, allDictionary, of, }: SSRProviderProps) => import("react/jsx-runtime").JSX.Element;
|
|
13
13
|
interface SSRWrapperProps {
|
|
14
14
|
className?: string;
|
|
15
15
|
appName: string;
|