@lenne.tech/nest-server 11.27.6 → 11.28.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.
- package/.claude/rules/architecture.md +66 -0
- package/.claude/rules/better-auth.md +88 -2
- package/.claude/rules/package-management.md +23 -14
- package/.claude/rules/role-system.md +90 -0
- package/.claude/rules/versioning.md +17 -2
- package/CLAUDE.md +8 -2
- package/FRAMEWORK-API.md +27 -1
- package/dist/core/common/decorators/restricted.decorator.d.ts +4 -4
- package/dist/core/common/decorators/restricted.decorator.js +29 -26
- package/dist/core/common/decorators/restricted.decorator.js.map +1 -1
- package/dist/core/common/exceptions/access-denied.exception.d.ts +4 -0
- package/dist/core/common/exceptions/access-denied.exception.js +12 -0
- package/dist/core/common/exceptions/access-denied.exception.js.map +1 -0
- package/dist/core/common/helpers/clone.helper.d.ts +6 -0
- package/dist/core/common/helpers/clone.helper.js +67 -0
- package/dist/core/common/helpers/clone.helper.js.map +1 -0
- package/dist/core/common/helpers/db.helper.d.ts +2 -14
- package/dist/core/common/helpers/db.helper.js +13 -106
- package/dist/core/common/helpers/db.helper.js.map +1 -1
- package/dist/core/common/helpers/id.helper.d.ts +15 -0
- package/dist/core/common/helpers/id.helper.js +104 -0
- package/dist/core/common/helpers/id.helper.js.map +1 -0
- package/dist/core/common/helpers/input.helper.d.ts +1 -6
- package/dist/core/common/helpers/input.helper.js +15 -72
- package/dist/core/common/helpers/input.helper.js.map +1 -1
- package/dist/core/common/helpers/service.helper.js +4 -3
- package/dist/core/common/helpers/service.helper.js.map +1 -1
- package/dist/core/common/inputs/combined-filter.input.d.ts +1 -12
- package/dist/core/common/inputs/combined-filter.input.js +2 -51
- package/dist/core/common/inputs/combined-filter.input.js.map +1 -1
- package/dist/core/common/inputs/filter.input.d.ts +10 -1
- package/dist/core/common/inputs/filter.input.js +40 -5
- package/dist/core/common/inputs/filter.input.js.map +1 -1
- package/dist/core/common/services/config.service.js +5 -5
- package/dist/core/common/services/config.service.js.map +1 -1
- package/dist/core/modules/ai/core-ai.constants.d.ts +22 -0
- package/dist/core/modules/ai/core-ai.constants.js +26 -0
- package/dist/core/modules/ai/core-ai.constants.js.map +1 -0
- package/dist/core/modules/ai/index.d.ts +1 -0
- package/dist/core/modules/ai/index.js +1 -0
- package/dist/core/modules/ai/index.js.map +1 -1
- package/dist/core/modules/ai/interfaces/ai-interaction-record.interface.d.ts +17 -0
- package/dist/core/modules/ai/interfaces/ai-interaction-record.interface.js +3 -0
- package/dist/core/modules/ai/interfaces/ai-interaction-record.interface.js.map +1 -0
- package/dist/core/modules/ai/services/core-ai-budget.service.d.ts +1 -2
- package/dist/core/modules/ai/services/core-ai-budget.service.js +7 -5
- package/dist/core/modules/ai/services/core-ai-budget.service.js.map +1 -1
- package/dist/core/modules/ai/services/core-ai-connection-preference.service.d.ts +1 -2
- package/dist/core/modules/ai/services/core-ai-connection-preference.service.js +7 -5
- package/dist/core/modules/ai/services/core-ai-connection-preference.service.js.map +1 -1
- package/dist/core/modules/ai/services/core-ai-connection.service.d.ts +1 -2
- package/dist/core/modules/ai/services/core-ai-connection.service.js +7 -5
- package/dist/core/modules/ai/services/core-ai-connection.service.js.map +1 -1
- package/dist/core/modules/ai/services/core-ai-conversation.service.d.ts +1 -2
- package/dist/core/modules/ai/services/core-ai-conversation.service.js +7 -5
- package/dist/core/modules/ai/services/core-ai-conversation.service.js.map +1 -1
- package/dist/core/modules/ai/services/core-ai-interaction.service.d.ts +2 -3
- package/dist/core/modules/ai/services/core-ai-interaction.service.js +7 -5
- package/dist/core/modules/ai/services/core-ai-interaction.service.js.map +1 -1
- package/dist/core/modules/ai/services/core-ai-mode.service.d.ts +1 -2
- package/dist/core/modules/ai/services/core-ai-mode.service.js +7 -5
- package/dist/core/modules/ai/services/core-ai-mode.service.js.map +1 -1
- package/dist/core/modules/ai/services/core-ai-prompt-hint.service.d.ts +1 -3
- package/dist/core/modules/ai/services/core-ai-prompt-hint.service.js +7 -5
- package/dist/core/modules/ai/services/core-ai-prompt-hint.service.js.map +1 -1
- package/dist/core/modules/ai/services/core-ai-prompt.service.d.ts +1 -2
- package/dist/core/modules/ai/services/core-ai-prompt.service.js +7 -5
- package/dist/core/modules/ai/services/core-ai-prompt.service.js.map +1 -1
- package/dist/core/modules/ai/services/core-ai-slot.service.d.ts +1 -2
- package/dist/core/modules/ai/services/core-ai-slot.service.js +7 -5
- package/dist/core/modules/ai/services/core-ai-slot.service.js.map +1 -1
- package/dist/core/modules/ai/services/core-ai-tool-grant.service.d.ts +1 -2
- package/dist/core/modules/ai/services/core-ai-tool-grant.service.js +7 -5
- package/dist/core/modules/ai/services/core-ai-tool-grant.service.js.map +1 -1
- package/dist/core/modules/ai/services/core-ai-tool-policy.service.d.ts +1 -2
- package/dist/core/modules/ai/services/core-ai-tool-policy.service.js +7 -5
- package/dist/core/modules/ai/services/core-ai-tool-policy.service.js.map +1 -1
- package/dist/core/modules/ai/services/core-ai.service.d.ts +2 -17
- package/dist/core/modules/ai/services/core-ai.service.js.map +1 -1
- package/dist/core/modules/auth/guards/roles.guard.js +2 -2
- package/dist/core/modules/auth/guards/roles.guard.js.map +1 -1
- package/dist/core/modules/better-auth/better-auth-roles.guard.js +3 -3
- package/dist/core/modules/better-auth/better-auth-roles.guard.js.map +1 -1
- package/dist/core/modules/better-auth/better-auth.config.js +6 -0
- package/dist/core/modules/better-auth/better-auth.config.js.map +1 -1
- package/dist/core/modules/better-auth/core-better-auth.constants.d.ts +3 -0
- package/dist/core/modules/better-auth/core-better-auth.constants.js +7 -0
- package/dist/core/modules/better-auth/core-better-auth.constants.js.map +1 -0
- package/dist/core/modules/better-auth/core-better-auth.controller.js +1 -3
- package/dist/core/modules/better-auth/core-better-auth.controller.js.map +1 -1
- package/dist/core/modules/better-auth/core-better-auth.module.d.ts +1 -2
- package/dist/core/modules/better-auth/core-better-auth.module.js +23 -20
- package/dist/core/modules/better-auth/core-better-auth.module.js.map +1 -1
- package/dist/core/modules/better-auth/core-better-auth.registry.d.ts +4 -0
- package/dist/core/modules/better-auth/core-better-auth.registry.js +16 -0
- package/dist/core/modules/better-auth/core-better-auth.registry.js.map +1 -0
- package/dist/core/modules/better-auth/core-better-auth.service.d.ts +1 -2
- package/dist/core/modules/better-auth/core-better-auth.service.js +7 -6
- package/dist/core/modules/better-auth/core-better-auth.service.js.map +1 -1
- package/dist/core/modules/better-auth/index.d.ts +1 -0
- package/dist/core/modules/better-auth/index.js +1 -0
- package/dist/core/modules/better-auth/index.js.map +1 -1
- package/dist/core/modules/tenant/core-tenant-member.model.js +3 -3
- package/dist/core/modules/tenant/core-tenant-member.model.js.map +1 -1
- package/dist/core/modules/tenant/core-tenant.guard.js +7 -6
- package/dist/core/modules/tenant/core-tenant.guard.js.map +1 -1
- package/dist/core/modules/tus/tus.constants.d.ts +1 -0
- package/dist/core/modules/tus/tus.constants.js +5 -0
- package/dist/core/modules/tus/tus.constants.js.map +1 -0
- package/dist/core/modules/tus/tus.module.d.ts +1 -1
- package/dist/core/modules/tus/tus.module.js +8 -6
- package/dist/core/modules/tus/tus.module.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/server/modules/user/user.service.js +1 -1
- package/dist/server/modules/user/user.service.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/docs/REQUEST-LIFECYCLE.md +39 -0
- package/migration-guides/11.27.6-to-11.27.7.md +374 -0
- package/migration-guides/11.27.7-to-11.28.0.md +350 -0
- package/package.json +6 -104
- package/src/core/common/decorators/restricted.decorator.ts +67 -20
- package/src/core/common/exceptions/access-denied.exception.ts +49 -0
- package/src/core/common/helpers/clone.helper.ts +110 -0
- package/src/core/common/helpers/db.helper.ts +14 -161
- package/src/core/common/helpers/id.helper.ts +198 -0
- package/src/core/common/helpers/input.helper.ts +21 -88
- package/src/core/common/helpers/service.helper.ts +6 -4
- package/src/core/common/inputs/combined-filter.input.ts +10 -57
- package/src/core/common/inputs/filter.input.ts +92 -1
- package/src/core/common/services/config.service.ts +4 -1
- package/src/core/modules/ai/core-ai.constants.ts +92 -0
- package/src/core/modules/ai/index.ts +1 -0
- package/src/core/modules/ai/interfaces/ai-interaction-record.interface.ts +34 -0
- package/src/core/modules/ai/services/core-ai-budget.service.ts +8 -4
- package/src/core/modules/ai/services/core-ai-connection-preference.service.ts +8 -4
- package/src/core/modules/ai/services/core-ai-connection.service.ts +5 -6
- package/src/core/modules/ai/services/core-ai-conversation.service.ts +5 -6
- package/src/core/modules/ai/services/core-ai-interaction.service.ts +6 -7
- package/src/core/modules/ai/services/core-ai-mode.service.ts +8 -2
- package/src/core/modules/ai/services/core-ai-prompt-hint.service.ts +7 -4
- package/src/core/modules/ai/services/core-ai-prompt.service.ts +8 -2
- package/src/core/modules/ai/services/core-ai-slot.service.ts +7 -4
- package/src/core/modules/ai/services/core-ai-tool-grant.service.ts +8 -4
- package/src/core/modules/ai/services/core-ai-tool-policy.service.ts +8 -4
- package/src/core/modules/ai/services/core-ai.service.ts +8 -11
- package/src/core/modules/auth/guards/roles.guard.ts +5 -4
- package/src/core/modules/better-auth/better-auth-roles.guard.ts +15 -7
- package/src/core/modules/better-auth/better-auth.config.ts +16 -0
- package/src/core/modules/better-auth/core-better-auth.constants.ts +73 -0
- package/src/core/modules/better-auth/core-better-auth.controller.ts +5 -6
- package/src/core/modules/better-auth/core-better-auth.module.ts +34 -8
- package/src/core/modules/better-auth/core-better-auth.registry.ts +53 -0
- package/src/core/modules/better-auth/core-better-auth.service.ts +19 -12
- package/src/core/modules/better-auth/index.ts +9 -0
- package/src/core/modules/tenant/core-tenant-member.model.ts +8 -3
- package/src/core/modules/tenant/core-tenant.guard.ts +26 -11
- package/src/core/modules/tus/tus.constants.ts +25 -0
- package/src/core/modules/tus/tus.module.ts +7 -2
- package/src/index.ts +1 -0
- package/src/server/modules/user/user.service.ts +3 -2
|
@@ -1,18 +1,27 @@
|
|
|
1
|
-
import { BadRequestException,
|
|
1
|
+
import { BadRequestException, ForbiddenException } from '@nestjs/common';
|
|
2
2
|
import { plainToInstance } from 'class-transformer';
|
|
3
3
|
import { validate } from 'class-validator';
|
|
4
4
|
import { ValidatorOptions } from 'class-validator/types/validation/ValidatorOptions';
|
|
5
5
|
import { Kind } from 'graphql/index';
|
|
6
|
-
import * as inspector from 'inspector';
|
|
7
|
-
import _ = require('lodash');
|
|
8
|
-
import rfdc = require('rfdc');
|
|
9
|
-
import * as util from 'util';
|
|
10
6
|
|
|
11
7
|
import { checkRestricted } from '../decorators/restricted.decorator';
|
|
12
8
|
import { ProcessType } from '../enums/process-type.enum';
|
|
13
9
|
import { RoleEnum } from '../enums/role.enum';
|
|
10
|
+
import { accessDeniedException } from '../exceptions/access-denied.exception';
|
|
11
|
+
import { ErrorCode } from '../../modules/error-code/error-codes';
|
|
12
|
+
import { clone } from './clone.helper';
|
|
14
13
|
import { merge } from './config.helper';
|
|
15
|
-
import { equalIds } from './
|
|
14
|
+
import { equalIds } from './id.helper';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* `clone` and `deepFreeze` moved to `./clone.helper` and are re-exported here so every existing
|
|
18
|
+
* import path keeps working. They were extracted because `config.service` needs `clone`/`deepFreeze`,
|
|
19
|
+
* and pulling them from HERE put it on a runtime import cycle
|
|
20
|
+
* (restricted.decorator → core-tenant.helpers → config.service → input.helper → restricted.decorator)
|
|
21
|
+
* that is one top-level line away from an SWC temporal-dead-zone crash. `clone.helper` imports no
|
|
22
|
+
* framework code, so it can never be part of a cycle. Do NOT move them back.
|
|
23
|
+
*/
|
|
24
|
+
export { clone, deepFreeze } from './clone.helper';
|
|
16
25
|
|
|
17
26
|
/**
|
|
18
27
|
* Helper class for inputs
|
|
@@ -241,9 +250,11 @@ export async function check(
|
|
|
241
250
|
}
|
|
242
251
|
let valid = false;
|
|
243
252
|
|
|
244
|
-
// Prevent access for everyone, including administrators
|
|
253
|
+
// Prevent access for everyone, including administrators. Always 403, never 401: the resource is
|
|
254
|
+
// locked permanently, so authenticating can never grant access and telling an anonymous
|
|
255
|
+
// requester to "authenticate and retry" (401) would be a lie. Both role guards do the same.
|
|
245
256
|
if (roles.includes(RoleEnum.S_NO_ONE)) {
|
|
246
|
-
throw new
|
|
257
|
+
throw new ForbiddenException(ErrorCode.ACCESS_DENIED);
|
|
247
258
|
}
|
|
248
259
|
|
|
249
260
|
// Check access
|
|
@@ -269,7 +280,8 @@ export async function check(
|
|
|
269
280
|
valid = true;
|
|
270
281
|
}
|
|
271
282
|
if (!valid) {
|
|
272
|
-
|
|
283
|
+
// 403 when authenticated, 401 otherwise — policy documented in accessDeniedException
|
|
284
|
+
throw accessDeniedException(user);
|
|
273
285
|
}
|
|
274
286
|
}
|
|
275
287
|
|
|
@@ -341,68 +353,6 @@ export function checkAndGetDate(input: any): Date {
|
|
|
341
353
|
return date;
|
|
342
354
|
}
|
|
343
355
|
|
|
344
|
-
/**
|
|
345
|
-
* Clone object
|
|
346
|
-
* @param object Any object
|
|
347
|
-
* @param options Finetuning of rfdc cloning
|
|
348
|
-
* @param options.checkResult Whether to compare object and cloned object via JSON.stringify and try alternative cloning
|
|
349
|
-
* methods if they are not equal
|
|
350
|
-
* @param options.circles Keeping track of circular references will slow down performance with an additional 25% overhead.
|
|
351
|
-
* Even if an object doesn't have any circular references, the tracking overhead is the cost.
|
|
352
|
-
* By default if an object with a circular reference is passed to rfdc, it will throw
|
|
353
|
-
* (similar to how JSON.stringify would throw). Use the circles option to detect and preserve
|
|
354
|
-
* circular references in the object. If performance is important, try removing the circular
|
|
355
|
-
* reference from the object (set to undefined) and then add it back manually after cloning
|
|
356
|
-
* instead of using this option.
|
|
357
|
-
* @param options.debug Whether to shoe console.debug messages
|
|
358
|
-
* @param options.proto Copy prototype properties as well as own properties into the new object.
|
|
359
|
-
* It's marginally faster to allow enumerable properties on the prototype to be copied into the
|
|
360
|
-
* cloned object (not onto it's prototype, directly onto the object).
|
|
361
|
-
*/
|
|
362
|
-
export function clone(object: any, options?: { checkResult?: boolean; circles?: boolean; proto?: boolean }) {
|
|
363
|
-
const config = {
|
|
364
|
-
checkResult: true,
|
|
365
|
-
circles: true,
|
|
366
|
-
debug: inspector.url() !== undefined,
|
|
367
|
-
proto: false,
|
|
368
|
-
...options,
|
|
369
|
-
};
|
|
370
|
-
|
|
371
|
-
try {
|
|
372
|
-
const cloned = rfdc(config)(object);
|
|
373
|
-
if (config.checkResult && !util.isDeepStrictEqual(object, cloned)) {
|
|
374
|
-
throw new Error('Cloned object differs from original object');
|
|
375
|
-
}
|
|
376
|
-
return cloned;
|
|
377
|
-
} catch (e) {
|
|
378
|
-
if (!config.circles) {
|
|
379
|
-
if (config.debug) {
|
|
380
|
-
console.debug(e, config, object, 'automatic try to use rfdc with circles');
|
|
381
|
-
}
|
|
382
|
-
try {
|
|
383
|
-
const clonedWithCircles = rfdc({
|
|
384
|
-
...config,
|
|
385
|
-
circles: true,
|
|
386
|
-
})(object);
|
|
387
|
-
if (config.checkResult && !util.isDeepStrictEqual(object, clonedWithCircles)) {
|
|
388
|
-
throw new Error('Cloned object differs from original object', { cause: e });
|
|
389
|
-
}
|
|
390
|
-
return clonedWithCircles;
|
|
391
|
-
} catch (innerError) {
|
|
392
|
-
if (config.debug) {
|
|
393
|
-
console.debug(innerError, 'rfcd with circles did not work => automatic use of _.clone!');
|
|
394
|
-
}
|
|
395
|
-
return _.cloneDeep(object);
|
|
396
|
-
}
|
|
397
|
-
} else {
|
|
398
|
-
if (config.debug) {
|
|
399
|
-
console.debug(e, config, object, 'automatic try to use _.clone instead rfdc');
|
|
400
|
-
}
|
|
401
|
-
return _.cloneDeep(object);
|
|
402
|
-
}
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
|
|
406
356
|
/**
|
|
407
357
|
* Combines objects to a new single plain object and ignores undefined
|
|
408
358
|
*/
|
|
@@ -410,23 +360,6 @@ export function combinePlain(...args: Record<any, any>[]): any {
|
|
|
410
360
|
return assignPlain({}, ...args);
|
|
411
361
|
}
|
|
412
362
|
|
|
413
|
-
/**
|
|
414
|
-
* Get deep frozen object
|
|
415
|
-
*/
|
|
416
|
-
export function deepFreeze(object: any, visited: WeakSet<object> = new WeakSet()) {
|
|
417
|
-
if (!object || typeof object !== 'object') {
|
|
418
|
-
return object;
|
|
419
|
-
}
|
|
420
|
-
if (visited.has(object)) {
|
|
421
|
-
return object;
|
|
422
|
-
}
|
|
423
|
-
visited.add(object);
|
|
424
|
-
for (const [key, value] of Object.entries(object)) {
|
|
425
|
-
object[key] = deepFreeze(value, visited);
|
|
426
|
-
}
|
|
427
|
-
return Object.freeze(object);
|
|
428
|
-
}
|
|
429
|
-
|
|
430
363
|
/**
|
|
431
364
|
* Standard error function
|
|
432
365
|
*/
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { UnauthorizedException } from '@nestjs/common';
|
|
2
1
|
import bcrypt = require('bcrypt');
|
|
3
2
|
import { sha256 } from 'js-sha256';
|
|
4
3
|
import _ = require('lodash');
|
|
5
4
|
import { Types } from 'mongoose';
|
|
6
5
|
|
|
7
6
|
import { RoleEnum } from '../enums/role.enum';
|
|
7
|
+
import { accessDeniedException } from '../exceptions/access-denied.exception';
|
|
8
8
|
import { PrepareInputOptions } from '../interfaces/prepare-input-options.interface';
|
|
9
9
|
import { PrepareOutputOptions } from '../interfaces/prepare-output-options.interface';
|
|
10
10
|
import { ResolveSelector } from '../interfaces/resolve-selector.interface';
|
|
@@ -151,15 +151,17 @@ export async function prepareInput<T = any>(
|
|
|
151
151
|
value === undefined && delete input[key];
|
|
152
152
|
}
|
|
153
153
|
|
|
154
|
-
// Process roles
|
|
154
|
+
// Process roles — 403 when authenticated, 401 otherwise (see accessDeniedException). The rejected
|
|
155
|
+
// roles are logged rather than returned: the client gets the translatable ErrorCode the guards use.
|
|
155
156
|
if (config.checkRoles && (input as Record<string, any>).roles && !currentUser?.hasRole?.(RoleEnum.ADMIN)) {
|
|
156
157
|
if (!(currentUser as any)?.roles) {
|
|
157
|
-
throw
|
|
158
|
+
throw accessDeniedException(currentUser);
|
|
158
159
|
} else {
|
|
159
160
|
const allowedRoles = _.intersection((input as Record<string, any>).roles, (currentUser as any).roles);
|
|
160
161
|
if (allowedRoles.length !== (input as Record<string, any>).roles.length) {
|
|
161
162
|
const missingRoles = _.difference((input as Record<string, any>).roles, (currentUser as any).roles);
|
|
162
|
-
|
|
163
|
+
console.debug(`Current user not allowed setting roles: ${missingRoles}`);
|
|
164
|
+
throw accessDeniedException(currentUser);
|
|
163
165
|
}
|
|
164
166
|
(input as Record<string, any>).roles = allowedRoles;
|
|
165
167
|
}
|
|
@@ -1,57 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
@InputType({
|
|
12
|
-
description: 'Combination of multiple filters via logical operator',
|
|
13
|
-
})
|
|
14
|
-
@Restricted(RoleEnum.S_EVERYONE)
|
|
15
|
-
export class CombinedFilterInput extends CoreInput {
|
|
16
|
-
/**
|
|
17
|
-
* Logical Operator to combine filters
|
|
18
|
-
*/
|
|
19
|
-
@UnifiedField({
|
|
20
|
-
description: 'Logical Operator to combine filters',
|
|
21
|
-
enum: LogicalOperatorEnum,
|
|
22
|
-
roles: RoleEnum.S_EVERYONE,
|
|
23
|
-
})
|
|
24
|
-
logicalOperator: LogicalOperatorEnum = undefined;
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Filters to combine via logical operator
|
|
28
|
-
*/
|
|
29
|
-
@UnifiedField({
|
|
30
|
-
description: 'Filters to combine via logical operator',
|
|
31
|
-
isOptional: true,
|
|
32
|
-
roles: RoleEnum.S_EVERYONE,
|
|
33
|
-
type: () => FilterInput,
|
|
34
|
-
})
|
|
35
|
-
filters: FilterInput[] = undefined;
|
|
36
|
-
|
|
37
|
-
// ===================================================================================================================
|
|
38
|
-
// Methods
|
|
39
|
-
// ===================================================================================================================
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Mapping for Subtypes
|
|
43
|
-
*/
|
|
44
|
-
override map(
|
|
45
|
-
data: Partial<this> | Record<string, any>,
|
|
46
|
-
options: {
|
|
47
|
-
cloneDeep?: boolean;
|
|
48
|
-
funcAllowed?: boolean;
|
|
49
|
-
mapId?: boolean;
|
|
50
|
-
} = {},
|
|
51
|
-
): this {
|
|
52
|
-
super.map(data, options);
|
|
53
|
-
this.filters = maps(data.filters, FilterInput, options.cloneDeep);
|
|
54
|
-
Object.keys(this).forEach((key) => this[key] === undefined && delete this[key]);
|
|
55
|
-
return this;
|
|
56
|
-
}
|
|
57
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* `CombinedFilterInput` is declared in `./filter.input` — the two classes are mutually recursive
|
|
3
|
+
* and must live in one module, or the cycle between them crashes SWC-compiled builds with
|
|
4
|
+
* `ReferenceError: Cannot access 'CombinedFilterInput' before initialization`. See the docblock in
|
|
5
|
+
* `./filter.input` for the full analysis.
|
|
6
|
+
*
|
|
7
|
+
* This file remains only so existing deep imports of `.../inputs/combined-filter.input` keep
|
|
8
|
+
* resolving. Do NOT move the class back here.
|
|
9
|
+
*/
|
|
10
|
+
export { CombinedFilterInput } from './filter.input';
|
|
@@ -1,12 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Filter inputs.
|
|
3
|
+
*
|
|
4
|
+
* `CombinedFilterInput` and `FilterInput` are mutually recursive: a filter may contain a combined
|
|
5
|
+
* filter, and a combined filter contains a list of filters. They therefore live in ONE module, and
|
|
6
|
+
* `CombinedFilterInput` is declared FIRST — that ordering is load-bearing, not cosmetic.
|
|
7
|
+
*
|
|
8
|
+
* They used to sit in two files that imported each other. `FilterInput` referenced
|
|
9
|
+
* `CombinedFilterInput` EAGERLY — in a decorator argument (`type: CombinedFilterInput`) and in the
|
|
10
|
+
* `design:type` metadata `emitDecoratorMetadata` emits for `combinedFilter?: CombinedFilterInput`.
|
|
11
|
+
* Decorator arguments and that metadata are evaluated at CLASS-DEFINITION time, i.e. while the
|
|
12
|
+
* module is still initializing. On a cycle that reads a class binding still in its temporal dead
|
|
13
|
+
* zone, and under SWC → CommonJS it threw:
|
|
14
|
+
*
|
|
15
|
+
* ReferenceError: Cannot access 'CombinedFilterInput' before initialization
|
|
16
|
+
*
|
|
17
|
+
* That was not hypothetical — `require('.../combined-filter.input.js')` crashed. It only stayed
|
|
18
|
+
* hidden because the package barrel happens to pull `filter.input` in first via other importers
|
|
19
|
+
* (`filter.args`, `filter.helper`), so entering through the barrel masked it. A deep import, a unit
|
|
20
|
+
* test importing the input directly, or a reordering of `src/index.ts` would all have detonated it.
|
|
21
|
+
*
|
|
22
|
+
* Making the reference lazy does NOT fix it: `type: () => CombinedFilterInput` still leaves the
|
|
23
|
+
* eager `design:type` metadata behind, and SWC's `typeof` guard does not protect the member
|
|
24
|
+
* expression it compiles to. The only real fix is to remove the import edge — hence one module.
|
|
25
|
+
*
|
|
26
|
+
* Within a single module the problem disappears: `FilterInput` reads `CombinedFilterInput` at
|
|
27
|
+
* definition time, and by then it is already initialized. The reverse direction is safe because
|
|
28
|
+
* `CombinedFilterInput` only reaches `FilterInput` lazily (a `() => FilterInput` thunk and a method
|
|
29
|
+
* body), never at definition time.
|
|
30
|
+
*
|
|
31
|
+
* `combined-filter.input.ts` remains as a re-export so existing deep imports keep working.
|
|
32
|
+
* See .claude/rules/architecture.md → "DI Token Placement (SWC-Safe)" for the general rule.
|
|
33
|
+
*/
|
|
1
34
|
import { InputType } from '@nestjs/graphql';
|
|
2
35
|
|
|
3
36
|
import { Restricted } from '../decorators/restricted.decorator';
|
|
4
37
|
import { UnifiedField } from '../decorators/unified-field.decorator';
|
|
38
|
+
import { LogicalOperatorEnum } from '../enums/logical-operator.enum';
|
|
5
39
|
import { RoleEnum } from '../enums/role.enum';
|
|
6
|
-
import {
|
|
40
|
+
import { maps } from '../helpers/model.helper';
|
|
7
41
|
import { CoreInput } from './core-input.input';
|
|
8
42
|
import { SingleFilterInput } from './single-filter.input';
|
|
9
43
|
|
|
44
|
+
/**
|
|
45
|
+
* Combination of multiple filters via logical operator.
|
|
46
|
+
*
|
|
47
|
+
* Declared BEFORE `FilterInput` on purpose — `FilterInput` dereferences this class at
|
|
48
|
+
* class-definition time, so it must already be initialized. See the module docblock.
|
|
49
|
+
*/
|
|
50
|
+
@InputType({
|
|
51
|
+
description: 'Combination of multiple filters via logical operator',
|
|
52
|
+
})
|
|
53
|
+
@Restricted(RoleEnum.S_EVERYONE)
|
|
54
|
+
export class CombinedFilterInput extends CoreInput {
|
|
55
|
+
/**
|
|
56
|
+
* Logical Operator to combine filters
|
|
57
|
+
*/
|
|
58
|
+
@UnifiedField({
|
|
59
|
+
description: 'Logical Operator to combine filters',
|
|
60
|
+
enum: LogicalOperatorEnum,
|
|
61
|
+
roles: RoleEnum.S_EVERYONE,
|
|
62
|
+
})
|
|
63
|
+
logicalOperator: LogicalOperatorEnum = undefined;
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Filters to combine via logical operator
|
|
67
|
+
*
|
|
68
|
+
* The `() => FilterInput` thunk is required: `FilterInput` is declared below, so an eager
|
|
69
|
+
* reference here would read it before initialization.
|
|
70
|
+
*/
|
|
71
|
+
@UnifiedField({
|
|
72
|
+
description: 'Filters to combine via logical operator',
|
|
73
|
+
isOptional: true,
|
|
74
|
+
roles: RoleEnum.S_EVERYONE,
|
|
75
|
+
type: () => FilterInput,
|
|
76
|
+
})
|
|
77
|
+
filters: FilterInput[] = undefined;
|
|
78
|
+
|
|
79
|
+
// ===================================================================================================================
|
|
80
|
+
// Methods
|
|
81
|
+
// ===================================================================================================================
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Mapping for Subtypes
|
|
85
|
+
*/
|
|
86
|
+
override map(
|
|
87
|
+
data: Partial<this> | Record<string, any>,
|
|
88
|
+
options: {
|
|
89
|
+
cloneDeep?: boolean;
|
|
90
|
+
funcAllowed?: boolean;
|
|
91
|
+
mapId?: boolean;
|
|
92
|
+
} = {},
|
|
93
|
+
): this {
|
|
94
|
+
super.map(data, options);
|
|
95
|
+
this.filters = maps(data.filters, FilterInput, options.cloneDeep);
|
|
96
|
+
Object.keys(this).forEach((key) => this[key] === undefined && delete this[key]);
|
|
97
|
+
return this;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
10
101
|
/**
|
|
11
102
|
* Input for filtering. The `singleFilter` will be ignored if the `combinedFilter` is set.
|
|
12
103
|
*/
|
|
@@ -4,7 +4,10 @@ import { BehaviorSubject, firstValueFrom } from 'rxjs';
|
|
|
4
4
|
import { filter, map } from 'rxjs/operators';
|
|
5
5
|
|
|
6
6
|
import { merge } from '../helpers/config.helper';
|
|
7
|
-
|
|
7
|
+
// Import from the clone.helper LEAF, never from input.helper: input.helper imports
|
|
8
|
+
// restricted.decorator, which reaches back here via core-tenant.helpers — that cycle is what the
|
|
9
|
+
// extraction removed. See clone.helper's docblock.
|
|
10
|
+
import { clone, deepFreeze } from '../helpers/clone.helper';
|
|
8
11
|
import { IServerOptions } from '../interfaces/server-options.interface';
|
|
9
12
|
|
|
10
13
|
/**
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dependency-injection tokens of the AI module.
|
|
3
|
+
*
|
|
4
|
+
* They live in a dedicated, import-free leaf file — never in a service or in `core-ai.module.ts` —
|
|
5
|
+
* so that no file needing a token has to import the file that declares it, and no import cycle can
|
|
6
|
+
* form around one.
|
|
7
|
+
*
|
|
8
|
+
* On a cycle, a token read at MODULE-EVALUATION time — inside an `@Inject()` decorator argument, in
|
|
9
|
+
* the `design:paramtypes` metadata `emitDecoratorMetadata` emits, or in a static field initializer —
|
|
10
|
+
* reads a `const` still in its temporal dead zone, and SWC-compiled builds (`nest start -b swc`) die
|
|
11
|
+
* at startup with:
|
|
12
|
+
*
|
|
13
|
+
* ReferenceError: Cannot access 'AI_CONNECTION_MODEL' before initialization
|
|
14
|
+
*
|
|
15
|
+
* These tokens were previously declared across eleven `*.service.ts` files, every one of which is
|
|
16
|
+
* imported by `core-ai.module.ts` and injects tokens through constructor decorators. Nothing had
|
|
17
|
+
* crashed — the graph happened to be acyclic — but a single back-import from any of those services
|
|
18
|
+
* would have armed it, and `tsc`, `pnpm test` and `oxlint` are ALL blind to that. Only
|
|
19
|
+
* `pnpm run check:swc-tdz` sees it.
|
|
20
|
+
*
|
|
21
|
+
* A file that imports nothing can never be mid-evaluation when someone imports it, in any module
|
|
22
|
+
* system, under any compiler. Keep this file import-free.
|
|
23
|
+
*
|
|
24
|
+
* The old locations re-export their tokens, so every existing import path still resolves.
|
|
25
|
+
* See .claude/rules/architecture.md → "DI Token Placement (SWC-Safe)".
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
// ---- budget ----
|
|
29
|
+
/** DI token for the model constructor (used by CrudService mapping). */
|
|
30
|
+
export const AI_BUDGET_LIMIT_CLASS = 'AI_BUDGET_LIMIT_CLASS';
|
|
31
|
+
/** Mongoose injection token. */
|
|
32
|
+
export const AI_BUDGET_LIMIT_MODEL = 'AiBudgetLimit';
|
|
33
|
+
|
|
34
|
+
// ---- connection-preference ----
|
|
35
|
+
/** DI token for the model constructor (used by CrudService mapping). */
|
|
36
|
+
export const AI_CONNECTION_PREFERENCE_CLASS = 'AI_CONNECTION_PREFERENCE_CLASS';
|
|
37
|
+
/** Mongoose injection token. */
|
|
38
|
+
export const AI_CONNECTION_PREFERENCE_MODEL = 'AiConnectionPreference';
|
|
39
|
+
|
|
40
|
+
// ---- connection ----
|
|
41
|
+
/** DI token for the model constructor (used by CrudService mapping). */
|
|
42
|
+
export const AI_CONNECTION_CLASS = 'AI_CONNECTION_CLASS';
|
|
43
|
+
/** Mongoose injection token. */
|
|
44
|
+
export const AI_CONNECTION_MODEL = 'AiConnection';
|
|
45
|
+
|
|
46
|
+
// ---- conversation ----
|
|
47
|
+
/** DI token for the model constructor (used by CrudService mapping). */
|
|
48
|
+
export const AI_CONVERSATION_CLASS = 'AI_CONVERSATION_CLASS';
|
|
49
|
+
/** Mongoose injection token. */
|
|
50
|
+
export const AI_CONVERSATION_MODEL = 'AiConversation';
|
|
51
|
+
|
|
52
|
+
// ---- interaction ----
|
|
53
|
+
/** DI token for the model constructor (used by CrudService mapping). */
|
|
54
|
+
export const AI_INTERACTION_CLASS = 'AI_INTERACTION_CLASS';
|
|
55
|
+
/** Mongoose injection token. */
|
|
56
|
+
export const AI_INTERACTION_MODEL = 'AiInteraction';
|
|
57
|
+
|
|
58
|
+
// ---- mode ----
|
|
59
|
+
/** DI token for the model constructor (used by CrudService mapping). */
|
|
60
|
+
export const AI_MODE_CLASS = 'AI_MODE_CLASS';
|
|
61
|
+
/** Mongoose injection token. */
|
|
62
|
+
export const AI_MODE_MODEL = 'AiMode';
|
|
63
|
+
|
|
64
|
+
// ---- prompt-hint ----
|
|
65
|
+
/** DI token for the model constructor (used by CrudService mapping). */
|
|
66
|
+
export const AI_PROMPT_HINT_CLASS = 'AI_PROMPT_HINT_CLASS';
|
|
67
|
+
/** Mongoose injection token. */
|
|
68
|
+
export const AI_PROMPT_HINT_MODEL = 'AiPromptHint';
|
|
69
|
+
|
|
70
|
+
// ---- prompt ----
|
|
71
|
+
/** DI token for the model constructor (used by CrudService mapping). */
|
|
72
|
+
export const AI_PROMPT_CLASS = 'AI_PROMPT_CLASS';
|
|
73
|
+
/** Mongoose injection token. */
|
|
74
|
+
export const AI_PROMPT_MODEL = 'AiPrompt';
|
|
75
|
+
|
|
76
|
+
// ---- slot ----
|
|
77
|
+
/** DI token for the model constructor (used by CrudService mapping). */
|
|
78
|
+
export const AI_SLOT_CLASS = 'AI_SLOT_CLASS';
|
|
79
|
+
/** Mongoose injection token. */
|
|
80
|
+
export const AI_SLOT_MODEL = 'AiSlot';
|
|
81
|
+
|
|
82
|
+
// ---- tool-grant ----
|
|
83
|
+
/** DI token for the model constructor (used by CrudService mapping). */
|
|
84
|
+
export const AI_TOOL_GRANT_CLASS = 'AI_TOOL_GRANT_CLASS';
|
|
85
|
+
/** Mongoose injection token. */
|
|
86
|
+
export const AI_TOOL_GRANT_MODEL = 'AiToolGrant';
|
|
87
|
+
|
|
88
|
+
// ---- tool-policy ----
|
|
89
|
+
/** DI token for the model constructor (used by CrudService mapping). */
|
|
90
|
+
export const AI_TOOL_POLICY_CLASS = 'AI_TOOL_POLICY_CLASS';
|
|
91
|
+
/** Mongoose injection token. */
|
|
92
|
+
export const AI_TOOL_POLICY_MODEL = 'AiToolPolicy';
|
|
@@ -20,6 +20,7 @@ export * from './inputs/core-ai-slot-update.input';
|
|
|
20
20
|
export * from './inputs/core-ai-prompt.input';
|
|
21
21
|
export * from './hooks/ai-hook.base';
|
|
22
22
|
export * from './hooks/ai-hook.registry';
|
|
23
|
+
export * from './interfaces/ai-interaction-record.interface';
|
|
23
24
|
export * from './interfaces/ai-hook.interface';
|
|
24
25
|
export * from './interfaces/ai-placeholder.interface';
|
|
25
26
|
export * from './interfaces/ai-tool.interface';
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The record passed to `CoreAiService.audit()` for each prompt run.
|
|
3
|
+
*
|
|
4
|
+
* It lives here, in an import-free leaf, rather than in `core-ai.service.ts` — and that is
|
|
5
|
+
* load-bearing, not tidiness.
|
|
6
|
+
*
|
|
7
|
+
* `core-ai.service` imports `core-ai-interaction.service` (it needs the class), and
|
|
8
|
+
* `core-ai-interaction.service` needs this type back. Declared in the service, that pair forms an
|
|
9
|
+
* import cycle. It never crashed for exactly one reason: the type was pulled in with `import type`,
|
|
10
|
+
* which both tsc and SWC erase, so no `require()` was emitted and the cycle was never real at
|
|
11
|
+
* runtime.
|
|
12
|
+
*
|
|
13
|
+
* That is a single keyword of protection, on a file where `core-ai.service` has a constructor
|
|
14
|
+
* `@Inject`, so `emitDecoratorMetadata` emits `design:paramtypes` at module-evaluation time — the
|
|
15
|
+
* exact eval-time dereference that turns a cycle fatal. An IDE "organize imports" or a lint autofix
|
|
16
|
+
* widening `import type` to a plain `import` would have armed it silently, and `tsc`, `pnpm test`
|
|
17
|
+
* and `oxlint` are ALL blind to that (vitest runs SWC through Vite's cycle-tolerant module runner).
|
|
18
|
+
* Only `pnpm run check:swc-tdz` would have caught it — after the fact.
|
|
19
|
+
*
|
|
20
|
+
* Moving the type out removes the edge entirely, so the cycle no longer exists rather than merely
|
|
21
|
+
* being disarmed. `core-ai.service` re-exports it, so every existing import path still resolves.
|
|
22
|
+
*
|
|
23
|
+
* See .claude/rules/architecture.md → "DI Token Placement (SWC-Safe)".
|
|
24
|
+
*/
|
|
25
|
+
export interface AiInteractionRecord {
|
|
26
|
+
actions: { name: string; success: boolean }[];
|
|
27
|
+
connectionId: string;
|
|
28
|
+
iterations: number;
|
|
29
|
+
prompt: string;
|
|
30
|
+
responseText: string;
|
|
31
|
+
tenantId?: string;
|
|
32
|
+
usage?: { completionTokens?: number; promptTokens?: number; totalTokens?: number };
|
|
33
|
+
userId?: string;
|
|
34
|
+
}
|
|
@@ -11,10 +11,14 @@ import { CoreAiBudgetLimitInput } from '../inputs/core-ai-budget-limit.input';
|
|
|
11
11
|
import { AiBudgetLimitDocument, CoreAiBudgetLimit } from '../models/core-ai-budget-limit.model';
|
|
12
12
|
import { CoreAiBudgetSummary, CoreAiUsageInfo, CoreAiUsageScope } from '../models/core-ai-usage-info.model';
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
|
|
14
|
+
import { AI_BUDGET_LIMIT_CLASS, AI_BUDGET_LIMIT_MODEL } from '../core-ai.constants';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* @deprecated Import from `../core-ai.constants` instead. Re-exported only so existing deep imports
|
|
18
|
+
* keep working; the tokens are declared in an import-free leaf so no cycle can form around them
|
|
19
|
+
* (SWC-safe — see core-ai.constants.ts).
|
|
20
|
+
*/
|
|
21
|
+
export { AI_BUDGET_LIMIT_CLASS, AI_BUDGET_LIMIT_MODEL } from '../core-ai.constants';
|
|
18
22
|
|
|
19
23
|
/** Resolved effective limit for a scope. */
|
|
20
24
|
export interface ResolvedAiBudgetLimit {
|
|
@@ -10,10 +10,14 @@ import {
|
|
|
10
10
|
CoreAiConnectionPreference,
|
|
11
11
|
} from '../models/core-ai-connection-preference.model';
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
|
|
13
|
+
import { AI_CONNECTION_PREFERENCE_CLASS, AI_CONNECTION_PREFERENCE_MODEL } from '../core-ai.constants';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @deprecated Import from `../core-ai.constants` instead. Re-exported only so existing deep imports
|
|
17
|
+
* keep working; the tokens are declared in an import-free leaf so no cycle can form around them
|
|
18
|
+
* (SWC-safe — see core-ai.constants.ts).
|
|
19
|
+
*/
|
|
20
|
+
export { AI_CONNECTION_PREFERENCE_CLASS, AI_CONNECTION_PREFERENCE_MODEL } from '../core-ai.constants';
|
|
17
21
|
|
|
18
22
|
/**
|
|
19
23
|
* CRUD + lookup for {@link CoreAiConnectionPreference} (tenant/user connection
|
|
@@ -23,15 +23,14 @@ import { LlmProviderFactory } from '../providers/llm-provider.factory';
|
|
|
23
23
|
import { AiCryptoService } from './ai-crypto.service';
|
|
24
24
|
import { CoreAiConnectionPreferenceService } from './core-ai-connection-preference.service';
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
* Mongoose injection token for the AI connection model.
|
|
28
|
-
*/
|
|
29
|
-
export const AI_CONNECTION_MODEL = 'AiConnection';
|
|
26
|
+
import { AI_CONNECTION_CLASS, AI_CONNECTION_MODEL } from '../core-ai.constants';
|
|
30
27
|
|
|
31
28
|
/**
|
|
32
|
-
*
|
|
29
|
+
* @deprecated Import from `../core-ai.constants` instead. Re-exported only so existing deep imports
|
|
30
|
+
* keep working; the tokens are declared in an import-free leaf so no cycle can form around them
|
|
31
|
+
* (SWC-safe — see core-ai.constants.ts).
|
|
33
32
|
*/
|
|
34
|
-
export
|
|
33
|
+
export { AI_CONNECTION_CLASS, AI_CONNECTION_MODEL } from '../core-ai.constants';
|
|
35
34
|
|
|
36
35
|
/**
|
|
37
36
|
* CRUD service for {@link CoreAiConnection} — the database-backed LLM
|
|
@@ -8,15 +8,14 @@ import { CoreAiConversationCreateInput } from '../inputs/core-ai-conversation-cr
|
|
|
8
8
|
import { CoreAiConversationInput } from '../inputs/core-ai-conversation.input';
|
|
9
9
|
import { AiConversationDocument, CoreAiConversation } from '../models/core-ai-conversation.model';
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
* Mongoose injection token for the AI conversation model.
|
|
13
|
-
*/
|
|
14
|
-
export const AI_CONVERSATION_MODEL = 'AiConversation';
|
|
11
|
+
import { AI_CONVERSATION_CLASS, AI_CONVERSATION_MODEL } from '../core-ai.constants';
|
|
15
12
|
|
|
16
13
|
/**
|
|
17
|
-
*
|
|
14
|
+
* @deprecated Import from `../core-ai.constants` instead. Re-exported only so existing deep imports
|
|
15
|
+
* keep working; the tokens are declared in an import-free leaf so no cycle can form around them
|
|
16
|
+
* (SWC-safe — see core-ai.constants.ts).
|
|
18
17
|
*/
|
|
19
|
-
export
|
|
18
|
+
export { AI_CONVERSATION_CLASS, AI_CONVERSATION_MODEL } from '../core-ai.constants';
|
|
20
19
|
|
|
21
20
|
/**
|
|
22
21
|
* CRUD service for multi-turn {@link CoreAiConversation}s.
|
|
@@ -5,17 +5,16 @@ import { Model } from 'mongoose';
|
|
|
5
5
|
import { CrudService } from '../../../common/services/crud.service';
|
|
6
6
|
import { CoreModelConstructor } from '../../../common/types/core-model-constructor.type';
|
|
7
7
|
import { AiInteractionDocument, CoreAiInteraction } from '../models/core-ai-interaction.model';
|
|
8
|
-
import type { AiInteractionRecord } from '
|
|
8
|
+
import type { AiInteractionRecord } from '../interfaces/ai-interaction-record.interface';
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
* Mongoose injection token for the AI interaction model.
|
|
12
|
-
*/
|
|
13
|
-
export const AI_INTERACTION_MODEL = 'AiInteraction';
|
|
10
|
+
import { AI_INTERACTION_CLASS, AI_INTERACTION_MODEL } from '../core-ai.constants';
|
|
14
11
|
|
|
15
12
|
/**
|
|
16
|
-
*
|
|
13
|
+
* @deprecated Import from `../core-ai.constants` instead. Re-exported only so existing deep imports
|
|
14
|
+
* keep working; the tokens are declared in an import-free leaf so no cycle can form around them
|
|
15
|
+
* (SWC-safe — see core-ai.constants.ts).
|
|
17
16
|
*/
|
|
18
|
-
export
|
|
17
|
+
export { AI_INTERACTION_CLASS, AI_INTERACTION_MODEL } from '../core-ai.constants';
|
|
19
18
|
|
|
20
19
|
/**
|
|
21
20
|
* CRUD + write service for {@link CoreAiInteraction} audit records.
|
|
@@ -6,8 +6,14 @@ import { CrudService } from '../../../common/services/crud.service';
|
|
|
6
6
|
import { CoreModelConstructor } from '../../../common/types/core-model-constructor.type';
|
|
7
7
|
import { AiModeDocument, CoreAiMode } from '../models/core-ai-mode.model';
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
import { AI_MODE_CLASS, AI_MODE_MODEL } from '../core-ai.constants';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @deprecated Import from `../core-ai.constants` instead. Re-exported only so existing deep imports
|
|
13
|
+
* keep working; the tokens are declared in an import-free leaf so no cycle can form around them
|
|
14
|
+
* (SWC-safe — see core-ai.constants.ts).
|
|
15
|
+
*/
|
|
16
|
+
export { AI_MODE_CLASS, AI_MODE_MODEL } from '../core-ai.constants';
|
|
11
17
|
|
|
12
18
|
/**
|
|
13
19
|
* Named-mode store. See {@link CoreAiMode}. Override via
|
|
@@ -9,11 +9,14 @@ import { CoreAiPromptHintCreateInput } from '../inputs/core-ai-prompt-hint-creat
|
|
|
9
9
|
import { CoreAiPromptHintInput } from '../inputs/core-ai-prompt-hint.input';
|
|
10
10
|
import { AiPromptHintDocument, CoreAiPromptHint } from '../models/core-ai-prompt-hint.model';
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
export const AI_PROMPT_HINT_MODEL = 'AiPromptHint';
|
|
12
|
+
import { AI_PROMPT_HINT_CLASS, AI_PROMPT_HINT_MODEL } from '../core-ai.constants';
|
|
14
13
|
|
|
15
|
-
/**
|
|
16
|
-
|
|
14
|
+
/**
|
|
15
|
+
* @deprecated Import from `../core-ai.constants` instead. Re-exported only so existing deep imports
|
|
16
|
+
* keep working; the tokens are declared in an import-free leaf so no cycle can form around them
|
|
17
|
+
* (SWC-safe — see core-ai.constants.ts).
|
|
18
|
+
*/
|
|
19
|
+
export { AI_PROMPT_HINT_CLASS, AI_PROMPT_HINT_MODEL } from '../core-ai.constants';
|
|
17
20
|
|
|
18
21
|
/** A failure signal recorded by the orchestrator for the learning loop. */
|
|
19
22
|
export interface AiPromptFeedbackSignal {
|