@manta-eu/client 0.11.0 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/README.md +44 -0
  2. package/dist/generated/graphql.d.ts +2124 -40
  3. package/dist/generated/graphql.d.ts.map +1 -1
  4. package/dist/generated/graphql.js +472 -24
  5. package/dist/generated/graphql.js.map +1 -1
  6. package/dist/generated/operations.d.ts +2 -0
  7. package/dist/generated/operations.d.ts.map +1 -0
  8. package/dist/generated/operations.js +165 -0
  9. package/dist/generated/operations.js.map +1 -0
  10. package/dist/graphql-clients.d.ts +2 -1
  11. package/dist/graphql-clients.d.ts.map +1 -1
  12. package/dist/graphql-clients.js +2 -1
  13. package/dist/graphql-clients.js.map +1 -1
  14. package/dist/shared/agent-types.d.ts +15 -0
  15. package/dist/shared/agent-types.d.ts.map +1 -1
  16. package/dist/shared/chat-manager.d.ts +1 -1
  17. package/dist/shared/chat-manager.d.ts.map +1 -1
  18. package/dist/shared/chat-manager.js +1 -1
  19. package/dist/shared/chat-manager.js.map +1 -1
  20. package/dist/shared/constants.d.ts +6 -0
  21. package/dist/shared/constants.d.ts.map +1 -1
  22. package/dist/shared/constants.js +6 -0
  23. package/dist/shared/constants.js.map +1 -1
  24. package/dist/shared/datastore-path.d.ts +3 -0
  25. package/dist/shared/datastore-path.d.ts.map +1 -1
  26. package/dist/shared/datastore-path.js +3 -0
  27. package/dist/shared/datastore-path.js.map +1 -1
  28. package/dist/shared/login-status.d.ts +6 -0
  29. package/dist/shared/login-status.d.ts.map +1 -0
  30. package/dist/shared/login-status.js +2 -0
  31. package/dist/shared/login-status.js.map +1 -0
  32. package/dist/shared/memory-schema-limits.d.ts +17 -0
  33. package/dist/shared/memory-schema-limits.d.ts.map +1 -0
  34. package/dist/shared/memory-schema-limits.js +17 -0
  35. package/dist/shared/memory-schema-limits.js.map +1 -0
  36. package/dist/shared/memory-schema-pattern.d.ts +3 -0
  37. package/dist/shared/memory-schema-pattern.d.ts.map +1 -0
  38. package/dist/shared/memory-schema-pattern.js +16 -0
  39. package/dist/shared/memory-schema-pattern.js.map +1 -0
  40. package/dist/shared/memory-schema-property.d.ts +64 -0
  41. package/dist/shared/memory-schema-property.d.ts.map +1 -0
  42. package/dist/shared/memory-schema-property.js +195 -0
  43. package/dist/shared/memory-schema-property.js.map +1 -0
  44. package/dist/shared/memory-schema-values.d.ts +20 -0
  45. package/dist/shared/memory-schema-values.d.ts.map +1 -0
  46. package/dist/shared/memory-schema-values.js +139 -0
  47. package/dist/shared/memory-schema-values.js.map +1 -0
  48. package/dist/shared/operation-root-fields.d.ts +7 -0
  49. package/dist/shared/operation-root-fields.d.ts.map +1 -0
  50. package/dist/shared/operation-root-fields.js +33 -0
  51. package/dist/shared/operation-root-fields.js.map +1 -0
  52. package/dist/shared/rdf-namespaces.d.ts +1 -0
  53. package/dist/shared/rdf-namespaces.d.ts.map +1 -1
  54. package/dist/shared/rdf-namespaces.js +2 -0
  55. package/dist/shared/rdf-namespaces.js.map +1 -1
  56. package/dist/testing/manta-mock.d.ts +25 -0
  57. package/dist/testing/manta-mock.d.ts.map +1 -0
  58. package/dist/testing/manta-mock.js +165 -0
  59. package/dist/testing/manta-mock.js.map +1 -0
  60. package/package.json +32 -6
  61. package/src/generated/graphql.ts +2726 -71
  62. package/src/generated/operations.ts +164 -0
  63. package/src/graphql-clients.ts +3 -2
  64. package/src/shared/agent-types.ts +16 -0
  65. package/src/shared/chat-manager.ts +1 -1
  66. package/src/shared/constants.ts +11 -0
  67. package/src/shared/datastore-path.ts +6 -0
  68. package/src/shared/login-status.ts +1 -0
  69. package/src/shared/memory-schema-limits.ts +16 -0
  70. package/src/shared/memory-schema-pattern.ts +15 -0
  71. package/src/shared/memory-schema-property.ts +280 -0
  72. package/src/shared/memory-schema-values.ts +174 -0
  73. package/src/shared/operation-root-fields.ts +56 -0
  74. package/src/shared/rdf-namespaces.ts +3 -0
  75. package/src/testing/manta-mock.ts +208 -0
