@dasasian/firebase-structured-logger 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.
Files changed (69) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +228 -0
  3. package/dist/client/breadcrumbs.d.ts +15 -0
  4. package/dist/client/breadcrumbs.d.ts.map +1 -0
  5. package/dist/client/breadcrumbs.js +52 -0
  6. package/dist/client/breadcrumbs.js.map +1 -0
  7. package/dist/client/errorHandler.d.ts +5 -0
  8. package/dist/client/errorHandler.d.ts.map +1 -0
  9. package/dist/client/errorHandler.js +19 -0
  10. package/dist/client/errorHandler.js.map +1 -0
  11. package/dist/client/index.d.ts +6 -0
  12. package/dist/client/index.d.ts.map +1 -0
  13. package/dist/client/index.js +16 -0
  14. package/dist/client/index.js.map +1 -0
  15. package/dist/client/logger.d.ts +40 -0
  16. package/dist/client/logger.d.ts.map +1 -0
  17. package/dist/client/logger.js +199 -0
  18. package/dist/client/logger.js.map +1 -0
  19. package/dist/client/rateLimiter.d.ts +12 -0
  20. package/dist/client/rateLimiter.d.ts.map +1 -0
  21. package/dist/client/rateLimiter.js +80 -0
  22. package/dist/client/rateLimiter.js.map +1 -0
  23. package/dist/functions/index.d.ts +12 -0
  24. package/dist/functions/index.d.ts.map +1 -0
  25. package/dist/functions/index.js +21 -0
  26. package/dist/functions/index.js.map +1 -0
  27. package/dist/functions/logHandler.d.ts +27 -0
  28. package/dist/functions/logHandler.d.ts.map +1 -0
  29. package/dist/functions/logHandler.js +137 -0
  30. package/dist/functions/logHandler.js.map +1 -0
  31. package/dist/functions/logger.d.ts +32 -0
  32. package/dist/functions/logger.d.ts.map +1 -0
  33. package/dist/functions/logger.js +253 -0
  34. package/dist/functions/logger.js.map +1 -0
  35. package/dist/functions/requestLogger.d.ts +30 -0
  36. package/dist/functions/requestLogger.d.ts.map +1 -0
  37. package/dist/functions/requestLogger.js +45 -0
  38. package/dist/functions/requestLogger.js.map +1 -0
  39. package/dist/functions/sourceMapCache.d.ts +9 -0
  40. package/dist/functions/sourceMapCache.d.ts.map +1 -0
  41. package/dist/functions/sourceMapCache.js +107 -0
  42. package/dist/functions/sourceMapCache.js.map +1 -0
  43. package/dist/functions/symbolicate.d.ts +31 -0
  44. package/dist/functions/symbolicate.d.ts.map +1 -0
  45. package/dist/functions/symbolicate.js +112 -0
  46. package/dist/functions/symbolicate.js.map +1 -0
  47. package/dist/shared/types.d.ts +36 -0
  48. package/dist/shared/types.d.ts.map +1 -0
  49. package/dist/shared/types.js +3 -0
  50. package/dist/shared/types.js.map +1 -0
  51. package/dist/tools/index.d.ts +3 -0
  52. package/dist/tools/index.d.ts.map +1 -0
  53. package/dist/tools/index.js +152 -0
  54. package/dist/tools/index.js.map +1 -0
  55. package/dist/tools/installSkills.d.ts +6 -0
  56. package/dist/tools/installSkills.d.ts.map +1 -0
  57. package/dist/tools/installSkills.js +89 -0
  58. package/dist/tools/installSkills.js.map +1 -0
  59. package/dist/tools/packDeploy.d.ts +15 -0
  60. package/dist/tools/packDeploy.d.ts.map +1 -0
  61. package/dist/tools/packDeploy.js +148 -0
  62. package/dist/tools/packDeploy.js.map +1 -0
  63. package/dist/tools/uploadSourceMaps.d.ts +9 -0
  64. package/dist/tools/uploadSourceMaps.d.ts.map +1 -0
  65. package/dist/tools/uploadSourceMaps.js +120 -0
  66. package/dist/tools/uploadSourceMaps.js.map +1 -0
  67. package/package.json +103 -0
  68. package/skills/logs/SKILL.md +185 -0
  69. package/skills/query-logs/SKILL.md +93 -0
