@jskit-ai/connectors-web 0.1.61 → 0.1.63
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/README.md
CHANGED
|
@@ -22,6 +22,7 @@ preserve other integration slots, registrations and extension values.
|
|
|
22
22
|
|
|
23
23
|
Provider `settingsFields` metadata supplies labelled select controls when `items`
|
|
24
24
|
are provided and text controls otherwise, with optional hints and placeholders.
|
|
25
|
+
A hint may be text or a function of the current settings.
|
|
25
26
|
Defaults and applicable fields come from
|
|
26
27
|
`getProviderSettingsSchema(provider, settings).getFieldDefinitions()`, which also
|
|
27
28
|
supports schemas containing custom validators. A provider may select a schema
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jskit-ai/connectors-web",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.63",
|
|
4
4
|
"description": "Shared Vue fields for portable application integration configuration.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"./client": "./src/client/index.js"
|
|
11
11
|
},
|
|
12
12
|
"dependencies": {
|
|
13
|
-
"@jskit-ai/connectors-core": "0.1.
|
|
13
|
+
"@jskit-ai/connectors-core": "0.1.63"
|
|
14
14
|
},
|
|
15
15
|
"peerDependencies": {
|
|
16
16
|
"vue": "^3.5.13",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<script setup>
|
|
2
2
|
import { computed, ref } from "vue";
|
|
3
|
-
import { getProviderAccountModes, getProviderAuthenticationMethods, getProviderClientAuthenticationMethods, getProviderScopes, getProviderSettingsSchema } from "@jskit-ai/connectors-core/shared/configuration";
|
|
3
|
+
import { DEFAULT_GRANT_TYPE, DEFAULT_TOKEN_ENDPOINT_AUTH_METHOD, getProviderAccountModes, getProviderAuthenticationMethods, getProviderClientAuthenticationMethods, getProviderScopes, getProviderSettingsSchema, providerGrantTypes, registrationClientAuthentication, registrationGrantType } from "@jskit-ai/connectors-core/shared/configuration";
|
|
4
4
|
|
|
5
5
|
const props = defineProps({
|
|
6
6
|
modelValue: { type: Object, required: true },
|
|
@@ -15,8 +15,8 @@ const panels = ref(["details", "credentials"]);
|
|
|
15
15
|
const integration = computed(() => props.modelValue.integrations[props.integrationId]);
|
|
16
16
|
const registrationId = computed(() => integration.value?.authentication.registrationRef);
|
|
17
17
|
const registration = computed(() => props.modelValue.registrations[registrationId.value]);
|
|
18
|
-
const grantType = computed(() => registration.value
|
|
19
|
-
const grantOptions = computed(() => (props.provider
|
|
18
|
+
const grantType = computed(() => registrationGrantType(registration.value));
|
|
19
|
+
const grantOptions = computed(() => providerGrantTypes(props.provider).map((value) => ({
|
|
20
20
|
value, title: { authorization_code: "User consent", client_credentials: "Service account" }[value] || value
|
|
21
21
|
})));
|
|
22
22
|
const modes = computed(() => getProviderAccountModes(props.provider, integration.value.settings || {}).filter((mode) =>
|
|
@@ -37,10 +37,35 @@ const visibleSettings = computed(() => (props.provider.settingsFields || []).fil
|
|
|
37
37
|
(!field.authenticationMethods || field.authenticationMethods.includes(integration.value.authentication.method))
|
|
38
38
|
));
|
|
39
39
|
const visibleScopes = computed(() => getProviderScopes(props.provider, integration.value.settings || {}, grantType.value, integration.value.authentication.method));
|
|
40
|
+
const clientSecretHint = computed(() =>
|
|
41
|
+
`Use an environment reference such as env:${environmentPrefix(registrationId.value || props.integrationId)}_CLIENT_SECRET. Keep the value outside this file.`);
|
|
40
42
|
const assistantPermissions = [
|
|
41
43
|
{ value: "ask", title: "Ask each time" }, { value: "always", title: "Always allow" }, { value: "never", title: "Never allow" }
|
|
42
44
|
];
|
|
43
45
|
|
|
46
|
+
// The environment-variable prefix editAuthentication uses for a new registration's references.
|
|
47
|
+
function environmentPrefix(id) {
|
|
48
|
+
return id.toUpperCase().replaceAll("-", "_");
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// A service account cannot connect as each app user; fall back to a mode these settings allow.
|
|
52
|
+
function accountModeForGrant(grant, settings, accountMode) {
|
|
53
|
+
return grant === "client_credentials" && accountMode === "per-user"
|
|
54
|
+
? getProviderAccountModes(props.provider, settings || {}).find((mode) => mode !== "per-user") : accountMode;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function settingValue(field) {
|
|
58
|
+
return integration.value.settings?.[field.name] ?? settingProperties.value[field.name]?.defaultTo;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function settingHint(field) {
|
|
62
|
+
return typeof field.hint === "function" ? field.hint(integration.value.settings) : field.hint;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function settingErrors(field) {
|
|
66
|
+
return props.fieldErrors[`${integrationPath.value}.settings.${field.name}`];
|
|
67
|
+
}
|
|
68
|
+
|
|
44
69
|
function editAssistantPolicy(changes) {
|
|
45
70
|
editIntegration({ assistantPolicy: { enabled: true, defaultPermission: "ask", actions: {}, ...integration.value.assistantPolicy, ...changes } });
|
|
46
71
|
}
|
|
@@ -91,25 +116,26 @@ function editAuthentication(method, current = integration.value) {
|
|
|
91
116
|
for (const field of props.provider.settingsFields || []) {
|
|
92
117
|
if (field.authenticationMethods && !field.authenticationMethods.includes(method)) delete settings[field.name];
|
|
93
118
|
}
|
|
94
|
-
const
|
|
119
|
+
const grant = method === "oauth2" ? props.provider.oauthGrantTypes?.[0] || DEFAULT_GRANT_TYPE : DEFAULT_GRANT_TYPE;
|
|
120
|
+
const availableScopes = getProviderScopes(props.provider, settings, grant, method);
|
|
95
121
|
const scopes = availableScopes.filter(scope => current.scopes.includes(scope.value) || scope.required || (scope.authenticationMethods && scope.recommended)).map(scope => scope.value);
|
|
96
122
|
if (method === "oauth2") {
|
|
97
123
|
let id = props.integrationId;
|
|
98
124
|
let suffix = 2;
|
|
99
125
|
while (Object.hasOwn(props.modelValue.registrations, id)) id = `${props.integrationId}-${suffix++}`;
|
|
100
|
-
const prefix = id
|
|
101
|
-
const grant = props.provider.oauthGrantTypes?.[0] || "authorization_code";
|
|
126
|
+
const prefix = environmentPrefix(id);
|
|
102
127
|
const clientAuthentication = getProviderClientAuthenticationMethods(props.provider, grant, settings)[0];
|
|
103
128
|
emit("update:modelValue", {
|
|
104
129
|
...props.modelValue,
|
|
105
130
|
integrations: { ...props.modelValue.integrations, [props.integrationId]: {
|
|
106
131
|
...current, scopes, authentication: { method, registrationRef: id },
|
|
132
|
+
accountMode: accountModeForGrant(grant, settings, current.accountMode),
|
|
107
133
|
...(current.settings ? { settings } : {})
|
|
108
134
|
} },
|
|
109
135
|
registrations: { ...props.modelValue.registrations, [id]: {
|
|
110
136
|
source: "own", clientId: "",
|
|
111
137
|
...(grant === "authorization_code" ? { callbackUrlRef: `env:${prefix}_CALLBACK_URL` } : { grantType: grant }),
|
|
112
|
-
...(clientAuthentication !==
|
|
138
|
+
...(clientAuthentication !== DEFAULT_TOKEN_ENDPOINT_AUTH_METHOD ? { tokenEndpointAuthMethod: clientAuthentication } : {}),
|
|
113
139
|
...(clientAuthentication !== "none" ? { clientSecretRef: `env:${prefix}_CLIENT_SECRET` } : {})
|
|
114
140
|
} }
|
|
115
141
|
});
|
|
@@ -137,7 +163,7 @@ function editRegistration(field, value) {
|
|
|
137
163
|
function editGrantType(value) {
|
|
138
164
|
const nextRegistration = { ...registration.value, grantType: value };
|
|
139
165
|
const methods = getProviderClientAuthenticationMethods(props.provider, value, integration.value.settings || {});
|
|
140
|
-
if (!methods.includes(nextRegistration
|
|
166
|
+
if (!methods.includes(registrationClientAuthentication(nextRegistration))) nextRegistration.tokenEndpointAuthMethod = methods[0];
|
|
141
167
|
if (nextRegistration.tokenEndpointAuthMethod === "none") delete nextRegistration.clientSecretRef;
|
|
142
168
|
if (value === "client_credentials") delete nextRegistration.callbackUrlRef;
|
|
143
169
|
const allowed = getProviderScopes(props.provider, integration.value.settings || {}, value, integration.value.authentication.method).map((scope) => scope.value);
|
|
@@ -146,8 +172,7 @@ function editGrantType(value) {
|
|
|
146
172
|
registrations: { ...props.modelValue.registrations, [registrationId.value]: nextRegistration },
|
|
147
173
|
integrations: { ...props.modelValue.integrations, [props.integrationId]: {
|
|
148
174
|
...integration.value,
|
|
149
|
-
accountMode: value
|
|
150
|
-
? props.provider.accountModes.find((mode) => mode !== "per-user") : integration.value.accountMode,
|
|
175
|
+
accountMode: accountModeForGrant(value, integration.value.settings, integration.value.accountMode),
|
|
151
176
|
scopes: integration.value.scopes.filter((scope) => allowed.includes(scope))
|
|
152
177
|
} }
|
|
153
178
|
});
|
|
@@ -185,22 +210,22 @@ function editGrantType(value) {
|
|
|
185
210
|
<v-autocomplete
|
|
186
211
|
v-if="field.searchable"
|
|
187
212
|
:label="field.label" :items="field.items" :disabled="disabled" auto-select-first
|
|
188
|
-
:model-value="
|
|
189
|
-
:hint="
|
|
213
|
+
:model-value="settingValue(field)"
|
|
214
|
+
:hint="settingHint(field)" persistent-hint :error-messages="settingErrors(field)"
|
|
190
215
|
@update:model-value="editSetting(field.name, $event)"
|
|
191
216
|
/>
|
|
192
217
|
<v-select
|
|
193
218
|
v-else-if="field.items"
|
|
194
219
|
:label="field.label" :items="field.items" :disabled="disabled"
|
|
195
|
-
:model-value="
|
|
196
|
-
:hint="field
|
|
220
|
+
:model-value="settingValue(field)"
|
|
221
|
+
:hint="settingHint(field)" persistent-hint :error-messages="settingErrors(field)"
|
|
197
222
|
@update:model-value="editSetting(field.name, $event)"
|
|
198
223
|
/>
|
|
199
224
|
<v-text-field
|
|
200
225
|
v-else
|
|
201
226
|
:label="field.label" :disabled="disabled" :placeholder="field.placeholder"
|
|
202
|
-
:model-value="
|
|
203
|
-
:hint="field
|
|
227
|
+
:model-value="settingValue(field) ?? ''"
|
|
228
|
+
:hint="settingHint(field)" persistent-hint :error-messages="settingErrors(field)"
|
|
204
229
|
@update:model-value="editSetting(field.name, $event)"
|
|
205
230
|
/>
|
|
206
231
|
</template>
|
|
@@ -236,7 +261,7 @@ function editGrantType(value) {
|
|
|
236
261
|
<slot v-if="registration.tokenEndpointAuthMethod !== 'none'" name="credential" :reference="registration.clientSecretRef" :disabled="disabled">
|
|
237
262
|
<v-text-field
|
|
238
263
|
label="Client secret reference" :model-value="registration.clientSecretRef" :disabled="disabled"
|
|
239
|
-
hint="
|
|
264
|
+
:hint="clientSecretHint"
|
|
240
265
|
persistent-hint :error-messages="fieldErrors[`${registrationPath}.clientSecretRef`]"
|
|
241
266
|
@update:model-value="editRegistration('clientSecretRef', $event)"
|
|
242
267
|
/>
|