@fuzdev/fuz_app 0.8.0 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,10 +3,12 @@
3
3
  *
4
4
  * Provides error types, named constructors, and HTTP status mapping
5
5
  * for the throw/catch error pattern used by `apply_route_specs`.
6
- * Extracted from zzz's `jsonrpc_errors.ts` only core error codes
7
- * (5 standard + 8 general application). Domain-specific codes stay
8
- * in consumers. `JSONRPC_ERROR_CODES` is extensible — consumers
9
- * add their own codes by casting `as JsonrpcErrorCode`.
6
+ * Core error codes (5 standard + 8 general application). Domain-specific
7
+ * codes stay in consumers add by casting `as JsonrpcErrorCode`.
8
+ *
9
+ * `JsonrpcErrorCode` and `JsonrpcErrorObject` types are Zod-inferred
10
+ * from `jsonrpc.ts` — this module re-uses those as the single source
11
+ * of truth.
10
12
  *
11
13
  * Complementary to `error_schemas.ts`: that module is declarative
12
14
  * (Zod schemas for surface introspection), this one is runtime
@@ -14,6 +16,7 @@
14
16
  *
15
17
  * @module
16
18
  */
19
+ import { JSONRPC_PARSE_ERROR, JSONRPC_INVALID_REQUEST, JSONRPC_METHOD_NOT_FOUND, JSONRPC_INVALID_PARAMS, JSONRPC_INTERNAL_ERROR, } from './jsonrpc.js';
17
20
  /**
18
21
  * Standard JSON-RPC error codes (5) plus general application codes (8).
19
22
  *
@@ -22,17 +25,12 @@
22
25
  * -32099 range reserved by the JSON-RPC spec.
23
26
  */