@@ -0,0 +1,185 @@
1
+ # /logs — Logging Validation Skill
2
+
3
+ Validate frontend and backend logging implementation for a given file.
4
+
5
+ ---
6
+
7
+ ## Phase 0 — Detect File Type
8
+
9
+ Identify whether the target file is frontend or backend:
10
+
11
+ **Frontend:** path starts with `src/`, imports from `firebase-structured-logger/client`, uses `logError/logWarn/logInfo/logDebug` or `bc.*`
12
+ **Backend:** path starts with `functions/src/`, imports from `firebase-structured-logger/functions`, uses `initRequestLogger/getLogger/logError/logWarn/logInfo/logDebug`
13
+
14
+ ---
15
+
16
+ ## Phase 1 — Delegate to Explore Agent
17
+
18
+ **Never analyze directly — always delegate to preserve main conversation context.**
19
+
20
+ Build a task for the Explore agent:
21
+
22
+ ```
23
+ Read these files:
24
+ 1. src/main.tsx (or app entry point) — find initLogger<AppLabels>() call, identify AppLabels type name
25
+ 2. The AppLabels type definition file — read all label field names
26
+ 3. [TARGET_FILE] — the file to analyze
27
+
28
+ File type: [FRONTEND|BACKEND]
29
+
30
+ Report back:
31
+ - AppLabels type name and all its fields
32
+ - For BACKEND: also note which AppLabels fields appear in request.data or function params
33
+ - Full contents of the target file with line numbers
34
+ ```
35
+
36
+ ---
37
+
38
+ ## Phase 2 — Analyze
39
+
40
+ Using the Explore agent's output, check the target file against the rules below.
41
+
42
+ ---
43
+
44
+ ### Frontend Rules
45
+
46
+ **Imports**
47
+ - Must use `logError/logWarn/logInfo/logDebug` from the project's logger utility (e.g. `src/utils/logger.ts`)
48
+ - Must use `bc` from `firebase-structured-logger/client` for breadcrumbs
49
+ - Never use `console.error()` directly — always use the logger
50
+
51
+ **Error paths**
52
+ - Every `catch` block must call `logError`
53
+ - `logError` accepts `unknown` — never cast with `as Error`
54
+ - Do not pass `errorType` explicitly unless overriding the auto-derived value from `error.name`
55
+
56
+ **Breadcrumbs**
57
+
58
+ Breadcrumbs reconstruct what the user was doing before an error — a session timeline, not just a wrapper around service calls. They belong primarily in components and screens, not service files.
59
+
60
+ UX-layer breadcrumbs to check for (flag if missing):
61
+ - Screen/route changes → `bc.nav('ScreenName')`
62
+ - Modal open/close → `bc.action('open_item_modal', { itemId })`
63
+ - Tab switches → `bc.action('switch_tab', { tab })`
64
+ - Explicit user decisions → `bc.action('merge_chosen')`, `bc.action('discard_changes')`
65
+ - Scan/camera events → `bc.action('barcode_scanned', { barcode })`
66
+
67
+ Service-layer breadcrumbs (secondary — useful but not sufficient on their own):
68
+ - Before a Firestore/API call → `bc.action('save_item', { itemId })`
69
+ - On error → `bc.error('save_failed', { itemId })`
70
+
71
+ **A component file with no UX-layer breadcrumbs is almost certainly missing them. A service file with only service-layer breadcrumbs may be fine.**
72
+
73
+ API:
74
+ - `bc.action(name: string, data?)` — user-initiated operations and decisions
75
+ - `bc.state(name: string, data?)` — significant state changes
76
+ - `bc.nav(screen: string)` — screen/route changes
77
+ - `bc.error(type: string, data?)` — when an error occurs
78
+
79
+ **Label completeness**
80
+ - For each function, check which `AppLabels` fields are in scope as variables
81
+ - Flag any that are not passed to the log call
82
+
83
+ **Rate limiting**
84
+ - Never log inside loops
85
+ - Never log on every keystroke or render
86
+
87
+ **PII**
88
+ - No email, name, address in labels or context
89
+ - `userId` is OK; full user objects are not
90
+
91
+ ---
92
+
93
+ ### Backend Rules
94
+
95
+ **Imports**
96
+ - Must import from `firebase-structured-logger/functions`
97
+ - Use `logError/logWarn/logInfo/logDebug` — never `console.log/console.error` directly
98
+
99
+ **`initRequestLogger` — mandatory at function entry**
100
+ - Every `onCall` handler must call `initRequestLogger<AppLabels>(request, { functionName, labels })` as the first line
101
+ - Auto-seeds `userId` and `functionName` — do not pass these manually in labels
102
+ - Any `AppLabels` fields present in `request.data` or function params should be passed in `labels`
103
+ - Flag missing `initRequestLogger` as a critical violation
104
+
105
+ **Error paths**
106
+ - Every `catch` block must call `logError`
107
+ - `logError` accepts `unknown` — never cast with `as Error`
108
+ - Do not pass `errorType` explicitly unless overriding the auto-derived value from `error.name`
109
+
110
+ **Label completeness**
111
+ - For each log call, check which `AppLabels` fields are in scope
112
+ - Fields already seeded via `initRequestLogger` labels do not need repeating
113
+ - Flag any in-scope fields not seeded at entry or passed on the log call
114
+
115
+ **PII**
116
+ - Same rules as frontend
117
+
118
+ ---
119
+
120
+ ## Output Format
121
+
122
+ Report in three sections:
123
+
124
+ ### Violations
125
+ ```
126
+ Line <N>: <description>
127
+ ```
128
+
129
+ ### Missing Logging
130
+ ```
131
+ Line <N>: <what should be logged and why>
132
+ ```
133
+
134
+ ### Label Completeness
135
+ ```
136
+ Function <name>: missing labels [<label1>, <label2>] — these entities are in scope
137
+ ```
138
+
139
+ If no issues found in a section, write "None."
140
+
141
+ ---
142
+
143
+ ## Phase 3 — Fix
144
+
145
+ When asked to fix violations found in Phase 2, use the FSL API Reference below. Do not read `firebase-structured-logger` source files — the reference is authoritative.
146
+
147
+ ---
148
+
149
+ ## FSL API Reference
150
+
151
+ ### Frontend
152
+ Import from project logger utility (e.g. `src/utils/logger.ts`):
153
+ ```ts
154
+ logError(raw: unknown, labels?: Partial<AppLabels>, context?: Record<string, unknown>, attachments?: Record<string, Blob | File | string>): Promise<void>
155
+ logWarn(message: string, labels?: Partial<AppLabels>, context?: Record<string, unknown>, attachments?: Record<string, Blob | File | string>): Promise<void>
156
+ logInfo(message: string, labels?: Partial<AppLabels>, context?: Record<string, unknown>, attachments?: Record<string, Blob | File | string>): Promise<void>
157
+ logDebug(message: string, labels?: Partial<AppLabels>, context?: Record<string, unknown>, attachments?: Record<string, Blob | File | string>): Promise<void>
158
+ ```
159
+
160
+ Import `bc` from `firebase-structured-logger/client`:
161
+ ```ts
162
+ bc.action(name: string, data?: Record<string, unknown>): void // before operations
163
+ bc.state(name: string, data?: Record<string, unknown>): void // on state changes
164
+ bc.nav(screen: string): void // on navigation
165
+ bc.error(type: string, data?: Record<string, unknown>): void // on errors
166
+ ```
167
+
168
+ ### Backend
169
+ Import from `firebase-structured-logger/functions`:
170
+ ```ts
171
+ // Call first in every onCall handler — auto-seeds userId and functionName
172
+ initRequestLogger<AppLabels>(request, { functionName: 'myFunc', labels: { organizationId: request.data.organizationId } })
173
+
174
+ logError(raw: unknown, labels?: Record<string, string | undefined>, context?: Record<string, unknown>, attachments?: Record<string, string | Buffer>): void
175
+ logWarn(message: string, labels?: Record<string, string | undefined>, context?: Record<string, unknown>, attachments?: Record<string, string | Buffer>): void
176
+ logInfo(message: string, labels?: Record<string, string | undefined>, context?: Record<string, unknown>, attachments?: Record<string, string | Buffer>): void
177
+ logDebug(message: string, labels?: Record<string, string | undefined>, context?: Record<string, unknown>, attachments?: Record<string, string | Buffer>): void
178
+ ```
179
+
180
+ ### Key behaviours
181
+ - `logError` auto-derives `errorType` from `error.name` — only pass explicitly to override (e.g. `{ errorType: 'DatabaseError' }`)
182
+ - `logError` accepts `unknown` — never cast with `as Error`
183
+ - `initRequestLogger` auto-seeds `userId` (from `request.auth.uid`) and `functionName` — do not pass these in labels
184
+ - Every log entry includes `labels.logId` (ULID) — if `attachments` are passed, they are uploaded to GCS at `logAttachments/{logId}/{name}` fire-and-forget; upload failure never blocks the log entry
185
+ - When catching an error, check if there are attachments in scope (images, file snapshots, captured data) that would help reproduce or diagnose it — if so, pass them via `attachments`
@@ -0,0 +1,93 @@
1
+ # /query-logs — Cloud Logging Query Skill
2
+
3
+ Query structured logs written by firebase-structured-logger using the firebase-mcp-server.
4
+
5
+ ## Setup
6
+
7
+ The `firebase_functions_logs` MCP tool reads from:
8
+ - **Production**: Google Cloud Logging (default)
9
+ - **Development**: Local JSONL file when `DEV_LOG_FILE` env var is set in the MCP server
10
+
11
+ ## Queryable Labels
12
+
13
+ All entries written by firebase-structured-logger include these labels:
14
+
15
+ | Label | Description |
16
+ |-------|-------------|
17
+ | `appId` | Application identifier (e.g. `acme`, `store`) |
18
+ | `userId` | Firebase Auth UID |
19
+ | `screen` | Current screen name |
20
+ | `releaseId` | Git short hash or explicit release ID |
21
+ | `platform` | `ios`, `android`, `macos`, `windows`, `web` |
22
+ | `browser` | `chrome`, `firefox`, `safari`, `edge` |
23
+ | `errorType` | Error class name (e.g. `TypeError`, `NetworkError`) |
24
+ | `errorCategory` | `crash` for unhandled errors |
25
+ | `functionName` | Cloud Function name (server-side logs only) |
26
+ | `logId` | ULID — unique per log entry, used to locate attachments in GCS |
27
+ | `hasAttachments` | `'true'` when attachments were uploaded alongside this entry |
28
+
29
+ App-specific labels are defined in each app's `AppLabels` type.
30
+
31
+ ## Common Queries
32
+
33
+ ### All errors for a user
34
+ ```
35
+ labels.userId="<uid>" severity=ERROR
36
+ ```
37
+
38
+ ### Errors on a specific screen
39
+ ```
40
+ labels.screen="<screen>" severity=ERROR
41
+ ```
42
+
43
+ ### Unhandled crashes
44
+ ```
45
+ labels.errorCategory="crash"
46
+ ```
47
+
48
+ ### Logs from a specific release
49
+ ```
50
+ labels.releaseId="<hash>"
51
+ ```
52
+
53
+ ### Recent errors (last hour)
54
+ ```
55
+ severity=ERROR timestamp>="<ISO8601>"
56
+ ```
57
+
58
+ ## Retrieving Attachments
59
+
60
+ When a log entry has `labels.hasAttachments = "true"`, files were uploaded to GCS alongside it.
61
+
62
+ **Step 1 — Find entries with attachments:**
63
+ ```
64
+ labels.hasAttachments="true"
65
+ ```
66
+
67
+ **Step 2 — List attachments for an entry:**
68
+
69
+ Use `firebase_storage_ls` with the path `logAttachments/{logId}/` to see what files are present.
70
+
71
+ **Step 3 — Download and analyze:**
72
+
73
+ Use `firebase_storage_read` with path `logAttachments/{logId}/{filename}` — this downloads the file to `/tmp` and returns a `tempPath`. Then use the `Read` tool on `tempPath` to analyze the content.
74
+
75
+ **Example flow:**
76
+ ```
77
+ 1. Query logs → find entry with logId "01KJBK2QBC5GJGMYZ5GT1Q5TQ6"
78
+ 2. firebase_storage_ls path: "logAttachments/01KJBK2QBC5GJGMYZ5GT1Q5TQ6/"
79
+ 3. firebase_storage_read path: "logAttachments/01KJBK2QBC5GJGMYZ5GT1Q5TQ6/photo.jpg"
80
+ 4. Read tool on tempPath → analyze image in context of the error
81
+ ```
82
+
83
+ Only check GCS when `hasAttachments = "true"` — entries without it have no files.
84
+
85
+ ---
86
+
87
+ ## Development (Local JSONL)
88
+
89
+ When running with Firebase Emulator, logs are written to the path configured in `initLogger({ devLogFile })`.
90
+
91
+ Set `DEV_LOG_FILE=/path/to/logs.jsonl` in the MCP server environment to enable local log reading.
92
+
93
+ Each JSONL line is a JSON object matching Cloud Logging structure for query compatibility.