@@ -0,0 +1,164 @@
1
+ export const operationRootFields: Record<string, readonly string[]> = {
2
+ abortUpload: ["abortUpload"],
3
+ AcceptInvitation: ["acceptInvitation"],
4
+ ActionPlanByIri: ["actionPlans"],
5
+ ActionPlanDiff: ["actionPlanDiff"],
6
+ ActionPlanRules: ["rules"],
7
+ ActionPlanRunHistory: ["actionPlanRunHistory"],
8
+ ActionPlans: ["actionPlans"],
9
+ ActionPlanSamples: ["actionPlanSamples"],
10
+ AddMemorySchemaFromTemplate: ["addMemorySchemaFromTemplate"],
11
+ ArchiveMemorySchema: ["archiveMemorySchema"],
12
+ AssignableGroups: ["assignableGroups"],
13
+ AssignableOrganizations: ["assignableOrganizations"],
14
+ AttributeStripeSubscription: ["attributeStripeSubscription"],
15
+ AvailableTeams: ["availableTeams"],
16
+ AwaitDataConnectionTest: ["awaitDataConnectionTest"],
17
+ BringDatastoreOnline: ["bringDatastoreOnline"],
18
+ CancelActionPlan: ["cancelActionPlan"],
19
+ ChangeManualActionAssignees: ["manualActionChangeAssignees"],
20
+ ClearMemorySchemaPropertyValues: ["clearMemorySchemaPropertyValues"],
21
+ ClearStagedRules: ["clearStagedRules"],
22
+ CommitStagedRules: ["commitStagedRules"],
23
+ CompleteStripeCheckout: ["completeStripeCheckout"],
24
+ completeUpload: ["completeUpload"],
25
+ ConnectedAccounts: ["connectedAccounts"],
26
+ ConnectedCustomApps: ["connectedCustomApps"],
27
+ ConsolidateMemories: ["consolidateMemories"],
28
+ ContinueDatastoreDeletion: ["continueDatastoreDeletion"],
29
+ ConversationStarters: ["conversationStarters"],
30
+ CoverageRules: ["rules"],
31
+ CreateCustomApp: ["createCustomApp"],
32
+ CreateDataConnection: ["createDataConnection"],
33
+ CreateInferalIntegration: ["createInferalIntegration"],
34
+ CreateMemory: ["createMemory"],
35
+ CreateMemorySchema: ["createMemorySchema"],
36
+ CreateStripeBillingPortalSession: ["createStripeBillingPortalSession"],
37
+ CreateStripeCheckoutSession: ["createStripeCheckoutSession"],
38
+ CurrentFactValue: ["currentFactValue"],
39
+ CustomApp: ["customApp"],
40
+ CustomAppDatastores: ["customAppDatastores"],
41
+ CustomApps: ["customApps"],
42
+ CustomAppUsers: ["customAppUsers"],
43
+ CustomerDatastores: ["customerDatastores"],
44
+ DashSetupConnect: ["dashSetupConnect"],
45
+ DashSetupProgress: ["dashSetupProgress"],
46
+ DataConnections: ["dataConnections"],
47
+ DataConnectorTypes: ["dataConnectorTypes"],
48
+ DatastoreDeletions: ["datastoreDeletions"],
49
+ DatastoreInvoices: ["datastoreInvoices"],
50
+ DatastoreProvisioningStatuses: ["datastoreProvisioningStatuses"],
51
+ DatastoreSubscriptions: ["datastoreSubscriptions"],
52
+ DatastoreTree: ["datastoreTree"],
53
+ DeclineInvitation: ["declineInvitation"],
54
+ DeleteActionPlan: ["deleteActionPlan"],
55
+ DeleteCustomApp: ["deleteCustomApp"],
56
+ DeleteDataConnection: ["deleteDataConnection"],
57
+ DeleteDatastore: ["deleteDatastore"],
58
+ DeleteLdesStream: ["deleteLDESStream"],
59
+ DeleteMemory: ["deleteMemory"],
60
+ DeleteMemorySchema: ["deleteMemorySchema"],
61
+ DeleteUserAccount: ["deleteUserAccount"],
62
+ DetectMemoryConflicts: ["detectMemoryConflicts"],
63
+ DisconnectConnectedAccount: ["disconnectConnectedAccount"],
64
+ DisconnectCustomApp: ["disconnectCustomApp"],
65
+ DisconnectGmailIntegration: ["disconnectGmailIntegration"],
66
+ DisconnectInferalIntegration: ["disconnectInferalIntegration"],
67
+ DismissMemorySchemaTemplateUpdate: ["dismissMemorySchemaTemplateUpdate"],
68
+ ExecuteAgentActionAddition: ["executeActionAddition"],
69
+ ExecuteAgentActionDeletion: ["executeActionDeletion"],
70
+ ExecuteAgentActionGraph: ["executeActionGraph"],
71
+ ExecuteAgentActionPlan: ["executeActionPlan"],
72
+ ExecuteAgentActionUpdate: ["executeActionUpdate"],
73
+ ExplainFact: ["explainFact"],
74
+ ForgetUserName: ["forgetUserName"],
75
+ GenerateStructuredData: ["generateStructuredData"],
76
+ GetActionPlansSummary: ["actionPlansSummary"],
77
+ GmailIntegrations: ["gmailIntegrations"],
78
+ GoogleAnalyticsSetupConnect: ["googleAnalyticsSetupConnect"],
79
+ GoogleAnalyticsSetupProgress: ["googleAnalyticsSetupProgress"],
80
+ GoogleBrandSuggestions: ["googleBrandSuggestions"],
81
+ GoogleMerchantCenterSetupConnect: ["googleMerchantCenterSetupConnect"],
82
+ GoogleMerchantCenterSetupProgress: ["googleMerchantCenterSetupProgress"],
83
+ GoogleSetupConnect: ["googleSetupConnect"],
84
+ GoogleSetupProgress: ["googleSetupProgress"],
85
+ GrantOperatorRole: ["grantOperatorRole"],
86
+ InferalIntegrations: ["inferalIntegrations"],
87
+ initiateUpload: ["initiateUpload"],
88
+ InviteCustomAppUser: ["inviteCustomAppUser"],
89
+ InviteCustomAppUsers: ["inviteCustomAppUsers"],
90
+ KnowledgeGraphState: ["knowledgeGraphState"],
91
+ LdesStreams: ["ldesStreams"],
92
+ LinkedinSetupConnect: ["linkedinSetupConnect"],
93
+ LinkedinSetupProgress: ["linkedinSetupProgress"],
94
+ LinkOrganizationToProvider: ["linkOrganizationToProvider"],
95
+ LinkUnlinkedDatastore: ["linkUnlinkedDatastore"],
96
+ ManualActionProgress: ["manualActionProgress"],
97
+ MaterializeOntologyCoverage: ["materializeOntologyCoverage"],
98
+ Memories: ["memories"],
99
+ MemoryRedundancyReview: ["memoryRedundancyReview"],
100
+ MemorySchemaRuleCounts: ["memorySchemaRuleCounts"],
101
+ MemorySchemas: ["memorySchemas"],
102
+ MemorySchemaTemplates: ["memorySchemaTemplates"],
103
+ MemorySchemaUsage: ["memorySchemaUsage"],
104
+ MetaInterestSuggestions: ["metaInterestSuggestions"],
105
+ MetaSetupConnect: ["metaSetupConnect"],
106
+ MetaSetupIncludePages: ["metaSetupIncludePages"],
107
+ MetaSetupProgress: ["metaSetupProgress"],
108
+ MicrosoftAdsSetupConnect: ["microsoftAdsSetupConnect"],
109
+ MicrosoftAdsSetupProgress: ["microsoftAdsSetupProgress"],
110
+ NodeProperties: ["nodeProperties"],
111
+ NodeRelationships: ["nodeRelationships"],
112
+ OrganizationLinking: ["organizationLinking"],
113
+ PauseLdesStream: ["pauseLDESStream"],
114
+ PendingInvitations: ["pendingInvitations"],
115
+ Profile: ["sessionContext"],
116
+ ProvisionDatastore: ["provisionDatastore"],
117
+ ReconfirmMemory: ["reconfirmMemory"],
118
+ RefreshResourceCapabilities: ["refreshResourceCapabilities"],
119
+ RefreshResources: ["refreshResources"],
120
+ RefreshResourcesStatus: ["refreshResourcesStatus"],
121
+ RegisterDatastore: ["registerDatastore"],
122
+ ReleaseRuleOwnership: ["releaseRuleOwnership"],
123
+ RemoveCustomAppUser: ["removeCustomAppUser"],
124
+ RemoveCustomAppUsers: ["removeCustomAppUsers"],
125
+ RemoveCustomAppUsersCreatedBetween: ["removeCustomAppUsersCreatedBetween"],
126
+ RenameDatastoreGroup: ["renameDatastoreGroup"],
127
+ RenameUser: ["renameUser"],
128
+ ResetMemorySchemaToTemplate: ["resetMemorySchemaToTemplate"],
129
+ ResolveManualAction: ["manualActionResolve"],
130
+ RestoreMemory: ["restoreMemory"],
131
+ ResumeLdesStream: ["resumeLDESStream"],
132
+ RevokeOperatorRole: ["revokeOperatorRole"],
133
+ RevokePreviousCustomAppSecret: ["revokePreviousCustomAppSecret"],
134
+ RotateCustomAppSecret: ["rotateCustomAppSecret"],
135
+ Rules: ["rules"],
136
+ SessionContext: ["sessionContext"],
137
+ SetActionPlanAutoPilot: ["setActionPlanAutoPilot"],
138
+ SetCustomAppEnabled: ["setCustomAppEnabled"],
139
+ ShaclShapes: ["shaclShapes"],
140
+ SparqlQuery: ["sparqlQuery"],
141
+ StageRuleOperation: ["stageRuleOperation"],
142
+ StartLdesStream: ["startLDESStream"],
143
+ StripeSubscriptionProducts: ["stripeSubscriptionProducts"],
144
+ SupportedActionShapes: ["supportedActionShapes"],
145
+ SyncGmailIntegration: ["syncGmailIntegration"],
146
+ TeamDirectory: ["teamDirectory"],
147
+ TeamGroups: ["teamGroups"],
148
+ TeamManagedMemberships: ["teamManagedMemberships"],
149
+ TeamMembers: ["teamMembers"],
150
+ TeamScope: ["teamScope"],
151
+ TenantOrganization: ["tenantOrganization"],
152
+ UnarchiveMemorySchema: ["unarchiveMemorySchema"],
153
+ UndoMemorySchemaAssignment: ["undoMemorySchemaAssignment"],
154
+ UnlinkedDatastores: ["unlinkedDatastores"],
155
+ UpdateCustomApp: ["updateCustomApp"],
156
+ UpdateDataConnection: ["updateDataConnection"],
157
+ UpdateMemory: ["updateMemory"],
158
+ UpdateMemorySchema: ["updateMemorySchema"],
159
+ UpdateUserPreferences: ["updateUserPreferences"],
160
+ UserPreferences: ["userPreferences"],
161
+ ValidateActionPlan: ["validateActionPlan"],
162
+ ValidateStagedRules: ["validateStagedRules"],
163
+ WarehouseQuery: ["warehouseQuery"],
164
+ };
@@ -1,4 +1,7 @@
1
1
  import { ClientError, GraphQLClient } from "graphql-request";
