@opengeni/db 0.31.1 → 0.36.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/dist/browser-auth.d.ts +209 -1
- package/dist/browser-downloads.d.ts +51 -0
- package/dist/browser-identities.d.ts +11 -2
- package/dist/browser-sessions.d.ts +83 -1
- package/dist/browser-state-artifacts.d.ts +75 -1
- package/dist/canonical-human-identities.d.ts +48 -0
- package/dist/canonical-human-identities.js +28 -0
- package/dist/canonical-human-identities.js.map +1 -0
- package/dist/capability-integrations.d.ts +8 -6
- package/dist/{chunk-MWDVXQOL.js → chunk-5KTIEDX7.js} +5773 -4212
- package/dist/chunk-5KTIEDX7.js.map +1 -0
- package/dist/{chunk-NBE6CHRI.js → chunk-CQZ4QSP5.js} +49 -9
- package/dist/chunk-CQZ4QSP5.js.map +1 -0
- package/dist/chunk-F32YT7MP.js +117 -0
- package/dist/chunk-F32YT7MP.js.map +1 -0
- package/dist/{chunk-ISI2TIUG.js → chunk-JC5QPLUM.js} +30 -3
- package/dist/chunk-JC5QPLUM.js.map +1 -0
- package/dist/{chunk-F5FT7BEZ.js → chunk-P3RE4D2B.js} +2 -2
- package/dist/chunk-TAUTWOS5.js +259 -0
- package/dist/chunk-TAUTWOS5.js.map +1 -0
- package/dist/{chunk-YHZXQ7HP.js → chunk-VKLB2ZGI.js} +446 -19
- package/dist/chunk-VKLB2ZGI.js.map +1 -0
- package/dist/database.d.ts +5 -0
- package/dist/editable-artifact-durable-export.js +2 -2
- package/dist/editable-artifacts.js +3 -3
- package/dist/index.d.ts +438 -29
- package/dist/index.js +35640 -28969
- package/dist/index.js.map +1 -1
- package/dist/insights.d.ts +23 -7
- package/dist/integration-bindings.d.ts +24 -24
- package/dist/integration-facets.d.ts +99 -0
- package/dist/interaction-revisions.d.ts +11 -0
- package/dist/interaction-schema.d.ts +698 -34
- package/dist/provision-roles.js +1 -1
- package/dist/runtime-posture.d.ts +8 -7
- package/dist/schema.d.ts +9464 -5412
- package/dist/schema.js +51 -9
- package/dist/session-control.d.ts +29 -3
- package/dist/session-tenancy.d.ts +44 -0
- package/dist/session-tenancy.js +16 -0
- package/dist/session-tenancy.js.map +1 -0
- package/dist/slack-task-policy-schema.d.ts +847 -0
- package/dist/slack-task-policy.d.ts +65 -0
- package/dist/task-notes-schema.d.ts +924 -0
- package/dist/task-notes.d.ts +85 -0
- package/dist/video-generation.d.ts +9 -0
- package/dist/video-generation.js +5 -3
- package/dist/xai-subscription.d.ts +326 -0
- package/drizzle/0212_browser_state_transfer_hardening.sql +560 -0
- package/drizzle/0213_browser_interaction_authority.sql +67 -0
- package/drizzle/0214_browser_download_saves.sql +34 -0
- package/drizzle/0215_browser_controller_host.sql +385 -0
- package/drizzle/0216_browser_auth_health_evidence.sql +137 -0
- package/drizzle/0217_external_browser_auth_operations.sql +22 -0
- package/drizzle/0218_organization_tenancy_foundation.sql +299 -0
- package/drizzle/0219_organization_tenancy_managed_human_provisioning.sql +317 -0
- package/drizzle/0219_site_auth_maintenance_sessions.sql +234 -0
- package/drizzle/0220_memory_slack_append_only_cascade.sql +38 -0
- package/drizzle/0220_session_channels.sql +54 -0
- package/drizzle/0221_sessions_channel_index.sql +5 -0
- package/drizzle/0222_session_visibility_authority_epochs.sql +158 -0
- package/drizzle/0222_sessions_channel_fk.sql +89 -0
- package/drizzle/0223_pending_tool_event_output.sql +55 -0
- package/drizzle/0223_sessions_channel_fk_validate.sql +118 -0
- package/drizzle/0224_slack_post_outcome_reconciliation.sql +123 -0
- package/drizzle/0225_session_visibility_fork_activation.sql +1363 -0
- package/drizzle/0226_personal_codex_authority_foundation.sql +365 -0
- package/drizzle/0227_slack_native_actions.sql +145 -0
- package/drizzle/0228_interaction_controller_data_plane.sql +14 -0
- package/drizzle/0228_slack_task_policy.sql +400 -0
- package/drizzle/0229_slack_inbox_file_fact.sql +10 -0
- package/drizzle/0230_user_scoped_variable_sets_rigs.sql +84 -0
- package/drizzle/0231_integration_definition_identity_cutover.sql +271 -0
- package/drizzle/0232_integration_facet_authority_cutover.sql +610 -0
- package/drizzle/0233_skill_and_integration_authority_cutover.sql +1162 -0
- package/drizzle/0234_xai_subscription_authority.sql +1139 -0
- package/drizzle/0235_canonical_human_login_bindings.sql +920 -0
- package/drizzle/0236_browser_identity_lifecycle.sql +39 -0
- package/drizzle/0236_session_visibility_slack_policy.sql +72 -0
- package/drizzle/0237_interaction_transition_reaper.sql +263 -0
- package/drizzle/0238_goal_persistence_policy.sql +471 -0
- package/drizzle/0238_supergrok_realtime_model.sql +29 -0
- package/drizzle/0239_supergrok_video_funding.sql +50 -0
- package/drizzle/0239_task_tree_notes.sql +990 -0
- package/package.json +13 -5
- package/src/browser-auth.ts +2600 -123
- package/src/browser-downloads.ts +517 -0
- package/src/browser-identities.ts +220 -3
- package/src/browser-sessions.ts +334 -45
- package/src/browser-state-artifacts.ts +402 -12
- package/src/canonical-human-identities.ts +317 -0
- package/src/capability-integrations.ts +121 -213
- package/src/database.ts +41 -1
- package/src/index.ts +4157 -394
- package/src/insights.ts +109 -28
- package/src/integration-bindings.ts +101 -101
- package/src/{integration-features.ts → integration-facets.ts} +187 -184
- package/src/interaction-revisions.ts +33 -3
- package/src/interaction-schema.ts +311 -8
- package/src/pack-components.ts +43 -43
- package/src/pack-installations.ts +0 -43
- package/src/plugin-packages.ts +9 -9
- package/src/provision-roles.ts +232 -0
- package/src/runtime-posture.ts +227 -14
- package/src/schema.ts +1188 -75
- package/src/session-control.ts +122 -37
- package/src/session-queue-commands.ts +78 -1
- package/src/session-tenancy.ts +188 -0
- package/src/session-tool-call-settlement.ts +9 -3
- package/src/slack-task-policy-schema.ts +130 -0
- package/src/slack-task-policy.ts +341 -0
- package/src/task-notes-schema.ts +135 -0
- package/src/task-notes.ts +178 -0
- package/src/video-generation.ts +90 -12
- package/src/workspace-artifacts.ts +1 -1
- package/src/xai-subscription.ts +1887 -0
- package/dist/chunk-ISI2TIUG.js.map +0 -1
- package/dist/chunk-MWDVXQOL.js.map +0 -1
- package/dist/chunk-NBE6CHRI.js.map +0 -1
- package/dist/chunk-YHZXQ7HP.js.map +0 -1
- package/dist/integration-features.d.ts +0 -99
- /package/dist/{chunk-F5FT7BEZ.js.map → chunk-P3RE4D2B.js.map} +0 -0
|
@@ -10,24 +10,24 @@ import {
|
|
|
10
10
|
type Database,
|
|
11
11
|
} from "./database";
|
|
12
12
|
import {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
13
|
+
IntegrationFacetBindingOwnershipConflictError,
|
|
14
|
+
IntegrationFacetBindingVersionConflictError,
|
|
15
|
+
listIntegrationFacetBindingOwners,
|
|
16
|
+
removeIntegrationFacetBindingOwner,
|
|
17
|
+
upsertIntegrationFacetBinding,
|
|
18
18
|
} from "./integration-bindings";
|
|
19
19
|
import * as schema from "./schema";
|
|
20
20
|
|
|
21
|
-
export type
|
|
21
|
+
export type IntegrationFacetKind =
|
|
22
22
|
| "knowledge_source"
|
|
23
23
|
| "inbound_trigger"
|
|
24
24
|
| "delivery_destination"
|
|
25
25
|
| "identity_link";
|
|
26
26
|
|
|
27
|
-
export type
|
|
27
|
+
export type IntegrationFacetBindingSummary = {
|
|
28
28
|
id: string;
|
|
29
|
-
|
|
30
|
-
kind:
|
|
29
|
+
facetKey: string;
|
|
30
|
+
kind: IntegrationFacetKind;
|
|
31
31
|
bindingKey: string;
|
|
32
32
|
displayName: string;
|
|
33
33
|
connectionId: string | null;
|
|
@@ -41,38 +41,38 @@ export type IntegrationFeatureBindingSummary = {
|
|
|
41
41
|
updatedAt: string;
|
|
42
42
|
};
|
|
43
43
|
|
|
44
|
-
export type
|
|
45
|
-
|
|
46
|
-
kind:
|
|
44
|
+
export type IntegrationFacetDefinitionSummary = {
|
|
45
|
+
facetKey: string;
|
|
46
|
+
kind: IntegrationFacetKind;
|
|
47
47
|
configSchema: Record<string, unknown>;
|
|
48
48
|
capabilities: Record<string, unknown>;
|
|
49
49
|
};
|
|
50
50
|
|
|
51
|
-
export type
|
|
51
|
+
export type IntegrationInstanceFacets = {
|
|
52
52
|
capabilityId: string;
|
|
53
53
|
instanceKey: string;
|
|
54
54
|
providerDomain: string;
|
|
55
55
|
connectionId: string | null;
|
|
56
|
-
|
|
57
|
-
definition:
|
|
58
|
-
binding:
|
|
56
|
+
facets: {
|
|
57
|
+
definition: IntegrationFacetDefinitionSummary;
|
|
58
|
+
binding: IntegrationFacetBindingSummary | null;
|
|
59
59
|
}[];
|
|
60
60
|
};
|
|
61
61
|
|
|
62
|
-
export type
|
|
62
|
+
export type IntegrationFacetMutationResult = {
|
|
63
63
|
capabilityId: string;
|
|
64
64
|
instanceKey: string;
|
|
65
|
-
|
|
65
|
+
facetKey: string;
|
|
66
66
|
status: "configured" | "paused" | "active";
|
|
67
|
-
binding:
|
|
67
|
+
binding: IntegrationFacetBindingSummary;
|
|
68
68
|
};
|
|
69
69
|
|
|
70
|
-
export type
|
|
70
|
+
export type IntegrationFacetRemovalResult = {
|
|
71
71
|
capabilityId: string;
|
|
72
72
|
instanceKey: string;
|
|
73
|
-
|
|
73
|
+
facetKey: string;
|
|
74
74
|
status: "not_configured" | "removed" | "retained_by_other_owners";
|
|
75
|
-
binding:
|
|
75
|
+
binding: IntegrationFacetBindingSummary | null;
|
|
76
76
|
remainingOwners: {
|
|
77
77
|
kind: "direct" | "plugin" | "pack" | "migration";
|
|
78
78
|
id: string;
|
|
@@ -80,20 +80,20 @@ export type IntegrationFeatureRemovalResult = {
|
|
|
80
80
|
}[];
|
|
81
81
|
};
|
|
82
82
|
|
|
83
|
-
export class
|
|
84
|
-
readonly name = "
|
|
83
|
+
export class IntegrationFacetNotFoundError extends Error {
|
|
84
|
+
readonly name = "IntegrationFacetNotFoundError";
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
-
export class
|
|
88
|
-
readonly name = "
|
|
87
|
+
export class IntegrationFacetConnectionError extends Error {
|
|
88
|
+
readonly name = "IntegrationFacetConnectionError";
|
|
89
89
|
}
|
|
90
90
|
|
|
91
|
-
export class
|
|
92
|
-
readonly name = "
|
|
91
|
+
export class IntegrationFacetConfigError extends Error {
|
|
92
|
+
readonly name = "IntegrationFacetConfigError";
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
-
export class
|
|
96
|
-
readonly name = "
|
|
95
|
+
export class IntegrationFacetOperationIdempotencyError extends Error {
|
|
96
|
+
readonly name = "IntegrationFacetOperationIdempotencyError";
|
|
97
97
|
}
|
|
98
98
|
|
|
99
99
|
type IntegrationInstanceContext = {
|
|
@@ -104,13 +104,13 @@ type IntegrationInstanceContext = {
|
|
|
104
104
|
connectionId: string | null;
|
|
105
105
|
};
|
|
106
106
|
|
|
107
|
-
export async function
|
|
107
|
+
export async function listIntegrationInstanceFacets(
|
|
108
108
|
db: Database,
|
|
109
109
|
workspaceId: string,
|
|
110
110
|
subjectId: string,
|
|
111
111
|
capabilityId: string,
|
|
112
112
|
instanceKey: string,
|
|
113
|
-
): Promise<
|
|
113
|
+
): Promise<IntegrationInstanceFacets> {
|
|
114
114
|
return await withWorkspaceSubjectRls(db, workspaceId, subjectId, async (scopedDb) => {
|
|
115
115
|
const context = await loadIntegrationInstanceContext(
|
|
116
116
|
scopedDb,
|
|
@@ -119,64 +119,67 @@ export async function listIntegrationInstanceFeatures(
|
|
|
119
119
|
capabilityId,
|
|
120
120
|
instanceKey,
|
|
121
121
|
);
|
|
122
|
-
if (!context) throw new
|
|
122
|
+
if (!context) throw new IntegrationFacetNotFoundError("Integration instance not found");
|
|
123
123
|
const rows = await scopedDb
|
|
124
124
|
.select({
|
|
125
|
-
|
|
126
|
-
kind: schema.
|
|
127
|
-
configSchema: schema.
|
|
128
|
-
capabilities: schema.
|
|
129
|
-
bindingId: schema.
|
|
130
|
-
bindingKey: schema.
|
|
131
|
-
displayName: schema.
|
|
132
|
-
connectionId: schema.
|
|
133
|
-
status: schema.
|
|
134
|
-
config: schema.
|
|
135
|
-
cursor: schema.
|
|
136
|
-
version: schema.
|
|
137
|
-
lastSuccessAt: schema.
|
|
138
|
-
lastErrorCode: schema.
|
|
139
|
-
createdAt: schema.
|
|
140
|
-
updatedAt: schema.
|
|
125
|
+
facetKey: schema.integrationFacetDefinitions.facetKey,
|
|
126
|
+
kind: schema.integrationFacetDefinitions.kind,
|
|
127
|
+
configSchema: schema.integrationFacetDefinitions.configSchema,
|
|
128
|
+
capabilities: schema.integrationFacetDefinitions.capabilities,
|
|
129
|
+
bindingId: schema.integrationFacetBindings.id,
|
|
130
|
+
bindingKey: schema.integrationFacetBindings.bindingKey,
|
|
131
|
+
displayName: schema.integrationFacetBindings.displayName,
|
|
132
|
+
connectionId: schema.integrationFacetBindings.connectionId,
|
|
133
|
+
status: schema.integrationFacetBindings.status,
|
|
134
|
+
config: schema.integrationFacetBindings.config,
|
|
135
|
+
cursor: schema.integrationFacetBindings.cursor,
|
|
136
|
+
version: schema.integrationFacetBindings.version,
|
|
137
|
+
lastSuccessAt: schema.integrationFacetBindings.lastSuccessAt,
|
|
138
|
+
lastErrorCode: schema.integrationFacetBindings.lastErrorCode,
|
|
139
|
+
createdAt: schema.integrationFacetBindings.createdAt,
|
|
140
|
+
updatedAt: schema.integrationFacetBindings.updatedAt,
|
|
141
141
|
})
|
|
142
|
-
.from(schema.
|
|
142
|
+
.from(schema.integrationFacetDefinitions)
|
|
143
143
|
.leftJoin(
|
|
144
|
-
schema.
|
|
144
|
+
schema.integrationFacetBindings,
|
|
145
145
|
and(
|
|
146
|
-
eq(schema.integrationFeatureBindings.featureFacetId, schema.integrationFeatureFacets.id),
|
|
147
146
|
eq(
|
|
148
|
-
schema.
|
|
147
|
+
schema.integrationFacetBindings.facetDefinitionId,
|
|
148
|
+
schema.integrationFacetDefinitions.id,
|
|
149
|
+
),
|
|
150
|
+
eq(
|
|
151
|
+
schema.integrationFacetBindings.integrationFacetInstallationId,
|
|
149
152
|
context.integrationFacetInstallationId,
|
|
150
153
|
),
|
|
151
|
-
eq(schema.
|
|
154
|
+
eq(schema.integrationFacetBindings.bindingKey, instanceKey),
|
|
152
155
|
),
|
|
153
156
|
)
|
|
154
157
|
.where(
|
|
155
158
|
and(
|
|
156
|
-
eq(schema.
|
|
157
|
-
ne(schema.
|
|
159
|
+
eq(schema.integrationFacetDefinitions.integrationFacetId, context.integrationFacetId),
|
|
160
|
+
ne(schema.integrationFacetDefinitions.kind, "tools"),
|
|
158
161
|
),
|
|
159
162
|
)
|
|
160
163
|
.orderBy(
|
|
161
|
-
asc(schema.
|
|
162
|
-
asc(schema.
|
|
164
|
+
asc(schema.integrationFacetDefinitions.kind),
|
|
165
|
+
asc(schema.integrationFacetDefinitions.facetKey),
|
|
163
166
|
);
|
|
164
167
|
return {
|
|
165
168
|
capabilityId,
|
|
166
169
|
instanceKey,
|
|
167
170
|
providerDomain: context.providerDomain,
|
|
168
171
|
connectionId: context.connectionId,
|
|
169
|
-
|
|
172
|
+
facets: rows.map((row) => ({
|
|
170
173
|
definition: {
|
|
171
|
-
|
|
172
|
-
kind:
|
|
174
|
+
facetKey: row.facetKey,
|
|
175
|
+
kind: facetKind(row.kind),
|
|
173
176
|
configSchema: row.configSchema,
|
|
174
177
|
capabilities: row.capabilities,
|
|
175
178
|
},
|
|
176
179
|
binding: row.bindingId
|
|
177
180
|
? bindingSummary({
|
|
178
181
|
id: row.bindingId,
|
|
179
|
-
|
|
182
|
+
facetKey: row.facetKey,
|
|
180
183
|
kind: row.kind,
|
|
181
184
|
bindingKey: row.bindingKey!,
|
|
182
185
|
displayName: row.displayName!,
|
|
@@ -196,7 +199,7 @@ export async function listIntegrationInstanceFeatures(
|
|
|
196
199
|
});
|
|
197
200
|
}
|
|
198
201
|
|
|
199
|
-
export async function
|
|
202
|
+
export async function configureIntegrationFacet(
|
|
200
203
|
db: Database,
|
|
201
204
|
input: {
|
|
202
205
|
accountId: string;
|
|
@@ -204,58 +207,58 @@ export async function configureIntegrationFeature(
|
|
|
204
207
|
subjectId: string;
|
|
205
208
|
capabilityId: string;
|
|
206
209
|
instanceKey: string;
|
|
207
|
-
|
|
210
|
+
facetKey: string;
|
|
208
211
|
displayName: string;
|
|
209
212
|
config: Record<string, unknown>;
|
|
210
213
|
expectedVersion?: number;
|
|
211
214
|
idempotencyKey: string;
|
|
212
215
|
},
|
|
213
|
-
): Promise<
|
|
216
|
+
): Promise<IntegrationFacetMutationResult> {
|
|
214
217
|
const requestDigest = sha256(
|
|
215
218
|
stableJson({
|
|
216
219
|
action: "configure",
|
|
217
220
|
capabilityId: input.capabilityId,
|
|
218
221
|
instanceKey: input.instanceKey,
|
|
219
|
-
|
|
222
|
+
facetKey: input.facetKey,
|
|
220
223
|
displayName: input.displayName,
|
|
221
224
|
config: input.config,
|
|
222
225
|
expectedVersion: input.expectedVersion ?? null,
|
|
223
226
|
}),
|
|
224
227
|
);
|
|
225
|
-
return await
|
|
228
|
+
return await withFacetOperation(db, input, requestDigest, "configure", async (tx) => {
|
|
226
229
|
const context = await requireMutationContext(tx, input);
|
|
227
|
-
const definition = await
|
|
228
|
-
|
|
229
|
-
await
|
|
230
|
-
const result = await
|
|
230
|
+
const definition = await requireFacetDefinition(tx, context, input.facetKey);
|
|
231
|
+
assertFacetConfig(input.config, definition.configSchema);
|
|
232
|
+
await requireFacetConnection(tx, input, context, definition.capabilities);
|
|
233
|
+
const result = await upsertIntegrationFacetBinding(tx, {
|
|
231
234
|
accountId: input.accountId,
|
|
232
235
|
workspaceId: input.workspaceId,
|
|
233
236
|
integrationFacetInstallationId: context.integrationFacetInstallationId,
|
|
234
|
-
|
|
237
|
+
facetDefinitionId: definition.id,
|
|
235
238
|
bindingKey: input.instanceKey,
|
|
236
239
|
displayName: input.displayName,
|
|
237
240
|
runtimeKey: null,
|
|
238
241
|
connectionId: context.connectionId,
|
|
239
242
|
config: input.config,
|
|
240
243
|
createdBySubjectId: input.subjectId,
|
|
241
|
-
owner:
|
|
244
|
+
owner: facetOwner(input.capabilityId, input.instanceKey, input.facetKey),
|
|
242
245
|
...(input.expectedVersion !== undefined ? { expectedVersion: input.expectedVersion } : {}),
|
|
243
246
|
});
|
|
244
247
|
return {
|
|
245
248
|
capabilityId: input.capabilityId,
|
|
246
249
|
instanceKey: input.instanceKey,
|
|
247
|
-
|
|
250
|
+
facetKey: input.facetKey,
|
|
248
251
|
status: "configured",
|
|
249
252
|
binding: bindingSummary({
|
|
250
253
|
...result.row,
|
|
251
|
-
|
|
254
|
+
facetKey: definition.facetKey,
|
|
252
255
|
kind: definition.kind,
|
|
253
256
|
}),
|
|
254
257
|
};
|
|
255
258
|
});
|
|
256
259
|
}
|
|
257
260
|
|
|
258
|
-
export async function
|
|
261
|
+
export async function setIntegrationFacetLifecycle(
|
|
259
262
|
db: Database,
|
|
260
263
|
input: {
|
|
261
264
|
accountId: string;
|
|
@@ -263,12 +266,12 @@ export async function setIntegrationFeatureLifecycle(
|
|
|
263
266
|
subjectId: string;
|
|
264
267
|
capabilityId: string;
|
|
265
268
|
instanceKey: string;
|
|
266
|
-
|
|
269
|
+
facetKey: string;
|
|
267
270
|
action: "pause" | "resume";
|
|
268
271
|
expectedVersion: number;
|
|
269
272
|
idempotencyKey: string;
|
|
270
273
|
},
|
|
271
|
-
): Promise<
|
|
274
|
+
): Promise<IntegrationFacetMutationResult> {
|
|
272
275
|
const requestDigest = sha256(
|
|
273
276
|
stableJson({
|
|
274
277
|
...input,
|
|
@@ -278,52 +281,52 @@ export async function setIntegrationFeatureLifecycle(
|
|
|
278
281
|
idempotencyKey: undefined,
|
|
279
282
|
}),
|
|
280
283
|
);
|
|
281
|
-
return await
|
|
284
|
+
return await withFacetOperation(db, input, requestDigest, "update", async (tx) => {
|
|
282
285
|
const context = await requireMutationContext(tx, input);
|
|
283
|
-
const definition = await
|
|
284
|
-
const binding = await
|
|
286
|
+
const definition = await requireFacetDefinition(tx, context, input.facetKey);
|
|
287
|
+
const binding = await loadFacetBinding(tx, context, input.instanceKey, definition.id, true);
|
|
285
288
|
if (!binding || binding.status === "disabled") {
|
|
286
|
-
throw new
|
|
289
|
+
throw new IntegrationFacetNotFoundError("Integration facet is not configured");
|
|
287
290
|
}
|
|
288
291
|
if (binding.version !== input.expectedVersion) {
|
|
289
|
-
throw new
|
|
292
|
+
throw new IntegrationFacetBindingVersionConflictError(
|
|
290
293
|
input.instanceKey,
|
|
291
294
|
input.expectedVersion,
|
|
292
295
|
binding.version,
|
|
293
296
|
);
|
|
294
297
|
}
|
|
295
|
-
await
|
|
298
|
+
await assertDirectFacetOwnership(tx, binding.id, input);
|
|
296
299
|
const targetStatus = input.action === "pause" ? "paused" : "active";
|
|
297
300
|
let row = binding;
|
|
298
301
|
if (binding.status !== targetStatus) {
|
|
299
302
|
const [updated] = await tx
|
|
300
|
-
.update(schema.
|
|
303
|
+
.update(schema.integrationFacetBindings)
|
|
301
304
|
.set({
|
|
302
305
|
status: targetStatus,
|
|
303
306
|
version: binding.version + 1,
|
|
304
307
|
...(input.action === "resume" ? { lastErrorCode: null } : {}),
|
|
305
308
|
updatedAt: new Date(),
|
|
306
309
|
})
|
|
307
|
-
.where(eq(schema.
|
|
310
|
+
.where(eq(schema.integrationFacetBindings.id, binding.id))
|
|
308
311
|
.returning();
|
|
309
|
-
if (!updated) throw new Error("Failed to update Integration
|
|
312
|
+
if (!updated) throw new Error("Failed to update Integration facet lifecycle");
|
|
310
313
|
row = updated;
|
|
311
314
|
}
|
|
312
315
|
return {
|
|
313
316
|
capabilityId: input.capabilityId,
|
|
314
317
|
instanceKey: input.instanceKey,
|
|
315
|
-
|
|
318
|
+
facetKey: input.facetKey,
|
|
316
319
|
status: input.action === "pause" ? "paused" : "active",
|
|
317
320
|
binding: bindingSummary({
|
|
318
321
|
...row,
|
|
319
|
-
|
|
322
|
+
facetKey: definition.facetKey,
|
|
320
323
|
kind: definition.kind,
|
|
321
324
|
}),
|
|
322
325
|
};
|
|
323
326
|
});
|
|
324
327
|
}
|
|
325
328
|
|
|
326
|
-
export async function
|
|
329
|
+
export async function removeIntegrationFacet(
|
|
327
330
|
db: Database,
|
|
328
331
|
input: {
|
|
329
332
|
accountId: string;
|
|
@@ -331,58 +334,58 @@ export async function removeIntegrationFeature(
|
|
|
331
334
|
subjectId: string;
|
|
332
335
|
capabilityId: string;
|
|
333
336
|
instanceKey: string;
|
|
334
|
-
|
|
337
|
+
facetKey: string;
|
|
335
338
|
expectedVersion: number;
|
|
336
339
|
idempotencyKey: string;
|
|
337
340
|
},
|
|
338
|
-
): Promise<
|
|
341
|
+
): Promise<IntegrationFacetRemovalResult> {
|
|
339
342
|
const requestDigest = sha256(
|
|
340
343
|
stableJson({
|
|
341
344
|
action: "remove",
|
|
342
345
|
capabilityId: input.capabilityId,
|
|
343
346
|
instanceKey: input.instanceKey,
|
|
344
|
-
|
|
347
|
+
facetKey: input.facetKey,
|
|
345
348
|
expectedVersion: input.expectedVersion,
|
|
346
349
|
}),
|
|
347
350
|
);
|
|
348
|
-
return await
|
|
351
|
+
return await withFacetOperation(db, input, requestDigest, "disconnect", async (tx) => {
|
|
349
352
|
const context = await requireMutationContext(tx, input);
|
|
350
|
-
const definition = await
|
|
351
|
-
const binding = await
|
|
352
|
-
const owner =
|
|
353
|
+
const definition = await requireFacetDefinition(tx, context, input.facetKey);
|
|
354
|
+
const binding = await loadFacetBinding(tx, context, input.instanceKey, definition.id, true);
|
|
355
|
+
const owner = facetOwner(input.capabilityId, input.instanceKey, input.facetKey);
|
|
353
356
|
if (!binding) {
|
|
354
357
|
return {
|
|
355
358
|
capabilityId: input.capabilityId,
|
|
356
359
|
instanceKey: input.instanceKey,
|
|
357
|
-
|
|
360
|
+
facetKey: input.facetKey,
|
|
358
361
|
status: "not_configured",
|
|
359
362
|
binding: null,
|
|
360
363
|
remainingOwners: [],
|
|
361
364
|
};
|
|
362
365
|
}
|
|
363
366
|
if (binding.version !== input.expectedVersion) {
|
|
364
|
-
throw new
|
|
367
|
+
throw new IntegrationFacetBindingVersionConflictError(
|
|
365
368
|
input.instanceKey,
|
|
366
369
|
input.expectedVersion,
|
|
367
370
|
binding.version,
|
|
368
371
|
);
|
|
369
372
|
}
|
|
370
|
-
const owners = await
|
|
373
|
+
const owners = await listIntegrationFacetBindingOwners(tx, binding.id);
|
|
371
374
|
if (!owners.some((candidate) => candidate.kind === owner.kind && candidate.id === owner.id)) {
|
|
372
375
|
return {
|
|
373
376
|
capabilityId: input.capabilityId,
|
|
374
377
|
instanceKey: input.instanceKey,
|
|
375
|
-
|
|
378
|
+
facetKey: input.facetKey,
|
|
376
379
|
status: "not_configured",
|
|
377
380
|
binding: bindingSummary({
|
|
378
381
|
...binding,
|
|
379
|
-
|
|
382
|
+
facetKey: definition.facetKey,
|
|
380
383
|
kind: definition.kind,
|
|
381
384
|
}),
|
|
382
385
|
remainingOwners: owners,
|
|
383
386
|
};
|
|
384
387
|
}
|
|
385
|
-
const removed = await
|
|
388
|
+
const removed = await removeIntegrationFacetBindingOwner(tx, {
|
|
386
389
|
workspaceId: input.workspaceId,
|
|
387
390
|
bindingId: binding.id,
|
|
388
391
|
owner,
|
|
@@ -391,12 +394,12 @@ export async function removeIntegrationFeature(
|
|
|
391
394
|
return {
|
|
392
395
|
capabilityId: input.capabilityId,
|
|
393
396
|
instanceKey: input.instanceKey,
|
|
394
|
-
|
|
397
|
+
facetKey: input.facetKey,
|
|
395
398
|
status: removed.remainingOwners.length > 0 ? "retained_by_other_owners" : "removed",
|
|
396
399
|
binding: removed.binding
|
|
397
400
|
? bindingSummary({
|
|
398
401
|
...removed.binding,
|
|
399
|
-
|
|
402
|
+
facetKey: definition.facetKey,
|
|
400
403
|
kind: definition.kind,
|
|
401
404
|
})
|
|
402
405
|
: null,
|
|
@@ -405,7 +408,7 @@ export async function removeIntegrationFeature(
|
|
|
405
408
|
});
|
|
406
409
|
}
|
|
407
410
|
|
|
408
|
-
async function
|
|
411
|
+
async function withFacetOperation<T extends Record<string, unknown>>(
|
|
409
412
|
db: Database,
|
|
410
413
|
input: {
|
|
411
414
|
accountId: string;
|
|
@@ -413,7 +416,7 @@ async function withFeatureOperation<T extends Record<string, unknown>>(
|
|
|
413
416
|
subjectId: string;
|
|
414
417
|
capabilityId: string;
|
|
415
418
|
instanceKey: string;
|
|
416
|
-
|
|
419
|
+
facetKey: string;
|
|
417
420
|
idempotencyKey: string;
|
|
418
421
|
},
|
|
419
422
|
requestDigest: string,
|
|
@@ -443,13 +446,13 @@ async function withFeatureOperation<T extends Record<string, unknown>>(
|
|
|
443
446
|
.limit(1);
|
|
444
447
|
if (existing) {
|
|
445
448
|
if (existing.requestDigest !== requestDigest) {
|
|
446
|
-
throw new
|
|
447
|
-
"Integration
|
|
449
|
+
throw new IntegrationFacetOperationIdempotencyError(
|
|
450
|
+
"Integration facet idempotency key was reused",
|
|
448
451
|
);
|
|
449
452
|
}
|
|
450
453
|
if (existing.status === "completed" && existing.result) return existing.result as T;
|
|
451
|
-
throw new
|
|
452
|
-
"Integration
|
|
454
|
+
throw new IntegrationFacetOperationIdempotencyError(
|
|
455
|
+
"Integration facet operation is already in progress",
|
|
453
456
|
);
|
|
454
457
|
}
|
|
455
458
|
const result = await execute(tx);
|
|
@@ -461,7 +464,7 @@ async function withFeatureOperation<T extends Record<string, unknown>>(
|
|
|
461
464
|
kind,
|
|
462
465
|
targetKind: "facet_binding",
|
|
463
466
|
targetId: `facet:${sha256(
|
|
464
|
-
`${input.capabilityId}\0${input.instanceKey}\0${input.
|
|
467
|
+
`${input.capabilityId}\0${input.instanceKey}\0${input.facetKey}`,
|
|
465
468
|
)}`,
|
|
466
469
|
status: "completed",
|
|
467
470
|
phase: "completed",
|
|
@@ -492,7 +495,7 @@ async function requireMutationContext(
|
|
|
492
495
|
input.instanceKey,
|
|
493
496
|
true,
|
|
494
497
|
);
|
|
495
|
-
if (!context) throw new
|
|
498
|
+
if (!context) throw new IntegrationFacetNotFoundError("Integration instance not found");
|
|
496
499
|
return context;
|
|
497
500
|
}
|
|
498
501
|
|
|
@@ -506,30 +509,30 @@ async function loadIntegrationInstanceContext(
|
|
|
506
509
|
): Promise<IntegrationInstanceContext | null> {
|
|
507
510
|
let query = db
|
|
508
511
|
.select({
|
|
509
|
-
accountId: schema.
|
|
512
|
+
accountId: schema.integrationFacetBindings.accountId,
|
|
510
513
|
integrationFacetInstallationId:
|
|
511
|
-
schema.
|
|
512
|
-
integrationFacetId: schema.
|
|
514
|
+
schema.integrationFacetBindings.integrationFacetInstallationId,
|
|
515
|
+
integrationFacetId: schema.integrationFacetDefinitions.integrationFacetId,
|
|
513
516
|
providerDomain: schema.capabilityIntegrationFacets.providerDomain,
|
|
514
|
-
connectionId: schema.
|
|
517
|
+
connectionId: schema.integrationFacetBindings.connectionId,
|
|
515
518
|
})
|
|
516
|
-
.from(schema.
|
|
519
|
+
.from(schema.integrationFacetBindings)
|
|
517
520
|
.innerJoin(
|
|
518
|
-
schema.
|
|
519
|
-
eq(schema.
|
|
521
|
+
schema.integrationFacetDefinitions,
|
|
522
|
+
eq(schema.integrationFacetDefinitions.id, schema.integrationFacetBindings.facetDefinitionId),
|
|
520
523
|
)
|
|
521
524
|
.innerJoin(
|
|
522
525
|
schema.capabilityIntegrationFacets,
|
|
523
526
|
eq(
|
|
524
527
|
schema.capabilityIntegrationFacets.facetId,
|
|
525
|
-
schema.
|
|
528
|
+
schema.integrationFacetDefinitions.integrationFacetId,
|
|
526
529
|
),
|
|
527
530
|
)
|
|
528
531
|
.innerJoin(
|
|
529
532
|
schema.capabilityFacetInstallations,
|
|
530
533
|
eq(
|
|
531
534
|
schema.capabilityFacetInstallations.id,
|
|
532
|
-
schema.
|
|
535
|
+
schema.integrationFacetBindings.integrationFacetInstallationId,
|
|
533
536
|
),
|
|
534
537
|
)
|
|
535
538
|
.innerJoin(
|
|
@@ -545,17 +548,17 @@ async function loadIntegrationInstanceContext(
|
|
|
545
548
|
)
|
|
546
549
|
.where(
|
|
547
550
|
and(
|
|
548
|
-
eq(schema.
|
|
549
|
-
eq(schema.
|
|
550
|
-
eq(schema.
|
|
551
|
-
eq(schema.
|
|
551
|
+
eq(schema.integrationFacetBindings.workspaceId, workspaceId),
|
|
552
|
+
eq(schema.integrationFacetBindings.bindingKey, instanceKey),
|
|
553
|
+
eq(schema.integrationFacetBindings.status, "active"),
|
|
554
|
+
eq(schema.integrationFacetDefinitions.kind, "tools"),
|
|
552
555
|
eq(schema.capabilityPluginInstallations.status, "active"),
|
|
553
556
|
sql`${schema.capabilityPluginVersions.manifest} ->> 'capabilityId' = ${capabilityId}`,
|
|
554
557
|
sql`(
|
|
555
|
-
${schema.
|
|
558
|
+
${schema.integrationFacetBindings.connectionId} is null
|
|
556
559
|
or exists (
|
|
557
560
|
select 1 from ${schema.connections} connection
|
|
558
|
-
where connection.id = ${schema.
|
|
561
|
+
where connection.id = ${schema.integrationFacetBindings.connectionId}
|
|
559
562
|
and (connection.subject_id is null or connection.subject_id = ${subjectId})
|
|
560
563
|
)
|
|
561
564
|
)`,
|
|
@@ -569,28 +572,28 @@ async function loadIntegrationInstanceContext(
|
|
|
569
572
|
return rows[0]!;
|
|
570
573
|
}
|
|
571
574
|
|
|
572
|
-
async function
|
|
575
|
+
async function requireFacetDefinition(
|
|
573
576
|
db: Database,
|
|
574
577
|
context: IntegrationInstanceContext,
|
|
575
|
-
|
|
576
|
-
): Promise<typeof schema.
|
|
578
|
+
facetKey: string,
|
|
579
|
+
): Promise<typeof schema.integrationFacetDefinitions.$inferSelect> {
|
|
577
580
|
const [definition] = await db
|
|
578
581
|
.select()
|
|
579
|
-
.from(schema.
|
|
582
|
+
.from(schema.integrationFacetDefinitions)
|
|
580
583
|
.where(
|
|
581
584
|
and(
|
|
582
|
-
eq(schema.
|
|
583
|
-
eq(schema.
|
|
584
|
-
ne(schema.
|
|
585
|
+
eq(schema.integrationFacetDefinitions.integrationFacetId, context.integrationFacetId),
|
|
586
|
+
eq(schema.integrationFacetDefinitions.facetKey, facetKey),
|
|
587
|
+
ne(schema.integrationFacetDefinitions.kind, "tools"),
|
|
585
588
|
),
|
|
586
589
|
)
|
|
587
590
|
.limit(1);
|
|
588
|
-
if (!definition) throw new
|
|
589
|
-
|
|
591
|
+
if (!definition) throw new IntegrationFacetNotFoundError("Integration facet not found");
|
|
592
|
+
facetKind(definition.kind);
|
|
590
593
|
return definition;
|
|
591
594
|
}
|
|
592
595
|
|
|
593
|
-
async function
|
|
596
|
+
async function requireFacetConnection(
|
|
594
597
|
db: Database,
|
|
595
598
|
input: { workspaceId: string; subjectId: string },
|
|
596
599
|
context: IntegrationInstanceContext,
|
|
@@ -598,8 +601,8 @@ async function requireFeatureConnection(
|
|
|
598
601
|
): Promise<void> {
|
|
599
602
|
if (!context.connectionId) {
|
|
600
603
|
if (capabilities.connectionRequired === true) {
|
|
601
|
-
throw new
|
|
602
|
-
"Integration
|
|
604
|
+
throw new IntegrationFacetConnectionError(
|
|
605
|
+
"Integration facet requires the instance Connection",
|
|
603
606
|
);
|
|
604
607
|
}
|
|
605
608
|
return;
|
|
@@ -624,30 +627,30 @@ async function requireFeatureConnection(
|
|
|
624
627
|
(connection.subjectId !== null && connection.subjectId !== input.subjectId) ||
|
|
625
628
|
connection.providerDomain.toLowerCase() !== context.providerDomain.toLowerCase()
|
|
626
629
|
) {
|
|
627
|
-
throw new
|
|
628
|
-
"Integration
|
|
630
|
+
throw new IntegrationFacetConnectionError(
|
|
631
|
+
"Integration facet Connection is unavailable or does not match the provider",
|
|
629
632
|
);
|
|
630
633
|
}
|
|
631
634
|
}
|
|
632
635
|
|
|
633
|
-
async function
|
|
636
|
+
async function loadFacetBinding(
|
|
634
637
|
db: Database,
|
|
635
638
|
context: IntegrationInstanceContext,
|
|
636
639
|
instanceKey: string,
|
|
637
|
-
|
|
640
|
+
facetDefinitionId: string,
|
|
638
641
|
lock = false,
|
|
639
|
-
): Promise<typeof schema.
|
|
642
|
+
): Promise<typeof schema.integrationFacetBindings.$inferSelect | null> {
|
|
640
643
|
let query = db
|
|
641
644
|
.select()
|
|
642
|
-
.from(schema.
|
|
645
|
+
.from(schema.integrationFacetBindings)
|
|
643
646
|
.where(
|
|
644
647
|
and(
|
|
645
648
|
eq(
|
|
646
|
-
schema.
|
|
649
|
+
schema.integrationFacetBindings.integrationFacetInstallationId,
|
|
647
650
|
context.integrationFacetInstallationId,
|
|
648
651
|
),
|
|
649
|
-
eq(schema.
|
|
650
|
-
eq(schema.
|
|
652
|
+
eq(schema.integrationFacetBindings.facetDefinitionId, facetDefinitionId),
|
|
653
|
+
eq(schema.integrationFacetBindings.bindingKey, instanceKey),
|
|
651
654
|
),
|
|
652
655
|
)
|
|
653
656
|
.limit(1);
|
|
@@ -656,35 +659,35 @@ async function loadFeatureBinding(
|
|
|
656
659
|
return binding ?? null;
|
|
657
660
|
}
|
|
658
661
|
|
|
659
|
-
async function
|
|
662
|
+
async function assertDirectFacetOwnership(
|
|
660
663
|
db: Database,
|
|
661
664
|
bindingId: string,
|
|
662
|
-
input: { capabilityId: string; instanceKey: string;
|
|
665
|
+
input: { capabilityId: string; instanceKey: string; facetKey: string },
|
|
663
666
|
): Promise<void> {
|
|
664
|
-
const expected =
|
|
665
|
-
const owners = await
|
|
667
|
+
const expected = facetOwner(input.capabilityId, input.instanceKey, input.facetKey);
|
|
668
|
+
const owners = await listIntegrationFacetBindingOwners(db, bindingId);
|
|
666
669
|
if (!owners.some((owner) => owner.kind === expected.kind && owner.id === expected.id)) {
|
|
667
|
-
throw new
|
|
668
|
-
"Integration
|
|
670
|
+
throw new IntegrationFacetBindingOwnershipConflictError(
|
|
671
|
+
"Integration facet is not directly owned",
|
|
669
672
|
);
|
|
670
673
|
}
|
|
671
674
|
if (owners.some((owner) => owner.kind !== expected.kind || owner.id !== expected.id)) {
|
|
672
|
-
throw new
|
|
673
|
-
"Integration
|
|
675
|
+
throw new IntegrationFacetBindingOwnershipConflictError(
|
|
676
|
+
"Integration facet is shared by another owner and cannot change lifecycle in place",
|
|
674
677
|
);
|
|
675
678
|
}
|
|
676
679
|
}
|
|
677
680
|
|
|
678
|
-
function
|
|
681
|
+
function facetOwner(capabilityId: string, instanceKey: string, facetKey: string) {
|
|
679
682
|
return {
|
|
680
683
|
kind: "direct" as const,
|
|
681
|
-
id: `
|
|
684
|
+
id: `facet:${sha256(`${capabilityId}\0${instanceKey}\0${facetKey}`)}`,
|
|
682
685
|
removable: true,
|
|
683
686
|
};
|
|
684
687
|
}
|
|
685
688
|
|
|
686
689
|
type BindingSummaryRow = Pick<
|
|
687
|
-
typeof schema.
|
|
690
|
+
typeof schema.integrationFacetBindings.$inferSelect,
|
|
688
691
|
| "id"
|
|
689
692
|
| "bindingKey"
|
|
690
693
|
| "displayName"
|
|
@@ -698,15 +701,15 @@ type BindingSummaryRow = Pick<
|
|
|
698
701
|
| "createdAt"
|
|
699
702
|
| "updatedAt"
|
|
700
703
|
> & {
|
|
701
|
-
|
|
704
|
+
facetKey: string;
|
|
702
705
|
kind: string;
|
|
703
706
|
};
|
|
704
707
|
|
|
705
|
-
function bindingSummary(row: BindingSummaryRow):
|
|
708
|
+
function bindingSummary(row: BindingSummaryRow): IntegrationFacetBindingSummary {
|
|
706
709
|
return {
|
|
707
710
|
id: row.id,
|
|
708
|
-
|
|
709
|
-
kind:
|
|
711
|
+
facetKey: row.facetKey,
|
|
712
|
+
kind: facetKind(row.kind),
|
|
710
713
|
bindingKey: row.bindingKey,
|
|
711
714
|
displayName: row.displayName,
|
|
712
715
|
connectionId: row.connectionId,
|
|
@@ -721,14 +724,14 @@ function bindingSummary(row: BindingSummaryRow): IntegrationFeatureBindingSummar
|
|
|
721
724
|
};
|
|
722
725
|
}
|
|
723
726
|
|
|
724
|
-
function
|
|
727
|
+
function facetKind(value: string): IntegrationFacetKind {
|
|
725
728
|
if (
|
|
726
729
|
value !== "knowledge_source" &&
|
|
727
730
|
value !== "inbound_trigger" &&
|
|
728
731
|
value !== "delivery_destination" &&
|
|
729
732
|
value !== "identity_link"
|
|
730
733
|
) {
|
|
731
|
-
throw new Error(`Unknown Integration
|
|
734
|
+
throw new Error(`Unknown Integration facet kind: ${value}`);
|
|
732
735
|
}
|
|
733
736
|
return value;
|
|
734
737
|
}
|
|
@@ -740,18 +743,18 @@ function bindingStatus(value: string): "active" | "paused" | "needs_attention" |
|
|
|
740
743
|
value !== "needs_attention" &&
|
|
741
744
|
value !== "disabled"
|
|
742
745
|
) {
|
|
743
|
-
throw new Error(`Unknown Integration
|
|
746
|
+
throw new Error(`Unknown Integration facet status: ${value}`);
|
|
744
747
|
}
|
|
745
748
|
return value;
|
|
746
749
|
}
|
|
747
750
|
|
|
748
|
-
function
|
|
751
|
+
function assertFacetConfig(
|
|
749
752
|
config: Record<string, unknown>,
|
|
750
753
|
schemaValue: Record<string, unknown>,
|
|
751
754
|
): void {
|
|
752
755
|
const serialized = stableJson(config);
|
|
753
756
|
if (Buffer.byteLength(serialized, "utf8") > 131_072) {
|
|
754
|
-
throw new
|
|
757
|
+
throw new IntegrationFacetConfigError("Integration facet config exceeds 131072 bytes");
|
|
755
758
|
}
|
|
756
759
|
validateSchemaValue(config, schemaValue, "config", 0);
|
|
757
760
|
}
|
|
@@ -762,17 +765,17 @@ function validateSchemaValue(
|
|
|
762
765
|
path: string,
|
|
763
766
|
depth: number,
|
|
764
767
|
): void {
|
|
765
|
-
if (depth > 8) throw new
|
|
768
|
+
if (depth > 8) throw new IntegrationFacetConfigError(`${path} exceeds supported depth`);
|
|
766
769
|
const type = schemaValue.type;
|
|
767
770
|
if (
|
|
768
771
|
Array.isArray(schemaValue.enum) &&
|
|
769
772
|
!schemaValue.enum.some((item) => stableJson(item) === stableJson(value))
|
|
770
773
|
) {
|
|
771
|
-
throw new
|
|
774
|
+
throw new IntegrationFacetConfigError(`${path} is not an allowed value`);
|
|
772
775
|
}
|
|
773
776
|
if (type === "object") {
|
|
774
777
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
775
|
-
throw new
|
|
778
|
+
throw new IntegrationFacetConfigError(`${path} must be an object`);
|
|
776
779
|
}
|
|
777
780
|
const object = value as Record<string, unknown>;
|
|
778
781
|
const properties = objectValue(schemaValue.properties);
|
|
@@ -780,11 +783,11 @@ function validateSchemaValue(
|
|
|
780
783
|
? schemaValue.required.filter((entry): entry is string => typeof entry === "string")
|
|
781
784
|
: [];
|
|
782
785
|
for (const key of required) {
|
|
783
|
-
if (!(key in object)) throw new
|
|
786
|
+
if (!(key in object)) throw new IntegrationFacetConfigError(`${path}.${key} is required`);
|
|
784
787
|
}
|
|
785
788
|
if (schemaValue.additionalProperties === false) {
|
|
786
789
|
const unknown = Object.keys(object).find((key) => !(key in properties));
|
|
787
|
-
if (unknown) throw new
|
|
790
|
+
if (unknown) throw new IntegrationFacetConfigError(`${path}.${unknown} is not supported`);
|
|
788
791
|
}
|
|
789
792
|
for (const [key, child] of Object.entries(object)) {
|
|
790
793
|
const childSchema = objectValue(properties[key]);
|
|
@@ -796,13 +799,13 @@ function validateSchemaValue(
|
|
|
796
799
|
}
|
|
797
800
|
if (type === "array") {
|
|
798
801
|
if (!Array.isArray(value)) {
|
|
799
|
-
throw new
|
|
802
|
+
throw new IntegrationFacetConfigError(`${path} must be an array`);
|
|
800
803
|
}
|
|
801
804
|
if (typeof schemaValue.minItems === "number" && value.length < schemaValue.minItems) {
|
|
802
|
-
throw new
|
|
805
|
+
throw new IntegrationFacetConfigError(`${path} has too few items`);
|
|
803
806
|
}
|
|
804
807
|
if (typeof schemaValue.maxItems === "number" && value.length > schemaValue.maxItems) {
|
|
805
|
-
throw new
|
|
808
|
+
throw new IntegrationFacetConfigError(`${path} has too many items`);
|
|
806
809
|
}
|
|
807
810
|
const itemSchema = objectValue(schemaValue.items);
|
|
808
811
|
if (Object.keys(itemSchema).length > 0) {
|
|
@@ -814,18 +817,18 @@ function validateSchemaValue(
|
|
|
814
817
|
}
|
|
815
818
|
if (type === "string") {
|
|
816
819
|
if (typeof value !== "string")
|
|
817
|
-
throw new
|
|
820
|
+
throw new IntegrationFacetConfigError(`${path} must be a string`);
|
|
818
821
|
if (typeof schemaValue.minLength === "number" && value.length < schemaValue.minLength) {
|
|
819
|
-
throw new
|
|
822
|
+
throw new IntegrationFacetConfigError(`${path} is too short`);
|
|
820
823
|
}
|
|
821
824
|
if (typeof schemaValue.maxLength === "number" && value.length > schemaValue.maxLength) {
|
|
822
|
-
throw new
|
|
825
|
+
throw new IntegrationFacetConfigError(`${path} is too long`);
|
|
823
826
|
}
|
|
824
827
|
return;
|
|
825
828
|
}
|
|
826
829
|
if (type === "boolean") {
|
|
827
830
|
if (typeof value !== "boolean")
|
|
828
|
-
throw new
|
|
831
|
+
throw new IntegrationFacetConfigError(`${path} must be a boolean`);
|
|
829
832
|
return;
|
|
830
833
|
}
|
|
831
834
|
if (type === "integer" || type === "number") {
|
|
@@ -834,15 +837,15 @@ function validateSchemaValue(
|
|
|
834
837
|
!Number.isFinite(value) ||
|
|
835
838
|
(type === "integer" && !Number.isInteger(value))
|
|
836
839
|
) {
|
|
837
|
-
throw new
|
|
840
|
+
throw new IntegrationFacetConfigError(
|
|
838
841
|
`${path} must be ${type === "integer" ? "an integer" : "a number"}`,
|
|
839
842
|
);
|
|
840
843
|
}
|
|
841
844
|
if (typeof schemaValue.minimum === "number" && value < schemaValue.minimum) {
|
|
842
|
-
throw new
|
|
845
|
+
throw new IntegrationFacetConfigError(`${path} is below the minimum`);
|
|
843
846
|
}
|
|
844
847
|
if (typeof schemaValue.maximum === "number" && value > schemaValue.maximum) {
|
|
845
|
-
throw new
|
|
848
|
+
throw new IntegrationFacetConfigError(`${path} exceeds the maximum`);
|
|
846
849
|
}
|
|
847
850
|
return;
|
|
848
851
|
}
|