attio-mcp 1.3.6 → 1.4.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/CHANGELOG.md +236 -2
- package/README.md +106 -266
- package/dist/api/attio-client.d.ts +13 -3
- package/dist/api/attio-client.d.ts.map +1 -1
- package/dist/api/attio-client.js +37 -7
- package/dist/api/attio-client.js.map +1 -1
- package/dist/api/attribute-types.d.ts.map +1 -1
- package/dist/api/attribute-types.js +42 -20
- package/dist/api/attribute-types.js.map +1 -1
- package/dist/api/client-context.d.ts.map +1 -1
- package/dist/api/client-context.js +28 -42
- package/dist/api/client-context.js.map +1 -1
- package/dist/cli/commands/generate-skill.d.ts +28 -0
- package/dist/cli/commands/generate-skill.d.ts.map +1 -0
- package/dist/cli/commands/generate-skill.js +101 -0
- package/dist/cli/commands/generate-skill.js.map +1 -0
- package/dist/cli/discover.js +65 -0
- package/dist/cli/discover.js.map +1 -1
- package/dist/config/deal-defaults.d.ts +2 -2
- package/dist/config/deal-defaults.d.ts.map +1 -1
- package/dist/config/deal-defaults.js +15 -6
- package/dist/config/deal-defaults.js.map +1 -1
- package/dist/config/tool-aliases.d.ts +12 -0
- package/dist/config/tool-aliases.d.ts.map +1 -1
- package/dist/config/tool-aliases.js +213 -69
- package/dist/config/tool-aliases.js.map +1 -1
- package/dist/constants/tool-names.d.ts +84 -0
- package/dist/constants/tool-names.d.ts.map +1 -0
- package/dist/constants/tool-names.js +81 -0
- package/dist/constants/tool-names.js.map +1 -0
- package/dist/constants/universal.constants.d.ts +24 -0
- package/dist/constants/universal.constants.d.ts.map +1 -1
- package/dist/constants/universal.constants.js +81 -9
- package/dist/constants/universal.constants.js.map +1 -1
- package/dist/handlers/tool-configs/universal/batch-search.js +4 -4
- package/dist/handlers/tool-configs/universal/core/crud-error-handlers.d.ts +26 -4
- package/dist/handlers/tool-configs/universal/core/crud-error-handlers.d.ts.map +1 -1
- package/dist/handlers/tool-configs/universal/core/crud-error-handlers.js +181 -21
- package/dist/handlers/tool-configs/universal/core/crud-error-handlers.js.map +1 -1
- package/dist/handlers/tool-configs/universal/core/crud-operations.js +13 -13
- package/dist/handlers/tool-configs/universal/core/crud-operations.js.map +1 -1
- package/dist/handlers/tool-configs/universal/core/detailed-info-operations.js +3 -3
- package/dist/handlers/tool-configs/universal/core/detailed-info-operations.js.map +1 -1
- package/dist/handlers/tool-configs/universal/core/error-enhancers/attribute-enhancer.d.ts +17 -0
- package/dist/handlers/tool-configs/universal/core/error-enhancers/attribute-enhancer.d.ts.map +1 -0
- package/dist/handlers/tool-configs/universal/core/error-enhancers/attribute-enhancer.js +118 -0
- package/dist/handlers/tool-configs/universal/core/error-enhancers/attribute-enhancer.js.map +1 -0
- package/dist/handlers/tool-configs/universal/core/error-enhancers/complex-type-enhancer.d.ts +14 -0
- package/dist/handlers/tool-configs/universal/core/error-enhancers/complex-type-enhancer.d.ts.map +1 -0
- package/dist/handlers/tool-configs/universal/core/error-enhancers/complex-type-enhancer.js +77 -0
- package/dist/handlers/tool-configs/universal/core/error-enhancers/complex-type-enhancer.js.map +1 -0
- package/dist/handlers/tool-configs/universal/core/error-enhancers/index.d.ts +24 -0
- package/dist/handlers/tool-configs/universal/core/error-enhancers/index.d.ts.map +1 -0
- package/dist/handlers/tool-configs/universal/core/error-enhancers/index.js +35 -0
- package/dist/handlers/tool-configs/universal/core/error-enhancers/index.js.map +1 -0
- package/dist/handlers/tool-configs/universal/core/error-enhancers/record-reference-enhancer.d.ts +15 -0
- package/dist/handlers/tool-configs/universal/core/error-enhancers/record-reference-enhancer.d.ts.map +1 -0
- package/dist/handlers/tool-configs/universal/core/error-enhancers/record-reference-enhancer.js +108 -0
- package/dist/handlers/tool-configs/universal/core/error-enhancers/record-reference-enhancer.js.map +1 -0
- package/dist/handlers/tool-configs/universal/core/error-enhancers/required-fields-enhancer.d.ts +14 -0
- package/dist/handlers/tool-configs/universal/core/error-enhancers/required-fields-enhancer.d.ts.map +1 -0
- package/dist/handlers/tool-configs/universal/core/error-enhancers/required-fields-enhancer.js +91 -0
- package/dist/handlers/tool-configs/universal/core/error-enhancers/required-fields-enhancer.js.map +1 -0
- package/dist/handlers/tool-configs/universal/core/error-enhancers/select-status-enhancer.d.ts +14 -0
- package/dist/handlers/tool-configs/universal/core/error-enhancers/select-status-enhancer.d.ts.map +1 -0
- package/dist/handlers/tool-configs/universal/core/error-enhancers/select-status-enhancer.js +118 -0
- package/dist/handlers/tool-configs/universal/core/error-enhancers/select-status-enhancer.js.map +1 -0
- package/dist/handlers/tool-configs/universal/core/error-enhancers/types.d.ts +77 -0
- package/dist/handlers/tool-configs/universal/core/error-enhancers/types.d.ts.map +1 -0
- package/dist/handlers/tool-configs/universal/core/error-enhancers/types.js +42 -0
- package/dist/handlers/tool-configs/universal/core/error-enhancers/types.js.map +1 -0
- package/dist/handlers/tool-configs/universal/core/error-enhancers/uniqueness-enhancer.d.ts +15 -0
- package/dist/handlers/tool-configs/universal/core/error-enhancers/uniqueness-enhancer.d.ts.map +1 -0
- package/dist/handlers/tool-configs/universal/core/error-enhancers/uniqueness-enhancer.js +109 -0
- package/dist/handlers/tool-configs/universal/core/error-enhancers/uniqueness-enhancer.js.map +1 -0
- package/dist/handlers/tool-configs/universal/core/index.d.ts +63 -22
- package/dist/handlers/tool-configs/universal/core/index.d.ts.map +1 -1
- package/dist/handlers/tool-configs/universal/core/index.js +24 -22
- package/dist/handlers/tool-configs/universal/core/index.js.map +1 -1
- package/dist/handlers/tool-configs/universal/core/metadata-operations.d.ts +43 -1
- package/dist/handlers/tool-configs/universal/core/metadata-operations.d.ts.map +1 -1
- package/dist/handlers/tool-configs/universal/core/metadata-operations.js +117 -11
- package/dist/handlers/tool-configs/universal/core/metadata-operations.js.map +1 -1
- package/dist/handlers/tool-configs/universal/core/notes-operations.js +12 -12
- package/dist/handlers/tool-configs/universal/core/notes-operations.js.map +1 -1
- package/dist/handlers/tool-configs/universal/core/record-details-operations.js +3 -3
- package/dist/handlers/tool-configs/universal/core/record-details-operations.js.map +1 -1
- package/dist/handlers/tool-configs/universal/core/search-operations.js +4 -4
- package/dist/handlers/tool-configs/universal/core/search-operations.js.map +1 -1
- package/dist/handlers/tool-configs/universal/field-mapper/constants/companies.d.ts.map +1 -1
- package/dist/handlers/tool-configs/universal/field-mapper/constants/companies.js +32 -9
- package/dist/handlers/tool-configs/universal/field-mapper/constants/companies.js.map +1 -1
- package/dist/handlers/tool-configs/universal/field-mapper/constants/deals.d.ts.map +1 -1
- package/dist/handlers/tool-configs/universal/field-mapper/constants/deals.js +45 -6
- package/dist/handlers/tool-configs/universal/field-mapper/constants/deals.js.map +1 -1
- package/dist/handlers/tool-configs/universal/field-mapper/constants/people.d.ts.map +1 -1
- package/dist/handlers/tool-configs/universal/field-mapper/constants/people.js +36 -5
- package/dist/handlers/tool-configs/universal/field-mapper/constants/people.js.map +1 -1
- package/dist/handlers/tool-configs/universal/field-mapper/transformers/value-transformer.d.ts +1 -1
- package/dist/handlers/tool-configs/universal/field-mapper/transformers/value-transformer.d.ts.map +1 -1
- package/dist/handlers/tool-configs/universal/field-mapper/transformers/value-transformer.js +17 -1
- package/dist/handlers/tool-configs/universal/field-mapper/transformers/value-transformer.js.map +1 -1
- package/dist/handlers/tool-configs/universal/field-mapper/validators/field-validator.d.ts.map +1 -1
- package/dist/handlers/tool-configs/universal/field-mapper/validators/field-validator.js +3 -1
- package/dist/handlers/tool-configs/universal/field-mapper/validators/field-validator.js.map +1 -1
- package/dist/handlers/tool-configs/universal/index.d.ts +75 -34
- package/dist/handlers/tool-configs/universal/index.d.ts.map +1 -1
- package/dist/handlers/tool-configs/universal/index.js +58 -58
- package/dist/handlers/tool-configs/universal/index.js.map +1 -1
- package/dist/handlers/tool-configs/universal/operations/advanced-search.d.ts.map +1 -1
- package/dist/handlers/tool-configs/universal/operations/advanced-search.js +5 -4
- package/dist/handlers/tool-configs/universal/operations/advanced-search.js.map +1 -1
- package/dist/handlers/tool-configs/universal/operations/batch-operations.js +3 -3
- package/dist/handlers/tool-configs/universal/operations/content-search.js +3 -3
- package/dist/handlers/tool-configs/universal/operations/index.d.ts +10 -10
- package/dist/handlers/tool-configs/universal/operations/index.js +15 -15
- package/dist/handlers/tool-configs/universal/operations/relationship-search.js +3 -3
- package/dist/handlers/tool-configs/universal/operations/timeframe-search.js +3 -3
- package/dist/handlers/tool-configs/universal/schemas/utility-schemas.d.ts.map +1 -1
- package/dist/handlers/tool-configs/universal/schemas/utility-schemas.js +5 -2
- package/dist/handlers/tool-configs/universal/schemas/utility-schemas.js.map +1 -1
- package/dist/handlers/tool-configs/universal/schemas/validation-schemas.d.ts +29 -0
- package/dist/handlers/tool-configs/universal/schemas/validation-schemas.d.ts.map +1 -1
- package/dist/handlers/tool-configs/universal/schemas/validation-schemas.js +28 -0
- package/dist/handlers/tool-configs/universal/schemas/validation-schemas.js.map +1 -1
- package/dist/handlers/tool-configs/universal/schemas.d.ts +1 -1
- package/dist/handlers/tool-configs/universal/schemas.d.ts.map +1 -1
- package/dist/handlers/tool-configs/universal/schemas.js +1 -1
- package/dist/handlers/tool-configs/universal/schemas.js.map +1 -1
- package/dist/handlers/tool-configs/universal/shared-handlers.d.ts +20 -1
- package/dist/handlers/tool-configs/universal/shared-handlers.d.ts.map +1 -1
- package/dist/handlers/tool-configs/universal/shared-handlers.js +216 -0
- package/dist/handlers/tool-configs/universal/shared-handlers.js.map +1 -1
- package/dist/handlers/tool-configs/universal/smithery-diagnostics.js +2 -2
- package/dist/handlers/tool-configs/universal/types.d.ts +9 -0
- package/dist/handlers/tool-configs/universal/types.d.ts.map +1 -1
- package/dist/handlers/tool-configs/universal/validators/schema-validator.d.ts +11 -0
- package/dist/handlers/tool-configs/universal/validators/schema-validator.d.ts.map +1 -1
- package/dist/handlers/tool-configs/universal/validators/schema-validator.js +63 -9
- package/dist/handlers/tool-configs/universal/validators/schema-validator.js.map +1 -1
- package/dist/handlers/tools/dispatcher/core.d.ts.map +1 -1
- package/dist/handlers/tools/dispatcher/core.js +5 -1
- package/dist/handlers/tools/dispatcher/core.js.map +1 -1
- package/dist/handlers/tools/formatters.d.ts +8 -1
- package/dist/handlers/tools/formatters.d.ts.map +1 -1
- package/dist/handlers/tools/formatters.js +30 -14
- package/dist/handlers/tools/formatters.js.map +1 -1
- package/dist/handlers/tools/registry.d.ts +125 -84
- package/dist/handlers/tools/registry.d.ts.map +1 -1
- package/dist/handlers/tools/registry.js +14 -9
- package/dist/handlers/tools/registry.js.map +1 -1
- package/dist/handlers/tools/standards/index.d.ts.map +1 -1
- package/dist/handlers/tools/standards/index.js +19 -11
- package/dist/handlers/tools/standards/index.js.map +1 -1
- package/dist/objects/companies/attributes.d.ts +5 -0
- package/dist/objects/companies/attributes.d.ts.map +1 -1
- package/dist/objects/companies/attributes.js +45 -31
- package/dist/objects/companies/attributes.js.map +1 -1
- package/dist/server/createServer.d.ts.map +1 -1
- package/dist/server/createServer.js +4 -3
- package/dist/server/createServer.js.map +1 -1
- package/dist/services/ErrorService.js +3 -3
- package/dist/services/ErrorService.js.map +1 -1
- package/dist/services/UniversalCreateService.d.ts.map +1 -1
- package/dist/services/UniversalCreateService.js +136 -12
- package/dist/services/UniversalCreateService.js.map +1 -1
- package/dist/services/UniversalSearchService.d.ts +4 -25
- package/dist/services/UniversalSearchService.d.ts.map +1 -1
- package/dist/services/UniversalSearchService.js +14 -324
- package/dist/services/UniversalSearchService.js.map +1 -1
- package/dist/services/UniversalUpdateService.d.ts +15 -4
- package/dist/services/UniversalUpdateService.d.ts.map +1 -1
- package/dist/services/UniversalUpdateService.js +79 -151
- package/dist/services/UniversalUpdateService.js.map +1 -1
- package/dist/services/create/factory.d.ts.map +1 -1
- package/dist/services/create/factory.js +2 -1
- package/dist/services/create/factory.js.map +1 -1
- package/dist/services/metadata/AttributeOptionsService.d.ts +38 -0
- package/dist/services/metadata/AttributeOptionsService.d.ts.map +1 -0
- package/dist/services/metadata/AttributeOptionsService.js +92 -0
- package/dist/services/metadata/AttributeOptionsService.js.map +1 -0
- package/dist/services/metadata/index.d.ts +1 -0
- package/dist/services/metadata/index.d.ts.map +1 -1
- package/dist/services/metadata/index.js +1 -0
- package/dist/services/metadata/index.js.map +1 -1
- package/dist/services/search/QueryApiService.d.ts +27 -0
- package/dist/services/search/QueryApiService.d.ts.map +1 -0
- package/dist/services/search/QueryApiService.js +144 -0
- package/dist/services/search/QueryApiService.js.map +1 -0
- package/dist/services/search/RecordsSearchService.d.ts +27 -0
- package/dist/services/search/RecordsSearchService.d.ts.map +1 -0
- package/dist/services/search/RecordsSearchService.js +122 -0
- package/dist/services/search/RecordsSearchService.js.map +1 -0
- package/dist/services/search/SearchCoordinator.d.ts +41 -0
- package/dist/services/search/SearchCoordinator.d.ts.map +1 -0
- package/dist/services/search/SearchCoordinator.js +83 -0
- package/dist/services/search/SearchCoordinator.js.map +1 -0
- package/dist/services/search/StrategyFactory.d.ts +31 -0
- package/dist/services/search/StrategyFactory.d.ts.map +1 -0
- package/dist/services/search/StrategyFactory.js +100 -0
- package/dist/services/search/StrategyFactory.js.map +1 -0
- package/dist/services/skill-generator/OutputWriterService.d.ts +41 -0
- package/dist/services/skill-generator/OutputWriterService.d.ts.map +1 -0
- package/dist/services/skill-generator/OutputWriterService.js +100 -0
- package/dist/services/skill-generator/OutputWriterService.js.map +1 -0
- package/dist/services/skill-generator/SchemaFormatterService.d.ts +61 -0
- package/dist/services/skill-generator/SchemaFormatterService.d.ts.map +1 -0
- package/dist/services/skill-generator/SchemaFormatterService.js +168 -0
- package/dist/services/skill-generator/SchemaFormatterService.js.map +1 -0
- package/dist/services/skill-generator/WorkspaceSchemaService.d.ts +84 -0
- package/dist/services/skill-generator/WorkspaceSchemaService.d.ts.map +1 -0
- package/dist/services/skill-generator/WorkspaceSchemaService.js +292 -0
- package/dist/services/skill-generator/WorkspaceSchemaService.js.map +1 -0
- package/dist/services/skill-generator/index.d.ts +12 -0
- package/dist/services/skill-generator/index.d.ts.map +1 -0
- package/dist/services/skill-generator/index.js +11 -0
- package/dist/services/skill-generator/index.js.map +1 -0
- package/dist/services/skill-generator/types.d.ts +137 -0
- package/dist/services/skill-generator/types.d.ts.map +1 -0
- package/dist/services/skill-generator/types.js +10 -0
- package/dist/services/skill-generator/types.js.map +1 -0
- package/dist/services/update/FieldPersistenceHandler.d.ts +101 -0
- package/dist/services/update/FieldPersistenceHandler.d.ts.map +1 -0
- package/dist/services/update/FieldPersistenceHandler.js +198 -0
- package/dist/services/update/FieldPersistenceHandler.js.map +1 -0
- package/dist/services/update/FieldValidationHandler.d.ts +77 -0
- package/dist/services/update/FieldValidationHandler.d.ts.map +1 -0
- package/dist/services/update/FieldValidationHandler.js +157 -0
- package/dist/services/update/FieldValidationHandler.js.map +1 -0
- package/dist/services/update/MetadataResolver.d.ts +50 -0
- package/dist/services/update/MetadataResolver.d.ts.map +1 -0
- package/dist/services/update/MetadataResolver.js +110 -0
- package/dist/services/update/MetadataResolver.js.map +1 -0
- package/dist/services/update/UpdateOrchestrator.d.ts +37 -0
- package/dist/services/update/UpdateOrchestrator.d.ts.map +1 -0
- package/dist/services/update/UpdateOrchestrator.js +58 -0
- package/dist/services/update/UpdateOrchestrator.js.map +1 -0
- package/dist/services/update/UpdateValidation.d.ts +5 -1
- package/dist/services/update/UpdateValidation.d.ts.map +1 -1
- package/dist/services/update/UpdateValidation.js +46 -14
- package/dist/services/update/UpdateValidation.js.map +1 -1
- package/dist/services/value-transformer/index.d.ts +57 -0
- package/dist/services/value-transformer/index.d.ts.map +1 -0
- package/dist/services/value-transformer/index.js +326 -0
- package/dist/services/value-transformer/index.js.map +1 -0
- package/dist/services/value-transformer/multi-select-transformer.d.ts +63 -0
- package/dist/services/value-transformer/multi-select-transformer.d.ts.map +1 -0
- package/dist/services/value-transformer/multi-select-transformer.js +144 -0
- package/dist/services/value-transformer/multi-select-transformer.js.map +1 -0
- package/dist/services/value-transformer/record-reference-transformer.d.ts +43 -0
- package/dist/services/value-transformer/record-reference-transformer.d.ts.map +1 -0
- package/dist/services/value-transformer/record-reference-transformer.js +245 -0
- package/dist/services/value-transformer/record-reference-transformer.js.map +1 -0
- package/dist/services/value-transformer/select-transformer.d.ts +48 -0
- package/dist/services/value-transformer/select-transformer.d.ts.map +1 -0
- package/dist/services/value-transformer/select-transformer.js +232 -0
- package/dist/services/value-transformer/select-transformer.js.map +1 -0
- package/dist/services/value-transformer/status-transformer.d.ts +32 -0
- package/dist/services/value-transformer/status-transformer.d.ts.map +1 -0
- package/dist/services/value-transformer/status-transformer.js +294 -0
- package/dist/services/value-transformer/status-transformer.js.map +1 -0
- package/dist/services/value-transformer/types.d.ts +100 -0
- package/dist/services/value-transformer/types.d.ts.map +1 -0
- package/dist/services/value-transformer/types.js +6 -0
- package/dist/services/value-transformer/types.js.map +1 -0
- package/dist/templates/skill/SKILL.template.md +78 -0
- package/dist/templates/skill/attribute-reference.template.md +126 -0
- package/dist/templates/skill/complex-types.template.md +255 -0
- package/dist/utils/client-resolver.d.ts.map +1 -1
- package/dist/utils/client-resolver.js +8 -16
- package/dist/utils/client-resolver.js.map +1 -1
- package/dist/utils/complex-type-validation.d.ts +16 -0
- package/dist/utils/complex-type-validation.d.ts.map +1 -0
- package/dist/utils/complex-type-validation.js +196 -0
- package/dist/utils/complex-type-validation.js.map +1 -0
- package/dist/utils/error-utilities.d.ts.map +1 -1
- package/dist/utils/error-utilities.js +16 -9
- package/dist/utils/error-utilities.js.map +1 -1
- package/dist/utils/location-normalizer.d.ts +26 -0
- package/dist/utils/location-normalizer.d.ts.map +1 -0
- package/dist/utils/location-normalizer.js +39 -0
- package/dist/utils/location-normalizer.js.map +1 -0
- package/dist/utils/metadata-utils.d.ts +27 -0
- package/dist/utils/metadata-utils.d.ts.map +1 -0
- package/dist/utils/metadata-utils.js +59 -0
- package/dist/utils/metadata-utils.js.map +1 -0
- package/dist/utils/personal-name-parser.d.ts.map +1 -1
- package/dist/utils/personal-name-parser.js +26 -17
- package/dist/utils/personal-name-parser.js.map +1 -1
- package/dist/validators/company/field_detector.d.ts.map +1 -1
- package/dist/validators/company/field_detector.js +5 -0
- package/dist/validators/company/field_detector.js.map +1 -1
- package/package.json +13 -11
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Select transformer - converts select option titles to ["title"] array format
|
|
3
|
+
*
|
|
4
|
+
* Problem: LLMs commonly pass select values as human-readable strings
|
|
5
|
+
* (e.g., "Technology", "Potential Customer") but Attio API requires
|
|
6
|
+
* array format: ["title"]
|
|
7
|
+
*
|
|
8
|
+
* Solution: Auto-detect single-select attributes (type="select" AND
|
|
9
|
+
* is_multiselect !== true) and transform string titles to title arrays.
|
|
10
|
+
*
|
|
11
|
+
* NOTE: Attio API accepts ["title"] format and silently rejects ["uuid"] format
|
|
12
|
+
* despite returning HTTP 200 OK (Issue #1045). This transformer uses titles.
|
|
13
|
+
*
|
|
14
|
+
* @see Issue #1019, #1045
|
|
15
|
+
*/
|
|
16
|
+
import { AttributeOptionsService } from '../../services/metadata/index.js';
|
|
17
|
+
import { isValidUUID } from '../../utils/validation/uuid-validation.js';
|
|
18
|
+
import { debug, error as logError, OperationType } from '../../utils/logger.js';
|
|
19
|
+
import { DEFAULT_ATTRIBUTES_CACHE_TTL } from '../../constants/universal.constants.js';
|
|
20
|
+
/**
|
|
21
|
+
* In-memory cache for select options
|
|
22
|
+
* Key format: {objectSlug}:{attributeSlug}
|
|
23
|
+
*/
|
|
24
|
+
const selectOptionsCache = new Map();
|
|
25
|
+
/**
|
|
26
|
+
* TTL for select options cache (5 minutes)
|
|
27
|
+
*/
|
|
28
|
+
const SELECT_CACHE_TTL = DEFAULT_ATTRIBUTES_CACHE_TTL;
|
|
29
|
+
/**
|
|
30
|
+
* Generate cache key for select options
|
|
31
|
+
*/
|
|
32
|
+
function getCacheKey(objectSlug, attributeSlug) {
|
|
33
|
+
return `${objectSlug}:${attributeSlug}`;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Clear all cached select options (for testing)
|
|
37
|
+
*/
|
|
38
|
+
export function clearSelectCache() {
|
|
39
|
+
selectOptionsCache.clear();
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Clean up expired cache entries
|
|
43
|
+
* Called periodically (10% chance) to prevent memory growth
|
|
44
|
+
*/
|
|
45
|
+
function cleanupExpiredEntries() {
|
|
46
|
+
const now = Date.now();
|
|
47
|
+
const keysToDelete = [];
|
|
48
|
+
for (const [key, entry] of selectOptionsCache.entries()) {
|
|
49
|
+
if (now - entry.timestamp >= SELECT_CACHE_TTL) {
|
|
50
|
+
keysToDelete.push(key);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
for (const key of keysToDelete) {
|
|
54
|
+
selectOptionsCache.delete(key);
|
|
55
|
+
}
|
|
56
|
+
if (keysToDelete.length > 0) {
|
|
57
|
+
debug('select-transformer', `Cleaned up ${keysToDelete.length} expired cache entries`, { expiredKeys: keysToDelete.length }, 'cleanupExpiredEntries', OperationType.DATA_PROCESSING);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Fetch select options with TTL-based caching
|
|
62
|
+
*
|
|
63
|
+
* @param objectSlug - Object slug (e.g., "companies")
|
|
64
|
+
* @param attributeSlug - Attribute slug (e.g., "industry")
|
|
65
|
+
* @returns Array of select options
|
|
66
|
+
*/
|
|
67
|
+
async function getSelectOptionsWithCache(objectSlug, attributeSlug) {
|
|
68
|
+
const cacheKey = getCacheKey(objectSlug, attributeSlug);
|
|
69
|
+
const now = Date.now();
|
|
70
|
+
// Check cache with TTL validation
|
|
71
|
+
if (selectOptionsCache.has(cacheKey)) {
|
|
72
|
+
const cached = selectOptionsCache.get(cacheKey);
|
|
73
|
+
const age = now - cached.timestamp;
|
|
74
|
+
if (age < SELECT_CACHE_TTL) {
|
|
75
|
+
debug('select-transformer', `Using cached select options for ${objectSlug}.${attributeSlug}`, {
|
|
76
|
+
age: `${Math.round(age / 1000)}s`,
|
|
77
|
+
ttl: `${SELECT_CACHE_TTL / 1000}s`,
|
|
78
|
+
}, 'getSelectOptionsWithCache', OperationType.DATA_PROCESSING);
|
|
79
|
+
return cached.data;
|
|
80
|
+
}
|
|
81
|
+
// Expired entry: delete and continue to fetch
|
|
82
|
+
selectOptionsCache.delete(cacheKey);
|
|
83
|
+
debug('select-transformer', 'Cache expired, fetching fresh data', { objectSlug, attributeSlug }, 'getSelectOptionsWithCache', OperationType.DATA_PROCESSING);
|
|
84
|
+
}
|
|
85
|
+
// Periodic cleanup (10% of requests)
|
|
86
|
+
if (Math.random() < 0.1) {
|
|
87
|
+
cleanupExpiredEntries();
|
|
88
|
+
}
|
|
89
|
+
// Fetch fresh data via AttributeOptionsService
|
|
90
|
+
try {
|
|
91
|
+
const result = await AttributeOptionsService.getOptions(objectSlug, attributeSlug, true // include archived for complete matching
|
|
92
|
+
);
|
|
93
|
+
// Map result to normalized AttributeOption format
|
|
94
|
+
const options = result.options.map((opt) => ({
|
|
95
|
+
id: 'id' in opt ? opt.id : '',
|
|
96
|
+
title: opt.title,
|
|
97
|
+
is_archived: opt.is_archived,
|
|
98
|
+
}));
|
|
99
|
+
// Store with timestamp
|
|
100
|
+
selectOptionsCache.set(cacheKey, {
|
|
101
|
+
data: options,
|
|
102
|
+
timestamp: now,
|
|
103
|
+
});
|
|
104
|
+
debug('select-transformer', 'Cached fresh select options', { objectSlug, attributeSlug, optionCount: options.length }, 'getSelectOptionsWithCache', OperationType.DATA_PROCESSING);
|
|
105
|
+
return options;
|
|
106
|
+
}
|
|
107
|
+
catch (err) {
|
|
108
|
+
logError('select-transformer', `Failed to fetch select options for ${objectSlug}.${attributeSlug}`, err);
|
|
109
|
+
return [];
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Find a select option by title (case-insensitive with partial matching)
|
|
114
|
+
*
|
|
115
|
+
* @param options - Available select options
|
|
116
|
+
* @param title - Title to match
|
|
117
|
+
* @returns Matched option or undefined
|
|
118
|
+
*/
|
|
119
|
+
function findOptionByTitle(options, title) {
|
|
120
|
+
const titleLower = title.toLowerCase().trim();
|
|
121
|
+
// Priority 1: Exact match (case-insensitive)
|
|
122
|
+
const exactMatch = options.find((opt) => opt.title.toLowerCase() === titleLower);
|
|
123
|
+
if (exactMatch)
|
|
124
|
+
return exactMatch;
|
|
125
|
+
// Priority 2: Partial match (one-directional: option title contains input)
|
|
126
|
+
return options.find((opt) => opt.title.toLowerCase().includes(titleLower));
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Check if an attribute is a single-select (NOT multi-select)
|
|
130
|
+
*
|
|
131
|
+
* CRITICAL (Issue #992): Attio uses type="select" for BOTH single-select
|
|
132
|
+
* and multi-select. The is_multiselect flag distinguishes them.
|
|
133
|
+
*
|
|
134
|
+
* - Single-select: type="select" && is_multiselect !== true
|
|
135
|
+
* - Multi-select: type="select" && is_multiselect === true
|
|
136
|
+
*
|
|
137
|
+
* Multi-select is handled by multi-select-transformer, so we skip here.
|
|
138
|
+
*/
|
|
139
|
+
function isSingleSelectAttribute(meta) {
|
|
140
|
+
return meta.type === 'select' && meta.is_multiselect !== true;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Create a "no transformation needed" result
|
|
144
|
+
*/
|
|
145
|
+
function noTransform(value) {
|
|
146
|
+
return { transformed: false, originalValue: value, transformedValue: value };
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Transform a select value from string title to ["title"] array format
|
|
150
|
+
*
|
|
151
|
+
* Supports:
|
|
152
|
+
* - Case-insensitive title matching: "technology" → ["Technology"]
|
|
153
|
+
* - Partial matching: "Tech" → ["Technology"] (if matches "Technology")
|
|
154
|
+
* - UUID pass-through: "uuid-string" → ["uuid-string"] (no API lookup)
|
|
155
|
+
* - Error suggestions: Lists valid options on invalid input
|
|
156
|
+
*
|
|
157
|
+
* NOTE: Uses ["title"] format not ["uuid"] because Attio API silently
|
|
158
|
+
* rejects UUID arrays despite returning HTTP 200 OK (Issue #1045).
|
|
159
|
+
*
|
|
160
|
+
* @param value - The value to transform
|
|
161
|
+
* @param attributeSlug - The attribute slug
|
|
162
|
+
* @param context - Transformation context
|
|
163
|
+
* @param attributeMeta - Attribute metadata (must be single-select)
|
|
164
|
+
* @returns Transform result with ["title"] array format
|
|
165
|
+
*/
|
|
166
|
+
export async function transformSelectValue(value, attributeSlug, context, attributeMeta) {
|
|
167
|
+
// Guard: Only transform single-select string values not already in array format
|
|
168
|
+
if (!isSingleSelectAttribute(attributeMeta))
|
|
169
|
+
return noTransform(value);
|
|
170
|
+
if (Array.isArray(value))
|
|
171
|
+
return noTransform(value);
|
|
172
|
+
if (typeof value !== 'string')
|
|
173
|
+
return noTransform(value);
|
|
174
|
+
// Short-circuit: UUID string detection (skip lookup)
|
|
175
|
+
if (isValidUUID(value)) {
|
|
176
|
+
const transformedValue = [value];
|
|
177
|
+
debug('select-transformer', 'Detected UUID string for select attribute', { attribute: attributeSlug, matchType: 'uuid-passthrough' }, 'transformSelectValue', OperationType.DATA_PROCESSING);
|
|
178
|
+
return {
|
|
179
|
+
transformed: true,
|
|
180
|
+
originalValue: value,
|
|
181
|
+
transformedValue,
|
|
182
|
+
description: `Wrapped UUID string in array for ${attributeSlug}`,
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
// Map resource type to object slug
|
|
186
|
+
const objectSlug = context.resourceType.toLowerCase();
|
|
187
|
+
// Fetch select options with caching
|
|
188
|
+
const options = await getSelectOptionsWithCache(objectSlug, attributeSlug);
|
|
189
|
+
if (options.length === 0) {
|
|
190
|
+
debug('select-transformer', `No select options found for ${objectSlug}.${attributeSlug}`, { hasValue: !!value, valueType: typeof value }, 'transformSelectValue', OperationType.DATA_PROCESSING);
|
|
191
|
+
return noTransform(value);
|
|
192
|
+
}
|
|
193
|
+
// Find matching option
|
|
194
|
+
const match = findOptionByTitle(options, value);
|
|
195
|
+
if (!match) {
|
|
196
|
+
// No match - throw error with valid options
|
|
197
|
+
const validOptions = options
|
|
198
|
+
.filter((opt) => !opt.is_archived)
|
|
199
|
+
.map((opt) => `"${opt.title}"`)
|
|
200
|
+
.join(', ');
|
|
201
|
+
throw new Error(`Invalid select value "${value}" for ${attributeSlug}. ` +
|
|
202
|
+
`Valid options are: ${validOptions}`);
|
|
203
|
+
}
|
|
204
|
+
// Transform to array format with option title
|
|
205
|
+
// NOTE: Attio API accepts ["title"] format, but silently rejects ["uuid"] format (Issue #1045)
|
|
206
|
+
const transformedValue = [match.title];
|
|
207
|
+
debug('select-transformer', 'Transformed select value', {
|
|
208
|
+
attribute: attributeSlug,
|
|
209
|
+
matchType: match.title.toLowerCase() === value.toLowerCase().trim()
|
|
210
|
+
? 'exact'
|
|
211
|
+
: 'partial',
|
|
212
|
+
matchedTitle: match.title,
|
|
213
|
+
}, 'transformSelectValue', OperationType.DATA_PROCESSING);
|
|
214
|
+
return {
|
|
215
|
+
transformed: true,
|
|
216
|
+
originalValue: value,
|
|
217
|
+
transformedValue,
|
|
218
|
+
description: `Converted select title "${value}" to ["${match.title}"]`,
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Get valid select options for error messages
|
|
223
|
+
*
|
|
224
|
+
* @param objectSlug - Object slug
|
|
225
|
+
* @param attributeSlug - Attribute slug
|
|
226
|
+
* @returns Array of valid option titles
|
|
227
|
+
*/
|
|
228
|
+
export async function getValidSelectOptions(objectSlug, attributeSlug) {
|
|
229
|
+
const options = await getSelectOptionsWithCache(objectSlug, attributeSlug);
|
|
230
|
+
return options.filter((opt) => !opt.is_archived).map((opt) => opt.title);
|
|
231
|
+
}
|
|
232
|
+
//# sourceMappingURL=select-transformer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"select-transformer.js","sourceRoot":"","sources":["../../../src/services/value-transformer/select-transformer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Status transformer - converts status titles to Attio status object format
|
|
3
|
+
*
|
|
4
|
+
* Problem: LLMs commonly pass status values as strings (e.g., "Demo Scheduling")
|
|
5
|
+
* but Attio API requires a structured object for status attributes.
|
|
6
|
+
*
|
|
7
|
+
* Solution: Auto-detect status attributes and transform string titles to the
|
|
8
|
+
* required object format by looking up the status ID from the workspace options.
|
|
9
|
+
*
|
|
10
|
+
* Note: Attio expects the key `status` (not `status_id`). The value can be the
|
|
11
|
+
* status UUID. We always wrap as an array to match Attio attribute value shapes.
|
|
12
|
+
*/
|
|
13
|
+
import { TransformContext, TransformResult, AttributeMetadata } from './types.js';
|
|
14
|
+
/**
|
|
15
|
+
* Clear the status options cache (useful for testing)
|
|
16
|
+
*/
|
|
17
|
+
export declare function clearStatusCache(): void;
|
|
18
|
+
/**
|
|
19
|
+
* Transform a status value from string title to Attio status object format
|
|
20
|
+
*
|
|
21
|
+
* @param value - The value to transform
|
|
22
|
+
* @param attributeSlug - The attribute slug (e.g., "stage")
|
|
23
|
+
* @param context - Transformation context
|
|
24
|
+
* @param attributeMeta - Attribute metadata (must have type "status")
|
|
25
|
+
* @returns Transform result
|
|
26
|
+
*/
|
|
27
|
+
export declare function transformStatusValue(value: unknown, attributeSlug: string, context: TransformContext, attributeMeta: AttributeMetadata): Promise<TransformResult>;
|
|
28
|
+
/**
|
|
29
|
+
* Get valid status options for error messages
|
|
30
|
+
*/
|
|
31
|
+
export declare function getValidStatusOptions(objectSlug: string, attributeSlug: string): Promise<string[]>;
|
|
32
|
+
//# sourceMappingURL=status-transformer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status-transformer.d.ts","sourceRoot":"","sources":["../../../src/services/value-transformer/status-transformer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EACL,gBAAgB,EAChB,eAAe,EACf,iBAAiB,EAElB,MAAM,YAAY,CAAC;AAiCpB;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,IAAI,CAEvC;AAsOD;;;;;;;;GAQG;AACH,wBAAsB,oBAAoB,CACxC,KAAK,EAAE,OAAO,EACd,aAAa,EAAE,MAAM,EACrB,OAAO,EAAE,gBAAgB,EACzB,aAAa,EAAE,iBAAiB,GAC/B,OAAO,CAAC,eAAe,CAAC,CA6H1B;AAED;;GAEG;AACH,wBAAsB,qBAAqB,CACzC,UAAU,EAAE,MAAM,EAClB,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,MAAM,EAAE,CAAC,CAGnB"}
|
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Status transformer - converts status titles to Attio status object format
|
|
3
|
+
*
|
|
4
|
+
* Problem: LLMs commonly pass status values as strings (e.g., "Demo Scheduling")
|
|
5
|
+
* but Attio API requires a structured object for status attributes.
|
|
6
|
+
*
|
|
7
|
+
* Solution: Auto-detect status attributes and transform string titles to the
|
|
8
|
+
* required object format by looking up the status ID from the workspace options.
|
|
9
|
+
*
|
|
10
|
+
* Note: Attio expects the key `status` (not `status_id`). The value can be the
|
|
11
|
+
* status UUID. We always wrap as an array to match Attio attribute value shapes.
|
|
12
|
+
*/
|
|
13
|
+
import { AttributeOptionsService } from '../../services/metadata/index.js';
|
|
14
|
+
import { isValidUUID } from '../../utils/validation/uuid-validation.js';
|
|
15
|
+
import { debug, error as logError, OperationType } from '../../utils/logger.js';
|
|
16
|
+
import { DEFAULT_ATTRIBUTES_CACHE_TTL } from '../../constants/universal.constants.js';
|
|
17
|
+
/**
|
|
18
|
+
* Cache for status options with TTL-based expiration
|
|
19
|
+
* @see Issue #984 - Add 5-minute TTL to prevent stale data
|
|
20
|
+
*/
|
|
21
|
+
const statusOptionsCache = new Map();
|
|
22
|
+
/**
|
|
23
|
+
* TTL for status options cache (5 minutes)
|
|
24
|
+
*/
|
|
25
|
+
const STATUS_CACHE_TTL = DEFAULT_ATTRIBUTES_CACHE_TTL;
|
|
26
|
+
/**
|
|
27
|
+
* Get cache key for status options
|
|
28
|
+
*/
|
|
29
|
+
function getCacheKey(objectSlug, attributeSlug) {
|
|
30
|
+
return `${objectSlug}:${attributeSlug}`;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Clear the status options cache (useful for testing)
|
|
34
|
+
*/
|
|
35
|
+
export function clearStatusCache() {
|
|
36
|
+
statusOptionsCache.clear();
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Clean up expired cache entries (lazy eviction)
|
|
40
|
+
* @see Issue #984 - Remove expired entries to prevent memory growth
|
|
41
|
+
*/
|
|
42
|
+
function cleanupExpiredEntries() {
|
|
43
|
+
const now = Date.now();
|
|
44
|
+
const keysToDelete = [];
|
|
45
|
+
for (const [key, entry] of statusOptionsCache.entries()) {
|
|
46
|
+
if (now - entry.timestamp >= STATUS_CACHE_TTL) {
|
|
47
|
+
keysToDelete.push(key);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
for (const key of keysToDelete) {
|
|
51
|
+
statusOptionsCache.delete(key);
|
|
52
|
+
}
|
|
53
|
+
if (keysToDelete.length > 0) {
|
|
54
|
+
debug('status-transformer', `Cleaned up ${keysToDelete.length} expired cache entries`, { expiredKeys: keysToDelete.length }, 'cleanupExpiredEntries', OperationType.DATA_PROCESSING);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Fetch status options with TTL-based caching
|
|
59
|
+
* @see Issue #984 - Add TTL expiration to prevent stale data
|
|
60
|
+
*/
|
|
61
|
+
async function getStatusOptionsWithCache(objectSlug, attributeSlug) {
|
|
62
|
+
const cacheKey = getCacheKey(objectSlug, attributeSlug);
|
|
63
|
+
const now = Date.now();
|
|
64
|
+
// Check cache with TTL
|
|
65
|
+
if (statusOptionsCache.has(cacheKey)) {
|
|
66
|
+
const cached = statusOptionsCache.get(cacheKey);
|
|
67
|
+
const age = now - cached.timestamp;
|
|
68
|
+
if (age < STATUS_CACHE_TTL) {
|
|
69
|
+
debug('status-transformer', `Using cached status options for ${objectSlug}.${attributeSlug}`, {
|
|
70
|
+
age: `${Math.round(age / 1000)}s`,
|
|
71
|
+
ttl: `${STATUS_CACHE_TTL / 1000}s`,
|
|
72
|
+
}, 'getStatusOptionsWithCache', OperationType.DATA_PROCESSING);
|
|
73
|
+
return cached.data;
|
|
74
|
+
}
|
|
75
|
+
// Expired, remove it
|
|
76
|
+
statusOptionsCache.delete(cacheKey);
|
|
77
|
+
debug('status-transformer', `Cache expired for ${objectSlug}.${attributeSlug}`, { age: `${Math.round(age / 1000)}s` }, 'getStatusOptionsWithCache', OperationType.DATA_PROCESSING);
|
|
78
|
+
}
|
|
79
|
+
// Periodically clean up expired entries (every 10th fetch)
|
|
80
|
+
if (Math.random() < 0.1) {
|
|
81
|
+
cleanupExpiredEntries();
|
|
82
|
+
}
|
|
83
|
+
// Fetch fresh data
|
|
84
|
+
try {
|
|
85
|
+
const result = await AttributeOptionsService.getOptions(objectSlug, attributeSlug, true // include archived for complete matching
|
|
86
|
+
);
|
|
87
|
+
const options = result.options.map((opt) => {
|
|
88
|
+
// Extract status ID - handle both string and object formats from Attio API
|
|
89
|
+
let id = '';
|
|
90
|
+
if ('id' in opt && opt.id) {
|
|
91
|
+
if (typeof opt.id === 'string') {
|
|
92
|
+
// Simple string ID
|
|
93
|
+
id = opt.id;
|
|
94
|
+
}
|
|
95
|
+
else if (typeof opt.id === 'object' && opt.id !== null) {
|
|
96
|
+
// Object ID structure: { workspace_id, object_id, attribute_id, option_id }
|
|
97
|
+
const idObj = opt.id;
|
|
98
|
+
if ('option_id' in idObj && typeof idObj.option_id === 'string') {
|
|
99
|
+
id = idObj.option_id;
|
|
100
|
+
}
|
|
101
|
+
else if ('status_id' in idObj &&
|
|
102
|
+
typeof idObj.status_id === 'string') {
|
|
103
|
+
id = idObj.status_id;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return {
|
|
108
|
+
id,
|
|
109
|
+
title: opt.title,
|
|
110
|
+
is_archived: opt.is_archived,
|
|
111
|
+
};
|
|
112
|
+
});
|
|
113
|
+
// Cache with timestamp
|
|
114
|
+
statusOptionsCache.set(cacheKey, {
|
|
115
|
+
data: options,
|
|
116
|
+
timestamp: now,
|
|
117
|
+
});
|
|
118
|
+
debug('status-transformer', `Cached fresh status options for ${objectSlug}.${attributeSlug}`, { optionCount: options.length }, 'getStatusOptionsWithCache', OperationType.DATA_PROCESSING);
|
|
119
|
+
return options;
|
|
120
|
+
}
|
|
121
|
+
catch (err) {
|
|
122
|
+
logError('status-transformer', `Failed to fetch status options for ${objectSlug}.${attributeSlug}`, err);
|
|
123
|
+
return [];
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Find status ID by title (case-insensitive)
|
|
128
|
+
*/
|
|
129
|
+
function findStatusByTitle(options, title) {
|
|
130
|
+
const titleLower = title.toLowerCase().trim();
|
|
131
|
+
// First try exact match (case-insensitive)
|
|
132
|
+
const exactMatch = options.find((opt) => opt.title.toLowerCase() === titleLower);
|
|
133
|
+
if (exactMatch)
|
|
134
|
+
return exactMatch;
|
|
135
|
+
// Then try partial match
|
|
136
|
+
const partialMatch = options.find((opt) => opt.title.toLowerCase().includes(titleLower) ||
|
|
137
|
+
titleLower.includes(opt.title.toLowerCase()));
|
|
138
|
+
return partialMatch;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Check if a value is already in the correct status format
|
|
142
|
+
*/
|
|
143
|
+
function isStatusFormat(value) {
|
|
144
|
+
if (!Array.isArray(value) || value.length === 0)
|
|
145
|
+
return false;
|
|
146
|
+
const first = value[0];
|
|
147
|
+
if (!first || typeof first !== 'object' || Array.isArray(first))
|
|
148
|
+
return false;
|
|
149
|
+
return 'status' in first;
|
|
150
|
+
}
|
|
151
|
+
function hasStringKey(value, key) {
|
|
152
|
+
return (typeof value === 'object' &&
|
|
153
|
+
value !== null &&
|
|
154
|
+
!Array.isArray(value) &&
|
|
155
|
+
key in value &&
|
|
156
|
+
typeof value[key] === 'string');
|
|
157
|
+
}
|
|
158
|
+
function normalizeIncomingStatusValue(value) {
|
|
159
|
+
// Already-correct Attio form: [{ status: "..." }]
|
|
160
|
+
if (isStatusFormat(value)) {
|
|
161
|
+
return { normalized: value };
|
|
162
|
+
}
|
|
163
|
+
// Handle array-of-objects with the legacy key: [{ status_id: "..." }] → [{ status: "..." }]
|
|
164
|
+
if (Array.isArray(value) &&
|
|
165
|
+
value.length > 0 &&
|
|
166
|
+
hasStringKey(value[0], 'status_id')) {
|
|
167
|
+
return { normalized: [{ status: value[0].status_id }] };
|
|
168
|
+
}
|
|
169
|
+
// Handle single object forms (common mistakes): { status: "..." } / { status_id: "..." }
|
|
170
|
+
if (hasStringKey(value, 'status')) {
|
|
171
|
+
return {
|
|
172
|
+
normalized: [{ status: value.status }],
|
|
173
|
+
extractedText: value.status,
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
if (hasStringKey(value, 'status_id')) {
|
|
177
|
+
return {
|
|
178
|
+
normalized: [{ status: value.status_id }],
|
|
179
|
+
extractedText: value.status_id,
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
// Handle array of string values: ["Demo Scheduling"] → "Demo Scheduling"
|
|
183
|
+
if (Array.isArray(value) &&
|
|
184
|
+
value.length > 0 &&
|
|
185
|
+
typeof value[0] === 'string') {
|
|
186
|
+
return { normalized: value, extractedText: value[0] };
|
|
187
|
+
}
|
|
188
|
+
return { normalized: value };
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Transform a status value from string title to Attio status object format
|
|
192
|
+
*
|
|
193
|
+
* @param value - The value to transform
|
|
194
|
+
* @param attributeSlug - The attribute slug (e.g., "stage")
|
|
195
|
+
* @param context - Transformation context
|
|
196
|
+
* @param attributeMeta - Attribute metadata (must have type "status")
|
|
197
|
+
* @returns Transform result
|
|
198
|
+
*/
|
|
199
|
+
export async function transformStatusValue(value, attributeSlug, context, attributeMeta) {
|
|
200
|
+
// Only transform status type attributes
|
|
201
|
+
if (attributeMeta.type !== 'status') {
|
|
202
|
+
return {
|
|
203
|
+
transformed: false,
|
|
204
|
+
originalValue: value,
|
|
205
|
+
transformedValue: value,
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
const normalizedIncoming = normalizeIncomingStatusValue(value);
|
|
209
|
+
const normalizedValue = normalizedIncoming.normalized;
|
|
210
|
+
// Skip if already in correct Attio format after normalization
|
|
211
|
+
if (isStatusFormat(normalizedValue)) {
|
|
212
|
+
return {
|
|
213
|
+
transformed: normalizedValue !== value,
|
|
214
|
+
originalValue: value,
|
|
215
|
+
transformedValue: normalizedValue,
|
|
216
|
+
description: normalizedValue !== value
|
|
217
|
+
? `Normalized status value format for ${attributeSlug}`
|
|
218
|
+
: undefined,
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
const extractedText = typeof normalizedIncoming.extractedText === 'string'
|
|
222
|
+
? normalizedIncoming.extractedText
|
|
223
|
+
: typeof normalizedValue === 'string'
|
|
224
|
+
? normalizedValue
|
|
225
|
+
: undefined;
|
|
226
|
+
// Only transform string-like values
|
|
227
|
+
if (typeof extractedText !== 'string') {
|
|
228
|
+
return {
|
|
229
|
+
transformed: false,
|
|
230
|
+
originalValue: value,
|
|
231
|
+
transformedValue: normalizedValue,
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
// Short-circuit if value is already a UUID
|
|
235
|
+
if (isValidUUID(extractedText)) {
|
|
236
|
+
const transformedValue = [{ status: extractedText }];
|
|
237
|
+
debug('status-transformer', `Detected UUID string for status attribute`, {
|
|
238
|
+
attribute: attributeSlug,
|
|
239
|
+
from: extractedText,
|
|
240
|
+
to: transformedValue,
|
|
241
|
+
}, 'transformStatusValue', OperationType.DATA_PROCESSING);
|
|
242
|
+
return {
|
|
243
|
+
transformed: true,
|
|
244
|
+
originalValue: value,
|
|
245
|
+
transformedValue,
|
|
246
|
+
description: `Converted UUID string to status object for ${attributeSlug}`,
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
// Map resource type to object slug
|
|
250
|
+
const objectSlug = context.resourceType.toLowerCase();
|
|
251
|
+
// Fetch status options
|
|
252
|
+
const options = await getStatusOptionsWithCache(objectSlug, attributeSlug);
|
|
253
|
+
if (options.length === 0) {
|
|
254
|
+
debug('status-transformer', `No status options found for ${objectSlug}.${attributeSlug}`, { value: extractedText }, 'transformStatusValue', OperationType.DATA_PROCESSING);
|
|
255
|
+
return {
|
|
256
|
+
transformed: false,
|
|
257
|
+
originalValue: value,
|
|
258
|
+
transformedValue: normalizedValue,
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
// Find matching status
|
|
262
|
+
const match = findStatusByTitle(options, extractedText);
|
|
263
|
+
if (!match) {
|
|
264
|
+
// No match found - return error with valid options
|
|
265
|
+
const validOptions = options
|
|
266
|
+
.filter((opt) => !opt.is_archived)
|
|
267
|
+
.map((opt) => `"${opt.title}"`)
|
|
268
|
+
.join(', ');
|
|
269
|
+
throw new Error(`Invalid status value "${extractedText}" for ${attributeSlug}. ` +
|
|
270
|
+
`Valid options are: ${validOptions}`);
|
|
271
|
+
}
|
|
272
|
+
// Transform to status ID format
|
|
273
|
+
const transformedValue = [{ status: match.id }];
|
|
274
|
+
debug('status-transformer', `Transformed status value`, {
|
|
275
|
+
attribute: attributeSlug,
|
|
276
|
+
from: extractedText,
|
|
277
|
+
to: transformedValue,
|
|
278
|
+
matchedTitle: match.title,
|
|
279
|
+
}, 'transformStatusValue', OperationType.DATA_PROCESSING);
|
|
280
|
+
return {
|
|
281
|
+
transformed: true,
|
|
282
|
+
originalValue: value,
|
|
283
|
+
transformedValue,
|
|
284
|
+
description: `Converted status title "${extractedText}" to status "${match.id}" (matched: "${match.title}")`,
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* Get valid status options for error messages
|
|
289
|
+
*/
|
|
290
|
+
export async function getValidStatusOptions(objectSlug, attributeSlug) {
|
|
291
|
+
const options = await getStatusOptionsWithCache(objectSlug, attributeSlug);
|
|
292
|
+
return options.filter((opt) => !opt.is_archived).map((opt) => opt.title);
|
|
293
|
+
}
|
|
294
|
+
//# sourceMappingURL=status-transformer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status-transformer.js","sourceRoot":"","sources":["../../../src/services/value-transformer/status-transformer.ts"],"names":[],"mappings":"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"}
|