2
+ import { mantaGQLPath } from "./shared/constants";
3
+
4
+ export { mantaGQLPath };
2
5
 
3
6
  // Default client constructors for the v1 and Manta GraphQL APIs
4
7
 
@@ -14,8 +17,6 @@ export function v1GraphQLClient(baseUrl: URL) {
14
17
  });
15
18
  }
16
19
 
17
- export const mantaGQLPath = "/graphql";
18
-
19
20
  // A bearer is the credential: sending cookies with it needs credentialed CORS, which only trusted origins get.
20
21
  export function mantaGraphQLCredentials(headers?: Record<string, string>): RequestCredentials {
21
22
  const sendsBearer = Object.keys(headers ?? {}).some((name) => name.toLowerCase() === "authorization");
@@ -20,20 +20,36 @@ export function isRuleScopedChatContext(context: ChatContext | undefined): boole
20
20
  return context?.kind === ChatContextKind.RuleEdit || context?.kind === ChatContextKind.RuleCreate;
21
21
  }
22
22
 
23
+ export type CachedMemorySchemaOption = {
24
+ value: string;
25
+ label: string | null;
26
+ };
27
+
23
28
  export type CachedMemorySchemaProperty = {
24
29
  path: string;
25
30
  label: string;
31
+ description: string | null;
32
+ valueType: string;
26
33
  dataType: string;
27
34
  required: boolean;
35
+ multiValued: boolean;
28
36
  allowedValues: string[];
37
+ options: CachedMemorySchemaOption[];
29
38
  keyProperty: boolean;
30
39
  inferred: boolean;
40
+ unit: string | null;
31
41
  };
