@owlmeans/static-resource 0.1.18-rc.7 → 0.1.18-rc.8

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 CHANGED
@@ -26,8 +26,13 @@ appendStaticResource<C, T>(context, 'products')
26
26
  // Access from context
27
27
  const resource = context.getStaticResource<Product>('products')
28
28
  const product = await resource.load('product-sku')
29
+ const active = await resource.list({ status: 'active' })
29
30
  ```
30
31
 
32
+ Reads are unpaged: `list(where)` returns every match, and `list(where, { page })` without a `size`
33
+ throws `UnsupportedArgumentError('page-without-size')`. Criteria and sorting are the shared
34
+ vocabulary from [`@owlmeans/resource`](../resource), evaluated in memory.
35
+
31
36
  ## API
32
37
 
33
38
  ### `createStaticResource(alias?, key?): Resource<ResourceRecord>`
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "schemaVersion": 2,
3
3
  "package": "@owlmeans/static-resource",
4
- "version": "0.1.18-rc.7",
5
- "generatedAt": "2026-08-24T21:14:00.143Z",
4
+ "version": "0.1.18-rc.8",
5
+ "generatedAt": "2026-09-01T16:28:56.999Z",
6
6
  "canonicalRepo": "https://github.com/owlmeans/common",
7
7
  "entries": [
8
8
  {
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: static-resource
3
- description: How to use @owlmeans/static-resource — Resource for serving static files from a server (e.g. uploaded assets, generated reports). Auto-invoked when serving static files via the framework.
3
+ description: How to use @owlmeans/static-resource — in-process Resource over a module-scope Map, for records an app holds in memory (fixtures, caches, short-lived handshake state). Auto-invoked when registering an in-memory resource on a context.
4
4
  user-invocable: false
5
5
  ---
6
6
  <!-- AUTO-GENERATED — do not edit. Regenerate via sync-agent-meta. -->
@@ -8,27 +8,54 @@ user-invocable: false
8
8
  # @owlmeans/static-resource
9
9
 
10
10
  **Layer:** Infra
11
- **Install:** `"@owlmeans/static-resource": "^0.1.18-rc.7"` in `dependencies`
11
+ **Install:** `"@owlmeans/static-resource": "^0.1.18-rc.8"` in `dependencies`
12
+
13
+ The whole `Resource` contract over a `Map` held at module scope. Use it where records must be
14
+ reachable through the context like any other resource but have no database behind them — fixtures,
15
+ a process-local cache, short-lived handshake state.
12
16
 
13
17
  ## Key Exports
14
18
 
15
19
  | Export | Description |
16
20
  |--------|-------------|
17
- | `makeStaticResource(options)` | Static-file Resource factory |
18
- | `StaticResource` types | Resource interface |
19
- | Constants | Default cache headers |
21
+ | `appendStaticResource(context, alias?, key?)` | Register one on the context and add `getStaticResource(alias?)` to it |
22
+ | `createStaticResource<T>(alias?, key?)` | The bare `Resource<T>`, when you register it yourself |
23
+ | `StaticResourceAppend` | The `getStaticResource` accessor the append adds |
24
+ | `DEFAULT_ALIAS` (`static`) | Constant |
25
+
26
+ `key` names the underlying store, defaulting to the alias — two resources sharing a `key` share
27
+ records, which is how two contexts in one process see the same set.
20
28
 
21
29
  ## Usage
22
30
 
23
31
  ```typescript
24
- import { makeStaticResource } from '@owlmeans/static-resource'
32
+ import { appendStaticResource } from '@owlmeans/static-resource'
25
33
 
