akanjs 2.0.6 → 2.0.7
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.ko.md +1 -1
- package/README.md +1 -1
- package/cli/application/application.command.ts +4 -1
- package/cli/application/application.runner.ts +5 -7
- package/cli/build.ts +1 -0
- package/cli/index.js +114 -74
- package/constant/serialize.ts +1 -1
- package/devkit/capacitor.base.config.ts +18 -4
- package/devkit/capacitorApp.ts +118 -64
- package/devkit/mobile/mobileTarget.ts +2 -1
- package/devkit/scanInfo.ts +1 -0
- package/package.json +1 -1
- package/server/akanApp.ts +53 -12
- package/server/processMetricsCollector.ts +79 -1
- package/server/resolver/database.resolver.ts +82 -31
- package/server/resolver/signal.resolver.ts +67 -28
- package/service/ipcTypes.ts +5 -0
- package/service/predefinedAdaptor/database.adaptor.ts +95 -27
- package/service/predefinedAdaptor/solidSqlite.ts +7 -7
- package/service/predefinedAdaptor/storage.adaptor.ts +35 -9
- package/signal/index.ts +1 -0
- package/signal/middleware.ts +5 -1
- package/signal/signalContext.ts +85 -31
- package/signal/trace.ts +279 -0
- package/types/devkit/capacitorApp.d.ts +14 -5
- package/types/server/processMetricsCollector.d.ts +2 -0
- package/types/service/ipcTypes.d.ts +5 -0
- package/types/service/predefinedAdaptor/database.adaptor.d.ts +26 -32
- package/types/service/predefinedAdaptor/solidSqlite.d.ts +3 -3
- package/types/service/predefinedAdaptor/storage.adaptor.d.ts +8 -2
- package/types/signal/index.d.ts +1 -0
- package/types/signal/signalContext.d.ts +4 -1
- package/types/signal/trace.d.ts +97 -0
- package/types/ui/Signal/style.d.ts +15 -0
- package/ui/Signal/Arg.tsx +22 -15
- package/ui/Signal/Doc.tsx +28 -21
- package/ui/Signal/Listener.tsx +15 -39
- package/ui/Signal/Message.tsx +32 -50
- package/ui/Signal/Object.tsx +16 -13
- package/ui/Signal/PubSub.tsx +29 -47
- package/ui/Signal/Response.tsx +7 -17
- package/ui/Signal/RestApi.tsx +41 -57
- package/ui/Signal/WebSocket.tsx +1 -1
- package/ui/Signal/style.ts +36 -0
- package/webkit/useCsrValues.ts +147 -37
|
@@ -67,33 +67,20 @@ export interface DocumentStore {
|
|
|
67
67
|
modifiedCount: number;
|
|
68
68
|
upsertedId: string | null;
|
|
69
69
|
}>;
|
|
70
|
-
find(query?: DocumentQuery, options?:
|
|
71
|
-
sort?: SortOption;
|
|
72
|
-
skip?: number | null;
|
|
73
|
-
limit?: number | null;
|
|
74
|
-
sample?: number;
|
|
75
|
-
}): Promise<any[]>;
|
|
70
|
+
find(query?: DocumentQuery, options?: FindManyOptions): Promise<any[]>;
|
|
76
71
|
findIds(query?: DocumentQuery, options?: {
|
|
77
72
|
sort?: SortOption;
|
|
78
73
|
skip?: number | null;
|
|
79
74
|
limit?: number | null;
|
|
80
75
|
sample?: number;
|
|
81
76
|
}): Promise<string[]>;
|
|
82
|
-
findOne(query?: DocumentQuery, options?:
|
|
83
|
-
sort?: SortOption;
|
|
84
|
-
skip?: number | null;
|
|
85
|
-
sample?: boolean;
|
|
86
|
-
}): Promise<any | null>;
|
|
77
|
+
findOne(query?: DocumentQuery, options?: FindOneOptions): Promise<any | null>;
|
|
87
78
|
findId(query?: DocumentQuery, options?: {
|
|
88
79
|
sort?: SortOption;
|
|
89
80
|
skip?: number | null;
|
|
90
81
|
sample?: boolean;
|
|
91
82
|
}): Promise<string | null>;
|
|
92
|
-
pickOne(query?: DocumentQuery, options?:
|
|
93
|
-
sort?: SortOption;
|
|
94
|
-
skip?: number | null;
|
|
95
|
-
sample?: boolean;
|
|
96
|
-
}): Promise<any>;
|
|
83
|
+
pickOne(query?: DocumentQuery, options?: FindOneOptions): Promise<any>;
|
|
97
84
|
pickById(id: string): Promise<any>;
|
|
98
85
|
exists(query?: DocumentQuery): Promise<string | null>;
|
|
99
86
|
count(query?: DocumentQuery): Promise<number>;
|
|
@@ -128,6 +115,20 @@ type FieldMap = Record<string, {
|
|
|
128
115
|
[key: string]: unknown;
|
|
129
116
|
}>;
|
|
130
117
|
type SortOption = Record<string, 1 | -1> | null | undefined;
|
|
118
|
+
type ProjectionOption = Partial<Record<string, boolean>> | null | undefined;
|
|
119
|
+
type FindManyOptions = {
|
|
120
|
+
sort?: SortOption;
|
|
121
|
+
skip?: number | null;
|
|
122
|
+
limit?: number | null;
|
|
123
|
+
sample?: number;
|
|
124
|
+
select?: ProjectionOption;
|
|
125
|
+
};
|
|
126
|
+
type FindOneOptions = {
|
|
127
|
+
sort?: SortOption;
|
|
128
|
+
skip?: number | null;
|
|
129
|
+
sample?: boolean;
|
|
130
|
+
select?: ProjectionOption;
|
|
131
|
+
};
|
|
131
132
|
interface DocumentDatabaseOwner {
|
|
132
133
|
getConnection(): AkanSqlClient;
|
|
133
134
|
getMeta(key: string): Promise<string | undefined> | string | undefined;
|
|
@@ -214,33 +215,20 @@ export declare class SqliteDocumentStore {
|
|
|
214
215
|
modifiedCount: number;
|
|
215
216
|
upsertedId: string | null;
|
|
216
217
|
}>;
|
|
217
|
-
find(query?: DocumentQuery, options?:
|
|
218
|
-
sort?: SortOption;
|
|
219
|
-
skip?: number | null;
|
|
220
|
-
limit?: number | null;
|
|
221
|
-
sample?: number;
|
|
222
|
-
}): Promise<any[]>;
|
|
218
|
+
find(query?: DocumentQuery, options?: FindManyOptions): Promise<any[]>;
|
|
223
219
|
findIds(query?: DocumentQuery, options?: {
|
|
224
220
|
sort?: SortOption;
|
|
225
221
|
skip?: number | null;
|
|
226
222
|
limit?: number | null;
|
|
227
223
|
sample?: number;
|
|
228
224
|
}): Promise<string[]>;
|
|
229
|
-
findOne(query?: DocumentQuery, options?:
|
|
230
|
-
sort?: SortOption;
|
|
231
|
-
skip?: number | null;
|
|
232
|
-
sample?: boolean;
|
|
233
|
-
}): Promise<any>;
|
|
225
|
+
findOne(query?: DocumentQuery, options?: FindOneOptions): Promise<any>;
|
|
234
226
|
findId(query?: DocumentQuery, options?: {
|
|
235
227
|
sort?: SortOption;
|
|
236
228
|
skip?: number | null;
|
|
237
229
|
sample?: boolean;
|
|
238
230
|
}): Promise<string | null>;
|
|
239
|
-
pickOne(query?: DocumentQuery, options?:
|
|
240
|
-
sort?: SortOption;
|
|
241
|
-
skip?: number | null;
|
|
242
|
-
sample?: boolean;
|
|
243
|
-
}): Promise<any>;
|
|
231
|
+
pickOne(query?: DocumentQuery, options?: FindOneOptions): Promise<any>;
|
|
244
232
|
pickById(id: string): Promise<any>;
|
|
245
233
|
exists(query?: DocumentQuery): Promise<string | null>;
|
|
246
234
|
count(query?: DocumentQuery): Promise<number>;
|
|
@@ -259,6 +247,11 @@ export declare class SqliteDocumentStore {
|
|
|
259
247
|
private applyDocumentUpdate;
|
|
260
248
|
private toRow;
|
|
261
249
|
private fromRow;
|
|
250
|
+
private normalizeProjection;
|
|
251
|
+
private projectionSql;
|
|
252
|
+
private projectionAlias;
|
|
253
|
+
private fromProjectedRow;
|
|
254
|
+
private parseProjectedValue;
|
|
262
255
|
private decodeDocumentPayload;
|
|
263
256
|
private decodeFieldValue;
|
|
264
257
|
private decodeMapValue;
|
|
@@ -266,6 +259,7 @@ export declare class SqliteDocumentStore {
|
|
|
266
259
|
hydrate(data: DocumentRecord, originalData?: DocumentRecord): any;
|
|
267
260
|
private runHooks;
|
|
268
261
|
private insertStmt;
|
|
262
|
+
private prepareReadStmt;
|
|
269
263
|
private assertValidRefName;
|
|
270
264
|
}
|
|
271
265
|
declare const SqliteDatabase_base: import("..").AdaptorCls<{}, {
|
|
@@ -13,12 +13,12 @@ export interface SolidEnv extends BaseEnv {
|
|
|
13
13
|
workspaceRoot?: string;
|
|
14
14
|
solid?: SolidConfig;
|
|
15
15
|
}
|
|
16
|
-
export type SolidValueType = "string" | "number" | "buffer";
|
|
16
|
+
export type SolidValueType = "string" | "number" | "buffer" | "json";
|
|
17
17
|
export declare const getSolidConfig: (env: SolidEnv) => Required<SolidConfig>;
|
|
18
18
|
export declare const openSolidDatabase: (config: Required<SolidConfig>) => Promise<Database>;
|
|
19
|
-
export declare const encodeSolidValue: (value:
|
|
19
|
+
export declare const encodeSolidValue: (value: unknown) => {
|
|
20
20
|
type: SolidValueType;
|
|
21
21
|
value: string | Buffer;
|
|
22
22
|
};
|
|
23
|
-
export declare const decodeSolidValue: <T
|
|
23
|
+
export declare const decodeSolidValue: <T>(type: SolidValueType, value: string | Buffer | null) => T | undefined;
|
|
24
24
|
export declare const toEpochMs: (value?: Dayjs | number | null) => number | null;
|
|
@@ -15,6 +15,7 @@ export interface UploadRequest {
|
|
|
15
15
|
};
|
|
16
16
|
rename?: string;
|
|
17
17
|
host?: string;
|
|
18
|
+
access?: "public" | "private";
|
|
18
19
|
}
|
|
19
20
|
export interface CopyRequest {
|
|
20
21
|
bucket: string;
|
|
@@ -28,6 +29,7 @@ export interface UploadFromStreamRequest {
|
|
|
28
29
|
body: ReadableStream;
|
|
29
30
|
mimetype: string;
|
|
30
31
|
root?: string;
|
|
32
|
+
access?: "public" | "private";
|
|
31
33
|
updateProgress: (progress: {
|
|
32
34
|
loaded?: number;
|
|
33
35
|
total?: number;
|
|
@@ -49,15 +51,18 @@ export interface StorageAdaptor {
|
|
|
49
51
|
saveData(request: DownloadRequest): Promise<LocalFilePath>;
|
|
50
52
|
copyData(request: CopyRequest): Promise<string>;
|
|
51
53
|
deleteData(url: string): Promise<boolean>;
|
|
54
|
+
deleteDataByPath(path: string): Promise<boolean>;
|
|
52
55
|
}
|
|
53
56
|
export interface BlobStorageOptions extends BaseEnv {
|
|
54
57
|
blobStorage?: {
|
|
55
58
|
baseDir?: string;
|
|
59
|
+
privateBaseDir?: string;
|
|
56
60
|
urlPrefix?: string;
|
|
57
61
|
};
|
|
58
62
|
}
|
|
59
63
|
declare const BlobStorage_base: import("..").AdaptorCls<{}, {
|
|
60
64
|
root: import("..").InjectInfo<"env", string, BlobStorageOptions, never>;
|
|
65
|
+
privateRoot: import("..").InjectInfo<"env", string, BlobStorageOptions, never>;
|
|
61
66
|
urlPrefix: import("..").InjectInfo<"env", string | undefined, BlobStorageOptions, never>;
|
|
62
67
|
}>;
|
|
63
68
|
export declare class BlobStorage extends BlobStorage_base implements StorageAdaptor {
|
|
@@ -65,10 +70,11 @@ export declare class BlobStorage extends BlobStorage_base implements StorageAdap
|
|
|
65
70
|
readData(path: string): Promise<ReadableStream>;
|
|
66
71
|
readDataAsJson<T>(path: string): Promise<T>;
|
|
67
72
|
getDataList(prefix?: string): Promise<string[]>;
|
|
68
|
-
uploadDataFromLocal({ path, localPath, meta }: UploadRequest): Promise<string>;
|
|
69
|
-
uploadDataFromStream({ path, body, mimetype, updateProgress, uploadSuccess }: UploadFromStreamRequest): Promise<void>;
|
|
73
|
+
uploadDataFromLocal({ path, localPath, meta, access }: UploadRequest): Promise<string>;
|
|
74
|
+
uploadDataFromStream({ path, body, mimetype, updateProgress, uploadSuccess, access, }: UploadFromStreamRequest): Promise<void>;
|
|
70
75
|
saveData({ path, localPath, renamePath }: DownloadRequest): Promise<LocalFilePath>;
|
|
71
76
|
copyData({ copyPath, pastePath, host }: CopyRequest): Promise<string>;
|
|
77
|
+
deleteDataByPath(path: string): Promise<boolean>;
|
|
72
78
|
deleteData(url: string): Promise<boolean>;
|
|
73
79
|
}
|
|
74
80
|
export {};
|
package/types/signal/index.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { type ConstantFieldTypeInput } from "akanjs/constant";
|
|
|
3
3
|
import type { Adaptor, AdaptorCls, DatabaseService, InjectRegistry, LiveRegistry } from "akanjs/service";
|
|
4
4
|
import type { Internal, InternalInfo, MiddlewareCls } from ".";
|
|
5
5
|
import type { EndpointInfo } from "./endpointInfo.d.ts";
|
|
6
|
+
import { SignalTrace } from "./trace.d.ts";
|
|
6
7
|
export type SignalTransportType = "http" | "websocket";
|
|
7
8
|
interface WebSocketRequest {
|
|
8
9
|
ws: Bun.ServerWebSocket<unknown>;
|
|
@@ -19,6 +20,7 @@ export declare class SignalContext<Ctx extends HttpExecutionContext | WebSocketE
|
|
|
19
20
|
adaptor: Adaptor;
|
|
20
21
|
args: unknown[];
|
|
21
22
|
internalArgs: unknown[];
|
|
23
|
+
trace: SignalTrace | null;
|
|
22
24
|
constructor(key: string, reqOrWsReq: Bun.BunRequest | WebSocketRequest, { endpointInfo, adaptor, registry, env, live, middleware, }: {
|
|
23
25
|
endpointInfo: EndpointInfo;
|
|
24
26
|
adaptor: Adaptor;
|
|
@@ -48,6 +50,7 @@ export declare class SignalContext<Ctx extends HttpExecutionContext | WebSocketE
|
|
|
48
50
|
getEnv(): Env;
|
|
49
51
|
}
|
|
50
52
|
export declare class HttpExecutionContext<Appended = unknown> {
|
|
53
|
+
#private;
|
|
51
54
|
req: Bun.BunRequest & Appended;
|
|
52
55
|
res: {
|
|
53
56
|
new (body?: BodyInit | null, init?: ResponseInit): Response;
|
|
@@ -56,11 +59,11 @@ export declare class HttpExecutionContext<Appended = unknown> {
|
|
|
56
59
|
json(data: any, init?: ResponseInit): Response;
|
|
57
60
|
redirect(url: string | URL, status?: number): Response;
|
|
58
61
|
};
|
|
59
|
-
url: URL;
|
|
60
62
|
params: RuntimeRecord;
|
|
61
63
|
searchParams: RuntimeRecord;
|
|
62
64
|
body: RuntimeRecord;
|
|
63
65
|
constructor(req: Bun.BunRequest);
|
|
66
|
+
get url(): URL;
|
|
64
67
|
getArgs(endpointInfo: EndpointInfo): Promise<unknown[]>;
|
|
65
68
|
makeResponse(result: unknown, endpointInfo: EndpointInfo): Response;
|
|
66
69
|
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/** Whether request tracing is enabled. Cached after first read. */
|
|
2
|
+
export declare const isTraceEnabled: () => boolean;
|
|
3
|
+
/** Override the trace flag at runtime (tests / harness control). */
|
|
4
|
+
export declare const setTraceEnabled: (enabled: boolean) => void;
|
|
5
|
+
export interface SpanRecord {
|
|
6
|
+
name: string;
|
|
7
|
+
durationMs: number;
|
|
8
|
+
}
|
|
9
|
+
/** Per-request trace context. Threaded via {@link AsyncLocalStorage}. */
|
|
10
|
+
export declare class SignalTrace {
|
|
11
|
+
#private;
|
|
12
|
+
readonly traceId: string;
|
|
13
|
+
readonly endpointKey: string;
|
|
14
|
+
readonly endpointType: string;
|
|
15
|
+
readonly startedAt: number;
|
|
16
|
+
readonly spans: SpanRecord[];
|
|
17
|
+
dbQueryCount: number;
|
|
18
|
+
dbQueryMs: number;
|
|
19
|
+
cacheHits: number;
|
|
20
|
+
cacheMisses: number;
|
|
21
|
+
dataLoaderBatchCount: number;
|
|
22
|
+
dataLoaderKeyCount: number;
|
|
23
|
+
constructor(endpointKey: string, endpointType: string);
|
|
24
|
+
recordSpan(name: string, durationMs: number): void;
|
|
25
|
+
countDbQuery(durationMs: number): void;
|
|
26
|
+
countCache(hit: boolean): void;
|
|
27
|
+
countDataLoaderBatch(keyCount: number): void;
|
|
28
|
+
finalize(): void;
|
|
29
|
+
}
|
|
30
|
+
export declare const getCurrentTrace: () => SignalTrace | undefined;
|
|
31
|
+
/** Run `fn` with `trace` as the ambient request trace. */
|
|
32
|
+
export declare const runWithTrace: <T>(trace: SignalTrace, fn: () => T) => T;
|
|
33
|
+
/**
|
|
34
|
+
* Time an async stage under the current trace. When tracing is off (or no trace is
|
|
35
|
+
* active) this is a thin passthrough with no measurement overhead.
|
|
36
|
+
*/
|
|
37
|
+
export declare const traceSpan: <T>(name: string, fn: () => Promise<T>) => Promise<T>;
|
|
38
|
+
/** Record a DB query duration against the current trace (no-op when untraced). */
|
|
39
|
+
export declare const traceDbQuery: (durationMs: number) => void;
|
|
40
|
+
/** Record a cache hit/miss against the current trace (no-op when untraced). */
|
|
41
|
+
export declare const traceCache: (hit: boolean) => void;
|
|
42
|
+
/** Record a DataLoader batch against the current trace (no-op when untraced). */
|
|
43
|
+
export declare const traceDataLoaderBatch: (keyCount: number) => void;
|
|
44
|
+
/**
|
|
45
|
+
* Process-wide aggregator. Keeps rolling per-endpoint, per-span statistics with a
|
|
46
|
+
* bounded sample ring per span so percentiles stay representative of steady state
|
|
47
|
+
* without unbounded memory growth.
|
|
48
|
+
*/
|
|
49
|
+
declare class TraceAggregator {
|
|
50
|
+
#private;
|
|
51
|
+
ingest(trace: SignalTrace): void;
|
|
52
|
+
reset(): void;
|
|
53
|
+
/** Summarized snapshot suitable for JSON exposure on the metrics endpoint. */
|
|
54
|
+
snapshot(): {
|
|
55
|
+
enabled: boolean;
|
|
56
|
+
endpoints: {
|
|
57
|
+
endpoint: string;
|
|
58
|
+
requests: number;
|
|
59
|
+
avgDbQueriesPerRequest: number;
|
|
60
|
+
avgDbQueryMsPerRequest: number;
|
|
61
|
+
cacheHitRatio: number | null;
|
|
62
|
+
avgDataLoaderBatchSize: number | null;
|
|
63
|
+
spans: {
|
|
64
|
+
name: string;
|
|
65
|
+
count: number;
|
|
66
|
+
meanMs: number;
|
|
67
|
+
p50Ms: number;
|
|
68
|
+
p95Ms: number;
|
|
69
|
+
p99Ms: number;
|
|
70
|
+
maxMs: number;
|
|
71
|
+
}[];
|
|
72
|
+
}[];
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
export declare const traceAggregator: TraceAggregator;
|
|
76
|
+
/** Snapshot of all aggregated trace stats. Safe to call when tracing is disabled. */
|
|
77
|
+
export declare const getTraceSnapshot: () => {
|
|
78
|
+
enabled: boolean;
|
|
79
|
+
endpoints: {
|
|
80
|
+
endpoint: string;
|
|
81
|
+
requests: number;
|
|
82
|
+
avgDbQueriesPerRequest: number;
|
|
83
|
+
avgDbQueryMsPerRequest: number;
|
|
84
|
+
cacheHitRatio: number | null;
|
|
85
|
+
avgDataLoaderBatchSize: number | null;
|
|
86
|
+
spans: {
|
|
87
|
+
name: string;
|
|
88
|
+
count: number;
|
|
89
|
+
meanMs: number;
|
|
90
|
+
p50Ms: number;
|
|
91
|
+
p95Ms: number;
|
|
92
|
+
p99Ms: number;
|
|
93
|
+
maxMs: number;
|
|
94
|
+
}[];
|
|
95
|
+
}[];
|
|
96
|
+
};
|
|
97
|
+
export {};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export declare const signalUi: {
|
|
2
|
+
sectionTitle: string;
|
|
3
|
+
sectionDescription: string;
|
|
4
|
+
sectionPanel: string;
|
|
5
|
+
endpointCard: string;
|
|
6
|
+
endpointContent: string;
|
|
7
|
+
tablePanel: string;
|
|
8
|
+
inputRow: string;
|
|
9
|
+
inputLabel: string;
|
|
10
|
+
codePanel: string;
|
|
11
|
+
};
|
|
12
|
+
export declare const getEndpointBadgeClassName: (type: string) => "badge badge-primary" | "badge badge-secondary";
|
|
13
|
+
export declare const getGuardBadgeClassName: (guard: string) => "badge badge-primary" | "badge badge-secondary" | "badge";
|
|
14
|
+
export declare const getStatusBadgeClassName: (status: string) => "badge badge-outline" | "badge badge-primary" | "badge badge-error";
|
|
15
|
+
export declare const getStatusTextareaClassName: (status: string) => "" | "border-error text-error" | "border-primary" | "textarea-disabled";
|
package/ui/Signal/Arg.tsx
CHANGED
|
@@ -9,6 +9,7 @@ import { AiOutlineDelete } from "react-icons/ai";
|
|
|
9
9
|
import { DatePicker } from "../DatePicker";
|
|
10
10
|
import { Input } from "../Input";
|
|
11
11
|
import UiObject from "./Object";
|
|
12
|
+
import { signalUi } from "./style";
|
|
12
13
|
|
|
13
14
|
interface ArgProps {
|
|
14
15
|
argType: DefaultPrimitiveName;
|
|
@@ -55,7 +56,7 @@ const ArgTable = ({ refName, endpointKey, args }: ArgTableProps) => {
|
|
|
55
56
|
return (
|
|
56
57
|
<table className="table">
|
|
57
58
|
<thead>
|
|
58
|
-
<tr
|
|
59
|
+
<tr>
|
|
59
60
|
<th>Arg Key</th>
|
|
60
61
|
<th className="text-center">Type</th>
|
|
61
62
|
<th className="text-center">Enum</th>
|
|
@@ -69,7 +70,9 @@ const ArgTable = ({ refName, endpointKey, args }: ArgTableProps) => {
|
|
|
69
70
|
return (
|
|
70
71
|
<tbody className="font-normal" key={idx}>
|
|
71
72
|
<tr>
|
|
72
|
-
<td>
|
|
73
|
+
<td>
|
|
74
|
+
<div className="font-bold">{arg.name}</div>
|
|
75
|
+
</td>
|
|
73
76
|
<td className="text-center">
|
|
74
77
|
<UiObject.Type objRef={argRef as ConstantCls} arrDepth={arg.arrDepth ?? 0} />
|
|
75
78
|
</td>
|
|
@@ -84,7 +87,7 @@ const ArgTable = ({ refName, endpointKey, args }: ArgTableProps) => {
|
|
|
84
87
|
onClick={() => {
|
|
85
88
|
onCopy(opt.toString());
|
|
86
89
|
}}
|
|
87
|
-
className="tooltip tooltip-primary btn btn-
|
|
90
|
+
className="tooltip tooltip-primary btn btn-outline btn-xs"
|
|
88
91
|
>
|
|
89
92
|
{opt}
|
|
90
93
|
</button>
|
|
@@ -95,8 +98,12 @@ const ArgTable = ({ refName, endpointKey, args }: ArgTableProps) => {
|
|
|
95
98
|
"-"
|
|
96
99
|
)}
|
|
97
100
|
</td>
|
|
98
|
-
<td className="text-center">
|
|
99
|
-
|
|
101
|
+
<td className="text-center text-base-content/70">
|
|
102
|
+
{l._(`${refName}.signal.${endpointKey}.arg.${arg.name}`)}
|
|
103
|
+
</td>
|
|
104
|
+
<td className="text-center text-base-content/70">
|
|
105
|
+
{l._(`${refName}.signal.${endpointKey}.arg.${arg.name}.desc`)}
|
|
106
|
+
</td>
|
|
100
107
|
</tr>
|
|
101
108
|
</tbody>
|
|
102
109
|
);
|
|
@@ -118,8 +125,8 @@ const ArgParam = ({ endpointKey, arg, value, onChange }: ArgParamProps) => {
|
|
|
118
125
|
else if ((arg.arrDepth ?? 0) > 0) throw new Error(`Param arg - ${endpointKey}/${arg.name} must not be array`);
|
|
119
126
|
const argType = PrimitiveRegistry.getName(argRef as typeof PrimitiveScalar) as DefaultPrimitiveName;
|
|
120
127
|
return (
|
|
121
|
-
<div className=
|
|
122
|
-
<div className=
|
|
128
|
+
<div className={signalUi.inputRow}>
|
|
129
|
+
<div className={signalUi.inputLabel}>{arg.name}</div>
|
|
123
130
|
<div className="w-full">
|
|
124
131
|
<Arg argType={argType} value={value as string} onChange={onChange} />
|
|
125
132
|
</div>
|
|
@@ -141,8 +148,8 @@ const ArgQuery = ({ endpointKey, arg, value, onChange }: ArgQueryProps) => {
|
|
|
141
148
|
throw new Error(`Query arg - ${endpointKey}/${arg.name} must not be more than 2D array`);
|
|
142
149
|
const argType = PrimitiveRegistry.getName(argRef as typeof PrimitiveScalar) as DefaultPrimitiveName;
|
|
143
150
|
return (
|
|
144
|
-
<div className=
|
|
145
|
-
<div className=
|
|
151
|
+
<div className={signalUi.inputRow}>
|
|
152
|
+
<div className={signalUi.inputLabel}>{arg.name}</div>
|
|
146
153
|
<div className="w-full">
|
|
147
154
|
{(arg.arrDepth ?? 0) > 0 && Array.isArray(value) ? (
|
|
148
155
|
<div>
|
|
@@ -156,7 +163,7 @@ const ArgQuery = ({ endpointKey, arg, value, onChange }: ArgQueryProps) => {
|
|
|
156
163
|
}}
|
|
157
164
|
/>
|
|
158
165
|
<button
|
|
159
|
-
className="btn btn-sm btn-square"
|
|
166
|
+
className="btn btn-outline btn-sm btn-square"
|
|
160
167
|
onClick={() => {
|
|
161
168
|
onChange([...(value.slice(0, idx) as string[]), ...(value.slice(idx + 1) as string[])]);
|
|
162
169
|
}}
|
|
@@ -166,7 +173,7 @@ const ArgQuery = ({ endpointKey, arg, value, onChange }: ArgQueryProps) => {
|
|
|
166
173
|
</div>
|
|
167
174
|
))}
|
|
168
175
|
<button
|
|
169
|
-
className="btn btn-sm"
|
|
176
|
+
className="btn btn-outline btn-sm"
|
|
170
177
|
onClick={() => {
|
|
171
178
|
onChange([...(value as string[]), arg.example]);
|
|
172
179
|
}}
|
|
@@ -195,8 +202,8 @@ const ArgFormData = ({ endpointKey, arg, value, onChange }: ArgFormDataProps) =>
|
|
|
195
202
|
throw new Error(`FormData arg - ${endpointKey}/${arg.name} must be Upload`);
|
|
196
203
|
else if ((arg.arrDepth ?? 0) < 1) throw new Error(`FormData arg - ${endpointKey}/${arg.name} must be array`);
|
|
197
204
|
return (
|
|
198
|
-
<div className=
|
|
199
|
-
<div className=
|
|
205
|
+
<div className={signalUi.inputRow}>
|
|
206
|
+
<div className={signalUi.inputLabel}>{arg.name}</div>
|
|
200
207
|
<div className="w-full">
|
|
201
208
|
<Arg argType="Upload" value={value as FileList} onChange={onChange} />
|
|
202
209
|
</div>
|
|
@@ -320,7 +327,7 @@ const ArgJson = ({ value, onChange }: ArgJsonProps) => {
|
|
|
320
327
|
<Input.TextArea
|
|
321
328
|
validate={(e) => true}
|
|
322
329
|
className="w-full"
|
|
323
|
-
inputClassName="w-full min-h-[300px]"
|
|
330
|
+
inputClassName="w-full min-h-[300px] rounded-xl border border-base-300 bg-base-100"
|
|
324
331
|
value={value}
|
|
325
332
|
onPressEnter={(value) => {
|
|
326
333
|
onChange(value);
|
|
@@ -342,7 +349,7 @@ const ArgUpload = ({ value, onChange }: ArgUploadProps) => {
|
|
|
342
349
|
<input
|
|
343
350
|
type="file"
|
|
344
351
|
multiple
|
|
345
|
-
className="file-input w-full max-w-xs"
|
|
352
|
+
className="file-input file-input-bordered w-full max-w-xs"
|
|
346
353
|
onChange={(e: ChangeEvent<HTMLInputElement>) => {
|
|
347
354
|
onChange(new Array(e.target.files?.length).fill(0).map((_, idx) => e.target.files?.[idx]) as any as FileList);
|
|
348
355
|
}}
|
package/ui/Signal/Doc.tsx
CHANGED
|
@@ -10,6 +10,7 @@ import { Copy } from "../Copy";
|
|
|
10
10
|
import { Input } from "../Input";
|
|
11
11
|
import { Modal } from "../Modal";
|
|
12
12
|
import RestApi from "./RestApi";
|
|
13
|
+
import { signalUi } from "./style";
|
|
13
14
|
import WebSocket from "./WebSocket";
|
|
14
15
|
|
|
15
16
|
export default function Doc() {
|
|
@@ -26,7 +27,6 @@ const DocSetting = ({
|
|
|
26
27
|
roleTypes = ["Public", "User", "Admin", "SuperAdmin"],
|
|
27
28
|
roleKeys = { me: "Admin", self: "User" },
|
|
28
29
|
}: DocSettingProps) => {
|
|
29
|
-
const trySignalType = st.use.trySignalType();
|
|
30
30
|
const tryRoles = st.use.tryRoles();
|
|
31
31
|
const tryAccount = st.use.tryAccount();
|
|
32
32
|
useEffect(() => {
|
|
@@ -38,9 +38,9 @@ const DocSetting = ({
|
|
|
38
38
|
.filter(([key, roleType]) => !!tryAccount[key as keyof typeof tryAccount])
|
|
39
39
|
.map(([key, roleType]) => roleType);
|
|
40
40
|
return (
|
|
41
|
-
<div className="flex w-full flex-wrap items-center justify-between gap-
|
|
42
|
-
<div className="flex flex-1 items-center gap-
|
|
43
|
-
|
|
41
|
+
<div className="flex w-full flex-wrap items-center justify-between gap-3 rounded-xl bg-base-200 p-3">
|
|
42
|
+
<div className="flex flex-1 flex-wrap items-center gap-2">
|
|
43
|
+
<span className="font-semibold text-base-content/70 text-sm">BaseURL</span>
|
|
44
44
|
<Copy text={baseUrl}>
|
|
45
45
|
<button className="btn btn-outline btn-sm">
|
|
46
46
|
{baseUrl}
|
|
@@ -48,10 +48,10 @@ const DocSetting = ({
|
|
|
48
48
|
</button>
|
|
49
49
|
</Copy>
|
|
50
50
|
</div>
|
|
51
|
-
<div className="flex items-center gap-
|
|
52
|
-
Mode
|
|
51
|
+
<div className="flex items-center gap-2">
|
|
52
|
+
<span className="font-semibold text-base-content/70 text-sm">Mode</span>
|
|
53
53
|
<button
|
|
54
|
-
className="btn btn-
|
|
54
|
+
className="btn btn-primary btn-sm"
|
|
55
55
|
onClick={() => {
|
|
56
56
|
st.do.setTrySignalType("restapi");
|
|
57
57
|
}}
|
|
@@ -60,8 +60,8 @@ const DocSetting = ({
|
|
|
60
60
|
Rest API
|
|
61
61
|
</button>
|
|
62
62
|
</div>
|
|
63
|
-
<div className="flex items-center gap-
|
|
64
|
-
For
|
|
63
|
+
<div className="flex flex-wrap items-center gap-1">
|
|
64
|
+
<span className="font-semibold text-base-content/70 text-sm">For</span>
|
|
65
65
|
<button
|
|
66
66
|
className={`btn btn-secondary btn-sm ${tryRoleForAll ? "" : "btn-outline"}`}
|
|
67
67
|
onClick={() => {
|
|
@@ -84,10 +84,10 @@ const DocSetting = ({
|
|
|
84
84
|
</button>
|
|
85
85
|
))}
|
|
86
86
|
</div>
|
|
87
|
-
<div className="flex items-center gap-
|
|
88
|
-
Auth
|
|
87
|
+
<div className="flex items-center gap-2">
|
|
88
|
+
<span className="font-semibold text-base-content/70 text-sm">Auth</span>
|
|
89
89
|
<DocAuthModal>
|
|
90
|
-
<button className={`btn btn-sm ${currentRoles.length > 0 ? "btn-
|
|
90
|
+
<button className={`btn btn-sm ${currentRoles.length > 0 ? "btn-primary" : "btn-outline"} `}>
|
|
91
91
|
<BiLock /> {currentRoles.length > 0 ? currentRoles.join(", ") : "Public"}
|
|
92
92
|
</button>
|
|
93
93
|
</DocAuthModal>
|
|
@@ -140,11 +140,11 @@ const DocAuthModal = ({ children }: DocAuthModalProps) => {
|
|
|
140
140
|
}
|
|
141
141
|
>
|
|
142
142
|
<div className="w-full">
|
|
143
|
-
<div>Current JWT</div>
|
|
143
|
+
<div className={signalUi.sectionTitle}>Current JWT</div>
|
|
144
144
|
<Input inputClassName="w-full" value={jwt ?? ""} onChange={setJwt} validate={() => true} />
|
|
145
145
|
</div>
|
|
146
146
|
<div className="w-full">
|
|
147
|
-
<div className=
|
|
147
|
+
<div className={signalUi.sectionTitle}>Account Decoded</div>
|
|
148
148
|
<div className="relative">
|
|
149
149
|
<Input.TextArea
|
|
150
150
|
inputClassName="w-full"
|
|
@@ -177,10 +177,10 @@ const DocSignals = ({ fetch }: DocSignalsProps) => {
|
|
|
177
177
|
const signal = fetch.serializedSignal;
|
|
178
178
|
const signalEntries = Object.entries(signal).sort(([keyA], [keyB]) => (lowerlize(keyA) > lowerlize(keyB) ? 1 : -1));
|
|
179
179
|
return (
|
|
180
|
-
<div>
|
|
180
|
+
<div className="flex flex-col gap-3">
|
|
181
181
|
{signalEntries.map(([refName, signal], idx) => {
|
|
182
182
|
return (
|
|
183
|
-
<div className="
|
|
183
|
+
<div className="font-bold text-3xl" key={idx}>
|
|
184
184
|
<DocSignal refName={refName} fetch={fetch} />
|
|
185
185
|
</div>
|
|
186
186
|
);
|
|
@@ -199,8 +199,13 @@ const DocSignal = ({ refName, fetch }: DocSignalProps) => {
|
|
|
199
199
|
return (
|
|
200
200
|
<div className="collapse-arrow collapse bg-base-200">
|
|
201
201
|
<input type="checkbox" />
|
|
202
|
-
<div className="collapse-title
|
|
203
|
-
|
|
202
|
+
<div className="collapse-title">
|
|
203
|
+
<div className="flex flex-wrap items-center gap-2">
|
|
204
|
+
<div className="font-bold text-xl">{refName}</div>
|
|
205
|
+
<div className="badge badge-primary">Signal</div>
|
|
206
|
+
</div>
|
|
207
|
+
</div>
|
|
208
|
+
<div className="collapse-content flex flex-col gap-3">
|
|
204
209
|
<RestApi.Endpoints refName={refName} fetch={fetch} />
|
|
205
210
|
</div>
|
|
206
211
|
</div>
|
|
@@ -217,10 +222,12 @@ const Zone = ({ refName, fetch, openAll }: ZoneProps) => {
|
|
|
217
222
|
const { l } = usePage();
|
|
218
223
|
return (
|
|
219
224
|
<div className="flex break-after-page flex-col gap-4">
|
|
220
|
-
<div
|
|
221
|
-
|
|
222
|
-
|
|
225
|
+
<div>
|
|
226
|
+
<div className="font-bold text-3xl">{refName}</div>
|
|
227
|
+
<div className="text-base-content/70">{l._(`${refName}.modelDesc`)}</div>
|
|
228
|
+
</div>
|
|
223
229
|
<DocSetting />
|
|
230
|
+
<div className="font-bold text-2xl">APIs</div>
|
|
224
231
|
<RestApi.Endpoints refName={refName} fetch={fetch} openAll={openAll} />
|
|
225
232
|
<div className="font-bold text-2xl">Web Socket</div>
|
|
226
233
|
<WebSocket.Endpoints refName={refName} fetch={fetch} openAll={openAll} />
|
package/ui/Signal/Listener.tsx
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
import { clsx } from "akanjs/client";
|
|
4
3
|
import { capitalize } from "akanjs/common";
|
|
5
4
|
import { useEffect, useRef } from "react";
|
|
5
|
+
import { getStatusBadgeClassName, getStatusTextareaClassName, signalUi } from "./style";
|
|
6
6
|
|
|
7
7
|
export default function Listener() {
|
|
8
8
|
return <div></div>;
|
|
@@ -23,51 +23,27 @@ const ListenerResult = ({ status, data }: ListenerResultProps) => {
|
|
|
23
23
|
<div className="relative">
|
|
24
24
|
<textarea
|
|
25
25
|
ref={ref}
|
|
26
|
-
className={
|
|
27
|
-
status === "
|
|
28
|
-
|
|
29
|
-
: status === "error"
|
|
30
|
-
? "textarea-error border-error text-error"
|
|
31
|
-
: status === "listening"
|
|
32
|
-
? "textarea-success animate-borderPulse-50 border-3 border-info"
|
|
33
|
-
: ""
|
|
34
|
-
} min-h-[300px] w-full rounded-md bg-base-100 p-4 font-normal text-sm`}
|
|
26
|
+
className={`${signalUi.codePanel} duration-300 ${
|
|
27
|
+
status === "listening" ? "animate-borderPulse-50 border-2" : ""
|
|
28
|
+
} ${getStatusTextareaClassName(status)}`}
|
|
35
29
|
value={dataStr}
|
|
36
30
|
onChange={() => true}
|
|
37
31
|
/>
|
|
38
32
|
|
|
39
|
-
<div className="absolute top-4 right-4 flex items-center justify-center gap-
|
|
40
|
-
{capitalize(status)}
|
|
41
|
-
|
|
33
|
+
<div className="absolute top-4 right-4 flex items-center justify-center gap-2 rounded-lg bg-base-200/80 px-2 py-1 font-bold">
|
|
34
|
+
<span className={getStatusBadgeClassName(status)}>{capitalize(status)}</span>
|
|
42
35
|
<div
|
|
43
|
-
className={
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
36
|
+
className={`size-[10px] rounded-full ${
|
|
37
|
+
status === "error"
|
|
38
|
+
? "bg-error"
|
|
39
|
+
: status === "listening"
|
|
40
|
+
? "animate-pop-300 bg-primary"
|
|
41
|
+
: status === "loading"
|
|
42
|
+
? "animate-ping bg-secondary"
|
|
43
|
+
: "bg-base-300"
|
|
44
|
+
}`}
|
|
50
45
|
></div>
|
|
51
46
|
</div>
|
|
52
|
-
{/* {status === "loading" ? (
|
|
53
|
-
<div className="animate-fadeIn absolute inset-0 flex items-center justify-center backdrop-blur-sm">
|
|
54
|
-
<span className="loading loading-dots loading-lg"></span>
|
|
55
|
-
</div>
|
|
56
|
-
) : status === "idle" ? (
|
|
57
|
-
<></>
|
|
58
|
-
) : status === "listening" ? (
|
|
59
|
-
<div className="absolute right-4 top-4 w-3 h-3">
|
|
60
|
-
<div className="rounded-full w-full h-full animate-bounce bg-success"></div>
|
|
61
|
-
</div>
|
|
62
|
-
) : (
|
|
63
|
-
<div className="absolute right-4 top-4">
|
|
64
|
-
<Copy text={dataStr}>
|
|
65
|
-
<button className="btn btn-sm">
|
|
66
|
-
<AiOutlineCopy /> Copy
|
|
67
|
-
</button>
|
|
68
|
-
</Copy>
|
|
69
|
-
</div>
|
|
70
|
-
)} */}
|
|
71
47
|
</div>
|
|
72
48
|
);
|
|
73
49
|
};
|