32
42
 
33
43
  export type CachedMemorySchema = {
34
44
  iri: string;
35
45
  label: string;
36
46
  description: string | null;
47
+ status: "active" | "archived";
48
+ defaultMemoryKind: string | null;
49
+ defaultVolatility: string | null;
50
+ defaultImportance: number | null;
51
+ extractionEnabled: boolean;
52
+ extractionGuidance: string | null;
37
53
  properties: CachedMemorySchemaProperty[];
38
54
  };
39
55
 
@@ -2,7 +2,7 @@ import { z } from "zod/v4";
2
2
  import { ChatContextKind } from "./agent-types";
3
3
  import type { IRI } from "./rdf-namespaces";
4
4
 
5
- export const chatManagerBasePath = "agents/chat-manager";
5
+ export { chatManagerBasePath } from "./constants";
6
6
  export const chatTicketPath = "agents/chat-ticket";
7
7
  export const chatTicketQueryParam = "chat_ticket";
8
8
  export const thinkChatFacetPath = "think-chat";
@@ -8,6 +8,16 @@ export const onboardingCompletedCookieName = "manta-onboarding-completed";
8
8
 
9
9
  export const errorRoutePath = "/error";
10
10
 
11
+ export const mantaGQLPath = "/graphql";
12
+
13
+ export const switchDatastoreRoutePath = "/api/switch-datastore";
14
+
15
+ export const chatManagerBasePath = "agents/chat-manager";
16
+
17
+ export const forwardedOriginHeader = "x-manta-forwarded-origin";
18
+
19
+ export const authErrorParam = "auth_error";
20
+
11
21
  // Keycloak access tokens live 300s. Each login-status poll renews a token with at most
