@a-company/paradigm 1.5.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/README.md +142 -0
- package/dist/accept-orchestration-CWZNCGZX.js +188 -0
- package/dist/agents-suggest-35LIQKDH.js +83 -0
- package/dist/aggregate-W7Q6VIM2.js +88 -0
- package/dist/auto-IU7VN55K.js +470 -0
- package/dist/beacon-B47XSTL7.js +251 -0
- package/dist/chunk-2M6OSOIG.js +1302 -0
- package/dist/chunk-4NCFWYGG.js +110 -0
- package/dist/chunk-5C4SGQKH.js +705 -0
- package/dist/chunk-5GOA7WYD.js +1095 -0
- package/dist/chunk-5JGJACDU.js +37 -0
- package/dist/chunk-6QC3YGB6.js +114 -0
- package/dist/chunk-753RICFF.js +325 -0
- package/dist/chunk-AD2LSCHB.js +1595 -0
- package/dist/chunk-CHSHON3O.js +669 -0
- package/dist/chunk-ELLR7WP6.js +3175 -0
- package/dist/chunk-ILOWBJRC.js +12 -0
- package/dist/chunk-IRKUEJVW.js +405 -0
- package/dist/chunk-MC7XC7XQ.js +533 -0
- package/dist/chunk-MO4EEYFW.js +38 -0
- package/dist/chunk-MQWH7PFI.js +13366 -0
- package/dist/chunk-N6PJAPDE.js +364 -0
- package/dist/chunk-PBHIFAL4.js +259 -0
- package/dist/chunk-PMXRGPRQ.js +305 -0
- package/dist/chunk-PW2EXJQT.js +689 -0
- package/dist/chunk-TAP5N3HH.js +245 -0
- package/dist/chunk-THFVK5AE.js +148 -0
- package/dist/chunk-UM54F7G5.js +1533 -0
- package/dist/chunk-UUZ2DMG5.js +185 -0
- package/dist/chunk-WS5KM7OL.js +780 -0
- package/dist/chunk-YDNKXH4Z.js +2316 -0
- package/dist/chunk-YO6DVTL7.js +99 -0
- package/dist/claude-SUYNN72C.js +362 -0
- package/dist/claude-cli-OF43XAO3.js +276 -0
- package/dist/claude-code-PW6SKD2M.js +126 -0
- package/dist/claude-code-teams-JLZ5IXB6.js +199 -0
- package/dist/constellation-K3CIQCHI.js +225 -0
- package/dist/cost-AEK6R7HK.js +174 -0
- package/dist/cost-KYXIQ62X.js +93 -0
- package/dist/cursor-cli-IHJMPRCW.js +269 -0
- package/dist/cursorrules-KI5QWHIX.js +84 -0
- package/dist/diff-AJJ5H6HV.js +125 -0
- package/dist/dist-7MPIRMTZ-IOQOREMZ.js +10866 -0
- package/dist/dist-NHJQVVUW.js +68 -0
- package/dist/dist-ZEMSQV74.js +20 -0
- package/dist/doctor-6Y6L6HEB.js +11 -0
- package/dist/echo-VYZW3OTT.js +248 -0
- package/dist/export-R4FJ5NOH.js +38 -0
- package/dist/history-EVO3L6SC.js +277 -0
- package/dist/hooks-MBWE4ILT.js +12 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +568 -0
- package/dist/lint-HXKTWRNO.js +316 -0
- package/dist/manual-Y3QOXWYA.js +204 -0
- package/dist/mcp.js +14745 -0
- package/dist/orchestrate-4ZH5GUQH.js +323 -0
- package/dist/probe-OYCP4JYG.js +151 -0
- package/dist/promote-Z52ZJTJU.js +181 -0
- package/dist/providers-4PGPZEWP.js +104 -0
- package/dist/remember-6VZ74B7E.js +77 -0
- package/dist/ripple-SBQOSTZD.js +215 -0
- package/dist/sentinel-LCFD56OJ.js +43 -0
- package/dist/server-F5ITNK6T.js +9846 -0
- package/dist/server-T6WIFYRQ.js +16076 -0
- package/dist/setup-DF4F3ICN.js +25 -0
- package/dist/setup-JHBPZAG7.js +296 -0
- package/dist/shift-HKIAP4ZN.js +226 -0
- package/dist/snapshot-GTVPRYZG.js +62 -0
- package/dist/spawn-BJRQA2NR.js +196 -0
- package/dist/summary-H6J6N6PJ.js +140 -0
- package/dist/switch-6EANJ7O6.js +232 -0
- package/dist/sync-BEOCW7TZ.js +11 -0
- package/dist/team-NWP2KJAB.js +32 -0
- package/dist/test-MA5TWJQV.js +934 -0
- package/dist/thread-JCJVRUQR.js +258 -0
- package/dist/triage-ETVXXFMV.js +1880 -0
- package/dist/tutorial-L5Q3ZDHK.js +666 -0
- package/dist/university-R2WDQLSI.js +40 -0
- package/dist/upgrade-5B3YGGC6.js +550 -0
- package/dist/validate-F3YHBCRZ.js +39 -0
- package/dist/validate-QEEY6KFS.js +64 -0
- package/dist/watch-4LT4O6K7.js +123 -0
- package/dist/watch-6IIWPWDN.js +111 -0
- package/dist/wisdom-LRM4FFCH.js +319 -0
- package/package.json +68 -0
- package/templates/paradigm/config.yaml +175 -0
- package/templates/paradigm/docs/commands.md +727 -0
- package/templates/paradigm/docs/decisions/000-template.md +47 -0
- package/templates/paradigm/docs/decisions/README.md +26 -0
- package/templates/paradigm/docs/error-patterns.md +215 -0
- package/templates/paradigm/docs/patterns.md +358 -0
- package/templates/paradigm/docs/queries.md +200 -0
- package/templates/paradigm/docs/troubleshooting.md +477 -0
- package/templates/paradigm/echoes.yaml +25 -0
- package/templates/paradigm/prompts/add-feature.md +152 -0
- package/templates/paradigm/prompts/add-gate.md +117 -0
- package/templates/paradigm/prompts/debug-auth.md +174 -0
- package/templates/paradigm/prompts/implement-ftux.md +722 -0
- package/templates/paradigm/prompts/implement-sandbox.md +651 -0
- package/templates/paradigm/prompts/read-docs.md +84 -0
- package/templates/paradigm/prompts/refactor.md +106 -0
- package/templates/paradigm/prompts/run-e2e-tests.md +340 -0
- package/templates/paradigm/prompts/trace-flow.md +202 -0
- package/templates/paradigm/prompts/validate-portals.md +279 -0
- package/templates/paradigm/specs/context-tracking.md +200 -0
- package/templates/paradigm/specs/context.md +461 -0
- package/templates/paradigm/specs/disciplines.md +413 -0
- package/templates/paradigm/specs/history.md +339 -0
- package/templates/paradigm/specs/logger.md +303 -0
- package/templates/paradigm/specs/navigator.md +236 -0
- package/templates/paradigm/specs/purpose.md +265 -0
- package/templates/paradigm/specs/scan.md +177 -0
- package/templates/paradigm/specs/symbols.md +451 -0
- package/templates/paradigm/specs/wisdom.md +294 -0
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# ADR 000: [Title]
|
|
2
|
+
|
|
3
|
+
**Status:** Proposed | Accepted | Deprecated | Superseded
|
|
4
|
+
**Date:** YYYY-MM-DD
|
|
5
|
+
**Decision Makers:** [Names]
|
|
6
|
+
|
|
7
|
+
## Context
|
|
8
|
+
|
|
9
|
+
[What is the issue that we're seeing that motivates this decision?]
|
|
10
|
+
|
|
11
|
+
## Decision
|
|
12
|
+
|
|
13
|
+
[What is the change that we're proposing and/or doing?]
|
|
14
|
+
|
|
15
|
+
## Rationale
|
|
16
|
+
|
|
17
|
+
[Why did we choose this option? What factors were considered?]
|
|
18
|
+
|
|
19
|
+
| Factor | Option A | Option B | Winner |
|
|
20
|
+
|--------|----------|----------|--------|
|
|
21
|
+
| [Factor 1] | ... | ... | ... |
|
|
22
|
+
|
|
23
|
+
## Consequences
|
|
24
|
+
|
|
25
|
+
### Positive
|
|
26
|
+
- [Benefit 1]
|
|
27
|
+
- [Benefit 2]
|
|
28
|
+
|
|
29
|
+
### Negative
|
|
30
|
+
- [Drawback 1]
|
|
31
|
+
- [Drawback 2]
|
|
32
|
+
|
|
33
|
+
### Mitigations
|
|
34
|
+
- [How we'll handle negative consequences]
|
|
35
|
+
|
|
36
|
+
## Alternatives Considered
|
|
37
|
+
|
|
38
|
+
[What other options were considered and why were they rejected?]
|
|
39
|
+
|
|
40
|
+
## References
|
|
41
|
+
|
|
42
|
+
- [Link to relevant documentation]
|
|
43
|
+
- [Link to related ADRs]
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
*ADR format based on [Michael Nygard's template](https://cognitect.com/blog/2011/11/15/documenting-architecture-decisions)*
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Architecture Decision Records (ADRs)
|
|
2
|
+
|
|
3
|
+
This directory contains Architecture Decision Records that document significant technical decisions made in this project.
|
|
4
|
+
|
|
5
|
+
## What is an ADR?
|
|
6
|
+
|
|
7
|
+
An ADR captures a single decision about the architecture or design of the system. It explains:
|
|
8
|
+
- **Context:** What problem or situation prompted the decision?
|
|
9
|
+
- **Decision:** What was decided?
|
|
10
|
+
- **Consequences:** What are the trade-offs?
|
|
11
|
+
|
|
12
|
+
## ADR Template
|
|
13
|
+
|
|
14
|
+
Copy `000-template.md` when creating a new ADR.
|
|
15
|
+
|
|
16
|
+
## Index
|
|
17
|
+
|
|
18
|
+
| # | Title | Status | Date |
|
|
19
|
+
|---|-------|--------|------|
|
|
20
|
+
| 000 | Template | Template | - |
|
|
21
|
+
|
|
22
|
+
*Add new ADRs to this index.*
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
*Part of Paradigm v1.0*
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
# Error Patterns
|
|
2
|
+
|
|
3
|
+
> Standard error handling across the project (Language-Agnostic)
|
|
4
|
+
|
|
5
|
+
## Error Response Format
|
|
6
|
+
|
|
7
|
+
All APIs/services return errors in this format:
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
// Error response
|
|
11
|
+
{
|
|
12
|
+
error: string // Human-readable message
|
|
13
|
+
code?: string // Machine-readable code (optional)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// Success response
|
|
17
|
+
{
|
|
18
|
+
success?: true // Optional confirmation
|
|
19
|
+
data?: any // Response payload
|
|
20
|
+
}
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Standard Error Codes
|
|
24
|
+
|
|
25
|
+
| Code | Meaning | When to Use |
|
|
26
|
+
|------|---------|-------------|
|
|
27
|
+
| `INVALID_REQUEST` | Malformed input | Missing fields, wrong types |
|
|
28
|
+
| `INVALID_CREDENTIALS` | Auth validation failed | Wrong password, expired token |
|
|
29
|
+
| `UNAUTHORIZED` | Not authenticated | Missing/expired session |
|
|
30
|
+
| `FORBIDDEN` | Authenticated but denied | Insufficient permissions |
|
|
31
|
+
| `NOT_FOUND` | Resource doesn't exist | Unknown ID, deleted item |
|
|
32
|
+
| `CONFLICT` | State conflict | Duplicate entry, version mismatch |
|
|
33
|
+
| `RATE_LIMITED` | Too many requests | Brute force protection |
|
|
34
|
+
| `SERVER_ERROR` | Internal error | Database down, unexpected crash |
|
|
35
|
+
| `UNAVAILABLE` | Service unavailable | Maintenance, overloaded |
|
|
36
|
+
|
|
37
|
+
## Patterns (Pseudocode)
|
|
38
|
+
|
|
39
|
+
### Basic Error Return
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
// Simple error
|
|
43
|
+
return error_response("Invalid request", status=400)
|
|
44
|
+
|
|
45
|
+
// With code
|
|
46
|
+
return error_response("Too many attempts", code="RATE_LIMITED", status=429)
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Input Validation
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
function handle_request(request):
|
|
53
|
+
data = parse_json(request.body)
|
|
54
|
+
|
|
55
|
+
if data is null:
|
|
56
|
+
return error_response("Invalid request body", status=400)
|
|
57
|
+
|
|
58
|
+
if not valid_email(data.email):
|
|
59
|
+
return error_response("Valid email required", status=400)
|
|
60
|
+
|
|
61
|
+
// Continue processing...
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Auth Check
|
|
65
|
+
|
|
66
|
+
```
|
|
67
|
+
function require_auth(request):
|
|
68
|
+
user = get_user_from_session(request)
|
|
69
|
+
|
|
70
|
+
if user is null:
|
|
71
|
+
return error_response("Unauthorized", status=401)
|
|
72
|
+
|
|
73
|
+
return user
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### Resource Access
|
|
77
|
+
|
|
78
|
+
```
|
|
79
|
+
function get_resource(id):
|
|
80
|
+
resource = database.find(id)
|
|
81
|
+
|
|
82
|
+
if resource is null:
|
|
83
|
+
return error_response("Not found", status=404)
|
|
84
|
+
|
|
85
|
+
if not user_can_access(resource):
|
|
86
|
+
return error_response("Forbidden", status=403)
|
|
87
|
+
|
|
88
|
+
return success_response(resource)
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Database Operations
|
|
92
|
+
|
|
93
|
+
```
|
|
94
|
+
function query_database(query, params):
|
|
95
|
+
try:
|
|
96
|
+
result = db.execute(query, params)
|
|
97
|
+
return result
|
|
98
|
+
catch DatabaseError as error:
|
|
99
|
+
log.component('#database').error('Query failed', { error })
|
|
100
|
+
return error_response("Database error", status=500)
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Error Handling Flow
|
|
104
|
+
|
|
105
|
+
```
|
|
106
|
+
┌─────────────────┐
|
|
107
|
+
│ Receive Input │
|
|
108
|
+
└────────┬────────┘
|
|
109
|
+
▼
|
|
110
|
+
┌─────────────────┐ ┌─────────────────┐
|
|
111
|
+
│ Validate Input │────▶│ 400 Bad Request │
|
|
112
|
+
└────────┬────────┘ no └─────────────────┘
|
|
113
|
+
│ yes
|
|
114
|
+
▼
|
|
115
|
+
┌─────────────────┐ ┌─────────────────┐
|
|
116
|
+
│ Check Auth │────▶│ 401 Unauthorized│
|
|
117
|
+
└────────┬────────┘ no └─────────────────┘
|
|
118
|
+
│ yes
|
|
119
|
+
▼
|
|
120
|
+
┌─────────────────┐ ┌─────────────────┐
|
|
121
|
+
│ Check Permission│────▶│ 403 Forbidden │
|
|
122
|
+
└────────┬────────┘ no └─────────────────┘
|
|
123
|
+
│ yes
|
|
124
|
+
▼
|
|
125
|
+
┌─────────────────┐ ┌─────────────────┐
|
|
126
|
+
│ Find Resource │────▶│ 404 Not Found │
|
|
127
|
+
└────────┬────────┘ no └─────────────────┘
|
|
128
|
+
│ yes
|
|
129
|
+
▼
|
|
130
|
+
┌─────────────────┐ ┌─────────────────┐
|
|
131
|
+
│ Execute Action │────▶│ 500 Server Error│
|
|
132
|
+
└────────┬────────┘ fail└─────────────────┘
|
|
133
|
+
│ ok
|
|
134
|
+
▼
|
|
135
|
+
┌─────────────────┐
|
|
136
|
+
│ 200 Success │
|
|
137
|
+
└─────────────────┘
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## Logging Errors
|
|
141
|
+
|
|
142
|
+
Always use the Paradigm logger:
|
|
143
|
+
|
|
144
|
+
```
|
|
145
|
+
// Component context (features)
|
|
146
|
+
log.component('#checkout').error('Payment failed', { reason, order_id })
|
|
147
|
+
|
|
148
|
+
// Component context (infrastructure)
|
|
149
|
+
log.component('#database').error('Connection lost', { host })
|
|
150
|
+
|
|
151
|
+
// Gate context
|
|
152
|
+
log.gate('^auth').warn('Access denied', { user_id, resource })
|
|
153
|
+
|
|
154
|
+
// Component context (integrations)
|
|
155
|
+
log.component('#stripe-client').error('API error', { status, message })
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## Graceful Degradation
|
|
159
|
+
|
|
160
|
+
When non-critical features fail, don't block the user:
|
|
161
|
+
|
|
162
|
+
```
|
|
163
|
+
// Bad: crashes if optional feature fails
|
|
164
|
+
data = fetch_optional_feature() // throws on error
|
|
165
|
+
|
|
166
|
+
// Good: graceful fallback
|
|
167
|
+
data = null
|
|
168
|
+
try:
|
|
169
|
+
data = fetch_optional_feature()
|
|
170
|
+
catch:
|
|
171
|
+
log.component('#optional').debug('Feature unavailable, using fallback')
|
|
172
|
+
|
|
173
|
+
// Continue with or without optional data
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
## Client-Side Handling
|
|
177
|
+
|
|
178
|
+
```
|
|
179
|
+
function api_call(endpoint, options):
|
|
180
|
+
try:
|
|
181
|
+
response = http.request(endpoint, options)
|
|
182
|
+
|
|
183
|
+
if not response.ok:
|
|
184
|
+
return { error: response.data.error or "Request failed" }
|
|
185
|
+
|
|
186
|
+
return { data: response.data }
|
|
187
|
+
catch NetworkError:
|
|
188
|
+
return { error: "Connection error" }
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
## Error State in UI
|
|
192
|
+
|
|
193
|
+
```
|
|
194
|
+
// State
|
|
195
|
+
error = null
|
|
196
|
+
|
|
197
|
+
function submit():
|
|
198
|
+
error = null // Clear previous error
|
|
199
|
+
|
|
200
|
+
result = api_call('/endpoint', data)
|
|
201
|
+
|
|
202
|
+
if result.error:
|
|
203
|
+
error = result.error
|
|
204
|
+
return
|
|
205
|
+
|
|
206
|
+
// Success handling...
|
|
207
|
+
|
|
208
|
+
// Display
|
|
209
|
+
if error:
|
|
210
|
+
show_error_message(error)
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
---
|
|
214
|
+
|
|
215
|
+
*Part of Paradigm v2.0 - Language Agnostic*
|
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
# Paradigm Coding Patterns
|
|
2
|
+
|
|
3
|
+
Common patterns for working with Paradigm symbols and the logger.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Component Pattern (Features)
|
|
8
|
+
|
|
9
|
+
Components with `[feature]` tag are user-facing operations. They should be logged at entry and exit.
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
// Component: #login-handler [feature]
|
|
13
|
+
|
|
14
|
+
function login(email, password):
|
|
15
|
+
// 1. Log entry with start() for duration tracking
|
|
16
|
+
tracker = log.component('#login-handler').start('Starting login', { email })
|
|
17
|
+
|
|
18
|
+
try:
|
|
19
|
+
// 2. Perform the operation
|
|
20
|
+
user = authenticate(email, password)
|
|
21
|
+
|
|
22
|
+
// 3. Emit success signal
|
|
23
|
+
log.signal('!login-success').info('User authenticated', {
|
|
24
|
+
userId: user.id
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
// 4. Log successful completion with duration
|
|
28
|
+
tracker.success('Login completed', { userId: user.id })
|
|
29
|
+
|
|
30
|
+
return user
|
|
31
|
+
|
|
32
|
+
catch error:
|
|
33
|
+
// 5. Emit failure signal
|
|
34
|
+
log.signal('!login-failed').warn('Login failed', {
|
|
35
|
+
email,
|
|
36
|
+
error: error.message
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
// 6. Log failure with duration
|
|
40
|
+
tracker.error('Login failed', { error: error.message })
|
|
41
|
+
|
|
42
|
+
throw error
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
**Key points:**
|
|
46
|
+
- Use `log.component('#name').start()` at entry
|
|
47
|
+
- Emit `!success` and `!failed` signals
|
|
48
|
+
- Always call `tracker.success()` or `tracker.error()`
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## Gate Pattern
|
|
53
|
+
|
|
54
|
+
Gates (`^`) are authorization checkpoints. Log before and after the check.
|
|
55
|
+
|
|
56
|
+
```
|
|
57
|
+
// Gate: ^authenticated
|
|
58
|
+
|
|
59
|
+
function requireAuth(request, next):
|
|
60
|
+
// 1. Log gate check start
|
|
61
|
+
log.gate('^authenticated').debug('Checking ^authenticated', {
|
|
62
|
+
path: request.path,
|
|
63
|
+
method: request.method
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
// 2. Perform authorization check
|
|
67
|
+
user = getSessionUser(request)
|
|
68
|
+
|
|
69
|
+
if not user:
|
|
70
|
+
// 3. Log denial
|
|
71
|
+
log.gate('^authenticated').warn('Access denied - no session', {
|
|
72
|
+
path: request.path,
|
|
73
|
+
ip: request.ip
|
|
74
|
+
})
|
|
75
|
+
return unauthorized("Authentication required")
|
|
76
|
+
|
|
77
|
+
// 4. Log success
|
|
78
|
+
log.gate('^authenticated').debug('Gate passed', {
|
|
79
|
+
userId: user.id,
|
|
80
|
+
path: request.path
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
// 5. Continue to next handler
|
|
84
|
+
return next()
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
**Key points:**
|
|
88
|
+
- Log at `debug` level for routine checks
|
|
89
|
+
- Log at `warn` level for denials
|
|
90
|
+
- Include context (path, userId) for debugging
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## Component Pattern
|
|
95
|
+
|
|
96
|
+
Components (`#`) are reusable infrastructure. Log operations and errors.
|
|
97
|
+
|
|
98
|
+
```
|
|
99
|
+
// Component: #database
|
|
100
|
+
|
|
101
|
+
class Database:
|
|
102
|
+
function query(sql, params):
|
|
103
|
+
// 1. Start duration tracking
|
|
104
|
+
tracker = log.component('#database').start('Executing query')
|
|
105
|
+
|
|
106
|
+
try:
|
|
107
|
+
// 2. Perform operation
|
|
108
|
+
result = this.connection.execute(sql, params)
|
|
109
|
+
|
|
110
|
+
// 3. Log success with metrics
|
|
111
|
+
tracker.success('Query completed', {
|
|
112
|
+
rows: result.length,
|
|
113
|
+
table: extractTable(sql)
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
return result
|
|
117
|
+
|
|
118
|
+
catch error:
|
|
119
|
+
// 4. Log failure
|
|
120
|
+
tracker.error('Query failed', {
|
|
121
|
+
error: error.message,
|
|
122
|
+
sql: sql.substring(0, 100) // Truncate for safety
|
|
123
|
+
})
|
|
124
|
+
throw error
|
|
125
|
+
|
|
126
|
+
function connect():
|
|
127
|
+
log.component('#database').info('Connecting to database', {
|
|
128
|
+
host: this.config.host,
|
|
129
|
+
database: this.config.database
|
|
130
|
+
})
|
|
131
|
+
|
|
132
|
+
// ... connection logic
|
|
133
|
+
|
|
134
|
+
log.component('#database').info('Database connected')
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
**Key points:**
|
|
138
|
+
- Use duration tracking for async operations
|
|
139
|
+
- Log connection lifecycle events
|
|
140
|
+
- Include relevant metrics (rows, duration)
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## State Component Pattern
|
|
145
|
+
|
|
146
|
+
State components (`#` with `[state]` tag) manage application state. Log changes with before/after values.
|
|
147
|
+
|
|
148
|
+
```
|
|
149
|
+
// Component: #user-store [state]
|
|
150
|
+
|
|
151
|
+
class AuthStore:
|
|
152
|
+
authenticated = false
|
|
153
|
+
user = null
|
|
154
|
+
|
|
155
|
+
function login(token, userData):
|
|
156
|
+
// 1. Log state change with context
|
|
157
|
+
log.component('#user-store').info('Authenticating user', {
|
|
158
|
+
from: this.authenticated,
|
|
159
|
+
to: true,
|
|
160
|
+
userId: userData.id
|
|
161
|
+
})
|
|
162
|
+
|
|
163
|
+
// 2. Update state
|
|
164
|
+
this.authenticated = true
|
|
165
|
+
this.user = userData
|
|
166
|
+
this.token = token
|
|
167
|
+
|
|
168
|
+
// 3. Emit signal
|
|
169
|
+
log.signal('!login-success').info('User session established', {
|
|
170
|
+
userId: userData.id
|
|
171
|
+
})
|
|
172
|
+
|
|
173
|
+
function logout():
|
|
174
|
+
previousUser = this.user?.id
|
|
175
|
+
|
|
176
|
+
log.component('#user-store').info('Logging out user', {
|
|
177
|
+
from: this.authenticated,
|
|
178
|
+
to: false,
|
|
179
|
+
userId: previousUser
|
|
180
|
+
})
|
|
181
|
+
|
|
182
|
+
this.authenticated = false
|
|
183
|
+
this.user = null
|
|
184
|
+
this.token = null
|
|
185
|
+
|
|
186
|
+
log.signal('!logout').info('User session ended', {
|
|
187
|
+
userId: previousUser
|
|
188
|
+
})
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
**Key points:**
|
|
192
|
+
- Include `from` and `to` values
|
|
193
|
+
- Pair state changes with signals
|
|
194
|
+
- Log at `info` level for visibility
|
|
195
|
+
|
|
196
|
+
---
|
|
197
|
+
|
|
198
|
+
## Flow Pattern
|
|
199
|
+
|
|
200
|
+
Flows (`$`) are multi-step processes. Log step transitions.
|
|
201
|
+
|
|
202
|
+
```
|
|
203
|
+
// Flow: $checkout-flow
|
|
204
|
+
// Steps: cart → shipping → payment → confirmation
|
|
205
|
+
|
|
206
|
+
class CheckoutFlow:
|
|
207
|
+
currentStep = 'cart'
|
|
208
|
+
|
|
209
|
+
function startFlow(cartId):
|
|
210
|
+
log.flow('$checkout-flow').info('Flow started', {
|
|
211
|
+
cartId,
|
|
212
|
+
step: 'cart'
|
|
213
|
+
})
|
|
214
|
+
this.currentStep = 'cart'
|
|
215
|
+
|
|
216
|
+
function nextStep():
|
|
217
|
+
steps = ['cart', 'shipping', 'payment', 'confirmation']
|
|
218
|
+
currentIndex = steps.indexOf(this.currentStep)
|
|
219
|
+
|
|
220
|
+
if currentIndex < steps.length - 1:
|
|
221
|
+
previousStep = this.currentStep
|
|
222
|
+
this.currentStep = steps[currentIndex + 1]
|
|
223
|
+
|
|
224
|
+
log.flow('$checkout-flow').info('Step completed', {
|
|
225
|
+
from: previousStep,
|
|
226
|
+
to: this.currentStep,
|
|
227
|
+
progress: `${currentIndex + 1}/${steps.length}`
|
|
228
|
+
})
|
|
229
|
+
|
|
230
|
+
function completeFlow(orderId):
|
|
231
|
+
log.flow('$checkout-flow').info('Flow completed', {
|
|
232
|
+
orderId,
|
|
233
|
+
totalSteps: 4
|
|
234
|
+
})
|
|
235
|
+
log.signal('!checkout-complete').info('Order placed', { orderId })
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
**Key points:**
|
|
239
|
+
- Log flow start and completion
|
|
240
|
+
- Log step transitions with from/to
|
|
241
|
+
- Include progress indicators
|
|
242
|
+
|
|
243
|
+
---
|
|
244
|
+
|
|
245
|
+
## Signal Pattern
|
|
246
|
+
|
|
247
|
+
Signals (`!`) are events. Use them consistently for important occurrences.
|
|
248
|
+
|
|
249
|
+
```
|
|
250
|
+
// Signals for authentication
|
|
251
|
+
log.signal('!login-success').info('User logged in', { userId })
|
|
252
|
+
log.signal('!login-failed').warn('Login attempt failed', { email, reason })
|
|
253
|
+
log.signal('!logout').info('User logged out', { userId })
|
|
254
|
+
log.signal('!session-expired').warn('Session expired', { userId })
|
|
255
|
+
|
|
256
|
+
// Signals for payments
|
|
257
|
+
log.signal('!payment-success').info('Payment processed', { orderId, amount })
|
|
258
|
+
log.signal('!payment-failed').error('Payment declined', { orderId, reason })
|
|
259
|
+
log.signal('!refund-issued').info('Refund processed', { orderId, amount })
|
|
260
|
+
|
|
261
|
+
// Signals for system events
|
|
262
|
+
log.signal('!rate-limit-exceeded').warn('Rate limit hit', { ip, endpoint })
|
|
263
|
+
log.signal('!cache-miss').debug('Cache miss', { key })
|
|
264
|
+
log.signal('!email-sent').info('Email dispatched', { to, template })
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
**Key points:**
|
|
268
|
+
- Use consistent naming: `!noun-verb` or `!noun-state`
|
|
269
|
+
- Choose appropriate level (info/warn/error)
|
|
270
|
+
- Include relevant context
|
|
271
|
+
|
|
272
|
+
---
|
|
273
|
+
|
|
274
|
+
## Error Handling Pattern
|
|
275
|
+
|
|
276
|
+
Consistent error handling with Paradigm logging:
|
|
277
|
+
|
|
278
|
+
```
|
|
279
|
+
function riskyOperation():
|
|
280
|
+
tracker = log.component('#risky-op').start('Starting operation')
|
|
281
|
+
|
|
282
|
+
try:
|
|
283
|
+
// Happy path
|
|
284
|
+
result = doSomethingRisky()
|
|
285
|
+
tracker.success('Operation completed', { result })
|
|
286
|
+
return result
|
|
287
|
+
|
|
288
|
+
catch KnownError as error:
|
|
289
|
+
// Expected error - warn level
|
|
290
|
+
log.signal('!known-error').warn('Expected error occurred', {
|
|
291
|
+
type: error.type,
|
|
292
|
+
message: error.message
|
|
293
|
+
})
|
|
294
|
+
tracker.error('Operation failed (known)', { error: error.type })
|
|
295
|
+
return fallbackValue
|
|
296
|
+
|
|
297
|
+
catch error:
|
|
298
|
+
// Unexpected error - error level
|
|
299
|
+
log.signal('!unexpected-error').error('Unexpected error', {
|
|
300
|
+
message: error.message,
|
|
301
|
+
stack: error.stack
|
|
302
|
+
})
|
|
303
|
+
tracker.error('Operation failed (unexpected)', {
|
|
304
|
+
error: error.message
|
|
305
|
+
})
|
|
306
|
+
throw error
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
---
|
|
310
|
+
|
|
311
|
+
## Middleware Pattern
|
|
312
|
+
|
|
313
|
+
Logging in request middleware:
|
|
314
|
+
|
|
315
|
+
```
|
|
316
|
+
function loggingMiddleware(request, next):
|
|
317
|
+
correlationId = request.headers['x-correlation-id'] or generateId()
|
|
318
|
+
|
|
319
|
+
return withCorrelation(correlationId, async () => {
|
|
320
|
+
tracker = log.component('#' + request.path).start('Request started', {
|
|
321
|
+
method: request.method,
|
|
322
|
+
path: request.path
|
|
323
|
+
})
|
|
324
|
+
|
|
325
|
+
try:
|
|
326
|
+
response = await next()
|
|
327
|
+
|
|
328
|
+
tracker.success('Request completed', {
|
|
329
|
+
status: response.status
|
|
330
|
+
})
|
|
331
|
+
|
|
332
|
+
return response
|
|
333
|
+
|
|
334
|
+
catch error:
|
|
335
|
+
tracker.error('Request failed', {
|
|
336
|
+
error: error.message
|
|
337
|
+
})
|
|
338
|
+
throw error
|
|
339
|
+
})
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
---
|
|
343
|
+
|
|
344
|
+
## Testing Pattern
|
|
345
|
+
|
|
346
|
+
When testing, you may want to suppress or capture logs:
|
|
347
|
+
|
|
348
|
+
```
|
|
349
|
+
// In tests, set LOG_LEVEL=error to reduce noise
|
|
350
|
+
// Or mock the logger to capture calls
|
|
351
|
+
|
|
352
|
+
beforeEach:
|
|
353
|
+
originalLogLevel = process.env.LOG_LEVEL
|
|
354
|
+
process.env.LOG_LEVEL = 'error'
|
|
355
|
+
|
|
356
|
+
afterEach:
|
|
357
|
+
process.env.LOG_LEVEL = originalLogLevel
|
|
358
|
+
```
|