@furystack/repository 10.0.35 → 10.0.37
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/CHANGELOG.md +20 -0
- package/README.md +24 -0
- package/esm/data-set.d.ts +42 -7
- package/esm/data-set.d.ts.map +1 -1
- package/esm/data-set.js +42 -7
- package/esm/data-set.js.map +1 -1
- package/esm/helpers.d.ts +25 -1
- package/esm/helpers.d.ts.map +1 -1
- package/esm/helpers.js +25 -1
- package/esm/helpers.js.map +1 -1
- package/package.json +5 -5
- package/src/data-set.ts +42 -7
- package/src/helpers.ts +25 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [10.0.37] - 2026-02-19
|
|
4
|
+
|
|
5
|
+
### 📚 Documentation
|
|
6
|
+
|
|
7
|
+
- Expanded JSDoc on `DataSet` class to explain its role as the authorized write gateway with event dispatching
|
|
8
|
+
- Expanded JSDoc on `add()`, `update()`, and `remove()` to document authorization checks, hooks, and emitted events
|
|
9
|
+
- Expanded JSDoc on `getDataSetFor()` with usage examples for server-side writes using `useSystemIdentityContext`
|
|
10
|
+
- Added README section covering server-side writes with the elevated `IdentityContext`, including a warning about bypassing the DataSet layer
|
|
11
|
+
|
|
12
|
+
### ⬆️ Dependencies
|
|
13
|
+
|
|
14
|
+
- Updated `@furystack/core`
|
|
15
|
+
|
|
16
|
+
## [10.0.36] - 2026-02-11
|
|
17
|
+
|
|
18
|
+
### ⬆️ Dependencies
|
|
19
|
+
|
|
20
|
+
- Bump `vitest` from `^4.0.17` to `^4.0.18`
|
|
21
|
+
- Updated internal dependencies
|
|
22
|
+
|
|
3
23
|
## [10.0.35] - 2026-02-09
|
|
4
24
|
|
|
5
25
|
### ⬆️ Dependencies
|
package/README.md
CHANGED
|
@@ -70,3 +70,27 @@ There is an additional property called `addFilter`, you can use that to add a pr
|
|
|
70
70
|
### Getting the Context
|
|
71
71
|
|
|
72
72
|
All methods above have an _injector instance_ on the call parameter - you can use that injector to get service instances from the right caller context. It means that you can use e.g. HttpUserContext to get the current user.
|
|
73
|
+
|
|
74
|
+
### Server-side writes and the elevated IdentityContext
|
|
75
|
+
|
|
76
|
+
The DataSet is the **recommended write gateway** for all entity mutations. Writing through the DataSet ensures that authorization rules, modification hooks, and change events (`onEntityAdded`, `onEntityUpdated`, `onEntityRemoved`) are all triggered. These events are required for features like [entity sync](./../entity-sync-service/README.md) to work correctly.
|
|
77
|
+
|
|
78
|
+
> **Warning:** Writing directly to the underlying physical store bypasses the DataSet layer entirely. No authorization checks, hooks, or events will fire, and downstream consumers (such as entity sync) will **not** be notified of the change.
|
|
79
|
+
|
|
80
|
+
For server-side or background operations that don't originate from an HTTP request (e.g. scheduled jobs, migrations, seed scripts), you won't have a user session. Use `useSystemIdentityContext` from `@furystack/core` to create a scoped child injector with elevated privileges:
|
|
81
|
+
|
|
82
|
+
```ts
|
|
83
|
+
import { useSystemIdentityContext } from '@furystack/core'
|
|
84
|
+
import { getDataSetFor } from '@furystack/repository'
|
|
85
|
+
import { usingAsync } from '@furystack/utils'
|
|
86
|
+
|
|
87
|
+
await usingAsync(useSystemIdentityContext({ injector, username: 'background-job' }), async (systemInjector) => {
|
|
88
|
+
const dataSet = getDataSetFor(systemInjector, MyModel, 'id')
|
|
89
|
+
await dataSet.add(systemInjector, { value: 'created by background job' })
|
|
90
|
+
})
|
|
91
|
+
// systemInjector is disposed here -- all scoped instances cleaned up
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
> **Warning:** `useSystemIdentityContext` bypasses **all** authorization checks. Only use it in trusted server-side contexts. Never pass the returned injector to user-facing request handlers.
|
|
95
|
+
|
|
96
|
+
This pattern ensures that all writes go through the same pipeline, keeping authorization, hooks, and event-driven features consistent regardless of the caller.
|
package/esm/data-set.d.ts
CHANGED
|
@@ -3,7 +3,33 @@ import type { Injector } from '@furystack/inject';
|
|
|
3
3
|
import { EventHub } from '@furystack/utils';
|
|
4
4
|
import type { DataSetSettings } from './data-set-setting.js';
|
|
5
5
|
/**
|
|
6
|
-
* An authorized Repository Store instance
|
|
6
|
+
* An authorized Repository Store instance that wraps a {@link PhysicalStore} with authorization,
|
|
7
|
+
* modification hooks, and event dispatching.
|
|
8
|
+
*
|
|
9
|
+
* The DataSet is the **recommended write gateway** for all entity mutations. Writing through the DataSet
|
|
10
|
+
* ensures that authorization rules are enforced, modification hooks are applied, and change events
|
|
11
|
+
* (`onEntityAdded`, `onEntityUpdated`, `onEntityRemoved`) are emitted -- which are required for features
|
|
12
|
+
* like entity sync to function correctly.
|
|
13
|
+
*
|
|
14
|
+
* All mutating methods require an `injector` parameter that provides the caller's context (e.g. the current
|
|
15
|
+
* user's identity). For server-side or background operations that don't originate from an HTTP request,
|
|
16
|
+
* use {@link useSystemIdentityContext} to create a scoped child injector with elevated privileges.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```ts
|
|
20
|
+
* import { useSystemIdentityContext } from '@furystack/core'
|
|
21
|
+
* import { getDataSetFor } from '@furystack/repository'
|
|
22
|
+
* import { usingAsync } from '@furystack/utils'
|
|
23
|
+
*
|
|
24
|
+
* // Server-side write with an elevated identity
|
|
25
|
+
* await usingAsync(
|
|
26
|
+
* useSystemIdentityContext({ injector, username: 'background-job' }),
|
|
27
|
+
* async (systemInjector) => {
|
|
28
|
+
* const dataSet = getDataSetFor(systemInjector, MyModel, 'id')
|
|
29
|
+
* await dataSet.add(systemInjector, newEntity)
|
|
30
|
+
* },
|
|
31
|
+
* )
|
|
32
|
+
* ```
|
|
7
33
|
*/
|
|
8
34
|
export declare class DataSet<T, TPrimaryKey extends keyof T, TWritableData = WithOptionalId<T, TPrimaryKey>> extends EventHub<{
|
|
9
35
|
onEntityAdded: {
|
|
@@ -26,15 +52,21 @@ export declare class DataSet<T, TPrimaryKey extends keyof T, TWritableData = Wit
|
|
|
26
52
|
*/
|
|
27
53
|
primaryKey: TPrimaryKey;
|
|
28
54
|
/**
|
|
29
|
-
* Adds an entity to the DataSet
|
|
30
|
-
*
|
|
55
|
+
* Adds an entity to the DataSet.
|
|
56
|
+
* Runs authorization checks, applies modification hooks, persists to the physical store,
|
|
57
|
+
* and emits an `onEntityAdded` event for each created entity.
|
|
58
|
+
* @param injector The injector from the caller's context. For server-side or background operations
|
|
59
|
+
* without an HTTP request, use a child injector with an elevated {@link IdentityContext}.
|
|
31
60
|
* @param entities The entities to add
|
|
32
61
|
* @returns The CreateResult with the created entities
|
|
33
62
|
*/
|
|
34
63
|
add(injector: Injector, ...entities: TWritableData[]): Promise<CreateResult<T>>;
|
|
35
64
|
/**
|
|
36
|
-
* Updates an entity in the store
|
|
37
|
-
*
|
|
65
|
+
* Updates an entity in the store.
|
|
66
|
+
* Runs authorization checks, applies modification hooks, persists to the physical store,
|
|
67
|
+
* and emits an `onEntityUpdated` event.
|
|
68
|
+
* @param injector The injector from the caller's context. For server-side or background operations
|
|
69
|
+
* without an HTTP request, use a child injector with an elevated {@link IdentityContext}.
|
|
38
70
|
* @param id The identifier of the entity
|
|
39
71
|
* @param change The update
|
|
40
72
|
*/
|
|
@@ -62,8 +94,11 @@ export declare class DataSet<T, TPrimaryKey extends keyof T, TWritableData = Wit
|
|
|
62
94
|
*/
|
|
63
95
|
get(injector: Injector, key: T[TPrimaryKey], select?: Array<keyof T>): Promise<PartialResult<T, (keyof T)[]> | undefined>;
|
|
64
96
|
/**
|
|
65
|
-
* Removes an entity based on its primary key
|
|
66
|
-
*
|
|
97
|
+
* Removes an entity based on its primary key.
|
|
98
|
+
* Runs authorization checks, persists to the physical store,
|
|
99
|
+
* and emits an `onEntityRemoved` event.
|
|
100
|
+
* @param injector The injector from the caller's context. For server-side or background operations
|
|
101
|
+
* without an HTTP request, use a child injector with an elevated {@link IdentityContext}.
|
|
67
102
|
* @param key The primary key
|
|
68
103
|
* @returns A promise that will be resolved / rejected based on the remove success
|
|
69
104
|
*/
|
package/esm/data-set.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"data-set.d.ts","sourceRoot":"","sources":["../src/data-set.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AAE3G,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AACjD,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAA;AAC3C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAA;AAE5D
|
|
1
|
+
{"version":3,"file":"data-set.d.ts","sourceRoot":"","sources":["../src/data-set.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AAE3G,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AACjD,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAA;AAC3C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAA;AAE5D;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,qBAAa,OAAO,CAAC,CAAC,EAAE,WAAW,SAAS,MAAM,CAAC,EAAE,aAAa,GAAG,cAAc,CAAC,CAAC,EAAE,WAAW,CAAC,CACjG,SAAQ,QAAQ,CAAC;IACf,aAAa,EAAE;QAAE,QAAQ,EAAE,QAAQ,CAAC;QAAC,MAAM,EAAE,CAAC,CAAA;KAAE,CAAA;IAChD,eAAe,EAAE;QAAE,QAAQ,EAAE,QAAQ,CAAC;QAAC,EAAE,EAAE,CAAC,CAAC,WAAW,CAAC,CAAC;QAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,CAAA;KAAE,CAAA;IAC/E,eAAe,EAAE;QAAE,QAAQ,EAAE,QAAQ,CAAC;QAAC,GAAG,EAAE,CAAC,CAAC,WAAW,CAAC,CAAA;KAAE,CAAA;CAC7D,CACD,YAAW,UAAU;aAkKO,QAAQ,EAAE,eAAe,CAAC,CAAC,EAAE,WAAW,EAAE,aAAa,CAAC;IAhKpF;;OAEG;IACI,UAAU,EAAE,WAAW,CAAA;IAE9B;;;;;;;;OAQG;IACU,GAAG,CAAC,QAAQ,EAAE,QAAQ,EAAE,GAAG,QAAQ,EAAE,aAAa,EAAE,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IAyB5F;;;;;;;;OAQG;IACU,MAAM,CAAC,QAAQ,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,CAAC,WAAW,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAuB9F;;;;;OAKG;IACU,KAAK,CAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE,UAAU,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC;IAU/E;;;;;OAKG;IACU,IAAI,CAAC,OAAO,SAAS,KAAK,CAAC,MAAM,CAAC,CAAC,EAC9C,QAAQ,EAAE,QAAQ,EAClB,MAAM,EAAE,WAAW,CAAC,CAAC,EAAE,OAAO,CAAC,GAC9B,OAAO,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC;IAW5C;;;;;;OAMG;IACU,GAAG,CAAC,QAAQ,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAiBjF;;;;;;;;OAQG;IACU,MAAM,CAAC,QAAQ,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,CAAC,WAAW,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;gBAoB/C,QAAQ,EAAE,eAAe,CAAC,CAAC,EAAE,WAAW,EAAE,aAAa,CAAC;CAIrF"}
|
package/esm/data-set.js
CHANGED
|
@@ -1,7 +1,33 @@
|
|
|
1
1
|
import { AuthorizationError } from '@furystack/core';
|
|
2
2
|
import { EventHub } from '@furystack/utils';
|
|
3
3
|
/**
|
|
4
|
-
* An authorized Repository Store instance
|
|
4
|
+
* An authorized Repository Store instance that wraps a {@link PhysicalStore} with authorization,
|
|
5
|
+
* modification hooks, and event dispatching.
|
|
6
|
+
*
|
|
7
|
+
* The DataSet is the **recommended write gateway** for all entity mutations. Writing through the DataSet
|
|
8
|
+
* ensures that authorization rules are enforced, modification hooks are applied, and change events
|
|
9
|
+
* (`onEntityAdded`, `onEntityUpdated`, `onEntityRemoved`) are emitted -- which are required for features
|
|
10
|
+
* like entity sync to function correctly.
|
|
11
|
+
*
|
|
12
|
+
* All mutating methods require an `injector` parameter that provides the caller's context (e.g. the current
|
|
13
|
+
* user's identity). For server-side or background operations that don't originate from an HTTP request,
|
|
14
|
+
* use {@link useSystemIdentityContext} to create a scoped child injector with elevated privileges.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```ts
|
|
18
|
+
* import { useSystemIdentityContext } from '@furystack/core'
|
|
19
|
+
* import { getDataSetFor } from '@furystack/repository'
|
|
20
|
+
* import { usingAsync } from '@furystack/utils'
|
|
21
|
+
*
|
|
22
|
+
* // Server-side write with an elevated identity
|
|
23
|
+
* await usingAsync(
|
|
24
|
+
* useSystemIdentityContext({ injector, username: 'background-job' }),
|
|
25
|
+
* async (systemInjector) => {
|
|
26
|
+
* const dataSet = getDataSetFor(systemInjector, MyModel, 'id')
|
|
27
|
+
* await dataSet.add(systemInjector, newEntity)
|
|
28
|
+
* },
|
|
29
|
+
* )
|
|
30
|
+
* ```
|
|
5
31
|
*/
|
|
6
32
|
export class DataSet extends EventHub {
|
|
7
33
|
settings;
|
|
@@ -10,8 +36,11 @@ export class DataSet extends EventHub {
|
|
|
10
36
|
*/
|
|
11
37
|
primaryKey;
|
|
12
38
|
/**
|
|
13
|
-
* Adds an entity to the DataSet
|
|
14
|
-
*
|
|
39
|
+
* Adds an entity to the DataSet.
|
|
40
|
+
* Runs authorization checks, applies modification hooks, persists to the physical store,
|
|
41
|
+
* and emits an `onEntityAdded` event for each created entity.
|
|
42
|
+
* @param injector The injector from the caller's context. For server-side or background operations
|
|
43
|
+
* without an HTTP request, use a child injector with an elevated {@link IdentityContext}.
|
|
15
44
|
* @param entities The entities to add
|
|
16
45
|
* @returns The CreateResult with the created entities
|
|
17
46
|
*/
|
|
@@ -34,8 +63,11 @@ export class DataSet extends EventHub {
|
|
|
34
63
|
return createResult;
|
|
35
64
|
}
|
|
36
65
|
/**
|
|
37
|
-
* Updates an entity in the store
|
|
38
|
-
*
|
|
66
|
+
* Updates an entity in the store.
|
|
67
|
+
* Runs authorization checks, applies modification hooks, persists to the physical store,
|
|
68
|
+
* and emits an `onEntityUpdated` event.
|
|
69
|
+
* @param injector The injector from the caller's context. For server-side or background operations
|
|
70
|
+
* without an HTTP request, use a child injector with an elevated {@link IdentityContext}.
|
|
39
71
|
* @param id The identifier of the entity
|
|
40
72
|
* @param change The update
|
|
41
73
|
*/
|
|
@@ -116,8 +148,11 @@ export class DataSet extends EventHub {
|
|
|
116
148
|
return instance;
|
|
117
149
|
}
|
|
118
150
|
/**
|
|
119
|
-
* Removes an entity based on its primary key
|
|
120
|
-
*
|
|
151
|
+
* Removes an entity based on its primary key.
|
|
152
|
+
* Runs authorization checks, persists to the physical store,
|
|
153
|
+
* and emits an `onEntityRemoved` event.
|
|
154
|
+
* @param injector The injector from the caller's context. For server-side or background operations
|
|
155
|
+
* without an HTTP request, use a child injector with an elevated {@link IdentityContext}.
|
|
121
156
|
* @param key The primary key
|
|
122
157
|
* @returns A promise that will be resolved / rejected based on the remove success
|
|
123
158
|
*/
|
package/esm/data-set.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"data-set.js","sourceRoot":"","sources":["../src/data-set.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAA;AAEpD,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAA;AAG3C
|
|
1
|
+
{"version":3,"file":"data-set.js","sourceRoot":"","sources":["../src/data-set.ts"],"names":[],"mappings":"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"}
|
package/esm/helpers.d.ts
CHANGED
|
@@ -7,11 +7,35 @@ import { Repository } from './repository.js';
|
|
|
7
7
|
*/
|
|
8
8
|
export declare const getRepository: (injector: Injector) => Repository;
|
|
9
9
|
/**
|
|
10
|
-
* Gets a DataSet for a specific model from the repository
|
|
10
|
+
* Gets a DataSet for a specific model from the repository.
|
|
11
|
+
*
|
|
12
|
+
* The DataSet is the recommended way to perform all entity mutations (add, update, remove).
|
|
13
|
+
* Writing through the DataSet ensures that authorization, modification hooks, and change events
|
|
14
|
+
* are properly triggered -- which is required for features like entity sync.
|
|
15
|
+
*
|
|
16
|
+
* For server-side or background operations that don't originate from an HTTP request,
|
|
17
|
+
* use {@link useSystemIdentityContext} to create a scoped child injector with elevated privileges.
|
|
18
|
+
*
|
|
11
19
|
* @param injector The Injector instance
|
|
12
20
|
* @param model The Model
|
|
13
21
|
* @param primaryKey The Primary Key field
|
|
14
22
|
* @returns A Repository DataSet for a specific model
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```ts
|
|
26
|
+
* import { useSystemIdentityContext } from '@furystack/core'
|
|
27
|
+
* import { getDataSetFor } from '@furystack/repository'
|
|
28
|
+
* import { usingAsync } from '@furystack/utils'
|
|
29
|
+
*
|
|
30
|
+
* // In a background job or service
|
|
31
|
+
* await usingAsync(
|
|
32
|
+
* useSystemIdentityContext({ injector, username: 'background-job' }),
|
|
33
|
+
* async (systemInjector) => {
|
|
34
|
+
* const dataSet = getDataSetFor(systemInjector, MyModel, 'id')
|
|
35
|
+
* await dataSet.add(systemInjector, newEntity)
|
|
36
|
+
* },
|
|
37
|
+
* )
|
|
38
|
+
* ```
|
|
15
39
|
*/
|
|
16
40
|
export declare const getDataSetFor: <T, TPrimaryKey extends keyof T>(injector: Injector, model: Constructable<T>, primaryKey: TPrimaryKey) => import("./data-set.js").DataSet<T, TPrimaryKey, import("@furystack/core").WithOptionalId<T, TPrimaryKey>>;
|
|
17
41
|
//# sourceMappingURL=helpers.d.ts.map
|
package/esm/helpers.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../src/helpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAChE,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAE5C;;;;GAIG;AACH,eAAO,MAAM,aAAa,GAAI,UAAU,QAAQ,eAAqC,CAAA;AAErF
|
|
1
|
+
{"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../src/helpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAChE,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAE5C;;;;GAIG;AACH,eAAO,MAAM,aAAa,GAAI,UAAU,QAAQ,eAAqC,CAAA;AAErF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,eAAO,MAAM,aAAa,GAAI,CAAC,EAAE,WAAW,SAAS,MAAM,CAAC,EAC1D,UAAU,QAAQ,EAClB,OAAO,aAAa,CAAC,CAAC,CAAC,EACvB,YAAY,WAAW,8GAC6C,CAAA"}
|
package/esm/helpers.js
CHANGED
|
@@ -6,11 +6,35 @@ import { Repository } from './repository.js';
|
|
|
6
6
|
*/
|
|
7
7
|
export const getRepository = (injector) => injector.getInstance(Repository);
|
|
8
8
|
/**
|
|
9
|
-
* Gets a DataSet for a specific model from the repository
|
|
9
|
+
* Gets a DataSet for a specific model from the repository.
|
|
10
|
+
*
|
|
11
|
+
* The DataSet is the recommended way to perform all entity mutations (add, update, remove).
|
|
12
|
+
* Writing through the DataSet ensures that authorization, modification hooks, and change events
|
|
13
|
+
* are properly triggered -- which is required for features like entity sync.
|
|
14
|
+
*
|
|
15
|
+
* For server-side or background operations that don't originate from an HTTP request,
|
|
16
|
+
* use {@link useSystemIdentityContext} to create a scoped child injector with elevated privileges.
|
|
17
|
+
*
|
|
10
18
|
* @param injector The Injector instance
|
|
11
19
|
* @param model The Model
|
|
12
20
|
* @param primaryKey The Primary Key field
|
|
13
21
|
* @returns A Repository DataSet for a specific model
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```ts
|
|
25
|
+
* import { useSystemIdentityContext } from '@furystack/core'
|
|
26
|
+
* import { getDataSetFor } from '@furystack/repository'
|
|
27
|
+
* import { usingAsync } from '@furystack/utils'
|
|
28
|
+
*
|
|
29
|
+
* // In a background job or service
|
|
30
|
+
* await usingAsync(
|
|
31
|
+
* useSystemIdentityContext({ injector, username: 'background-job' }),
|
|
32
|
+
* async (systemInjector) => {
|
|
33
|
+
* const dataSet = getDataSetFor(systemInjector, MyModel, 'id')
|
|
34
|
+
* await dataSet.add(systemInjector, newEntity)
|
|
35
|
+
* },
|
|
36
|
+
* )
|
|
37
|
+
* ```
|
|
14
38
|
*/
|
|
15
39
|
export const getDataSetFor = (injector, model, primaryKey) => injector.getInstance(Repository).getDataSetFor(model, primaryKey);
|
|
16
40
|
//# sourceMappingURL=helpers.js.map
|
package/esm/helpers.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"helpers.js","sourceRoot":"","sources":["../src/helpers.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAE5C;;;;GAIG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,QAAkB,EAAE,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC,UAAU,CAAC,CAAA;AAErF
|
|
1
|
+
{"version":3,"file":"helpers.js","sourceRoot":"","sources":["../src/helpers.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAE5C;;;;GAIG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,QAAkB,EAAE,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC,UAAU,CAAC,CAAA;AAErF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,CAC3B,QAAkB,EAClB,KAAuB,EACvB,UAAuB,EACvB,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC,aAAa,CAAC,KAAK,EAAE,UAAU,CAAC,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@furystack/repository",
|
|
3
|
-
"version": "10.0.
|
|
3
|
+
"version": "10.0.37",
|
|
4
4
|
"description": "Repository implementation for FuryStack",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
@@ -38,13 +38,13 @@
|
|
|
38
38
|
},
|
|
39
39
|
"homepage": "https://github.com/furystack/furystack",
|
|
40
40
|
"dependencies": {
|
|
41
|
-
"@furystack/core": "^15.0
|
|
42
|
-
"@furystack/inject": "^12.0.
|
|
43
|
-
"@furystack/utils": "^8.1.
|
|
41
|
+
"@furystack/core": "^15.1.0",
|
|
42
|
+
"@furystack/inject": "^12.0.30",
|
|
43
|
+
"@furystack/utils": "^8.1.10"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
46
|
"typescript": "^5.9.3",
|
|
47
|
-
"vitest": "^4.0.
|
|
47
|
+
"vitest": "^4.0.18"
|
|
48
48
|
},
|
|
49
49
|
"engines": {
|
|
50
50
|
"node": ">=22.0.0"
|
package/src/data-set.ts
CHANGED
|
@@ -5,7 +5,33 @@ import { EventHub } from '@furystack/utils'
|
|
|
5
5
|
import type { DataSetSettings } from './data-set-setting.js'
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
|
-
* An authorized Repository Store instance
|
|
8
|
+
* An authorized Repository Store instance that wraps a {@link PhysicalStore} with authorization,
|
|
9
|
+
* modification hooks, and event dispatching.
|
|
10
|
+
*
|
|
11
|
+
* The DataSet is the **recommended write gateway** for all entity mutations. Writing through the DataSet
|
|
12
|
+
* ensures that authorization rules are enforced, modification hooks are applied, and change events
|
|
13
|
+
* (`onEntityAdded`, `onEntityUpdated`, `onEntityRemoved`) are emitted -- which are required for features
|
|
14
|
+
* like entity sync to function correctly.
|
|
15
|
+
*
|
|
16
|
+
* All mutating methods require an `injector` parameter that provides the caller's context (e.g. the current
|
|
17
|
+
* user's identity). For server-side or background operations that don't originate from an HTTP request,
|
|
18
|
+
* use {@link useSystemIdentityContext} to create a scoped child injector with elevated privileges.
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```ts
|
|
22
|
+
* import { useSystemIdentityContext } from '@furystack/core'
|
|
23
|
+
* import { getDataSetFor } from '@furystack/repository'
|
|
24
|
+
* import { usingAsync } from '@furystack/utils'
|
|
25
|
+
*
|
|
26
|
+
* // Server-side write with an elevated identity
|
|
27
|
+
* await usingAsync(
|
|
28
|
+
* useSystemIdentityContext({ injector, username: 'background-job' }),
|
|
29
|
+
* async (systemInjector) => {
|
|
30
|
+
* const dataSet = getDataSetFor(systemInjector, MyModel, 'id')
|
|
31
|
+
* await dataSet.add(systemInjector, newEntity)
|
|
32
|
+
* },
|
|
33
|
+
* )
|
|
34
|
+
* ```
|
|
9
35
|
*/
|
|
10
36
|
export class DataSet<T, TPrimaryKey extends keyof T, TWritableData = WithOptionalId<T, TPrimaryKey>>
|
|
11
37
|
extends EventHub<{
|
|
@@ -21,8 +47,11 @@ export class DataSet<T, TPrimaryKey extends keyof T, TWritableData = WithOptiona
|
|
|
21
47
|
public primaryKey: TPrimaryKey
|
|
22
48
|
|
|
23
49
|
/**
|
|
24
|
-
* Adds an entity to the DataSet
|
|
25
|
-
*
|
|
50
|
+
* Adds an entity to the DataSet.
|
|
51
|
+
* Runs authorization checks, applies modification hooks, persists to the physical store,
|
|
52
|
+
* and emits an `onEntityAdded` event for each created entity.
|
|
53
|
+
* @param injector The injector from the caller's context. For server-side or background operations
|
|
54
|
+
* without an HTTP request, use a child injector with an elevated {@link IdentityContext}.
|
|
26
55
|
* @param entities The entities to add
|
|
27
56
|
* @returns The CreateResult with the created entities
|
|
28
57
|
*/
|
|
@@ -52,8 +81,11 @@ export class DataSet<T, TPrimaryKey extends keyof T, TWritableData = WithOptiona
|
|
|
52
81
|
}
|
|
53
82
|
|
|
54
83
|
/**
|
|
55
|
-
* Updates an entity in the store
|
|
56
|
-
*
|
|
84
|
+
* Updates an entity in the store.
|
|
85
|
+
* Runs authorization checks, applies modification hooks, persists to the physical store,
|
|
86
|
+
* and emits an `onEntityUpdated` event.
|
|
87
|
+
* @param injector The injector from the caller's context. For server-side or background operations
|
|
88
|
+
* without an HTTP request, use a child injector with an elevated {@link IdentityContext}.
|
|
57
89
|
* @param id The identifier of the entity
|
|
58
90
|
* @param change The update
|
|
59
91
|
*/
|
|
@@ -141,8 +173,11 @@ export class DataSet<T, TPrimaryKey extends keyof T, TWritableData = WithOptiona
|
|
|
141
173
|
}
|
|
142
174
|
|
|
143
175
|
/**
|
|
144
|
-
* Removes an entity based on its primary key
|
|
145
|
-
*
|
|
176
|
+
* Removes an entity based on its primary key.
|
|
177
|
+
* Runs authorization checks, persists to the physical store,
|
|
178
|
+
* and emits an `onEntityRemoved` event.
|
|
179
|
+
* @param injector The injector from the caller's context. For server-side or background operations
|
|
180
|
+
* without an HTTP request, use a child injector with an elevated {@link IdentityContext}.
|
|
146
181
|
* @param key The primary key
|
|
147
182
|
* @returns A promise that will be resolved / rejected based on the remove success
|
|
148
183
|
*/
|
package/src/helpers.ts
CHANGED
|
@@ -9,11 +9,35 @@ import { Repository } from './repository.js'
|
|
|
9
9
|
export const getRepository = (injector: Injector) => injector.getInstance(Repository)
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
|
-
* Gets a DataSet for a specific model from the repository
|
|
12
|
+
* Gets a DataSet for a specific model from the repository.
|
|
13
|
+
*
|
|
14
|
+
* The DataSet is the recommended way to perform all entity mutations (add, update, remove).
|
|
15
|
+
* Writing through the DataSet ensures that authorization, modification hooks, and change events
|
|
16
|
+
* are properly triggered -- which is required for features like entity sync.
|
|
17
|
+
*
|
|
18
|
+
* For server-side or background operations that don't originate from an HTTP request,
|
|
19
|
+
* use {@link useSystemIdentityContext} to create a scoped child injector with elevated privileges.
|
|
20
|
+
*
|
|
13
21
|
* @param injector The Injector instance
|
|
14
22
|
* @param model The Model
|
|
15
23
|
* @param primaryKey The Primary Key field
|
|
16
24
|
* @returns A Repository DataSet for a specific model
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```ts
|
|
28
|
+
* import { useSystemIdentityContext } from '@furystack/core'
|
|
29
|
+
* import { getDataSetFor } from '@furystack/repository'
|
|
30
|
+
* import { usingAsync } from '@furystack/utils'
|
|
31
|
+
*
|
|
32
|
+
* // In a background job or service
|
|
33
|
+
* await usingAsync(
|
|
34
|
+
* useSystemIdentityContext({ injector, username: 'background-job' }),
|
|
35
|
+
* async (systemInjector) => {
|
|
36
|
+
* const dataSet = getDataSetFor(systemInjector, MyModel, 'id')
|
|
37
|
+
* await dataSet.add(systemInjector, newEntity)
|
|
38
|
+
* },
|
|
39
|
+
* )
|
|
40
|
+
* ```
|
|
17
41
|
*/
|
|
18
42
|
export const getDataSetFor = <T, TPrimaryKey extends keyof T>(
|
|
19
43
|
injector: Injector,
|