@rpcbase/client 0.473.0 → 0.475.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.
@@ -0,0 +1,37 @@
1
+ import { ApiErrorFields, ApiErrorResponse } from '@rpcbase/api';
2
+ type ApiClientErrorResponse = {
3
+ status: number;
4
+ data: unknown;
5
+ headers?: unknown;
6
+ };
7
+ export type ApiClientErrorOptions = {
8
+ status: number;
9
+ code: string;
10
+ data: unknown;
11
+ headers?: unknown;
12
+ message?: string;
13
+ fields?: ApiErrorFields;
14
+ requestId?: string;
15
+ cause?: unknown;
16
+ };
17
+ export declare class ApiClientError extends Error {
18
+ readonly __rpcbaseApiClientError = true;
19
+ readonly status: number;
20
+ readonly code: string;
21
+ readonly data: unknown;
22
+ readonly fields?: ApiErrorFields;
23
+ readonly requestId?: string;
24
+ readonly response: ApiClientErrorResponse;
25
+ constructor(options: ApiClientErrorOptions);
26
+ }
27
+ export declare const createApiClientError: ({ status, data, headers, cause, }: {
28
+ status: number;
29
+ data: unknown;
30
+ headers?: unknown;
31
+ cause?: unknown;
32
+ }) => ApiClientError;
33
+ export declare const isApiClientError: (error: unknown) => error is ApiClientError;
34
+ export declare const getApiClientErrorFromUnknown: (error: unknown) => ApiClientError | null;
35
+ export declare const isApiErrorResponse: (value: unknown) => value is ApiErrorResponse;
36
+ export {};
37
+ //# sourceMappingURL=ApiClientError.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ApiClientError.d.ts","sourceRoot":"","sources":["../../src/apiClient/ApiClientError.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAA;AAGpE,KAAK,sBAAsB,GAAG;IAC5B,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,OAAO,CAAA;IACb,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB,CAAA;AAED,MAAM,MAAM,qBAAqB,GAAG;IAClC,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,OAAO,CAAA;IACb,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,MAAM,CAAC,EAAE,cAAc,CAAA;IACvB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,KAAK,CAAC,EAAE,OAAO,CAAA;CAChB,CAAA;AAED,qBAAa,cAAe,SAAQ,KAAK;IACvC,QAAQ,CAAC,uBAAuB,QAAO;IACvC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAA;IACtB,QAAQ,CAAC,MAAM,CAAC,EAAE,cAAc,CAAA;IAChC,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAA;IAC3B,QAAQ,CAAC,QAAQ,EAAE,sBAAsB,CAAA;gBAE7B,OAAO,EAAE,qBAAqB;CAc3C;AAgED,eAAO,MAAM,oBAAoB,GAAI,mCAKlC;IACD,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,OAAO,CAAA;IACb,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,KAAK,CAAC,EAAE,OAAO,CAAA;CAChB,KAAG,cAgBH,CAAA;AAED,eAAO,MAAM,gBAAgB,GAAI,OAAO,OAAO,KAAG,KAAK,IAAI,cAKQ,CAAA;AAEnE,eAAO,MAAM,4BAA4B,GAAI,OAAO,OAAO,KAAG,cAAc,GAAG,IAa9E,CAAA;AAED,eAAO,MAAM,kBAAkB,GAAI,OAAO,OAAO,KAAG,KAAK,IAAI,gBAS5D,CAAA"}
@@ -0,0 +1,3 @@
1
+ import { Application, Request, Response } from 'express';
2
+ export declare const callServerApiRoute: <TResponse = Record<string, unknown>>(app: Application, method: string, matchPath: string, requestUrl: string, req: Partial<Request>, res: Partial<Response>) => Promise<TResponse>;
3
+ //# sourceMappingURL=callServerApiRoute.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"callServerApiRoute.d.ts","sourceRoot":"","sources":["../../src/apiClient/callServerApiRoute.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAW,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AA6BtE,eAAO,MAAM,kBAAkB,GAAI,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACpE,KAAK,WAAW,EAChB,QAAQ,MAAM,EACd,WAAW,MAAM,EACjB,YAAY,MAAM,EAClB,KAAK,OAAO,CAAC,OAAO,CAAC,EACrB,KAAK,OAAO,CAAC,QAAQ,CAAC,KACrB,OAAO,CAAC,SAAS,CAqPhB,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"getServerApiClient.d.ts","sourceRoot":"","sources":["../../src/apiClient/getServerApiClient.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAA8B,MAAM,SAAS,CAAA;AACjE,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,cAAc,CAAA;AAKvC,KAAK,uBAAuB,GAAG;IAC7B,MAAM,CAAC,EAAE,WAAW,CAAA;CACrB,CAAA;AAcD,eAAO,MAAM,kBAAkB,GAAS,KAAK,WAAW;UA0LtC,SAAS,kCACf,MAAM,WACH,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,iBACjB,GAAG,GAAG,uBAAuB,YAClC,uBAAuB,KAChC,OAAO,CAAC,SAAS,CAAC;WALP,SAAS,kCACf,MAAM,WACH,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,iBACjB,GAAG,GAAG,uBAAuB,YAClC,uBAAuB,KAChC,OAAO,CAAC,SAAS,CAAC;UALP,SAAS,kCACf,MAAM,WACH,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,iBACjB,GAAG,GAAG,uBAAuB,YAClC,uBAAuB,KAChC,OAAO,CAAC,SAAS,CAAC;aALP,SAAS,kCACf,MAAM,WACH,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,iBACjB,GAAG,GAAG,uBAAuB,YAClC,uBAAuB,KAChC,OAAO,CAAC,SAAS,CAAC;EA8BxB,CAAA;AAED,eAAe,kBAAkB,CAAA"}
1
+ {"version":3,"file":"getServerApiClient.d.ts","sourceRoot":"","sources":["../../src/apiClient/getServerApiClient.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AAC1C,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,cAAc,CAAA;AAKvC,KAAK,uBAAuB,GAAG;IAC7B,MAAM,CAAC,EAAE,WAAW,CAAA;CACrB,CAAA;AAGD,eAAO,MAAM,kBAAkB,GAAS,KAAK,WAAW;UA8EtC,SAAS,kCACf,MAAM,WACH,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,iBACjB,GAAG,GAAG,uBAAuB,YAClC,uBAAuB,KAChC,OAAO,CAAC,SAAS,CAAC;WALP,SAAS,kCACf,MAAM,WACH,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,iBACjB,GAAG,GAAG,uBAAuB,YAClC,uBAAuB,KAChC,OAAO,CAAC,SAAS,CAAC;UALP,SAAS,kCACf,MAAM,WACH,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,iBACjB,GAAG,GAAG,uBAAuB,YAClC,uBAAuB,KAChC,OAAO,CAAC,SAAS,CAAC;aALP,SAAS,kCACf,MAAM,WACH,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,iBACjB,GAAG,GAAG,uBAAuB,YAClC,uBAAuB,KAChC,OAAO,CAAC,SAAS,CAAC;EA8BxB,CAAA;AAED,eAAe,kBAAkB,CAAA"}
@@ -1,5 +1,6 @@
1
1
  import { Application } from 'express';
2
2
  import { Ctx } from '@rpcbase/api';
3
+ export * from './ApiClientError';
3
4
  type ServerArgs = {
4
5
  app: Application;
5
6
  };
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/apiClient/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AAC1C,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,cAAc,CAAA;AAGvC,KAAK,UAAU,GAAG;IAChB,GAAG,EAAE,WAAW,CAAC;CAClB,CAAC;AAEF,KAAK,WAAW,GAAG;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,KAAK,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG;KAC5C,CAAC,IAAI,MAAM,GAAG,CAAC,CAAC,EAAE,KAAK;CACzB,CAAC;AAEF,MAAM,MAAM,uBAAuB,GAAG;IACpC,MAAM,CAAC,EAAE,WAAW,CAAA;CACrB,CAAA;AAED,KAAK,eAAe,GAAG;IACrB,CAAC,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAClC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,aAAa,EACtB,OAAO,CAAC,EAAE,uBAAuB,GAChC,OAAO,CAAC,SAAS,CAAC,CAAA;IACrB,CAAC,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAClC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,aAAa,EACtB,GAAG,EAAE,GAAG,EACR,OAAO,CAAC,EAAE,uBAAuB,GAChC,OAAO,CAAC,SAAS,CAAC,CAAA;CACtB,CAAA;AAED,MAAM,MAAM,UAAU,GAAG,KAAK,GAAG,KAAK,GAAG,MAAM,GAAG,QAAQ,CAAC;AAC3D,KAAK,YAAY,CAAC,CAAC,IAAI,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC;AAE7C,MAAM,MAAM,SAAS,GAAG,YAAY,CAAC,eAAe,CAAC,CAAC;AAEtD,QAAA,IAAI,SAAS,EAAE,SAAS,CAAA;AAOxB,eAAO,MAAM,aAAa,GAAU,OAAO,UAAU,GAAG,WAAW,kBA4DlE,CAAA;AAED,OAAO,EAAE,SAAS,EAAE,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/apiClient/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AAC1C,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,cAAc,CAAA;AAKvC,cAAc,kBAAkB,CAAA;AAGhC,KAAK,UAAU,GAAG;IAChB,GAAG,EAAE,WAAW,CAAC;CAClB,CAAC;AAEF,KAAK,WAAW,GAAG;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,KAAK,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG;KAC5C,CAAC,IAAI,MAAM,GAAG,CAAC,CAAC,EAAE,KAAK;CACzB,CAAC;AAEF,MAAM,MAAM,uBAAuB,GAAG;IACpC,MAAM,CAAC,EAAE,WAAW,CAAA;CACrB,CAAA;AAED,KAAK,eAAe,GAAG;IACrB,CAAC,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAClC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,aAAa,EACtB,OAAO,CAAC,EAAE,uBAAuB,GAChC,OAAO,CAAC,SAAS,CAAC,CAAA;IACrB,CAAC,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAClC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,aAAa,EACtB,GAAG,EAAE,GAAG,EACR,OAAO,CAAC,EAAE,uBAAuB,GAChC,OAAO,CAAC,SAAS,CAAC,CAAA;CACtB,CAAA;AAED,MAAM,MAAM,UAAU,GAAG,KAAK,GAAG,KAAK,GAAG,MAAM,GAAG,QAAQ,CAAC;AAC3D,KAAK,YAAY,CAAC,CAAC,IAAI,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC;AAE7C,MAAM,MAAM,SAAS,GAAG,YAAY,CAAC,eAAe,CAAC,CAAC;AAEtD,QAAA,IAAI,SAAS,EAAE,SAAS,CAAA;AAOxB,eAAO,MAAM,aAAa,GAAU,OAAO,UAAU,GAAG,WAAW,kBA2DlE,CAAA;AAED,OAAO,EAAE,SAAS,EAAE,CAAA"}
@@ -0,0 +1,297 @@
1
+ import { createApiClientError } from "./index.js";
2
+ import { randomUUID } from "node:crypto";
3
+ //#region src/apiClient/callServerApiRoute.ts
4
+ var NO_ERROR = { hasError: false };
5
+ var callServerApiRoute = (app, method, matchPath, requestUrl, req, res) => new Promise((resolve, reject) => {
6
+ let isEnded = false;
7
+ let timeoutId = null;
8
+ let statusCode = 200;
9
+ let headersSent = false;
10
+ const responseHeaders = /* @__PURE__ */ new Map();
11
+ const responseWaiters = /* @__PURE__ */ new Set();
12
+ const resolveRequest = (data) => {
13
+ if (isEnded) return;
14
+ isEnded = true;
15
+ if (timeoutId) clearTimeout(timeoutId);
16
+ resolve(data);
17
+ };
18
+ const rejectRequest = (error) => {
19
+ if (isEnded) return;
20
+ isEnded = true;
21
+ if (timeoutId) clearTimeout(timeoutId);
22
+ reject(error);
23
+ };
24
+ const responseHeadersObject = () => Object.fromEntries(responseHeaders.entries());
25
+ const rejectUnhandledError = (error) => {
26
+ if (isEnded) return;
27
+ let requestId = responseHeaders.get("x-request-id");
28
+ if (typeof requestId !== "string" || !requestId) {
29
+ requestId = randomUUID();
30
+ responseHeaders.set("x-request-id", requestId);
31
+ }
32
+ rejectRequest(createApiClientError({
33
+ status: 500,
34
+ data: {
35
+ success: false,
36
+ error: "internal_error",
37
+ requestId
38
+ },
39
+ headers: responseHeadersObject(),
40
+ cause: error
41
+ }));
42
+ };
43
+ const notifyResponse = () => {
44
+ for (const waiter of responseWaiters) waiter();
45
+ responseWaiters.clear();
46
+ };
47
+ const finishResponse = (data) => {
48
+ if (isEnded) return;
49
+ headersSent = true;
50
+ notifyResponse();
51
+ if (statusCode < 200 || statusCode >= 300) {
52
+ rejectRequest(createApiClientError({
53
+ status: statusCode,
54
+ data,
55
+ headers: responseHeadersObject()
56
+ }));
57
+ return;
58
+ }
59
+ resolveRequest(data);
60
+ };
61
+ const mockReq = {
62
+ ...req,
63
+ method: method.toUpperCase(),
64
+ url: requestUrl,
65
+ originalUrl: requestUrl
66
+ };
67
+ const mockRes = {
68
+ ...res,
69
+ locals: { ...res.locals ?? {} }
70
+ };
71
+ Object.defineProperties(mockRes, {
72
+ headersSent: {
73
+ configurable: true,
74
+ get: () => headersSent
75
+ },
76
+ statusCode: {
77
+ configurable: true,
78
+ get: () => statusCode,
79
+ set: (value) => {
80
+ statusCode = value;
81
+ }
82
+ }
83
+ });
84
+ mockRes.status = ((value) => {
85
+ statusCode = value;
86
+ return mockRes;
87
+ });
88
+ mockRes.json = ((data) => {
89
+ finishResponse(data);
90
+ return mockRes;
91
+ });
92
+ mockRes.send = ((data) => {
93
+ finishResponse(data);
94
+ return mockRes;
95
+ });
96
+ mockRes.end = ((data) => {
97
+ finishResponse(data);
98
+ return mockRes;
99
+ });
100
+ mockRes.sendStatus = ((value) => {
101
+ statusCode = value;
102
+ finishResponse(String(value));
103
+ return mockRes;
104
+ });
105
+ mockRes.setHeader = ((name, value) => {
106
+ responseHeaders.set(name.toLowerCase(), value);
107
+ return mockRes;
108
+ });
109
+ mockRes.getHeader = ((name) => responseHeaders.get(name.toLowerCase()));
110
+ mockRes.getHeaders = (() => responseHeadersObject());
111
+ mockRes.hasHeader = ((name) => responseHeaders.has(name.toLowerCase()));
112
+ mockRes.removeHeader = ((name) => {
113
+ responseHeaders.delete(name.toLowerCase());
114
+ });
115
+ mockRes.set = ((field, value) => {
116
+ if (typeof field === "string") responseHeaders.set(field.toLowerCase(), value);
117
+ else for (const [name, headerValue] of Object.entries(field)) responseHeaders.set(name.toLowerCase(), headerValue);
118
+ return mockRes;
119
+ });
120
+ mockRes.header = mockRes.set;
121
+ mockRes.type = ((value) => {
122
+ responseHeaders.set("content-type", value);
123
+ return mockRes;
124
+ });
125
+ const routerStack = app.router.stack;
126
+ const firstApiMiddlewareIndex = routerStack.findIndex((layer) => layer.name === "__FIRST_API_MIDDLEWARE__");
127
+ if (!(firstApiMiddlewareIndex > -1)) throw new Error("middleware: __FIRST_API_MIDDLEWARE__ was not found in stack");
128
+ const apiStack = routerStack.slice(firstApiMiddlewareIndex + 1);
129
+ const runHandler = (handler, state) => new Promise((resolveHandler) => {
130
+ let settled = false;
131
+ const settle = (outcome) => {
132
+ if (settled) return;
133
+ settled = true;
134
+ responseWaiters.delete(onResponse);
135
+ resolveHandler(outcome);
136
+ };
137
+ const onResponse = () => settle({ responded: true });
138
+ responseWaiters.add(onResponse);
139
+ const next = (error) => {
140
+ settle(error === void 0 || error === null ? NO_ERROR : {
141
+ hasError: true,
142
+ error
143
+ });
144
+ };
145
+ try {
146
+ const result = state.hasError ? handler(state.error, mockReq, mockRes, next) : handler(mockReq, mockRes, next);
147
+ if (result && typeof result.then === "function") Promise.resolve(result).catch(next);
148
+ } catch (error) {
149
+ next(error);
150
+ }
151
+ });
152
+ const processLayer = async (index, state) => {
153
+ if (isEnded) return;
154
+ if (index >= apiStack.length) {
155
+ if (state.hasError) rejectUnhandledError(state.error);
156
+ return;
157
+ }
158
+ const layer = apiStack[index];
159
+ let isNonMatchingLayer;
160
+ try {
161
+ isNonMatchingLayer = !layer.match(matchPath);
162
+ } catch (error) {
163
+ await processLayer(index + 1, {
164
+ hasError: true,
165
+ error
166
+ });
167
+ return;
168
+ }
169
+ if (isNonMatchingLayer) {
170
+ await processLayer(index + 1, state);
171
+ return;
172
+ }
173
+ if (layer.route) {
174
+ if (state.hasError) {
175
+ await processLayer(index + 1, state);
176
+ return;
177
+ }
178
+ if (!layer.route.methods[method.toLowerCase()]) {
179
+ await processLayer(index + 1, state);
180
+ return;
181
+ }
182
+ if (layer.route.stack.length !== 1) throw new Error(`expected only one handler per route for route: ${layer.route.path}`);
183
+ const outcome = await runHandler(layer.route.stack[0].handle, state);
184
+ if ("responded" in outcome) return;
185
+ await processLayer(index + 1, outcome);
186
+ return;
187
+ }
188
+ const isErrorHandler = layer.handle.length === 4;
189
+ if (state.hasError !== isErrorHandler) {
190
+ await processLayer(index + 1, state);
191
+ return;
192
+ }
193
+ const outcome = await runHandler(layer.handle, state);
194
+ if ("responded" in outcome) return;
195
+ await processLayer(index + 1, outcome);
196
+ };
197
+ timeoutId = setTimeout(() => {
198
+ rejectRequest(/* @__PURE__ */ new Error("Route handler timed out"));
199
+ }, 3e4);
200
+ processLayer(0, NO_ERROR).catch(rejectUnhandledError);
201
+ });
202
+ //#endregion
203
+ //#region src/apiClient/getServerApiClient.ts
204
+ var getServerApiClient = async (app) => {
205
+ const isCtx = (value) => {
206
+ if (!value || typeof value !== "object") return false;
207
+ return "req" in value && "res" in value;
208
+ };
209
+ const createAbortError = () => {
210
+ const error = /* @__PURE__ */ new Error("The operation was aborted.");
211
+ error.name = "AbortError";
212
+ return error;
213
+ };
214
+ const mergeQueryValues = (target, key, value) => {
215
+ const existing = target[key];
216
+ if (Array.isArray(existing)) {
217
+ existing.push(value);
218
+ return;
219
+ }
220
+ if (typeof existing === "string") {
221
+ target[key] = [existing, value];
222
+ return;
223
+ }
224
+ target[key] = value;
225
+ };
226
+ const toQueryValue = (value) => {
227
+ if (typeof value === "string") return value;
228
+ if (typeof value === "number") return Number.isFinite(value) ? String(value) : null;
229
+ if (typeof value === "boolean") return value ? "true" : "false";
230
+ if (typeof value === "bigint") return String(value);
231
+ if (value instanceof Date) return value.toISOString();
232
+ return null;
233
+ };
234
+ const buildQuery = (path, payload) => {
235
+ const url = new URL(path, "http://localhost");
236
+ const query = {};
237
+ for (const [key, value] of url.searchParams) mergeQueryValues(query, key, value);
238
+ for (const [key, rawValue] of Object.entries(payload)) {
239
+ if (!key) continue;
240
+ if (Array.isArray(rawValue)) {
241
+ for (const item of rawValue) {
242
+ const converted = toQueryValue(item);
243
+ if (converted !== null) mergeQueryValues(query, key, converted);
244
+ }
245
+ continue;
246
+ }
247
+ const converted = toQueryValue(rawValue);
248
+ if (converted !== null) mergeQueryValues(query, key, converted);
249
+ }
250
+ const searchParams = new URLSearchParams();
251
+ for (const [key, rawValue] of Object.entries(query)) {
252
+ if (Array.isArray(rawValue)) {
253
+ for (const value of rawValue) searchParams.append(key, value);
254
+ continue;
255
+ }
256
+ searchParams.append(key, rawValue);
257
+ }
258
+ const matchPath = url.pathname;
259
+ return {
260
+ matchPath,
261
+ requestUrl: `${matchPath}${searchParams.toString() ? `?${searchParams.toString()}` : ""}`,
262
+ query
263
+ };
264
+ };
265
+ const createMethod = (method) => {
266
+ return async (path, payload, ctxOrOptions, options) => {
267
+ const ctx = isCtx(ctxOrOptions) ? ctxOrOptions : void 0;
268
+ const requestOptions = isCtx(ctxOrOptions) ? options : ctxOrOptions;
269
+ if (!ctx) throw new Error("Context must be provided in SSR mode");
270
+ if (requestOptions?.signal?.aborted) throw createAbortError();
271
+ if (method.toLowerCase() === "get") {
272
+ const { matchPath, requestUrl, query } = buildQuery(path, payload);
273
+ return callServerApiRoute(app, method, matchPath, requestUrl, {
274
+ ...ctx.req,
275
+ body: {},
276
+ query
277
+ }, ctx.res);
278
+ }
279
+ const { matchPath, requestUrl, query } = buildQuery(path, {});
280
+ return callServerApiRoute(app, method, matchPath, requestUrl, {
281
+ ...ctx.req,
282
+ body: payload,
283
+ query
284
+ }, ctx.res);
285
+ };
286
+ };
287
+ return {
288
+ get: createMethod("get"),
289
+ post: createMethod("post"),
290
+ put: createMethod("put"),
291
+ delete: createMethod("delete")
292
+ };
293
+ };
294
+ //#endregion
295
+ export { getServerApiClient as default, getServerApiClient };
296
+
297
+ //# sourceMappingURL=getServerApiClient-Dv6Onzp4.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getServerApiClient-Dv6Onzp4.js","names":["randomUUID","Application","IRouter","Request","Response","createApiClientError","NextMiddleware","err","LayerHandler","req","res","next","ErrorLayerHandler","error","RouterLayer","name","match","path","handle","route","methods","Record","stack","Array","DispatchState","hasError","HandlerOutcome","responded","NO_ERROR","callServerApiRoute","app","method","matchPath","requestUrl","Partial","Promise","TResponse","resolve","reject","isEnded","timeoutId","ReturnType","setTimeout","statusCode","headersSent","responseHeaders","Map","responseWaiters","Set","resolveRequest","data","clearTimeout","rejectRequest","responseHeadersObject","Object","fromEntries","entries","rejectUnhandledError","requestId","get","set","success","status","headers","cause","notifyResponse","waiter","clear","finishResponse","mockReq","toUpperCase","url","originalUrl","mockRes","locals","defineProperties","configurable","value","json","send","end","sendStatus","String","setHeader","toLowerCase","getHeader","getHeaders","hasHeader","has","removeHeader","delete","field","headerValue","header","type","routerStack","router","firstApiMiddlewareIndex","findIndex","layer","Error","apiStack","slice","runHandler","handler","state","resolveHandler","settled","settle","outcome","onResponse","add","undefined","result","PromiseLike","then","catch","processLayer","index","length","isNonMatchingLayer","isErrorHandler","Application","Ctx","callServerApiRoute","ApiClientRequestOptions","signal","AbortSignal","getServerApiClient","app","isCtx","value","createAbortError","error","Error","name","mergeQueryValues","target","Record","key","existing","Array","isArray","push","toQueryValue","Number","isFinite","String","Date","toISOString","buildQuery","path","payload","url","URL","query","searchParams","rawValue","Object","entries","item","converted","URLSearchParams","append","matchPath","pathname","requestUrl","toString","createMethod","method","ctxOrOptions","options","Promise","TResponse","ctx","undefined","requestOptions","aborted","normalizedMethod","toLowerCase","req","body","res","apiClient","get","post","put","delete"],"sources":["../src/apiClient/callServerApiRoute.ts","../src/apiClient/getServerApiClient.ts"],"sourcesContent":["import { randomUUID } from \"node:crypto\"\n\nimport type { Application, IRouter, Request, Response } from \"express\"\n\nimport { createApiClientError } from \"./ApiClientError\"\n\n\ntype NextMiddleware = (err?: unknown) => void\ntype LayerHandler = (req: Request, res: Response, next: NextMiddleware) => unknown\ntype ErrorLayerHandler = (error: unknown, req: Request, res: Response, next: NextMiddleware) => unknown\n\ntype RouterLayer = {\n name: string\n match: (path: string) => boolean\n handle: LayerHandler | ErrorLayerHandler\n route?: {\n methods: Record<string, boolean | undefined>\n path: string\n stack: Array<{ handle: LayerHandler }>\n }\n}\n\ntype DispatchState =\n | { hasError: false }\n | { hasError: true; error: unknown }\n\ntype HandlerOutcome = DispatchState | { responded: true }\n\nconst NO_ERROR: DispatchState = { hasError: false }\n\n\nexport const callServerApiRoute = <TResponse = Record<string, unknown>>(\n app: Application,\n method: string,\n matchPath: string,\n requestUrl: string,\n req: Partial<Request>,\n res: Partial<Response>,\n): Promise<TResponse> => new Promise((resolve, reject) => {\n let isEnded = false\n let timeoutId: ReturnType<typeof setTimeout> | null = null\n let statusCode = 200\n let headersSent = false\n const responseHeaders = new Map<string, unknown>()\n const responseWaiters = new Set<() => void>()\n\n const resolveRequest = (data: TResponse) => {\n if (isEnded) return\n isEnded = true\n if (timeoutId) clearTimeout(timeoutId)\n resolve(data)\n }\n\n const rejectRequest = (error: unknown) => {\n if (isEnded) return\n isEnded = true\n if (timeoutId) clearTimeout(timeoutId)\n reject(error)\n }\n\n const responseHeadersObject = () => Object.fromEntries(responseHeaders.entries())\n\n const rejectUnhandledError = (error: unknown) => {\n if (isEnded) return\n\n let requestId = responseHeaders.get(\"x-request-id\")\n if (typeof requestId !== \"string\" || !requestId) {\n requestId = randomUUID()\n responseHeaders.set(\"x-request-id\", requestId)\n }\n\n const data = {\n success: false,\n error: \"internal_error\",\n requestId,\n }\n\n rejectRequest(createApiClientError({\n status: 500,\n data,\n headers: responseHeadersObject(),\n cause: error,\n }))\n }\n\n const notifyResponse = () => {\n for (const waiter of responseWaiters) waiter()\n responseWaiters.clear()\n }\n\n const finishResponse = (data: unknown) => {\n if (isEnded) return\n headersSent = true\n notifyResponse()\n\n if (statusCode < 200 || statusCode >= 300) {\n rejectRequest(createApiClientError({\n status: statusCode,\n data,\n headers: responseHeadersObject(),\n }))\n return\n }\n\n resolveRequest(data as TResponse)\n }\n\n const mockReq = {\n ...req,\n method: method.toUpperCase(),\n url: requestUrl,\n originalUrl: requestUrl,\n } as Request\n\n const mockRes = {\n ...res,\n locals: { ...(res.locals ?? {}) },\n } as Response\n\n Object.defineProperties(mockRes, {\n headersSent: {\n configurable: true,\n get: () => headersSent,\n },\n statusCode: {\n configurable: true,\n get: () => statusCode,\n set: (value: number) => {\n statusCode = value\n },\n },\n })\n\n mockRes.status = ((value: number) => {\n statusCode = value\n return mockRes\n }) as Response[\"status\"]\n mockRes.json = ((data: unknown) => {\n finishResponse(data)\n return mockRes\n }) as Response[\"json\"]\n mockRes.send = ((data: unknown) => {\n finishResponse(data)\n return mockRes\n }) as Response[\"send\"]\n mockRes.end = ((data?: unknown) => {\n finishResponse(data)\n return mockRes\n }) as Response[\"end\"]\n mockRes.sendStatus = ((value: number) => {\n statusCode = value\n finishResponse(String(value))\n return mockRes\n }) as Response[\"sendStatus\"]\n mockRes.setHeader = ((name: string, value: unknown) => {\n responseHeaders.set(name.toLowerCase(), value)\n return mockRes\n }) as Response[\"setHeader\"]\n mockRes.getHeader = ((name: string) => responseHeaders.get(name.toLowerCase())) as Response[\"getHeader\"]\n mockRes.getHeaders = (() => responseHeadersObject()) as Response[\"getHeaders\"]\n mockRes.hasHeader = ((name: string) => responseHeaders.has(name.toLowerCase())) as Response[\"hasHeader\"]\n mockRes.removeHeader = ((name: string) => {\n responseHeaders.delete(name.toLowerCase())\n }) as Response[\"removeHeader\"]\n mockRes.set = ((field: string | Record<string, unknown>, value?: unknown) => {\n if (typeof field === \"string\") {\n responseHeaders.set(field.toLowerCase(), value)\n } else {\n for (const [name, headerValue] of Object.entries(field)) {\n responseHeaders.set(name.toLowerCase(), headerValue)\n }\n }\n return mockRes\n }) as Response[\"set\"]\n mockRes.header = mockRes.set\n mockRes.type = ((value: string) => {\n responseHeaders.set(\"content-type\", value)\n return mockRes\n }) as Response[\"type\"]\n\n const routerStack = (app.router as unknown as IRouter).stack as unknown as RouterLayer[]\n\n const firstApiMiddlewareIndex = routerStack.findIndex((layer) => layer.name === \"__FIRST_API_MIDDLEWARE__\")\n if (!(firstApiMiddlewareIndex > -1)) {\n throw new Error(\"middleware: __FIRST_API_MIDDLEWARE__ was not found in stack\")\n }\n\n const apiStack = routerStack.slice(firstApiMiddlewareIndex + 1)\n\n const runHandler = (\n handler: LayerHandler | ErrorLayerHandler,\n state: DispatchState,\n ): Promise<HandlerOutcome> => new Promise((resolveHandler) => {\n let settled = false\n\n const settle = (outcome: HandlerOutcome) => {\n if (settled) return\n settled = true\n responseWaiters.delete(onResponse)\n resolveHandler(outcome)\n }\n\n const onResponse = () => settle({ responded: true })\n responseWaiters.add(onResponse)\n\n const next: NextMiddleware = (error) => {\n settle(error === undefined || error === null\n ? NO_ERROR\n : { hasError: true, error })\n }\n\n try {\n const result = state.hasError\n ? (handler as ErrorLayerHandler)(state.error, mockReq, mockRes, next)\n : (handler as LayerHandler)(mockReq, mockRes, next)\n\n if (result && typeof (result as PromiseLike<unknown>).then === \"function\") {\n void Promise.resolve(result).catch(next)\n }\n } catch (error) {\n next(error)\n }\n })\n\n const processLayer = async (index: number, state: DispatchState): Promise<void> => {\n if (isEnded) return\n if (index >= apiStack.length) {\n if (state.hasError) rejectUnhandledError(state.error)\n return\n }\n\n const layer = apiStack[index]\n\n let isNonMatchingLayer: boolean\n try {\n isNonMatchingLayer = !layer.match(matchPath)\n } catch (error) {\n await processLayer(index + 1, { hasError: true, error })\n return\n }\n\n if (isNonMatchingLayer) {\n await processLayer(index + 1, state)\n return\n }\n\n if (layer.route) {\n if (state.hasError) {\n await processLayer(index + 1, state)\n return\n }\n\n if (!layer.route.methods[method.toLowerCase()]) {\n await processLayer(index + 1, state)\n return\n }\n\n if (layer.route.stack.length !== 1) {\n throw new Error(`expected only one handler per route for route: ${layer.route.path}`)\n }\n\n const outcome = await runHandler(layer.route.stack[0].handle, state)\n if (\"responded\" in outcome) return\n await processLayer(index + 1, outcome)\n return\n }\n\n const isErrorHandler = layer.handle.length === 4\n if (state.hasError !== isErrorHandler) {\n await processLayer(index + 1, state)\n return\n }\n\n const outcome = await runHandler(layer.handle, state)\n if (\"responded\" in outcome) return\n await processLayer(index + 1, outcome)\n }\n\n timeoutId = setTimeout(() => {\n rejectRequest(new Error(\"Route handler timed out\"))\n }, 30000)\n\n void processLayer(0, NO_ERROR).catch(rejectUnhandledError)\n })\n","import type { Application } from \"express\"\nimport type { Ctx } from \"@rpcbase/api\"\n\nimport { callServerApiRoute } from \"./callServerApiRoute\"\n\n\ntype ApiClientRequestOptions = {\n signal?: AbortSignal\n}\n\n\nexport const getServerApiClient = async(app: Application) => {\n const isCtx = (value: unknown): value is Ctx => {\n if (!value || typeof value !== \"object\") return false\n return \"req\" in value && \"res\" in value\n }\n\n const createAbortError = () => {\n const error = new Error(\"The operation was aborted.\")\n error.name = \"AbortError\"\n return error\n }\n\n const mergeQueryValues = (target: Record<string, string | string[]>, key: string, value: string) => {\n const existing = target[key]\n if (Array.isArray(existing)) {\n existing.push(value)\n return\n }\n\n if (typeof existing === \"string\") {\n target[key] = [existing, value]\n return\n }\n\n target[key] = value\n }\n\n const toQueryValue = (value: unknown): string | null => {\n if (typeof value === \"string\") return value\n if (typeof value === \"number\") return Number.isFinite(value) ? String(value) : null\n if (typeof value === \"boolean\") return value ? \"true\" : \"false\"\n if (typeof value === \"bigint\") return String(value)\n if (value instanceof Date) return value.toISOString()\n return null\n }\n\n const buildQuery = (path: string, payload: Record<string, unknown>) => {\n const url = new URL(path, \"http://localhost\")\n\n const query: Record<string, string | string[]> = {}\n for (const [key, value] of url.searchParams) {\n mergeQueryValues(query, key, value)\n }\n\n for (const [key, rawValue] of Object.entries(payload)) {\n if (!key) continue\n\n if (Array.isArray(rawValue)) {\n for (const item of rawValue) {\n const converted = toQueryValue(item)\n if (converted !== null) mergeQueryValues(query, key, converted)\n }\n continue\n }\n\n const converted = toQueryValue(rawValue)\n if (converted !== null) mergeQueryValues(query, key, converted)\n }\n\n const searchParams = new URLSearchParams()\n for (const [key, rawValue] of Object.entries(query)) {\n if (Array.isArray(rawValue)) {\n for (const value of rawValue) {\n searchParams.append(key, value)\n }\n continue\n }\n\n searchParams.append(key, rawValue)\n }\n\n const matchPath = url.pathname\n const requestUrl = `${matchPath}${searchParams.toString() ? `?${searchParams.toString()}` : \"\"}`\n\n return { matchPath, requestUrl, query }\n }\n\n const createMethod = (method: string) => {\n return async <TResponse = Record<string, unknown>>(\n path: string,\n payload: Record<string, unknown>,\n ctxOrOptions?: Ctx | ApiClientRequestOptions,\n options?: ApiClientRequestOptions,\n ): Promise<TResponse> => {\n const ctx = isCtx(ctxOrOptions) ? ctxOrOptions : undefined\n const requestOptions = isCtx(ctxOrOptions) ? options : ctxOrOptions\n if (!ctx) {\n throw new Error(\"Context must be provided in SSR mode\")\n }\n if (requestOptions?.signal?.aborted) {\n throw createAbortError()\n }\n\n const normalizedMethod = method.toLowerCase()\n\n if (normalizedMethod === \"get\") {\n const { matchPath, requestUrl, query } = buildQuery(path, payload)\n return callServerApiRoute<TResponse>(app, method, matchPath, requestUrl, { ...ctx.req, body: {}, query }, ctx.res)\n }\n\n const { matchPath, requestUrl, query } = buildQuery(path, {})\n return callServerApiRoute<TResponse>(app, method, matchPath, requestUrl, { ...ctx.req, body: payload, query }, ctx.res)\n }\n }\n\n const apiClient = {\n get: createMethod(\"get\"),\n post: createMethod(\"post\"),\n put: createMethod(\"put\"),\n delete: createMethod(\"delete\")\n }\n\n return apiClient\n}\n\nexport default getServerApiClient\n"],"mappings":"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"}
package/dist/index.js CHANGED
@@ -396,6 +396,104 @@ function _temp8$1() {
396
396
  };
397
397
  }
