@iblai/data-layer 1.38.2 → 1.40.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/index.js CHANGED
@@ -42242,7 +42242,10 @@ const CREDENTIALS_CUSTOM_ENDPOINTS = {
42242
42242
 
42243
42243
  const credentialsCustomApiSlice = react.createApi({
42244
42244
  reducerPath: CREDENTIALS_CUSTOM_REDUCER_PATH,
42245
- baseQuery: iblFetchBaseQuery,
42245
+ // The Secrets page hides a kind's rows on a 403 of its list and shows the
42246
+ // retry notice on any other failure, which needs the status: RTK Query
42247
+ // keeps only `{}` of a thrown `{ status, data }`.
42248
+ baseQuery: withReturnedErrors(iblFetchBaseQuery),
42246
42249
  tagTypes: [
42247
42250
  'IntegrationCredentialsSchema',
42248
42251
  'CredentialsSchema',
@@ -42262,6 +42265,23 @@ const credentialsCustomApiSlice = react.createApi({
42262
42265
  }),
42263
42266
  }),
42264
42267
  invalidatesTags: ['MaskedIntegrationCredentials'],
42268
+ // The Secrets screens read the admin list and the VM secrets, and the
42269
+ // backend deletes the secrets that read this credential with it. The
42270
+ // slices are imported lazily: api-slice.ts imports this file.
42271
+ async onQueryStarted(_args, { queryFulfilled, dispatch }) {
42272
+ try {
42273
+ await queryFulfilled;
42274
+ const [{ credentialsApiSlice }, { virtualMachineApiSlice }] = await Promise.all([
42275
+ Promise.resolve().then(function () { return apiSlice$1; }),
42276
+ Promise.resolve().then(function () { return apiSlice; }),
42277
+ ]);
42278
+ dispatch(credentialsApiSlice.util.invalidateTags(['IntegrationCredentials']));
42279
+ dispatch(virtualMachineApiSlice.util.invalidateTags(['VirtualMachineSecrets']));
42280
+ }
42281
+ catch (_a) {
42282
+ // Only a successful delete invalidates.
42283
+ }
42284
+ },
42265
42285
  }),