26
- context.registerResource(makeStaticResource({
27
- alias: 'public',
28
- root: '/var/lib/app/public',
29
- }))
34
+ appendStaticResource(context, 'fixtures')
35
+
36
+ const fixtures = context.getStaticResource<Fixture>('fixtures')
37
+ await fixtures.save({ id: 'seed', name: 'Owl' })
38
+ await fixtures.list({ name: { $startsWith: 'Owl' } }, { sort: ['name'] })
30
39
  ```
31
40
 
41
+ ## Semantics
42
+
43
+ - The store is a map keyed by id and there is nothing here to mint one from, so **every write
44
+ needs an id**: `create`, `update` and `save` all throw `MisshapedRecord('id')` without one.
45
+ `create` additionally throws `RecordExists`, `update` `UnknownRecordError`; `save` is the upsert.
46
+ - `load(id)` / `get(id)` / `delete(id)` / `take(id)` hit the map directly. `take(id)` **deletes**
47
+ the record it returns and throws `UnknownRecordError` on a miss.
48
+ - `load(where)`, `get(where)`, `list`, `count` and `purge` go through the shared in-memory engine
49
+ from `@owlmeans/resource`, so criteria and `{ sort }` mean exactly what they mean against a
50
+ database. `purge(where)` refuses an empty criteria object.
51
+ - **Unpaged**: `list(where)` with no `size` returns every match — the whole store is already in
52
+ memory; `size: 0` says the same explicitly, and `page` without `size` throws
53
+ `UnsupportedArgumentError('page-without-size')`.
54
+ - `opts.ttl` is honoured on writes — a number is seconds from now, a `Date` the instant to expire
55
+ at, and the record is dropped from the map when it elapses. An expiry already armed keeps its
56
+ appointment: rewriting the record without a ttl does not cancel it, so a renewal passes the ttl
57
+ again and a record that must survive gets a fresh id.
58
+
32
59
  ## Depends On
33
60
 
34
- - `@owlmeans/resource`, `@owlmeans/server-context`
61
+ - `@owlmeans/resource`, `@owlmeans/context`
@@ -1,5 +1,5 @@
1
1
  import type { Resource, ResourceRecord } from '@owlmeans/resource';
2
2
  import type { Config, Context, StaticResourceAppend } from './types.js';
3
- export declare const createStaticResource: (alias?: string, key?: string) => Resource<ResourceRecord>;
3
+ export declare const createStaticResource: <T extends ResourceRecord = ResourceRecord>(alias?: string, key?: string) => Resource<T>;
4
4
  export declare const appendStaticResource: <C extends Config, T extends Context<C>>(ctx: T, alias?: string, key?: string) => T & StaticResourceAppend;
5
5
  //# sourceMappingURL=resource.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"resource.d.ts","sourceRoot":"","sources":["../src/resource.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAC8D,QAAQ,EAChF,cAAc,EACf,MAAM,oBAAoB,CAAA;AAE3B,OAAO,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAA;AAMvE,eAAO,MAAM,oBAAoB,WAAW,MAAM,QAAwB,MAAM,6BA2J/E,CAAA;AAED,eAAO,MAAM,oBAAoB,GAAI,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,OAAO,CAAC,CAAC,CAAC,OACpE,CAAC,UAAS,MAAM,QAAwB,MAAM,KAClD,CAAC,GAAG,oBAWN,CAAA"}
1
+ {"version":3,"file":"resource.d.ts","sourceRoot":"","sources":["../src/resource.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAC2B,QAAQ,EAAE,cAAc,EAC9D,MAAM,oBAAoB,CAAA;AAK3B,OAAO,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAA;AAYvE,eAAO,MAAM,oBAAoB,GAAI,CAAC,SAAS,cAAc,GAAG,cAAc,EAC5E,QAAO,MAAsB,EAAE,MAAM,MAAM,KAC1C,QAAQ,CAAC,CAAC,CA4HZ,CAAA;AAED,eAAO,MAAM,oBAAoB,GAAI,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,OAAO,CAAC,CAAC,CAAC,EACzE,KAAK,CAAC,EAAE,QAAO,MAAsB,EAAE,MAAM,MAAM,KAClD,CAAC,GAAG,oBAWN,CAAA"}
package/build/resource.js CHANGED
@@ -1,134 +1,107 @@
1
1
  import { appendContextual } from '@owlmeans/context';
2
2
  import { DEFAULT_ALIAS } from './consts.js';
3
- import { MisshapedRecord, RecordExists, UnknownRecordError, UnsupportedArgumentError } from '@owlmeans/resource';
3
+ import { applyQuery, filterRecords, firstMatch, MisshapedRecord, RecordExists, UnknownRecordError, UnsupportedArgumentError } from '@owlmeans/resource';
4
4
  const stores = {};
5
+ /**
6
+ * Milliseconds until the record expires, which is what `setTimeout` wants. A number is seconds
7
+ * from now and a Date is the instant to expire at — the two spellings have to land on the same
8
+ * moment, or the same ttl means an hour through one and a second through the other.
9
+ */
10
+ const expiresIn = (ttl) => ttl instanceof Date ? ttl.getTime() - Date.now() : ttl * 1000;
5
11
  export const createStaticResource = (alias = DEFAULT_ALIAS, key) => {
6
- key = key ?? alias;
12
+ const storeKey = key ?? alias;
7
13
  const getStore = () => {
8
- if (stores[key] == null) {
9
- stores[key] = new Map();
14
+ if (stores[storeKey] == null) {
15
+ stores[storeKey] = new Map();
10
16
  }
11
- return stores[key];
17
+ return stores[storeKey];
18
+ };
19
+ const records = () => [...getStore().values()];
20
+ const expire = (id, opts) => {
21
+ if (opts?.ttl == null) {
22
+ return;
23
+ }
24
+ const store = getStore();
25
+ setTimeout(() => void store.delete(id), expiresIn(opts.ttl));
26
+ };
27
+ /** An id hits the map directly; criteria go through the shared in-memory engine. */
28
+ const first = (idOrWhere, opts) => typeof idOrWhere === 'string'
29
+ ? getStore().get(idOrWhere) ?? null
30
+ : firstMatch(records(), idOrWhere, opts);
31
+ const write = (record, opts) => {
32
+ if (record.id == null) {
33
+ /**
34
+ * The store is a map keyed by id and there is nothing here to mint one from, so a record
35
+ * without an id is misshaped rather than new — `save` cannot create it.
36
+ */
37
+ throw new MisshapedRecord('id');
38
+ }
39
+ getStore().set(record.id, record);
40
+ expire(record.id, opts);
41
+ return record;
12
42
  };
13
43
  const resource = appendContextual(alias, {
14
- get: async (id, field, opts) => {
15
- const record = await resource.load(id, field, opts);
44
+ get: async (idOrWhere, opts) => {
45
+ const record = first(idOrWhere, opts);
16
46
  if (record == null) {
17
- throw new UnknownRecordError(id);
47
+ throw new UnknownRecordError(typeof idOrWhere === 'string' ? idOrWhere : 'criteria');
18
48
  }
19
49
  return record;
20
50
  },
21
- load: async (id, field, opts) => {
22
- field = field ?? 'id';
23
- if (opts != null) {
24
- throw new UnsupportedArgumentError('static:get:opts');
51
+ load: async (idOrWhere, opts) => first(idOrWhere, opts),
52
+ /** Unpaged unless a size is asked for — the whole store is already in memory. */
53
+ list: async (where, opts) => {
54
+ if (opts?.page != null && opts.size == null) {
55
+ throw new UnsupportedArgumentError('page-without-size');
25
56
  }
26
- const store = getStore();
27
- const record = field === 'id'
28
- ? store.get(id)
29
- : [...store.values()].find(record => record[field] === id);
30
- if (record == null) {
31
- return null;
32
- }
33
- return record;
34
- },
35
- list: async (criteria, opts) => {
36
- if (criteria != null) {
37
- throw new UnsupportedArgumentError('static:list:criteria');
38
- }
39
- if (opts != null) {
40
- throw new UnsupportedArgumentError('static:list:opts');
41
- }
42
- const result = {
43
- items: [...getStore().values()]
44
- };
45
- return result;
46
- },
47
- save: async (record, opts) => {
48
- const store = getStore();
49
- if (record.id == null) {
50
- throw new MisshapedRecord('id');
51
- }
52
- store.set(record.id, record);
53
- if (typeof opts === 'object' && opts?.ttl != null) {
54
- const ttl = opts.ttl instanceof Date
55
- ? (opts.ttl.getTime() - Date.now()) / 1000
56
- : typeof opts.ttl === 'number'
57
- ? opts.ttl * 1000
58
- : null;
59
- if (ttl == null) {
60
- throw new UnsupportedArgumentError('static:opts:ttl-string');
61
- }
62
- setTimeout(() => record.id != null && void store.delete(record.id), ttl);
63
- }
64
- return record;
57
+ return applyQuery(records(), where, opts);
65
58
  },
59
+ count: async (where) => filterRecords(records(), where).length,
66
60
  create: async (record, opts) => {
67
- const store = getStore();
68
61
  if (record.id == null) {
69
- throw new UnknownRecordError('id');
62
+ throw new MisshapedRecord('id');
70
63
  }
71
- if (store.has(record.id)) {
64
+ if (getStore().has(record.id)) {
72
65
  throw new RecordExists(record.id);
73
66
  }
74
- store.set(record.id, record);
75
- if (opts?.ttl != null) {
76
- const ttl = opts.ttl instanceof Date
77
- ? (opts.ttl.getTime() - Date.now()) / 1000
78
- : typeof opts.ttl === 'number'
79
- ? opts.ttl * 1000
80
- : null;
81
- if (ttl == null) {
82
- throw new UnsupportedArgumentError('static:opts:ttl-string');
83
- }
84
- setTimeout(() => record.id != null && void store.delete(record.id), ttl);
85
- }
86
- return record;
67
+ return write(record, opts);
87
68
  },
88
69
  update: async (record, opts) => {
89
- return resource.save(record, opts);
90
- },
91
- delete: async (id, opts) => {
92
- let record = null;
93
- if (typeof id === 'object') {
94
- if (id.id == null) {
95
- throw new MisshapedRecord('id');
96
- }
97
- record = await resource.load(id.id);
98
- }
99
- else if (typeof opts === 'string') {
100
- record = await resource.load(id, opts);
70
+ if (record.id == null) {
71
+ throw new MisshapedRecord('id');
101
72
  }
102
- else if (typeof id === 'string') {
103
- record = await resource.load(id);
73
+ if (!getStore().has(record.id)) {
74
+ throw new UnknownRecordError(record.id);
104
75
  }
76
+ return write(record, opts);
77
+ },
78
+ save: async (record, opts) => write(record, opts),
79
+ delete: async (id) => {
80
+ const store = getStore();
81
+ const record = store.get(id) ?? null;
105
82
  if (record == null) {
106
83
  return null;
107
84
  }
108
- let field = 'id';
109
- if (typeof opts === 'string') {
110
- field = opts;
111
- opts = undefined;
112
- }
113
- else if (typeof opts === 'object') {
114
- field = opts.field ?? field;
115
- }
116
- id = record.id ?? '';
117
- if (id === '') {
118
- throw new MisshapedRecord('id');
119
- }
120
- const store = getStore();
121
- if (store.delete(id)) {
122
- return record;
123
- }
124
- return null;
85
+ store.delete(id);
86
+ return record;
125
87
  },
126
- pick: async (id, opts) => {
127
- const record = await resource.delete(id, opts);
88
+ take: async (id) => {
89
+ const store = getStore();
90
+ const record = store.get(id);
128
91
  if (record == null) {
129
- throw new UnknownRecordError((typeof id === 'string' ? id : id.id) ?? 'unknown');
92
+ throw new UnknownRecordError(id);
130
93
  }
94
+ store.delete(id);
131
95
  return record;
96
+ },
97
+ purge: async (where) => {
98
+ if (where == null || Object.keys(where).length < 1) {
99
+ throw new UnsupportedArgumentError('purge:empty-criteria');
100
+ }
101
+ const store = getStore();
102
+ const matched = filterRecords(records(), where);
103
+ matched.forEach(record => record.id != null && store.delete(record.id));
104
+ return matched.length;
132
105
  }
133
106
  });
134
107
  return resource;
@@ -1 +1 @@
1
- {"version":3,"file":"resource.js","sourceRoot":"","sources":["../src/resource.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"resource.js","sourceRoot":"","sources":["../src/resource.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@owlmeans/static-resource",
3
- "version": "0.1.18-rc.7",
3
+ "version": "0.1.18-rc.8",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -21,9 +21,9 @@
21
21
  }
22
22
  },
23
23
  "dependencies": {
24
- "@owlmeans/context": "^0.1.18-rc.6",
25
- "@owlmeans/error": "^0.1.18-rc.6",
26
- "@owlmeans/resource": "^0.1.18-rc.7"
24
+ "@owlmeans/context": "^0.1.18-rc.7",
25
+ "@owlmeans/error": "^0.1.18-rc.7",
26
+ "@owlmeans/resource": "^0.1.18-rc.8"
27
27
  },
28
28
  "devDependencies": {
29
29
  "@owlmeans/dep-config": "workspace:*",
package/src/resource.ts CHANGED
@@ -1,167 +1,146 @@
1
1
  import { appendContextual } from '@owlmeans/context'
2
2
  import { DEFAULT_ALIAS } from './consts.js'
3
3
  import type {
4
- GetterOptions, ListOptions, ListResult, LifecycleOptions, ListCriteria, Resource,
5
- ResourceRecord
4
+ Criteria, FirstOptions, ListOptions, Resource, ResourceRecord, Ttl, WriteOptions
5
+ } from '@owlmeans/resource'
6
+ import {
7
+ applyQuery, filterRecords, firstMatch, MisshapedRecord, RecordExists, UnknownRecordError,
8
+ UnsupportedArgumentError
6
9
  } from '@owlmeans/resource'
7
- import { MisshapedRecord, RecordExists, UnknownRecordError, UnsupportedArgumentError } from '@owlmeans/resource'
8
10
  import type { Config, Context, StaticResourceAppend } from './types.js'
9
11
 
10
- type Getter = string | GetterOptions
11
- type ResourceType = Resource<ResourceRecord>
12
-
13
12
  const stores: Record<string, Map<string, ResourceRecord>> = {}
14
- export const createStaticResource = (alias: string = DEFAULT_ALIAS, key?: string) => {
15
- key = key ?? alias
16
13
 
17
- const getStore = () => {
18
- if (stores[key] == null) {
19
- stores[key] = new Map()
14
+ /**
15
+ * Milliseconds until the record expires, which is what `setTimeout` wants. A number is seconds
16
+ * from now and a Date is the instant to expire at — the two spellings have to land on the same
17
+ * moment, or the same ttl means an hour through one and a second through the other.
18
+ */
19
+ const expiresIn = (ttl: Ttl): number =>
20
+ ttl instanceof Date ? ttl.getTime() - Date.now() : ttl * 1000
21
+
22
+ export const createStaticResource = <T extends ResourceRecord = ResourceRecord>(
23
+ alias: string = DEFAULT_ALIAS, key?: string
24
+ ): Resource<T> => {
25
+ const storeKey = key ?? alias
26
+
27
+ const getStore = (): Map<string, T> => {
28
+ if (stores[storeKey] == null) {
29
+ stores[storeKey] = new Map()
20
30
  }
21
31
 
22
- return stores[key]
32
+ return stores[storeKey] as Map<string, T>
23
33
  }
24
34
 
25
- const resource: Resource<ResourceRecord> = appendContextual<ResourceType>(alias, {
26
- get: async <T extends ResourceRecord>(id: string, field?: Getter, opts?: LifecycleOptions) => {
27
- const record = await resource.load<T>(id, field, opts)
28
- if (record == null) {
29
- throw new UnknownRecordError(id)
30
- }
35
+ const records = (): T[] => [...getStore().values()]
31
36
 
32
- return record
33
- },
37
+ const expire = (id: string, opts?: WriteOptions): void => {
38
+ if (opts?.ttl == null) {
39
+ return
40
+ }
41
+ const store = getStore()
42
+ setTimeout(() => void store.delete(id), expiresIn(opts.ttl))
43
+ }
34
44
 
35
- load: async <T extends ResourceRecord>(id: string, field?: Getter, opts?: LifecycleOptions) => {
36
- field = field ?? 'id'
37
- if (opts != null) {
38
- throw new UnsupportedArgumentError('static:get:opts')
39
- }
40
- const store = getStore()
41
- const record = field === 'id'
42
- ? store.get(id) as T | null
43
- : [...store.values()].find(
44
- record => record[field as keyof typeof record] === id
45
- ) as T | undefined
45
+ /** An id hits the map directly; criteria go through the shared in-memory engine. */
46
+ const first = (idOrWhere: string | Criteria<T>, opts?: FirstOptions<T>): T | null =>
47
+ typeof idOrWhere === 'string'
48
+ ? getStore().get(idOrWhere) ?? null
49
+ : firstMatch(records(), idOrWhere, opts)
50
+
51
+ const write = (record: Partial<T>, opts?: WriteOptions): T => {
52
+ if (record.id == null) {
53
+ /**
54
+ * The store is a map keyed by id and there is nothing here to mint one from, so a record
55
+ * without an id is misshaped rather than new — `save` cannot create it.
56
+ */
57
+ throw new MisshapedRecord('id')
58
+ }
59
+ getStore().set(record.id, record as T)
60
+ expire(record.id, opts)
46
61
 
62
+ return record as T
63
+ }
64
+
65
+ const resource: Resource<T> = appendContextual<Resource<T>>(alias, {
66
+ get: async (idOrWhere: string | Criteria<T>, opts?: FirstOptions<T>): Promise<T> => {
67
+ const record = first(idOrWhere, opts)
47
68
  if (record == null) {
48
- return null
69
+ throw new UnknownRecordError(typeof idOrWhere === 'string' ? idOrWhere : 'criteria')
49
70
  }
50
71
 
51
72
  return record
52
73
  },
53
74
 
54
- list: async <T extends ResourceRecord>(criteria?: ListOptions | ListCriteria, opts?: ListOptions) => {
55
- if (criteria != null) {
56
- throw new UnsupportedArgumentError('static:list:criteria')
57
- }
58
- if (opts != null) {
59
- throw new UnsupportedArgumentError('static:list:opts')
60
- }
75
+ load: async (idOrWhere: string | Criteria<T>, opts?: FirstOptions<T>): Promise<T | null> =>
76
+ first(idOrWhere, opts),
61
77
 
62
- const result: ListResult<T> = {
63
- items: [...getStore().values()] as T[]
78
+ /** Unpaged unless a size is asked for — the whole store is already in memory. */
79
+ list: async (where?: Criteria<T>, opts?: ListOptions<T>) => {
80
+ if (opts?.page != null && opts.size == null) {
81
+ throw new UnsupportedArgumentError('page-without-size')
64
82
  }
65
83
 
66
- return result
84
+ return applyQuery(records(), where, opts)
67
85
  },
68
86
 
69
- save: async <T extends ResourceRecord>(record: Partial<T>, opts?: Getter) => {
70
- const store = getStore()
87
+ count: async (where?: Criteria<T>) => filterRecords(records(), where).length,
88
+
89
+ create: async (record: Partial<T>, opts?: WriteOptions) => {
71
90
  if (record.id == null) {
72
91
  throw new MisshapedRecord('id')
73
92
  }
74
- store.set(record.id, record as ResourceRecord)
75
-
76
- if (typeof opts === 'object' && opts?.ttl != null) {
77
- const ttl = opts.ttl instanceof Date
78
- ? (opts.ttl.getTime() - Date.now()) / 1000
79
- : typeof opts.ttl === 'number'
80
- ? opts.ttl * 1000
81
- : null
82
- if (ttl == null) {
83
- throw new UnsupportedArgumentError('static:opts:ttl-string')
84
- }
85
- setTimeout(() => record.id != null && void store.delete(record.id), ttl)
93
+ if (getStore().has(record.id)) {
94
+ throw new RecordExists(record.id)
86
95
  }
87
96
 
88
- return record as T
97
+ return write(record, opts)
89
98
  },
90
99
 
91
- create: async (record, opts) => {
92
- const store = getStore()
100
+ update: async (record: Partial<T>, opts?: WriteOptions) => {
93
101
  if (record.id == null) {
94
- throw new UnknownRecordError('id')
95
- }
96
- if (store.has(record.id)) {
97
- throw new RecordExists(record.id)
102
+ throw new MisshapedRecord('id')
98
103
  }
99
- store.set(record.id, record)
100
- if (opts?.ttl != null) {
101
- const ttl = opts.ttl instanceof Date
102
- ? (opts.ttl.getTime() - Date.now()) / 1000
103
- : typeof opts.ttl === 'number'
104
- ? opts.ttl * 1000
105
- : null
106
- if (ttl == null) {
107
- throw new UnsupportedArgumentError('static:opts:ttl-string')
108
- }
109
- setTimeout(() => record.id != null && void store.delete(record.id), ttl)
104
+ if (!getStore().has(record.id)) {
105
+ throw new UnknownRecordError(record.id)
110
106
  }
111
107
 
112
- return record as any
113
- },
114
-
115
- update: async (record, opts) => {
116
- return resource.save(record, opts)
108
+ return write(record, opts)
117
109
  },
118
110
 
119
- delete: async (id, opts) => {
120
- let record: ResourceRecord | null = null
121
- if (typeof id === 'object') {
122
- if (id.id == null) {
123
- throw new MisshapedRecord('id')
124
- }
125
- record = await resource.load(id.id)
126
- } else if (typeof opts === 'string') {
127
- record = await resource.load(id, opts)
128
- } else if (typeof id === 'string') {
129
- record = await resource.load(id)
130
- }
111
+ save: async (record: Partial<T>, opts?: WriteOptions) => write(record, opts),
131
112
 
113
+ delete: async (id: string) => {
114
+ const store = getStore()
115
+ const record = store.get(id) ?? null
132
116
  if (record == null) {
133
117
  return null
134
118
  }
119
+ store.delete(id)
135
120
 
136
- let field = 'id'
137
- if (typeof opts === 'string') {
138
- field = opts
139
- opts = undefined
140
- } else if (typeof opts === 'object') {
141
- field = opts.field ?? field
142
- }
143
-
144
- id = record.id ?? ''
145
-
146
- if (id === '') {
147
- throw new MisshapedRecord('id')
148
- }
121
+ return record
122
+ },
149
123
 
124
+ take: async (id: string) => {
150
125
  const store = getStore()
151
- if (store.delete(id)) {
152
- return record as any
126
+ const record = store.get(id)
127
+ if (record == null) {
128
+ throw new UnknownRecordError(id)
153
129
  }
130
+ store.delete(id)
154
131
 
155
- return null
132
+ return record
156
133
  },
157
134
 
158
- pick: async (id, opts) => {
159
- const record = await resource.delete(id, opts)
160
- if (record == null) {
161
- throw new UnknownRecordError((typeof id === 'string' ? id : id.id) ?? 'unknown')
135
+ purge: async (where: Criteria<T>) => {
136
+ if (where == null || Object.keys(where).length < 1) {
137
+ throw new UnsupportedArgumentError('purge:empty-criteria')
162
138
  }
139
+ const store = getStore()
140
+ const matched = filterRecords(records(), where)
141
+ matched.forEach(record => record.id != null && store.delete(record.id))
163
142
 
164
- return record as any
143
+ return matched.length
165
144
  }
166
145
  })
167
146
 
package/build/.gitkeep DELETED
File without changes