@nest-yalc-2/omnikernel-module 1.1.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.
Files changed (230) hide show
  1. package/LICENSE +661 -0
  2. package/README.md +193 -0
  3. package/package.json +52 -0
  4. package/src/__tests__/omni-collection.entity.spec.ts +49 -0
  5. package/src/__tests__/omni-collection.service.spec.ts +83 -0
  6. package/src/__tests__/omni-document.entity.spec.ts +55 -0
  7. package/src/__tests__/omni-document.service.spec.ts +83 -0
  8. package/src/__tests__/omni-extension-projection-constraints.spec.ts +518 -0
  9. package/src/__tests__/omni-extension-projection.registration.spec.ts +946 -0
  10. package/src/__tests__/omni-extension-projection.service.spec.ts +806 -0
  11. package/src/__tests__/omni-external-ref.entity.spec.ts +36 -0
  12. package/src/__tests__/omni-external-ref.service.spec.ts +252 -0
  13. package/src/__tests__/omni-named.entity.spec.ts +33 -0
  14. package/src/__tests__/omni-record.entity.spec.ts +32 -0
  15. package/src/__tests__/omni-record.service.spec.ts +107 -0
  16. package/src/__tests__/omni-relation-semantics.spec.ts +102 -0
  17. package/src/__tests__/omni-relation.entity.spec.ts +38 -0
  18. package/src/__tests__/omni-scope-substrate.spec.ts +81 -0
  19. package/src/__tests__/omni-scoped.backend.spec.ts +115 -0
  20. package/src/__tests__/omni-scoped.service.spec.ts +354 -0
  21. package/src/__tests__/omnikernel.diagnostics.spec.ts +94 -0
  22. package/src/__tests__/omnikernel.module.spec.ts +40 -0
  23. package/src/__tests__/omnikernel.persistence.spec.ts +154 -0
  24. package/src/__tests__/omnikernel.public-api.spec.ts +238 -0
  25. package/src/__tests__/omnikernel.query.service.spec.ts +155 -0
  26. package/src/__tests__/tsconfig.json +6 -0
  27. package/src/base/omni-base.entity.d.ts +9 -0
  28. package/src/base/omni-base.entity.js +53 -0
  29. package/src/base/omni-base.entity.js.map +1 -0
  30. package/src/base/omni-base.entity.ts +41 -0
  31. package/src/base/omni-external-ref.entity.d.ts +13 -0
  32. package/src/base/omni-external-ref.entity.js +72 -0
  33. package/src/base/omni-external-ref.entity.js.map +1 -0
  34. package/src/base/omni-external-ref.entity.ts +53 -0
  35. package/src/base/omni-named.entity.d.ts +6 -0
  36. package/src/base/omni-named.entity.js +35 -0
  37. package/src/base/omni-named.entity.js.map +1 -0
  38. package/src/base/omni-named.entity.ts +16 -0
  39. package/src/base/omni-record.entity.d.ts +13 -0
  40. package/src/base/omni-record.entity.js +71 -0
  41. package/src/base/omni-record.entity.js.map +1 -0
  42. package/src/base/omni-record.entity.ts +51 -0
  43. package/src/base/omni-relation.entity.d.ts +15 -0
  44. package/src/base/omni-relation.entity.js +91 -0
  45. package/src/base/omni-relation.entity.js.map +1 -0
  46. package/src/base/omni-relation.entity.ts +72 -0
  47. package/src/index.d.ts +49 -0
  48. package/src/index.js +66 -0
  49. package/src/index.js.map +1 -0
  50. package/src/index.ts +49 -0
  51. package/src/omni-collection-kind.enum.d.ts +4 -0
  52. package/src/omni-collection-kind.enum.js +13 -0
  53. package/src/omni-collection-kind.enum.js.map +1 -0
  54. package/src/omni-collection-kind.enum.ts +10 -0
  55. package/src/omni-collection.backend.d.ts +2 -0
  56. package/src/omni-collection.backend.js +15 -0
  57. package/src/omni-collection.backend.js.map +1 -0
  58. package/src/omni-collection.backend.ts +16 -0
  59. package/src/omni-collection.dto.d.ts +32 -0
  60. package/src/omni-collection.dto.js +184 -0
  61. package/src/omni-collection.dto.js.map +1 -0
  62. package/src/omni-collection.dto.ts +170 -0
  63. package/src/omni-collection.entity.d.ts +7 -0
  64. package/src/omni-collection.entity.js +41 -0
  65. package/src/omni-collection.entity.js.map +1 -0
  66. package/src/omni-collection.entity.ts +21 -0
  67. package/src/omni-collection.service.d.ts +14 -0
  68. package/src/omni-collection.service.js +24 -0
  69. package/src/omni-collection.service.js.map +1 -0
  70. package/src/omni-collection.service.ts +75 -0
  71. package/src/omni-document-kind.enum.d.ts +6 -0
  72. package/src/omni-document-kind.enum.js +15 -0
  73. package/src/omni-document-kind.enum.js.map +1 -0
  74. package/src/omni-document-kind.enum.ts +12 -0
  75. package/src/omni-document.backend.d.ts +2 -0
  76. package/src/omni-document.backend.js +15 -0
  77. package/src/omni-document.backend.js.map +1 -0
  78. package/src/omni-document.backend.ts +16 -0
  79. package/src/omni-document.dto.d.ts +35 -0
  80. package/src/omni-document.dto.js +213 -0
  81. package/src/omni-document.dto.js.map +1 -0
  82. package/src/omni-document.dto.ts +198 -0
  83. package/src/omni-document.entity.d.ts +10 -0
  84. package/src/omni-document.entity.js +53 -0
  85. package/src/omni-document.entity.js.map +1 -0
  86. package/src/omni-document.entity.ts +30 -0
  87. package/src/omni-document.service.d.ts +14 -0
  88. package/src/omni-document.service.js +24 -0
  89. package/src/omni-document.service.js.map +1 -0
  90. package/src/omni-document.service.ts +75 -0
  91. package/src/omni-dto.helpers.d.ts +1 -0
  92. package/src/omni-dto.helpers.js +10 -0
  93. package/src/omni-dto.helpers.js.map +1 -0
  94. package/src/omni-dto.helpers.ts +21 -0
  95. package/src/omni-extension-projection.definition.d.ts +17 -0
  96. package/src/omni-extension-projection.definition.js +160 -0
  97. package/src/omni-extension-projection.definition.js.map +1 -0
  98. package/src/omni-extension-projection.definition.ts +294 -0
  99. package/src/omni-extension-projection.resource.d.ts +42 -0
  100. package/src/omni-extension-projection.resource.js +127 -0
  101. package/src/omni-extension-projection.resource.js.map +1 -0
  102. package/src/omni-extension-projection.resource.ts +274 -0
  103. package/src/omni-extension-projection.service.d.ts +33 -0
  104. package/src/omni-extension-projection.service.js +332 -0
  105. package/src/omni-extension-projection.service.js.map +1 -0
  106. package/src/omni-extension-projection.service.ts +452 -0
  107. package/src/omni-external-ref-binding.validator.d.ts +14 -0
  108. package/src/omni-external-ref-binding.validator.js +34 -0
  109. package/src/omni-external-ref-binding.validator.js.map +1 -0
  110. package/src/omni-external-ref-binding.validator.ts +53 -0
  111. package/src/omni-external-ref-internal-type.enum.d.ts +5 -0
  112. package/src/omni-external-ref-internal-type.enum.js +14 -0
  113. package/src/omni-external-ref-internal-type.enum.js.map +1 -0
  114. package/src/omni-external-ref-internal-type.enum.ts +11 -0
  115. package/src/omni-external-ref.backend.d.ts +2 -0
  116. package/src/omni-external-ref.backend.js +19 -0
  117. package/src/omni-external-ref.backend.js.map +1 -0
  118. package/src/omni-external-ref.backend.ts +25 -0
  119. package/src/omni-external-ref.dto.d.ts +26 -0
  120. package/src/omni-external-ref.dto.js +140 -0
  121. package/src/omni-external-ref.dto.js.map +1 -0
  122. package/src/omni-external-ref.dto.ts +128 -0
  123. package/src/omni-external-ref.service.d.ts +33 -0
  124. package/src/omni-external-ref.service.js +133 -0
  125. package/src/omni-external-ref.service.js.map +1 -0
  126. package/src/omni-external-ref.service.ts +255 -0
  127. package/src/omni-migration.d.ts +28 -0
  128. package/src/omni-migration.js +239 -0
  129. package/src/omni-migration.js.map +1 -0
  130. package/src/omni-migration.ts +365 -0
  131. package/src/omni-named.backend.d.ts +2 -0
  132. package/src/omni-named.backend.js +13 -0
  133. package/src/omni-named.backend.js.map +1 -0
  134. package/src/omni-named.backend.ts +11 -0
  135. package/src/omni-named.dto.d.ts +19 -0
  136. package/src/omni-named.dto.js +94 -0
  137. package/src/omni-named.dto.js.map +1 -0
  138. package/src/omni-named.dto.ts +86 -0
  139. package/src/omni-projection.catalog.d.ts +49 -0
  140. package/src/omni-projection.catalog.js +177 -0
  141. package/src/omni-projection.catalog.js.map +1 -0
  142. package/src/omni-projection.catalog.ts +345 -0
  143. package/src/omni-projection.lifecycle.d.ts +20 -0
  144. package/src/omni-projection.lifecycle.js +3 -0
  145. package/src/omni-projection.lifecycle.js.map +1 -0
  146. package/src/omni-projection.lifecycle.ts +53 -0
  147. package/src/omni-record-status.enum.d.ts +5 -0
  148. package/src/omni-record-status.enum.js +14 -0
  149. package/src/omni-record-status.enum.js.map +1 -0
  150. package/src/omni-record-status.enum.ts +11 -0
  151. package/src/omni-record.backend.d.ts +2 -0
  152. package/src/omni-record.backend.js +13 -0
  153. package/src/omni-record.backend.js.map +1 -0
  154. package/src/omni-record.backend.ts +19 -0
  155. package/src/omni-record.dto.d.ts +29 -0
  156. package/src/omni-record.dto.js +169 -0
  157. package/src/omni-record.dto.js.map +1 -0
  158. package/src/omni-record.dto.ts +157 -0
  159. package/src/omni-record.service.d.ts +18 -0
  160. package/src/omni-record.service.js +45 -0
  161. package/src/omni-record.service.js.map +1 -0
  162. package/src/omni-record.service.ts +113 -0
  163. package/src/omni-relation-kind.contract.d.ts +9 -0
  164. package/src/omni-relation-kind.contract.js +33 -0
  165. package/src/omni-relation-kind.contract.js.map +1 -0
  166. package/src/omni-relation-kind.contract.ts +49 -0
  167. package/src/omni-relation-kind.enum.d.ts +6 -0
  168. package/src/omni-relation-kind.enum.js +15 -0
  169. package/src/omni-relation-kind.enum.js.map +1 -0
  170. package/src/omni-relation-kind.enum.ts +12 -0
  171. package/src/omni-relation-projection.definition.d.ts +25 -0
  172. package/src/omni-relation-projection.definition.js +83 -0
  173. package/src/omni-relation-projection.definition.js.map +1 -0
  174. package/src/omni-relation-projection.definition.ts +166 -0
  175. package/src/omni-relation-projection.resource.d.ts +51 -0
  176. package/src/omni-relation-projection.resource.js +203 -0
  177. package/src/omni-relation-projection.resource.js.map +1 -0
  178. package/src/omni-relation-projection.resource.ts +360 -0
  179. package/src/omni-relation-projection.service.d.ts +47 -0
  180. package/src/omni-relation-projection.service.js +385 -0
  181. package/src/omni-relation-projection.service.js.map +1 -0
  182. package/src/omni-relation-projection.service.ts +610 -0
  183. package/src/omni-relation-semantics.d.ts +11 -0
  184. package/src/omni-relation-semantics.js +34 -0
  185. package/src/omni-relation-semantics.js.map +1 -0
  186. package/src/omni-relation-semantics.ts +52 -0
  187. package/src/omni-relation-status.enum.d.ts +5 -0
  188. package/src/omni-relation-status.enum.js +14 -0
  189. package/src/omni-relation-status.enum.js.map +1 -0
  190. package/src/omni-relation-status.enum.ts +11 -0
  191. package/src/omni-relation.backend.d.ts +2 -0
  192. package/src/omni-relation.backend.js +17 -0
  193. package/src/omni-relation.backend.js.map +1 -0
  194. package/src/omni-relation.backend.ts +21 -0
  195. package/src/omni-relation.dto.d.ts +28 -0
  196. package/src/omni-relation.dto.js +153 -0
  197. package/src/omni-relation.dto.js.map +1 -0
  198. package/src/omni-relation.dto.ts +142 -0
  199. package/src/omni-relation.service.d.ts +19 -0
  200. package/src/omni-relation.service.js +76 -0
  201. package/src/omni-relation.service.js.map +1 -0
  202. package/src/omni-relation.service.ts +159 -0
  203. package/src/omni-scope.d.ts +33 -0
  204. package/src/omni-scope.js +91 -0
  205. package/src/omni-scope.js.map +1 -0
  206. package/src/omni-scope.ts +161 -0
  207. package/src/omni-scoped.backend.d.ts +21 -0
  208. package/src/omni-scoped.backend.js +47 -0
  209. package/src/omni-scoped.backend.js.map +1 -0
  210. package/src/omni-scoped.backend.ts +110 -0
  211. package/src/omni-scoped.repository.d.ts +10 -0
  212. package/src/omni-scoped.repository.js +26 -0
  213. package/src/omni-scoped.repository.js.map +1 -0
  214. package/src/omni-scoped.repository.ts +34 -0
  215. package/src/omni-scoped.service.d.ts +36 -0
  216. package/src/omni-scoped.service.js +171 -0
  217. package/src/omni-scoped.service.js.map +1 -0
  218. package/src/omni-scoped.service.ts +338 -0
  219. package/src/omnikernel.diagnostics.d.ts +16 -0
  220. package/src/omnikernel.diagnostics.js +50 -0
  221. package/src/omnikernel.diagnostics.js.map +1 -0
  222. package/src/omnikernel.diagnostics.ts +83 -0
  223. package/src/omnikernel.module.d.ts +5 -0
  224. package/src/omnikernel.module.js +87 -0
  225. package/src/omnikernel.module.js.map +1 -0
  226. package/src/omnikernel.module.ts +97 -0
  227. package/src/omnikernel.query.service.d.ts +17 -0
  228. package/src/omnikernel.query.service.js +85 -0
  229. package/src/omnikernel.query.service.js.map +1 -0
  230. package/src/omnikernel.query.service.ts +108 -0