398
398
  //#endregion
399
+ //#region src/apiClient/ApiClientError.ts
400
+ var ApiClientError = class extends Error {
401
+ __rpcbaseApiClientError = true;
402
+ status;
403
+ code;
404
+ data;
405
+ fields;
406
+ requestId;
407
+ response;
408
+ constructor(options) {
409
+ super(options.message ?? `API request failed with status ${options.status}.`, { cause: options.cause });
410
+ this.name = "ApiClientError";
411
+ this.status = options.status;
412
+ this.code = options.code;
413
+ this.data = options.data;
414
+ this.fields = options.fields;
415
+ this.requestId = options.requestId;
416
+ this.response = {
417
+ status: options.status,
418
+ data: options.data,
419
+ ...options.headers === void 0 ? {} : { headers: options.headers }
420
+ };
421
+ }
422
+ };
423
+ var isRecord = (value) => Boolean(value) && typeof value === "object" && !Array.isArray(value);
424
+ var API_ERROR_CODE_PATTERN = /^[a-z][A-Za-z0-9_.:-]*$/u;
425
+ var normalizeCode = (value, status) => {
426
+ if (typeof value === "string") {
427
+ const code = value.trim();
428
+ if (API_ERROR_CODE_PATTERN.test(code)) return code;
429
+ }
430
+ return status >= 500 ? "internal_error" : "http_error";
431
+ };
432
+ var normalizeMessage = (data) => {
433
+ if (typeof data.message === "string" && data.message.trim()) return data.message.trim();
434
+ if (typeof data.error === "string") {
435
+ const error = data.error.trim();
436
+ if (error && !API_ERROR_CODE_PATTERN.test(error)) return error;
437
+ }
438
+ };
439
+ var isApiErrorFields = (value) => {
440
+ if (!isRecord(value)) return false;
441
+ return Object.values(value).every((messages) => Array.isArray(messages) && messages.every((message) => typeof message === "string"));
442
+ };
443
+ var normalizeFields = (value) => {
444
+ if (!isRecord(value)) return void 0;
445
+ const fields = {};
446
+ for (const [key, messages] of Object.entries(value)) {
447
+ if (!Array.isArray(messages) || !messages.every((message) => typeof message === "string")) continue;
448
+ fields[key] = messages;
449
+ }
450
+ return Object.keys(fields).length ? fields : void 0;
451
+ };
452
+ var getHeader = (headers, name) => {
453
+ if (!headers || typeof headers !== "object") return void 0;
454
+ const get = headers.get;
455
+ if (typeof get === "function") {
456
+ const value = get.call(headers, name);
457
+ if (typeof value === "string" && value.trim()) return value.trim();
458
+ }
459
+ const record = headers;
460
+ const normalizedName = name.toLowerCase();
461
+ const value = Object.entries(record).find(([headerName]) => headerName.toLowerCase() === normalizedName)?.[1];
462
+ if (typeof value === "string" && value.trim()) return value.trim();
463
+ if (Array.isArray(value) && typeof value[0] === "string" && value[0].trim()) return value[0].trim();
464
+ };
465
+ var createApiClientError = ({ status, data, headers, cause }) => {
466
+ const body = isRecord(data) ? data : {};
467
+ const requestId = getHeader(headers, "x-request-id") ?? (typeof body.requestId === "string" && body.requestId.trim() ? body.requestId.trim() : void 0);
468
+ return new ApiClientError({
469
+ status,
470
+ code: normalizeCode(body.error, status),
471
+ data,
472
+ headers,
473
+ message: normalizeMessage(body),
474
+ fields: normalizeFields(body.fields),
475
+ requestId,
476
+ cause
477
+ });
478
+ };
479
+ var isApiClientError = (error) => error instanceof ApiClientError || error instanceof Error && error.__rpcbaseApiClientError === true && typeof error.status === "number" && typeof error.code === "string";
480
+ var getApiClientErrorFromUnknown = (error) => {
481
+ if (isApiClientError(error)) return error;
482
+ if (!isRecord(error)) return null;
483
+ const response = error.response;
484
+ if (!isRecord(response) || typeof response.status !== "number") return null;
485
+ return createApiClientError({
486
+ status: response.status,
487
+ data: response.data,
488
+ headers: response.headers,
489
+ cause: error
490
+ });
491
+ };
492
+ var isApiErrorResponse = (value) => {
493
+ if (!isRecord(value)) return false;
494
+ return value.success === false && typeof value.error === "string" && Boolean(value.error.trim()) && typeof value.requestId === "string" && Boolean(value.requestId.trim()) && (value.message === void 0 || typeof value.message === "string") && (value.fields === void 0 || isApiErrorFields(value.fields));
495
+ };
496
+ //#endregion
399
497
  //#region src/apiClient/index.ts