42266
42286
  deleteCredential: builder.mutation({
42267
42287
  query: ({ org, name, platform_key, model_name }) => ({
@@ -42331,7 +42351,7 @@ const { useDeleteIntegrationCredentialMutation, useDeleteCredentialMutation, use
42331
42351
  const credentialsApiSlice = react.createApi({
42332
42352
  reducerPath: 'credentialsApiSlice',
42333
42353
  baseQuery: iblFakeBaseQuery,
42334
- tagTypes: ['Credentials', 'ProviderConfig', 'ExternalMapping'],
42354
+ tagTypes: ['Credentials', 'ProviderConfig', 'ExternalMapping', 'IntegrationCredentials'],
42335
42355
  endpoints: (builder) => ({
42336
42356
  getCredentials: builder.query({
42337
42357
  ...buildEndpointFromService(exports.SERVICES.DM, async (args) => {
@@ -42431,11 +42451,15 @@ const credentialsApiSlice = react.createApi({
42431
42451
  createCallCredentials: builder.mutation({
42432
42452
  ...buildEndpointFromAxdService(AiMentorService.aiMentorOrgsUsersMentorsCreateCallCredentialsCreate),
42433
42453
  }),
42454
+ // The admin list (ids + service_info), which the Secrets screens join
42455
+ // with the VM secrets that read a credential.
42434
42456
  getIntegrationCredentials: builder.query({
42435
42457
  ...buildEndpointFromDmService(AiAccountService.aiAccountOrgsIntegrationCredentialRetrieve),
42458
+ providesTags: ['IntegrationCredentials'],
42436
42459
  }),
42437
42460
  createIntegrationCredential: builder.mutation({
42438
42461
  ...buildEndpointFromDmService(AiAccountService.aiAccountOrgsIntegrationCredentialCreate),
42462
+ invalidatesTags: ['IntegrationCredentials'],
42439
42463
  async onQueryStarted(_args, { queryFulfilled, dispatch }) {
42440
42464
  try {
42441
42465
  await queryFulfilled;
@@ -42448,9 +42472,42 @@ const credentialsApiSlice = react.createApi({
42448
42472
  }),
42449
42473
  createLLMCredential: builder.mutation({
42450
42474
  ...buildEndpointFromDmService(AiAccountService.aiAccountOrgsCredentialCreate),
42475
+ async onQueryStarted(_args, { queryFulfilled, dispatch }) {
42476
+ try {
42477
+ await queryFulfilled;
42478
+ dispatch(credentialsCustomApiSlice.util.invalidateTags(['MaskedLLMCredentials']));
42479
+ }
42480
+ catch (_a) {
42481
+ // Swallow — invalidation should only happen on success.
42482
+ }
42483
+ },
42484
+ }),
42485
+ // PATCH `/credential/` replaces the whole value for every provider but
42486
+ // Azure OpenAI, whose per-model values the backend merges.
42487
+ updateLLMCredential: builder.mutation({
42488
+ ...buildEndpointFromDmService(AiAccountService.aiAccountOrgsCredentialPartialUpdate),
42489
+ async onQueryStarted(_args, { queryFulfilled, dispatch }) {
42490
+ try {
42491
+ await queryFulfilled;
42492
+ dispatch(credentialsCustomApiSlice.util.invalidateTags(['MaskedLLMCredentials']));
42493
+ }
42494
+ catch (_a) {
42495
+ // Swallow — invalidation should only happen on success.
42496
+ }
42497
+ },
42451
42498
  }),
42452
42499
  updateIntegrationCredential: builder.mutation({
42453
42500
  ...buildEndpointFromDmService(AiAccountService.aiAccountOrgsIntegrationCredentialPartialUpdate),
42501
+ invalidatesTags: ['IntegrationCredentials'],
42502
+ async onQueryStarted(_args, { queryFulfilled, dispatch }) {
42503
+ try {
42504
+ await queryFulfilled;
42505
+ dispatch(credentialsCustomApiSlice.util.invalidateTags(['MaskedIntegrationCredentials']));
42506
+ }
42507
+ catch (_a) {
42508
+ // Swallow — invalidation should only happen on success.
42509
+ }
42510
+ },
42454
42511
  }),
42455
42512
  getConnectedServiceAuthUrl: builder.query({
42456
42513
  queryFn: async (queryParams, api, extraOptions) => {
@@ -42561,7 +42618,45 @@ const credentialsApiSlice = react.createApi({
42561
42618
  }),
42562
42619
  }),
42563
42620
  });
42564
- const { useGetCredentialsQuery, useLazyGetCredentialsQuery, useGetUserCredentialsQuery, useLazyGetUserCredentialsQuery, useCreateCallCredentialsMutation, useGetIntegrationCredentialsQuery, useLazyGetIntegrationCredentialsQuery, useCreateIntegrationCredentialMutation, useUpdateIntegrationCredentialMutation, useGetLLMCredentialsQuery, useLazyGetLLMCredentialsQuery, useCreateLLMCredentialMutation, useGetConnectedServiceAuthUrlQuery, useLazyGetConnectedServiceAuthUrlQuery, useConnectedServicesCallbackQuery, useLazyConnectedServicesCallbackQuery, useGetUsersAsAssertionsQuery, useLazyGetUsersAsAssertionsQuery, useCreateCredentialAssertionMutation, useGetCredentialsListQuery, useLazyGetCredentialsListQuery, useCreateCredentialMutation, useUpdateCredentialMutation, useDeleteCourseCredentialMutation, useGetProviderConfigQuery, useLazyGetProviderConfigQuery, useCreateProviderConfigMutation, useDeleteProviderConfigMutation, useGetExternalMappingQuery, useLazyGetExternalMappingQuery, useCreateExternalMappingMutation, useDeleteExternalMappingMutation, } = credentialsApiSlice;
42621
+ const { useGetCredentialsQuery, useLazyGetCredentialsQuery, useGetUserCredentialsQuery, useLazyGetUserCredentialsQuery, useCreateCallCredentialsMutation, useGetIntegrationCredentialsQuery, useLazyGetIntegrationCredentialsQuery, useCreateIntegrationCredentialMutation, useUpdateIntegrationCredentialMutation, useGetLLMCredentialsQuery, useLazyGetLLMCredentialsQuery, useCreateLLMCredentialMutation, useUpdateLLMCredentialMutation, useGetConnectedServiceAuthUrlQuery, useLazyGetConnectedServiceAuthUrlQuery, useConnectedServicesCallbackQuery, useLazyConnectedServicesCallbackQuery, useGetUsersAsAssertionsQuery, useLazyGetUsersAsAssertionsQuery, useCreateCredentialAssertionMutation, useGetCredentialsListQuery, useLazyGetCredentialsListQuery, useCreateCredentialMutation, useUpdateCredentialMutation, useDeleteCourseCredentialMutation, useGetProviderConfigQuery, useLazyGetProviderConfigQuery, useCreateProviderConfigMutation, useDeleteProviderConfigMutation, useGetExternalMappingQuery, useLazyGetExternalMappingQuery, useCreateExternalMappingMutation, useDeleteExternalMappingMutation, } = credentialsApiSlice;
42622
+
42623
+ var apiSlice$1 = /*#__PURE__*/Object.freeze({
42624
+ __proto__: null,
42625
+ credentialsApiSlice: credentialsApiSlice,
42626
+ useConnectedServicesCallbackQuery: useConnectedServicesCallbackQuery,
42627
+ useCreateCallCredentialsMutation: useCreateCallCredentialsMutation,
42628
+ useCreateCredentialAssertionMutation: useCreateCredentialAssertionMutation,
42629
+ useCreateCredentialMutation: useCreateCredentialMutation,
42630
+ useCreateExternalMappingMutation: useCreateExternalMappingMutation,
42631
+ useCreateIntegrationCredentialMutation: useCreateIntegrationCredentialMutation,
42632
+ useCreateLLMCredentialMutation: useCreateLLMCredentialMutation,
42633
+ useCreateProviderConfigMutation: useCreateProviderConfigMutation,
42634
+ useDeleteCourseCredentialMutation: useDeleteCourseCredentialMutation,
42635
+ useDeleteExternalMappingMutation: useDeleteExternalMappingMutation,
42636
+ useDeleteProviderConfigMutation: useDeleteProviderConfigMutation,
42637
+ useGetConnectedServiceAuthUrlQuery: useGetConnectedServiceAuthUrlQuery,
42638
+ useGetCredentialsListQuery: useGetCredentialsListQuery,
42639
+ useGetCredentialsQuery: useGetCredentialsQuery,
42640
+ useGetExternalMappingQuery: useGetExternalMappingQuery,
42641
+ useGetIntegrationCredentialsQuery: useGetIntegrationCredentialsQuery,
42642
+ useGetLLMCredentialsQuery: useGetLLMCredentialsQuery,
42643
+ useGetProviderConfigQuery: useGetProviderConfigQuery,
42644
+ useGetUserCredentialsQuery: useGetUserCredentialsQuery,
42645
+ useGetUsersAsAssertionsQuery: useGetUsersAsAssertionsQuery,
42646
+ useLazyConnectedServicesCallbackQuery: useLazyConnectedServicesCallbackQuery,
42647
+ useLazyGetConnectedServiceAuthUrlQuery: useLazyGetConnectedServiceAuthUrlQuery,
42648
+ useLazyGetCredentialsListQuery: useLazyGetCredentialsListQuery,
42649
+ useLazyGetCredentialsQuery: useLazyGetCredentialsQuery,
42650
+ useLazyGetExternalMappingQuery: useLazyGetExternalMappingQuery,
42651
+ useLazyGetIntegrationCredentialsQuery: useLazyGetIntegrationCredentialsQuery,
42652
+ useLazyGetLLMCredentialsQuery: useLazyGetLLMCredentialsQuery,
42653
+ useLazyGetProviderConfigQuery: useLazyGetProviderConfigQuery,
42654
+ useLazyGetUserCredentialsQuery: useLazyGetUserCredentialsQuery,
42655
+ useLazyGetUsersAsAssertionsQuery: useLazyGetUsersAsAssertionsQuery,
42656
+ useUpdateCredentialMutation: useUpdateCredentialMutation,
42657
+ useUpdateIntegrationCredentialMutation: useUpdateIntegrationCredentialMutation,
42658
+ useUpdateLLMCredentialMutation: useUpdateLLMCredentialMutation
42659
+ });
42565
42660
 
42566
42661
  const chatPrivacyApiSlice = react.createApi({
42567
42662
  reducerPath: 'chatPrivacyApiSlice',
@@ -48182,6 +48277,45 @@ const getSpendCapExceededError = (error) => {
48182
48277
  return null;
48183
48278
  };
48184
48279
 
48280
+ // Backend contract: iblai-dm-pro#3150 (iblai-platform#2766). The endpoint is
48281
+ // mounted at the DM root, not under /api/ai-mentor/, and scopes its answer to
48282
+ // the tenant named in the `iblai-org` header.
48283
+ const AGENT_SETTINGS_REDUCER_PATH = 'agentSettingsApiSlice';
48284
+ const AGENT_SETTINGS_FIELD_PERMISSIONS_PATH = '/v1/agents/settings/field-permissions';
48285
+ const IBLAI_ORG_HEADER = 'iblai-org';
48286
+ const AGENT_SETTINGS_QUERY_KEYS = {
48287
+ FIELD_PERMISSIONS: 'AGENT_SETTINGS_FIELD_PERMISSIONS',
48288
+ };
48289
+
48290
+ const agentSettingsApiSlice = react.createApi({
48291
+ reducerPath: AGENT_SETTINGS_REDUCER_PATH,
48292
+ tagTypes: [AGENT_SETTINGS_QUERY_KEYS.FIELD_PERMISSIONS],
48293
+ baseQuery: iblFetchBaseQuery,
48294
+ endpoints: (builder) => ({
48295
+ /**
48296
+ * Which create-agent fields the caller may write. A 403 means they may not
48297
+ * create agents at all and a 404 an older backend; both are returned as
48298
+ * `{ error }` so the form can fail open on them instead of logging out.
48299
+ */
48300
+ getAgentSettingsFieldPermissions: builder.query({
48301
+ query: ({ org }) => ({
48302
+ url: AGENT_SETTINGS_FIELD_PERMISSIONS_PATH,
48303
+ service: exports.SERVICES.DM,
48304
+ method: 'GET',
48305
+ headers: { [IBLAI_ORG_HEADER]: org },
48306
+ returnErrorStatuses: [403, 404],
48307
+ }),
48308
+ // The answer is advisory (the form fails open without it), so a failure
48309
+ // frees the form at once instead of holding it through three retries.
48310
+ extraOptions: { maxRetries: 0 },
48311
+ providesTags: (_result, _error, { org }) => [
48312
+ { type: AGENT_SETTINGS_QUERY_KEYS.FIELD_PERMISSIONS, id: org },
48313
+ ],
48314
+ }),
48315
+ }),
48316
+ });
48317
+ const { useGetAgentSettingsFieldPermissionsQuery, useLazyGetAgentSettingsFieldPermissionsQuery, } = agentSettingsApiSlice;
48318
+
48185
48319
  exports.recommendationPromptTypeEnum = void 0;
48186
48320
  (function (recommendationPromptTypeEnum) {
48187
48321
  recommendationPromptTypeEnum["mentors"] = "mentors";
@@ -49953,11 +50087,51 @@ const VIRTUAL_MACHINE_REJECTED_HOST_SUFFIXES = [
49953
50087
  ];
49954
50088
  /** `env_var` of a VM secret: a POSIX-style environment variable name. */
49955
50089
  const VIRTUAL_MACHINE_ENV_VAR_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/;
50090
+ /** The backend caps `env_var` at 128 characters. */
50091
+ const VIRTUAL_MACHINE_ENV_VAR_MAX_LENGTH = 128;
50092
+ /**
50093
+ * Variable names the UI refuses for a secret. The backend only checks the
50094
+ * POSIX shape, but the sandbox sets `env_var` in the VM's environment, so a
50095
+ * secret named PATH or LD_PRELOAD would break every command run there.
50096
+ */
50097
+ const VIRTUAL_MACHINE_RESERVED_ENV_VARS = [
50098
+ 'PATH',
50099
+ 'HOME',
50100
+ 'USER',
50101
+ 'LOGNAME',
50102
+ 'SHELL',
50103
+ 'PWD',
50104
+ 'OLDPWD',
50105
+ 'TMPDIR',
50106
+ 'TERM',
50107
+ 'LANG',
50108
+ 'LANGUAGE',
50109
+ 'LC_ALL',
50110
+ 'LD_PRELOAD',
50111
+ 'LD_LIBRARY_PATH',
50112
+ 'PYTHONPATH',
50113
+ 'PYTHONHOME',
50114
+ 'NODE_OPTIONS',
50115
+ 'HTTP_PROXY',
50116
+ 'HTTPS_PROXY',
50117
+ 'NO_PROXY',
50118
+ ];
50119
+ /** Prefixes the sandbox and ibl.ai keep for their own variables. */
50120
+ const VIRTUAL_MACHINE_RESERVED_ENV_VAR_PREFIXES = ['MSB_', 'IBLAI_'];
50121
+ /**
50122
+ * The port a bare hostname gets in an allowlist. Secrets are only ever
50123
+ * swapped into HTTPS requests, so `api.acme.com` means `api.acme.com:443`.
50124
+ */
50125
+ const VIRTUAL_MACHINE_DEFAULT_HOST_PORT = 443;
49956
50126
  /** A network policy holds between 1 and 100 hosts. */
49957
50127
  const VIRTUAL_MACHINE_MAX_POLICY_HOSTS = 100;
49958
50128
  /** An agent may bind at most 20 VM secrets. */
49959
50129
  const VIRTUAL_MACHINE_MAX_SECRETS_PER_MENTOR = 20;
49960
- /** A pasted secret value must be at least this long. */
50130
+ /**
50131
+ * The backend's floor for a pasted secret value (its output scrubber blanks
50132
+ * every occurrence of a bound value, so a very short one would blank too
50133
+ * much). The UI no longer checks it; a refusal is shown under the Key field.
50134
+ */
49961
50135
  const VIRTUAL_MACHINE_SECRET_VALUE_MIN_LENGTH = 8;
49962
50136
  /**
49963
50137
  * Default VM runtime billing: charged to the chatting user's credits, prorated
@@ -49977,12 +50151,14 @@ const VIRTUAL_MACHINE_DEFAULT_BILLING = {
49977
50151
  * Hand-written: these endpoints are newer than the pinned `@iblai/iblai-api`
49978
50152
  * release. Records are keyed in the body (PATCH) or the query string (DELETE),
49979
50153
  * never in the URL. A 403 on either list means the caller lacks the matching
49980
- * `Ibl.Mentor/VirtualMachine…/list` permission — hosts hide the pages then.
50154
+ * `Ibl.Mentor/VirtualMachine…/list` permission — hosts hide the pages then,
50155
+ * which needs the status: the base query returns failures rather than throwing
50156
+ * them, since RTK Query keeps only `{}` of a thrown `{ status, data }`.
49981
50157
  */
49982
50158
  const virtualMachineApiSlice = react.createApi({
49983
50159
  reducerPath: VIRTUAL_MACHINE_REDUCER_PATH,
49984
50160
  tagTypes: [VIRTUAL_MACHINE_QUERY_KEYS.NETWORK_POLICIES, VIRTUAL_MACHINE_QUERY_KEYS.SECRETS],
49985
- baseQuery: iblFetchBaseQuery,
50161
+ baseQuery: withReturnedErrors(iblFetchBaseQuery),
49986
50162
  endpoints: (builder) => ({
49987
50163
  // ── Network policies ────────────────────────────────────────────────
49988
50164
  listVirtualMachineNetworkPolicies: builder.query({
@@ -50063,6 +50239,21 @@ const virtualMachineApiSlice = react.createApi({
50063
50239
  });
50064
50240
  const { useListVirtualMachineNetworkPoliciesQuery, useLazyListVirtualMachineNetworkPoliciesQuery, useCreateVirtualMachineNetworkPolicyMutation, useUpdateVirtualMachineNetworkPolicyMutation, useDeleteVirtualMachineNetworkPolicyMutation, useListVirtualMachineSecretsQuery, useLazyListVirtualMachineSecretsQuery, useCreateVirtualMachineSecretMutation, useUpdateVirtualMachineSecretMutation, useDeleteVirtualMachineSecretMutation, } = virtualMachineApiSlice;
50065
50241
 
50242
+ var apiSlice = /*#__PURE__*/Object.freeze({
50243
+ __proto__: null,
50244
+ useCreateVirtualMachineNetworkPolicyMutation: useCreateVirtualMachineNetworkPolicyMutation,
50245
+ useCreateVirtualMachineSecretMutation: useCreateVirtualMachineSecretMutation,
50246
+ useDeleteVirtualMachineNetworkPolicyMutation: useDeleteVirtualMachineNetworkPolicyMutation,
50247
+ useDeleteVirtualMachineSecretMutation: useDeleteVirtualMachineSecretMutation,
50248
+ useLazyListVirtualMachineNetworkPoliciesQuery: useLazyListVirtualMachineNetworkPoliciesQuery,
50249
+ useLazyListVirtualMachineSecretsQuery: useLazyListVirtualMachineSecretsQuery,
50250
+ useListVirtualMachineNetworkPoliciesQuery: useListVirtualMachineNetworkPoliciesQuery,
50251
+ useListVirtualMachineSecretsQuery: useListVirtualMachineSecretsQuery,
50252
+ useUpdateVirtualMachineNetworkPolicyMutation: useUpdateVirtualMachineNetworkPolicyMutation,
50253
+ useUpdateVirtualMachineSecretMutation: useUpdateVirtualMachineSecretMutation,
50254
+ virtualMachineApiSlice: virtualMachineApiSlice
50255
+ });
50256
+
50066
50257
  /**
50067
50258
  * Normalise a `host:port` entry the way the backend stores it: trimmed and
50068
50259
  * lowercased.
@@ -50070,13 +50261,78 @@ const { useListVirtualMachineNetworkPoliciesQuery, useLazyListVirtualMachineNetw
50070
50261
  function normalizeHostPort(value) {
50071
50262
  return value.trim().toLowerCase();
50072
50263
  }
50264
+ const SCHEME_PORTS = { 'https:': 443, 'http:': 80 };
50265
+ // A loop rather than `/x+$/`, which takes quadratic time on a long run of x
50266
+ // that does not reach the end (CodeQL js/polynomial-redos).
50267
+ function trimChar(value, char, { start = false } = {}) {
50268
+ let from = 0;
50269
+ let to = value.length;
50270
+ if (start)
50271
+ while (from < to && value[from] === char)
50272
+ from += 1;
50273
+ while (to > from && value[to - 1] === char)
50274
+ to -= 1;
50275
+ return value.slice(from, to);
50276
+ }
50277
+ /**
50278
+ * Turn what a person typed or pasted into the `host:port` the backend stores.
50279
+ * People paste the address from a service's instructions, so a whole URL
50280
+ * (`https://api.acme.com/v1/keys`) is reduced to its host, with the scheme's
50281
+ * port unless the URL names one; `api.acme.com/v1` loses its path; a trailing
50282
+ * dot goes. Anything unparseable comes back trimmed and lowercased so
50283
+ * `validateHostPort` can explain it.
50284
+ */
50285
+ function normalizeHostInput(value, options = {}) {
50286
+ let entry = normalizeHostPort(value);
50287
+ if (entry.length === 0)
50288
+ return entry;
50289
+ let port = null;
50290
+ if (entry.includes('://')) {
50291
+ try {
50292
+ const url = new URL(entry);
50293
+ if (!url.hostname)
50294
+ return entry;
50295
+ port = url.port || (SCHEME_PORTS[url.protocol] ? String(SCHEME_PORTS[url.protocol]) : null);
50296
+ entry = url.hostname;
50297
+ }
50298
+ catch (_a) {
50299
+ return entry;
50300
+ }
50301
+ }
50302
+ else {
50303
+ const pathStart = entry.search(/[/?#]/);
50304
+ if (pathStart !== -1)
50305
+ entry = entry.slice(0, pathStart);
50306
+ }
50307
+ if (port === null) {
50308
+ const separator = entry.lastIndexOf(':');
50309
+ if (separator !== -1) {
50310
+ port = entry.slice(separator + 1);
50311
+ entry = entry.slice(0, separator);
50312
+ }
50313
+ }
50314
+ entry = trimChar(entry, '.');
50315
+ if (entry.length === 0)
50316
+ return entry;
50317
+ if (port)
50318
+ return `${entry}:${port}`;
50319
+ return options.defaultPort !== undefined ? `${entry}:${options.defaultPort}` : entry;
50320
+ }
50073
50321
  /** Split a pasted or typed string into candidate `host:port` entries. */
50074
- function splitHostPortInput(value) {
50322
+ function splitHostPortInput(value, options = {}) {
50075
50323
  return value
50076
50324
  .split(/[\s,;]+/)
50077
- .map(normalizeHostPort)
50325
+ .map((entry) => normalizeHostInput(entry, options))
50078
50326
  .filter((entry) => entry.length > 0);
50079
50327
  }
50328
+ /**
50329
+ * The `host:port` a person reads: the standard HTTPS port is implied, so
50330
+ * `api.acme.com:443` shows as `api.acme.com`; any other port stays visible.
50331
+ * The stored and compared form is never changed by this.
50332
+ */
50333
+ function formatHostPort(entry) {
50334
+ return entry.endsWith(':443') ? entry.slice(0, -4) : entry;
50335
+ }
50080
50336
  const IPV4_PATTERN = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/;
50081
50337
  /** Whether the host part is an IPv4 literal (the `host:port` grammar admits no IPv6). */
50082
50338
  function isIpAddressHost(host) {
@@ -50232,6 +50488,75 @@ function findUncoveredSecretHosts(secrets, allowedHosts) {
50232
50488
  }
50233
50489
  return uncovered;
50234
50490
  }
50491
+ /** Whether a variable name is one the VM itself relies on (see the reserved list). */
50492
+ function isReservedEnvVar(name) {
50493
+ const upper = name.toUpperCase();
50494
+ if (VIRTUAL_MACHINE_RESERVED_ENV_VARS.includes(upper))
50495
+ return true;
50496
+ return VIRTUAL_MACHINE_RESERVED_ENV_VAR_PREFIXES.some((prefix) => upper.startsWith(prefix));
50497
+ }
50498
+ const ENV_VAR_WORDS = ['KEY', 'TOKEN', 'SECRET', 'PASSWORD'];
50499
+ const ENV_VAR_FALLBACK = 'SECRET';
50500
+ /** Leaves room for a `_NN` suffix under the backend's 128-character cap. */
50501
+ const ENV_VAR_DERIVED_MAX_LENGTH = VIRTUAL_MACHINE_ENV_VAR_MAX_LENGTH - 8;
50502
+ /**
50503
+ * The variable name a secret gets from its display name, so a person never
50504
+ * has to invent one: "Acme API key" → `ACME_API_KEY`, "Clé Stripe" →
50505
+ * `CLE_STRIPE_KEY`. Accents are folded, every other run of characters becomes
50506
+ * an underscore, a leading digit gets `KEY_` in front, a name without
50507
+ * KEY/TOKEN/SECRET/PASSWORD gets `_KEY` (which also keeps "Path" from
50508
+ * becoming the VM's PATH), nothing derivable falls back to `SECRET`, and a
50509
+ * clash with `taken` gets `_2`, `_3`, …
50510
+ */
50511
+ function deriveSecretEnvVar(name, options = {}) {
50512
+ var _a;
50513
+ let base = trimChar(name
50514
+ .normalize('NFKD')
50515
+ .replace(/[\u0300-\u036f]/g, '')
50516
+ .toUpperCase()
50517
+ .replace(/[^A-Z0-9]+/g, '_'), '_', { start: true }).replace(/_{2,}/g, '_');
50518
+ if (base.length === 0)
50519
+ base = ENV_VAR_FALLBACK;
50520
+ if (/^[0-9]/.test(base))
50521
+ base = `KEY_${base}`;
50522
+ if (!ENV_VAR_WORDS.some((word) => base.split('_').includes(word)))
50523
+ base = `${base}_KEY`;
50524
+ if (isReservedEnvVar(base))
50525
+ base = `KEY_${base}`;
50526
+ base = trimChar(base.slice(0, ENV_VAR_DERIVED_MAX_LENGTH), '_');
50527
+ const taken = new Set(((_a = options.taken) !== null && _a !== void 0 ? _a : []).map((entry) => entry.toUpperCase()));
50528
+ if (!taken.has(base))
50529
+ return base;
50530
+ for (let suffix = 2;; suffix += 1) {
50531
+ const candidate = `${base}_${suffix}`;
50532
+ if (!taken.has(candidate))
50533
+ return candidate;
50534
+ }
50535
+ }
50536
+ function validateSecretEnvVar(value, options = {}) {
50537
+ var _a;
50538
+ const entry = value.trim();
50539
+ if (entry.length === 0)
50540
+ return 'required';
50541
+ if (!VIRTUAL_MACHINE_ENV_VAR_PATTERN.test(entry))
50542
+ return 'format';
50543
+ if (entry.length > VIRTUAL_MACHINE_ENV_VAR_MAX_LENGTH)
50544
+ return 'too_long';
50545
+ if (isReservedEnvVar(entry))
50546
+ return 'reserved';
50547
+ const upper = entry.toUpperCase();
50548
+ if (((_a = options.taken) !== null && _a !== void 0 ? _a : []).some((taken) => taken.toUpperCase() === upper))
50549
+ return 'taken';
50550
+ return null;
50551
+ }
50552
+ /**
50553
+ * The backend refuses a duplicate variable with a plain-string 400
50554
+ * (`"ACME_KEY already exists for this organization."`), not a field error,
50555
+ * so the form has to recognise it to put the message under the right field.
50556
+ */
50557
+ function isSecretEnvVarTakenMessage(message) {
50558
+ return /already exists/i.test(message !== null && message !== void 0 ? message : '');
50559
+ }
50235
50560
 
50236
50561
  const mentorReducer = {
50237
50562
  [mentorApiSlice.reducerPath]: mentorApiSlice.reducer,
@@ -50295,6 +50620,7 @@ const mentorReducer = {
50295
50620
  [supportTicketsApiSlice.reducerPath]: supportTicketsApiSlice.reducer,
50296
50621
  [gradingApiSlice.reducerPath]: gradingApiSlice.reducer,
50297
50622
  [spendCapsApiSlice.reducerPath]: spendCapsApiSlice.reducer,
50623
+ [agentSettingsApiSlice.reducerPath]: agentSettingsApiSlice.reducer,
50298
50624
  [userChatHistoryApiSlice.reducerPath]: userChatHistoryApiSlice.reducer,
50299
50625
  [virtualMachineApiSlice.reducerPath]: virtualMachineApiSlice.reducer,
50300
50626
  [userLlmUsageApiSlice.reducerPath]: userLlmUsageApiSlice.reducer,
@@ -50361,6 +50687,7 @@ const mentorMiddleware = [
50361
50687
  supportTicketsApiSlice.middleware,
50362
50688
  gradingApiSlice.middleware,
50363
50689
  spendCapsApiSlice.middleware,
50690
+ agentSettingsApiSlice.middleware,
50364
50691
  userChatHistoryApiSlice.middleware,
50365
50692
  virtualMachineApiSlice.middleware,
50366
50693
  userLlmUsageApiSlice.middleware,
@@ -50408,6 +50735,7 @@ const skillsReducer = {
50408
50735
  [studioAuthoringApiSlice.reducerPath]: studioAuthoringApiSlice.reducer,
50409
50736
  [watchedGroupsApiSlice.reducerPath]: watchedGroupsApiSlice.reducer,
50410
50737
  [spendCapsApiSlice.reducerPath]: spendCapsApiSlice.reducer,
50738
+ [agentSettingsApiSlice.reducerPath]: agentSettingsApiSlice.reducer,
50411
50739
  [chatPrivacyApiSlice.reducerPath]: chatPrivacyApiSlice.reducer,
50412
50740
  [agentSkillsApiSlice.reducerPath]: agentSkillsApiSlice.reducer,
50413
50741
  [userChatHistoryApiSlice.reducerPath]: userChatHistoryApiSlice.reducer,
@@ -50457,6 +50785,7 @@ const skillsMiddleware = [
50457
50785
  studioAuthoringApiSlice.middleware,
50458
50786
  watchedGroupsApiSlice.middleware,
50459
50787
  spendCapsApiSlice.middleware,
50788
+ agentSettingsApiSlice.middleware,
50460
50789
  chatPrivacyApiSlice.middleware,
50461
50790
  agentSkillsApiSlice.middleware,
50462
50791
  userChatHistoryApiSlice.middleware,
@@ -50479,6 +50808,9 @@ const initializeDataLayer = (dmUrl, lmsUrl, legacyLmsUrl, storageService, httpEr
50479
50808
  Config.edxProxyEnabled = (_a = options === null || options === void 0 ? void 0 : options.edxProxy) !== null && _a !== void 0 ? _a : false;
50480
50809
  };
50481
50810
 
50811
+ exports.AGENT_SETTINGS_FIELD_PERMISSIONS_PATH = AGENT_SETTINGS_FIELD_PERMISSIONS_PATH;
50812
+ exports.AGENT_SETTINGS_QUERY_KEYS = AGENT_SETTINGS_QUERY_KEYS;
50813
+ exports.AGENT_SETTINGS_REDUCER_PATH = AGENT_SETTINGS_REDUCER_PATH;
50482
50814
  exports.AGENT_SKILLS_ENDPOINTS = AGENT_SKILLS_ENDPOINTS;
50483
50815
  exports.AGENT_SKILLS_REDUCER_PATH = AGENT_SKILLS_REDUCER_PATH;
50484
50816
  exports.AGENT_SKILLS_TAG_TYPES = AGENT_SKILLS_TAG_TYPES;
@@ -50526,6 +50858,7 @@ exports.GRADING_REDUCER_PATH = GRADING_REDUCER_PATH;
50526
50858
  exports.HOSTING_ENDPOINTS = HOSTING_ENDPOINTS;
50527
50859
  exports.HOSTING_QUERY_KEYS = HOSTING_QUERY_KEYS;
50528
50860
  exports.HOSTING_REDUCER_PATH = HOSTING_REDUCER_PATH;
50861
+ exports.IBLAI_ORG_HEADER = IBLAI_ORG_HEADER;
50529
50862
  exports.IblDataLayer = IblDataLayer;
50530
50863
  exports.LEARNER_COMPLETION_PATH = LEARNER_COMPLETION_PATH;
50531
50864
  exports.LOGO_ENDPOINTS = LOGO_ENDPOINTS;
@@ -50590,8 +50923,10 @@ exports.USER_PROGRESS_DATA_POINTS = USER_PROGRESS_DATA_POINTS;
50590
50923
  exports.USER_PROGRESS_SUMMARY_TYPE = USER_PROGRESS_SUMMARY_TYPE;
50591
50924
  exports.VERCEL_SPA = VERCEL_SPA;
50592
50925
  exports.VIRTUAL_MACHINE_DEFAULT_BILLING = VIRTUAL_MACHINE_DEFAULT_BILLING;
50926
+ exports.VIRTUAL_MACHINE_DEFAULT_HOST_PORT = VIRTUAL_MACHINE_DEFAULT_HOST_PORT;
50593
50927
  exports.VIRTUAL_MACHINE_EGRESS_PROFILES = VIRTUAL_MACHINE_EGRESS_PROFILES;
50594
50928
  exports.VIRTUAL_MACHINE_ENDPOINTS = VIRTUAL_MACHINE_ENDPOINTS;
50929
+ exports.VIRTUAL_MACHINE_ENV_VAR_MAX_LENGTH = VIRTUAL_MACHINE_ENV_VAR_MAX_LENGTH;
50595
50930
  exports.VIRTUAL_MACHINE_ENV_VAR_PATTERN = VIRTUAL_MACHINE_ENV_VAR_PATTERN;
50596
50931
  exports.VIRTUAL_MACHINE_HOST_PORT_PATTERN = VIRTUAL_MACHINE_HOST_PORT_PATTERN;
50597
50932
  exports.VIRTUAL_MACHINE_MAX_POLICY_HOSTS = VIRTUAL_MACHINE_MAX_POLICY_HOSTS;
@@ -50601,6 +50936,8 @@ exports.VIRTUAL_MACHINE_QUERY_KEYS = VIRTUAL_MACHINE_QUERY_KEYS;
50601
50936
  exports.VIRTUAL_MACHINE_REDUCER_PATH = VIRTUAL_MACHINE_REDUCER_PATH;
50602
50937
  exports.VIRTUAL_MACHINE_REJECTED_HOSTS = VIRTUAL_MACHINE_REJECTED_HOSTS;
50603
50938
  exports.VIRTUAL_MACHINE_REJECTED_HOST_SUFFIXES = VIRTUAL_MACHINE_REJECTED_HOST_SUFFIXES;
50939
+ exports.VIRTUAL_MACHINE_RESERVED_ENV_VARS = VIRTUAL_MACHINE_RESERVED_ENV_VARS;
50940
+ exports.VIRTUAL_MACHINE_RESERVED_ENV_VAR_PREFIXES = VIRTUAL_MACHINE_RESERVED_ENV_VAR_PREFIXES;
50604
50941
  exports.VIRTUAL_MACHINE_SECRET_VALUE_MIN_LENGTH = VIRTUAL_MACHINE_SECRET_VALUE_MIN_LENGTH;
50605
50942
  exports.WATCHED_GROUPS_ENDPOINTS = WATCHED_GROUPS_ENDPOINTS;
50606
50943
  exports.WATCHED_GROUPS_QUERY_KEYS = WATCHED_GROUPS_QUERY_KEYS;
@@ -50610,6 +50947,7 @@ exports.WATCHER_NOTIFICATION_EVENT_LABELS = WATCHER_NOTIFICATION_EVENT_LABELS;
50610
50947
  exports.WORKFLOWS_ENDPOINTS = WORKFLOWS_ENDPOINTS;
50611
50948
  exports.WORKFLOWS_QUERY_KEYS = WORKFLOWS_QUERY_KEYS;
50612
50949
  exports.WORKFLOWS_REDUCER_PATH = WORKFLOWS_REDUCER_PATH;
50950
+ exports.agentSettingsApiSlice = agentSettingsApiSlice;
50613
50951
  exports.agentSkillsApiSlice = agentSkillsApiSlice;
50614
50952
  exports.analyticsApiSlice = analyticsApiSlice;
50615
50953
  exports.apiKeysApiReducer = apiKeysApiReducer;
@@ -50649,6 +50987,7 @@ exports.credentialsCustomApiSlice = credentialsCustomApiSlice;
50649
50987
  exports.customAiSearchApiSlice = customAiSearchApiSlice;
50650
50988
  exports.customDomainApiSlice = customDomainApiSlice;
50651
50989
  exports.datasetsApiSlice = datasetsApiSlice;
50990
+ exports.deriveSecretEnvVar = deriveSecretEnvVar;
50652
50991
  exports.disclaimersApiSlice = disclaimersApiSlice;
50653
50992
  exports.edxProctoringApiSlice = edxProctoringApiSlice;
50654
50993
  exports.edxSsoApiSlice = edxSsoApiSlice;
@@ -50667,6 +51006,7 @@ exports.filterSlashSkills = filterSlashSkills;
50667
51006
  exports.findResumeBlock = findResumeBlock;
50668
51007
  exports.findUncoveredSecretHosts = findUncoveredSecretHosts;
50669
51008
  exports.flattenOutline = flattenOutline;
51009
+ exports.formatHostPort = formatHostPort;
50670
51010
  exports.getNextRecentMessagesPageParam = getNextRecentMessagesPageParam;
50671
51011
  exports.getSections = getSections;
50672
51012
  exports.getSpendCapExceededError = getSpendCapExceededError;
@@ -50683,6 +51023,8 @@ exports.isPoliciesResponse = isPoliciesResponse;
50683
51023
  exports.isPrivacyBlockedError = isPrivacyBlockedError;
50684
51024
  exports.isRejectedHostname = isRejectedHostname;
50685
51025
  exports.isRejectedIpAddress = isRejectedIpAddress;
51026
+ exports.isReservedEnvVar = isReservedEnvVar;
51027
+ exports.isSecretEnvVarTakenMessage = isSecretEnvVarTakenMessage;
50686
51028
  exports.isSpendCapExceededErrorBody = isSpendCapExceededErrorBody;
50687
51029
  exports.isUserLlmUsageEmpty = isUserLlmUsageEmpty;
50688
51030
  exports.isValidHostPort = isValidHostPort;
@@ -50700,6 +51042,7 @@ exports.mentorReducer = mentorReducer;
50700
51042
  exports.moderationLogsApiReducer = moderationLogsApiReducer;
50701
51043
  exports.moderationLogsApiSlice = moderationLogsApiSlice;
50702
51044
  exports.monetizationApiSlice = monetizationApiSlice;
51045
+ exports.normalizeHostInput = normalizeHostInput;
50703
51046
  exports.normalizeHostPort = normalizeHostPort;
50704
51047
  exports.normalizeLearnerCompletionError = normalizeLearnerCompletionError;
50705
51048
  exports.normalizeOutline = normalizeOutline;
@@ -50921,6 +51264,7 @@ exports.useGetAdminProjectDetailsQuery = useGetAdminProjectDetailsQuery;
50921
51264
  exports.useGetAdminProjectsQuery = useGetAdminProjectsQuery;
50922
51265
  exports.useGetAgentConfigQuery = useGetAgentConfigQuery;
50923
51266
  exports.useGetAgentCostQuery = useGetAgentCostQuery;
51267
+ exports.useGetAgentSettingsFieldPermissionsQuery = useGetAgentSettingsFieldPermissionsQuery;
50924
51268
  exports.useGetAgentSkillQuery = useGetAgentSkillQuery;
50925
51269
  exports.useGetAgentSkillResourceQuery = useGetAgentSkillResourceQuery;
50926
51270
  exports.useGetAgentSkillResourcesQuery = useGetAgentSkillResourcesQuery;
@@ -51213,6 +51557,7 @@ exports.useLazyGetAccountBillingInfoQuery = useLazyGetAccountBillingInfoQuery;
51213
51557
  exports.useLazyGetAdminProjectDetailsQuery = useLazyGetAdminProjectDetailsQuery;
51214
51558
  exports.useLazyGetAdminProjectsQuery = useLazyGetAdminProjectsQuery;
51215
51559
  exports.useLazyGetAgentConfigQuery = useLazyGetAgentConfigQuery;
51560
+ exports.useLazyGetAgentSettingsFieldPermissionsQuery = useLazyGetAgentSettingsFieldPermissionsQuery;
51216
51561
  exports.useLazyGetAgentSkillResourcesQuery = useLazyGetAgentSkillResourcesQuery;
51217
51562
  exports.useLazyGetAgentSkillsQuery = useLazyGetAgentSkillsQuery;
51218
51563
  exports.useLazyGetAgentSpendCapQuery = useLazyGetAgentSpendCapQuery;
@@ -51545,6 +51890,7 @@ exports.useUpdateGlobalMemoryMutation = useUpdateGlobalMemoryMutation;
51545
51890
  exports.useUpdateGraderCriterionMutation = useUpdateGraderCriterionMutation;
51546
51891
  exports.useUpdateHostingDomainMutation = useUpdateHostingDomainMutation;
51547
51892
  exports.useUpdateIntegrationCredentialMutation = useUpdateIntegrationCredentialMutation;
51893
+ exports.useUpdateLLMCredentialMutation = useUpdateLLMCredentialMutation;
51548
51894
  exports.useUpdateLtiKeyMutation = useUpdateLtiKeyMutation;
51549
51895
  exports.useUpdateLtiMentorMutation = useUpdateLtiMentorMutation;
51550
51896
  exports.useUpdateLtiToolMutation = useUpdateLtiToolMutation;
@@ -51631,6 +51977,7 @@ exports.userInvitationsApiSlice = userInvitationsApiSlice;
51631
51977
  exports.userLlmUsageApiSlice = userLlmUsageApiSlice;
51632
51978
  exports.validateHostPort = validateHostPort;
51633
51979
  exports.validateLearnerCompletionArgs = validateLearnerCompletionArgs;
51980
+ exports.validateSecretEnvVar = validateSecretEnvVar;
51634
51981
  exports.validateUserLlmUsageParams = validateUserLlmUsageParams;
51635
51982
  exports.virtualMachineApiSlice = virtualMachineApiSlice;
51636
51983
  exports.watchedGroupsApiSlice = watchedGroupsApiSlice;