@@ -0,0 +1,159 @@
1
+ import { BadRequestException } from '@nestjs/common';
2
+ import type { CrudGenFindManyOptions } from '@nest-yalc-2/crud-gen/api-graphql/crud-gen-gql.interface.js';
3
+ import {
4
+ IsNull,
5
+ type DeepPartial,
6
+ type FindOptionsWhere,
7
+ type Repository,
8
+ } from 'typeorm';
9
+ import { OmniRecordEntity } from './base/omni-record.entity.js';
10
+ import { OmniRelationEntity } from './base/omni-relation.entity.js';
11
+ import {
12
+ canonicalOmniRelationKinds,
13
+ type OmniRelationKindContract,
14
+ } from './omni-relation-kind.contract.js';
15
+ import { isAllowedOmniRelation } from './omni-relation-semantics.js';
16
+ import type { OmniDeletePolicy, OmniScope } from './omni-scope.js';
17
+ import { OmniScopedService } from './omni-scoped.service.js';
18
+
19
+ /**
20
+ * Scoped graph CRUD with immutable endpoints. The database composite foreign
21
+ * keys prevent cross-scope edges; this service additionally turns missing or
22
+ * invalid endpoints into normal API failures before persistence.
23
+ */
24
+ export class OmniRelationService extends OmniScopedService<OmniRelationEntity> {
25
+ constructor(
26
+ repository: any,
27
+ scope: OmniScope,
28
+ deletion: OmniDeletePolicy,
29
+ protected readonly recordRepository: Repository<OmniRecordEntity>,
30
+ protected readonly kinds: OmniRelationKindContract,
31
+ ) {
32
+ super(repository, scope, deletion);
33
+ }
34
+
35
+ override async createEntity(
36
+ input: DeepPartial<OmniRelationEntity>,
37
+ findOptions?: CrudGenFindManyOptions<OmniRelationEntity>,
38
+ returnEntity?: true,
39
+ ): Promise<OmniRelationEntity>;
40
+ override async createEntity(
41
+ input: DeepPartial<OmniRelationEntity>,
42
+ findOptions?: CrudGenFindManyOptions<OmniRelationEntity>,
43
+ returnEntity?: boolean,
44
+ ): Promise<OmniRelationEntity | boolean>;
45
+ override async createEntity(
46
+ input: DeepPartial<OmniRelationEntity>,
47
+ findOptions?: CrudGenFindManyOptions<OmniRelationEntity>,
48
+ returnEntity = true,
49
+ ): Promise<OmniRelationEntity | boolean> {
50
+ this.rejectServerFields(input as object);
51
+ await this.assertRelation(input);
52
+ return super.createEntity(input, findOptions, returnEntity);
53
+ }
54
+
55
+ override async updateEntity(
56
+ conditions: FindOptionsWhere<OmniRelationEntity>,
57
+ input: DeepPartial<OmniRelationEntity>,
58
+ findOptions?: CrudGenFindManyOptions<OmniRelationEntity>,
59
+ returnEntity?: true,
60
+ ): Promise<OmniRelationEntity>;
61
+ override async updateEntity(
62
+ conditions: FindOptionsWhere<OmniRelationEntity>,
63
+ input: DeepPartial<OmniRelationEntity>,
64
+ findOptions?: CrudGenFindManyOptions<OmniRelationEntity>,
65
+ returnEntity?: boolean,
66
+ ): Promise<OmniRelationEntity | boolean>;
67
+ override async updateEntity(
68
+ conditions: FindOptionsWhere<OmniRelationEntity>,
69
+ input: DeepPartial<OmniRelationEntity>,
70
+ findOptions?: CrudGenFindManyOptions<OmniRelationEntity>,
71
+ returnEntity = true,
72
+ ): Promise<OmniRelationEntity | boolean> {
73
+ for (const field of ['guid', 'sourceRecordId', 'targetRecordId']) {
74
+ if (Object.prototype.hasOwnProperty.call(input, field)) {
75
+ throw new BadRequestException(`Omni relation ${field} is immutable.`);
76
+ }
77
+ }
78
+
79
+ const current = await super.getEntity(
80
+ conditions,
81
+ undefined,
82
+ undefined,
83
+ undefined,
84
+ {
85
+ failOnNull: true,
86
+ },
87
+ );
88
+ if (!current) this.notFound();
89
+ await this.assertRelation({ ...current, ...input });
90
+ return super.updateEntity(conditions, input, findOptions, returnEntity);
91
+ }
92
+
93
+ protected async assertRelation(
94
+ input: DeepPartial<OmniRelationEntity>,
95
+ recordRepository: Repository<OmniRecordEntity> = this.recordRepository,
96
+ ): Promise<void> {
97
+ const sourceRecordId = this.requiredIdentifier(
98
+ input.sourceRecordId,
99
+ 'sourceRecordId',
100
+ );
101
+ const targetRecordId = this.requiredIdentifier(
102
+ input.targetRecordId,
103
+ 'targetRecordId',
104
+ );
105
+ const kind = this.requiredIdentifier(input.kind, 'kind');
106
+ try {
107
+ this.kinds.assert(kind);
108
+ } catch (error) {
109
+ throw new BadRequestException(
110
+ error instanceof Error
111
+ ? error.message
112
+ : 'Omni relation kind is invalid.',
113
+ );
114
+ }
115
+
116
+ const records = await recordRepository.find({
117
+ where: [
118
+ { scopeId: this.scopeId, guid: sourceRecordId, deletedAt: IsNull() },
119
+ { scopeId: this.scopeId, guid: targetRecordId, deletedAt: IsNull() },
120
+ ],
121
+ });
122
+ const source = records.find((record) => record.guid === sourceRecordId);
123
+ const target = records.find((record) => record.guid === targetRecordId);
124
+ if (!source || !target) this.notFound();
125
+
126
+ this.assertEndpointKinds(source, target);
127
+
128
+ const isCanonical = canonicalOmniRelationKinds.includes(
129
+ kind as (typeof canonicalOmniRelationKinds)[number],
130
+ );
131
+ if (
132
+ isCanonical &&
133
+ !isAllowedOmniRelation({
134
+ sourceKind: source.kind,
135
+ targetKind: target.kind,
136
+ relationKind: kind,
137
+ })
138
+ ) {
139
+ throw new BadRequestException(
140
+ 'Omni relation kind is not valid for these endpoint kinds.',
141
+ );
142
+ }
143
+ }
144
+
145
+ /** Resource-specific relation projections may narrow endpoint kinds. */
146
+ protected assertEndpointKinds(
147
+ _source: OmniRecordEntity,
148
+ _target: OmniRecordEntity,
149
+ ): void {}
150
+
151
+ protected requiredIdentifier(value: unknown, field: string): string {
152
+ if (typeof value !== 'string' || value.trim().length === 0) {
153
+ throw new BadRequestException(
154
+ `Omni relation ${field} must be a non-empty string.`,
155
+ );
156
+ }
157
+ return value;
158
+ }
159
+ }
@@ -0,0 +1,33 @@
1
+ export interface OmniScope {
2
+ readonly scopeId: string;
3
+ cacheKey(key: string): string;
4
+ }
5
+ export type OmniScopeResolver = (request: unknown) => string | undefined;
6
+ export interface OmniKernelRegistrationOptions {
7
+ dbConnection: string;
8
+ resolveScope?: OmniScopeResolver;
9
+ defaultScopeId?: string;
10
+ reservedRecordKinds?: readonly string[];
11
+ relationKinds?: readonly string[];
12
+ deletion?: Partial<OmniDeletionPolicies>;
13
+ }
14
+ export type OmniDeletePolicy = 'hard' | 'tombstone';
15
+ export interface OmniDeletionPolicies {
16
+ named: OmniDeletePolicy;
17
+ record: OmniDeletePolicy;
18
+ document: OmniDeletePolicy;
19
+ collection: OmniDeletePolicy;
20
+ relation: OmniDeletePolicy;
21
+ externalRef: OmniDeletePolicy;
22
+ }
23
+ export declare const OMNI_KERNEL_OPTIONS: unique symbol;
24
+ export declare const defaultOmniDeletionPolicies: OmniDeletionPolicies;
25
+ export declare function normalizeOmniKernelRegistrationOptions(options: string | OmniKernelRegistrationOptions): Required<Pick<OmniKernelRegistrationOptions, 'dbConnection' | 'defaultScopeId' | 'relationKinds'>> & Omit<OmniKernelRegistrationOptions, 'dbConnection' | 'defaultScopeId' | 'relationKinds' | 'reservedRecordKinds' | 'deletion'> & {
26
+ reservedRecordKinds: readonly string[];
27
+ deletion: OmniDeletionPolicies;
28
+ };
29
+ export declare class OmniScopeContext implements OmniScope {
30
+ readonly scopeId: string;
31
+ constructor(request: unknown, options: ReturnType<typeof normalizeOmniKernelRegistrationOptions>);
32
+ cacheKey(key: string): string;
33
+ }
@@ -0,0 +1,91 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
12
+ return function (target, key) { decorator(target, key, paramIndex); }
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.OmniScopeContext = exports.defaultOmniDeletionPolicies = exports.OMNI_KERNEL_OPTIONS = void 0;
16
+ exports.normalizeOmniKernelRegistrationOptions = normalizeOmniKernelRegistrationOptions;
17
+ const common_1 = require("@nestjs/common");
18
+ const core_1 = require("@nestjs/core");
19
+ exports.OMNI_KERNEL_OPTIONS = Symbol('OMNI_KERNEL_OPTIONS');
20
+ exports.defaultOmniDeletionPolicies = {
21
+ named: 'hard',
22
+ record: 'tombstone',
23
+ document: 'tombstone',
24
+ collection: 'tombstone',
25
+ relation: 'hard',
26
+ externalRef: 'hard',
27
+ };
28
+ function normalizeOmniDeletionPolicies(deletion) {
29
+ const knownResources = new Set(Object.keys(exports.defaultOmniDeletionPolicies));
30
+ for (const [resource, policy] of Object.entries(deletion ?? {})) {
31
+ if (!knownResources.has(resource)) {
32
+ throw new TypeError(`Unknown OmniKernel deletion policy resource: ${resource}.`);
33
+ }
34
+ if (policy !== 'hard' && policy !== 'tombstone') {
35
+ throw new TypeError(`OmniKernel deletion policy for ${resource} must be hard or tombstone.`);
36
+ }
37
+ }
38
+ return {
39
+ ...exports.defaultOmniDeletionPolicies,
40
+ ...deletion,
41
+ };
42
+ }
43
+ function normalizeOmniKernelRegistrationOptions(options) {
44
+ const candidate = typeof options === 'string' ? { dbConnection: options } : options;
45
+ if (!candidate.dbConnection) {
46
+ throw new TypeError('OmniKernelModule requires a database connection name.');
47
+ }
48
+ if (candidate.defaultScopeId !== undefined &&
49
+ (candidate.defaultScopeId.trim().length === 0 ||
50
+ candidate.defaultScopeId.length > 64)) {
51
+ throw new TypeError('OmniKernel defaultScopeId must be 1-64 characters.');
52
+ }
53
+ const reservedRecordKinds = candidate.reservedRecordKinds ?? [];
54
+ if (!Array.isArray(reservedRecordKinds) ||
55
+ reservedRecordKinds.some((kind) => typeof kind !== 'string' ||
56
+ kind.trim().length === 0 ||
57
+ kind.length > 64) ||
58
+ new Set(reservedRecordKinds).size !== reservedRecordKinds.length) {
59
+ throw new TypeError('OmniKernel reservedRecordKinds must be unique 1-64 character strings.');
60
+ }
61
+ return {
62
+ ...candidate,
63
+ defaultScopeId: candidate.defaultScopeId ?? 'default',
64
+ relationKinds: candidate.relationKinds ?? [],
65
+ reservedRecordKinds: Object.freeze([...reservedRecordKinds]),
66
+ deletion: normalizeOmniDeletionPolicies(candidate.deletion),
67
+ };
68
+ }
69
+ let OmniScopeContext = class OmniScopeContext {
70
+ constructor(request, options) {
71
+ const requestForResolver = request?.req ?? request;
72
+ const scopeId = options.resolveScope
73
+ ? options.resolveScope(requestForResolver)
74
+ : options.defaultScopeId;
75
+ if (!scopeId || scopeId.trim().length === 0 || scopeId.length > 64) {
76
+ throw new TypeError('Omni scope context is unavailable.');
77
+ }
78
+ this.scopeId = scopeId;
79
+ }
80
+ cacheKey(key) {
81
+ return `${this.scopeId}:${key}`;
82
+ }
83
+ };
84
+ exports.OmniScopeContext = OmniScopeContext;
85
+ exports.OmniScopeContext = OmniScopeContext = __decorate([
86
+ (0, common_1.Injectable)({ scope: common_1.Scope.REQUEST }),
87
+ __param(0, (0, common_1.Inject)(core_1.REQUEST)),
88
+ __param(1, (0, common_1.Inject)(exports.OMNI_KERNEL_OPTIONS)),
89
+ __metadata("design:paramtypes", [Object, void 0])
90
+ ], OmniScopeContext);
91
+ //# sourceMappingURL=omni-scope.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"omni-scope.js","sourceRoot":"","sources":["omni-scope.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,161 @@
1
+ import { Inject, Injectable, Scope } from '@nestjs/common';
2
+ import { REQUEST } from '@nestjs/core';
3
+
4
+ export interface OmniScope {
5
+ readonly scopeId: string;
6
+ cacheKey(key: string): string;
7
+ }
8
+
9
+ export type OmniScopeResolver = (request: unknown) => string | undefined;
10
+
11
+ export interface OmniKernelRegistrationOptions {
12
+ dbConnection: string;
13
+ /**
14
+ * Authentication adapters resolve a trusted server scope from the request.
15
+ * The adapter owns authentication; OmniKernel never reads a client DTO field.
16
+ */
17
+ resolveScope?: OmniScopeResolver;
18
+ /**
19
+ * Compatibility/default partition for applications that do not yet have an
20
+ * authentication adapter. It is server configuration, never request input.
21
+ */
22
+ defaultScopeId?: string;
23
+ /** Kinds exclusively owned by registered extension projections. */
24
+ reservedRecordKinds?: readonly string[];
25
+ relationKinds?: readonly string[];
26
+ deletion?: Partial<OmniDeletionPolicies>;
27
+ }
28
+
29
+ export type OmniDeletePolicy = 'hard' | 'tombstone';
30
+
31
+ export interface OmniDeletionPolicies {
32
+ named: OmniDeletePolicy;
33
+ record: OmniDeletePolicy;
34
+ document: OmniDeletePolicy;
35
+ collection: OmniDeletePolicy;
36
+ relation: OmniDeletePolicy;
37
+ externalRef: OmniDeletePolicy;
38
+ }
39
+
40
+ export const OMNI_KERNEL_OPTIONS = Symbol('OMNI_KERNEL_OPTIONS');
41
+
42
+ export const defaultOmniDeletionPolicies: OmniDeletionPolicies = {
43
+ named: 'hard',
44
+ record: 'tombstone',
45
+ document: 'tombstone',
46
+ collection: 'tombstone',
47
+ relation: 'hard',
48
+ externalRef: 'hard',
49
+ };
50
+
51
+ function normalizeOmniDeletionPolicies(
52
+ deletion: Partial<OmniDeletionPolicies> | undefined,
53
+ ): OmniDeletionPolicies {
54
+ const knownResources = new Set(Object.keys(defaultOmniDeletionPolicies));
55
+ for (const [resource, policy] of Object.entries(deletion ?? {})) {
56
+ if (!knownResources.has(resource)) {
57
+ throw new TypeError(
58
+ `Unknown OmniKernel deletion policy resource: ${resource}.`,
59
+ );
60
+ }
61
+ if (policy !== 'hard' && policy !== 'tombstone') {
62
+ throw new TypeError(
63
+ `OmniKernel deletion policy for ${resource} must be hard or tombstone.`,
64
+ );
65
+ }
66
+ }
67
+ return {
68
+ ...defaultOmniDeletionPolicies,
69
+ ...deletion,
70
+ };
71
+ }
72
+
73
+ export function normalizeOmniKernelRegistrationOptions(
74
+ options: string | OmniKernelRegistrationOptions,
75
+ ): Required<
76
+ Pick<
77
+ OmniKernelRegistrationOptions,
78
+ 'dbConnection' | 'defaultScopeId' | 'relationKinds'
79
+ >
80
+ > &
81
+ Omit<
82
+ OmniKernelRegistrationOptions,
83
+ | 'dbConnection'
84
+ | 'defaultScopeId'
85
+ | 'relationKinds'
86
+ | 'reservedRecordKinds'
87
+ | 'deletion'
88
+ > & {
89
+ reservedRecordKinds: readonly string[];
90
+ deletion: OmniDeletionPolicies;
91
+ } {
92
+ const candidate =
93
+ typeof options === 'string' ? { dbConnection: options } : options;
94
+ if (!candidate.dbConnection) {
95
+ throw new TypeError(
96
+ 'OmniKernelModule requires a database connection name.',
97
+ );
98
+ }
99
+ if (
100
+ candidate.defaultScopeId !== undefined &&
101
+ (candidate.defaultScopeId.trim().length === 0 ||
102
+ candidate.defaultScopeId.length > 64)
103
+ ) {
104
+ throw new TypeError('OmniKernel defaultScopeId must be 1-64 characters.');
105
+ }
106
+ const reservedRecordKinds = candidate.reservedRecordKinds ?? [];
107
+ if (
108
+ !Array.isArray(reservedRecordKinds) ||
109
+ reservedRecordKinds.some(
110
+ (kind) =>
111
+ typeof kind !== 'string' ||
112
+ kind.trim().length === 0 ||
113
+ kind.length > 64,
114
+ ) ||
115
+ new Set(reservedRecordKinds).size !== reservedRecordKinds.length
116
+ ) {
117
+ throw new TypeError(
118
+ 'OmniKernel reservedRecordKinds must be unique 1-64 character strings.',
119
+ );
120
+ }
121
+
122
+ return {
123
+ ...candidate,
124
+ defaultScopeId: candidate.defaultScopeId ?? 'default',
125
+ relationKinds: candidate.relationKinds ?? [],
126
+ reservedRecordKinds: Object.freeze([...reservedRecordKinds]),
127
+ deletion: normalizeOmniDeletionPolicies(candidate.deletion),
128
+ };
129
+ }
130
+
131
+ type RequestEnvelope = { req?: unknown };
132
+
133
+ /**
134
+ * Request-scoped server context used by every Omni generated API and loader.
135
+ * It is intentionally unavailable when neither the trusted adapter nor a
136
+ * configured default provides a scope.
137
+ */
138
+ @Injectable({ scope: Scope.REQUEST })
139
+ export class OmniScopeContext implements OmniScope {
140
+ readonly scopeId: string;
141
+
142
+ constructor(
143
+ @Inject(REQUEST) request: unknown,
144
+ @Inject(OMNI_KERNEL_OPTIONS)
145
+ options: ReturnType<typeof normalizeOmniKernelRegistrationOptions>,
146
+ ) {
147
+ const requestForResolver =
148
+ (request as RequestEnvelope | undefined)?.req ?? request;
149
+ const scopeId = options.resolveScope
150
+ ? options.resolveScope(requestForResolver)
151
+ : options.defaultScopeId;
152
+ if (!scopeId || scopeId.trim().length === 0 || scopeId.length > 64) {
153
+ throw new TypeError('Omni scope context is unavailable.');
154
+ }
155
+ this.scopeId = scopeId;
156
+ }
157
+
158
+ cacheKey(key: string): string {
159
+ return `${this.scopeId}:${key}`;
160
+ }
161
+ }
@@ -0,0 +1,21 @@
1
+ import { type InjectionToken, type Provider } from '@nestjs/common';
2
+ import { getProviderToken } from '@nest-yalc-2/crud-gen/crud-gen.helpers.js';
3
+ import { type GenericService } from '@nest-yalc-2/crud-gen/typeorm/generic.service.js';
4
+ import type { ClassType } from '@nest-yalc-2/types/globals.d.js';
5
+ import type { ObjectLiteral } from 'typeorm';
6
+ import type { GenericTypeORMRepository } from '@nest-yalc-2/crud-gen/typeorm/generic.repository.js';
7
+ import { OmniScopeContext, normalizeOmniKernelRegistrationOptions } from './omni-scope.js';
8
+ export interface OmniScopedBackendFactoryOptions<Entity extends ObjectLiteral> {
9
+ entityModel: ClassType<Entity>;
10
+ dbConnection: string;
11
+ serviceToken?: string;
12
+ serviceProvider?: InjectionToken;
13
+ additionalInject?: readonly InjectionToken[];
14
+ createService: (repository: GenericTypeORMRepository<Entity>, scope: OmniScopeContext, options: ReturnType<typeof normalizeOmniKernelRegistrationOptions>, ...additionalDependencies: unknown[]) => GenericService<Entity>;
15
+ }
16
+ export interface OmniScopedBackendFactoryResult<Entity extends ObjectLiteral> {
17
+ providers: Provider[];
18
+ repository: ClassType<GenericTypeORMRepository<Entity>>;
19
+ }
20
+ export declare function omniScopedBackendProvidersFactory<Entity extends ObjectLiteral>(options: OmniScopedBackendFactoryOptions<Entity>): OmniScopedBackendFactoryResult<Entity>;
21
+ export declare function omniBackendServiceToken(provider: Parameters<typeof getProviderToken>[0]): string;
@@ -0,0 +1,47 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.omniScopedBackendProvidersFactory = omniScopedBackendProvidersFactory;
4
+ exports.omniBackendServiceToken = omniBackendServiceToken;
5
+ const common_1 = require("@nestjs/common");
6
+ const typeorm_1 = require("@nestjs/typeorm");
7
+ const crud_gen_helpers_js_1 = require("@nest-yalc-2/crud-gen/crud-gen.helpers.js");
8
+ const generic_service_js_1 = require("@nest-yalc-2/crud-gen/typeorm/generic.service.js");
9
+ const generic_repository_js_1 = require("@nest-yalc-2/crud-gen/typeorm/generic.repository.js");
10
+ const data_loader_1 = require("@nest-yalc-2/data-loader");
11
+ const event_emitter_1 = require("@nestjs/event-emitter");
12
+ const omni_scope_js_1 = require("./omni-scope.js");
13
+ function omniScopedBackendProvidersFactory(options) {
14
+ const serviceToken = options.serviceToken ?? (0, generic_service_js_1.getServiceToken)(options.entityModel);
15
+ const serviceProviderToken = options.serviceProvider ?? serviceToken;
16
+ const additionalInject = options.additionalInject ?? [];
17
+ const serviceProvider = {
18
+ provide: serviceProviderToken,
19
+ scope: common_1.Scope.REQUEST,
20
+ useFactory: (repository, scope, moduleOptions, ...additionalDependencies) => options.createService(repository, scope, moduleOptions, ...additionalDependencies),
21
+ inject: [
22
+ (0, typeorm_1.getRepositoryToken)(options.entityModel, options.dbConnection),
23
+ omni_scope_js_1.OmniScopeContext,
24
+ omni_scope_js_1.OMNI_KERNEL_OPTIONS,
25
+ ...additionalInject,
26
+ ],
27
+ };
28
+ const loaderProvider = {
29
+ provide: (0, data_loader_1.getDataloaderToken)(options.entityModel),
30
+ scope: common_1.Scope.REQUEST,
31
+ useFactory: (service, scope, events) => new data_loader_1.GQLDataLoader((0, data_loader_1.getFn)(service), 'guid', events, {
32
+ cacheKeyFn: (key) => scope.cacheKey(key),
33
+ }),
34
+ inject: [serviceToken, omni_scope_js_1.OmniScopeContext, event_emitter_1.EventEmitter2],
35
+ };
36
+ const serviceAlias = serviceProviderToken === serviceToken
37
+ ? []
38
+ : [{ provide: serviceToken, useExisting: serviceProviderToken }];
39
+ return {
40
+ providers: [serviceProvider, ...serviceAlias, loaderProvider],
41
+ repository: (0, generic_repository_js_1.CGExtendedRepositoryFactory)(options.entityModel),
42
+ };
43
+ }
44
+ function omniBackendServiceToken(provider) {
45
+ return (0, crud_gen_helpers_js_1.getProviderToken)(provider);
46
+ }
47
+ //# sourceMappingURL=omni-scoped.backend.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"omni-scoped.backend.js","sourceRoot":"","sources":["omni-scoped.backend.ts"],"names":[],"mappings":";;AAmDA,8EAoDC;AAED,0DAIC;AA7GD,2CAKwB;AACxB,6CAAqD;AACrD,mFAA6E;AAC7E,yFAG0D;AAC1D,+FAAkG;AAClG,0DAIkC;AAElC,yDAAsD;AAGtD,mDAIyB;AAyBzB,SAAgB,iCAAiC,CAC/C,OAAgD;IAEhD,MAAM,YAAY,GAChB,OAAO,CAAC,YAAY,IAAI,IAAA,oCAAe,EAAC,OAAO,CAAC,WAAW,CAAC,CAAC;IAC/D,MAAM,oBAAoB,GAAG,OAAO,CAAC,eAAe,IAAI,YAAY,CAAC;IACrE,MAAM,gBAAgB,GAAG,OAAO,CAAC,gBAAgB,IAAI,EAAE,CAAC;IACxD,MAAM,eAAe,GAAoB;QACvC,OAAO,EAAE,oBAAoB;QAC7B,KAAK,EAAE,cAAK,CAAC,OAAO;QACpB,UAAU,EAAE,CACV,UAA4C,EAC5C,KAAuB,EACvB,aAAwE,EACxE,GAAG,sBAAiC,EACpC,EAAE,CACF,OAAO,CAAC,aAAa,CACnB,UAAU,EACV,KAAK,EACL,aAAa,EACb,GAAG,sBAAsB,CAC1B;QACH,MAAM,EAAE;YACN,IAAA,4BAAkB,EAAC,OAAO,CAAC,WAAW,EAAE,OAAO,CAAC,YAAY,CAAC;YAC7D,gCAAgB;YAChB,mCAAmB;YACnB,GAAG,gBAAgB;SACpB;KACF,CAAC;IACF,MAAM,cAAc,GAAoB;QACtC,OAAO,EAAE,IAAA,gCAAkB,EAAC,OAAO,CAAC,WAAW,CAAC;QAChD,KAAK,EAAE,cAAK,CAAC,OAAO;QACpB,UAAU,EAAE,CACV,OAA+B,EAC/B,KAAuB,EACvB,MAAqB,EACrB,EAAE,CACF,IAAI,2BAAa,CAAC,IAAA,mBAAK,EAAC,OAAO,CAAC,EAAE,MAAsB,EAAE,MAAM,EAAE;YAChE,UAAU,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC;SACzC,CAAC;QACJ,MAAM,EAAE,CAAC,YAAY,EAAE,gCAAgB,EAAE,6BAAa,CAAC;KACxD,CAAC;IAEF,MAAM,YAAY,GAChB,oBAAoB,KAAK,YAAY;QACnC,CAAC,CAAC,EAAE;QACJ,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,oBAAoB,EAAE,CAAC,CAAC;IAErE,OAAO;QACL,SAAS,EAAE,CAAC,eAAe,EAAE,GAAG,YAAY,EAAE,cAAc,CAAC;QAC7D,UAAU,EAAE,IAAA,mDAA2B,EAAC,OAAO,CAAC,WAAW,CAAC;KAC7D,CAAC;AACJ,CAAC;AAED,SAAgB,uBAAuB,CACrC,QAAgD;IAEhD,OAAO,IAAA,sCAAgB,EAAC,QAAQ,CAAC,CAAC;AACpC,CAAC"}
@@ -0,0 +1,110 @@
1
+ import {
2
+ Scope,
3
+ type FactoryProvider,
4
+ type InjectionToken,
5
+ type Provider,
6
+ } from '@nestjs/common';
7
+ import { getRepositoryToken } from '@nestjs/typeorm';
8
+ import { getProviderToken } from '@nest-yalc-2/crud-gen/crud-gen.helpers.js';
9
+ import {
10
+ getServiceToken,
11
+ type GenericService,
12
+ } from '@nest-yalc-2/crud-gen/typeorm/generic.service.js';
13
+ import { CGExtendedRepositoryFactory } from '@nest-yalc-2/crud-gen/typeorm/generic.repository.js';
14
+ import {
15
+ GQLDataLoader,
16
+ getDataloaderToken,
17
+ getFn,
18
+ } from '@nest-yalc-2/data-loader';
19
+ import type { ClassType } from '@nest-yalc-2/types/globals.d.js';
20
+ import { EventEmitter2 } from '@nestjs/event-emitter';
21
+ import type { ObjectLiteral } from 'typeorm';
22
+ import type { GenericTypeORMRepository } from '@nest-yalc-2/crud-gen/typeorm/generic.repository.js';
23
+ import {
24
+ OMNI_KERNEL_OPTIONS,
25
+ OmniScopeContext,
26
+ normalizeOmniKernelRegistrationOptions,
27
+ } from './omni-scope.js';
28
+
29
+ export interface OmniScopedBackendFactoryOptions<Entity extends ObjectLiteral> {
30
+ entityModel: ClassType<Entity>;
31
+ dbConnection: string;
32
+ serviceToken?: string;
33
+ serviceProvider?: InjectionToken;
34
+ additionalInject?: readonly InjectionToken[];
35
+ createService: (
36
+ repository: GenericTypeORMRepository<Entity>,
37
+ scope: OmniScopeContext,
38
+ options: ReturnType<typeof normalizeOmniKernelRegistrationOptions>,
39
+ ...additionalDependencies: unknown[]
40
+ ) => GenericService<Entity>;
41
+ }
42
+
43
+ export interface OmniScopedBackendFactoryResult<Entity extends ObjectLiteral> {
44
+ providers: Provider[];
45
+ repository: ClassType<GenericTypeORMRepository<Entity>>;
46
+ }
47
+
48
+ /**
49
+ * Builds the normal CrudGen service/loader provider shape with a request
50
+ * scope. The loader cache key carries the same scope as the service query.
51
+ */
52
+ export function omniScopedBackendProvidersFactory<Entity extends ObjectLiteral>(
53
+ options: OmniScopedBackendFactoryOptions<Entity>,
54
+ ): OmniScopedBackendFactoryResult<Entity> {
55
+ const serviceToken =
56
+ options.serviceToken ?? getServiceToken(options.entityModel);
57
+ const serviceProviderToken = options.serviceProvider ?? serviceToken;
58
+ const additionalInject = options.additionalInject ?? [];
59
+ const serviceProvider: FactoryProvider = {
60
+ provide: serviceProviderToken,
61
+ scope: Scope.REQUEST,
62
+ useFactory: (
63
+ repository: GenericTypeORMRepository<Entity>,
64
+ scope: OmniScopeContext,
65
+ moduleOptions: ReturnType<typeof normalizeOmniKernelRegistrationOptions>,
66
+ ...additionalDependencies: unknown[]
67
+ ) =>
68
+ options.createService(
69
+ repository,
70
+ scope,
71
+ moduleOptions,
72
+ ...additionalDependencies,
73
+ ),
74
+ inject: [
75
+ getRepositoryToken(options.entityModel, options.dbConnection),
76
+ OmniScopeContext,
77
+ OMNI_KERNEL_OPTIONS,
78
+ ...additionalInject,
79
+ ],
80
+ };
81
+ const loaderProvider: FactoryProvider = {
82
+ provide: getDataloaderToken(options.entityModel),
83
+ scope: Scope.REQUEST,
84
+ useFactory: (
85
+ service: GenericService<Entity>,
86
+ scope: OmniScopeContext,
87
+ events: EventEmitter2,
88
+ ) =>
89
+ new GQLDataLoader(getFn(service), 'guid' as keyof Entity, events, {
90
+ cacheKeyFn: (key) => scope.cacheKey(key),
91
+ }),
92
+ inject: [serviceToken, OmniScopeContext, EventEmitter2],
93
+ };
94
+
95
+ const serviceAlias: Provider[] =
96
+ serviceProviderToken === serviceToken
97
+ ? []
98
+ : [{ provide: serviceToken, useExisting: serviceProviderToken }];
99
+
100
+ return {
101
+ providers: [serviceProvider, ...serviceAlias, loaderProvider],
102
+ repository: CGExtendedRepositoryFactory(options.entityModel),
103
+ };
104
+ }
105
+
106
+ export function omniBackendServiceToken(
107
+ provider: Parameters<typeof getProviderToken>[0],
108
+ ): string {
109
+ return getProviderToken(provider);
110
+ }
@@ -0,0 +1,10 @@
1
+ import type { FindOptionsWhere, ObjectLiteral, Repository } from 'typeorm';
2
+ import type { OmniScope } from './omni-scope.js';
3
+ export declare class OmniScopedRepository<Entity extends ObjectLiteral> {
4
+ private readonly repository;
5
+ private readonly scope;
6
+ constructor(repository: Repository<Entity>, scope: OmniScope);
7
+ where(where?: FindOptionsWhere<Entity>): FindOptionsWhere<Entity>;
8
+ findOneByGuid(guid: string): Promise<Entity | null>;
9
+ find(where?: FindOptionsWhere<Entity>): Promise<Entity[]>;
10
+ }
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.OmniScopedRepository = void 0;
4
+ class OmniScopedRepository {
5
+ constructor(repository, scope) {
6
+ this.repository = repository;
7
+ this.scope = scope;
8
+ }
9
+ where(where = {}) {
10
+ if ('scopeId' in where) {
11
+ throw new TypeError('Omni scopeId is derived from server context.');
12
+ }
13
+ return {
14
+ ...where,
15
+ scopeId: this.scope.scopeId,
16
+ };
17
+ }
18
+ findOneByGuid(guid) {
19
+ return this.repository.findOne({ where: this.where({ guid }) });
20
+ }
21
+ find(where = {}) {
22
+ return this.repository.find({ where: this.where(where) });
23
+ }
24
+ }
25
+ exports.OmniScopedRepository = OmniScopedRepository;
26
+ //# sourceMappingURL=omni-scoped.repository.js.map