12
22
  // accessTokenRotationWindowMs left; window - poll (60s) absorbs background-tab timer throttling,
13
23
  // and renewing only past 180s of age keeps Keycloak refreshes to ~one per 3 min however many tabs poll.
@@ -20,3 +30,4 @@ export const memoryExtractionFlagKey = "memory-extraction-enabled";
20
30
  export const memoryAutoSupersedeFlagKey = "memory-auto-supersede-enabled";
21
31
  export const memoryReplayFlagKey = "memory-replay-enabled";
22
32
  export const memoryMaintenanceFlagKey = "memory-maintenance-enabled";
33
+ export const memoryAutoAssignFlagKey = "memory-auto-assign-enabled";
@@ -10,6 +10,12 @@ export const redirectRoutePath = "/redirect";
10
10
 
11
11
  export const imageRoutePath = "/image";
12
12
 
13
+ export const sparqlRoutePath = "/sparql";
14
+
15
+ export const uploadedFileRoutePath = "/agents/uploads/file";
16
+
17
+ export const uploadPartRoutePath = "/agents/uploads/part";
18
+
13
19
  export type DatastoreLocation = { datastoreId: string | undefined; path: string };
14
20
 
15
21
  const datastorePathPattern = new RegExp(`^${datastoreRoutePrefix}/([^/]+)(/.*)?$`);
