@fiction/sdk 1.0.1 → 1.0.2
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/README.md +6 -221
- package/dist/api.d.ts +23 -0
- package/dist/base-CEr2lLFg.js +194 -0
- package/dist/base-CEr2lLFg.js.map +1 -0
- package/dist/index-C-0XxdQQ.js +299 -0
- package/dist/{index-iLB4ucpG.js.map → index-C-0XxdQQ.js.map} +1 -1
- package/dist/index.d.ts +7 -0
- package/dist/sdk.css +1 -1
- package/dist/sdk.js +2616 -3397
- package/dist/sdk.js.map +1 -1
- package/dist/sdkClient.d.ts +666 -0
- package/dist/sdkStorage.d.ts +27 -0
- package/dist/self/ClientAudio.d.ts +75 -0
- package/dist/self/SelfController.d.ts +68 -0
- package/dist/self/constants.d.ts +29 -0
- package/dist/self/index.d.ts +7 -0
- package/dist/self/schema.d.ts +28 -0
- package/dist/self/ui/ElAudioVisualizer.vue.d.ts +19 -0
- package/dist/self/ui/ElSelfAbout.vue.d.ts +6 -0
- package/dist/self/ui/ElSelfChat.vue.d.ts +8 -0
- package/dist/self/ui/ElSelfHeader.vue.d.ts +9 -0
- package/dist/self/ui/ElSelfSidebar.vue.d.ts +11 -0
- package/dist/self/ui/ElSelfVoice.vue.d.ts +6 -0
- package/dist/self/ui/SelfAgent.vue.d.ts +19 -0
- package/dist/self/ui/SelfProvider.vue.d.ts +12 -0
- package/dist/self/ui/SelfWrap.vue.d.ts +142 -0
- package/dist/self/utils.d.ts +18 -0
- package/dist/self.js +4874 -0
- package/dist/self.js.map +1 -0
- package/dist/types/SDKAppType.stub.d.ts +6 -0
- package/package.json +25 -26
- package/dist/base-CWJerwpW.js +0 -299
- package/dist/base-CWJerwpW.js.map +0 -1
- package/dist/index-iLB4ucpG.js +0 -402
- package/dist/sdk.d.ts +0 -460
- package/dist/ui.d.ts +0 -19
- package/dist/ui.js +0 -30388
- package/dist/ui.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,234 +1,19 @@
|
|
|
1
1
|
# Fiction SDK
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Lightweight client library for Fiction-owned projects (app, www, widget).
|
|
4
4
|
|
|
5
|
-
##
|
|
6
|
-
|
|
7
|
-
- ✅ **Fully typed Hono RPC client** - Type-safe endpoints, request bodies, response types
|
|
8
|
-
- ✅ **Convenience auth methods** - High-level helpers for common operations
|
|
9
|
-
- ✅ **Vue reactivity** - Reactive state management with Vue refs
|
|
10
|
-
- ✅ **Auto user/token updates** - API responses automatically update client state
|
|
11
|
-
- ✅ **Cookie-based auth** - Cross-domain session management
|
|
12
|
-
- ✅ **UI components** - Import pre-built Vue components from `/ui` export
|
|
13
|
-
- ✅ **Extends SettingsObject** - Built-in logger and proper dependency injection
|
|
14
|
-
|
|
15
|
-
## Installation
|
|
5
|
+
## Development
|
|
16
6
|
|
|
17
7
|
```bash
|
|
18
|
-
pnpm
|
|
8
|
+
pnpm dev # Watch mode - rebuilds on change
|
|
9
|
+
pnpm build # Production build (ES modules + types)
|
|
19
10
|
```
|
|
20
11
|
|
|
21
12
|
## Usage
|
|
22
13
|
|
|
23
|
-
### Quick Start with Convenience Methods
|
|
24
|
-
|
|
25
14
|
```typescript
|
|
26
15
|
import { FictionSDK } from '@fiction/sdk'
|
|
27
|
-
|
|
28
|
-
const sdk = new FictionSDK({
|
|
29
|
-
isDev: true,
|
|
30
|
-
apiBase: 'http://localhost:5555'
|
|
31
|
-
})
|
|
32
|
-
|
|
33
|
-
// Simple auth methods
|
|
34
|
-
await sdk.sendCode('user@example.com')
|
|
35
|
-
await sdk.verifyCode('user@example.com', '123456')
|
|
36
|
-
await sdk.login('user@example.com', 'password')
|
|
37
|
-
await sdk.logout()
|
|
38
|
-
|
|
39
|
-
// Reactive state
|
|
40
|
-
console.log(sdk.activeUser.value) // Current user
|
|
41
|
-
console.log(sdk.loading.value) // Loading state
|
|
42
|
-
console.log(sdk.error.value) // Error message
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
### Fully Typed API Access
|
|
46
|
-
|
|
47
|
-
When you have access to the app's server types, you get full type safety:
|
|
48
|
-
|
|
49
|
-
```typescript
|
|
50
|
-
import { FictionSDK } from '@fiction/sdk'
|
|
51
|
-
import type { AppType } from '@/modules/main/server'
|
|
52
|
-
|
|
53
|
-
// Create SDK with app types for full type safety
|
|
54
|
-
const sdk = new FictionSDK<AppType>({
|
|
55
|
-
isDev: true,
|
|
56
|
-
apiBase: 'http://localhost:5555'
|
|
57
|
-
})
|
|
58
|
-
|
|
59
|
-
// Now sdk.apiClient is fully typed with all endpoints!
|
|
60
|
-
// Autocomplete, type checking, compile-time errors
|
|
61
|
-
|
|
62
|
-
// Example: Type-safe auth endpoint
|
|
63
|
-
const response = await sdk.apiClient.api.auth['send-code'].$post({
|
|
64
|
-
json: { email: 'user@example.com' }
|
|
65
|
-
})
|
|
66
|
-
|
|
67
|
-
const data = await response.json()
|
|
68
|
-
// data is fully typed based on the endpoint's response schema
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
### Reactive State
|
|
72
|
-
|
|
73
|
-
The SDK exposes Vue refs for reactive state management:
|
|
74
|
-
|
|
75
|
-
```typescript
|
|
76
|
-
// Reactive user state
|
|
77
|
-
sdk.activeUser.value // EnrichedUser | undefined
|
|
78
|
-
sdk.token.value // string | null
|
|
79
|
-
sdk.loading.value // boolean
|
|
80
|
-
sdk.error.value // string | null
|
|
81
|
-
|
|
82
|
-
// Watch for changes
|
|
83
|
-
watch(sdk.activeUser, (user) => {
|
|
84
|
-
console.log('User changed:', user)
|
|
85
|
-
})
|
|
86
|
-
```
|
|
87
|
-
|
|
88
|
-
### UI Components
|
|
89
|
-
|
|
90
|
-
Import pre-built Vue components for rapid integration:
|
|
91
|
-
|
|
92
|
-
```typescript
|
|
93
|
-
// Import UI components from /ui export
|
|
94
|
-
import { SelfAgent, TestButton } from '@fiction/sdk/ui'
|
|
95
|
-
|
|
96
|
-
// Use in your Vue app
|
|
97
|
-
<template>
|
|
98
|
-
<SelfAgent
|
|
99
|
-
:self="selfData"
|
|
100
|
-
context="website"
|
|
101
|
-
@close="handleClose"
|
|
102
|
-
/>
|
|
103
|
-
|
|
104
|
-
<TestButton
|
|
105
|
-
label="Click me"
|
|
106
|
-
@click="handleClick"
|
|
107
|
-
/>
|
|
108
|
-
</template>
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
**Available Components:**
|
|
112
|
-
- `SelfAgent` - Full digital self agent interface with chat, voice, and profile
|
|
113
|
-
- `TestButton` - Simple test button component (for validation)
|
|
114
|
-
|
|
115
|
-
### Advanced: Direct Typed API Access
|
|
116
|
-
|
|
117
|
-
Use the typed Hono RPC client directly for custom endpoints:
|
|
118
|
-
|
|
119
|
-
```typescript
|
|
120
|
-
// Type-safe login
|
|
121
|
-
const loginResponse = await sdk.apiClient.api.auth.login.$post({
|
|
122
|
-
json: { email: 'user@example.com', password: 'secret' }
|
|
123
|
-
})
|
|
124
|
-
|
|
125
|
-
// Type-safe user fetch
|
|
126
|
-
const userResponse = await sdk.apiClient.api.auth.me.$get()
|
|
127
|
-
|
|
128
|
-
// Type-safe self access
|
|
129
|
-
const selfResponse = await sdk.apiClient.api.self['by-handle'].$get({
|
|
130
|
-
query: { handle: 'andrew' }
|
|
131
|
-
})
|
|
132
|
-
|
|
133
|
-
// All responses are fully typed based on endpoint schemas
|
|
134
|
-
const data = await loginResponse.json()
|
|
135
|
-
```
|
|
136
|
-
|
|
137
|
-
## API Reference
|
|
138
|
-
|
|
139
|
-
### FictionSDK Class
|
|
140
|
-
|
|
141
|
-
```typescript
|
|
142
|
-
class FictionSDK<TAppType extends Hono = any> extends SettingsObject<FictionSDKSettings>
|
|
143
|
-
```
|
|
144
|
-
|
|
145
|
-
#### Constructor
|
|
146
|
-
|
|
147
|
-
```typescript
|
|
148
|
-
new FictionSDK<TAppType>(settings?: FictionSDKSettings)
|
|
149
|
-
```
|
|
150
|
-
|
|
151
|
-
**Settings:**
|
|
152
|
-
- `apiBase?: string` - API base URL (default: auto-detected)
|
|
153
|
-
- `isDev?: boolean` - Development mode (default: auto-detected from hostname)
|
|
154
|
-
|
|
155
|
-
#### Properties
|
|
156
|
-
|
|
157
|
-
- `apiClient: ReturnType<typeof createApiClient<TAppType>>` - Typed Hono RPC client
|
|
158
|
-
- `activeUser: Ref<EnrichedUser | undefined>` - Current authenticated user
|
|
159
|
-
- `token: Ref<string | null>` - Authentication token
|
|
160
|
-
- `loading: Ref<boolean>` - Loading state
|
|
161
|
-
- `error: Ref<string | null>` - Error message
|
|
162
|
-
- `logger: ReturnType<typeof createLogger>` - Logger instance (from SettingsObject)
|
|
163
|
-
- `initialized: Promise<EnrichedUser | undefined>` - Promise that resolves when user loads
|
|
164
|
-
|
|
165
|
-
#### Methods
|
|
166
|
-
|
|
167
|
-
**Convenience Auth Methods:**
|
|
168
|
-
- `sendCode(email: string): Promise<void>` - Send verification code to email
|
|
169
|
-
- `verifyCode(email: string, code: string): Promise<void>` - Verify code and login
|
|
170
|
-
- `login(email: string, password: string): Promise<void>` - Login with password
|
|
171
|
-
- `logout(): Promise<void>` - Logout and clear session
|
|
172
|
-
- `getCurrentUser(): Promise<EnrichedUser | undefined>` - Fetch current user from server
|
|
173
|
-
|
|
174
|
-
**Utility Methods:**
|
|
175
|
-
- `processApiResponse(response: ApiResponse<any>): void` - Process API response for auto state updates
|
|
176
|
-
- `clearSession(): void` - Clear all user data and tokens
|
|
177
|
-
|
|
178
|
-
### createApiClient Function
|
|
179
|
-
|
|
180
|
-
```typescript
|
|
181
|
-
function createApiClient<TAppType extends Hono = any>(
|
|
182
|
-
settings: ApiClientSettings,
|
|
183
|
-
responseHandler?: (response: any) => void
|
|
184
|
-
): ReturnType<typeof hc<TAppType>>
|
|
185
|
-
```
|
|
186
|
-
|
|
187
|
-
Creates a fully typed Hono RPC client with optional response interceptor.
|
|
188
|
-
|
|
189
|
-
**Example:**
|
|
190
|
-
```typescript
|
|
191
|
-
import type { AppType } from '@/modules/main/server'
|
|
192
|
-
|
|
193
|
-
const client = createApiClient<AppType>(
|
|
194
|
-
{ isDev: true },
|
|
195
|
-
(response) => {
|
|
196
|
-
// Handle ApiResponse with user/token updates
|
|
197
|
-
console.log('API response:', response)
|
|
198
|
-
}
|
|
199
|
-
)
|
|
200
|
-
|
|
201
|
-
// Fully typed endpoint calls
|
|
202
|
-
const response = await client.api.auth['send-code'].$post({
|
|
203
|
-
json: { email: 'user@example.com' }
|
|
204
|
-
})
|
|
16
|
+
import { SelfAgent } from '@fiction/sdk/self'
|
|
205
17
|
```
|
|
206
18
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
- **ES Module**: 140KB uncompressed, 27KB gzipped
|
|
210
|
-
- **UMD**: 161KB uncompressed, 51KB gzipped
|
|
211
|
-
- **TypeScript declarations**: Included
|
|
212
|
-
|
|
213
|
-
## Development
|
|
214
|
-
|
|
215
|
-
```bash
|
|
216
|
-
# Install dependencies
|
|
217
|
-
pnpm install
|
|
218
|
-
|
|
219
|
-
# Build
|
|
220
|
-
pnpm run build
|
|
221
|
-
|
|
222
|
-
# Type check
|
|
223
|
-
pnpm run typecheck
|
|
224
|
-
|
|
225
|
-
# Run tests
|
|
226
|
-
pnpm run test
|
|
227
|
-
|
|
228
|
-
# Watch mode
|
|
229
|
-
pnpm run test:watch
|
|
230
|
-
```
|
|
231
|
-
|
|
232
|
-
## License
|
|
233
|
-
|
|
234
|
-
MIT
|
|
19
|
+
**Build required before typecheck** - Widget/www import from `dist/`, not source.
|
package/dist/api.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Hono } from 'hono';
|
|
2
|
+
import { hc } from 'hono/client';
|
|
3
|
+
export interface ApiClientSettings {
|
|
4
|
+
isDev: boolean;
|
|
5
|
+
apiBase?: string;
|
|
6
|
+
[key: string]: unknown;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Create fully typed Hono RPC client for Fiction SDK
|
|
10
|
+
*
|
|
11
|
+
* @template TAppType - The Hono app type from the server (enables full type safety)
|
|
12
|
+
* @param settings - Configuration for API base URL and environment
|
|
13
|
+
* @param responseHandler - Optional handler to process ApiResponse for auto user/token updates
|
|
14
|
+
* @returns Typed Hono client with response interceptor
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```typescript
|
|
18
|
+
* import type { SDKAppType } from '@/modules/main/server'
|
|
19
|
+
* const client = createApiClient<SDKAppType>({ isDev: true })
|
|
20
|
+
* const response = await client.api.auth['check-email'].$post({ json: { email } })
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export declare function createApiClient<TAppType extends Hono = any>(settings: ApiClientSettings, responseHandler?: (response: any) => void): ReturnType<typeof hc<TAppType>>;
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
var E = Object.defineProperty;
|
|
2
|
+
var D = (l, e, o) => e in l ? E(l, e, { enumerable: !0, configurable: !0, writable: !0, value: o }) : l[e] = o;
|
|
3
|
+
var i = (l, e) => E(l, "name", { value: e, configurable: !0 });
|
|
4
|
+
var h = (l, e, o) => D(l, typeof e != "symbol" ? e + "" : e, o);
|
|
5
|
+
const p = globalThis.process, f = typeof window < "u", y = typeof p < "u" && !f, d = f ? typeof window < "u" && window.location && !window.location.hostname.includes("localhost") : y && typeof p < "u" && p.env?.NODE_ENV === "production", k = !d, v = {
|
|
6
|
+
error: { priority: 50, color: "#FF0000", nodeColor: "\x1B[31m" },
|
|
7
|
+
warn: { priority: 40, color: "#FFA500", nodeColor: "\x1B[33m" },
|
|
8
|
+
info: { priority: 30, color: "#00ABFF", nodeColor: "\x1B[36m" },
|
|
9
|
+
debug: { priority: 20, color: "#00BD0C", nodeColor: "\x1B[32m" },
|
|
10
|
+
trace: { priority: 10, color: "#5233FF", nodeColor: "\x1B[35m" }
|
|
11
|
+
}, N = ["password", "token", "secret", "apikey", "api_key", "authorization", "cookie"], m = class m {
|
|
12
|
+
constructor(e = {}, o) {
|
|
13
|
+
h(this, "settings");
|
|
14
|
+
h(this, "enabledInBrowser", !1);
|
|
15
|
+
h(this, "context");
|
|
16
|
+
this.context = o, this.settings = {
|
|
17
|
+
enabled: e.enabled ?? !0,
|
|
18
|
+
minLevel: e.minLevel ?? this.getDefaultLevel(),
|
|
19
|
+
timestamps: e.timestamps ?? !0
|
|
20
|
+
}, f && this.initBrowserLogging();
|
|
21
|
+
}
|
|
22
|
+
getDefaultLevel() {
|
|
23
|
+
if (y && typeof p < "u" && p.env?.LOG_LEVEL)
|
|
24
|
+
return p.env.LOG_LEVEL;
|
|
25
|
+
if (f && typeof localStorage < "u") {
|
|
26
|
+
const e = localStorage.getItem("FICTION_LOG_LEVEL");
|
|
27
|
+
if (e)
|
|
28
|
+
return e;
|
|
29
|
+
}
|
|
30
|
+
return d ? "info" : "debug";
|
|
31
|
+
}
|
|
32
|
+
initBrowserLogging() {
|
|
33
|
+
if (!f)
|
|
34
|
+
return;
|
|
35
|
+
const o = localStorage.getItem("FICTION_LOG") === "true", t = window.location?.hostname || "";
|
|
36
|
+
this.enabledInBrowser = k || o || t === "localhost" || t.includes("127.0.0.1"), d && !o && !m.hasShownHelp && (console.log(
|
|
37
|
+
"%cFiction WWW Logger (disabled in production)",
|
|
38
|
+
"color: #888; font-size: 12px"
|
|
39
|
+
), console.log(
|
|
40
|
+
'%cTo enable: localStorage.setItem("FICTION_LOG", "true")',
|
|
41
|
+
"color: #888; font-size: 11px"
|
|
42
|
+
), m.hasShownHelp = !0);
|
|
43
|
+
}
|
|
44
|
+
shouldLog(e) {
|
|
45
|
+
if (!this.settings.enabled || f && !this.enabledInBrowser)
|
|
46
|
+
return !1;
|
|
47
|
+
const o = v[e].priority, t = v[this.settings.minLevel].priority;
|
|
48
|
+
return o >= t;
|
|
49
|
+
}
|
|
50
|
+
formatTimestamp() {
|
|
51
|
+
return (/* @__PURE__ */ new Date()).toLocaleTimeString("en-GB", {
|
|
52
|
+
hour12: !1,
|
|
53
|
+
hour: "2-digit",
|
|
54
|
+
minute: "2-digit",
|
|
55
|
+
second: "2-digit"
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
formatISOTimestamp() {
|
|
59
|
+
return (/* @__PURE__ */ new Date()).toISOString();
|
|
60
|
+
}
|
|
61
|
+
redactSensitive(e) {
|
|
62
|
+
if (typeof e != "object" || e === null)
|
|
63
|
+
return e;
|
|
64
|
+
if (Array.isArray(e))
|
|
65
|
+
return e.map((t) => this.redactSensitive(t));
|
|
66
|
+
const o = {};
|
|
67
|
+
for (const [t, r] of Object.entries(e)) {
|
|
68
|
+
const s = t.toLowerCase();
|
|
69
|
+
N.some((n) => s.includes(n)) ? o[t] = "[REDACTED]" : typeof r == "object" && r !== null ? o[t] = this.redactSensitive(r) : o[t] = r;
|
|
70
|
+
}
|
|
71
|
+
return o;
|
|
72
|
+
}
|
|
73
|
+
formatData(e, o = 3, t = 0) {
|
|
74
|
+
if (t >= o)
|
|
75
|
+
return "[Max Depth]";
|
|
76
|
+
if (e == null)
|
|
77
|
+
return e;
|
|
78
|
+
if (e instanceof Error)
|
|
79
|
+
return {
|
|
80
|
+
name: e.name,
|
|
81
|
+
message: e.message,
|
|
82
|
+
stack: d ? e.stack?.split(`
|
|
83
|
+
`).slice(0, 3).join(`
|
|
84
|
+
`) : e.stack,
|
|
85
|
+
...e
|
|
86
|
+
// Include any additional error properties
|
|
87
|
+
};
|
|
88
|
+
if (e instanceof Date)
|
|
89
|
+
return e.toISOString();
|
|
90
|
+
if (typeof e != "object")
|
|
91
|
+
return e;
|
|
92
|
+
if (Array.isArray(e))
|
|
93
|
+
return e.length > 20 && d ? `Array(${e.length}) [${e.slice(0, 3).map((r) => this.formatData(r, o, t + 1)).join(", ")}, ...]` : e.map((r) => this.formatData(r, o, t + 1));
|
|
94
|
+
try {
|
|
95
|
+
const r = {}, s = Object.entries(e), n = d ? 50 : 200;
|
|
96
|
+
for (const [g, u] of s.slice(0, n))
|
|
97
|
+
r[g] = this.formatData(u, o, t + 1);
|
|
98
|
+
return s.length > n && (r["..."] = `${s.length - n} more properties`), this.redactSensitive(r);
|
|
99
|
+
} catch {
|
|
100
|
+
return "[Unserializable]";
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
logToBrowser(e) {
|
|
104
|
+
if (!f || !this.shouldLog(e.level))
|
|
105
|
+
return;
|
|
106
|
+
const { level: o, description: t, context: r, data: s, error: n } = e, g = v[o], a = `[${r || this.context || "www"}] ${o.toUpperCase()}:`, w = `color: ${g.color}; font-weight: bold;`;
|
|
107
|
+
s !== void 0 ? console[o](`%c${a}`, w, t, this.formatData(s)) : console[o](`%c${a}`, w, t), n && (n instanceof Error ? console.error(n) : console.error("Error details:", n));
|
|
108
|
+
}
|
|
109
|
+
async logToNode(e) {
|
|
110
|
+
if (!y || !this.shouldLog(e.level))
|
|
111
|
+
return;
|
|
112
|
+
const { level: o, description: t, context: r, data: s, error: n } = e, g = r || this.context || "www";
|
|
113
|
+
if (d) {
|
|
114
|
+
const u = {
|
|
115
|
+
timestamp: this.formatISOTimestamp(),
|
|
116
|
+
level: o.toUpperCase()
|
|
117
|
+
};
|
|
118
|
+
s && (u.data = this.formatData(s)), n && (u.error = this.formatData(n)), console[o](`${u.timestamp} ${u.level} [${g}] ${t}`, s || n ? JSON.stringify({ data: s, error: n }) : "");
|
|
119
|
+
} else
|
|
120
|
+
try {
|
|
121
|
+
const a = (await import("./index-C-0XxdQQ.js").catch(() => null))?.default, w = v[o], $ = this.formatTimestamp();
|
|
122
|
+
if (a) {
|
|
123
|
+
const C = a.dim, b = a.hex(w.color), I = C(`${$} `), T = b(`${o.toUpperCase()} `), B = b(`(${g}): `), O = `${I}${T}${B}${t}`;
|
|
124
|
+
console[o](O), s !== void 0 && console.log(JSON.stringify(this.formatData(s), null, 2)), n && (n instanceof Error && a ? (console.error(a.red("Error:"), n.message), n.stack && console.error(a.gray(n.stack))) : console.error("Error:", n));
|
|
125
|
+
} else
|
|
126
|
+
console[o](`${$} ${o.toUpperCase()} (${g}): ${t}`), s !== void 0 && console.log(JSON.stringify(this.formatData(s), null, 2)), n && console.error("Error:", n);
|
|
127
|
+
} catch {
|
|
128
|
+
console[o](`${this.formatTimestamp()} ${o.toUpperCase()} (${g}): ${t}`), s !== void 0 && console.log(JSON.stringify(this.formatData(s), null, 2)), n && console.error("Error:", n);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
log(e) {
|
|
132
|
+
f ? this.logToBrowser(e) : y && this.logToNode(e).catch(console.error);
|
|
133
|
+
}
|
|
134
|
+
error(e, o) {
|
|
135
|
+
this.log({ level: "error", description: e, data: o, context: this.context });
|
|
136
|
+
}
|
|
137
|
+
warn(e, o) {
|
|
138
|
+
this.log({ level: "warn", description: e, data: o, context: this.context });
|
|
139
|
+
}
|
|
140
|
+
info(e, o) {
|
|
141
|
+
this.log({ level: "info", description: e, data: o, context: this.context });
|
|
142
|
+
}
|
|
143
|
+
debug(e, o) {
|
|
144
|
+
this.log({ level: "debug", description: e, data: o, context: this.context });
|
|
145
|
+
}
|
|
146
|
+
trace(e, o) {
|
|
147
|
+
this.log({ level: "trace", description: e, data: o, context: this.context });
|
|
148
|
+
}
|
|
149
|
+
isEnabled() {
|
|
150
|
+
return f ? this.enabledInBrowser : !0;
|
|
151
|
+
}
|
|
152
|
+
setLevel(e) {
|
|
153
|
+
this.settings.minLevel = e;
|
|
154
|
+
}
|
|
155
|
+
createContextLogger(e) {
|
|
156
|
+
const o = new m(this.settings, e);
|
|
157
|
+
return {
|
|
158
|
+
error: /* @__PURE__ */ i((t, r) => o.error(t, r), "error"),
|
|
159
|
+
warn: /* @__PURE__ */ i((t, r) => o.warn(t, r), "warn"),
|
|
160
|
+
info: /* @__PURE__ */ i((t, r) => o.info(t, r), "info"),
|
|
161
|
+
debug: /* @__PURE__ */ i((t, r) => o.debug(t, r), "debug"),
|
|
162
|
+
trace: /* @__PURE__ */ i((t, r) => o.trace(t, r), "trace"),
|
|
163
|
+
isEnabled: /* @__PURE__ */ i(() => o.isEnabled(), "isEnabled"),
|
|
164
|
+
setLevel: /* @__PURE__ */ i((t) => o.setLevel(t), "setLevel")
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
i(m, "Logger"), h(m, "hasShownHelp", !1);
|
|
169
|
+
let x = m;
|
|
170
|
+
function F(l) {
|
|
171
|
+
return new x({}, l).createContextLogger(l);
|
|
172
|
+
}
|
|
173
|
+
i(F, "createLogger");
|
|
174
|
+
const c = new x();
|
|
175
|
+
c.error.bind(c);
|
|
176
|
+
c.warn.bind(c);
|
|
177
|
+
c.info.bind(c);
|
|
178
|
+
c.debug.bind(c);
|
|
179
|
+
c.trace.bind(c);
|
|
180
|
+
const L = class L {
|
|
181
|
+
constructor(e, o) {
|
|
182
|
+
h(this, "name");
|
|
183
|
+
h(this, "settings");
|
|
184
|
+
h(this, "logger");
|
|
185
|
+
this.name = e, this.settings = o, this.logger = F(e);
|
|
186
|
+
}
|
|
187
|
+
};
|
|
188
|
+
i(L, "SettingsObject");
|
|
189
|
+
let S = L;
|
|
190
|
+
export {
|
|
191
|
+
S,
|
|
192
|
+
F as c
|
|
193
|
+
};
|
|
194
|
+
//# sourceMappingURL=base-CEr2lLFg.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base-CEr2lLFg.js","sources":["../../utils/logger.ts","../../utils/base.ts"],"sourcesContent":["/* eslint-disable no-console */\n\n// Use globalThis.process instead of node:process import for browser compatibility\n// Safe because we always check `typeof process !== 'undefined'` before accessing properties\n// eslint-disable-next-line node/prefer-global/process\nconst process = (globalThis as any).process\n\ntype LogLevel = 'error' | 'warn' | 'info' | 'debug' | 'trace'\ntype LogData = Record<string, unknown> | unknown\n\nexport interface LogHelper {\n error: (description: string, data?: LogData) => void\n warn: (description: string, data?: LogData) => void\n info: (description: string, data?: LogData) => void\n debug: (description: string, data?: LogData) => void\n trace: (description: string, data?: LogData) => void\n isEnabled?: () => boolean\n setLevel?: (level: LogLevel) => void\n}\n\ninterface LoggerConfig {\n level: LogLevel\n context?: string\n description?: string\n data?: LogData\n error?: Error | unknown\n timestamp?: boolean\n}\n\ninterface LogSettings {\n enabled?: boolean\n minLevel?: LogLevel\n timestamps?: boolean\n}\n\n// Universal environment detection\nconst isBrowser = typeof window !== 'undefined'\nconst isNode = typeof process !== 'undefined' && !isBrowser\nconst isProd = isBrowser\n ? (typeof window !== 'undefined' && window.location && !window.location.hostname.includes('localhost'))\n : (isNode && typeof process !== 'undefined' && process.env?.NODE_ENV === 'production')\nconst isDev = !isProd\n\n// Log level configuration\nconst logLevels: Record<LogLevel, { priority: number, color: string, nodeColor?: string }> = {\n error: { priority: 50, color: '#FF0000', nodeColor: '\\x1B[31m' },\n warn: { priority: 40, color: '#FFA500', nodeColor: '\\x1B[33m' },\n info: { priority: 30, color: '#00ABFF', nodeColor: '\\x1B[36m' },\n debug: { priority: 20, color: '#00BD0C', nodeColor: '\\x1B[32m' },\n trace: { priority: 10, color: '#5233FF', nodeColor: '\\x1B[35m' },\n}\n\n// Sensitive keys to redact\nconst SENSITIVE_KEYS = ['password', 'token', 'secret', 'apikey', 'api_key', 'authorization', 'cookie']\n\nexport class Logger {\n private settings: Required<LogSettings>\n private enabledInBrowser: boolean = false\n private context?: string\n private static hasShownHelp = false\n\n constructor(settings: LogSettings = {}, context?: string) {\n this.context = context\n this.settings = {\n enabled: settings.enabled ?? true,\n minLevel: settings.minLevel ?? this.getDefaultLevel(),\n timestamps: settings.timestamps ?? true,\n }\n\n if (isBrowser) {\n this.initBrowserLogging()\n }\n }\n\n private getDefaultLevel(): LogLevel {\n // Check environment variable first\n if (isNode && typeof process !== 'undefined' && process.env?.LOG_LEVEL) {\n return process.env.LOG_LEVEL as LogLevel\n }\n\n // Check localStorage in browser\n if (isBrowser && typeof localStorage !== 'undefined') {\n const level = localStorage.getItem('FICTION_LOG_LEVEL')\n if (level)\n return level as LogLevel\n }\n\n // Default: info in production, debug in development\n return isProd ? 'info' : 'debug'\n }\n\n private initBrowserLogging(): void {\n if (!isBrowser)\n return\n\n const logKey = 'FICTION_LOG'\n const enabled = localStorage.getItem(logKey) === 'true'\n const hostname = window.location?.hostname || ''\n\n // Enable in dev, or if explicitly enabled via localStorage\n this.enabledInBrowser = isDev || enabled || hostname === 'localhost' || hostname.includes('127.0.0.1')\n\n // Show help message once in production\n if (isProd && !enabled && !Logger.hasShownHelp) {\n console.log(\n '%cFiction WWW Logger (disabled in production)',\n 'color: #888; font-size: 12px',\n )\n console.log(\n '%cTo enable: localStorage.setItem(\"FICTION_LOG\", \"true\")',\n 'color: #888; font-size: 11px',\n )\n Logger.hasShownHelp = true\n }\n }\n\n private shouldLog(level: LogLevel): boolean {\n if (!this.settings.enabled)\n return false\n\n // In browser, check if enabled\n if (isBrowser && !this.enabledInBrowser)\n return false\n\n const currentPriority = logLevels[level].priority\n const minPriority = logLevels[this.settings.minLevel].priority\n\n return currentPriority >= minPriority\n }\n\n private formatTimestamp(): string {\n return new Date().toLocaleTimeString('en-GB', {\n hour12: false,\n hour: '2-digit',\n minute: '2-digit',\n second: '2-digit',\n })\n }\n\n private formatISOTimestamp(): string {\n return new Date().toISOString()\n }\n\n private redactSensitive(obj: any): any {\n if (typeof obj !== 'object' || obj === null)\n return obj\n\n if (Array.isArray(obj)) {\n return obj.map((item) => this.redactSensitive(item))\n }\n\n const result: any = {}\n for (const [key, value] of Object.entries(obj)) {\n const lowerKey = key.toLowerCase()\n if (SENSITIVE_KEYS.some((sensitive) => lowerKey.includes(sensitive))) {\n result[key] = '[REDACTED]'\n } else if (typeof value === 'object' && value !== null) {\n result[key] = this.redactSensitive(value)\n } else {\n result[key] = value\n }\n }\n return result\n }\n\n private formatData(data: unknown, maxDepth: number = 3, currentDepth: number = 0): unknown {\n if (currentDepth >= maxDepth) {\n return '[Max Depth]'\n }\n\n if (data === null || data === undefined) {\n return data\n }\n\n // Handle Error objects specially\n if (data instanceof Error) {\n return {\n name: data.name,\n message: data.message,\n stack: isProd ? data.stack?.split('\\n').slice(0, 3).join('\\n') : data.stack,\n ...(data as any), // Include any additional error properties\n }\n }\n\n if (data instanceof Date) {\n return data.toISOString()\n }\n\n if (typeof data !== 'object') {\n return data\n }\n\n if (Array.isArray(data)) {\n if (data.length > 20 && isProd) {\n return `Array(${data.length}) [${data.slice(0, 3).map((item) =>\n this.formatData(item, maxDepth, currentDepth + 1)).join(', ')}, ...]`\n }\n return data.map((item) => this.formatData(item, maxDepth, currentDepth + 1))\n }\n\n // Handle regular objects\n try {\n const formatted: Record<string, unknown> = {}\n const entries = Object.entries(data)\n const maxProperties = isProd ? 50 : 200\n\n for (const [key, value] of entries.slice(0, maxProperties)) {\n formatted[key] = this.formatData(value, maxDepth, currentDepth + 1)\n }\n\n if (entries.length > maxProperties) {\n formatted['...'] = `${entries.length - maxProperties} more properties`\n }\n\n return this.redactSensitive(formatted)\n } catch {\n return '[Unserializable]'\n }\n }\n\n private logToBrowser(config: LoggerConfig): void {\n if (!isBrowser || !this.shouldLog(config.level))\n return\n\n const { level, description, context, data, error } = config\n const levelConfig = logLevels[level]\n const ctx = context || this.context || 'www'\n\n // Format for browser console\n const prefix = `[${ctx}] ${level.toUpperCase()}:`\n const style = `color: ${levelConfig.color}; font-weight: bold;`\n\n // Log main message\n if (data !== undefined) {\n console[level](`%c${prefix}`, style, description, this.formatData(data))\n } else {\n console[level](`%c${prefix}`, style, description)\n }\n\n // Log error details if present\n if (error) {\n if (error instanceof Error) {\n console.error(error)\n } else {\n console.error('Error details:', error)\n }\n }\n }\n\n private async logToNode(config: LoggerConfig): Promise<void> {\n if (!isNode || !this.shouldLog(config.level))\n return\n\n const { level, description, context, data, error } = config\n const ctx = context || this.context || 'www'\n\n if (isProd) {\n // Production: Single-line JSON format for log aggregation\n const logEntry: any = {\n timestamp: this.formatISOTimestamp(),\n level: level.toUpperCase(),\n context: ctx,\n message: description,\n }\n if (data) {\n logEntry.data = this.formatData(data)\n }\n if (error) {\n logEntry.error = this.formatData(error)\n }\n\n console[level](`${logEntry.timestamp} ${logEntry.level} [${ctx}] ${description}`, data || error ? JSON.stringify({ data, error }) : '')\n } else {\n // Development: Pretty-printed format\n try {\n // Dynamic import for Node-only dependencies\n const chalkModule = await import('chalk').catch(() => null)\n const chalk = chalkModule?.default\n\n const levelConfig = logLevels[level]\n const timestamp = this.formatTimestamp()\n\n if (chalk) {\n const dim = chalk.dim\n const colored = chalk.hex(levelConfig.color)\n\n const logTimestamp = dim(`${timestamp} `)\n const logLevel = colored(`${level.toUpperCase()} `)\n const logContext = colored(`(${ctx}): `)\n const logMessage = `${logTimestamp}${logLevel}${logContext}${description}`\n\n console[level](logMessage)\n\n // Log data if present\n if (data !== undefined) {\n console.log(JSON.stringify(this.formatData(data), null, 2))\n }\n\n // Log error if present\n if (error) {\n if (error instanceof Error && chalk) {\n console.error(chalk.red('Error:'), error.message)\n if (error.stack) {\n console.error(chalk.gray(error.stack))\n }\n } else {\n console.error('Error:', error)\n }\n }\n } else {\n // Fallback without chalk\n console[level](`${timestamp} ${level.toUpperCase()} (${ctx}): ${description}`)\n if (data !== undefined) {\n console.log(JSON.stringify(this.formatData(data), null, 2))\n }\n if (error) {\n console.error('Error:', error)\n }\n }\n } catch {\n // Fallback if dynamic imports fail\n console[level](`${this.formatTimestamp()} ${level.toUpperCase()} (${ctx}): ${description}`)\n if (data !== undefined) {\n console.log(JSON.stringify(this.formatData(data), null, 2))\n }\n if (error) {\n console.error('Error:', error)\n }\n }\n }\n }\n\n private log(config: LoggerConfig): void {\n if (isBrowser) {\n this.logToBrowser(config)\n } else if (isNode) {\n // Use promise but don't await (fire and forget)\n this.logToNode(config).catch(console.error)\n }\n }\n\n error(description: string, data?: LogData): void {\n this.log({ level: 'error', description, data, context: this.context })\n }\n\n warn(description: string, data?: LogData): void {\n this.log({ level: 'warn', description, data, context: this.context })\n }\n\n info(description: string, data?: LogData): void {\n this.log({ level: 'info', description, data, context: this.context })\n }\n\n debug(description: string, data?: LogData): void {\n this.log({ level: 'debug', description, data, context: this.context })\n }\n\n trace(description: string, data?: LogData): void {\n this.log({ level: 'trace', description, data, context: this.context })\n }\n\n isEnabled(): boolean {\n if (isBrowser) {\n return this.enabledInBrowser\n }\n return true // Always enabled in Node\n }\n\n setLevel(level: LogLevel): void {\n this.settings.minLevel = level\n }\n\n createContextLogger(context: string): LogHelper {\n const contextualLogger = new Logger(this.settings, context)\n\n return {\n error: (description: string, data?: LogData) => contextualLogger.error(description, data),\n warn: (description: string, data?: LogData) => contextualLogger.warn(description, data),\n info: (description: string, data?: LogData) => contextualLogger.info(description, data),\n debug: (description: string, data?: LogData) => contextualLogger.debug(description, data),\n trace: (description: string, data?: LogData) => contextualLogger.trace(description, data),\n isEnabled: () => contextualLogger.isEnabled(),\n setLevel: (level: LogLevel) => contextualLogger.setLevel(level),\n }\n }\n}\n\n// Factory function - main export\nexport function createLogger(context: string): LogHelper {\n return new Logger({}, context).createContextLogger(context)\n}\n\n// Default logger instance for convenience\nexport const logger = new Logger()\n\n// Convenience exports\nexport const error = logger.error.bind(logger)\nexport const warn = logger.warn.bind(logger)\nexport const info = logger.info.bind(logger)\nexport const debug = logger.debug.bind(logger)\nexport const trace = logger.trace.bind(logger)\n","import { createLogger } from './logger'\n\nexport type SettingsObjectSettings = {\n [key: string]: unknown\n}\n\n/**\n * Base class for objects with settings and contextual logging.\n * Services use this.logger.error(message, { data }) pattern directly.\n */\nexport abstract class SettingsObject<T extends SettingsObjectSettings = SettingsObjectSettings> {\n name: string\n settings: T\n logger: ReturnType<typeof createLogger>\n\n constructor(name: string, settings: T) {\n this.name = name\n this.settings = settings\n this.logger = createLogger(name)\n }\n}\n"],"names":["process","isBrowser","isNode","isProd","isDev","logLevels","SENSITIVE_KEYS","_Logger","settings","context","__publicField","level","enabled","hostname","currentPriority","minPriority","obj","item","result","key","value","lowerKey","sensitive","data","maxDepth","currentDepth","formatted","entries","maxProperties","config","description","error","levelConfig","prefix","style","ctx","logEntry","chalk","timestamp","dim","colored","logTimestamp","logLevel","logContext","logMessage","contextualLogger","__name","Logger","createLogger","logger","_SettingsObject","name","SettingsObject"],"mappings":"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"}
|