@koderlabs/tasks-sdk-nestjs 0.1.0 → 0.1.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 +187 -5
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,9 +1,191 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @koderlabs/tasks-sdk-nestjs
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
> Runtime: Node.js with NestJS 9+. Server-only. Does not use the core `@koderlabs/tasks-sdk` browser client — uses a server-side management key + direct `fetch` to the InstantTasks ingest API.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
Production-grade observability for NestJS apps: errors, request context,
|
|
6
|
+
breadcrumbs, spans, HTTP tracing, console capture, TypeORM tracing.
|
|
7
|
+
|
|
8
|
+
## Install
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
npm install @koderlabs/tasks-sdk-nestjs
|
|
12
|
+
# or
|
|
13
|
+
pnpm add @koderlabs/tasks-sdk-nestjs
|
|
14
|
+
# or
|
|
15
|
+
yarn add @koderlabs/tasks-sdk-nestjs
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Peer dependencies: `@nestjs/common`, `@nestjs/core`. `typeorm` is an optional
|
|
19
|
+
peer required only when `captureTypeOrm: true`.
|
|
20
|
+
|
|
21
|
+
## Quick start
|
|
22
|
+
|
|
23
|
+
```ts
|
|
24
|
+
import { InstantTasksModule, InstantTasksReportInterceptor } from '@koderlabs/tasks-sdk-nestjs';
|
|
25
|
+
import { APP_INTERCEPTOR } from '@nestjs/core';
|
|
26
|
+
|
|
27
|
+
@Module({
|
|
28
|
+
imports: [
|
|
29
|
+
InstantTasksModule.forRoot({
|
|
30
|
+
apiUrl: process.env.INSTANTTASKS_API_URL!,
|
|
31
|
+
projectId: process.env.INSTANTTASKS_PROJECT_ID!,
|
|
32
|
+
managementKey: process.env.INSTANTTASKS_MANAGEMENT_KEY!,
|
|
33
|
+
environment: process.env.NODE_ENV,
|
|
34
|
+
release: process.env.GIT_SHA,
|
|
35
|
+
|
|
36
|
+
// Opt-in observability — all default false
|
|
37
|
+
captureRequestContext: true,
|
|
38
|
+
captureHttp: true,
|
|
39
|
+
captureConsole: true,
|
|
40
|
+
captureSpans: true,
|
|
41
|
+
captureTypeOrm: true,
|
|
42
|
+
dataSource,
|
|
43
|
+
}),
|
|
44
|
+
],
|
|
45
|
+
providers: [
|
|
46
|
+
{ provide: APP_INTERCEPTOR, useClass: InstantTasksReportInterceptor },
|
|
47
|
+
],
|
|
48
|
+
})
|
|
49
|
+
export class AppModule {}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Options
|
|
53
|
+
|
|
54
|
+
| Option | Type | Default | Purpose |
|
|
55
|
+
|---|---|---|---|
|
|
56
|
+
| `apiUrl` | `string` | — | InstantTasks base URL (no trailing slash; `/api/v1` stripped) |
|
|
57
|
+
| `projectId` | `string` | — | Project UUID |
|
|
58
|
+
| `managementKey` | `string` | — | `sk_*` server key |
|
|
59
|
+
| `environment` | `string` | `process.env.NODE_ENV` | Free-form environment tag |
|
|
60
|
+
| `release` | `string` | `'prod'` | Release identifier (git sha) |
|
|
61
|
+
| `beforeSend` | `(e) => e \| null` | — | Last chance to mutate/drop |
|
|
62
|
+
| `dryRun` | `boolean` | `false` | Skip network — useful in tests |
|
|
63
|
+
| `debug` | `boolean` | `false` | Verbose logs |
|
|
64
|
+
| `captureRequestContext` | `boolean` | `false` | Install ALS middleware capturing method/route/url/ip/userAgent/userId per request |
|
|
65
|
+
| `captureHttp` | `boolean` | `false` | Patch `fetch` + `http.request` + `https.request`, emit `http` breadcrumbs |
|
|
66
|
+
| `captureConsole` | `boolean` | `false` | Patch `console.log/warn/error`, emit `console` breadcrumbs (output preserved; Nest Logger messages skipped) |
|
|
67
|
+
| `captureSpans` | `boolean` | `false` | Wrap every controller call in a `http.<method>.<route>` span attached to the request context |
|
|
68
|
+
| `captureTypeOrm` | `boolean` | `false` | Install a TypeORM `Logger` that emits `db` breadcrumbs + `db.query` spans |
|
|
69
|
+
| `dataSource` | `DataSource` | — | Required when `captureTypeOrm: true` |
|
|
70
|
+
| `ignoreUrls` | `Array<string \| RegExp>` | `[]` | URLs not to record as HTTP breadcrumbs (own ingest is added automatically) |
|
|
71
|
+
| `maxBreadcrumbs` | `number` | `50` | Per-request ring capacity |
|
|
72
|
+
|
|
73
|
+
## How it composes
|
|
74
|
+
|
|
75
|
+
```
|
|
76
|
+
HTTP request
|
|
77
|
+
↓
|
|
78
|
+
RequestContextMiddleware → starts AsyncLocalStorage scope with empty ring
|
|
79
|
+
↓
|
|
80
|
+
SpanInterceptor → records http.<method>.<route> span on success/error
|
|
81
|
+
↓
|
|
82
|
+
your controller
|
|
83
|
+
├─ fetch() → http breadcrumb (sanitized URL, status, durationMs)
|
|
84
|
+
├─ console.log() → console breadcrumb (output still goes to stdout)
|
|
85
|
+
└─ TypeORM query → db breadcrumb + db.query span
|
|
86
|
+
↓
|
|
87
|
+
ReportInterceptor (5xx) → Reporter.reportError() reads ALS, attaches:
|
|
88
|
+
{ request, breadcrumbs, spans } → POST /api/v1/sdk/events
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Out-of-band errors (`uncaughtException`, `unhandledrejection`) still report,
|
|
92
|
+
but without request context — they fire outside any HTTP scope.
|
|
93
|
+
|
|
94
|
+
## Manual breadcrumbs
|
|
95
|
+
|
|
96
|
+
```ts
|
|
97
|
+
import { leaveBreadcrumb } from '@koderlabs/tasks-sdk-nestjs';
|
|
98
|
+
|
|
99
|
+
@Injectable()
|
|
100
|
+
export class MyService {
|
|
101
|
+
doThing() {
|
|
102
|
+
leaveBreadcrumb({ category: 'custom', message: 'started thing', data: { id: 42 } });
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
`leaveBreadcrumb()` is a no-op outside an HTTP request scope.
|
|
108
|
+
|
|
109
|
+
## Gotchas
|
|
110
|
+
|
|
111
|
+
### AsyncLocalStorage doesn't follow detached callbacks
|
|
112
|
+
|
|
113
|
+
Code that escapes the request scope loses the ring:
|
|
114
|
+
|
|
115
|
+
- Bull / BullMQ processors run on a separate event loop tick — wrap your
|
|
116
|
+
handler in `requestContextStorage.run(ring, ...)` if you need breadcrumbs.
|
|
117
|
+
- `setTimeout` scheduled inside a request DOES inherit the scope.
|
|
118
|
+
- Custom EventEmitters that fire after the request response is sent still
|
|
119
|
+
see the scope (memory-leak risk if you hold the ring forever).
|
|
120
|
+
|
|
121
|
+
### Console capture skips Nest Logger output
|
|
122
|
+
|
|
123
|
+
We pattern-match `[Nest]` / `NestApplication` / `RoutesResolver` in the
|
|
124
|
+
first argument and skip those messages. This prevents feedback loops when
|
|
125
|
+
`AllExceptionsFilter` logs via Nest Logger which eventually hits
|
|
126
|
+
`console.error`.
|
|
127
|
+
|
|
128
|
+
### TypeORM Logger is exclusive
|
|
129
|
+
|
|
130
|
+
TypeORM allows exactly one logger per DataSource. `captureTypeOrm: true`
|
|
131
|
+
replaces whatever logger the host configured. If you have a custom logger,
|
|
132
|
+
wrap it instead:
|
|
133
|
+
|
|
134
|
+
```ts
|
|
135
|
+
import { InstantTasksTypeOrmLogger } from '@koderlabs/tasks-sdk-nestjs';
|
|
136
|
+
|
|
137
|
+
class CombinedLogger extends InstantTasksTypeOrmLogger {
|
|
138
|
+
override logQuery(sql, params) {
|
|
139
|
+
super.logQuery(sql, params);
|
|
140
|
+
yourExistingLogger.logQuery(sql, params);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
dataSource.setOptions({ logger: new CombinedLogger() });
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### HTTP tracing patches globals
|
|
147
|
+
|
|
148
|
+
Patches `globalThis.fetch` and `require('http')`/`https`.`request`.
|
|
149
|
+
Idempotent via a Symbol sentinel — calling `installHttpTracing()` twice is
|
|
150
|
+
safe. Restores on `onModuleDestroy`.
|
|
151
|
+
|
|
152
|
+
Sanitization mirrors `@koderlabs/tasks-sdk-web-network`:
|
|
153
|
+
- `Authorization`, `Cookie`, `Set-Cookie`, `X-Auth-Token`,
|
|
154
|
+
`Proxy-Authorization` headers → `[Filtered]`
|
|
155
|
+
- `?token=…`, `?access_token=…`, `?api_key=…`, `?secret=…` query values → `[Filtered]`
|
|
156
|
+
|
|
157
|
+
The SDK's own ingest endpoint (`/api/v1/sdk/`) is added to `ignoreUrls`
|
|
158
|
+
automatically to avoid recursion.
|
|
159
|
+
|
|
160
|
+
### Span interceptor only runs in HTTP context
|
|
161
|
+
|
|
162
|
+
Skipped for WebSocket, GraphQL, microservice transports. If you need spans
|
|
163
|
+
for those, wire your own interceptor and call `getCurrentContext()?.addSpan()`.
|
|
164
|
+
|
|
165
|
+
## Tests
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
pnpm --filter @koderlabs/tasks-sdk-nestjs test
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
19 tests cover: breadcrumb ring isolation, request-context middleware,
|
|
172
|
+
fetch tracing, console capture, span interceptor, end-to-end integration
|
|
173
|
+
with all flags wired.
|
|
174
|
+
|
|
175
|
+
## Default-off principle
|
|
176
|
+
|
|
177
|
+
Every new capability defaults to `false`. With no flags set, behaviour is
|
|
178
|
+
identical to the MVP — only `uncaughtException`, `unhandledRejection`, and
|
|
179
|
+
5xx HTTP responses get reported. Enable features incrementally.
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
## Suite overview
|
|
184
|
+
|
|
185
|
+
Full SDK suite map + platform availability matrix: [docs/sdk/overview.md](https://github.com/jawaidgadiwala/instant-tasks/blob/main/docs/sdk/overview.md).
|
|
186
|
+
|
|
187
|
+
## License
|
|
188
|
+
|
|
189
|
+
KoderLabs proprietary. See [`LICENSE`](./LICENSE) for terms. Use of this package requires a separate signed written agreement with KoderLabs; access alone confers no rights.
|
|
8
190
|
|
|
9
191
|
Licensing inquiries: jawaidgadiwala@gmail.com
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@koderlabs/tasks-sdk-nestjs",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "NestJS module for InstantTasks — reporter + interceptor + breadcrumbs + req context + http/console/spans/typeorm tracing.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"instanttasks",
|
|
@@ -58,7 +58,7 @@
|
|
|
58
58
|
"node": ">=20"
|
|
59
59
|
},
|
|
60
60
|
"publishConfig": {
|
|
61
|
-
"access": "
|
|
61
|
+
"access": "public"
|
|
62
62
|
},
|
|
63
63
|
"scripts": {
|
|
64
64
|
"build": "tsup",
|