@@ -0,0 +1 @@
1
+ export const signedOutLoginStatus = { valid: false, canSwitchDatastore: false, allowedModels: [] };
@@ -0,0 +1,16 @@
1
+ export const memorySchemaLimits = {
2
+ activeSchemas: 100,
3
+ properties: 20,
4
+ options: 50,
5
+ label: 80,
6
+ key: 50,
7
+ description: 1000,
8
+ extractionGuidance: 2000,
9
+ propertyDescription: 500,
10
+ optionValue: 100,
11
+ optionLabel: 100,
12
+ optionDescription: 300,
13
+ unit: 30,
14
+ pattern: 200,
15
+ maxLength: 10_000,
16
+ } as const;
@@ -0,0 +1,15 @@
1
+ import { RE2JS } from "re2js";
2
+
3
+ const compiledPatterns = new Map<string, RE2JS>();
4
+ const compiledPatternLimit = 500;
5
+
6
+ // RE2 matches in linear time, so an admin-authored pattern cannot stall a write on a long value. It lives apart from
7
+ // the other value checks because it is large: a browser loads it only where a pattern is checked.
8
+ export function compileMemoryValuePattern(pattern: string): RE2JS {
9
+ const cached = compiledPatterns.get(pattern);
10
+ if (cached) return cached;
11
+ const compiled = RE2JS.compile(pattern);
12
+ if (compiledPatterns.size >= compiledPatternLimit) compiledPatterns.clear();
13
+ compiledPatterns.set(pattern, compiled);
14
+ return compiled;
15
+ }
@@ -0,0 +1,280 @@
1
+ import { isPresent } from "@manta-eu/lib/present";
2
+ import { memorySchemaLimits } from "./memory-schema-limits";
3
+ import {
4
+ compareMemoryValues,
5
+ memorySchemaValueTypes,
6
+ memoryValueBoundTypes,
7
+ memoryValueConstraintViolation,
8
+ memoryValueTextTypes,
9
+ parseMemoryValue,
10
+ type CompileMemoryValuePattern,
11
+ type MemorySchemaValueType,
12
+ } from "./memory-schema-values";
13
+ import { isValidFullIri } from "./rdf-namespaces";
14
+
15
+ export type MemorySchemaOptionInput = {
16
+ value: string;
17
+ label?: string | null;
18
+ description?: string | null;
19
+ };
20
+
21
+ export type MemorySchemaPropertyInput = {
22
+ path?: string | null;
23
+ key?: string | null;
24
+ label: string;
25
+ description?: string | null;
26
+ valueType: MemorySchemaValueType;
27
+ entityClass?: string | null;
28
+ required?: boolean | null;
29
+ multiValued?: boolean | null;
30
+ keyProperty?: boolean | null;
31
+ computed?: boolean | null;
32
+ options?: readonly MemorySchemaOptionInput[] | null;
33
+ minValue?: string | null;
34
+ maxValue?: string | null;
35
+ maxLength?: number | null;
36
+ pattern?: string | null;
37
+ defaultValue?: string | null;
38
+ unit?: string | null;
39
+ };
40
+
41
+ export type MemorySchemaValidationError = { field: string; message: string };
42
+
43
+ export type MemorySchemaOption = { value: string; label: string | null; description: string | null };
44
+
45
+ export type CheckedMemorySchemaProperty = {
46
+ label: string;
47
+ description: string | null;
48
+ valueType: MemorySchemaValueType;
49
+ entityClass: string | null;
50
+ required: boolean;
51
+ multiValued: boolean;
52
+ keyProperty: boolean;
53
+ inferred: boolean;
54
+ options: MemorySchemaOption[];
55
+ allowedValues: string[];
56
+ minValue: string | null;
57
+ maxValue: string | null;
58
+ maxLength: number | null;
59
+ pattern: string | null;
60
+ defaultValue: string | null;
61
+ unit: string | null;
62
+ };
63
+
64
+ export type MemorySchemaPropertyCheck = {
65
+ errors: MemorySchemaValidationError[];
66
+ property: CheckedMemorySchemaProperty | null;
67
+ };
68
+
69
+ const propertyKeyPattern = /^[a-z][A-Za-z0-9]*$/;
70
+
71
+ function labelWords(label: string): string[] {
72
+ return label
73
+ .normalize("NFKD")
74
+ .replace(/[̀-ͯ]/g, "")
75
+ .split(/[^A-Za-z0-9]+/)
76
+ .filter(isPresent);
77
+ }
78
+
79
+ function capitalized(word: string): string {
80
+ return word.charAt(0).toUpperCase() + word.slice(1);
81
+ }
82
+
83
+ function withoutLeadingDigits(words: string[]): string[] {
84
+ const [first, ...rest] = words;
85
+ if (first === undefined) return [];
86
+ const stripped = first.replace(/^\d+/, "");
87
+ return isPresent(stripped) ? [stripped, ...rest] : withoutLeadingDigits(rest);
88
+ }
89
+
90
+ export function deriveMemorySchemaKey(label: string): string {
91
+ const words = withoutLeadingDigits(labelWords(label));
92
+ const withoutSuffix = words.at(-1)?.toLowerCase() === "memory" ? words.slice(0, -1) : words;
93
+ return withoutSuffix.map(capitalized).join("");
94
+ }
95
+
96
+ export function deriveMemoryPropertyKey(label: string): string {
97
+ const [first, ...rest] = withoutLeadingDigits(labelWords(label));
98
+ if (first === undefined) return "";
99
+ return [first.toLowerCase(), ...rest.map(capitalized)].join("");
100
+ }
101
+
102
+ export function memoryPropertyKeyProblem(key: string): string | null {
103
+ if (!propertyKeyPattern.test(key)) {
104
+ return "A property key starts with a lowercase letter and holds only letters and digits";
105
+ }
106
+ if (key.length > memorySchemaLimits.key) return `A property key must be at most ${memorySchemaLimits.key} characters`;
107
+ return null;
108
+ }
109
+
110
+ export function trimmedOrNull(value: string | null | undefined): string | null {
111
+ const trimmed = value?.trim() ?? "";
112
+ return isPresent(trimmed) ? trimmed : null;
113
+ }
114
+
115
+ type Add = (field: string, message: string) => void;
116
+
117
+ function checkLength(add: Add, field: string, value: string | null, max: number, name: string): void {
118
+ if (value !== null && [...value].length > max) add(field, `${name} must be at most ${max} characters`);
119
+ }
120
+
121
+ function checkOptions(add: Add, field: string, input: readonly MemorySchemaOptionInput[]): MemorySchemaOption[] {
122
+ if (input.length > memorySchemaLimits.options) {
123
+ add(field, `A property takes at most ${memorySchemaLimits.options} allowed values`);
124
+ }
125
+ const seen = new Set<string>();
126
+ return input.map((option, index) => {
127
+ const value = option.value.trim();
128
+ const label = trimmedOrNull(option.label);
129
+ const description = trimmedOrNull(option.description);
130
+ const optionField = `${field}.${index}`;
131
+ if (!isPresent(value)) add(`${optionField}.value`, "An allowed value cannot be empty");
132
+ if (seen.has(value)) add(`${optionField}.value`, `"${value}" is listed twice`);
133
+ seen.add(value);
134
+ checkLength(add, `${optionField}.value`, value, memorySchemaLimits.optionValue, "An allowed value");
135
+ checkLength(add, `${optionField}.label`, label, memorySchemaLimits.optionLabel, "An option label");
136
+ checkLength(
137
+ add,
138
+ `${optionField}.description`,
139
+ description,
140
+ memorySchemaLimits.optionDescription,
141
+ "An option description",
142
+ );
143
+ return { value, label, description };
144
+ });
145
+ }
146
+
147
+ function checkBound(
148
+ add: Add,
149
+ field: string,
150
+ valueType: MemorySchemaValueType,
151
+ raw: string | null | undefined,
152
+ ): string | null {
153
+ const trimmed = trimmedOrNull(raw);
154
+ if (trimmed === null) return null;
155
+ if (!memoryValueBoundTypes.includes(valueType)) {
156
+ add(field, "Only number, date and date-time properties take a minimum or maximum");
157
+ return null;
158
+ }
159
+ const parsed = parseMemoryValue(valueType, trimmed);
160
+ if (parsed === null) add(field, `"${trimmed}" is not a valid ${valueType} value`);
161
+ return parsed;
162
+ }
163
+
164
+ function isValueType(value: string): value is MemorySchemaValueType {
165
+ return memorySchemaValueTypes.some((valueType) => valueType === value);
166
+ }
167
+
168
+ export function checkMemorySchemaProperty(
169
+ input: Omit<MemorySchemaPropertyInput, "valueType"> & { valueType: string },
170
+ field: string,
171
+ compilePattern: CompileMemoryValuePattern | null,
172
+ ): MemorySchemaPropertyCheck {
173
+ const errors: MemorySchemaValidationError[] = [];
174
+ const add: Add = (at, message) => errors.push({ field: at, message });
175
+
176
+ const label = input.label.trim();
177
+ if (!isPresent(label)) add(`${field}.label`, "A property needs a label");
178
+ checkLength(add, `${field}.label`, label, memorySchemaLimits.label, "A property label");
179
+
180
+ if (!isValueType(input.valueType)) {
181
+ add(`${field}.valueType`, `Unknown value type ${String(input.valueType)}`);
182
+ return { errors, property: null };
183
+ }
184
+ const valueType = input.valueType;
185
+
186
+ const description = trimmedOrNull(input.description);
187
+ checkLength(add, `${field}.description`, description, memorySchemaLimits.propertyDescription, "A description");
188
+
189
+ const entityClass = trimmedOrNull(input.entityClass);
190
+ if (entityClass !== null && valueType !== "entity") {
191
+ add(`${field}.entityClass`, "Only an entity reference takes an entity class");
192
+ }
193
+ if (entityClass !== null && !isValidFullIri(entityClass)) {
194
+ add(`${field}.entityClass`, "The entity class must be a full IRI");
195
+ }
196
+
197
+ const multiValued = input.multiValued === true;
198
+ const keyProperty = input.keyProperty === true;
199
+ const inferred = input.computed === true;
200
+ const required = input.required === true;
201
+ if (keyProperty && multiValued) add(`${field}.keyProperty`, "A key property must hold a single value");
202
+ if (keyProperty && valueType === "longText") add(`${field}.keyProperty`, "Long text cannot be a key property");
203
+ if (keyProperty && inferred) add(`${field}.keyProperty`, "A computed property cannot be a key property");
204
+ if (required && inferred) add(`${field}.required`, "A computed property cannot be required");
205
+
206
+ const options = checkOptions(add, `${field}.options`, input.options ?? []);
207
+ if (isPresent(options) && valueType !== "text") {
208
+ add(`${field}.options`, "Only text properties take a list of allowed values");
209
+ }
210
+
211
+ const minValue = checkBound(add, `${field}.minValue`, valueType, input.minValue);
212
+ const maxValue = checkBound(add, `${field}.maxValue`, valueType, input.maxValue);
213
+ if (minValue !== null && maxValue !== null && compareMemoryValues(valueType, minValue, maxValue) > 0) {
214
+ add(`${field}.maxValue`, "The maximum must not be below the minimum");
215
+ }
216
+
217
+ const takesLength = [...memoryValueTextTypes, "url"].includes(valueType);
218
+ const maxLength = input.maxLength ?? null;
219
+ if (maxLength !== null) {
220
+ if (!takesLength) {
221
+ add(`${field}.maxLength`, "Only text and URL properties take a maximum length");
222
+ } else if (!Number.isInteger(maxLength) || maxLength < 1 || maxLength > memorySchemaLimits.maxLength) {
223
+ add(`${field}.maxLength`, `The maximum length must be between 1 and ${memorySchemaLimits.maxLength}`);
224
+ }
225
+ }
226
+
227
+ const pattern = trimmedOrNull(input.pattern);
228
+ if (pattern !== null) {
229
+ checkLength(add, `${field}.pattern`, pattern, memorySchemaLimits.pattern, "A pattern");
230
+ if (!memoryValueTextTypes.includes(valueType)) {
231
+ add(`${field}.pattern`, "Only text properties take a pattern");
232
+ } else if (compilePattern !== null) {
233
+ try {
234
+ compilePattern(pattern);
235
+ } catch {
236
+ add(`${field}.pattern`, "The pattern is not a valid regular expression");
237
+ }
238
+ }
239
+ }
240
+
241
+ const unit = trimmedOrNull(input.unit);
242
+ checkLength(add, `${field}.unit`, unit, memorySchemaLimits.unit, "A unit");
243
+ if (unit !== null && valueType !== "integer" && valueType !== "decimal") {
244
+ add(`${field}.unit`, "Only number properties take a unit");
245
+ }
246
+
247
+ const property: CheckedMemorySchemaProperty = {
248
+ label,
249
+ description,
250
+ valueType,
251
+ entityClass: valueType === "entity" ? entityClass : null,
252
+ required,
253
+ multiValued,
254
+ keyProperty,
255
+ inferred,
256
+ options,
257
+ allowedValues: options.map((option) => option.value),
258
+ minValue,
259
+ maxValue,
260
+ maxLength: takesLength ? maxLength : null,
261
+ pattern,
262
+ defaultValue: null,
263
+ unit,
264
+ };
265
+
266
+ const rawDefault = trimmedOrNull(input.defaultValue);
267
+ if (rawDefault !== null) {
268
+ if (inferred) {
269
+ add(`${field}.defaultValue`, "A computed property cannot have a default value");
270
+ } else {
271
+ const parsed = parseMemoryValue(valueType, rawDefault);
272
+ const violation = parsed === null ? null : memoryValueConstraintViolation(property, parsed, compilePattern);
273
+ if (parsed === null) add(`${field}.defaultValue`, `"${rawDefault}" is not a valid ${valueType} value`);
274
+ else if (violation !== null) add(`${field}.defaultValue`, `The default value ${violation}`);
275
+ else property.defaultValue = parsed;
276
+ }
277
+ }
278
+
279
+ return { errors, property };
280
+ }