0
# Namespace Management
1
2
Namespace management provides a global context registry system to avoid conflicts between different library versions and enable context sharing across modules.
3
4
## API Reference
5
6
```typescript { .api }
7
/**
8
* Create a namespace for managing multiple contexts
9
* @param defaultOpts - Default options applied to all contexts in namespace
10
* @returns Namespace instance for managing contexts by key
11
*/
12
function createNamespace<T = any>(defaultOpts: ContextOptions): ContextNamespace;
13
14
/**
15
* Get context from the default global namespace
16
* @param key - Unique key identifying the context (recommend using package name)
17
* @param opts - Context options, merged with namespace defaults
18
* @returns Context instance for the given key
19
*/
20
function getContext<T>(key: string, opts?: ContextOptions): UseContext<T>;
21
22
/**
23
* Get use function for named context from default global namespace
24
* @param key - Unique key identifying the context
25
* @param opts - Context options
26
* @returns Function that returns current context value when called
27
*/
28
function useContext<T>(key: string, opts?: ContextOptions): () => T;
29
30
interface ContextNamespace {
31
/**
32
* Get or create a context by key within the namespace
33
* @param key - Unique key for the context
34
* @param opts - Context options, merged with namespace defaults
35
* @returns Context instance for the key
36
*/
37
get<T>(key: string, opts?: ContextOptions): UseContext<T>;
38
}
39
40
/**
41
* The default global namespace instance
42
*/
43
const defaultNamespace: ContextNamespace;
44
```
45
46
## Basic Usage
47
48
### Using Default Global Namespace
49
50
```typescript
51
import { useContext, getContext } from "unctx";
52
53
interface UserSession {
54
userId: string;
55
token: string;
56
permissions: string[];
57
}
58
59
// Get context use function (recommended for library authors)
60
const useUserSession = useContext<UserSession>("my-auth-lib");
61
62
// Or get full context instance
63
const userSessionContext = getContext<UserSession>("my-auth-lib");
64
65
// Set up context in your library initialization
66
userSessionContext.set({
67
userId: "user-123",
68
token: "jwt-token",
69
permissions: ["read", "write"]
70
});
71
72
// Use in any module
73
function authenticatedFetch(url: string) {
74
const session = useUserSession();
75
return fetch(url, {
76
headers: {
77
'Authorization': `Bearer ${session.token}`
78
}
79
});
80
}
81
```
82
83
### Creating Custom Namespaces
84
85
```typescript
86
import { createNamespace } from "unctx";
87
import { AsyncLocalStorage } from "node:async_hooks";
88
89
// Create namespace with default async context support
90
const myLibNamespace = createNamespace({
91
asyncContext: true,
92
AsyncLocalStorage
93
});
94
95
interface DatabaseConnection {
96
host: string;
97
database: string;
98
transaction?: string;
99
}
100
101
// Get context from custom namespace
102
const dbContext = myLibNamespace.get<DatabaseConnection>("database");
103
104
// All contexts in this namespace inherit async support
105
await dbContext.callAsync(
106
{ host: "localhost", database: "myapp" },
107
async () => {
108
const db = dbContext.use();
109
await executeQuery(db);
110
}
111
);
112
```
113
114
## Version Safety
115
116
Namespaces prevent conflicts when multiple versions of a library are present:
117
118
```typescript
119
// Library v1.0 code
120
import { useContext } from "unctx";
121
const useMyLib = useContext<ConfigV1>("my-awesome-lib");
122
123
// Library v2.0 code (different interface)
124
import { useContext } from "unctx";
125
const useMyLib = useContext<ConfigV2>("my-awesome-lib");
126
127
// Both can coexist without conflicts - they share the same context
128
// but are typed differently in each version
129
```
130
131
## Library Integration Patterns
132
133
### Library Author Pattern
134
135
```typescript
136
// In your library (my-http-client/src/context.ts)
137
import { useContext, getContext } from "unctx";
138
139
interface HttpClientConfig {
140
baseURL: string;
141
timeout: number;
142
retries: number;
143
}
144
145
// Export the use function for consumers
146
export const useHttpConfig = useContext<HttpClientConfig>("my-http-client");
147
148
// Keep the full context internal for library setup
149
const httpConfigContext = getContext<HttpClientConfig>("my-http-client");
150
151
export function configureHttpClient(config: HttpClientConfig) {
152
httpConfigContext.set(config);
153
}
154
155
// In your library methods
156
export function makeRequest(endpoint: string) {
157
const config = useHttpConfig();
158
return fetch(`${config.baseURL}${endpoint}`, {
159
timeout: config.timeout
160
});
161
}
162
```
163
164
### Library Consumer Pattern
165
166
```typescript
167
// In application code
168
import { configureHttpClient, makeRequest } from "my-http-client";
169
170
// Configure library globally
171
configureHttpClient({
172
baseURL: "https://api.example.com",
173
timeout: 5000,
174
retries: 3
175
});
176
177
// Use throughout application
178
async function fetchUserData(userId: string) {
179
// Library automatically uses configured context
180
return makeRequest(`/users/${userId}`);
181
}
182
```
183
184
## Namespace Context Inheritance
185
186
```typescript
187
import { createNamespace } from "unctx";
188
189
// Create namespace with default options
190
const appNamespace = createNamespace({
191
asyncContext: true // All contexts get async support
192
});
193
194
// Contexts inherit namespace defaults
195
const userContext = appNamespace.get<User>("user");
196
const sessionContext = appNamespace.get<Session>("session");
197
198
// Both contexts have async support enabled
199
await userContext.callAsync(userData, async () => {
200
await sessionContext.callAsync(sessionData, async () => {
201
// Both contexts available across async boundaries
202
const user = userContext.use();
203
const session = sessionContext.use();
204
205
await processUserSession(user, session);
206
});
207
});
208
```
209
210
## Context Isolation
211
212
Different namespaces provide complete isolation:
213
214
```typescript
215
import { createNamespace } from "unctx";
216
217
const libANamespace = createNamespace();
218
const libBNamespace = createNamespace();
219
220
const libAContext = libANamespace.get<string>("shared-key");
221
const libBContext = libBNamespace.get<number>("shared-key");
222
223
// These are completely separate contexts despite same key
224
libAContext.set("string value");
225
libBContext.set(42);
226
227
console.log(libAContext.use()); // "string value"
228
console.log(libBContext.use()); // 42
229
```
230
231
## Best Practices
232
233
### Key Naming Convention
234
235
```typescript
236
// Use package name as key to avoid conflicts
237
const useMyLib = useContext<Config>("@company/my-lib");
238
239
// For scoped packages, use full scope
240
const useScoped = useContext<Data>("@scope/package-name");
241
242
// Add version suffix if needed for breaking changes
243
const useMyLibV2 = useContext<ConfigV2>("my-lib-v2");
244
```
245
246
### Error Handling
247
248
```typescript
249
import { getContext } from "unctx";
250
251
const appContext = getContext<AppState>("my-app");
252
253
function safeGetAppState(): AppState | null {
254
try {
255
return appContext.use();
256
} catch {
257
// Context not available, return fallback
258
return null;
259
}
260
}
261
262
// Or use tryUse for safe access
263
function getAppStateWithFallback(): AppState {
264
return appContext.tryUse() ?? getDefaultAppState();
265
}
266
```
267
268
### Cleanup and Lifecycle
269
270
```typescript
271
import { getContext } from "unctx";
272
273
const resourceContext = getContext<Resource>("my-resource");
274
275
// Application shutdown cleanup
276
export function cleanup() {
277
const resource = resourceContext.tryUse();
278
if (resource) {
279
resource.cleanup();
280
resourceContext.unset();
281
}
282
}
283
284
// Test isolation
285
beforeEach(() => {
286
resourceContext.unset();
287
});
288
```