@solidxai/core 0.1.10-beta.26 → 0.1.10-beta.28
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/settings.local.json +15 -0
- package/CLAUDE.md +26 -0
- package/MICROSOFT_ACTIVE_DIRECTORY_OAUTH_FLOW.md +616 -0
- package/ai-interaction-cleanup.sql +53 -0
- package/dist/constants/error-messages.d.ts +1 -0
- package/dist/constants/error-messages.d.ts.map +1 -1
- package/dist/constants/error-messages.js +1 -0
- package/dist/constants/error-messages.js.map +1 -1
- package/dist/controllers/microsoft-active-directory-authentication.controller.d.ts +28 -0
- package/dist/controllers/microsoft-active-directory-authentication.controller.d.ts.map +1 -0
- package/dist/controllers/microsoft-active-directory-authentication.controller.js +122 -0
- package/dist/controllers/microsoft-active-directory-authentication.controller.js.map +1 -0
- package/dist/controllers/service.controller.d.ts +1 -5
- package/dist/controllers/service.controller.d.ts.map +1 -1
- package/dist/controllers/service.controller.js +6 -11
- package/dist/controllers/service.controller.js.map +1 -1
- package/dist/controllers/test.controller.d.ts +1 -6
- package/dist/controllers/test.controller.d.ts.map +1 -1
- package/dist/controllers/test.controller.js +2 -20
- package/dist/controllers/test.controller.js.map +1 -1
- package/dist/dtos/create-permission-metadata.dto.d.ts.map +1 -1
- package/dist/dtos/create-permission-metadata.dto.js +2 -0
- package/dist/dtos/create-permission-metadata.dto.js.map +1 -1
- package/dist/dtos/create-role-metadata.dto.d.ts +2 -0
- package/dist/dtos/create-role-metadata.dto.d.ts.map +1 -1
- package/dist/dtos/create-role-metadata.dto.js +13 -1
- package/dist/dtos/create-role-metadata.dto.js.map +1 -1
- package/dist/dtos/import-instructions.dto.d.ts +2 -0
- package/dist/dtos/import-instructions.dto.d.ts.map +1 -1
- package/dist/dtos/import-instructions.dto.js +15 -1
- package/dist/dtos/import-instructions.dto.js.map +1 -1
- package/dist/dtos/update-permission-metadata.dto.d.ts.map +1 -1
- package/dist/dtos/update-permission-metadata.dto.js +3 -1
- package/dist/dtos/update-permission-metadata.dto.js.map +1 -1
- package/dist/dtos/update-role-metadata.dto.d.ts +2 -0
- package/dist/dtos/update-role-metadata.dto.d.ts.map +1 -1
- package/dist/dtos/update-role-metadata.dto.js +13 -1
- package/dist/dtos/update-role-metadata.dto.js.map +1 -1
- package/dist/entities/action-metadata.entity.d.ts.map +1 -1
- package/dist/entities/action-metadata.entity.js +1 -0
- package/dist/entities/action-metadata.entity.js.map +1 -1
- package/dist/entities/agent-event.entity.d.ts.map +1 -1
- package/dist/entities/agent-event.entity.js +1 -0
- package/dist/entities/agent-event.entity.js.map +1 -1
- package/dist/entities/agent-session.entity.d.ts.map +1 -1
- package/dist/entities/agent-session.entity.js +1 -0
- package/dist/entities/agent-session.entity.js.map +1 -1
- package/dist/entities/chatter-message.entity.d.ts.map +1 -1
- package/dist/entities/chatter-message.entity.js +2 -0
- package/dist/entities/chatter-message.entity.js.map +1 -1
- package/dist/entities/email-template.entity.d.ts.map +1 -1
- package/dist/entities/email-template.entity.js +1 -0
- package/dist/entities/email-template.entity.js.map +1 -1
- package/dist/entities/field-metadata.entity.d.ts.map +1 -1
- package/dist/entities/field-metadata.entity.js +4 -0
- package/dist/entities/field-metadata.entity.js.map +1 -1
- package/dist/entities/list-of-values.entity.d.ts.map +1 -1
- package/dist/entities/list-of-values.entity.js +4 -0
- package/dist/entities/list-of-values.entity.js.map +1 -1
- package/dist/entities/locale.entity.d.ts.map +1 -1
- package/dist/entities/locale.entity.js +1 -0
- package/dist/entities/locale.entity.js.map +1 -1
- package/dist/entities/media.entity.d.ts.map +1 -1
- package/dist/entities/media.entity.js +1 -0
- package/dist/entities/media.entity.js.map +1 -1
- package/dist/entities/menu-item-metadata.entity.d.ts.map +1 -1
- package/dist/entities/menu-item-metadata.entity.js +2 -0
- package/dist/entities/menu-item-metadata.entity.js.map +1 -1
- package/dist/entities/model-metadata.entity.d.ts.map +1 -1
- package/dist/entities/model-metadata.entity.js +3 -0
- package/dist/entities/model-metadata.entity.js.map +1 -1
- package/dist/entities/module-metadata.entity.d.ts.map +1 -1
- package/dist/entities/module-metadata.entity.js +2 -0
- package/dist/entities/module-metadata.entity.js.map +1 -1
- package/dist/entities/permission-metadata.entity.d.ts.map +1 -1
- package/dist/entities/permission-metadata.entity.js.map +1 -1
- package/dist/entities/role-metadata.entity.d.ts +2 -0
- package/dist/entities/role-metadata.entity.d.ts.map +1 -1
- package/dist/entities/role-metadata.entity.js +10 -2
- package/dist/entities/role-metadata.entity.js.map +1 -1
- package/dist/entities/saved-filters.entity.d.ts.map +1 -1
- package/dist/entities/saved-filters.entity.js +3 -0
- package/dist/entities/saved-filters.entity.js.map +1 -1
- package/dist/entities/scheduled-job.entity.d.ts.map +1 -1
- package/dist/entities/scheduled-job.entity.js +2 -0
- package/dist/entities/scheduled-job.entity.js.map +1 -1
- package/dist/entities/security-rule.entity.d.ts.map +1 -1
- package/dist/entities/security-rule.entity.js +1 -0
- package/dist/entities/security-rule.entity.js.map +1 -1
- package/dist/entities/sms-template.entity.d.ts.map +1 -1
- package/dist/entities/sms-template.entity.js +2 -0
- package/dist/entities/sms-template.entity.js.map +1 -1
- package/dist/entities/user-activity-history.entity.d.ts.map +1 -1
- package/dist/entities/user-activity-history.entity.js +1 -0
- package/dist/entities/user-activity-history.entity.js.map +1 -1
- package/dist/entities/user.entity.d.ts +3 -0
- package/dist/entities/user.entity.d.ts.map +1 -1
- package/dist/entities/user.entity.js +15 -1
- package/dist/entities/user.entity.js.map +1 -1
- package/dist/entities/view-metadata.entity.d.ts.map +1 -1
- package/dist/entities/view-metadata.entity.js +2 -0
- package/dist/entities/view-metadata.entity.js.map +1 -1
- package/dist/helpers/microsoft-active-directory-oauth.helper.d.ts +34 -0
- package/dist/helpers/microsoft-active-directory-oauth.helper.d.ts.map +1 -0
- package/dist/helpers/microsoft-active-directory-oauth.helper.js +43 -0
- package/dist/helpers/microsoft-active-directory-oauth.helper.js.map +1 -0
- package/dist/helpers/module.helper.js +0 -5
- package/dist/helpers/module.helper.js.map +1 -1
- package/dist/helpers/user-helper.d.ts.map +1 -1
- package/dist/helpers/user-helper.js +4 -0
- package/dist/helpers/user-helper.js.map +1 -1
- package/dist/index.d.ts +1 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -5
- package/dist/index.js.map +1 -1
- package/dist/interfaces.d.ts +0 -8
- package/dist/interfaces.d.ts.map +1 -1
- package/dist/interfaces.js.map +1 -1
- package/dist/passport-strategies/microsoft-active-directory-oauth.strategy.d.ts +14 -0
- package/dist/passport-strategies/microsoft-active-directory-oauth.strategy.d.ts.map +1 -0
- package/dist/passport-strategies/microsoft-active-directory-oauth.strategy.js +67 -0
- package/dist/passport-strategies/microsoft-active-directory-oauth.strategy.js.map +1 -0
- package/dist/seeders/seed-data/solid-core-metadata.json +317 -814
- package/dist/services/authentication.service.d.ts +12 -0
- package/dist/services/authentication.service.d.ts.map +1 -1
- package/dist/services/authentication.service.js +64 -0
- package/dist/services/authentication.service.js.map +1 -1
- package/dist/services/crud-helper.service.d.ts.map +1 -1
- package/dist/services/crud-helper.service.js +11 -3
- package/dist/services/crud-helper.service.js.map +1 -1
- package/dist/services/import-transaction.service.d.ts.map +1 -1
- package/dist/services/import-transaction.service.js +6 -0
- package/dist/services/import-transaction.service.js.map +1 -1
- package/dist/services/settings/default-settings-provider.service.d.ts +100 -0
- package/dist/services/settings/default-settings-provider.service.d.ts.map +1 -1
- package/dist/services/settings/default-settings-provider.service.js +56 -0
- package/dist/services/settings/default-settings-provider.service.js.map +1 -1
- package/dist/services/user.service.d.ts +2 -0
- package/dist/services/user.service.d.ts.map +1 -1
- package/dist/services/user.service.js +46 -0
- package/dist/services/user.service.js.map +1 -1
- package/dist/solid-core.module.d.ts.map +1 -1
- package/dist/solid-core.module.js +4 -29
- package/dist/solid-core.module.js.map +1 -1
- package/dist/subscribers/scheduled-job.subscriber.js +1 -1
- package/dist/subscribers/scheduled-job.subscriber.js.map +1 -1
- package/dist/subscribers/security-rule.subscriber.js +1 -1
- package/dist/subscribers/security-rule.subscriber.js.map +1 -1
- package/package.json +4 -4
- package/src/constants/error-messages.ts +2 -1
- package/src/controllers/microsoft-active-directory-authentication.controller.ts +104 -0
- package/src/controllers/service.controller.ts +4 -7
- package/src/controllers/test.controller.ts +0 -9
- package/src/dtos/create-permission-metadata.dto.ts +3 -0
- package/src/dtos/create-role-metadata.dto.ts +11 -1
- package/src/dtos/import-instructions.dto.ts +11 -1
- package/src/dtos/update-permission-metadata.dto.ts +4 -1
- package/src/dtos/update-role-metadata.dto.ts +21 -1
- package/src/entities/action-metadata.entity.ts +1 -0
- package/src/entities/agent-event.entity.ts +1 -0
- package/src/entities/agent-session.entity.ts +1 -0
- package/src/entities/chatter-message.entity.ts +2 -0
- package/src/entities/email-template.entity.ts +1 -0
- package/src/entities/field-metadata.entity.ts +4 -1
- package/src/entities/list-of-values.entity.ts +5 -1
- package/src/entities/locale.entity.ts +1 -0
- package/src/entities/media.entity.ts +1 -0
- package/src/entities/menu-item-metadata.entity.ts +2 -0
- package/src/entities/model-metadata.entity.ts +3 -0
- package/src/entities/module-metadata.entity.ts +2 -0
- package/src/entities/permission-metadata.entity.ts +2 -2
- package/src/entities/role-metadata.entity.ts +11 -3
- package/src/entities/saved-filters.entity.ts +3 -0
- package/src/entities/scheduled-job.entity.ts +2 -0
- package/src/entities/security-rule.entity.ts +1 -0
- package/src/entities/sms-template.entity.ts +2 -0
- package/src/entities/user-activity-history.entity.ts +1 -0
- package/src/entities/user.entity.ts +15 -1
- package/src/entities/view-metadata.entity.ts +2 -0
- package/src/helpers/microsoft-active-directory-oauth.helper.ts +83 -0
- package/src/helpers/module.helper.ts +5 -5
- package/src/helpers/user-helper.ts +5 -1
- package/src/index.ts +1 -5
- package/src/interfaces.ts +0 -8
- package/src/passport-strategies/microsoft-active-directory-oauth.strategy.ts +63 -0
- package/src/seeders/seed-data/solid-core-metadata.json +317 -814
- package/src/services/1.js +6 -0
- package/src/services/authentication.service.ts +78 -0
- package/src/services/crud-helper.service.ts +9 -3
- package/src/services/import-transaction.service.ts +11 -1
- package/src/services/settings/default-settings-provider.service.ts +59 -0
- package/src/services/user.service.ts +61 -0
- package/src/solid-core.module.ts +4 -31
- package/src/subscribers/scheduled-job.subscriber.ts +1 -1
- package/src/subscribers/security-rule.subscriber.ts +1 -1
- package/dist/commands/ingest.command.d.ts +0 -16
- package/dist/commands/ingest.command.d.ts.map +0 -1
- package/dist/commands/ingest.command.js +0 -50
- package/dist/commands/ingest.command.js.map +0 -1
- package/dist/controllers/ai-interaction.controller.d.ts +0 -29
- package/dist/controllers/ai-interaction.controller.d.ts.map +0 -1
- package/dist/controllers/ai-interaction.controller.js +0 -218
- package/dist/controllers/ai-interaction.controller.js.map +0 -1
- package/dist/dtos/create-ai-interaction.dto.d.ts +0 -23
- package/dist/dtos/create-ai-interaction.dto.d.ts.map +0 -1
- package/dist/dtos/create-ai-interaction.dto.js +0 -149
- package/dist/dtos/create-ai-interaction.dto.js.map +0 -1
- package/dist/dtos/invoke-ai-prompt.dto.d.ts +0 -5
- package/dist/dtos/invoke-ai-prompt.dto.d.ts.map +0 -1
- package/dist/dtos/invoke-ai-prompt.dto.js +0 -30
- package/dist/dtos/invoke-ai-prompt.dto.js.map +0 -1
- package/dist/dtos/update-ai-interaction.dto.d.ts +0 -24
- package/dist/dtos/update-ai-interaction.dto.d.ts.map +0 -1
- package/dist/dtos/update-ai-interaction.dto.js +0 -150
- package/dist/dtos/update-ai-interaction.dto.js.map +0 -1
- package/dist/entities/ai-interaction.entity.d.ts +0 -24
- package/dist/entities/ai-interaction.entity.d.ts.map +0 -1
- package/dist/entities/ai-interaction.entity.js +0 -116
- package/dist/entities/ai-interaction.entity.js.map +0 -1
- package/dist/jobs/database/trigger-mcp-client-publisher-database.service.d.ts +0 -11
- package/dist/jobs/database/trigger-mcp-client-publisher-database.service.d.ts.map +0 -1
- package/dist/jobs/database/trigger-mcp-client-publisher-database.service.js +0 -39
- package/dist/jobs/database/trigger-mcp-client-publisher-database.service.js.map +0 -1
- package/dist/jobs/database/trigger-mcp-client-queue-options.d.ts +0 -8
- package/dist/jobs/database/trigger-mcp-client-queue-options.d.ts.map +0 -1
- package/dist/jobs/database/trigger-mcp-client-queue-options.js +0 -10
- package/dist/jobs/database/trigger-mcp-client-queue-options.js.map +0 -1
- package/dist/jobs/database/trigger-mcp-client-subscriber-database.service.d.ts +0 -25
- package/dist/jobs/database/trigger-mcp-client-subscriber-database.service.d.ts.map +0 -1
- package/dist/jobs/database/trigger-mcp-client-subscriber-database.service.js +0 -222
- package/dist/jobs/database/trigger-mcp-client-subscriber-database.service.js.map +0 -1
- package/dist/jobs/rabbitmq/trigger-mcp-client-publisher.service.d.ts +0 -11
- package/dist/jobs/rabbitmq/trigger-mcp-client-publisher.service.d.ts.map +0 -1
- package/dist/jobs/rabbitmq/trigger-mcp-client-publisher.service.js +0 -39
- package/dist/jobs/rabbitmq/trigger-mcp-client-publisher.service.js.map +0 -1
- package/dist/jobs/rabbitmq/trigger-mcp-client-queue-options.d.ts +0 -8
- package/dist/jobs/rabbitmq/trigger-mcp-client-queue-options.d.ts.map +0 -1
- package/dist/jobs/rabbitmq/trigger-mcp-client-queue-options.js +0 -10
- package/dist/jobs/rabbitmq/trigger-mcp-client-queue-options.js.map +0 -1
- package/dist/jobs/rabbitmq/trigger-mcp-client-subscriber.service.d.ts +0 -18
- package/dist/jobs/rabbitmq/trigger-mcp-client-subscriber.service.d.ts.map +0 -1
- package/dist/jobs/rabbitmq/trigger-mcp-client-subscriber.service.js +0 -103
- package/dist/jobs/rabbitmq/trigger-mcp-client-subscriber.service.js.map +0 -1
- package/dist/jobs/redis/trigger-mcp-client-publisher-redis.service.d.ts +0 -11
- package/dist/jobs/redis/trigger-mcp-client-publisher-redis.service.d.ts.map +0 -1
- package/dist/jobs/redis/trigger-mcp-client-publisher-redis.service.js +0 -39
- package/dist/jobs/redis/trigger-mcp-client-publisher-redis.service.js.map +0 -1
- package/dist/jobs/redis/trigger-mcp-client-queue-options-redis.d.ts +0 -8
- package/dist/jobs/redis/trigger-mcp-client-queue-options-redis.d.ts.map +0 -1
- package/dist/jobs/redis/trigger-mcp-client-queue-options-redis.js +0 -10
- package/dist/jobs/redis/trigger-mcp-client-queue-options-redis.js.map +0 -1
- package/dist/jobs/redis/trigger-mcp-client-subscriber-redis.service.d.ts +0 -18
- package/dist/jobs/redis/trigger-mcp-client-subscriber-redis.service.d.ts.map +0 -1
- package/dist/jobs/redis/trigger-mcp-client-subscriber-redis.service.js +0 -103
- package/dist/jobs/redis/trigger-mcp-client-subscriber-redis.service.js.map +0 -1
- package/dist/repository/ai-interaction.repository.d.ts +0 -12
- package/dist/repository/ai-interaction.repository.d.ts.map +0 -1
- package/dist/repository/ai-interaction.repository.js +0 -34
- package/dist/repository/ai-interaction.repository.js.map +0 -1
- package/dist/services/ai-interaction.service.d.ts +0 -23
- package/dist/services/ai-interaction.service.d.ts.map +0 -1
- package/dist/services/ai-interaction.service.js +0 -217
- package/dist/services/ai-interaction.service.js.map +0 -1
- package/dist/services/genai/ingest-metadata.service.d.ts +0 -38
- package/dist/services/genai/ingest-metadata.service.d.ts.map +0 -1
- package/dist/services/genai/ingest-metadata.service.js +0 -542
- package/dist/services/genai/ingest-metadata.service.js.map +0 -1
- package/dist/services/genai/mcp-handlers/mcp-handler-factory.service.d.ts +0 -9
- package/dist/services/genai/mcp-handlers/mcp-handler-factory.service.d.ts.map +0 -1
- package/dist/services/genai/mcp-handlers/mcp-handler-factory.service.js +0 -39
- package/dist/services/genai/mcp-handlers/mcp-handler-factory.service.js.map +0 -1
- package/dist/services/genai/r2r-helper.service.d.ts +0 -9
- package/dist/services/genai/r2r-helper.service.d.ts.map +0 -1
- package/dist/services/genai/r2r-helper.service.js +0 -40
- package/dist/services/genai/r2r-helper.service.js.map +0 -1
- package/dist-tests/api/authenticate.spec.js +0 -119
- package/dist-tests/api/authenticate.spec.js.map +0 -1
- package/dist-tests/api/crud-service.findOne.cityMaster.spec.js +0 -97
- package/dist-tests/api/crud-service.findOne.cityMaster.spec.js.map +0 -1
- package/dist-tests/api/ping.spec.js +0 -21
- package/dist-tests/api/ping.spec.js.map +0 -1
- package/dist-tests/helpers/auth.js +0 -41
- package/dist-tests/helpers/auth.js.map +0 -1
- package/dist-tests/helpers/env.js +0 -11
- package/dist-tests/helpers/env.js.map +0 -1
- package/docs/dashboards/AGENTIC_DASHBOARD_IMPLEMENTATION_PLAN.md +0 -438
- package/docs/dashboards/dashboard-curl-smoke-tests.txt +0 -146
- package/docs/dashboards/delete-legacy-dashboard-metadata.sql +0 -172
- package/docs/grouping-enhancements.md +0 -89
- package/docs/java-spring/README.md +0 -3
- package/docs/java-spring/solid-core-module-deep-dive-report.md +0 -1317
- package/docs/module-package-import-handoff.md +0 -691
- package/docs/seed-changes.md +0 -65
- package/docs/test-data-workflow.md +0 -200
- package/docs/type-declaration-import-issue.md +0 -24
- package/src/commands/ingest.command.ts +0 -36
- package/src/controllers/ai-interaction.controller.ts +0 -112
- package/src/dtos/create-ai-interaction.dto.ts +0 -89
- package/src/dtos/invoke-ai-prompt.dto.ts +0 -10
- package/src/dtos/update-ai-interaction.dto.ts +0 -93
- package/src/entities/ai-interaction.entity.ts +0 -71
- package/src/jobs/database/trigger-mcp-client-publisher-database.service.ts +0 -22
- package/src/jobs/database/trigger-mcp-client-queue-options.ts +0 -9
- package/src/jobs/database/trigger-mcp-client-subscriber-database.service.ts +0 -278
- package/src/jobs/rabbitmq/trigger-mcp-client-publisher.service.ts +0 -22
- package/src/jobs/rabbitmq/trigger-mcp-client-queue-options.ts +0 -9
- package/src/jobs/rabbitmq/trigger-mcp-client-subscriber.service.ts +0 -104
- package/src/jobs/redis/trigger-mcp-client-publisher-redis.service.ts +0 -23
- package/src/jobs/redis/trigger-mcp-client-queue-options-redis.ts +0 -9
- package/src/jobs/redis/trigger-mcp-client-subscriber-redis.service.ts +0 -98
- package/src/repository/ai-interaction.repository.ts +0 -17
- package/src/services/ai-interaction.service.ts +0 -239
- package/src/services/genai/ingest-metadata.service.ts +0 -798
- package/src/services/genai/mcp-handlers/mcp-handler-factory.service.ts +0 -33
- package/src/services/genai/r2r-helper.service.ts +0 -37
|
@@ -1,798 +0,0 @@
|
|
|
1
|
-
import { Injectable, Logger } from '@nestjs/common';
|
|
2
|
-
import * as crypto from 'crypto';
|
|
3
|
-
import * as fs from 'fs';
|
|
4
|
-
import * as path from 'path';
|
|
5
|
-
|
|
6
|
-
import { getDynamicModuleNames, getDynamicModuleNamesBasedOnMetadata } from 'src/helpers/module.helper';
|
|
7
|
-
import { CreateModuleMetadataDto } from 'src/dtos/create-module-metadata.dto';
|
|
8
|
-
import { R2RHelperService } from './r2r-helper.service';
|
|
9
|
-
import { r2rClient } from 'r2r-js';
|
|
10
|
-
import { CreateModelMetadataDto } from 'src/dtos/create-model-metadata.dto';
|
|
11
|
-
import { CreateFieldMetadataDto } from 'src/dtos/create-field-metadata.dto';
|
|
12
|
-
|
|
13
|
-
export type FieldIngestionInfo = {
|
|
14
|
-
fieldName: string;
|
|
15
|
-
fieldChunkId?: string;
|
|
16
|
-
fieldHash?: string;
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
export type ModelIngestionInfo = {
|
|
20
|
-
modelName: string;
|
|
21
|
-
modelChunkId?: string;
|
|
22
|
-
modelHash?: string;
|
|
23
|
-
fields: FieldIngestionInfo[];
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
export type ModuleRAGIngestionInfo = {
|
|
27
|
-
moduleName?: string;
|
|
28
|
-
collectionId?: string;
|
|
29
|
-
|
|
30
|
-
// Full json document is also uploaded so we track references...
|
|
31
|
-
documentId?: string;
|
|
32
|
-
documentHash?: string;
|
|
33
|
-
|
|
34
|
-
// module references
|
|
35
|
-
moduleChunkId?: string;
|
|
36
|
-
// track a hash of module metadata to skip unchanged
|
|
37
|
-
moduleHash?: string;
|
|
38
|
-
|
|
39
|
-
// model references...
|
|
40
|
-
models: ModelIngestionInfo[];
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
@Injectable()
|
|
44
|
-
export class IngestMetadataService {
|
|
45
|
-
private readonly logger = new Logger(IngestMetadataService.name);
|
|
46
|
-
private ragClient: r2rClient;
|
|
47
|
-
|
|
48
|
-
constructor(
|
|
49
|
-
private readonly r2rService: R2RHelperService,
|
|
50
|
-
) { }
|
|
51
|
-
|
|
52
|
-
// Stable stringify so hashes/ids don't flap
|
|
53
|
-
// private stableStringify(obj: any): string {
|
|
54
|
-
// return JSON.stringify(obj, Object.keys(obj).sort(), 2);
|
|
55
|
-
// }
|
|
56
|
-
// private sha256(input: string): string {
|
|
57
|
-
// return crypto.createHash('sha256').update(input).digest('hex');
|
|
58
|
-
// }
|
|
59
|
-
// private hashSchema(obj: any): string {
|
|
60
|
-
// return this.sha256(this.stableStringify(obj));
|
|
61
|
-
// }
|
|
62
|
-
private _sha256OfJson(obj: any): string {
|
|
63
|
-
const s = JSON.stringify(obj);
|
|
64
|
-
return crypto.createHash('sha256').update(s).digest('hex');
|
|
65
|
-
}
|
|
66
|
-
// // Small natural-language one-liners for relations
|
|
67
|
-
// private relationSig(model: any): string[] {
|
|
68
|
-
// const rels: string[] = [];
|
|
69
|
-
// for (const f of model.fields ?? []) {
|
|
70
|
-
// if (f.relation?.targetModel) {
|
|
71
|
-
// rels.push(`${model.singularName}.${f.name} -> ${f.relation.targetModel}(${f.relation.targetField ?? 'id'})`);
|
|
72
|
-
// }
|
|
73
|
-
// }
|
|
74
|
-
// return rels;
|
|
75
|
-
// }
|
|
76
|
-
|
|
77
|
-
private _oneLineBool(b?: boolean): 'yes' | 'no' {
|
|
78
|
-
return b ? 'yes' : 'no';
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
private _shortList(arr?: string[] | null, max = 10): string {
|
|
82
|
-
if (!Array.isArray(arr) || arr.length === 0) return 'none';
|
|
83
|
-
const a = arr.slice(0, max);
|
|
84
|
-
return `${a.join(', ')}${arr.length > max ? ', …' : ''}`;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
async ingest() {
|
|
88
|
-
// Create a new ragClient...
|
|
89
|
-
this.ragClient = await this.r2rService.getClient();
|
|
90
|
-
|
|
91
|
-
// const allModuleMetadataJson = [];
|
|
92
|
-
this.logger.debug(`getting dynamics modules`);
|
|
93
|
-
// const enabledModules = getDynamicModuleNames();
|
|
94
|
-
const enabledModules = getDynamicModuleNamesBasedOnMetadata();
|
|
95
|
-
this.logger.log(`ingesting metadata`);
|
|
96
|
-
|
|
97
|
-
for (let i = 0; i < enabledModules.length; i++) {
|
|
98
|
-
const enabledModule = enabledModules[i];
|
|
99
|
-
const fileName = `${enabledModule}-metadata.json`;
|
|
100
|
-
const enabledModuleSeedFile = `src/${enabledModule}/metadata/${fileName}`;
|
|
101
|
-
const fullPath = path.join(process.cwd(), enabledModuleSeedFile);
|
|
102
|
-
const overallMetadata: any = JSON.parse(fs.readFileSync(fullPath, 'utf-8').toString());
|
|
103
|
-
|
|
104
|
-
const moduleMetadata: CreateModuleMetadataDto = overallMetadata.moduleMetadata;
|
|
105
|
-
|
|
106
|
-
// Manage all the ingestion info file paths...
|
|
107
|
-
const enabledModulIngestionInfoFile = `src/${enabledModule}/metadata/genai/${enabledModule}-ingested-info.json`;
|
|
108
|
-
const enabledModulIngestionInfoFullPath = path.join(process.cwd(), enabledModulIngestionInfoFile);
|
|
109
|
-
const ingestionInfo: ModuleRAGIngestionInfo = fs.existsSync(enabledModulIngestionInfoFullPath) ? JSON.parse(fs.readFileSync(enabledModulIngestionInfoFullPath, 'utf-8').toString()) : {};
|
|
110
|
-
const enabledModulIngestionInfoDir = path.dirname(enabledModulIngestionInfoFullPath);
|
|
111
|
-
if (!fs.existsSync(enabledModulIngestionInfoDir)) {
|
|
112
|
-
fs.mkdirSync(enabledModulIngestionInfoDir, { recursive: true });
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
ingestionInfo.moduleName = enabledModule
|
|
116
|
-
|
|
117
|
-
// Process module metadata first.
|
|
118
|
-
this.logger.log(`[Start] Processing module metadata for ${moduleMetadata.name}`)
|
|
119
|
-
|
|
120
|
-
// Create or use an existing collection...
|
|
121
|
-
const collectionId = await this.resolveRagCollectionForModule(ingestionInfo, enabledModule)
|
|
122
|
-
ingestionInfo.collectionId = collectionId;
|
|
123
|
-
|
|
124
|
-
// Delete and re-insert a document representing the full json...
|
|
125
|
-
// await this.deleteInsertRagDocumentForModuleMetadataJsonFile(ingestionInfo, fullPath, fileName)
|
|
126
|
-
|
|
127
|
-
// Delete all metadata chunks.
|
|
128
|
-
// const collectionName = `${enabledModule}-rag-collection`;
|
|
129
|
-
// const deleteResult = await this.ragClient.documents.deleteByFilter({
|
|
130
|
-
// filters: {
|
|
131
|
-
// // AND semantics across fields:
|
|
132
|
-
// "$and": [
|
|
133
|
-
// { 'metadata.kind': { $eq: 'solidx-metadata' } },
|
|
134
|
-
// { 'metadata.collectionName': { $eq: collectionName } },
|
|
135
|
-
// { 'title': { $like: '%Ingested Chunks%' } },
|
|
136
|
-
// ]
|
|
137
|
-
// },
|
|
138
|
-
// });
|
|
139
|
-
// this.logger.log(`Deleted existing documents for collectionName: ${collectionName}. Got response:`, deleteResult);
|
|
140
|
-
|
|
141
|
-
// Delete and re-insert a chunk representing the module.
|
|
142
|
-
await this.deleteInsertRagChunkForModule(ingestionInfo, moduleMetadata);
|
|
143
|
-
|
|
144
|
-
// Delete and re-insert chunks representing each model.
|
|
145
|
-
for (const model of moduleMetadata.models) {
|
|
146
|
-
await this.deleteInsertRagChunkForModel(ingestionInfo, enabledModule, model);
|
|
147
|
-
|
|
148
|
-
// Disabling this for now...
|
|
149
|
-
// for (const field of model.fields) {
|
|
150
|
-
// await this.deleteInsertRagChunkForField(ingestionInfo, enabledModule, model.singularName, field);
|
|
151
|
-
// }
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
// TODO: Delete and re-insert chunks representing roles
|
|
155
|
-
|
|
156
|
-
// TODO: Delete and re-insert chunks representing menus
|
|
157
|
-
|
|
158
|
-
// TODO: Delete and re-insert chunks representing actions
|
|
159
|
-
|
|
160
|
-
// TODO: Delete and re-insert chunks representing list views
|
|
161
|
-
|
|
162
|
-
// TODO: Delete and re-insert chunks representing kanban views
|
|
163
|
-
|
|
164
|
-
// TODO: Delete and re-insert chunks representing form views
|
|
165
|
-
|
|
166
|
-
// TODO: Delete and re-insert chunks representing security rules
|
|
167
|
-
|
|
168
|
-
// TODO: Delete and re-insert chunks representing scheduled jobs
|
|
169
|
-
|
|
170
|
-
// Save ingestion info to disk...
|
|
171
|
-
fs.writeFileSync(enabledModulIngestionInfoFullPath, JSON.stringify({ ...ingestionInfo }, null, 2), 'utf8');
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
private async resolveRagCollectionForModule(ingestionInfo: ModuleRAGIngestionInfo, moduleName: string): Promise<string> {
|
|
176
|
-
this.logger.debug(`Resolving RAG collection for module: ${moduleName}`);
|
|
177
|
-
|
|
178
|
-
const collectionName = `${moduleName}-rag-collection`;
|
|
179
|
-
|
|
180
|
-
// delete and recreate
|
|
181
|
-
// if (alwaysRecreate === true) {
|
|
182
|
-
const existingCollection = await this.ragClient.collections.retrieveByName({
|
|
183
|
-
name: collectionName
|
|
184
|
-
});
|
|
185
|
-
|
|
186
|
-
if (existingCollection) {
|
|
187
|
-
try {
|
|
188
|
-
await this.ragClient.collections.delete({ id: existingCollection.results.id });
|
|
189
|
-
} catch (e) {
|
|
190
|
-
this.logger.warn(`[Warn] Failed deleteByFilter for collection': ${String(e)}`);
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
// }
|
|
194
|
-
|
|
195
|
-
// let existingCollection: CollectionResponse = null;
|
|
196
|
-
// if (ingestionInfo.collectionId) {
|
|
197
|
-
// // See if collection already exists...
|
|
198
|
-
// const r = await this.ragClient.collections.list({
|
|
199
|
-
// ids: [
|
|
200
|
-
// ingestionInfo.collectionId
|
|
201
|
-
// ]
|
|
202
|
-
// });
|
|
203
|
-
|
|
204
|
-
// if (r) {
|
|
205
|
-
// if (r.results.length === 1) {
|
|
206
|
-
// existingCollection = r.results[0];
|
|
207
|
-
// }
|
|
208
|
-
// if (r.results.length > 1) {
|
|
209
|
-
// // TODO: do something that will print a meaningful error on the console...
|
|
210
|
-
// }
|
|
211
|
-
// }
|
|
212
|
-
// }
|
|
213
|
-
|
|
214
|
-
// if (!existingCollection) {
|
|
215
|
-
const r = await this.ragClient.collections.create({
|
|
216
|
-
name: collectionName,
|
|
217
|
-
description: `Collection created to group all documents, chunks related to module: ${moduleName}`
|
|
218
|
-
});
|
|
219
|
-
|
|
220
|
-
// TODO: for some reason if we are unable to create a collection then fail with a visible error message in the console...
|
|
221
|
-
return r.results.id;
|
|
222
|
-
// }
|
|
223
|
-
// return existingCollection.id;
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
private async deleteInsertRagDocumentForModuleMetadataJsonFile(ingestionInfo: ModuleRAGIngestionInfo, fullPath: string, fileName: string): Promise<void> {
|
|
227
|
-
this.logger.debug(`Ingesting file: ${fullPath}`);
|
|
228
|
-
|
|
229
|
-
// 1) Compute hash of the entire JSON string (as-is)
|
|
230
|
-
const jsonStr = fs.readFileSync(fullPath, 'utf-8');
|
|
231
|
-
const contentHash = this._sha256OfJson(JSON.parse(jsonStr));
|
|
232
|
-
|
|
233
|
-
// 2) Short-circuit if unchanged and we still have a documentId
|
|
234
|
-
if (ingestionInfo.documentHash === contentHash && ingestionInfo.documentId) {
|
|
235
|
-
this.logger.log(`[Skip] Unchanged: ${fileName} (hash=${contentHash.slice(0, 8)}…)`);
|
|
236
|
-
return;
|
|
237
|
-
// return ingestionInfo.documentId;
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
// 3) Delete the previous doc if present
|
|
241
|
-
if (ingestionInfo.documentId) {
|
|
242
|
-
try {
|
|
243
|
-
await this.ragClient.documents.delete({ id: ingestionInfo.documentId });
|
|
244
|
-
} catch (e) {
|
|
245
|
-
this.logger.warn(
|
|
246
|
-
`[Warn] Failed deleting prior document ${ingestionInfo.documentId}: ${String(e)}`
|
|
247
|
-
);
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
// 4) Create a fresh document; attach the hash into metadata for traceability
|
|
252
|
-
const ingestResult = await this.ragClient.documents.create({
|
|
253
|
-
file: {
|
|
254
|
-
path: fullPath,
|
|
255
|
-
name: fileName
|
|
256
|
-
},
|
|
257
|
-
collectionIds: [ingestionInfo.collectionId],
|
|
258
|
-
metadata: {
|
|
259
|
-
contentHash,
|
|
260
|
-
fileName
|
|
261
|
-
},
|
|
262
|
-
});
|
|
263
|
-
// console.log("file ingest result:", JSON.stringify(ingestResult, null, 2));
|
|
264
|
-
|
|
265
|
-
const newId = ingestResult?.results?.documentId;
|
|
266
|
-
if (!newId) {
|
|
267
|
-
throw new Error(`R2R did not return a documentId for ${fileName}`);
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
// 5) Persist identifiers + hash on our side
|
|
271
|
-
ingestionInfo.documentId = newId;
|
|
272
|
-
ingestionInfo.documentHash = contentHash;
|
|
273
|
-
|
|
274
|
-
this.logger.log(`[OK] Ingested ${fileName} → id=${newId}, hash=${contentHash.slice(0, 8)}…`);
|
|
275
|
-
// return newId;
|
|
276
|
-
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
private async deleteInsertRagChunkForModule(ingestionInfo: ModuleRAGIngestionInfo, moduleMetadata: CreateModuleMetadataDto): Promise<void> {
|
|
280
|
-
const moduleName: string = moduleMetadata?.name;
|
|
281
|
-
|
|
282
|
-
// Hash the meaningful parts of the module to detect changes and skip re-ingest.
|
|
283
|
-
const schemaHash = this._sha256OfJson({
|
|
284
|
-
name: moduleMetadata?.name ?? null,
|
|
285
|
-
description: moduleMetadata?.description ?? null,
|
|
286
|
-
|
|
287
|
-
// Keep model names + brief shape so module-level hash changes when models change.
|
|
288
|
-
models: (moduleMetadata?.models ?? []).map((m: any) => ({
|
|
289
|
-
singularName: m?.singularName ?? null,
|
|
290
|
-
description: m?.description ?? null,
|
|
291
|
-
|
|
292
|
-
// Include field names to detect field-level changes at module granularity - maybe remove this later?
|
|
293
|
-
// fields: Array.isArray(m?.fields) ? m.fields.map((f: any) => f?.name ?? null) : [],
|
|
294
|
-
})),
|
|
295
|
-
});
|
|
296
|
-
|
|
297
|
-
// Skip unchanged module
|
|
298
|
-
if (ingestionInfo.moduleHash === schemaHash && ingestionInfo.moduleChunkId) {
|
|
299
|
-
this.logger.log(`[Skip] Module unchanged: ${moduleName}`);
|
|
300
|
-
return;
|
|
301
|
-
// return ingestionInfo.moduleChunkId;
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
const models: any[] = moduleMetadata?.models ?? [];
|
|
305
|
-
const modelLines = models.map((m) => {
|
|
306
|
-
const name = m?.singularName;
|
|
307
|
-
const desc = m?.description ? `: ${m.description}` : '';
|
|
308
|
-
return `- ${name}${desc}`;
|
|
309
|
-
});
|
|
310
|
-
|
|
311
|
-
const text = `SolidX Module: ${moduleName}
|
|
312
|
-
Purpose: ${moduleMetadata?.description ?? 'N/A'}
|
|
313
|
-
|
|
314
|
-
Models (${models.length}):
|
|
315
|
-
${modelLines.join('\n')}
|
|
316
|
-
|
|
317
|
-
Usage: Use this chunk to choose the correct model/field chunks for code generation or metadata edits.`;
|
|
318
|
-
|
|
319
|
-
// metadata has to be concise and queryable
|
|
320
|
-
const metadata = {
|
|
321
|
-
collectionName: `${moduleName}-rag-collection`,
|
|
322
|
-
kind: 'solidx-metadata',
|
|
323
|
-
type: 'module',
|
|
324
|
-
moduleName,
|
|
325
|
-
modelCount: models.length,
|
|
326
|
-
schemaHash,
|
|
327
|
-
models: models.map((m) => m?.singularName).filter(Boolean),
|
|
328
|
-
};
|
|
329
|
-
|
|
330
|
-
// Delete previous chunk if we have one
|
|
331
|
-
// if (ingestionInfo.moduleChunkId) {
|
|
332
|
-
// try {
|
|
333
|
-
// await this.ragClient.documents.delete({ id: ingestionInfo.moduleChunkId });
|
|
334
|
-
// } catch (e) {
|
|
335
|
-
// this.logger.warn(`[Warn] Failed deleting old module chunk (${ingestionInfo.moduleChunkId}): ${String(e)}`);
|
|
336
|
-
// }
|
|
337
|
-
// }
|
|
338
|
-
|
|
339
|
-
// We changed the approach to delete and re-create using metadata.
|
|
340
|
-
// delete any existing module records by metadata (idempotent)
|
|
341
|
-
try {
|
|
342
|
-
const deleteResult = await this.ragClient.documents.deleteByFilter({
|
|
343
|
-
filters: {
|
|
344
|
-
// AND semantics across fields:
|
|
345
|
-
"$and": [
|
|
346
|
-
{ 'metadata.kind': { $eq: 'solidx-metadata' } },
|
|
347
|
-
{ 'metadata.type': { $eq: 'module' } },
|
|
348
|
-
{ 'metadata.moduleName': { $eq: moduleName } },
|
|
349
|
-
// (optional but nice to constrain tightly if you always set it)
|
|
350
|
-
{ 'metadata.collectionName': { $eq: `${moduleName}-rag-collection` } },
|
|
351
|
-
]
|
|
352
|
-
},
|
|
353
|
-
});
|
|
354
|
-
|
|
355
|
-
this.logger.log(`Deleted existing module document for moduleName: ${moduleName}. Got response:`, deleteResult);
|
|
356
|
-
|
|
357
|
-
} catch (e) {
|
|
358
|
-
this.logger.warn(`[Warn] Failed deleteByFilter for module '${moduleName}': ${String(e)}`);
|
|
359
|
-
// Non-fatal: we can still proceed to create; caller’s auth will limit scope anyway
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
const r = await this.ragClient.documents.create({
|
|
363
|
-
chunks: [text],
|
|
364
|
-
// raw_text: text,
|
|
365
|
-
metadata: metadata,
|
|
366
|
-
collectionIds: [ingestionInfo.collectionId],
|
|
367
|
-
});
|
|
368
|
-
|
|
369
|
-
const newId = r?.results?.documentId;
|
|
370
|
-
if (!newId) {
|
|
371
|
-
throw new Error(`R2R did not return a documentId while creating module chunk for module name ${moduleName}`);
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
// Update ingestion info for persistence by the caller
|
|
375
|
-
ingestionInfo.moduleChunkId = r.results?.documentId;
|
|
376
|
-
ingestionInfo.moduleHash = schemaHash;
|
|
377
|
-
|
|
378
|
-
this.logger.log(`[OK] Ingested module ${moduleName} → id=${newId}, hash=${schemaHash.slice(0, 8)}…`);
|
|
379
|
-
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
private async deleteInsertRagChunkForModel(ingestionInfo: ModuleRAGIngestionInfo, moduleName: string, model: CreateModelMetadataDto): Promise<void> {
|
|
383
|
-
const modelName: string = model?.singularName;
|
|
384
|
-
|
|
385
|
-
// 1) Hash full JSON (as-is) to detect changes and skip re-ingest
|
|
386
|
-
const schemaHash = this._sha256OfJson(model);
|
|
387
|
-
|
|
388
|
-
// Ensure ingestionInfo.models[] has an entry for this model
|
|
389
|
-
const modelsArr = ingestionInfo.models ?? (ingestionInfo.models = []);
|
|
390
|
-
let modelEntry = modelsArr.find(m => m.modelName === modelName);
|
|
391
|
-
if (!modelEntry) {
|
|
392
|
-
modelEntry = { modelName, fields: [] };
|
|
393
|
-
modelsArr.push(modelEntry);
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
// 2) Short-circuit if unchanged
|
|
397
|
-
if (modelEntry.modelHash === schemaHash && modelEntry.modelChunkId) {
|
|
398
|
-
this.logger.log(`[Skip] Model unchanged: ${moduleName}.${modelName}`);
|
|
399
|
-
return;
|
|
400
|
-
// return modelEntry.modelChunkId;
|
|
401
|
-
}
|
|
402
|
-
|
|
403
|
-
// 3) Build retrieval-friendly text (concise)
|
|
404
|
-
const fields: CreateFieldMetadataDto[] = Array.isArray(model?.fields) ? model.fields : [];
|
|
405
|
-
const userkey = fields.find((f: CreateFieldMetadataDto) => f?.isUserKey)?.name ?? 'id';
|
|
406
|
-
const uniques = fields.filter((f: CreateFieldMetadataDto) => f?.unique).map((f: any) => f.name);
|
|
407
|
-
const required = fields.filter((f: CreateFieldMetadataDto) => f?.required).map((f: any) => f.name);
|
|
408
|
-
const rels = fields
|
|
409
|
-
.filter((f: CreateFieldMetadataDto) => f.type === 'relation')
|
|
410
|
-
.map((f: CreateFieldMetadataDto) => `${modelName}.${f.name} -> ${f.relationCoModelSingularName}.${f.relationCoModelColumnName ?? 'id'}`);
|
|
411
|
-
|
|
412
|
-
const fieldSummaryLines = fields.slice(0, 30).map((f: CreateFieldMetadataDto) => {
|
|
413
|
-
const bits = [
|
|
414
|
-
`${f.name}:${f.type}`,
|
|
415
|
-
f.required ? 'req' : '',
|
|
416
|
-
f.unique ? 'unique' : '',
|
|
417
|
-
f.isUserKey ? 'userkey' : '',
|
|
418
|
-
f.relationCoModelSingularName ? `rel->${f.relationCoModelSingularName}` : '',
|
|
419
|
-
].filter(Boolean).join('|');
|
|
420
|
-
return `- ${bits}`;
|
|
421
|
-
});
|
|
422
|
-
|
|
423
|
-
const text =
|
|
424
|
-
`SolidX Model: ${modelName}
|
|
425
|
-
Module: ${moduleName}
|
|
426
|
-
Purpose: ${model?.description ?? 'N/A'}
|
|
427
|
-
|
|
428
|
-
Signature:
|
|
429
|
-
- Primary: ${userkey}
|
|
430
|
-
- Unique: ${uniques.length ? uniques.join(', ') : 'none'}
|
|
431
|
-
- Required (${required.length}): ${required.slice(0, 12).join(', ')}${required.length > 12 ? '…' : ''}
|
|
432
|
-
|
|
433
|
-
Relations (${rels.length}):
|
|
434
|
-
${rels.length ? `- ${rels.join('\n- ')}` : 'None'}
|
|
435
|
-
|
|
436
|
-
Fields (${fields.length}) [name:type|flags]:
|
|
437
|
-
${fieldSummaryLines.join('\n')}
|
|
438
|
-
|
|
439
|
-
Usage: Use this chunk to generate DTOs, subscribers, custom service methods, and CRUD handlers for ${modelName}.
|
|
440
|
-
|
|
441
|
-
Full model metadata json:
|
|
442
|
-
${JSON.stringify(model)}
|
|
443
|
-
|
|
444
|
-
`;
|
|
445
|
-
|
|
446
|
-
// 4) Metadata (concise & queryable)
|
|
447
|
-
const metadata = {
|
|
448
|
-
collectionName: `${moduleName}-rag-collection`,
|
|
449
|
-
kind: 'solidx-metadata',
|
|
450
|
-
type: 'model',
|
|
451
|
-
moduleName,
|
|
452
|
-
modelName,
|
|
453
|
-
fieldCount: fields.length,
|
|
454
|
-
requiredCount: required.length,
|
|
455
|
-
relationCount: rels.length,
|
|
456
|
-
userkey: userkey,
|
|
457
|
-
uniqueFields: uniques,
|
|
458
|
-
hasTimestamps: !!fields.find((f: CreateFieldMetadataDto) => ['time', 'date', 'datetime'].includes(f.type)),
|
|
459
|
-
schemaHash,
|
|
460
|
-
};
|
|
461
|
-
|
|
462
|
-
// 5) Delete previous chunk if present
|
|
463
|
-
// if (modelEntry.modelChunkId) {
|
|
464
|
-
// try {
|
|
465
|
-
// await this.ragClient.documents.delete({ id: modelEntry.modelChunkId });
|
|
466
|
-
// } catch (e) {
|
|
467
|
-
// this.logger.warn(`[Warn] Failed deleting old model chunk (${modelEntry.modelChunkId}): ${String(e)}`);
|
|
468
|
-
// }
|
|
469
|
-
// }
|
|
470
|
-
|
|
471
|
-
// We changed the approach to delete and re-create using metadata.
|
|
472
|
-
// delete any existing module records by metadata (idempotent)
|
|
473
|
-
try {
|
|
474
|
-
const deleteResult = await this.ragClient.documents.deleteByFilter({
|
|
475
|
-
filters: {
|
|
476
|
-
// AND semantics across fields:
|
|
477
|
-
"$and": [
|
|
478
|
-
{ 'metadata.kind': { $eq: 'solidx-metadata' } },
|
|
479
|
-
{ 'metadata.type': { $eq: 'model' } },
|
|
480
|
-
{ 'metadata.moduleName': { $eq: moduleName } },
|
|
481
|
-
{ 'metadata.modelName': { $eq: modelName } },
|
|
482
|
-
// (optional but nice to constrain tightly if you always set it)
|
|
483
|
-
{ 'metadata.collectionName': { $eq: `${moduleName}-rag-collection` } },
|
|
484
|
-
]
|
|
485
|
-
},
|
|
486
|
-
});
|
|
487
|
-
|
|
488
|
-
this.logger.log(`Deleted existing model document for modelName: ${modelName}. Got response:`, deleteResult);
|
|
489
|
-
|
|
490
|
-
} catch (e) {
|
|
491
|
-
this.logger.warn(`[Warn] Failed deleteByFilter for module '${moduleName}': ${String(e)}`);
|
|
492
|
-
// Non-fatal: we can still proceed to create; caller’s auth will limit scope anyway
|
|
493
|
-
}
|
|
494
|
-
|
|
495
|
-
// 6) Create new document (R2R auto-generates the ID)
|
|
496
|
-
const r = await this.ragClient.documents.create({
|
|
497
|
-
chunks: [text],
|
|
498
|
-
metadata,
|
|
499
|
-
collectionIds: [ingestionInfo.collectionId],
|
|
500
|
-
});
|
|
501
|
-
|
|
502
|
-
const newId = r?.results?.documentId;
|
|
503
|
-
if (!newId) {
|
|
504
|
-
throw new Error(`R2R did not return a documentId while creating model chunk for ${moduleName}.${modelName}`);
|
|
505
|
-
}
|
|
506
|
-
|
|
507
|
-
// 7) Update ingestionInfo for persistence
|
|
508
|
-
modelEntry.modelChunkId = newId;
|
|
509
|
-
modelEntry.modelHash = schemaHash;
|
|
510
|
-
|
|
511
|
-
this.logger.log(`[OK] Ingested model ${moduleName}.${modelName} → id=${newId}, hash=${schemaHash.slice(0, 8)}…`);
|
|
512
|
-
// return newId;
|
|
513
|
-
}
|
|
514
|
-
|
|
515
|
-
private _buildFieldTextAndMetadata(moduleName: string, modelName: string, f: CreateFieldMetadataDto) {
|
|
516
|
-
// Identity
|
|
517
|
-
const name = f?.name;
|
|
518
|
-
const displayName = f?.displayName ?? name;
|
|
519
|
-
const description = f?.description ?? 'N/A';
|
|
520
|
-
|
|
521
|
-
// Types
|
|
522
|
-
const type = f?.type;
|
|
523
|
-
const ormType = f?.ormType ?? null;
|
|
524
|
-
|
|
525
|
-
// Constraints / validation
|
|
526
|
-
const required = !!f?.required;
|
|
527
|
-
const unique = !!f?.unique;
|
|
528
|
-
const index = !!f?.index;
|
|
529
|
-
const length = f?.length ?? null;
|
|
530
|
-
const min = f?.min ?? null;
|
|
531
|
-
const max = f?.max ?? null;
|
|
532
|
-
const defaultValue = f?.defaultValue ?? null;
|
|
533
|
-
const regex = f?.regexPattern ?? null;
|
|
534
|
-
const regexErr = f?.regexPatternNotMatchingErrorMsg ?? null;
|
|
535
|
-
|
|
536
|
-
// Relation
|
|
537
|
-
const relationType = f?.relationType ?? null; // e.g., many-to-one, many-to-many, one-to-many
|
|
538
|
-
const relModule = f?.relationModelModuleName ?? null;
|
|
539
|
-
const relModel = f?.relationCoModelSingularName ?? null;
|
|
540
|
-
const relField = f?.relationCoModelFieldName ?? 'id';
|
|
541
|
-
// const relOwner = f?.isRelationManyToManyOwner ?? null;
|
|
542
|
-
// const relJoinTable = f?.relationJoinTableName ?? null;
|
|
543
|
-
// const relCreateInverse = !!f?.relationCreateInverse;
|
|
544
|
-
const relCascade = f?.relationCascade ?? null;
|
|
545
|
-
const relFixedFilter = f?.relationFieldFixedFilter ?? null;
|
|
546
|
-
|
|
547
|
-
// Selection (dropdowns)
|
|
548
|
-
const selectionDynProvider = f?.selectionDynamicProvider ?? null;
|
|
549
|
-
const selectionDynCtxt = f?.selectionDynamicProviderCtxt ?? null;
|
|
550
|
-
const selectionStatic = Array.isArray(f?.selectionStaticValues) ? f.selectionStaticValues : null;
|
|
551
|
-
const selectionValueType = f?.selectionValueType ?? null;
|
|
552
|
-
const isMultiSelect = !!f?.isMultiSelect;
|
|
553
|
-
|
|
554
|
-
// Media (uploads)
|
|
555
|
-
const mediaTypes = Array.isArray(f?.mediaTypes) ? f.mediaTypes : null;
|
|
556
|
-
const mediaMaxSizeKb = f?.mediaMaxSizeKb ?? null;
|
|
557
|
-
const mediaStorageProvider = f?.mediaStorageProviderUserKey ?? null; // likely object/id in your JSON
|
|
558
|
-
|
|
559
|
-
// Computed fields
|
|
560
|
-
const computedProvider = f?.computedFieldValueProvider ?? null;
|
|
561
|
-
const computedProviderCtxt = f?.computedFieldValueProviderCtxt ?? null;
|
|
562
|
-
const computedValueType = f?.computedFieldValueType ?? null;
|
|
563
|
-
const computedTriggerCfg = f?.computedFieldTriggerConfig ?? null;
|
|
564
|
-
|
|
565
|
-
// Security / privacy / audit
|
|
566
|
-
// const encrypt = !!f?.encrypt;
|
|
567
|
-
// const encryptionType = f?.encryptionType ?? null;
|
|
568
|
-
// const decryptWhen = f?.decryptWhen ?? null;
|
|
569
|
-
const isPrivate = !!f?.private;
|
|
570
|
-
const enableAuditTracking = !!f?.enableAuditTracking;
|
|
571
|
-
|
|
572
|
-
// Keys / system flags / mapping
|
|
573
|
-
const isUserKey = !!f?.isUserKey;
|
|
574
|
-
const isSystem = !!f?.isSystem;
|
|
575
|
-
const isMarkedForRemoval = !!f?.isMarkedForRemoval;
|
|
576
|
-
const columnName = f?.columnName ?? null;
|
|
577
|
-
const relCoModelColumn = f?.relationCoModelColumnName ?? null;
|
|
578
|
-
const uuid = f?.uuid ?? null;
|
|
579
|
-
|
|
580
|
-
const relationSummary = (() => {
|
|
581
|
-
if (!relationType || !relModel) return 'none';
|
|
582
|
-
const parts = [
|
|
583
|
-
`type=${relationType}`,
|
|
584
|
-
relModule ? `module=${relModule}` : null,
|
|
585
|
-
`model=${relModel}`,
|
|
586
|
-
relField ? `field=${relField}` : null,
|
|
587
|
-
// relOwner !== null ? `m2mOwner=${relOwner}` : null,
|
|
588
|
-
// relCreateInverse ? 'createInverse=yes' : null,
|
|
589
|
-
relCascade ? `cascade=${relCascade}` : null,
|
|
590
|
-
// relJoinTable ? `joinTable=${relJoinTable}` : null,
|
|
591
|
-
relFixedFilter ? `fixedFilter=${relFixedFilter}` : null,
|
|
592
|
-
].filter(Boolean);
|
|
593
|
-
return parts.join(', ');
|
|
594
|
-
})();
|
|
595
|
-
|
|
596
|
-
const selectionSummary = (() => {
|
|
597
|
-
const parts: string[] = [];
|
|
598
|
-
if (selectionDynProvider) parts.push(`dynamicProvider=${selectionDynProvider}`);
|
|
599
|
-
if (selectionDynCtxt) parts.push(`dynamicCtxt=${selectionDynCtxt}`);
|
|
600
|
-
if (selectionStatic?.length) parts.push(`static=[${this._shortList(selectionStatic, 12)}]`);
|
|
601
|
-
if (selectionValueType) parts.push(`valueType=${selectionValueType}`);
|
|
602
|
-
parts.push(`multiSelect=${this._oneLineBool(isMultiSelect)}`);
|
|
603
|
-
return parts.length ? parts.join(', ') : 'none';
|
|
604
|
-
})();
|
|
605
|
-
|
|
606
|
-
const mediaSummary = (() => {
|
|
607
|
-
const parts: string[] = [];
|
|
608
|
-
if (mediaTypes?.length) parts.push(`types=[${this._shortList(mediaTypes, 12)}]`);
|
|
609
|
-
if (mediaMaxSizeKb) parts.push(`maxSizeKb=${mediaMaxSizeKb}`);
|
|
610
|
-
if (mediaStorageProvider) parts.push(`storageProvider=${typeof mediaStorageProvider === 'string' ? mediaStorageProvider : 'set'}`);
|
|
611
|
-
return parts.length ? parts.join(', ') : 'none';
|
|
612
|
-
})();
|
|
613
|
-
|
|
614
|
-
const computedSummary = (() => {
|
|
615
|
-
const parts: string[] = [];
|
|
616
|
-
if (computedProvider) parts.push(`provider=${computedProvider}`);
|
|
617
|
-
if (computedProviderCtxt) parts.push(`providerCtxt=${computedProviderCtxt}`);
|
|
618
|
-
if (computedValueType) parts.push(`valueType=${computedValueType}`);
|
|
619
|
-
if (computedTriggerCfg?.length) parts.push(`triggers=${computedTriggerCfg.length}`);
|
|
620
|
-
return parts.length ? parts.join(', ') : 'none';
|
|
621
|
-
})();
|
|
622
|
-
|
|
623
|
-
const securitySummary = [
|
|
624
|
-
// `encrypt=${this.oneLineBool(encrypt)}`,
|
|
625
|
-
// encryptionType ? `encType=${encryptionType}` : null,
|
|
626
|
-
// decryptWhen ? `decryptWhen=${decryptWhen}` : null,
|
|
627
|
-
`private=${this._oneLineBool(isPrivate)}`,
|
|
628
|
-
`auditTracking=${this._oneLineBool(enableAuditTracking)}`
|
|
629
|
-
].filter(Boolean).join(', ');
|
|
630
|
-
|
|
631
|
-
const constraintSummary = [
|
|
632
|
-
`required=${this._oneLineBool(required)}`,
|
|
633
|
-
`unique=${this._oneLineBool(unique)}`,
|
|
634
|
-
`index=${this._oneLineBool(index)}`,
|
|
635
|
-
length !== null ? `length=${length}` : null,
|
|
636
|
-
min !== null ? `min=${min}` : null,
|
|
637
|
-
max !== null ? `max=${max}` : null,
|
|
638
|
-
defaultValue !== null ? `default=${defaultValue}` : null,
|
|
639
|
-
regex ? `regex=${regex}${regexErr ? ` (${regexErr})` : ''}` : null
|
|
640
|
-
].filter(Boolean).join(', ');
|
|
641
|
-
|
|
642
|
-
const mappingSummary = [
|
|
643
|
-
columnName ? `column=${columnName}` : null,
|
|
644
|
-
relCoModelColumn ? `relColumn=${relCoModelColumn}` : null,
|
|
645
|
-
uuid ? `uuid=${uuid}` : null,
|
|
646
|
-
`userKey=${this._oneLineBool(isUserKey)}`,
|
|
647
|
-
`system=${this._oneLineBool(isSystem)}`,
|
|
648
|
-
`markedForRemoval=${this._oneLineBool(isMarkedForRemoval)}`
|
|
649
|
-
].filter(Boolean).join(', ');
|
|
650
|
-
|
|
651
|
-
const text = [
|
|
652
|
-
`SolidX Field: ${name} (${displayName})`,
|
|
653
|
-
`Model: ${modelName}`,
|
|
654
|
-
`Module: ${moduleName}`,
|
|
655
|
-
``,
|
|
656
|
-
`Type: ${type}${ormType ? ` (orm=${ormType})` : ''}`,
|
|
657
|
-
`Description: ${description}`,
|
|
658
|
-
``,
|
|
659
|
-
`Constraints: ${constraintSummary || 'none'}`,
|
|
660
|
-
`Relation: ${relationSummary}`,
|
|
661
|
-
`Selection: ${selectionSummary}`,
|
|
662
|
-
`Media: ${mediaSummary}`,
|
|
663
|
-
`Computed: ${computedSummary}`,
|
|
664
|
-
`Security/Privacy/Audit: ${securitySummary}`,
|
|
665
|
-
`Mapping/Flags: ${mappingSummary || 'none'}`,
|
|
666
|
-
``,
|
|
667
|
-
`Usage: Use this chunk to generate exact field contracts (DTO, form control, DB column), `,
|
|
668
|
-
`validation rules, relation wiring, and UI widgets (selection/media/computed).`,
|
|
669
|
-
].join('\n');
|
|
670
|
-
|
|
671
|
-
const metadata = {
|
|
672
|
-
kind: 'solidx-metadata',
|
|
673
|
-
type: 'field',
|
|
674
|
-
moduleName,
|
|
675
|
-
modelName,
|
|
676
|
-
fieldName: name,
|
|
677
|
-
displayName,
|
|
678
|
-
description,
|
|
679
|
-
dataType: type,
|
|
680
|
-
ormType,
|
|
681
|
-
required,
|
|
682
|
-
unique,
|
|
683
|
-
index,
|
|
684
|
-
defaultValue,
|
|
685
|
-
length,
|
|
686
|
-
min,
|
|
687
|
-
max,
|
|
688
|
-
regexPattern: regex,
|
|
689
|
-
regexPatternNotMatchingErrorMsg: regexErr,
|
|
690
|
-
|
|
691
|
-
// relation
|
|
692
|
-
relationType,
|
|
693
|
-
relationModelModuleName: relModule,
|
|
694
|
-
relationCoModelSingularName: relModel,
|
|
695
|
-
relationCoModelFieldName: relField,
|
|
696
|
-
// isRelationManyToManyOwner: relOwner,
|
|
697
|
-
// relationJoinTableName: relJoinTable,
|
|
698
|
-
// relationCreateInverse: relCreateInverse,
|
|
699
|
-
relationCascade: relCascade,
|
|
700
|
-
relationFieldFixedFilter: relFixedFilter,
|
|
701
|
-
|
|
702
|
-
// selection
|
|
703
|
-
selectionDynProvider,
|
|
704
|
-
selectionDynCtxt,
|
|
705
|
-
selectionStaticValues: selectionStatic,
|
|
706
|
-
selectionValueType,
|
|
707
|
-
isMultiSelect,
|
|
708
|
-
|
|
709
|
-
// media
|
|
710
|
-
mediaTypes,
|
|
711
|
-
mediaMaxSizeKb,
|
|
712
|
-
mediaStorageProvider: mediaStorageProvider ? (typeof mediaStorageProvider === 'string' ? mediaStorageProvider : 'set') : null,
|
|
713
|
-
|
|
714
|
-
// computed
|
|
715
|
-
computedFieldValueProvider: computedProvider,
|
|
716
|
-
computedFieldValueProviderCtxt: computedProviderCtxt,
|
|
717
|
-
computedFieldValueType: computedValueType,
|
|
718
|
-
computedFieldTriggerConfigCount: Array.isArray(computedTriggerCfg) ? computedTriggerCfg.length : 0,
|
|
719
|
-
|
|
720
|
-
// security/privacy/audit
|
|
721
|
-
// encrypt,
|
|
722
|
-
// encryptionType,
|
|
723
|
-
// decryptWhen,
|
|
724
|
-
private: isPrivate,
|
|
725
|
-
enableAuditTracking,
|
|
726
|
-
|
|
727
|
-
// mapping/flags
|
|
728
|
-
columnName,
|
|
729
|
-
relationCoModelColumnName: relCoModelColumn,
|
|
730
|
-
isUserKey,
|
|
731
|
-
isSystem,
|
|
732
|
-
isMarkedForRemoval,
|
|
733
|
-
};
|
|
734
|
-
|
|
735
|
-
return { text, metadata };
|
|
736
|
-
}
|
|
737
|
-
|
|
738
|
-
private async deleteInsertRagChunkForField(ingestionInfo: ModuleRAGIngestionInfo, moduleName: string, modelName: string, field: CreateFieldMetadataDto,): Promise<string> {
|
|
739
|
-
const fieldName: string = field?.name ?? 'unknown_field';
|
|
740
|
-
|
|
741
|
-
// 1) Full JSON hash (as-is)
|
|
742
|
-
const schemaHash = this._sha256OfJson(field);
|
|
743
|
-
|
|
744
|
-
// 2) Ensure ingestionInfo entry for the model & field
|
|
745
|
-
const modelsArr = ingestionInfo.models ?? (ingestionInfo.models = []);
|
|
746
|
-
let modelEntry = modelsArr.find(m => m.modelName === modelName);
|
|
747
|
-
if (!modelEntry) {
|
|
748
|
-
modelEntry = { modelName, fields: [] };
|
|
749
|
-
modelsArr.push(modelEntry);
|
|
750
|
-
}
|
|
751
|
-
const fieldsArr = modelEntry.fields ?? (modelEntry.fields = []);
|
|
752
|
-
let fieldEntry = fieldsArr.find(f => f.fieldName === fieldName);
|
|
753
|
-
if (!fieldEntry) {
|
|
754
|
-
fieldEntry = { fieldName };
|
|
755
|
-
fieldsArr.push(fieldEntry);
|
|
756
|
-
}
|
|
757
|
-
|
|
758
|
-
// 3) Skip if unchanged
|
|
759
|
-
if (fieldEntry.fieldHash === schemaHash && fieldEntry.fieldChunkId) {
|
|
760
|
-
this.logger.log(`[Skip] Field unchanged: ${moduleName}.${modelName}.${fieldName}`);
|
|
761
|
-
return fieldEntry.fieldChunkId;
|
|
762
|
-
}
|
|
763
|
-
|
|
764
|
-
// 4) Build text + metadata tailored to FieldMetadata
|
|
765
|
-
const { text, metadata } = this._buildFieldTextAndMetadata(moduleName, modelName, field);
|
|
766
|
-
|
|
767
|
-
// also keep the hash in metadata for audit/debug
|
|
768
|
-
(metadata as any).schemaHash = schemaHash;
|
|
769
|
-
|
|
770
|
-
// 5) Delete previous chunk if present
|
|
771
|
-
if (fieldEntry.fieldChunkId) {
|
|
772
|
-
try {
|
|
773
|
-
await this.ragClient.documents.delete({ id: fieldEntry.fieldChunkId });
|
|
774
|
-
} catch (e) {
|
|
775
|
-
this.logger.warn(`[Warn] Failed deleting old field chunk (${fieldEntry.fieldChunkId}): ${String(e)}`);
|
|
776
|
-
}
|
|
777
|
-
}
|
|
778
|
-
|
|
779
|
-
// 6) Create new document (R2R auto-generates the ID)
|
|
780
|
-
const r = await this.ragClient.documents.create({
|
|
781
|
-
raw_text: text,
|
|
782
|
-
metadata,
|
|
783
|
-
collectionIds: [ingestionInfo.collectionId],
|
|
784
|
-
});
|
|
785
|
-
|
|
786
|
-
const newId = r?.results?.documentId;
|
|
787
|
-
if (!newId) {
|
|
788
|
-
throw new Error(`R2R did not return a documentId while creating field chunk for ${moduleName}.${modelName}.${fieldName}`);
|
|
789
|
-
}
|
|
790
|
-
|
|
791
|
-
// 7) Update ingestion info
|
|
792
|
-
fieldEntry.fieldChunkId = newId;
|
|
793
|
-
fieldEntry.fieldHash = schemaHash;
|
|
794
|
-
|
|
795
|
-
this.logger.log(`[OK] Ingested field ${moduleName}.${modelName}.${fieldName} → id=${newId}, hash=${schemaHash.slice(0, 8)}…`);
|
|
796
|
-
return newId;
|
|
797
|
-
}
|
|
798
|
-
}
|