@intrig/next 1.0.7 → 1.0.11

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 (59) hide show
  1. package/eslint.config.cjs +19 -0
  2. package/jest.config.ts +10 -0
  3. package/package.json +3 -6
  4. package/project.json +20 -0
  5. package/src/extra/{index.d.ts → index.ts} +2 -2
  6. package/src/extra/useAsNetworkState.ts +53 -0
  7. package/src/extra/{useAsPromise.d.ts → useAsPromise.ts} +58 -7
  8. package/src/extra/useLocalReducer.ts +61 -0
  9. package/src/extra/{useResolvedCachedValue.d.ts → useResolvedCachedValue.ts} +39 -7
  10. package/src/extra/{useResolvedValue.d.ts → useResolvedValue.ts} +39 -7
  11. package/src/extra.ts +190 -0
  12. package/src/{index.d.ts → index.ts} +1 -1
  13. package/src/intrig-context.ts +64 -0
  14. package/src/intrig-layout.tsx +18 -0
  15. package/src/intrig-middleware.spec.ts +9 -0
  16. package/src/intrig-middleware.ts +31 -0
  17. package/src/intrig-provider.tsx +454 -0
  18. package/src/logger.ts +13 -0
  19. package/src/media-type-utils.ts +184 -0
  20. package/src/{network-state.d.ts → network-state.tsx} +174 -92
  21. package/tsconfig.json +28 -0
  22. package/tsconfig.lib.json +10 -0
  23. package/tsconfig.spec.json +14 -0
  24. package/src/extra/index.js +0 -5
  25. package/src/extra/index.js.map +0 -1
  26. package/src/extra/useAsNetworkState.d.ts +0 -13
  27. package/src/extra/useAsNetworkState.js +0 -41
  28. package/src/extra/useAsNetworkState.js.map +0 -1
  29. package/src/extra/useAsPromise.js +0 -30
  30. package/src/extra/useAsPromise.js.map +0 -1
  31. package/src/extra/useLocalReducer.d.ts +0 -6
  32. package/src/extra/useLocalReducer.js +0 -50
  33. package/src/extra/useLocalReducer.js.map +0 -1
  34. package/src/extra/useResolvedCachedValue.js +0 -15
  35. package/src/extra/useResolvedCachedValue.js.map +0 -1
  36. package/src/extra/useResolvedValue.js +0 -17
  37. package/src/extra/useResolvedValue.js.map +0 -1
  38. package/src/extra.d.ts +0 -52
  39. package/src/extra.js +0 -92
  40. package/src/extra.js.map +0 -1
  41. package/src/index.js +0 -4
  42. package/src/index.js.map +0 -1
  43. package/src/intrig-context.d.ts +0 -42
  44. package/src/intrig-context.js +0 -21
  45. package/src/intrig-context.js.map +0 -1
  46. package/src/intrig-middleware.d.ts +0 -2
  47. package/src/intrig-middleware.js +0 -24
  48. package/src/intrig-middleware.js.map +0 -1
  49. package/src/intrig-provider.d.ts +0 -102
  50. package/src/intrig-provider.js +0 -296
  51. package/src/intrig-provider.js.map +0 -1
  52. package/src/logger.d.ts +0 -7
  53. package/src/logger.js +0 -11
  54. package/src/logger.js.map +0 -1
  55. package/src/media-type-utils.d.ts +0 -4
  56. package/src/media-type-utils.js +0 -121
  57. package/src/media-type-utils.js.map +0 -1
  58. package/src/network-state.js +0 -185
  59. package/src/network-state.js.map +0 -1
@@ -1,3 +1,3 @@
1
1
  export * from './intrig-provider';
2
2
  export * from './network-state';