24
27
  export const JSONRPC_ERROR_CODES = {
25
- // Standard JSON-RPC errors — https://www.jsonrpc.org/specification
26
- /** -32700 */
27
- parse_error: -32700,
28
- /** -32600 */
29
- invalid_request: -32600,
30
- /** -32601 */
31
- method_not_found: -32601,
32
- /** -32602 */
33
- invalid_params: -32602,
34
- /** -32603 */
35
- internal_error: -32603,
28
+ // Standard JSON-RPC errors — values from jsonrpc.ts
29
+ parse_error: JSONRPC_PARSE_ERROR,
30
+ invalid_request: JSONRPC_INVALID_REQUEST,
31
+ method_not_found: JSONRPC_METHOD_NOT_FOUND,
32
+ invalid_params: JSONRPC_INVALID_PARAMS,
33
+ internal_error: JSONRPC_INTERNAL_ERROR,
36
34
  // General application errors (-32000 to -32099)
37
35
  /**
38
36
  * Same as HTTP 401 "unauthorized", but correctly named.
@@ -57,9 +55,9 @@ export const JSONRPC_ERROR_CODES = {
57
55
  timeout: -32008,
58
56
  };
59
57
  /**
60
- * Named constructors for `JsonrpcErrorJson` objects.
58
+ * Named constructors for `JsonrpcErrorObject` values.
61
59
  *
62
- * Each function creates a JSON-RPC error response object with the correct
60
+ * Each function creates a JSON-RPC error object with the correct
63
61
  * code and a sensible default message. Used by the catch layer in
64
62
  * `apply_route_specs` to build response bodies.
65
63
  */
@@ -170,21 +168,38 @@ export const jsonrpc_errors = {
170
168
  timeout: create_error_thrower(jsonrpc_error_messages.timeout),
171
169
  };
172
170
  // --- HTTP status mapping ---
173
- const JSONRPC_ERROR_CODE_HTTP_STATUS = new Map([
174
- [-32700, 400], // parse_error
175
- [-32600, 400], // invalid_request
176
- [-32601, 404], // method_not_found
177
- [-32602, 400], // invalid_params
178
- [-32603, 500], // internal_error
179
- [-32001, 401], // unauthenticated
180
- [-32002, 403], // forbidden
181
- [-32003, 404], // not_found
182
- [-32004, 409], // conflict
183
- [-32005, 422], // validation_error
184
- [-32006, 429], // rate_limited
185
- [-32007, 503], // service_unavailable
186
- [-32008, 504], // timeout
187
- ]);
171
+ /**
172
+ * Maps JSON-RPC error codes to HTTP status codes.
173
+ *
174
+ * Extensible — consumers with domain-specific error codes can spread
175
+ * this into their own mapping object.
176
+ */
177
+ export const JSONRPC_ERROR_CODE_TO_HTTP_STATUS = {
178
+ [-32700]: 400, // parse_error
179
+ [-32600]: 400, // invalid_request
180
+ [-32601]: 404, // method_not_found
181
+ [-32602]: 400, // invalid_params
182
+ [-32603]: 500, // internal_error
183
+ [-32001]: 401, // unauthenticated
184
+ [-32002]: 403, // forbidden
185
+ [-32003]: 404, // not_found
186
+ [-32004]: 409, // conflict
187
+ [-32005]: 422, // validation_error
188
+ [-32006]: 429, // rate_limited
189
+ [-32007]: 503, // service_unavailable
190
+ [-32008]: 504, // timeout
191
+ };
192
+ /**
193
+ * Maps HTTP status codes to JSON-RPC error codes (reverse mapping).
194
+ *
195
+ * When multiple error codes map to the same HTTP status (e.g. parse_error
196
+ * and invalid_request both map to 400), the last one wins. Use for
197
+ * best-effort HTTP → JSON-RPC translation.
198
+ */
199
+ export const HTTP_STATUS_TO_JSONRPC_ERROR_CODE = Object.fromEntries(Object.entries(JSONRPC_ERROR_CODE_TO_HTTP_STATUS).map(([code, status]) => [
200
+ status,
201
+ Number(code),
202
+ ]));
188
203
  /**
189
204
  * Map a JSON-RPC error code to an HTTP status code.
190
205
  *
@@ -194,4 +209,13 @@ const JSONRPC_ERROR_CODE_HTTP_STATUS = new Map([
194
209
  * @param code - the JSON-RPC error code
195
210
  * @returns the corresponding HTTP status code
196
211
  */
197
- export const jsonrpc_error_code_to_http_status = (code) => JSONRPC_ERROR_CODE_HTTP_STATUS.get(code) ?? 500;
212
+ export const jsonrpc_error_code_to_http_status = (code) => JSONRPC_ERROR_CODE_TO_HTTP_STATUS[code] ?? 500;
213
+ /**
214
+ * Map an HTTP status code to a JSON-RPC error code.
215
+ *
216
+ * Returns `internal_error` (-32603) for unrecognized status codes.
217
+ *
218
+ * @param status - the HTTP status code
219
+ * @returns the corresponding JSON-RPC error code
220
+ */
221
+ export const http_status_to_jsonrpc_error_code = (status) => HTTP_STATUS_TO_JSONRPC_ERROR_CODE[status] ?? JSONRPC_ERROR_CODES.internal_error;
@@ -0,0 +1,56 @@
1
+ /**
2
+ * JSON-RPC message builders, type guards, and converters.
3
+ *
4
+ * Used by the SAES runtime (ActionEvent, ActionPeer, transports) and
5
+ * the RPC endpoint dispatcher. Complements `jsonrpc.ts` (schemas) and
6
+ * `jsonrpc_errors.ts` (error infrastructure).
7
+ *
8
+ * @module
9
+ */
10
+ import { type JsonrpcErrorResponse, type JsonrpcMethod, type JsonrpcNotification, type JsonrpcNotificationParams, type JsonrpcRequest, type JsonrpcRequestId, type JsonrpcRequestParams, type JsonrpcResponse, type JsonrpcResult, type JsonrpcMessage, JSONRPC_VERSION } from './jsonrpc.js';
11
+ /** Creates a JSON-RPC request message. */
12
+ export declare const create_jsonrpc_request: (method: JsonrpcMethod, params: JsonrpcRequestParams | undefined, id: JsonrpcRequestId) => JsonrpcRequest;
13
+ /** Creates a JSON-RPC success response message. */
14
+ export declare const create_jsonrpc_response: (id: JsonrpcRequestId, result: JsonrpcResult) => JsonrpcResponse;
15
+ /** Creates a JSON-RPC notification message (no id, no response expected). */
16
+ export declare const create_jsonrpc_notification: (method: JsonrpcMethod, params: JsonrpcNotificationParams | undefined) => JsonrpcNotification;
17
+ /** Creates a JSON-RPC error response message. */
18
+ export declare const create_jsonrpc_error_response: (id: JsonrpcErrorResponse["id"], error: JsonrpcErrorResponse["error"]) => JsonrpcErrorResponse;
19
+ /**
20
+ * Creates a JSON-RPC error response from any error.
21
+ * Handles `ThrownJsonrpcError` (preserves code/message/data) and
22
+ * regular `Error` objects (maps to internal_error, includes stack in DEV).
23
+ */
24
+ export declare const create_jsonrpc_error_response_from_thrown: (id: JsonrpcRequestId | null, error: unknown) => JsonrpcErrorResponse;
25
+ /** Checks if a value is a valid JSON-RPC request id (string or finite number). */
26
+ export declare const is_jsonrpc_request_id: (id: unknown) => id is JsonrpcRequestId;
27
+ /** Checks if a value is a JSON-RPC object (has `jsonrpc: '2.0'`). */
28
+ export declare const is_jsonrpc_object: (message: unknown) => message is {
29
+ jsonrpc: typeof JSONRPC_VERSION;
30
+ };
31
+ /** Checks if a value is any valid JSON-RPC message or batch array. */
32
+ export declare const is_jsonrpc_message: (message: unknown) => message is JsonrpcMessage | Array<JsonrpcMessage>;
33
+ /** Checks if a value is a JSON-RPC request (has method + id). */
34
+ export declare const is_jsonrpc_request: (message: unknown) => message is JsonrpcRequest;
35
+ /** Checks if a value is a JSON-RPC notification (has method, no id). */
36
+ export declare const is_jsonrpc_notification: (message: unknown) => message is JsonrpcNotification;
37
+ /** Checks if a value is a JSON-RPC success response (has result + id). */
38
+ export declare const is_jsonrpc_response: (message: unknown) => message is JsonrpcResponse;
39
+ /** Checks if a value is a JSON-RPC error response (has error + id). */
40
+ export declare const is_jsonrpc_error_response: (message: unknown) => message is JsonrpcErrorResponse;
41
+ /**
42
+ * Extracts a JSON-RPC request id from a message or raw value.
43
+ * Returns `null` if no valid id can be extracted.
44
+ */
45
+ export declare const to_jsonrpc_message_id: (message_or_id: unknown) => JsonrpcRequestId | null;
46
+ /**
47
+ * Normalizes input to JSON-RPC params format.
48
+ * Returns `undefined` for null/undefined, wraps primitives in `{value}`.
49
+ */
50
+ export declare const to_jsonrpc_params: (input: unknown) => Record<string, any> | undefined;
51
+ /**
52
+ * Normalizes output to JSON-RPC result format.
53
+ * Returns empty object for null/undefined, wraps primitives in `{value}`.
54
+ */
55
+ export declare const to_jsonrpc_result: (output: unknown) => Record<string, any>;
56
+ //# sourceMappingURL=jsonrpc_helpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jsonrpc_helpers.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/http/jsonrpc_helpers.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,OAAO,EACN,KAAK,oBAAoB,EACzB,KAAK,aAAa,EAClB,KAAK,mBAAmB,EACxB,KAAK,yBAAyB,EAC9B,KAAK,cAAc,EACnB,KAAK,gBAAgB,EACrB,KAAK,oBAAoB,EACzB,KAAK,eAAe,EACpB,KAAK,aAAa,EAClB,KAAK,cAAc,EAEnB,eAAe,EACf,MAAM,cAAc,CAAC;AAKtB,0CAA0C;AAC1C,eAAO,MAAM,sBAAsB,GAClC,QAAQ,aAAa,EACrB,QAAQ,oBAAoB,GAAG,SAAS,EACxC,IAAI,gBAAgB,KAClB,cAUF,CAAC;AAEF,mDAAmD;AACnD,eAAO,MAAM,uBAAuB,GACnC,IAAI,gBAAgB,EACpB,QAAQ,aAAa,KACnB,eAID,CAAC;AAEH,6EAA6E;AAC7E,eAAO,MAAM,2BAA2B,GACvC,QAAQ,aAAa,EACrB,QAAQ,yBAAyB,GAAG,SAAS,KAC3C,mBASF,CAAC;AAEF,iDAAiD;AACjD,eAAO,MAAM,6BAA6B,GACzC,IAAI,oBAAoB,CAAC,IAAI,CAAC,EAC9B,OAAO,oBAAoB,CAAC,OAAO,CAAC,KAClC,oBAID,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,yCAAyC,GACrD,IAAI,gBAAgB,GAAG,IAAI,EAC3B,OAAO,OAAO,KACZ,oBAyBF,CAAC;AAIF,kFAAkF;AAClF,eAAO,MAAM,qBAAqB,GAAI,IAAI,OAAO,KAAG,EAAE,IAAI,gBAGzD,CAAC;AAEF,qEAAqE;AACrE,eAAO,MAAM,iBAAiB,GAAI,SAAS,OAAO,KAAG,OAAO,IAAI;IAAC,OAAO,EAAE,OAAO,eAAe,CAAA;CAInD,CAAC;AAE9C,sEAAsE;AACtE,eAAO,MAAM,kBAAkB,GAC9B,SAAS,OAAO,KACd,OAAO,IAAI,cAAc,GAAG,KAAK,CAAC,cAAc,CAGrB,CAAC;AAE/B,iEAAiE;AACjE,eAAO,MAAM,kBAAkB,GAAI,SAAS,OAAO,KAAG,OAAO,IAAI,cACI,CAAC;AAEtE,wEAAwE;AACxE,eAAO,MAAM,uBAAuB,GAAI,SAAS,OAAO,KAAG,OAAO,IAAI,mBACE,CAAC;AAEzE,0EAA0E;AAC1E,eAAO,MAAM,mBAAmB,GAAI,SAAS,OAAO,KAAG,OAAO,IAAI,eACG,CAAC;AAEtE,uEAAuE;AACvE,eAAO,MAAM,yBAAyB,GAAI,SAAS,OAAO,KAAG,OAAO,IAAI,oBACJ,CAAC;AAIrE;;;GAGG;AACH,eAAO,MAAM,qBAAqB,GAAI,eAAe,OAAO,KAAG,gBAAgB,GAAG,IAOjF,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,iBAAiB,GAAI,OAAO,OAAO,KAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAQxE,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,iBAAiB,GAAI,QAAQ,OAAO,KAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAQrE,CAAC"}
@@ -0,0 +1,138 @@
1
+ /**
2
+ * JSON-RPC message builders, type guards, and converters.
3
+ *
4
+ * Used by the SAES runtime (ActionEvent, ActionPeer, transports) and
5
+ * the RPC endpoint dispatcher. Complements `jsonrpc.ts` (schemas) and
6
+ * `jsonrpc_errors.ts` (error infrastructure).
7
+ *
8
+ * @module
9
+ */
10
+ import { DEV } from 'esm-env';
11
+ import { JSONRPC_VERSION, } from './jsonrpc.js';
12
+ import { ThrownJsonrpcError, JSONRPC_ERROR_CODES } from './jsonrpc_errors.js';
13
+ // --- Message builders ---
14
+ /** Creates a JSON-RPC request message. */
15
+ export const create_jsonrpc_request = (method, params, id) => {
16
+ const message = {
17
+ jsonrpc: JSONRPC_VERSION,
18
+ id,
19
+ method,
20
+ };
21
+ if (params !== undefined) {
22
+ message.params = params;
23
+ }
24
+ return message;
25
+ };
26
+ /** Creates a JSON-RPC success response message. */
27
+ export const create_jsonrpc_response = (id, result) => ({
28
+ jsonrpc: JSONRPC_VERSION,
29
+ id,
30
+ result,
31
+ });
32
+ /** Creates a JSON-RPC notification message (no id, no response expected). */
33
+ export const create_jsonrpc_notification = (method, params) => {
34
+ const message = {
35
+ jsonrpc: JSONRPC_VERSION,
36
+ method,
37
+ };
38
+ if (params !== undefined) {
39
+ message.params = params;
40
+ }
41
+ return message;
42
+ };
43
+ /** Creates a JSON-RPC error response message. */
44
+ export const create_jsonrpc_error_response = (id, error) => ({
45
+ jsonrpc: JSONRPC_VERSION,
46
+ id,
47
+ error,
48
+ });
49
+ /**
50
+ * Creates a JSON-RPC error response from any error.
51
+ * Handles `ThrownJsonrpcError` (preserves code/message/data) and
52
+ * regular `Error` objects (maps to internal_error, includes stack in DEV).
53
+ */
54
+ export const create_jsonrpc_error_response_from_thrown = (id, error) => {
55
+ let code = JSONRPC_ERROR_CODES.internal_error;
56
+ let message = 'internal server error';
57
+ let data = undefined;
58
+ if (error instanceof ThrownJsonrpcError) {
59
+ code = error.code;
60
+ message = error.message;
61
+ data = error.data;
62
+ }
63
+ else if (error instanceof Error) {
64
+ if (DEV) {
65
+ message = error.message;
66
+ data = { stack: error.stack };
67
+ }
68
+ }
69
+ return {
70
+ jsonrpc: JSONRPC_VERSION,
71
+ id,
72
+ error: {
73
+ code,
74
+ message,
75
+ data,
76
+ },
77
+ };
78
+ };
79
+ // --- Type guards ---
80
+ /** Checks if a value is a valid JSON-RPC request id (string or finite number). */
81
+ export const is_jsonrpc_request_id = (id) => {
82
+ const type = typeof id;
83
+ return type === 'string' || (type === 'number' && !Number.isNaN(id) && Number.isFinite(id));
84
+ };
85
+ /** Checks if a value is a JSON-RPC object (has `jsonrpc: '2.0'`). */
86
+ export const is_jsonrpc_object = (message) => typeof message === 'object' &&
87
+ message !== null &&
88
+ !Array.isArray(message) &&
89
+ message.jsonrpc === JSONRPC_VERSION;
90
+ /** Checks if a value is any valid JSON-RPC message or batch array. */
91
+ export const is_jsonrpc_message = (message) => Array.isArray(message)
92
+ ? message.length > 0 && message.every((m) => is_jsonrpc_object(m))
93
+ : is_jsonrpc_object(message);
94
+ /** Checks if a value is a JSON-RPC request (has method + id). */
95
+ export const is_jsonrpc_request = (message) => is_jsonrpc_object(message) && 'method' in message && 'id' in message;
96
+ /** Checks if a value is a JSON-RPC notification (has method, no id). */
97
+ export const is_jsonrpc_notification = (message) => is_jsonrpc_object(message) && 'method' in message && !('id' in message);
98
+ /** Checks if a value is a JSON-RPC success response (has result + id). */
99
+ export const is_jsonrpc_response = (message) => is_jsonrpc_object(message) && 'result' in message && 'id' in message;
100
+ /** Checks if a value is a JSON-RPC error response (has error + id). */
101
+ export const is_jsonrpc_error_response = (message) => is_jsonrpc_object(message) && 'error' in message && 'id' in message;
102
+ // --- Converters ---
103
+ /**
104
+ * Extracts a JSON-RPC request id from a message or raw value.
105
+ * Returns `null` if no valid id can be extracted.
106
+ */
107
+ export const to_jsonrpc_message_id = (message_or_id) => {
108
+ if (message_or_id == null)
109
+ return null;
110
+ const maybe_id = typeof message_or_id === 'object' ? message_or_id.id : message_or_id;
111
+ return is_jsonrpc_request_id(maybe_id) ? maybe_id : null;
112
+ };
113
+ /**
114
+ * Normalizes input to JSON-RPC params format.
115
+ * Returns `undefined` for null/undefined, wraps primitives in `{value}`.
116
+ */
117
+ export const to_jsonrpc_params = (input) => {
118
+ if (input === undefined || input === null) {
119
+ return undefined;
120
+ }
121
+ if (typeof input === 'object' && !Array.isArray(input)) {
122
+ return input;
123
+ }
124
+ return { value: input };
125
+ };
126
+ /**
127
+ * Normalizes output to JSON-RPC result format.
128
+ * Returns empty object for null/undefined, wraps primitives in `{value}`.
129
+ */
130
+ export const to_jsonrpc_result = (output) => {
131
+ if (output === null || output === undefined) {
132
+ return {};
133
+ }
134
+ if (typeof output === 'object' && !Array.isArray(output)) {
135
+ return output;
136
+ }
137
+ return { value: output };
138
+ };
@@ -1,6 +1,6 @@
1
1
  import './assert_dev_env.js';
2
2
  import { z } from 'zod';
3
- import type { JsonrpcErrorCode } from '../http/jsonrpc_errors.js';
3
+ import { type JsonrpcErrorCode } from '../http/jsonrpc.js';
4
4
  /**
5
5
  * Create a `RequestInit` for a JSON-RPC POST request.
6
6
  *
@@ -1 +1 @@
1
- {"version":3,"file":"rpc_helpers.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/rpc_helpers.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAW7B,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAGtB,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,2BAA2B,CAAC;AAEhE;;;;;;;GAOG;AACH,eAAO,MAAM,oBAAoB,GAChC,QAAQ,MAAM,EACd,SAAS,OAAO,EAChB,KAAI,MAAM,GAAG,MAAe,KAC1B,WAID,CAAC;AAEH;;;;;;;;GAQG;AACH,eAAO,MAAM,kBAAkB,GAC9B,eAAe,MAAM,EACrB,QAAQ,MAAM,EACd,SAAS,OAAO,EAChB,KAAI,MAAM,GAAG,MAAe,KAC1B,MAMF,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,6BAA6B,GACzC,MAAM,OAAO,EACb,gBAAgB,gBAAgB,KAC9B,IAUF,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,+BAA+B,GAAI,MAAM,OAAO,EAAE,gBAAgB,CAAC,CAAC,OAAO,KAAG,IAU1F,CAAC"}
1
+ {"version":3,"file":"rpc_helpers.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/rpc_helpers.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAW7B,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAEtB,OAAO,EAIN,KAAK,gBAAgB,EACrB,MAAM,oBAAoB,CAAC;AAE5B;;;;;;;GAOG;AACH,eAAO,MAAM,oBAAoB,GAChC,QAAQ,MAAM,EACd,SAAS,OAAO,EAChB,KAAI,MAAM,GAAG,MAAe,KAC1B,WAID,CAAC;AAEH;;;;;;;;GAQG;AACH,eAAO,MAAM,kBAAkB,GAC9B,eAAe,MAAM,EACrB,QAAQ,MAAM,EACd,SAAS,OAAO,EAChB,KAAI,MAAM,GAAG,MAAe,KAC1B,MAMF,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,6BAA6B,GACzC,MAAM,OAAO,EACb,gBAAgB,gBAAgB,KAC9B,IAUF,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,+BAA+B,GAAI,MAAM,OAAO,EAAE,gBAAgB,CAAC,CAAC,OAAO,KAAG,IAU1F,CAAC"}
@@ -8,7 +8,7 @@ import './assert_dev_env.js';
8
8
  */
9
9
  import { assert } from 'vitest';
10
10
  import { z } from 'zod';
11
- import { JSONRPC_VERSION, JsonrpcErrorResponse, JsonrpcResponse } from '../http/jsonrpc.js';
11
+ import { JSONRPC_VERSION, JsonrpcErrorResponse, JsonrpcResponse, } from '../http/jsonrpc.js';
12
12
  /**
13
13
  * Create a `RequestInit` for a JSON-RPC POST request.
14
14
  *
@@ -67,20 +67,20 @@
67
67
  <!-- TODO: panels will be user-draggable/rearrangeable, hardcoded order for now -->
68
68
  <div class="overview">
69
69
  <section>
70
- <div class="panel_header">
70
+ <div class="panel-header">
71
71
  <h3>accounts</h3>
72
72
  <a href={resolve('/admin/accounts' as any)} class="text_50 font_size_sm">view all &rarr;</a>
73
73
  </div>
74
74
  {#if accounts.loading}
75
75
  <p class="text_50">loading...</p>
76
76
  {:else if accounts.error}
77
- <p class="color_c">{accounts.error}</p>
77
+ <p class="color_c_50">{accounts.error}</p>
78
78
  {:else}
79
- <div class="baseline_row gap_xs">
79
+ <div class="baseline-row gap_xs">
80
80
  <strong class="font_size_lg">{accounts.account_count}</strong>
81
81
  <span class="text_50">accounts</span>
82
82
  </div>
83
- <div class="baseline_row gap_xs flex-wrap:wrap font_size_sm mt_xs">
83
+ <div class="baseline-row gap_xs flex-wrap:wrap font_size_sm mt_xs">
84
84
  {#each role_counts as [role, count] (role)}
85
85
  <span>{count} {role}</span>
86
86
  <span class="text_50">&middot;</span>
@@ -88,7 +88,7 @@
88
88
  <span>{unroled_count} unroled</span>
89
89
  </div>
90
90
  {#if accounts.accounts.length > 0}
91
- <ul class="compact_list">
91
+ <ul class="compact-list">
92
92
  {#each accounts.accounts.slice(0, 6) as entry (entry)}
93
93
  <li>
94
94
  <strong>{entry.account.username}</strong>
@@ -109,25 +109,25 @@
109
109
  </section>
110
110
 
111
111
  <section>
112
- <div class="panel_header">
112
+ <div class="panel-header">
113
113
  <h3>sessions</h3>
114
114
  <a href={resolve('/admin/sessions' as any)} class="text_50 font_size_sm">view all &rarr;</a>
115
115
  </div>
116
116
  {#if sessions.loading}
117
117
  <p class="text_50">loading...</p>
118
118
  {:else if sessions.error}
119
- <p class="color_c">{sessions.error}</p>
119
+ <p class="color_c_50">{sessions.error}</p>
120
120
  {:else}
121
- <div class="baseline_row gap_xs">
121
+ <div class="baseline-row gap_xs">
122
122
  <strong class="font_size_lg">{sessions.active_count}</strong>
123
123
  <span class="text_50">active</span>
124
124
  </div>
125
- <div class="baseline_row gap_xs">
125
+ <div class="baseline-row gap_xs">
126
126
  <strong class="font_size_lg">{unique_users}</strong>
127
127
  <span class="text_50">unique users</span>
128
128
  </div>
129
129
  {#if most_recent}
130
- <div class="baseline_row gap_xs font_size_sm mt_sm">
130
+ <div class="baseline-row gap_xs font_size_sm mt_sm">
131
131
  <span class="text_50">last active:</span>
132
132
  <strong>{most_recent.username}</strong>
133
133
  <span class="text_50" title={format_datetime_local(most_recent.last_seen_at)}
@@ -139,16 +139,16 @@
139
139
  </section>
140
140
 
141
141
  <section>
142
- <div class="panel_header">
142
+ <div class="panel-header">
143
143
  <h3>invites</h3>
144
144
  <a href={resolve('/admin/invites' as any)} class="text_50 font_size_sm">view all &rarr;</a>
145
145
  </div>
146
146
  {#if invites.loading}
147
147
  <p class="text_50">loading...</p>
148
148
  {:else if invites.error}
149
- <p class="color_c">{invites.error}</p>
149
+ <p class="color_c_50">{invites.error}</p>
150
150
  {:else}
151
- <div class="baseline_row gap_sm">
151
+ <div class="baseline-row gap_sm">
152
152
  <span class="text_50">public signup</span>
153
153
  {#if app_settings.settings?.open_signup}
154
154
  <span class="chip color_b">open</span>
@@ -156,7 +156,7 @@
156
156
  <span class="chip">closed</span>
157
157
  {/if}
158
158
  </div>
159
- <div class="baseline_row gap_xs">
159
+ <div class="baseline-row gap_xs">
160
160
  <strong class="font_size_lg">{invites.unclaimed_count}</strong>
161
161
  <span class="text_50">unclaimed</span>
162
162
  <span class="text_50">/</span>
@@ -164,7 +164,7 @@
164
164
  <span class="text_50">total</span>
165
165
  </div>
166
166
  {#if invites.invites.length > 0}
167
- <ul class="compact_list">
167
+ <ul class="compact-list">
168
168
  {#each invites.invites.slice(0, 4) as invite (invite.id)}
169
169
  <li>
170
170
  <span>{invite.email || invite.username || '—'}</span>
@@ -184,18 +184,18 @@
184
184
  </section>
185
185
 
186
186
  <section>
187
- <div class="panel_header">
187
+ <div class="panel-header">
188
188
  <h3>recent activity</h3>
189
189
  <a href={resolve('/admin/audit-log' as any)} class="text_50 font_size_sm">view all &rarr;</a>
190
190
  </div>
191
191
  {#if audit_log.loading}
192
192
  <p class="text_50">loading...</p>
193
193
  {:else if audit_log.error}
194
- <p class="color_c">{audit_log.error}</p>
194
+ <p class="color_c_50">{audit_log.error}</p>
195
195
  {:else if recent_events.length === 0}
196
196
  <p class="text_50">no events</p>
197
197
  {:else}
198
- <ul class="compact_list">
198
+ <ul class="compact-list">
199
199
  {#each recent_events as event (event.id)}
200
200
  <li>
201
201
  <span class="text_50 font_size_sm" title={format_datetime_local(event.created_at)}
@@ -212,27 +212,27 @@
212
212
  </section>
213
213
 
214
214
  <section>
215
- <div class="panel_header">
215
+ <div class="panel-header">
216
216
  <h3>security</h3>
217
217
  <a href={resolve('/admin/audit-log' as any)} class="text_50 font_size_sm">audit log &rarr;</a>
218
218
  </div>
219
219
  {#if audit_log.loading}
220
220
  <p class="text_50">loading...</p>
221
221
  {:else if audit_log.error}
222
- <p class="color_c">{audit_log.error}</p>
222
+ <p class="color_c_50">{audit_log.error}</p>
223
223
  {:else}
224
- <div class="baseline_row gap_xs">
225
- <strong class="font_size_lg" class:color_c={failed_logins.length > 0}>
224
+ <div class="baseline-row gap_xs">
225
+ <strong class="font_size_lg" class:color_c_50={failed_logins.length > 0}>
226
226
  {failed_logins.length}
227
227
  </strong>
228
228
  <span class="text_50">failed logins</span>
229
229
  </div>
230
- <div class="baseline_row gap_xs">
230
+ <div class="baseline-row gap_xs">
231
231
  <strong class="font_size_lg">{permit_changes.length}</strong>
232
232
  <span class="text_50">permit changes</span>
233
233
  </div>
234
234
  {#if permit_changes.length > 0}
235
- <ul class="compact_list">
235
+ <ul class="compact-list">
236
236
  {#each permit_changes.slice(0, 4) as event (event.id)}
237
237
  <li class="font_size_sm">
238
238
  <span class="text_50" title={format_datetime_local(event.created_at)}
@@ -250,15 +250,15 @@
250
250
  </section>
251
251
 
252
252
  <section>
253
- <div class="panel_header">
253
+ <div class="panel-header">
254
254
  <h3>system</h3>
255
255
  </div>
256
256
  {#if app_settings.loading}
257
257
  <p class="text_50">loading...</p>
258
258
  {:else if app_settings.error}
259
- <p class="color_c">{app_settings.error}</p>
259
+ <p class="color_c_50">{app_settings.error}</p>
260
260
  {:else}
261
- <div class="baseline_row gap_sm">
261
+ <div class="baseline-row gap_sm">
262
262
  <span class="text_50">public signup</span>
263
263
  {#if app_settings.settings?.open_signup}
264
264
  <span class="chip color_b">open</span>
@@ -267,7 +267,7 @@
267
267
  {/if}
268
268
  </div>
269
269
  {#if app_settings.settings?.updated_at}
270
- <div class="baseline_row gap_xs font_size_sm mt_xs">
270
+ <div class="baseline-row gap_xs font_size_sm mt_xs">
271
271
  <span class="text_50">last changed:</span>
272
272
  <span title={format_datetime_local(app_settings.settings.updated_at)}>
273
273
  {format_relative_time(app_settings.settings.updated_at)}
@@ -280,7 +280,7 @@
280
280
  {/if}
281
281
  {/if}
282
282
  {#if auth_state.account}
283
- <div class="baseline_row gap_sm">
283
+ <div class="baseline-row gap_sm">
284
284
  <span class="text_50">logged in as</span>
285
285
  <strong>{auth_state.account.username}</strong>
286
286
  </div>
@@ -310,25 +310,25 @@
310
310
  gap: var(--space_lg);
311
311
  }
312
312
 
313
- .panel_header {
313
+ .panel-header {
314
314
  display: flex;
315
315
  justify-content: space-between;
316
316
  align-items: baseline;
317
317
  margin-bottom: var(--space_md);
318
318
  }
319
319
 
320
- .baseline_row {
320
+ .baseline-row {
321
321
  display: flex;
322
322
  align-items: baseline;
323
323
  }
324
324
 
325
- .compact_list {
325
+ .compact-list {
326
326
  list-style: none;
327
327
  padding: 0;
328
328
  margin: var(--space_sm) 0 0;
329
329
  }
330
330
 
331
- .compact_list li {
331
+ .compact-list li {
332
332
  display: flex;
333
333
  align-items: baseline;
334
334
  gap: var(--space_xs);
@@ -15,29 +15,29 @@
15
15
  } = $props();
16
16
  </script>
17
17
 
18
- <div class="column_layout {class_name}" style:--column_width={column_width} {...rest}>
19
- <aside class="column_fixed unstyled">
18
+ <div class="column-layout {class_name}" style:--column_width={column_width} {...rest}>
19
+ <aside class="column-fixed unstyled">
20
20
  {@render aside()}
21
21
  </aside>
22
- <div class="column_fluid">
22
+ <div class="column-fluid">
23
23
  {@render children()}
24
24
  </div>
25
25
  </div>
26
26
 
27
27
  <style>
28
- .column_layout {
28
+ .column-layout {
29
29
  display: flex;
30
30
  height: 100%;
31
31
  }
32
32
 
33
- .column_fixed {
33
+ .column-fixed {
34
34
  width: var(--column_width, 280px);
35
35
  min-width: var(--column_width, 280px);
36
36
  height: 100%;
37
37
  overflow: auto;
38
38
  }
39
39
 
40
- .column_fluid {
40
+ .column-fluid {
41
41
  flex: 1;
42
42
  height: 100%;
43
43
  min-width: 0;