400
498
  var apiClient;
401
499
  var isApiClientRequestOptions = (value) => {
@@ -405,7 +503,7 @@ var isApiClientRequestOptions = (value) => {
405
503
  var initApiClient = async (args) => {
406
504
  if (env.SSR) {
407
505
  if (!args) throw new Error("Server args must be provided in SSR mode");
408
- const { getServerApiClient } = await import("./getServerApiClient-Dtfqua8g.js");
506
+ const { getServerApiClient } = await import("./getServerApiClient-Dv6Onzp4.js");
409
507
  apiClient = await getServerApiClient(args.app);
410
508
  } else {
411
509
  const axiosClient = (await import("axios/dist/browser/axios.cjs")).default.create({
@@ -426,8 +524,7 @@ var initApiClient = async (args) => {
426
524
  try {
427
525
  return (await axiosClient(config)).data;
428
526
  } catch (error) {
429
- console.log("AXIOS API ERROR", error);
430
- throw error;
527
+ throw getApiClientErrorFromUnknown(error) ?? error;
431
528
  }
432
529
  };
433
530
  };
@@ -3343,6 +3440,6 @@ var useNotificationsRealtime = () => {
3343
3440
  return useContext(NotificationsRealtimeContext);
3344
3441
  };
3345
3442
  //#endregion
3346
- export { NotificationsRealtimeContext, NotificationsRealtimeProvider, RPCBASE_SERVICE_WORKER_MESSAGE_SOURCE, RPCBASE_SERVICE_WORKER_PATH, RPCBASE_SERVICE_WORKER_SCOPE, RootProvider, RouteErrorBoundary, RtsSsrRuntimeProvider, SSR_ERROR_STATE_GLOBAL_KEY, STATIC_RPCBASE_RTS_HYDRATION_DATA_KEY, SsrErrorFallback, apiClient, archiveNotification, clearHydratedRtsQueryData, consumeClientSsrErrorState, consumeHydratedRtsCount, getFeatureFlag, getNotificationSettings, hydrateRtsFromWindow, initApiClient, initWithRoutes, listNotifications, markAllNotificationsRead, markNotificationRead, markNotificationsReadByUrl, peekClientSsrErrorState, peekHydratedRtsCount, peekHydratedRtsQueryData, peekHydratedRtsQueryPageInfo, peekHydratedRtsQueryTotalCount, registerRpcbaseServiceWorker, reportClientException, runNotificationDigest, scheduleRpcbaseServiceWorkerRegistration, sendRpcbaseServiceWorkerMessage, serializeSsrErrorState, setClientExceptionReporter, subscribeRpcbaseServiceWorkerMessages, toast, updateNotificationSettings, useMediaQuery, useNotificationsRealtime, useThrottledMeasure };
3443
+ export { ApiClientError, NotificationsRealtimeContext, NotificationsRealtimeProvider, RPCBASE_SERVICE_WORKER_MESSAGE_SOURCE, RPCBASE_SERVICE_WORKER_PATH, RPCBASE_SERVICE_WORKER_SCOPE, RootProvider, RouteErrorBoundary, RtsSsrRuntimeProvider, SSR_ERROR_STATE_GLOBAL_KEY, STATIC_RPCBASE_RTS_HYDRATION_DATA_KEY, SsrErrorFallback, apiClient, archiveNotification, clearHydratedRtsQueryData, consumeClientSsrErrorState, consumeHydratedRtsCount, createApiClientError, getApiClientErrorFromUnknown, getFeatureFlag, getNotificationSettings, hydrateRtsFromWindow, initApiClient, initWithRoutes, isApiClientError, isApiErrorResponse, listNotifications, markAllNotificationsRead, markNotificationRead, markNotificationsReadByUrl, peekClientSsrErrorState, peekHydratedRtsCount, peekHydratedRtsQueryData, peekHydratedRtsQueryPageInfo, peekHydratedRtsQueryTotalCount, registerRpcbaseServiceWorker, reportClientException, runNotificationDigest, scheduleRpcbaseServiceWorkerRegistration, sendRpcbaseServiceWorkerMessage, serializeSsrErrorState, setClientExceptionReporter, subscribeRpcbaseServiceWorkerMessages, toast, updateNotificationSettings, useMediaQuery, useNotificationsRealtime, useThrottledMeasure };
3347
3444
 
3348
3445
  //# sourceMappingURL=index.js.map