akanjs 2.0.5 → 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.
Files changed (81) hide show
  1. package/README.ko.md +1 -1
  2. package/README.md +1 -1
  3. package/cli/application/application.command.ts +4 -1
  4. package/cli/application/application.runner.ts +6 -8
  5. package/cli/build.ts +3 -1
  6. package/cli/cloud/cloud.runner.ts +7 -8
  7. package/cli/index.js +288 -115
  8. package/cli/library/library.runner.ts +2 -2
  9. package/cli/module/module.runner.ts +2 -2
  10. package/cli/npmRegistry.ts +13 -0
  11. package/cli/openBrowser.ts +15 -0
  12. package/cli/pluralizeName.ts +5 -0
  13. package/cli/scalar/scalar.prompt.ts +2 -2
  14. package/cli/scalar/scalar.runner.ts +2 -2
  15. package/cli/semver.ts +18 -0
  16. package/cli/templates/lib/sig.ts +2 -2
  17. package/cli/workspace/workspace.runner.ts +3 -3
  18. package/client/cookie.ts +10 -15
  19. package/common/index.ts +1 -0
  20. package/common/jwtDecode.ts +17 -0
  21. package/constant/serialize.ts +1 -1
  22. package/devkit/akanApp/akanApp.host.ts +46 -9
  23. package/devkit/akanConfig/akanConfig.ts +2 -1
  24. package/devkit/capacitor.base.config.ts +18 -4
  25. package/devkit/capacitorApp.ts +118 -64
  26. package/devkit/incrementalBuilder/incrementalBuilder.host.ts +83 -9
  27. package/devkit/mobile/mobileTarget.ts +2 -1
  28. package/devkit/scanInfo.ts +1 -0
  29. package/document/dataLoader.ts +140 -6
  30. package/document/database.ts +1 -1
  31. package/package.json +7 -13
  32. package/server/akanApp.ts +250 -44
  33. package/server/di/diLifecycle.ts +1 -1
  34. package/server/processMetricsCollector.ts +79 -1
  35. package/server/proxy/localeWebProxy.ts +29 -12
  36. package/server/resolver/database.resolver.ts +82 -31
  37. package/server/resolver/signal.resolver.ts +67 -28
  38. package/service/ipcTypes.ts +5 -0
  39. package/service/predefinedAdaptor/database.adaptor.ts +95 -27
  40. package/service/predefinedAdaptor/solidSqlite.ts +7 -7
  41. package/service/predefinedAdaptor/storage.adaptor.ts +35 -9
  42. package/service/serviceModule.ts +1 -6
  43. package/signal/base.signal.ts +1 -1
  44. package/signal/index.ts +1 -0
  45. package/signal/middleware.ts +5 -1
  46. package/signal/signalContext.ts +85 -31
  47. package/signal/signalRegistry.ts +35 -10
  48. package/signal/trace.ts +279 -0
  49. package/types/cli/npmRegistry.d.ts +1 -0
  50. package/types/cli/openBrowser.d.ts +1 -0
  51. package/types/cli/pluralizeName.d.ts +1 -0
  52. package/types/cli/semver.d.ts +1 -0
  53. package/types/client/cookie.d.ts +6 -1
  54. package/types/common/index.d.ts +1 -0
  55. package/types/common/jwtDecode.d.ts +2 -0
  56. package/types/devkit/capacitorApp.d.ts +14 -5
  57. package/types/devkit/incrementalBuilder/incrementalBuilder.host.d.ts +9 -5
  58. package/types/document/dataLoader.d.ts +21 -2
  59. package/types/document/database.d.ts +1 -1
  60. package/types/server/processMetricsCollector.d.ts +2 -0
  61. package/types/service/ipcTypes.d.ts +5 -0
  62. package/types/service/predefinedAdaptor/database.adaptor.d.ts +26 -32
  63. package/types/service/predefinedAdaptor/solidSqlite.d.ts +3 -3
  64. package/types/service/predefinedAdaptor/storage.adaptor.d.ts +8 -2
  65. package/types/service/serviceModule.d.ts +1 -1
  66. package/types/signal/index.d.ts +1 -0
  67. package/types/signal/signalContext.d.ts +4 -1
  68. package/types/signal/signalRegistry.d.ts +25 -4
  69. package/types/signal/trace.d.ts +97 -0
  70. package/types/ui/Signal/style.d.ts +15 -0
  71. package/ui/Signal/Arg.tsx +22 -15
  72. package/ui/Signal/Doc.tsx +30 -24
  73. package/ui/Signal/Listener.tsx +15 -39
  74. package/ui/Signal/Message.tsx +32 -50
  75. package/ui/Signal/Object.tsx +16 -13
  76. package/ui/Signal/PubSub.tsx +29 -47
  77. package/ui/Signal/Response.tsx +7 -17
  78. package/ui/Signal/RestApi.tsx +41 -57
  79. package/ui/Signal/WebSocket.tsx +1 -1
  80. package/ui/Signal/style.ts +36 -0
  81. package/webkit/useCsrValues.ts +147 -37
