@mongrov/core 0.1.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.
- package/LICENSE +21 -0
- package/README.md +211 -0
- package/dist/context/logging-provider.d.ts +11 -0
- package/dist/context/logging-provider.d.ts.map +1 -0
- package/dist/context/logging-provider.js +43 -0
- package/dist/context/logging-provider.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.d.ts +17 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +159 -0
- package/dist/logger.js.map +1 -0
- package/dist/network-state.d.ts +13 -0
- package/dist/network-state.d.ts.map +1 -0
- package/dist/network-state.js +85 -0
- package/dist/network-state.js.map +1 -0
- package/dist/offline-queue.d.ts +30 -0
- package/dist/offline-queue.d.ts.map +1 -0
- package/dist/offline-queue.js +121 -0
- package/dist/offline-queue.js.map +1 -0
- package/dist/transports/file.d.ts +19 -0
- package/dist/transports/file.d.ts.map +1 -0
- package/dist/transports/file.js +136 -0
- package/dist/transports/file.js.map +1 -0
- package/dist/transports/index.d.ts +4 -0
- package/dist/transports/index.d.ts.map +1 -0
- package/dist/transports/index.js +4 -0
- package/dist/transports/index.js.map +1 -0
- package/dist/transports/ring-buffer.d.ts +15 -0
- package/dist/transports/ring-buffer.d.ts.map +1 -0
- package/dist/transports/ring-buffer.js +66 -0
- package/dist/transports/ring-buffer.js.map +1 -0
- package/dist/transports/webhook.d.ts +18 -0
- package/dist/transports/webhook.d.ts.map +1 -0
- package/dist/transports/webhook.js +88 -0
- package/dist/transports/webhook.js.map +1 -0
- package/dist/types.d.ts +59 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +73 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Mongrov
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
# @mongrov/core
|
|
2
|
+
|
|
3
|
+
Structured logging framework for React Native / Expo. Zero UI, zero Sentry, zero vendor opinions.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @mongrov/core
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
### Peer Dependencies
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npx expo install expo-file-system expo-network react-native-mmkv
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
| Dependency | Why |
|
|
18
|
+
|---|---|
|
|
19
|
+
| `expo-file-system` | File transport writes rolling daily logs |
|
|
20
|
+
| `expo-network` | Offline queue checks connectivity before flushing |
|
|
21
|
+
| `react-native-mmkv` | Offline queue persistence (fast, synchronous) |
|
|
22
|
+
|
|
23
|
+
## Quick Start
|
|
24
|
+
|
|
25
|
+
```typescript
|
|
26
|
+
import { createLogger } from '@mongrov/core'
|
|
27
|
+
|
|
28
|
+
const logger = createLogger({
|
|
29
|
+
appVersion: '1.0.0',
|
|
30
|
+
ringBuffer: true,
|
|
31
|
+
file: true,
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
logger.info('App started')
|
|
35
|
+
logger.error('Something went wrong', { code: 500 })
|
|
36
|
+
|
|
37
|
+
// Retrieve logs
|
|
38
|
+
const logs = logger.getLogs({ level: 'error' })
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## React Integration
|
|
42
|
+
|
|
43
|
+
```typescript
|
|
44
|
+
import { LoggingProvider, useLogger } from '@mongrov/core'
|
|
45
|
+
|
|
46
|
+
// In your root layout
|
|
47
|
+
export default function RootLayout() {
|
|
48
|
+
return (
|
|
49
|
+
<LoggingProvider config={{ appVersion: '1.0.0', ringBuffer: true, file: true }}>
|
|
50
|
+
<Stack />
|
|
51
|
+
</LoggingProvider>
|
|
52
|
+
)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// In any component
|
|
56
|
+
function MyScreen() {
|
|
57
|
+
const logger = useLogger()
|
|
58
|
+
logger.info('Screen rendered')
|
|
59
|
+
return <View />
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Configuration
|
|
64
|
+
|
|
65
|
+
```typescript
|
|
66
|
+
interface LoggerConfig {
|
|
67
|
+
// Minimum level to capture (default: 'debug' in dev, 'info' in prod)
|
|
68
|
+
minLevel?: 'debug' | 'info' | 'warn' | 'error'
|
|
69
|
+
|
|
70
|
+
// Built-in transports
|
|
71
|
+
ringBuffer?: RingBufferConfig | boolean // In-memory circular buffer
|
|
72
|
+
file?: FileConfig | boolean // Rolling daily file storage
|
|
73
|
+
webhook?: WebhookConfig // HTTP POST with batching
|
|
74
|
+
|
|
75
|
+
// Custom transports
|
|
76
|
+
transports?: LogTransport[]
|
|
77
|
+
|
|
78
|
+
// Static context
|
|
79
|
+
appVersion: string
|
|
80
|
+
updateId?: string
|
|
81
|
+
|
|
82
|
+
// Callback hooks
|
|
83
|
+
onError?: (entry: LogEntry) => void
|
|
84
|
+
onException?: (error: Error, context?: Record<string, unknown>) => void
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Ring Buffer
|
|
89
|
+
|
|
90
|
+
In-memory circular buffer. Default size: 1000 entries. No persistence.
|
|
91
|
+
|
|
92
|
+
```typescript
|
|
93
|
+
{ ringBuffer: true } // defaults
|
|
94
|
+
{ ringBuffer: { maxSize: 5000 } } // custom size
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### File Transport
|
|
98
|
+
|
|
99
|
+
Rolling daily log files. JSONL format.
|
|
100
|
+
|
|
101
|
+
```typescript
|
|
102
|
+
{ file: true } // defaults
|
|
103
|
+
{ file: { maxSizeMB: 10, retentionDays: 14 } }
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### Webhook Transport
|
|
107
|
+
|
|
108
|
+
Generic HTTP POST with batching and offline queue.
|
|
109
|
+
|
|
110
|
+
```typescript
|
|
111
|
+
{
|
|
112
|
+
webhook: {
|
|
113
|
+
url: 'https://your-api.com/logs',
|
|
114
|
+
headers: { Authorization: 'Bearer token' },
|
|
115
|
+
batchSize: 10,
|
|
116
|
+
batchIntervalMs: 5000,
|
|
117
|
+
formatPayload: (entries) => ({ text: entries.map(e => e.message).join('\n') }),
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## Custom Transports
|
|
123
|
+
|
|
124
|
+
Implement the `LogTransport` interface:
|
|
125
|
+
|
|
126
|
+
```typescript
|
|
127
|
+
import type { LogTransport, LogEntry } from '@mongrov/core'
|
|
128
|
+
|
|
129
|
+
const myTransport: LogTransport = {
|
|
130
|
+
name: 'my-transport',
|
|
131
|
+
async send(entries: LogEntry[]) {
|
|
132
|
+
// your logic here
|
|
133
|
+
},
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const logger = createLogger({
|
|
137
|
+
appVersion: '1.0.0',
|
|
138
|
+
transports: [myTransport],
|
|
139
|
+
})
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
## API Reference
|
|
143
|
+
|
|
144
|
+
### Logger Methods
|
|
145
|
+
|
|
146
|
+
| Method | Description |
|
|
147
|
+
|---|---|
|
|
148
|
+
| `debug(message, data?)` | Log debug message |
|
|
149
|
+
| `info(message, data?)` | Log info message |
|
|
150
|
+
| `warn(message, data?)` | Log warning message |
|
|
151
|
+
| `error(message, data?)` | Log error message |
|
|
152
|
+
| `captureException(error, context?)` | Log error + call `onException` callback |
|
|
153
|
+
| `setUser(userId)` | Set user ID in context |
|
|
154
|
+
| `setScreen(screenName)` | Set current screen in context |
|
|
155
|
+
| `setContext(key, value)` | Set custom context key |
|
|
156
|
+
| `getLogs(filter?)` | Get logs from ring buffer |
|
|
157
|
+
| `exportLogs(filter?)` | Export logs as JSON string |
|
|
158
|
+
| `flush()` | Force-push queued webhook entries |
|
|
159
|
+
| `destroy()` | Flush pending + cleanup listeners |
|
|
160
|
+
|
|
161
|
+
### LogFilter
|
|
162
|
+
|
|
163
|
+
```typescript
|
|
164
|
+
{
|
|
165
|
+
level?: 'debug' | 'info' | 'warn' | 'error' // minimum level
|
|
166
|
+
since?: Date // entries after this time
|
|
167
|
+
search?: string // substring match on message
|
|
168
|
+
limit?: number // max entries to return
|
|
169
|
+
}
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
## Usage with Sentry
|
|
173
|
+
|
|
174
|
+
```typescript
|
|
175
|
+
import * as Sentry from '@sentry/react-native'
|
|
176
|
+
|
|
177
|
+
const logger = createLogger({
|
|
178
|
+
appVersion: '1.0.0',
|
|
179
|
+
ringBuffer: true,
|
|
180
|
+
onError: (entry) => {
|
|
181
|
+
Sentry.addBreadcrumb({
|
|
182
|
+
message: entry.message,
|
|
183
|
+
level: entry.level,
|
|
184
|
+
data: entry.data,
|
|
185
|
+
})
|
|
186
|
+
},
|
|
187
|
+
onException: (error, context) => {
|
|
188
|
+
Sentry.captureException(error, { extra: context })
|
|
189
|
+
},
|
|
190
|
+
})
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
## Usage with RocketChat
|
|
194
|
+
|
|
195
|
+
```typescript
|
|
196
|
+
const logger = createLogger({
|
|
197
|
+
appVersion: '1.0.0',
|
|
198
|
+
webhook: {
|
|
199
|
+
url: 'https://your-rocketchat.com/hooks/xxx',
|
|
200
|
+
formatPayload: (entries) => ({
|
|
201
|
+
text: entries
|
|
202
|
+
.map((e) => `[${e.level.toUpperCase()}] ${e.message}`)
|
|
203
|
+
.join('\n'),
|
|
204
|
+
}),
|
|
205
|
+
},
|
|
206
|
+
})
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
## License
|
|
210
|
+
|
|
211
|
+
MIT
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { type Logger } from '../logger';
|
|
3
|
+
import type { LoggerConfig } from '../types';
|
|
4
|
+
interface LoggingProviderProps {
|
|
5
|
+
config: LoggerConfig;
|
|
6
|
+
children: React.ReactNode;
|
|
7
|
+
}
|
|
8
|
+
export declare function LoggingProvider({ config, children }: LoggingProviderProps): import("react/jsx-runtime").JSX.Element;
|
|
9
|
+
export declare function useLogger(): Logger;
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=logging-provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logging-provider.d.ts","sourceRoot":"","sources":["../../src/context/logging-provider.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAgE,MAAM,OAAO,CAAA;AACpF,OAAO,EAAgB,KAAK,MAAM,EAAE,MAAM,WAAW,CAAA;AACrD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AAI5C,UAAU,oBAAoB;IAC5B,MAAM,EAAE,YAAY,CAAA;IACpB,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;CAC1B;AAED,wBAAgB,eAAe,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,oBAAoB,2CAqCzE;AAED,wBAAgB,SAAS,IAAI,MAAM,CAMlC"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { createContext, useContext, useEffect, useMemo, useRef } from 'react';
|
|
3
|
+
import { createLogger } from '../logger';
|
|
4
|
+
const LoggerContext = createContext(null);
|
|
5
|
+
export function LoggingProvider({ config, children }) {
|
|
6
|
+
// Stable ref to config so the effect doesn't re-run on every render
|
|
7
|
+
const configRef = useRef(config);
|
|
8
|
+
configRef.current = config;
|
|
9
|
+
// Create logger once, re-create if destroyed by Strict Mode remount
|
|
10
|
+
const logger = useMemo(() => createLogger(configRef.current), []);
|
|
11
|
+
useEffect(() => {
|
|
12
|
+
// Try to track screen via expo-router
|
|
13
|
+
let unsubscribe;
|
|
14
|
+
try {
|
|
15
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
16
|
+
const { router } = require('expo-router');
|
|
17
|
+
if (router && typeof router.subscribe === 'function') {
|
|
18
|
+
unsubscribe = router.subscribe((state) => {
|
|
19
|
+
if (state?.routes?.length) {
|
|
20
|
+
const currentRoute = state.routes[state.routes.length - 1];
|
|
21
|
+
logger.setScreen(currentRoute.name);
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
// expo-router not available — screen tracking disabled
|
|
28
|
+
}
|
|
29
|
+
return () => {
|
|
30
|
+
unsubscribe?.();
|
|
31
|
+
logger.destroy();
|
|
32
|
+
};
|
|
33
|
+
}, [logger]);
|
|
34
|
+
return (_jsx(LoggerContext.Provider, { value: logger, children: children }));
|
|
35
|
+
}
|
|
36
|
+
export function useLogger() {
|
|
37
|
+
const logger = useContext(LoggerContext);
|
|
38
|
+
if (!logger) {
|
|
39
|
+
throw new Error('useLogger must be used within a LoggingProvider');
|
|
40
|
+
}
|
|
41
|
+
return logger;
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=logging-provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logging-provider.js","sourceRoot":"","sources":["../../src/context/logging-provider.tsx"],"names":[],"mappings":";AAAA,OAAc,EAAE,aAAa,EAAE,UAAU,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,OAAO,CAAA;AACpF,OAAO,EAAE,YAAY,EAAe,MAAM,WAAW,CAAA;AAGrD,MAAM,aAAa,GAAG,aAAa,CAAgB,IAAI,CAAC,CAAA;AAOxD,MAAM,UAAU,eAAe,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAwB;IACxE,oEAAoE;IACpE,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC,CAAA;IAChC,SAAS,CAAC,OAAO,GAAG,MAAM,CAAA;IAE1B,oEAAoE;IACpE,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,YAAY,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,EAAE,CAAC,CAAA;IAEjE,SAAS,CAAC,GAAG,EAAE;QACb,sCAAsC;QACtC,IAAI,WAAqC,CAAA;QACzC,IAAI,CAAC;YACH,8DAA8D;YAC9D,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,aAAa,CAAC,CAAA;YACzC,IAAI,MAAM,IAAI,OAAO,MAAM,CAAC,SAAS,KAAK,UAAU,EAAE,CAAC;gBACrD,WAAW,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC,KAA2C,EAAE,EAAE;oBAC7E,IAAI,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;wBAC1B,MAAM,YAAY,GAAG,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAA;wBAC1D,MAAM,CAAC,SAAS,CAAC,YAAY,CAAC,IAAI,CAAC,CAAA;oBACrC,CAAC;gBACH,CAAC,CAAC,CAAA;YACJ,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,uDAAuD;QACzD,CAAC;QAED,OAAO,GAAG,EAAE;YACV,WAAW,EAAE,EAAE,CAAA;YACf,MAAM,CAAC,OAAO,EAAE,CAAA;QAClB,CAAC,CAAA;IACH,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAA;IAEZ,OAAO,CACL,KAAC,aAAa,CAAC,QAAQ,IAAC,KAAK,EAAE,MAAM,YAClC,QAAQ,GACc,CAC1B,CAAA;AACH,CAAC;AAED,MAAM,UAAU,SAAS;IACvB,MAAM,MAAM,GAAG,UAAU,CAAC,aAAa,CAAC,CAAA;IACxC,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAA;IACpE,CAAC;IACD,OAAO,MAAM,CAAA;AACf,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { createLogger } from './logger';
|
|
2
|
+
export type { Logger } from './logger';
|
|
3
|
+
export type { LogLevel, LogEntry, LoggerConfig, LogFilter, LogTransport, WebhookConfig, FileConfig, RingBufferConfig, LogContext, } from './types';
|
|
4
|
+
export { RingBufferTransport } from './transports/ring-buffer';
|
|
5
|
+
export { FileTransport } from './transports/file';
|
|
6
|
+
export { WebhookTransport } from './transports/webhook';
|
|
7
|
+
export { LoggingProvider, useLogger } from './context/logging-provider';
|
|
8
|
+
export { useNetworkState, getNetworkState, addNetworkStateListener } from './network-state';
|
|
9
|
+
export { OfflineQueue } from './offline-queue';
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AACvC,YAAY,EAAE,MAAM,EAAE,MAAM,UAAU,CAAA;AAGtC,YAAY,EACV,QAAQ,EACR,QAAQ,EACR,YAAY,EACZ,SAAS,EACT,YAAY,EACZ,aAAa,EACb,UAAU,EACV,gBAAgB,EAChB,UAAU,GACX,MAAM,SAAS,CAAA;AAGhB,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAA;AAC9D,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AAGvD,OAAO,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAA;AAGvE,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAA;AAG3F,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// Logger
|
|
2
|
+
export { createLogger } from './logger';
|
|
3
|
+
// Transports (for custom composition)
|
|
4
|
+
export { RingBufferTransport } from './transports/ring-buffer';
|
|
5
|
+
export { FileTransport } from './transports/file';
|
|
6
|
+
export { WebhookTransport } from './transports/webhook';
|
|
7
|
+
// Context
|
|
8
|
+
export { LoggingProvider, useLogger } from './context/logging-provider';
|
|
9
|
+
// Network (used internally, exported for convenience)
|
|
10
|
+
export { useNetworkState, getNetworkState, addNetworkStateListener } from './network-state';
|
|
11
|
+
// Offline queue (exported for advanced usage)
|
|
12
|
+
export { OfflineQueue } from './offline-queue';
|
|
13
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,SAAS;AACT,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AAgBvC,sCAAsC;AACtC,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAA;AAC9D,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AAEvD,UAAU;AACV,OAAO,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAA;AAEvE,sDAAsD;AACtD,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAA;AAE3F,8CAA8C;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA"}
|
package/dist/logger.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { LogEntry, LogFilter, LoggerConfig } from './types';
|
|
2
|
+
export interface Logger {
|
|
3
|
+
debug(message: string, data?: Record<string, unknown>): void;
|
|
4
|
+
info(message: string, data?: Record<string, unknown>): void;
|
|
5
|
+
warn(message: string, data?: Record<string, unknown>): void;
|
|
6
|
+
error(message: string, data?: Record<string, unknown>): void;
|
|
7
|
+
captureException(error: Error, context?: Record<string, unknown>): void;
|
|
8
|
+
setUser(userId: string): void;
|
|
9
|
+
setScreen(screenName: string): void;
|
|
10
|
+
setContext(key: string, value: string): void;
|
|
11
|
+
getLogs(filter?: LogFilter): LogEntry[];
|
|
12
|
+
exportLogs(filter?: LogFilter): string;
|
|
13
|
+
flush(): Promise<void>;
|
|
14
|
+
destroy(): Promise<void>;
|
|
15
|
+
}
|
|
16
|
+
export declare function createLogger(config: LoggerConfig): Logger;
|
|
17
|
+
//# sourceMappingURL=logger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,QAAQ,EACR,SAAS,EACT,YAAY,EAKb,MAAM,SAAS,CAAA;AAwChB,MAAM,WAAW,MAAM;IACrB,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAA;IAC5D,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAA;IAC3D,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAA;IAC3D,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAA;IAC5D,gBAAgB,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAA;IAEvE,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IAC7B,SAAS,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IACnC,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IAE5C,OAAO,CAAC,MAAM,CAAC,EAAE,SAAS,GAAG,QAAQ,EAAE,CAAA;IACvC,UAAU,CAAC,MAAM,CAAC,EAAE,SAAS,GAAG,MAAM,CAAA;IAEtC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;IACtB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;CACzB;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,CAkJzD"}
|
package/dist/logger.js
ADDED
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import { RingBufferTransport } from './transports/ring-buffer';
|
|
2
|
+
import { FileTransport } from './transports/file';
|
|
3
|
+
import { WebhookTransport } from './transports/webhook';
|
|
4
|
+
const LEVEL_ORDER = {
|
|
5
|
+
debug: 0,
|
|
6
|
+
info: 1,
|
|
7
|
+
warn: 2,
|
|
8
|
+
error: 3,
|
|
9
|
+
};
|
|
10
|
+
let counter = 0;
|
|
11
|
+
function generateId() {
|
|
12
|
+
return `${Date.now()}-${++counter}`;
|
|
13
|
+
}
|
|
14
|
+
function generateSessionId() {
|
|
15
|
+
return `${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;
|
|
16
|
+
}
|
|
17
|
+
function getPlatform() {
|
|
18
|
+
try {
|
|
19
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
20
|
+
const { Platform } = require('react-native');
|
|
21
|
+
return Platform.OS === 'android' ? 'android' : 'ios';
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return 'ios';
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
function isDev() {
|
|
28
|
+
try {
|
|
29
|
+
// @ts-expect-error __DEV__ is a React Native global
|
|
30
|
+
return typeof __DEV__ !== 'undefined' ? __DEV__ : false;
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
export function createLogger(config) {
|
|
37
|
+
const dev = isDev();
|
|
38
|
+
const minLevel = config.minLevel ?? (dev ? 'debug' : 'info');
|
|
39
|
+
const minLevelNum = LEVEL_ORDER[minLevel];
|
|
40
|
+
const sessionId = generateSessionId();
|
|
41
|
+
const platform = getPlatform();
|
|
42
|
+
// Mutable context
|
|
43
|
+
const ctx = {
|
|
44
|
+
sessionId,
|
|
45
|
+
appVersion: config.appVersion,
|
|
46
|
+
updateId: config.updateId,
|
|
47
|
+
platform,
|
|
48
|
+
};
|
|
49
|
+
const extraContext = {};
|
|
50
|
+
// Initialize transports
|
|
51
|
+
const transports = [];
|
|
52
|
+
let ringBuffer = null;
|
|
53
|
+
let webhookTransport = null;
|
|
54
|
+
// Ring buffer
|
|
55
|
+
if (config.ringBuffer) {
|
|
56
|
+
const rbConfig = typeof config.ringBuffer === 'boolean' ? {} : config.ringBuffer;
|
|
57
|
+
ringBuffer = new RingBufferTransport(rbConfig.maxSize);
|
|
58
|
+
transports.push(ringBuffer);
|
|
59
|
+
}
|
|
60
|
+
// File transport
|
|
61
|
+
if (config.file) {
|
|
62
|
+
const fileConfig = typeof config.file === 'boolean' ? {} : config.file;
|
|
63
|
+
transports.push(new FileTransport(fileConfig));
|
|
64
|
+
}
|
|
65
|
+
// Webhook transport
|
|
66
|
+
if (config.webhook) {
|
|
67
|
+
webhookTransport = new WebhookTransport(config.webhook);
|
|
68
|
+
transports.push(webhookTransport);
|
|
69
|
+
}
|
|
70
|
+
// Custom transports
|
|
71
|
+
if (config.transports) {
|
|
72
|
+
transports.push(...config.transports);
|
|
73
|
+
}
|
|
74
|
+
function buildEntry(level, message, data) {
|
|
75
|
+
return {
|
|
76
|
+
id: generateId(),
|
|
77
|
+
timestamp: new Date().toISOString(),
|
|
78
|
+
level,
|
|
79
|
+
message,
|
|
80
|
+
data,
|
|
81
|
+
context: { ...ctx, ...extraContext },
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
function log(level, message, data) {
|
|
85
|
+
if (LEVEL_ORDER[level] < minLevelNum)
|
|
86
|
+
return;
|
|
87
|
+
const entry = buildEntry(level, message, data);
|
|
88
|
+
// Console output in dev
|
|
89
|
+
if (dev) {
|
|
90
|
+
const consoleFn = level === 'error' ? console.error
|
|
91
|
+
: level === 'warn' ? console.warn
|
|
92
|
+
: level === 'debug' ? console.debug
|
|
93
|
+
: console.log;
|
|
94
|
+
consoleFn(`[${level.toUpperCase()}] ${message}`, data ?? '');
|
|
95
|
+
}
|
|
96
|
+
// Route to all transports (non-blocking)
|
|
97
|
+
for (const transport of transports) {
|
|
98
|
+
transport.send([entry]).catch(() => {
|
|
99
|
+
// Transport errors are non-fatal
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
// Callback hooks for error/warn
|
|
103
|
+
const onLog = config.onLog ?? config.onError;
|
|
104
|
+
if ((level === 'error' || level === 'warn') && onLog) {
|
|
105
|
+
onLog(entry);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
const logger = {
|
|
109
|
+
debug: (message, data) => log('debug', message, data),
|
|
110
|
+
info: (message, data) => log('info', message, data),
|
|
111
|
+
warn: (message, data) => log('warn', message, data),
|
|
112
|
+
error: (message, data) => log('error', message, data),
|
|
113
|
+
captureException(error, context) {
|
|
114
|
+
log('error', error.message, {
|
|
115
|
+
stack: error.stack,
|
|
116
|
+
name: error.name,
|
|
117
|
+
...context,
|
|
118
|
+
});
|
|
119
|
+
if (config.onException) {
|
|
120
|
+
config.onException(error, context);
|
|
121
|
+
}
|
|
122
|
+
},
|
|
123
|
+
setUser(userId) {
|
|
124
|
+
ctx.userId = userId;
|
|
125
|
+
},
|
|
126
|
+
setScreen(screenName) {
|
|
127
|
+
ctx.screenName = screenName;
|
|
128
|
+
},
|
|
129
|
+
setContext(key, value) {
|
|
130
|
+
;
|
|
131
|
+
extraContext[key] = value;
|
|
132
|
+
},
|
|
133
|
+
getLogs(filter) {
|
|
134
|
+
if (!ringBuffer) {
|
|
135
|
+
throw new Error('Ring buffer not configured. Enable ringBuffer in LoggerConfig.');
|
|
136
|
+
}
|
|
137
|
+
return ringBuffer.getEntries(filter);
|
|
138
|
+
},
|
|
139
|
+
exportLogs(filter) {
|
|
140
|
+
if (!ringBuffer) {
|
|
141
|
+
throw new Error('Ring buffer not configured. Enable ringBuffer in LoggerConfig.');
|
|
142
|
+
}
|
|
143
|
+
const entries = ringBuffer.getEntries(filter);
|
|
144
|
+
return JSON.stringify(entries, null, 2);
|
|
145
|
+
},
|
|
146
|
+
async flush() {
|
|
147
|
+
if (webhookTransport) {
|
|
148
|
+
await webhookTransport.flush();
|
|
149
|
+
}
|
|
150
|
+
},
|
|
151
|
+
async destroy() {
|
|
152
|
+
if (webhookTransport) {
|
|
153
|
+
await webhookTransport.destroy();
|
|
154
|
+
}
|
|
155
|
+
},
|
|
156
|
+
};
|
|
157
|
+
return logger;
|
|
158
|
+
}
|
|
159
|
+
//# sourceMappingURL=logger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export interface NetworkState {
|
|
2
|
+
isConnected: boolean;
|
|
3
|
+
type: string | null;
|
|
4
|
+
isInternetReachable: boolean | null;
|
|
5
|
+
}
|
|
6
|
+
type NetworkStateListener = (state: NetworkState) => void;
|
|
7
|
+
export declare function getNetworkState(): Promise<NetworkState>;
|
|
8
|
+
export declare function addNetworkStateListener(callback: NetworkStateListener): {
|
|
9
|
+
remove: () => void;
|
|
10
|
+
};
|
|
11
|
+
export declare function useNetworkState(): NetworkState;
|
|
12
|
+
export {};
|
|
13
|
+
//# sourceMappingURL=network-state.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"network-state.d.ts","sourceRoot":"","sources":["../src/network-state.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,YAAY;IAC3B,WAAW,EAAE,OAAO,CAAA;IACpB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IACnB,mBAAmB,EAAE,OAAO,GAAG,IAAI,CAAA;CACpC;AAED,KAAK,oBAAoB,GAAG,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,CAAA;AA+DzD,wBAAsB,eAAe,IAAI,OAAO,CAAC,YAAY,CAAC,CAG7D;AAED,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,oBAAoB,GAC7B;IAAE,MAAM,EAAE,MAAM,IAAI,CAAA;CAAE,CAcxB;AAGD,wBAAgB,eAAe,IAAI,YAAY,CAe9C"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
let cachedState = {
|
|
2
|
+
isConnected: true,
|
|
3
|
+
type: null,
|
|
4
|
+
isInternetReachable: null,
|
|
5
|
+
};
|
|
6
|
+
const listeners = new Set();
|
|
7
|
+
let pollingInterval = null;
|
|
8
|
+
function getExpoNetwork() {
|
|
9
|
+
try {
|
|
10
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
11
|
+
return require('expo-network');
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
throw new Error('@mongrov/core network-state requires expo-network as a peer dependency');
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
async function fetchNetworkState() {
|
|
18
|
+
const Network = getExpoNetwork();
|
|
19
|
+
const state = await Network.getNetworkStateAsync();
|
|
20
|
+
return {
|
|
21
|
+
isConnected: state.isConnected ?? false,
|
|
22
|
+
type: state.type ?? null,
|
|
23
|
+
isInternetReachable: state.isInternetReachable ?? null,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
async function pollAndNotify() {
|
|
27
|
+
try {
|
|
28
|
+
const newState = await fetchNetworkState();
|
|
29
|
+
const changed = newState.isConnected !== cachedState.isConnected ||
|
|
30
|
+
newState.type !== cachedState.type ||
|
|
31
|
+
newState.isInternetReachable !== cachedState.isInternetReachable;
|
|
32
|
+
cachedState = newState;
|
|
33
|
+
if (changed) {
|
|
34
|
+
listeners.forEach((cb) => cb(newState));
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
// Silently ignore polling errors
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
function startPolling() {
|
|
42
|
+
if (pollingInterval)
|
|
43
|
+
return;
|
|
44
|
+
pollAndNotify();
|
|
45
|
+
pollingInterval = setInterval(pollAndNotify, 15000);
|
|
46
|
+
}
|
|
47
|
+
function stopPolling() {
|
|
48
|
+
if (pollingInterval) {
|
|
49
|
+
clearInterval(pollingInterval);
|
|
50
|
+
pollingInterval = null;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
export async function getNetworkState() {
|
|
54
|
+
cachedState = await fetchNetworkState();
|
|
55
|
+
return cachedState;
|
|
56
|
+
}
|
|
57
|
+
export function addNetworkStateListener(callback) {
|
|
58
|
+
listeners.add(callback);
|
|
59
|
+
if (listeners.size === 1) {
|
|
60
|
+
startPolling();
|
|
61
|
+
}
|
|
62
|
+
return {
|
|
63
|
+
remove: () => {
|
|
64
|
+
listeners.delete(callback);
|
|
65
|
+
if (listeners.size === 0) {
|
|
66
|
+
stopPolling();
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
// React hook — only usable in components
|
|
72
|
+
export function useNetworkState() {
|
|
73
|
+
// Lazy import React to avoid issues in non-React contexts
|
|
74
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
75
|
+
const React = require('react');
|
|
76
|
+
const { useState, useEffect } = React;
|
|
77
|
+
const [state, setState] = useState(cachedState);
|
|
78
|
+
useEffect(() => {
|
|
79
|
+
getNetworkState().then(setState);
|
|
80
|
+
const subscription = addNetworkStateListener(setState);
|
|
81
|
+
return () => subscription.remove();
|
|
82
|
+
}, []);
|
|
83
|
+
return state;
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=network-state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"network-state.js","sourceRoot":"","sources":["../src/network-state.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { LogEntry } from './types';
|
|
2
|
+
interface MMKVStorage {
|
|
3
|
+
getString(key: string): string | undefined;
|
|
4
|
+
set(key: string, value: string): void;
|
|
5
|
+
delete(key: string): void;
|
|
6
|
+
}
|
|
7
|
+
export declare class OfflineQueue {
|
|
8
|
+
private queue;
|
|
9
|
+
private readonly maxSize;
|
|
10
|
+
private readonly maxRetries;
|
|
11
|
+
private readonly sendFn;
|
|
12
|
+
private storage;
|
|
13
|
+
private networkSubscription;
|
|
14
|
+
private flushing;
|
|
15
|
+
constructor(sendFn: (entries: LogEntry[]) => Promise<void>, options?: {
|
|
16
|
+
maxSize?: number;
|
|
17
|
+
maxRetries?: number;
|
|
18
|
+
storage?: MMKVStorage;
|
|
19
|
+
});
|
|
20
|
+
enqueue(entries: LogEntry[]): void;
|
|
21
|
+
flush(): Promise<void>;
|
|
22
|
+
getQueueSize(): number;
|
|
23
|
+
destroy(): void;
|
|
24
|
+
private sendWithRetry;
|
|
25
|
+
private loadFromStorage;
|
|
26
|
+
private saveToStorage;
|
|
27
|
+
private listenForConnectivity;
|
|
28
|
+
}
|
|
29
|
+
export {};
|
|
30
|
+
//# sourceMappingURL=offline-queue.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"offline-queue.d.ts","sourceRoot":"","sources":["../src/offline-queue.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AAQvC,UAAU,WAAW;IACnB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAA;IAC1C,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACrC,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAA;CAC1B;AAcD,qBAAa,YAAY;IACvB,OAAO,CAAC,KAAK,CAAiB;IAC9B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAQ;IAChC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAQ;IACnC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAwC;IAC/D,OAAO,CAAC,OAAO,CAAa;IAC5B,OAAO,CAAC,mBAAmB,CAAsC;IACjE,OAAO,CAAC,QAAQ,CAAQ;gBAGtB,MAAM,EAAE,CAAC,OAAO,EAAE,QAAQ,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,EAC9C,OAAO,CAAC,EAAE;QACR,OAAO,CAAC,EAAE,MAAM,CAAA;QAChB,UAAU,CAAC,EAAE,MAAM,CAAA;QACnB,OAAO,CAAC,EAAE,WAAW,CAAA;KACtB;IAUH,OAAO,CAAC,OAAO,EAAE,QAAQ,EAAE,GAAG,IAAI;IAW5B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAwB5B,YAAY,IAAI,MAAM;IAItB,OAAO,IAAI,IAAI;YAOD,aAAa;IAiB3B,OAAO,CAAC,eAAe;IAcvB,OAAO,CAAC,aAAa;IAYrB,OAAO,CAAC,qBAAqB;CAO9B"}
|