3
- export * from './extra/index';
3
+ export * from './extra/index'
@@ -0,0 +1,64 @@
1
+ "use server"
2
+ import { NetworkAction, NetworkState } from '@intrig/next/network-state';
3
+ import { AxiosProgressEvent } from 'axios';
4
+ import { ZodSchema } from 'zod';
5
+ import { createContext, useContext } from 'react';
6
+ import { DefaultConfigs } from '@intrig/next/intrig-provider';
7
+
8
+ type GlobalState = Record<string, NetworkState>;
9
+
10
+ interface RequestType<T = any> {
11
+ method: 'get' | 'post' | 'put' | 'delete';
12
+ url: string;
13
+ headers?: Record<string, string>;
14
+ params?: Record<string, any>;
15
+ data?: any; // This allows transformations, while retaining flexibility.
16
+ originalData?: T; // Keeps track of the original data type.
17
+ onUploadProgress?: (event: AxiosProgressEvent) => void;
18
+ onDownloadProgress?: (event: AxiosProgressEvent) => void;
19
+ signal?: AbortSignal;
20
+ key: string;
21
+ }
22
+
23
+ /**
24
+ * Defines the ContextType interface for managing global state, dispatching actions,
25
+ * and holding a collection of Axios instances.
26
+ *
27
+ * @interface ContextType
28
+ * @property {GlobalState} state - The global state of the application.
29
+ * @property {React.Dispatch<NetworkAction<unknown>>} dispatch - The dispatch function to send network actions.
30
+ * @property {Record<string, AxiosInstance>} axios - A record of Axios instances for making HTTP requests.
31
+ */
32
+ export interface ContextType {
33
+ state: GlobalState;
34
+ filteredState: GlobalState;
35
+ dispatch: React.Dispatch<NetworkAction<unknown, unknown>>;
36
+ configs: DefaultConfigs;
37
+ execute: <T, E = unknown>(request: RequestType, dispatch: (state: NetworkState<T, E>) => void, schema: ZodSchema<T> | undefined, errorSchema: ZodSchema<E> | undefined) => Promise<void>;
38
+ }
39
+
40
+ /**
41
+ * Context object created using `createContext` function. Provides a way to share state, dispatch functions,
42
+ * and axios instance across components without having to pass props down manually at every level.
43
+ *
44
+ * @type {ContextType}
45
+ */
46
+ let Context = createContext<ContextType>({
47
+ state: {},
48
+ filteredState: {},
49
+ dispatch() {},
50
+ configs: {},
51
+ async execute() {
52
+
53
+ }
54
+ });
55
+
56
+ export function useIntrigContext() {
57
+ return useContext(Context);
58
+ }
59
+
60
+ export {
61
+ Context,
62
+ GlobalState,
63
+ RequestType,
64
+ }
@@ -0,0 +1,18 @@
1
+ "use server"
2
+
3
+ import { headers } from 'next/headers';
4
+ import { DefaultConfigs, IntrigProvider } from './intrig-provider';
5
+
6
+ export default async function IntrigLayout({children, configs}: { children: React.ReactNode, configs?: DefaultConfigs}) {
7
+
8
+ let headersData = await headers();
9
+ let hydratedResponsesStr = headersData.get('INTRIG_HYDRATED');
10
+ let hydratedResponses = hydratedResponsesStr ? JSON.parse(hydratedResponsesStr) : {}
11
+ headersData.delete('INTRIG_HYDRATED');
12
+
13
+ return <>
14
+ <IntrigProvider configs={configs} initState={hydratedResponses}>
15
+ {children}
16
+ </IntrigProvider>
17
+ </>
18
+ }
@@ -0,0 +1,9 @@
1
+ import { extractPathVariables } from './intrig-middleware';
2
+
3
+ describe('intrig-middleware', () => {
4
+ it('should extract params', () => {
5
+ let variables = extractPathVariables('/api/v1/database/{dbId}/table/{tableId}', '/api/v1/database/dap/table/users');
6
+
7
+ console.log(variables);
8
+ })
9
+ })
@@ -0,0 +1,31 @@
1
+ "use server"
2
+
3
+ import axios from 'axios';
4
+ //@ts-ignore
5
+ let insightHook = await import('intrig-hook');
6
+ import {headers as requestHeaders} from 'next/headers'
7
+
8
+ export async function getAxiosInstance(key: string) {
9
+ const baseURL = process.env[`${key.toUpperCase()}_API_URL`];
10
+ if (!baseURL) {
11
+ throw new Error(
12
+ `Environment variable ${key.toUpperCase()}_API_URL is not defined.`
13
+ );
14
+ }
15
+
16
+ const axiosInstance = axios.create({ baseURL });
17
+
18
+ if (insightHook?.requestInterceptor) {
19
+ axiosInstance.interceptors.request.use(insightHook.requestInterceptor);
20
+ }
21
+
22
+ return axiosInstance;
23
+ }
24
+
25
+ export async function addResponseToHydrate(key: string, responseData: any) {
26
+ let _headers = await requestHeaders();
27
+ let intrigHydrated = _headers.get('INTRIG_HYDRATED');
28
+ let ob = intrigHydrated ? JSON.parse(intrigHydrated) : {};
29
+ ob[key] = responseData;
30
+ _headers.set('INTRIG_HYDRATED', JSON.stringify(ob));
31
+ }
@@ -0,0 +1,454 @@
1
+ "use client"
2
+ import {
3
+ createContext,
4
+ PropsWithChildren,
5
+ useCallback,
6
+ useContext,
7
+ useMemo,
8
+ useReducer,
9
+ useState,
10
+ } from 'react';
11
+ import {
12
+ error,
13
+ ErrorState,
14
+ ErrorWithContext,
15
+ init, IntrigHook,
16
+ isError,
17
+ isPending,
18
+ NetworkAction,
19
+ NetworkState,
20
+ pending,
21
+ Progress,
22
+ success
23
+ } from './network-state';
24
+ import axios, {
25
+ Axios,
26
+ AxiosProgressEvent,
27
+ AxiosRequestConfig,
28
+ CreateAxiosDefaults,
29
+ isAxiosError,
30
+ } from 'axios';
31
+ import { ZodSchema } from 'zod';
32
+ import logger from './logger'
33
+
34
+ import {Context, RequestType, GlobalState} from './intrig-context';
35
+
36
+ /**
37
+ * Handles state updates for network requests based on the provided action.
38
+ *
39
+ * @param {GlobalState} state - The current state of the application.
40
+ * @param {NetworkAction<unknown>} action - The action containing source, operation, key, and state.
41
+ * @return {GlobalState} - The updated state after applying the action.
42
+ */
43
+ function requestReducer(
44
+ state: GlobalState,
45
+ action: NetworkAction<unknown, unknown>
46
+ ): GlobalState {
47
+ return {
48
+ ...state,
49
+ [`${action.source}:${action.operation}:${action.key}`]: action.state,
50
+ };
51
+ }
52
+
53
+ export interface DefaultConfigs extends CreateAxiosDefaults {
54
+ debounceDelay?: number;
55
+ }
56
+
57
+ export interface IntrigProviderProps {
58
+ configs?: DefaultConfigs;
59
+ children: React.ReactNode;
60
+ initState?: GlobalState;
61
+ }
62
+
63
+ /**
64
+ * IntrigProvider is a context provider component that sets up global state management
65
+ * and provides Axios instances for API requests.
66
+ *
67
+ * @param {Object} props - The properties object.
68
+ * @param {React.ReactNode} props.children - The child components to be wrapped by the provider.
69
+ * @param {Object} [props.configs={}] - Configuration object for Axios instances.
70
+ * @param {Object} [props.configs.defaults={}] - Default configuration for Axios.
71
+ * @param {Object} [props.configs.petstore={}] - Configuration specific to the petstore API.
72
+ * @return {JSX.Element} A context provider component that wraps the provided children.
73
+ */
74
+ export function IntrigProvider({
75
+ children,
76
+ configs = {},
77
+ initState = {},
78
+ }: IntrigProviderProps) {
79
+ const [state, dispatch] = useReducer(requestReducer, initState);
80
+
81
+ const axiosInstance: Axios = useMemo(() => {
82
+ return axios.create({
83
+ ...(configs ?? {}),
84
+ });
85
+ }, [configs]);
86
+
87
+ const contextValue = useMemo(() => {
88
+ async function execute<T, E = unknown>(request: RequestType, dispatch: (state: NetworkState<T, E>) => void, schema: ZodSchema<T> | undefined, errorSchema: ZodSchema<E> | undefined) {
89
+ try {
90
+ dispatch(pending());
91
+ let response = await axiosInstance.request(request);
92
+
93
+ if (response.status >= 200 && response.status < 300) {
94
+ if (schema) {
95
+ let data = schema.safeParse(response.data);
96
+ if (!data.success) {
97
+ dispatch(
98
+ error(data.error.issues, response.status, request)
99
+ );
100
+ return;
101
+ }
102
+ dispatch(success(data.data));
103
+ } else {
104
+ dispatch(success(response.data));
105
+ }
106
+ } else {
107
+ let { data, error: validationError } = errorSchema?.safeParse(response.data ?? {}) ?? {};
108
+ //todo: handle error validation error.
109
+ dispatch(
110
+ error(data ?? response.data ?? response.statusText, response.status)
111
+ );
112
+ }
113
+ } catch (e: any) {
114
+ if (isAxiosError(e)) {
115
+ let { data, error: validationError } = errorSchema?.safeParse(e.response?.data ?? {}) ?? {};
116
+ dispatch(error(data ?? e.response?.data, e.response?.status, request));
117
+ } else {
118
+ dispatch(error(e));
119
+ }
120
+ }
121
+ }
122
+
123
+ return {
124
+ state,
125
+ dispatch,
126
+ filteredState: state,
127
+ configs,
128
+ execute,
129
+ };
130
+ }, [state, axiosInstance]);
131
+
132
+ return <Context.Provider value={contextValue}>{children}</Context.Provider>;
133
+ }
134
+
135
+ export interface StubType<P, B, T> {
136
+ <P, B, T>(hook: IntrigHook<P, B, T>, fn: (params: P, body: B, dispatch: (state: NetworkState<T>) => void) => Promise<void>): void
137
+ }
138
+
139
+ export type WithStubSupport<T> = T & {
140
+ stubs?: (stub: StubType<any, any, any>) => void;
141
+ }
142
+
143
+ export interface IntrigProviderStubProps {
144
+ configs?: DefaultConfigs;
145
+ stubs?: (stub: StubType<any, any, any>) => void;
146
+ children: React.ReactNode;
147
+ }
148
+
149
+ export function IntrigProviderStub({ children, configs = {}, stubs = () => {} }: IntrigProviderStubProps) {
150
+ const [state, dispatch] = useReducer(requestReducer, {} as GlobalState);
151
+
152
+ const collectedStubs = useMemo(() => {
153
+ let fns: Record<string, (params: any, body: any, dispatch: (state: NetworkState<any>) => void) => Promise<void>> = {};
154
+ function stub<P, B, T>(hook: IntrigHook<P, B, T>, fn: (params: P, body: B, dispatch: (state: NetworkState<T>) => void) => Promise<void>) {
155
+ fns[hook.key] = fn;
156
+ }
157
+ stubs(stub);
158
+ return fns
159
+ }, [stubs]);
160
+
161
+ const contextValue = useMemo(() => {
162
+
163
+ async function execute<T>(request: RequestType, dispatch: (state: NetworkState<T>) => void, schema: ZodSchema<T> | undefined) {
164
+ let stub = collectedStubs[request.key];
165
+
166
+ if (!!stub) {
167
+ try {
168
+ await stub(request.params, request.data, dispatch);
169
+ } catch (e) {
170
+ dispatch(error(e));
171
+ }
172
+ } else {
173
+ dispatch(init())
174
+ }
175
+ }
176
+
177
+ return {
178
+ state,
179
+ dispatch,
180
+ filteredState: state,
181
+ configs,
182
+ execute,
183
+ };
184
+ }, [state, dispatch, configs, collectedStubs]);
185
+
186
+ return <Context.Provider value={contextValue}>
187
+ {children}
188
+ </Context.Provider>
189
+ }
190
+
191
+ export interface StatusTrapProps {
192
+ type: 'pending' | 'error' | 'pending + error';
193
+ propagate?: boolean;
194
+ }
195
+
196
+ /**
197
+ * StatusTrap component is used to track and manage network request states.
198
+ *
199
+ * @param {Object} props - The properties object.
200
+ * @param {React.ReactNode} props.children - The child elements to be rendered.
201
+ * @param {string} props.type - The type of network state to handle ("error", "pending", "pending + error").
202
+ * @param {boolean} [props.propagate=true] - Whether to propagate the event to the parent context.
203
+ * @return {React.ReactElement} The context provider component with filtered state and custom dispatch.
204
+ */
205
+ export function StatusTrap({
206
+ children,
207
+ type,
208
+ propagate = true,
209
+ }: PropsWithChildren<StatusTrapProps>) {
210
+ const ctx = useContext(Context);
211
+
212
+ const [requests, setRequests] = useState<string[]>([]);
213
+
214
+ const shouldHandleEvent = useCallback(
215
+ (state: NetworkState) => {
216
+ switch (type) {
217
+ case 'error':
218
+ return isError(state);
219
+ case 'pending':
220
+ return isPending(state);
221
+ case 'pending + error':
222
+ return isPending(state) || isError(state);
223
+ default:
224
+ return false;
225
+ }
226
+ },
227
+ [type]
228
+ );
229
+
230
+ const dispatch = useCallback(
231
+ (event: NetworkAction<any, any>) => {
232
+ if (!event.handled) {
233
+ if (shouldHandleEvent(event.state)) {
234
+ setRequests((prev) => [...prev, event.key]);
235
+ if (!propagate) {
236
+ ctx.dispatch({
237
+ ...event,
238
+ handled: true,
239
+ });
240
+ return;
241
+ }
242
+ } else {
243
+ setRequests((prev) => prev.filter((k) => k !== event.key));
244
+ }
245
+ }
246
+ ctx.dispatch(event);
247
+ },
248
+ [ctx, propagate, shouldHandleEvent]
249
+ );
250
+
251
+ const filteredState = useMemo(() => {
252
+ return Object.fromEntries(
253
+ Object.entries(ctx.state).filter(([key]) => requests.includes(key))
254
+ );
255
+ }, [ctx.state, requests]);
256
+
257
+ return (
258
+ <Context.Provider
259
+ value={{
260
+ ...ctx,
261
+ dispatch,
262
+ filteredState,
263
+ }}
264
+ >
265
+ {children}
266
+ </Context.Provider>
267
+ );
268
+ }
269
+
270
+ export interface NetworkStateProps<T, E = unknown> {
271
+ key: string;
272
+ operation: string;
273
+ source: string;
274
+ schema?: ZodSchema<T>;
275
+ errorSchema?: ZodSchema<E>;
276
+ debounceDelay?: number;
277
+ }
278
+
279
+ /**
280
+ * useNetworkState is a custom hook that manages the network state within the specified context.
281
+ * It handles making network requests, dispatching appropriate states based on the request lifecycle,
282
+ * and allows aborting ongoing requests.
283
+ *
284
+ * @param {Object} params - The parameters required to configure and use the network state.
285
+ * @param {string} params.key - A unique identifier for the network request.
286
+ * @param {string} params.operation - The operation type related to the request.
287
+ * @param {string} params.source - The source or endpoint for the network request.
288
+ * @param {Object} params.schema - The schema used for validating the response data.
289
+ * @param {number} [params.debounceDelay] - The debounce delay for executing the network request.
290
+ *
291
+ * @return {[NetworkState<T>, (request: AxiosRequestConfig) => void, () => void]}
292
+ * Returns a state object representing the current network state,
293
+ * a function to execute the network request, and a function to clear the request.
294
+ */
295
+ export function useNetworkState<T, E = unknown>({
296
+ key,
297
+ operation,
298
+ source,
299
+ schema,
300
+ errorSchema,
301
+ debounceDelay: requestDebounceDelay,
302
+ }: NetworkStateProps<T>): [
303
+ NetworkState<T, E>,
304
+ (request: RequestType) => void,
305
+ clear: () => void,
306
+ (state: NetworkState<T, E>) => void
307
+ ] {
308
+ const context = useContext(Context);
309
+
310
+ const [abortController, setAbortController] = useState<AbortController>();
311
+
312
+ const networkState = useMemo(() => {
313
+ logger.info(`Updating status ${key} ${operation} ${source}`);
314
+ logger.debug(`⇦`, context.state?.[`${source}:${operation}:${key}`])
315
+ return (
316
+ (context.state?.[`${source}:${operation}:${key}`] as NetworkState<T>) ??
317
+ init()
318
+ );
319
+ }, [context.state?.[`${source}:${operation}:${key}`]]);
320
+
321
+ const dispatch = useCallback(
322
+ (state: NetworkState<T>) => {
323
+ context.dispatch({ key, operation, source, state });
324
+ },
325
+ [key, operation, source, context.dispatch]
326
+ );
327
+
328
+ const debounceDelay = useMemo(() => {
329
+ return requestDebounceDelay ?? context.configs?.debounceDelay ?? 0;
330
+ }, [context.configs, requestDebounceDelay]);
331
+
332
+ const execute = useCallback(
333
+ async (request: RequestType) => {
334
+ logger.info(`Executing request ${key} ${operation} ${source}`);
335
+ logger.debug(`⇨`, request)
336
+
337
+ let abortController = new AbortController();
338
+ setAbortController(abortController);
339
+
340
+ let requestConfig: RequestType = {
341
+ ...request,
342
+ onUploadProgress(event: AxiosProgressEvent) {
343
+ dispatch(
344
+ pending({
345
+ type: 'upload',
346
+ loaded: event.loaded,
347
+ total: event.total,
348
+ })
349
+ );
350
+ request.onUploadProgress?.(event);
351
+ },
352
+ onDownloadProgress(event: AxiosProgressEvent) {
353
+ dispatch(
354
+ pending({
355
+ type: 'download',
356
+ loaded: event.loaded,
357
+ total: event.total,
358
+ })
359
+ );
360
+ request.onDownloadProgress?.(event);
361
+ },
362
+ signal: abortController.signal,
363
+ };
364
+
365
+ await context.execute(requestConfig, dispatch, schema, errorSchema);
366
+ },
367
+ [networkState, context.dispatch, axios]
368
+ );
369
+
370
+ const deboundedExecute = useMemo(
371
+ () => debounce(execute, debounceDelay ?? 0),
372
+ [execute]
373
+ );
374
+
375
+ const clear = useCallback(() => {
376
+ logger.info(`Clearing request ${key} ${operation} ${source}`);
377
+ dispatch(init());
378
+ setAbortController((abortController) => {
379
+ logger.info(`Aborting request ${key} ${operation} ${source}`);
380
+ abortController?.abort();
381
+ return undefined;
382
+ });
383
+ }, [dispatch, abortController]);
384
+
385
+ return [networkState, deboundedExecute, clear, dispatch];
386
+ }
387
+
388
+ function debounce<T extends (...args: any[]) => void>(func: T, delay: number) {
389
+ let timeoutId: any;
390
+
391
+ return (...args: Parameters<T>) => {
392
+ if (timeoutId) {
393
+ clearTimeout(timeoutId);
394
+ }
395
+ timeoutId = setTimeout(() => {
396
+ func(...args);
397
+ }, delay);
398
+ };
399
+ }
400
+
401
+ /**
402
+ * Handles central error extraction from the provided context.
403
+ * It filters the state to retain error states and maps them to a structured error object with additional context information.
404
+ * @return {Object[]} An array of objects representing the error states with context information such as source, operation, and key.
405
+ */
406
+ export function useCentralError() {
407
+ const ctx = useContext(Context);
408
+
409
+ return useMemo(() => {
410
+ return Object.entries(ctx.filteredState)
411
+ .filter(([, state]) => isError(state))
412
+ .map(([k, state]) => {
413
+ let [source, operation, key] = k.split(':');
414
+ return {
415
+ ...(state as ErrorState<unknown>),
416
+ source,
417
+ operation,
418
+ key,
419
+ } satisfies ErrorWithContext;
420
+ });
421
+ }, [ctx.filteredState]);
422
+ }
423
+
424
+ /**
425
+ * Uses central pending state handling by aggregating pending states from context.
426
+ * It calculates the overall progress of pending states if any, or returns an initial state otherwise.
427
+ *
428
+ * @return {NetworkState} The aggregated network state based on the pending states and their progress.
429
+ */
430
+ export function useCentralPendingState() {
431
+ const ctx = useContext(Context);
432
+
433
+ const result: NetworkState = useMemo(() => {
434
+ let pendingStates = Object.values(ctx.filteredState).filter(isPending);
435
+ if (!pendingStates.length) {
436
+ return init();
437
+ }
438
+
439
+ let progress = pendingStates
440
+ .filter((a) => a.progress)
441
+ .reduce(
442
+ (progress, current) => {
443
+ return {
444
+ total: progress.total + (current.progress?.total ?? 0),
445
+ loaded: progress.loaded + (current.progress?.loaded ?? 0),
446
+ };
447
+ },
448
+ { total: 0, loaded: 0 } satisfies Progress
449
+ );
450
+ return pending(!!progress.total ? progress : undefined);
451
+ }, [ctx.filteredState]);
452
+
453
+ return result;
454
+ }
package/src/logger.ts ADDED
@@ -0,0 +1,13 @@
1
+ import log from 'loglevel';
2
+
3
+ // Set the default logging level (can be overridden via environment variables)
4
+ log.setLevel(process.env.LOG_LEVEL as log.LogLevelDesc || 'info');
5
+
6
+ const logWrapper = {
7
+ info: (msg: string, meta?: object) => meta ? log.info(msg, meta) : log.info(msg),
8
+ warn: (msg: string, meta?: object) => meta ? log.warn(msg, meta) : log.warn(msg),
9
+ error: (msg: string, meta?: object) => meta ? log.error(msg, meta) : log.error(msg),
10
+ debug: (msg: string, meta?: object) => meta ? log.debug(msg, meta) : log.debug(msg),
11
+ };
12
+
13
+ export default logWrapper;