@@ -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 {};
@@ -17,7 +17,7 @@ export declare class ServiceModel<Srv extends ServiceCls = ServiceCls, CnstModel
17
17
  });
18
18
  static fromModel<Srv extends ServiceCls, CnstModel extends ConstantModel, DbModel extends DatabaseModel>(srv: Srv, cnst: CnstModel, db: DbModel): ServiceModel<Srv, CnstModel, DbModel>;
19
19
  static from<Srv extends ServiceCls>(srv: Srv): ServiceModel<Srv, never, never, { [K in `${Uncapitalize<Srv["refName"]>}Service`]: UnCls<Srv>; }>;
20
- with<SrvModules extends ServiceModel[]>(...srvs: SrvModules): ServiceModel<Srv & MergeAllKeyOfObjects<SrvModules, "srv">, CnstModel, DbModel, SrvMap & MergeAllKeyOfObjects<SrvModules, "srvMap">>;
20
+ with<SrvModules extends ServiceModel[]>(...srvs: SrvModules): ServiceModel<Srv, CnstModel, DbModel, SrvMap & MergeAllKeyOfObjects<SrvModules, "srvMap">>;
21
21
  static getDefaultDbServiceMethods(className: string): {
22
22
  [x: string]: ((this: DatabaseService, query: QueryOf<any>, queryOption?: ListQueryOption) => Promise<any>) | ((this: DatabaseService, query: QueryOf<any>, queryOption?: FindQueryOption) => Promise<any>) | ((this: DatabaseService, type: SaveEventType, listener: (doc: Doc, type: CRUDEventType) => PromiseOrObject<void>) => any) | ((this: DatabaseService, id: string, data: DataInputOf) => Promise<any>);
23
23
  __get(this: DatabaseService, id: string): Promise<any>;
@@ -15,4 +15,5 @@ export * from "./signalContext.d.ts";
15
15
  export * from "./signalRegistry.d.ts";
16
16
  export * from "./slice.d.ts";
17
17
  export * from "./sliceInfo.d.ts";
18
+ export * from "./trace.d.ts";
18
19
  export * from "./types.d.ts";
@@ -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
  }
@@ -3,6 +3,14 @@ import type { InternalCls } from "./internal.d.ts";
3
3
  import type { ServerSignalCls } from "./serverSignal.d.ts";
4
4
  import type { SliceCls } from "./slice.d.ts";
5
5
  import type { SerializedSignal } from "./types.d.ts";
