@owlmeans/static-resource 0.1.2 → 0.1.4
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 +26 -305
- package/package.json +6 -5
- package/tsconfig.json +5 -4
package/README.md
CHANGED
|
@@ -1,330 +1,51 @@
|
|
|
1
1
|
# @owlmeans/static-resource
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
In-memory `Resource<T>` backed by static config data — for read-only data loaded at startup.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Overview
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
- `createStaticResource(alias?, key?)` — creates an in-memory resource populated from config
|
|
8
|
+
- `appendStaticResource(ctx, alias?, key?)` — registers it in the context with a `getStaticResource` accessor
|
|
9
|
+
- `StaticResourceAppend` — mixin type adding `getStaticResource<T>(alias?)` to context
|
|
10
|
+
- Useful for config-driven lookup tables (e.g., product catalogs, permission sets)
|
|
8
11
|
|
|
9
|
-
|
|
10
|
-
- **Supports TTL (Time To Live)** for automatic cleanup of expired records
|
|
11
|
-
- **Integrates with context system** for dependency injection and resource management
|
|
12
|
-
- **Offers CRUD operations** with validation and error handling
|
|
13
|
-
- **Enables testing scenarios** where persistent storage is not needed
|
|
12
|
+
## Installation
|
|
14
13
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
### Static Resource
|
|
18
|
-
A static resource is an in-memory storage that implements the standard `Resource<ResourceRecord>` interface from `@owlmeans/resource`. It stores records in memory and provides methods for creating, reading, and deleting records.
|
|
19
|
-
|
|
20
|
-
### Key-Value Storage
|
|
21
|
-
Records are stored using a key-value approach where each record must have an `id` field. Multiple static resource instances can share the same underlying storage by using the same key.
|
|
22
|
-
|
|
23
|
-
### TTL Support
|
|
24
|
-
Records can be created with a Time To Live (TTL) option, after which they are automatically removed from the storage.
|
|
25
|
-
|
|
26
|
-
## API Reference
|
|
27
|
-
|
|
28
|
-
### Factory Functions
|
|
29
|
-
|
|
30
|
-
#### `createStaticResource(alias?, key?): Resource<ResourceRecord>`
|
|
31
|
-
|
|
32
|
-
Creates a new static resource instance.
|
|
33
|
-
|
|
34
|
-
```typescript
|
|
35
|
-
import { createStaticResource } from '@owlmeans/static-resource'
|
|
36
|
-
|
|
37
|
-
const resource = createStaticResource('my-cache')
|
|
14
|
+
```bash
|
|
15
|
+
bun add @owlmeans/static-resource
|
|
38
16
|
```
|
|
39
17
|
|
|
40
|
-
|
|
41
|
-
- `alias`: string (optional) - Resource alias, defaults to `DEFAULT_ALIAS` ('static')
|
|
42
|
-
- `key`: string (optional) - Storage key, defaults to the alias value
|
|
43
|
-
|
|
44
|
-
**Returns:** Resource instance implementing full CRUD operations
|
|
45
|
-
|
|
46
|
-
#### `appendStaticResource<C, T>(ctx, alias?, key?): T & StaticResourceAppend`
|
|
47
|
-
|
|
48
|
-
Adds static resource functionality to a context.
|
|
18
|
+
## Usage
|
|
49
19
|
|
|
50
20
|
```typescript
|
|
51
21
|
import { appendStaticResource } from '@owlmeans/static-resource'
|
|
52
|
-
import {
|
|
53
|
-
|
|
54
|
-
const config = makeBasicConfig(AppType.Backend, 'my-service')
|
|
55
|
-
const context = makeBasicContext(config)
|
|
56
|
-
const contextWithStatic = appendStaticResource(context, 'cache')
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
**Parameters:**
|
|
60
|
-
- `ctx`: T - The context to extend
|
|
61
|
-
- `alias`: string (optional) - Resource alias, defaults to `DEFAULT_ALIAS`
|
|
62
|
-
- `key`: string (optional) - Storage key, defaults to the alias value
|
|
63
|
-
|
|
64
|
-
**Returns:** Extended context with `getStaticResource` method
|
|
65
|
-
|
|
66
|
-
### Resource Methods
|
|
67
|
-
|
|
68
|
-
The static resource implements the standard `Resource<ResourceRecord>` interface:
|
|
69
|
-
|
|
70
|
-
#### `get<T>(id, field?, opts?): Promise<T>`
|
|
71
|
-
|
|
72
|
-
Retrieves a record by ID or field value. Throws `UnknownRecordError` if not found.
|
|
73
|
-
|
|
74
|
-
```typescript
|
|
75
|
-
const user = await resource.get<User>('user-123')
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
#### `load<T>(id, field?, opts?): Promise<T | null>`
|
|
79
|
-
|
|
80
|
-
Loads a record by ID or field value. Returns `null` if not found.
|
|
81
|
-
|
|
82
|
-
```typescript
|
|
83
|
-
const user = await resource.load<User>('user-123')
|
|
84
|
-
if (user) {
|
|
85
|
-
console.log('User found:', user.name)
|
|
86
|
-
}
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
#### `list<T>(criteria?, opts?): Promise<ListResult<T>>`
|
|
90
|
-
|
|
91
|
-
Lists all records in the storage.
|
|
92
|
-
|
|
93
|
-
```typescript
|
|
94
|
-
const result = await resource.list<User>()
|
|
95
|
-
console.log('Total users:', result.items.length)
|
|
96
|
-
```
|
|
22
|
+
import type { StaticResourceAppend } from '@owlmeans/static-resource'
|
|
97
23
|
|
|
98
|
-
|
|
24
|
+
appendStaticResource<C, T>(context, 'products')
|
|
99
25
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
```typescript
|
|
105
|
-
const user = await resource.create({
|
|
106
|
-
id: 'user-123',
|
|
107
|
-
name: 'John Doe',
|
|
108
|
-
email: 'john@example.com'
|
|
109
|
-
}, { ttl: 3600 }) // TTL in seconds
|
|
26
|
+
// Access from context
|
|
27
|
+
const resource = context.getStaticResource<Product>('products')
|
|
28
|
+
const product = await resource.load('product-sku')
|
|
110
29
|
```
|
|
111
30
|
|
|
112
|
-
|
|
113
|
-
- `ttl`: number | Date - Time to live in seconds (number) or expiration date (Date)
|
|
114
|
-
|
|
115
|
-
**Throws:**
|
|
116
|
-
- `UnknownRecordError` - If record doesn't have an `id` field
|
|
117
|
-
- `RecordExists` - If record with the same ID already exists
|
|
118
|
-
|
|
119
|
-
#### `delete(id, opts?): Promise<T | null>`
|
|
120
|
-
|
|
121
|
-
Deletes a record and returns it, or `null` if not found.
|
|
122
|
-
|
|
123
|
-
```typescript
|
|
124
|
-
const deletedUser = await resource.delete('user-123')
|
|
125
|
-
```
|
|
126
|
-
|
|
127
|
-
#### `pick<T>(id, opts?): Promise<T>`
|
|
128
|
-
|
|
129
|
-
Deletes a record and returns it. Throws `UnknownRecordError` if not found.
|
|
130
|
-
|
|
131
|
-
```typescript
|
|
132
|
-
const pickedUser = await resource.pick('user-123')
|
|
133
|
-
```
|
|
134
|
-
|
|
135
|
-
### Unsupported Methods
|
|
136
|
-
|
|
137
|
-
The following methods throw `UnsupportedMethodError`:
|
|
138
|
-
- `save()` - Static resources don't support updating existing records
|
|
139
|
-
- `update()` - Static resources don't support partial updates
|
|
140
|
-
|
|
141
|
-
### Types
|
|
142
|
-
|
|
143
|
-
#### `StaticResourceAppend`
|
|
144
|
-
|
|
145
|
-
Interface added to contexts when using `appendStaticResource`.
|
|
146
|
-
|
|
147
|
-
```typescript
|
|
148
|
-
interface StaticResourceAppend {
|
|
149
|
-
getStaticResource: <T extends ResourceRecord>(alias?: string) => Resource<T>
|
|
150
|
-
}
|
|
151
|
-
```
|
|
152
|
-
|
|
153
|
-
#### `Config` and `Context`
|
|
154
|
-
|
|
155
|
-
Type aliases for basic context configuration and context interfaces.
|
|
156
|
-
|
|
157
|
-
```typescript
|
|
158
|
-
interface Config extends BasicConfig {}
|
|
159
|
-
interface Context<C extends Config = Config> extends BasicContext<C> {}
|
|
160
|
-
```
|
|
161
|
-
|
|
162
|
-
### Constants
|
|
163
|
-
|
|
164
|
-
#### `DEFAULT_ALIAS`
|
|
165
|
-
|
|
166
|
-
Default alias for static resources.
|
|
167
|
-
|
|
168
|
-
```typescript
|
|
169
|
-
const DEFAULT_ALIAS = 'static'
|
|
170
|
-
```
|
|
171
|
-
|
|
172
|
-
## Usage Examples
|
|
173
|
-
|
|
174
|
-
### Basic Usage
|
|
175
|
-
|
|
176
|
-
```typescript
|
|
177
|
-
import { createStaticResource } from '@owlmeans/static-resource'
|
|
178
|
-
|
|
179
|
-
// Create a static resource
|
|
180
|
-
const cache = createStaticResource('user-cache')
|
|
181
|
-
|
|
182
|
-
// Create records
|
|
183
|
-
await cache.create({ id: 'user-1', name: 'Alice', role: 'admin' })
|
|
184
|
-
await cache.create({ id: 'user-2', name: 'Bob', role: 'user' })
|
|
185
|
-
|
|
186
|
-
// Retrieve records
|
|
187
|
-
const alice = await cache.get('user-1')
|
|
188
|
-
console.log('Found user:', alice.name)
|
|
189
|
-
|
|
190
|
-
// List all records
|
|
191
|
-
const { items } = await cache.list()
|
|
192
|
-
console.log('Total users:', items.length)
|
|
193
|
-
|
|
194
|
-
// Delete a record
|
|
195
|
-
const deleted = await cache.delete('user-1')
|
|
196
|
-
console.log('Deleted user:', deleted?.name)
|
|
197
|
-
```
|
|
198
|
-
|
|
199
|
-
### Context Integration
|
|
200
|
-
|
|
201
|
-
```typescript
|
|
202
|
-
import { appendStaticResource } from '@owlmeans/static-resource'
|
|
203
|
-
import { makeBasicContext, makeBasicConfig, AppType } from '@owlmeans/context'
|
|
204
|
-
|
|
205
|
-
const config = makeBasicConfig(AppType.Backend, 'user-service')
|
|
206
|
-
const context = makeBasicContext(config)
|
|
207
|
-
|
|
208
|
-
// Add static resource to context
|
|
209
|
-
const enhancedContext = appendStaticResource(context, 'session-cache')
|
|
210
|
-
|
|
211
|
-
// Configure and initialize context
|
|
212
|
-
enhancedContext.configure()
|
|
213
|
-
await enhancedContext.init()
|
|
214
|
-
|
|
215
|
-
// Use the static resource
|
|
216
|
-
const sessionCache = enhancedContext.getStaticResource('session-cache')
|
|
217
|
-
await sessionCache.create({
|
|
218
|
-
id: 'session-123',
|
|
219
|
-
userId: 'user-456',
|
|
220
|
-
expires: new Date(Date.now() + 3600000)
|
|
221
|
-
})
|
|
222
|
-
```
|
|
223
|
-
|
|
224
|
-
### TTL Usage
|
|
225
|
-
|
|
226
|
-
```typescript
|
|
227
|
-
import { createStaticResource } from '@owlmeans/static-resource'
|
|
228
|
-
|
|
229
|
-
const cache = createStaticResource('temporary-cache')
|
|
230
|
-
|
|
231
|
-
// Create record with TTL in seconds
|
|
232
|
-
await cache.create({
|
|
233
|
-
id: 'temp-data',
|
|
234
|
-
value: 'This will expire'
|
|
235
|
-
}, { ttl: 60 }) // Expires in 60 seconds
|
|
236
|
-
|
|
237
|
-
// Create record with expiration date
|
|
238
|
-
const expirationDate = new Date(Date.now() + 30000) // 30 seconds from now
|
|
239
|
-
await cache.create({
|
|
240
|
-
id: 'temp-data-2',
|
|
241
|
-
value: 'This will also expire'
|
|
242
|
-
}, { ttl: expirationDate })
|
|
243
|
-
|
|
244
|
-
// Records will be automatically removed after TTL expires
|
|
245
|
-
setTimeout(async () => {
|
|
246
|
-
const record = await cache.load('temp-data')
|
|
247
|
-
console.log('Record exists:', record !== null) // false
|
|
248
|
-
}, 61000)
|
|
249
|
-
```
|
|
250
|
-
|
|
251
|
-
### Shared Storage
|
|
252
|
-
|
|
253
|
-
```typescript
|
|
254
|
-
import { createStaticResource } from '@owlmeans/static-resource'
|
|
255
|
-
|
|
256
|
-
// Multiple resources sharing the same storage
|
|
257
|
-
const cacheA = createStaticResource('cache-a', 'shared-storage')
|
|
258
|
-
const cacheB = createStaticResource('cache-b', 'shared-storage')
|
|
259
|
-
|
|
260
|
-
// Record created in cacheA is accessible from cacheB
|
|
261
|
-
await cacheA.create({ id: 'shared-record', data: 'shared data' })
|
|
262
|
-
const record = await cacheB.load('shared-record')
|
|
263
|
-
console.log('Shared record:', record?.data) // 'shared data'
|
|
264
|
-
```
|
|
265
|
-
|
|
266
|
-
### Error Handling
|
|
267
|
-
|
|
268
|
-
```typescript
|
|
269
|
-
import { createStaticResource } from '@owlmeans/static-resource'
|
|
270
|
-
import { UnknownRecordError, RecordExists } from '@owlmeans/resource'
|
|
271
|
-
|
|
272
|
-
const resource = createStaticResource('error-demo')
|
|
273
|
-
|
|
274
|
-
try {
|
|
275
|
-
// This will throw UnknownRecordError
|
|
276
|
-
await resource.get('non-existent-id')
|
|
277
|
-
} catch (error) {
|
|
278
|
-
if (error instanceof UnknownRecordError) {
|
|
279
|
-
console.log('Record not found:', error.message)
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
try {
|
|
284
|
-
await resource.create({ id: 'user-1', name: 'Alice' })
|
|
285
|
-
// This will throw RecordExists
|
|
286
|
-
await resource.create({ id: 'user-1', name: 'Bob' })
|
|
287
|
-
} catch (error) {
|
|
288
|
-
if (error instanceof RecordExists) {
|
|
289
|
-
console.log('Record already exists:', error.message)
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
```
|
|
31
|
+
## API
|
|
293
32
|
|
|
294
|
-
|
|
33
|
+
### `createStaticResource(alias?, key?): Resource<ResourceRecord>`
|
|
295
34
|
|
|
296
|
-
|
|
35
|
+
Creates an in-memory resource. `key` is the config path where data is loaded from.
|
|
297
36
|
|
|
298
|
-
|
|
299
|
-
- **`RecordExists`** - Thrown when trying to create a record with an existing ID
|
|
300
|
-
- **`MisshapedRecord`** - Thrown when record structure is invalid (missing ID)
|
|
301
|
-
- **`UnsupportedArgumentError`** - Thrown when unsupported arguments are provided
|
|
302
|
-
- **`UnsupportedMethodError`** - Thrown when calling unsupported methods
|
|
37
|
+
### `appendStaticResource<C, T>(ctx, alias?, key?): T & StaticResourceAppend`
|
|
303
38
|
|
|
304
|
-
|
|
39
|
+
Registers the static resource and adds `getStaticResource` to the context.
|
|
305
40
|
|
|
306
|
-
|
|
307
|
-
- **types**: TypeScript interfaces and type definitions
|
|
308
|
-
- **consts**: Static values and constants
|
|
309
|
-
- **resource**: Resource implementation and factory functions
|
|
41
|
+
### `StaticResourceAppend`
|
|
310
42
|
|
|
311
|
-
|
|
312
|
-
- Uses `@owlmeans/context` for dependency injection
|
|
313
|
-
- Implements `@owlmeans/resource` interface for consistency
|
|
314
|
-
- Supports `@owlmeans/error` error types
|
|
43
|
+
Mixin interface: `getStaticResource<T>(alias?): Resource<T>`
|
|
315
44
|
|
|
316
|
-
|
|
45
|
+
### `DEFAULT_ALIAS`
|
|
317
46
|
|
|
318
|
-
|
|
319
|
-
2. **Implement TTL for cleanup** - Always set TTL for records that should expire automatically
|
|
320
|
-
3. **Share storage carefully** - Use the same key only when you want resources to share data
|
|
321
|
-
4. **Handle errors gracefully** - Always catch and handle resource-specific errors
|
|
322
|
-
5. **Integrate with context** - Use `appendStaticResource` for proper context integration
|
|
323
|
-
6. **Test scenarios** - Perfect for unit tests where you don't want persistent storage
|
|
47
|
+
`'static'` — default resource alias.
|
|
324
48
|
|
|
325
|
-
##
|
|
49
|
+
## Related Packages
|
|
326
50
|
|
|
327
|
-
|
|
328
|
-
- `@owlmeans/context` - For contextual resource management
|
|
329
|
-
- `@owlmeans/resource` - For resource interface and error types
|
|
330
|
-
- `@owlmeans/error` - For error handling infrastructure
|
|
51
|
+
- [`@owlmeans/resource`](../resource) — `Resource<T>` interface implemented here
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@owlmeans/static-resource",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
@@ -21,13 +21,14 @@
|
|
|
21
21
|
}
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@owlmeans/context": "^0.1.
|
|
25
|
-
"@owlmeans/error": "^0.1.
|
|
26
|
-
"@owlmeans/resource": "^0.1.
|
|
24
|
+
"@owlmeans/context": "^0.1.4",
|
|
25
|
+
"@owlmeans/error": "^0.1.4",
|
|
26
|
+
"@owlmeans/resource": "^0.1.4"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
|
+
"@owlmeans/dep-config": "workspace:*",
|
|
29
30
|
"nodemon": "^3.1.11",
|
|
30
|
-
"typescript": "^
|
|
31
|
+
"typescript": "^6.0.2"
|
|
31
32
|
},
|
|
32
33
|
"publishConfig": {
|
|
33
34
|
"access": "public"
|
package/tsconfig.json
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"extends": [
|
|
3
|
-
"
|
|
3
|
+
"@owlmeans/dep-config/tsconfig.base.json",
|
|
4
|
+
"@owlmeans/dep-config/tsconfig.node.json"
|
|
4
5
|
],
|
|
5
6
|
"compilerOptions": {
|
|
6
|
-
"rootDir": "./src/",
|
|
7
|
-
"outDir": "./build/"
|
|
7
|
+
"rootDir": "./src/",
|
|
8
|
+
"outDir": "./build/"
|
|
8
9
|
},
|
|
9
10
|
"exclude": [
|
|
10
11
|
"./dist/**/*",
|
|
11
12
|
"./build/**/*",
|
|
12
13
|
"./*.ts"
|
|
13
14
|
]
|
|
14
|
-
}
|
|
15
|
+
}
|