akanjs 3.0.0-alpha.44 → 3.0.0-alpha.46
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/base/primitiveRegistry.ts +14 -10
- package/common/index.ts +1 -0
- package/common/routeConvention.ts +22 -12
- package/fetch/client/fetchClient.ts +31 -8
- package/fetch/client/wsClient.ts +18 -10
- package/fetch/fetchType/endpointFetch.type.ts +1 -1
- package/local/apps/serverLifecycle/serverLifecycle-local.db-shm +0 -0
- package/local/apps/serverLifecycle/serverLifecycle-local_solid.db-shm +0 -0
- package/package.json +1 -1
- package/service/adapt.ts +4 -4
- package/service/predefinedAdaptor/database.adaptor.ts +2 -0
- package/service/serve.ts +7 -6
- package/signal/intercept.ts +4 -4
- package/types/base/primitiveRegistry.d.ts +6 -6
- package/types/common/index.d.ts +1 -1
- package/types/common/routeConvention.d.ts +6 -0
- package/types/fetch/fetchType/endpointFetch.type.d.ts +1 -1
- package/types/service/adapt.d.ts +2 -2
- package/types/service/serve.d.ts +2 -2
- package/types/signal/intercept.d.ts +2 -2
|
@@ -209,12 +209,12 @@ declare global {
|
|
|
209
209
|
[DEFAULT_VALUE]: boolean;
|
|
210
210
|
[PURIFIED_VALUE]: boolean;
|
|
211
211
|
[EXAMPLE_VALUE]: boolean;
|
|
212
|
-
validate(value: boolean | number): boolean;
|
|
213
|
-
parseValue(input: boolean | number): boolean | number;
|
|
214
|
-
serializeValue(value: boolean | number): boolean | number;
|
|
215
|
-
_parse(input: boolean | number): boolean;
|
|
216
|
-
_serialize(value: boolean | number): boolean;
|
|
217
|
-
_checkValue(value: boolean | number): void;
|
|
212
|
+
validate(value: boolean | number | string): boolean;
|
|
213
|
+
parseValue(input: boolean | number | string): boolean | number | string;
|
|
214
|
+
serializeValue(value: boolean | number | string): boolean | number | string;
|
|
215
|
+
_parse(input: boolean | number | string): boolean;
|
|
216
|
+
_serialize(value: boolean | number | string): boolean;
|
|
217
|
+
_checkValue(value: boolean | number | string): void;
|
|
218
218
|
}
|
|
219
219
|
interface DateConstructor {
|
|
220
220
|
refName: "Date";
|
|
@@ -305,10 +305,14 @@ Object.assign(String, scalarPrimitiveStatics, {
|
|
|
305
305
|
});
|
|
306
306
|
PrimitiveRegistry.register(String);
|
|
307
307
|
|
|
308
|
-
const normalizeBooleanPrimitiveValue = (value: boolean | number): boolean | null => {
|
|
308
|
+
const normalizeBooleanPrimitiveValue = (value: boolean | number | string): boolean | null => {
|
|
309
309
|
if (typeof value === "boolean") return value;
|
|
310
310
|
if (value === 1) return true;
|
|
311
311
|
if (value === 0) return false;
|
|
312
|
+
if (typeof value !== "string") return null;
|
|
313
|
+
const text = value.trim().toLowerCase();
|
|
314
|
+
if (text === "true" || text === "1") return true;
|
|
315
|
+
if (text === "false" || text === "0") return false;
|
|
312
316
|
return null;
|
|
313
317
|
};
|
|
314
318
|
|
|
@@ -317,13 +321,13 @@ Object.assign(Boolean, {
|
|
|
317
321
|
refName: "Boolean",
|
|
318
322
|
[DEFAULT_VALUE]: false,
|
|
319
323
|
[EXAMPLE_VALUE]: true,
|
|
320
|
-
validate(value: boolean | number) {
|
|
324
|
+
validate(value: boolean | number | string) {
|
|
321
325
|
return normalizeBooleanPrimitiveValue(value) !== null;
|
|
322
326
|
},
|
|
323
|
-
parseValue(input: boolean | number) {
|
|
327
|
+
parseValue(input: boolean | number | string) {
|
|
324
328
|
return normalizeBooleanPrimitiveValue(input) ?? input;
|
|
325
329
|
},
|
|
326
|
-
serializeValue(value: boolean | number) {
|
|
330
|
+
serializeValue(value: boolean | number | string) {
|
|
327
331
|
return normalizeBooleanPrimitiveValue(value) ?? value;
|
|
328
332
|
},
|
|
329
333
|
});
|
package/common/index.ts
CHANGED
|
@@ -67,27 +67,37 @@ export function isRouteSourceFile(filePath: string): boolean {
|
|
|
67
67
|
return tryParseRouteModuleKey(key) !== null;
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
-
|
|
71
|
-
|
|
70
|
+
/**
|
|
71
|
+
* Why a `page/` file breaks the route convention, or null when it is fine. Null also covers a non-source
|
|
72
|
+
* asset, which `page/` tolerates. `akan sync <lib>` reports these alongside its other layout violations,
|
|
73
|
+
* so the rule stays in one place instead of being restated where it cannot afford to throw.
|
|
74
|
+
*/
|
|
75
|
+
export function getPageSourceFileViolation(filePath: string): string | null {
|
|
76
|
+
if (!SOURCE_EXT_RE.test(filePath)) return null;
|
|
72
77
|
|
|
73
78
|
const key = filePath.startsWith("./") ? filePath : `./${filePath.split(/[\\/]/).join("/")}`;
|
|
74
79
|
const match = ROUTE_SOURCE_RE.exec(key);
|
|
75
|
-
|
|
76
|
-
if (!match) throw new Error(`[route-convention] invalid page source file: ${displayPath}`);
|
|
80
|
+
if (!match) return "invalid page source file";
|
|
77
81
|
|
|
78
82
|
const file = match[1] as string;
|
|
79
83
|
const ext = match[2] as string;
|
|
80
84
|
const leaf = file.split("/").filter(Boolean).at(-1);
|
|
81
|
-
if (!leaf)
|
|
85
|
+
if (!leaf) return "invalid page source file";
|
|
82
86
|
|
|
83
|
-
if (ext !== "tsx")
|
|
87
|
+
if (ext !== "tsx") return "route source files under page/ must use .tsx";
|
|
84
88
|
if (leaf.startsWith("_") && !RESERVED_ROUTE_FILES.has(leaf) && leaf !== INTERNAL_ROOT_LAYOUT_LEAF)
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
89
|
+
return "only _index.tsx, _layout.tsx and _overrides.tsx are allowed as reserved route files under page/";
|
|
90
|
+
if (/^[A-Z]/.test(leaf)) return "route page filenames must not start with an uppercase letter";
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export function validatePageSourceFile(filePath: string, options: ValidatePageSourceFileOptions = {}): boolean {
|
|
95
|
+
if (!SOURCE_EXT_RE.test(filePath)) return false;
|
|
96
|
+
|
|
97
|
+
const violation = getPageSourceFileViolation(filePath);
|
|
98
|
+
if (!violation) return true;
|
|
99
|
+
const key = filePath.startsWith("./") ? filePath : `./${filePath.split(/[\\/]/).join("/")}`;
|
|
100
|
+
throw new Error(`[route-convention] ${violation}: ${options.filePath ?? key}`);
|
|
91
101
|
}
|
|
92
102
|
|
|
93
103
|
export function validateSubRoutePageKey(
|
|
@@ -81,6 +81,7 @@ export class FetchClient {
|
|
|
81
81
|
readonly handler: Record<string, FetchHandler>;
|
|
82
82
|
readonly slice: Record<string, SliceMeta> = {};
|
|
83
83
|
readonly sortKeyMap = new Map<string, string[]>();
|
|
84
|
+
readonly #originWs = new Map<string, WsClient>();
|
|
84
85
|
readonly #handlerStore: Record<string, FetchHandler> = {};
|
|
85
86
|
readonly #handlerFactory = new Map<string, FetchHandlerFactory>();
|
|
86
87
|
#sharedRegistryAppliedVersion = 0;
|
|
@@ -95,8 +96,7 @@ export class FetchClient {
|
|
|
95
96
|
) {
|
|
96
97
|
this.origin = origin;
|
|
97
98
|
this.http = new HttpClient(origin, ErrorCls);
|
|
98
|
-
|
|
99
|
-
this.ws = new WsClient(wsUri, ErrorCls);
|
|
99
|
+
this.ws = new WsClient(FetchClient.#makeWsUri(origin), ErrorCls);
|
|
100
100
|
Object.assign(this.#handlerStore, handler);
|
|
101
101
|
this.handler = this.#makeHandlerProxy();
|
|
102
102
|
this.applySignal(serializedSignal);
|
|
@@ -158,6 +158,7 @@ export class FetchClient {
|
|
|
158
158
|
this.ErrorCls = ErrorCls;
|
|
159
159
|
this.http.setErrorConstructor(ErrorCls);
|
|
160
160
|
this.ws.setErrorConstructor(ErrorCls);
|
|
161
|
+
for (const ws of this.#originWs.values()) ws.setErrorConstructor(ErrorCls);
|
|
161
162
|
}
|
|
162
163
|
applySignal(serializedSignal: { [key: string]: SerializedSignal }, { share = true }: { share?: boolean } = {}) {
|
|
163
164
|
if (share && Object.keys(serializedSignal).length > 0) {
|
|
@@ -232,6 +233,8 @@ export class FetchClient {
|
|
|
232
233
|
}
|
|
233
234
|
disconnect() {
|
|
234
235
|
this.ws.destroy();
|
|
236
|
+
for (const ws of this.#originWs.values()) ws.destroy();
|
|
237
|
+
this.#originWs.clear();
|
|
235
238
|
}
|
|
236
239
|
clone({ origin, connect = true, jwt }: { origin?: string; connect?: boolean; jwt?: string } = {}) {
|
|
237
240
|
const instance = new FetchClient(origin ?? this.origin, {}, this.serializedSignal, this.ErrorCls);
|
|
@@ -245,6 +248,20 @@ export class FetchClient {
|
|
|
245
248
|
setJwt(jwt: string | null) {
|
|
246
249
|
this.jwt = jwt;
|
|
247
250
|
this.ws.setJwt(jwt);
|
|
251
|
+
for (const ws of this.#originWs.values()) ws.setJwt(jwt);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
#resolveWs(origin?: string) {
|
|
255
|
+
if (!origin) return this.ws;
|
|
256
|
+
const target = origin.replace(/\/+$/, "");
|
|
257
|
+
if (target === this.origin.replace(/\/+$/, "")) return this.ws;
|
|
258
|
+
const cached = this.#originWs.get(target);
|
|
259
|
+
if (cached) return cached;
|
|
260
|
+
const ws = new WsClient(FetchClient.#makeWsUri(target), this.ErrorCls);
|
|
261
|
+
this.#originWs.set(target, ws);
|
|
262
|
+
ws.setJwt(this.jwt);
|
|
263
|
+
ws.connect();
|
|
264
|
+
return ws;
|
|
248
265
|
}
|
|
249
266
|
#makeAuthHeaders(option?: FetchPolicy): Record<string, string> {
|
|
250
267
|
if (option?.token) return { Authorization: `Bearer ${option.token}` };
|
|
@@ -338,13 +355,13 @@ export class FetchClient {
|
|
|
338
355
|
handleEvent(parsedReturn);
|
|
339
356
|
};
|
|
340
357
|
wrappedListeners.set(handleEvent, wrapped);
|
|
341
|
-
this
|
|
358
|
+
const ws = this.#resolveWs(fetchPolicy?.origin);
|
|
359
|
+
ws.subscribe({
|
|
342
360
|
key,
|
|
343
361
|
data,
|
|
344
362
|
handleEvent: wrapped,
|
|
345
363
|
});
|
|
346
|
-
return () =>
|
|
347
|
-
this.ws.unsubscribe({ key, data, handleEvent: wrappedListeners.get(handleEvent) ?? handleEvent });
|
|
364
|
+
return () => ws.unsubscribe({ key, data, handleEvent: wrappedListeners.get(handleEvent) ?? handleEvent });
|
|
348
365
|
};
|
|
349
366
|
});
|
|
350
367
|
return;
|
|
@@ -356,8 +373,9 @@ export class FetchClient {
|
|
|
356
373
|
const serializerMap = this.#makeArgSerializer(endpoint.args);
|
|
357
374
|
return (...argData: unknown[]) => {
|
|
358
375
|
const args = argData.slice(0, msgArgLength);
|
|
376
|
+
const fetchPolicy = argData[msgArgLength] as FetchPolicy | undefined;
|
|
359
377
|
const data = msgArgs.map((arg, idx) => serializerMap.get(arg.name)?.(args[idx]) ?? null);
|
|
360
|
-
this.
|
|
378
|
+
this.#resolveWs(fetchPolicy?.origin).emit(key, data);
|
|
361
379
|
};
|
|
362
380
|
});
|
|
363
381
|
this.#setHandlerFactory(`listen${capitalize(key)}`, () => {
|
|
@@ -369,8 +387,9 @@ export class FetchClient {
|
|
|
369
387
|
handleEvent(parsedReturn);
|
|
370
388
|
};
|
|
371
389
|
wrappedListeners.set(handleEvent, wrapped);
|
|
372
|
-
this.
|
|
373
|
-
|
|
390
|
+
const ws = this.#resolveWs(fetchPolicy.origin);
|
|
391
|
+
ws.on(key, wrapped);
|
|
392
|
+
return () => ws.off(key, wrappedListeners.get(handleEvent) ?? handleEvent);
|
|
374
393
|
}) as FetchHandler;
|
|
375
394
|
});
|
|
376
395
|
return;
|
|
@@ -380,6 +399,10 @@ export class FetchClient {
|
|
|
380
399
|
break;
|
|
381
400
|
}
|
|
382
401
|
}
|
|
402
|
+
static #makeWsUri(origin: string) {
|
|
403
|
+
return `${origin.replace("http://", "ws://").replace("https://", "wss://")}/ws`;
|
|
404
|
+
}
|
|
405
|
+
|
|
383
406
|
static paginationArgs: SerializedArg[] = [
|
|
384
407
|
{ type: "search", name: "skip", refName: "Int" },
|
|
385
408
|
{ type: "search", name: "limit", refName: "Int" },
|
package/fetch/client/wsClient.ts
CHANGED
|
@@ -41,6 +41,7 @@ export class WsClient {
|
|
|
41
41
|
#listenerMap = new Map<string, Set<Listener>>();
|
|
42
42
|
#destroyed = false;
|
|
43
43
|
#connectRequested = false;
|
|
44
|
+
#outbox: string[] = [];
|
|
44
45
|
#unconnectedWarnTimers = new Map<string, ReturnType<typeof setTimeout>>();
|
|
45
46
|
#jwt: string | null = null;
|
|
46
47
|
connected = false;
|
|
@@ -94,6 +95,9 @@ export class WsClient {
|
|
|
94
95
|
const data: WebsocketReqData = { key: option.key, data: option.data, subscribe: true };
|
|
95
96
|
this.#ws?.send(JSON.stringify(data));
|
|
96
97
|
});
|
|
98
|
+
const queued = this.#outbox;
|
|
99
|
+
this.#outbox = [];
|
|
100
|
+
for (const frame of queued) this.#ws?.send(frame);
|
|
97
101
|
};
|
|
98
102
|
this.#ws.onmessage = (e) => {
|
|
99
103
|
try {
|
|
@@ -197,6 +201,7 @@ export class WsClient {
|
|
|
197
201
|
}
|
|
198
202
|
for (const timer of this.#unconnectedWarnTimers.values()) clearTimeout(timer);
|
|
199
203
|
this.#unconnectedWarnTimers.clear();
|
|
204
|
+
this.#outbox = [];
|
|
200
205
|
this.#ws?.close();
|
|
201
206
|
this.#ws = null;
|
|
202
207
|
}
|
|
@@ -240,28 +245,31 @@ export class WsClient {
|
|
|
240
245
|
`[akanjs] WebSocket is not connected. Call fetch.instance.connect(), or drop the root layout "wsConnect = false", before ${action} "${key}".`,
|
|
241
246
|
);
|
|
242
247
|
}
|
|
243
|
-
#
|
|
244
|
-
|
|
248
|
+
#warnUnconnected(action: "emit" | "subscribe", key: string) {
|
|
249
|
+
const timerKey = `${action}:${key}`;
|
|
250
|
+
if (this.#connectRequested || this.#unconnectedWarnTimers.has(timerKey)) return;
|
|
245
251
|
const timer = setTimeout(() => {
|
|
246
|
-
this.#unconnectedWarnTimers.delete(
|
|
252
|
+
this.#unconnectedWarnTimers.delete(timerKey);
|
|
247
253
|
if (this.#connectRequested || this.#destroyed) return;
|
|
248
|
-
this.#warnNotConnected(
|
|
254
|
+
this.#warnNotConnected(action, key);
|
|
249
255
|
}, 0);
|
|
250
|
-
this.#unconnectedWarnTimers.set(
|
|
256
|
+
this.#unconnectedWarnTimers.set(timerKey, timer);
|
|
251
257
|
}
|
|
252
258
|
emit(key: string, data: WsRequestPayload) {
|
|
259
|
+
const payload: WebsocketReqData = { key, data: Array.isArray(data) ? data : [data] };
|
|
260
|
+
const frame = JSON.stringify(payload);
|
|
261
|
+
|
|
253
262
|
if (this.#ws?.readyState !== WebSocket.OPEN) {
|
|
254
|
-
this.
|
|
255
|
-
this.#
|
|
263
|
+
this.#outbox.push(frame);
|
|
264
|
+
this.#warnUnconnected("emit", key);
|
|
256
265
|
return this;
|
|
257
266
|
}
|
|
258
|
-
|
|
259
|
-
this.#ws.send(JSON.stringify(payload));
|
|
267
|
+
this.#ws.send(frame);
|
|
260
268
|
return this;
|
|
261
269
|
}
|
|
262
270
|
subscribe(option: { key: string; data: unknown[]; handleEvent: (data: unknown) => void }) {
|
|
263
271
|
const roomId = WsClient.makeRoomId(option.key, option.data);
|
|
264
|
-
if (!this.#ws) this.#
|
|
272
|
+
if (!this.#ws) this.#warnUnconnected("subscribe", option.key);
|
|
265
273
|
if (!this.#roomSubscribeMap.has(roomId)) {
|
|
266
274
|
this.#roomSubscribeMap.set(roomId, { key: option.key, data: option.data, listener: new Set() });
|
|
267
275
|
if (this.#ws?.readyState === WebSocket.OPEN) {
|
|
@@ -44,7 +44,7 @@ type QueryOrMutationFetchFn<E, SlceCls extends SliceCls | never> = (
|
|
|
44
44
|
/** Typed off `PromptResult` rather than the endpoint's return ref, which is the `Any` carrier a prompt rides on. */
|
|
45
45
|
type PromptFetchFn<E> = (...args: [...EndpInfoArgs<E>, fetchPolicy?: FetchPolicy]) => Promise<PromptMessage[]>;
|
|
46
46
|
|
|
47
|
-
type MessageEmitFn<E> = (...args: EndpInfoArgs<E
|
|
47
|
+
type MessageEmitFn<E> = (...args: [...EndpInfoArgs<E>, fetchPolicy?: FetchPolicy]) => void;
|
|
48
48
|
|
|
49
49
|
type MessageListenFn<E, SlceCls extends SliceCls | never> = (
|
|
50
50
|
handleEvent: (data: EndpInfoReturns<E, SlceCls>) => PromiseOrObject<void>,
|
|
Binary file
|
|
Binary file
|
package/package.json
CHANGED
package/service/adapt.ts
CHANGED
|
@@ -4,8 +4,8 @@ import { type ExtractInjectInfoObject, type InjectBuilder, type InjectInfo, inje
|
|
|
4
4
|
|
|
5
5
|
export interface Adaptor {
|
|
6
6
|
readonly logger: Logger;
|
|
7
|
-
onInit(): Promise<void
|
|
8
|
-
onDestroy(): Promise<void
|
|
7
|
+
onInit(): Promise<void> | void;
|
|
8
|
+
onDestroy(): Promise<void> | void;
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
export type AdaptorCls<
|
|
@@ -30,9 +30,9 @@ export function adapt(name: string, injectBuilder?: InjectBuilder) {
|
|
|
30
30
|
readonly logger = new Logger(name);
|
|
31
31
|
static readonly [INJECT_META] = injectInfoMap;
|
|
32
32
|
static readonly refName = name;
|
|
33
|
-
|
|
33
|
+
onInit(): Promise<void> | void {
|
|
34
34
|
}
|
|
35
|
-
|
|
35
|
+
onDestroy(): Promise<void> | void {
|
|
36
36
|
}
|
|
37
37
|
}
|
|
38
38
|
return Adaptor;
|
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
type DocumentUpdateOptions,
|
|
19
19
|
documentQueryHelper,
|
|
20
20
|
encodeDocumentValue,
|
|
21
|
+
isDocumentId,
|
|
21
22
|
isDocumentUpdateNode,
|
|
22
23
|
NoDocumentError,
|
|
23
24
|
resolveDocumentUpdate,
|
|
@@ -1033,6 +1034,7 @@ export class SqlDocumentStore {
|
|
|
1033
1034
|
async create(data: DocumentRecord, { runSaveHooks = true }: WriteHookOptions = {}) {
|
|
1034
1035
|
const now = Date.now();
|
|
1035
1036
|
const id = data.id ?? createDocumentId(now);
|
|
1037
|
+
if (!isDocumentId(id)) throw new Error(`Invalid ID value: ${id}`);
|
|
1036
1038
|
const doc = this.hydrate(
|
|
1037
1039
|
this.prepareDocument({
|
|
1038
1040
|
...data,
|
package/service/serve.ts
CHANGED
|
@@ -43,9 +43,9 @@ const avoidKeys = new Set([
|
|
|
43
43
|
export interface Service {
|
|
44
44
|
readonly logger: Logger;
|
|
45
45
|
|
|
46
|
-
onInit(): Promise<void
|
|
46
|
+
onInit(): Promise<void> | void;
|
|
47
47
|
_libsOnInit(): Promise<void>;
|
|
48
|
-
onDestroy(): Promise<void
|
|
48
|
+
onDestroy(): Promise<void> | void;
|
|
49
49
|
_libsOnDestroy(): Promise<void>;
|
|
50
50
|
}
|
|
51
51
|
|
|
@@ -121,9 +121,9 @@ export function serve(
|
|
|
121
121
|
}
|
|
122
122
|
static [INJECT_META] = {};
|
|
123
123
|
readonly logger = new Logger(this.constructor.name);
|
|
124
|
-
|
|
124
|
+
onInit(): Promise<void> | void {
|
|
125
125
|
}
|
|
126
|
-
|
|
126
|
+
onDestroy(): Promise<void> | void {
|
|
127
127
|
}
|
|
128
128
|
};
|
|
129
129
|
applyMixins(srvRef, extSrvs, avoidKeys);
|
|
@@ -132,10 +132,11 @@ export function serve(
|
|
|
132
132
|
const onDestroyFns = extSrvs.map((srv) => srv.prototype.onDestroy);
|
|
133
133
|
Object.assign(srvRef.prototype, {
|
|
134
134
|
async _libsOnInit(this: Service) {
|
|
135
|
-
|
|
135
|
+
|
|
136
|
+
await Promise.all([...onInitFns, this.onInit].map(async (onInit) => await onInit?.call(this)));
|
|
136
137
|
},
|
|
137
138
|
async _libsOnDestroy(this: Service) {
|
|
138
|
-
await Promise.all([...onDestroyFns.map((onDestroy) => onDestroy?.call(this))
|
|
139
|
+
await Promise.all([...onDestroyFns, this.onDestroy].map(async (onDestroy) => await onDestroy?.call(this)));
|
|
139
140
|
},
|
|
140
141
|
});
|
|
141
142
|
|
package/signal/intercept.ts
CHANGED
|
@@ -7,8 +7,8 @@ export type InterceptorCls<Methods = {}, InjectMap extends { [key: string]: Inje
|
|
|
7
7
|
Methods &
|
|
8
8
|
ExtractInjectInfoObject<InjectMap> & {
|
|
9
9
|
readonly logger: Logger;
|
|
10
|
-
onInit(): Promise<void
|
|
11
|
-
onDestroy(): Promise<void
|
|
10
|
+
onInit(): Promise<void> | void;
|
|
11
|
+
onDestroy(): Promise<void> | void;
|
|
12
12
|
intercept(context: SignalContext): AsyncGenerator<unknown> | Promise<unknown>;
|
|
13
13
|
},
|
|
14
14
|
{ readonly [INJECT_META]: InjectMap; readonly refName: string }
|
|
@@ -31,9 +31,9 @@ export function intercept(refName: string, injectBuilder?: InjectBuilder) {
|
|
|
31
31
|
intercept(context: SignalContext): AsyncGenerator | Promise<(res: Response) => Promise<Response>> {
|
|
32
32
|
return Promise.resolve((res: Response) => Promise.resolve(res));
|
|
33
33
|
}
|
|
34
|
-
|
|
34
|
+
onInit(): Promise<void> | void {
|
|
35
35
|
}
|
|
36
|
-
|
|
36
|
+
onDestroy(): Promise<void> | void {
|
|
37
37
|
}
|
|
38
38
|
};
|
|
39
39
|
}
|
|
@@ -114,12 +114,12 @@ declare global {
|
|
|
114
114
|
[DEFAULT_VALUE]: boolean;
|
|
115
115
|
[PURIFIED_VALUE]: boolean;
|
|
116
116
|
[EXAMPLE_VALUE]: boolean;
|
|
117
|
-
validate(value: boolean | number): boolean;
|
|
118
|
-
parseValue(input: boolean | number): boolean | number;
|
|
119
|
-
serializeValue(value: boolean | number): boolean | number;
|
|
120
|
-
_parse(input: boolean | number): boolean;
|
|
121
|
-
_serialize(value: boolean | number): boolean;
|
|
122
|
-
_checkValue(value: boolean | number): void;
|
|
117
|
+
validate(value: boolean | number | string): boolean;
|
|
118
|
+
parseValue(input: boolean | number | string): boolean | number | string;
|
|
119
|
+
serializeValue(value: boolean | number | string): boolean | number | string;
|
|
120
|
+
_parse(input: boolean | number | string): boolean;
|
|
121
|
+
_serialize(value: boolean | number | string): boolean;
|
|
122
|
+
_checkValue(value: boolean | number | string): void;
|
|
123
123
|
}
|
|
124
124
|
interface DateConstructor {
|
|
125
125
|
refName: "Date";
|
package/types/common/index.d.ts
CHANGED
|
@@ -24,7 +24,7 @@ export { pathGet } from "./pathGet.d.ts";
|
|
|
24
24
|
export { pathSet } from "./pathSet.d.ts";
|
|
25
25
|
export { randomPick } from "./randomPick.d.ts";
|
|
26
26
|
export { randomPicks } from "./randomPicks.d.ts";
|
|
27
|
-
export { assertUniqueRoutePatterns, compareRouteSpecificity, getRouteExports, isRouteSourceFile, isSpecialRouteLeaf, LAYOUT_ROUTE_EXPORTS, matchRoutePattern, normalizeRoutePattern, PAGE_ROUTE_EXPORTS, type ParsedRouteModuleKey, parseRouteModuleKey, RESERVED_ROUTE_CONFIG_EXPORTS, ROOT_LAYOUT_ROUTE_EXPORTS, type RouteModuleKind, routeSegmentToPatternPart, routeSegmentToTreePath, tryParseRouteModuleKey, type ValidatePageSourceFileOptions, type ValidateSubRoutePageKeyOptions, validatePageSourceFile, validateSubRoutePageKey, } from "./routeConvention.d.ts";
|
|
27
|
+
export { assertUniqueRoutePatterns, compareRouteSpecificity, getPageSourceFileViolation, getRouteExports, isRouteSourceFile, isSpecialRouteLeaf, LAYOUT_ROUTE_EXPORTS, matchRoutePattern, normalizeRoutePattern, PAGE_ROUTE_EXPORTS, type ParsedRouteModuleKey, parseRouteModuleKey, RESERVED_ROUTE_CONFIG_EXPORTS, ROOT_LAYOUT_ROUTE_EXPORTS, type RouteModuleKind, routeSegmentToPatternPart, routeSegmentToTreePath, tryParseRouteModuleKey, type ValidatePageSourceFileOptions, type ValidateSubRoutePageKeyOptions, validatePageSourceFile, validateSubRoutePageKey, } from "./routeConvention.d.ts";
|
|
28
28
|
export { sleep } from "./sleep.d.ts";
|
|
29
29
|
export { splitVersion } from "./splitVersion.d.ts";
|
|
30
30
|
export { getBasePathFromPathname, parseBasePaths, parseSubRouteHosts, resolveSubRouteHosts } from "./subRoute.d.ts";
|
|
@@ -27,6 +27,12 @@ export interface ValidatePageSourceFileOptions {
|
|
|
27
27
|
filePath?: string;
|
|
28
28
|
}
|
|
29
29
|
export declare function isRouteSourceFile(filePath: string): boolean;
|
|
30
|
+
/**
|
|
31
|
+
* Why a `page/` file breaks the route convention, or null when it is fine. Null also covers a non-source
|
|
32
|
+
* asset, which `page/` tolerates. `akan sync <lib>` reports these alongside its other layout violations,
|
|
33
|
+
* so the rule stays in one place instead of being restated where it cannot afford to throw.
|
|
34
|
+
*/
|
|
35
|
+
export declare function getPageSourceFileViolation(filePath: string): string | null;
|
|
30
36
|
export declare function validatePageSourceFile(filePath: string, options?: ValidatePageSourceFileOptions): boolean;
|
|
31
37
|
export declare function validateSubRoutePageKey(key: string, basePaths: Iterable<string>, options?: ValidateSubRoutePageKeyOptions): void;
|
|
32
38
|
export declare function parseRouteModuleKey(key: string): ParsedRouteModuleKey;
|
|
@@ -7,7 +7,7 @@ type EndpInfoReturns<E, SlceCls extends SliceCls | never> = EndpointClientReturn
|
|
|
7
7
|
type QueryOrMutationFetchFn<E, SlceCls extends SliceCls | never> = (...args: [...EndpInfoArgs<E>, fetchPolicy?: FetchPolicy]) => Promise<EndpInfoReturns<E, SlceCls>>;
|
|
8
8
|
/** Typed off `PromptResult` rather than the endpoint's return ref, which is the `Any` carrier a prompt rides on. */
|
|
9
9
|
type PromptFetchFn<E> = (...args: [...EndpInfoArgs<E>, fetchPolicy?: FetchPolicy]) => Promise<PromptMessage[]>;
|
|
10
|
-
type MessageEmitFn<E> = (...args: EndpInfoArgs<E
|
|
10
|
+
type MessageEmitFn<E> = (...args: [...EndpInfoArgs<E>, fetchPolicy?: FetchPolicy]) => void;
|
|
11
11
|
type MessageListenFn<E, SlceCls extends SliceCls | never> = (handleEvent: (data: EndpInfoReturns<E, SlceCls>) => PromiseOrObject<void>, options?: FetchPolicy) => () => void;
|
|
12
12
|
type PubsubSubscribeFn<E, SlceCls extends SliceCls | never> = (...args: [
|
|
13
13
|
...EndpInfoArgs<E>,
|
package/types/service/adapt.d.ts
CHANGED
|
@@ -3,8 +3,8 @@ import { Logger } from "akanjs/common";
|
|
|
3
3
|
import { type ExtractInjectInfoObject, type InjectBuilder, type InjectInfo } from "./injectInfo.d.ts";
|
|
4
4
|
export interface Adaptor {
|
|
5
5
|
readonly logger: Logger;
|
|
6
|
-
onInit(): Promise<void
|
|
7
|
-
onDestroy(): Promise<void
|
|
6
|
+
onInit(): Promise<void> | void;
|
|
7
|
+
onDestroy(): Promise<void> | void;
|
|
8
8
|
}
|
|
9
9
|
export type AdaptorCls<Methods = any, InjectMap extends Record<string, InjectInfo> = {}> = Cls<Methods & ExtractInjectInfoObject<InjectMap> & Adaptor, {
|
|
10
10
|
readonly [INJECT_META]: InjectMap;
|
package/types/service/serve.d.ts
CHANGED
|
@@ -10,9 +10,9 @@ interface ServiceOptions {
|
|
|
10
10
|
export type ServiceType = "database" | "plain";
|
|
11
11
|
export interface Service {
|
|
12
12
|
readonly logger: Logger;
|
|
13
|
-
onInit(): Promise<void
|
|
13
|
+
onInit(): Promise<void> | void;
|
|
14
14
|
_libsOnInit(): Promise<void>;
|
|
15
|
-
onDestroy(): Promise<void
|
|
15
|
+
onDestroy(): Promise<void> | void;
|
|
16
16
|
_libsOnDestroy(): Promise<void>;
|
|
17
17
|
}
|
|
18
18
|
export type ServiceCls<RefName extends string = string, Methods = {}, InjectMap extends {
|
|
@@ -6,8 +6,8 @@ export type InterceptorCls<Methods = {}, InjectMap extends {
|
|
|
6
6
|
[key: string]: InjectInfo;
|
|
7
7
|
} = {}> = Cls<Methods & ExtractInjectInfoObject<InjectMap> & {
|
|
8
8
|
readonly logger: Logger;
|
|
9
|
-
onInit(): Promise<void
|
|
10
|
-
onDestroy(): Promise<void
|
|
9
|
+
onInit(): Promise<void> | void;
|
|
10
|
+
onDestroy(): Promise<void> | void;
|
|
11
11
|
intercept(context: SignalContext): AsyncGenerator<unknown> | Promise<unknown>;
|
|
12
12
|
}, {
|
|
13
13
|
readonly [INJECT_META]: InjectMap;
|