6
+ type SignalBaseRef<SigCls> = SigCls extends {
7
+ srv: {
8
+ srv: {
9
+ refName: infer RefName;
10
+ };
11
+ };
12
+ } ? RefName : never;
13
+ type SignalWithBase<RefName extends string, SigCls> = SignalBaseRef<SigCls> extends RefName ? SigCls : never;
6
14
  export declare class DatabaseSignal<IntlCls extends InternalCls = InternalCls, EndpCls extends EndpointCls = EndpointCls, SlceCls extends SliceCls = SliceCls, SrvrCls extends ServerSignalCls = ServerSignalCls> {
7
15
  internal: IntlCls;
8
16
  endpoint: EndpCls;
@@ -21,8 +29,21 @@ export declare class ServiceSignal<IntlCls extends InternalCls = InternalCls, En
21
29
  /** Registry for database and service signals used by routing and fetch serialization. */
22
30
  export declare class SignalRegistry {
23
31
  #private;
24
- static registerDatabase<IntlCls extends InternalCls, EndpCls extends EndpointCls, SlceCls extends SliceCls, SrvrCls extends ServerSignalCls>(internal: IntlCls, endpoint: EndpCls, slice: SlceCls, server: SrvrCls): DatabaseSignal<IntlCls, EndpCls, SlceCls, SrvrCls>;
25
- static getDatabase(refName: string): DatabaseSignal<any, any, any, any> | undefined;
26
- static registerService<IntlCls extends InternalCls, EndpCls extends EndpointCls, SrvrCls extends ServerSignalCls>(internal: IntlCls, endpoint: EndpCls, server: SrvrCls): ServiceSignal<IntlCls, EndpCls, SrvrCls>;
27
- static getService(refName: string): ServiceSignal<any, any, any> | undefined;
32
+ static registerDatabase<RefName extends string, IntlCls extends InternalCls, EndpCls extends EndpointCls, SlceCls extends SliceCls, SrvrCls extends ServerSignalCls>(refName: RefName, internal: SignalWithBase<RefName, IntlCls>, endpoint: SignalWithBase<RefName, EndpCls>, slice: SignalWithBase<RefName, SlceCls>, server: SrvrCls): DatabaseSignal<IntlCls, EndpCls, SlceCls, SrvrCls>;
33
+ static getDatabase(refName: string): DatabaseSignal<InternalCls, EndpointCls<import("../service.d.ts").ServiceModel<import("../service.d.ts").ServiceCls, any, any, {
34
+ [x: `${Uncapitalize<string>}Service`]: import("../service.d.ts").ExtractInjectInfoObject<{}> & import("../service.d.ts").Service;
35
+ }>, {
36
+ [key: string]: import("./endpointInfo.d.ts").EndpointInfo<import("./endpointInfo.d.ts").EndpointType, {
37
+ [key: string]: any;
38
+ }, any, any, any, any, import("../constant.d.ts").ConstantFieldTypeInput, never, never, boolean>;
39
+ }>, SliceCls, ServerSignalCls> | undefined;
40
+ static registerService<RefName extends string, IntlCls extends InternalCls, EndpCls extends EndpointCls, SrvrCls extends ServerSignalCls>(refName: RefName, internal: SignalWithBase<RefName, IntlCls>, endpoint: SignalWithBase<RefName, EndpCls>, server: SrvrCls): ServiceSignal<IntlCls, EndpCls, SrvrCls>;
41
+ static getService(refName: string): ServiceSignal<InternalCls, EndpointCls<import("../service.d.ts").ServiceModel<import("../service.d.ts").ServiceCls, any, any, {
42
+ [x: `${Uncapitalize<string>}Service`]: import("../service.d.ts").ExtractInjectInfoObject<{}> & import("../service.d.ts").Service;
43
+ }>, {
44
+ [key: string]: import("./endpointInfo.d.ts").EndpointInfo<import("./endpointInfo.d.ts").EndpointType, {
45
+ [key: string]: any;
46
+ }, any, any, any, any, import("../constant.d.ts").ConstantFieldTypeInput, never, never, boolean>;
47
+ }>, ServerSignalCls> | undefined;
28
48
  }
49
+ export {};
@@ -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 className="text-bold">
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>{arg.name}</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-secondary btn-xs"
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">{l._(`${refName}.signal.${endpointKey}.arg.${arg.name}`)}</td>
99
- <td className="text-center">{l._(`${refName}.signal.${endpointKey}.arg.${arg.name}.desc`)}</td>
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="flex w-full items-center gap-2">
122
- <div className="w-36 pl-2">- {arg.name}</div>
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="flex items-center gap-2">
145
- <div className="w-36 pl-2">- {arg.name}</div>
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="flex w-full items-center gap-2">
199
- <div className="w-36 pl-2">- {arg.name}</div>
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
@@ -1,9 +1,8 @@
1
1
  "use client";
2
2
  import { fetch, usePage } from "akanjs/client";
3
- import { lowerlize } from "akanjs/common";
3
+ import { decodeJwtPayload, lowerlize } from "akanjs/common";
4
4
  import { type Account, type FetchProxy, getDefaultAccount } from "akanjs/fetch";
5
5
  import { st } from "akanjs/store";
6
- import { jwtDecode } from "jwt-decode";
7
6
  import { type ReactNode, useEffect, useState } from "react";
8
7
  import { AiOutlineApi, AiOutlineCopy } from "react-icons/ai";
9
8
  import { BiLock } from "react-icons/bi";
@@ -11,6 +10,7 @@ import { Copy } from "../Copy";
11
10
  import { Input } from "../Input";
12
11
  import { Modal } from "../Modal";
13
12
  import RestApi from "./RestApi";
13
+ import { signalUi } from "./style";
14
14
  import WebSocket from "./WebSocket";
15
15
 
16
16
  export default function Doc() {
@@ -27,7 +27,6 @@ const DocSetting = ({
27
27
  roleTypes = ["Public", "User", "Admin", "SuperAdmin"],
28
28
  roleKeys = { me: "Admin", self: "User" },
29
29
  }: DocSettingProps) => {
30
- const trySignalType = st.use.trySignalType();
31
30
  const tryRoles = st.use.tryRoles();
32
31
  const tryAccount = st.use.tryAccount();
33
32
  useEffect(() => {
@@ -39,9 +38,9 @@ const DocSetting = ({
39
38
  .filter(([key, roleType]) => !!tryAccount[key as keyof typeof tryAccount])
40
39
  .map(([key, roleType]) => roleType);
41
40
  return (
42
- <div className="flex w-full flex-wrap items-center justify-between gap-4">
43
- <div className="flex flex-1 items-center gap-1">
44
- BaseURL:{" "}
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>
45
44
  <Copy text={baseUrl}>
46
45
  <button className="btn btn-outline btn-sm">
47
46
  {baseUrl}
@@ -49,10 +48,10 @@ const DocSetting = ({
49
48
  </button>
50
49
  </Copy>
51
50
  </div>
52
- <div className="flex items-center gap-1">
53
- Mode:
51
+ <div className="flex items-center gap-2">
52
+ <span className="font-semibold text-base-content/70 text-sm">Mode</span>
54
53
  <button
55
- className="btn btn-sm btn-outline"
54
+ className="btn btn-primary btn-sm"
56
55
  onClick={() => {
57
56
  st.do.setTrySignalType("restapi");
58
57
  }}
@@ -61,8 +60,8 @@ const DocSetting = ({
61
60
  Rest API
62
61
  </button>
63
62
  </div>
64
- <div className="flex items-center gap-0.5">
65
- For:
63
+ <div className="flex flex-wrap items-center gap-1">
64
+ <span className="font-semibold text-base-content/70 text-sm">For</span>
66
65
  <button
67
66
  className={`btn btn-secondary btn-sm ${tryRoleForAll ? "" : "btn-outline"}`}
68
67
  onClick={() => {
@@ -85,10 +84,10 @@ const DocSetting = ({
85
84
  </button>
86
85
  ))}
87
86
  </div>
88
- <div className="flex items-center gap-1">
89
- Auth:
87
+ <div className="flex items-center gap-2">
88
+ <span className="font-semibold text-base-content/70 text-sm">Auth</span>
90
89
  <DocAuthModal>
91
- <button className={`btn btn-sm ${currentRoles.length > 0 ? "btn-warning" : "btn-neutral"} `}>
90
+ <button className={`btn btn-sm ${currentRoles.length > 0 ? "btn-primary" : "btn-outline"} `}>
92
91
  <BiLock /> {currentRoles.length > 0 ? currentRoles.join(", ") : "Public"}
93
92
  </button>
94
93
  </DocAuthModal>
@@ -105,7 +104,7 @@ const DocAuthModal = ({ children }: DocAuthModalProps) => {
105
104
  const tryJwt = st.use.tryJwt();
106
105
  const [jwt, setJwt] = useState(tryJwt);
107
106
  const [modalOpen, setModalOpen] = useState(false);
108
- const decodedAccount = jwt ? (jwtDecode as (jwt: string) => Account)(jwt) : null;
107
+ const decodedAccount = jwt ? decodeJwtPayload<Account>(jwt) : null;
109
108
  const accountStr = JSON.stringify(decodedAccount ?? getDefaultAccount(), null, 2);
110
109
  return (
111
110
  <>
@@ -141,11 +140,11 @@ const DocAuthModal = ({ children }: DocAuthModalProps) => {
141
140
  }
142
141
  >
143
142
  <div className="w-full">
144
- <div>Current JWT</div>
143
+ <div className={signalUi.sectionTitle}>Current JWT</div>
145
144
  <Input inputClassName="w-full" value={jwt ?? ""} onChange={setJwt} validate={() => true} />
146
145
  </div>
147
146
  <div className="w-full">
148
- <div className="flex items-center gap-2">Account Decoded</div>
147
+ <div className={signalUi.sectionTitle}>Account Decoded</div>
149
148
  <div className="relative">
150
149
  <Input.TextArea
151
150
  inputClassName="w-full"
@@ -178,10 +177,10 @@ const DocSignals = ({ fetch }: DocSignalsProps) => {
178
177
  const signal = fetch.serializedSignal;
179
178
  const signalEntries = Object.entries(signal).sort(([keyA], [keyB]) => (lowerlize(keyA) > lowerlize(keyB) ? 1 : -1));
180
179
  return (
181
- <div>
180
+ <div className="flex flex-col gap-3">
182
181
  {signalEntries.map(([refName, signal], idx) => {
183
182
  return (
184
- <div className="px-5 pb-5 font-bold text-3xl" key={idx}>
183
+ <div className="font-bold text-3xl" key={idx}>
185
184
  <DocSignal refName={refName} fetch={fetch} />
186
185
  </div>
187
186
  );
@@ -200,8 +199,13 @@ const DocSignal = ({ refName, fetch }: DocSignalProps) => {
200
199
  return (
201
200
  <div className="collapse-arrow collapse bg-base-200">
202
201
  <input type="checkbox" />
203
- <div className="collapse-title font-medium text-xl">{refName}</div>
204
- <div className="collapse-content">
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">
205
209
  <RestApi.Endpoints refName={refName} fetch={fetch} />
206
210
  </div>
207
211
  </div>
@@ -218,10 +222,12 @@ const Zone = ({ refName, fetch, openAll }: ZoneProps) => {
218
222
  const { l } = usePage();
219
223
  return (
220
224
  <div className="flex break-after-page flex-col gap-4">
221
- <div className="font-bold text-3xl">{refName}</div>
222
- <div className="mb-5"> - {l._(`${refName}.modelDesc`)}</div>
223
- <div className="font-bold text-2xl">APIs</div>
225
+ <div>
226
+ <div className="font-bold text-3xl">{refName}</div>
227
+ <div className="text-base-content/70">{l._(`${refName}.modelDesc`)}</div>
228
+ </div>
224
229
  <DocSetting />
230
+ <div className="font-bold text-2xl">APIs</div>
225
231
  <RestApi.Endpoints refName={refName} fetch={fetch} openAll={openAll} />
226
232
  <div className="font-bold text-2xl">Web Socket</div>
227
233
  <WebSocket.Endpoints refName={refName} fetch={fetch} openAll={openAll} />
@@ -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={`textarea duration-300 ${
27
- status === "loading"
28
- ? "textarea-disabled"
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-3 rounded-lg bg-base-200/50 px-2 py-1 font-bold">
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={clsx("size-[14px] rounded-full", {
44
- "animate-bounce bg-base-300": status === "ready",
45
- "animate-pop-300 bg-success": status === "listening",
46
-
47
- "animate-none bg-error": status === "error",
48
- "animate-ping bg-warning": status === "loading",
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
  };