@iblai/data-layer 1.39.0 → 1.41.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',
@@ -45616,6 +45711,110 @@ const moderationLogsApiSlice = react.createApi({
45616
45711
  const moderationLogsApiReducer = moderationLogsApiSlice.reducer;
45617
45712
  const { useGetModerationLogsQuery, useLazyGetModerationLogsQuery, useDeleteModerationLogMutation, } = moderationLogsApiSlice;
45618
45713
 
45714
+ const PRIVACY_FLAGS_REDUCER_PATH = 'privacyFlagsApiSlice';
45715
+ const PRIVACY_FLAGS_QUERY_KEYS = {
45716
+ PRIVACY_FLAGS: 'PRIVACY_FLAGS',
45717
+ PRIVACY_FLAG: 'PRIVACY_FLAG',
45718
+ };
45719
+ /** Guardrail that produced the detection. */
45720
+ const PRIVACY_FLAG_RAILS = ['pii', 'phi'];
45721
+ /** What the privacy router did with the detected content. */
45722
+ const PRIVACY_FLAG_ACTIONS = ['redact', 'mask', 'block', 'allow'];
45723
+ /** Where in the pipeline the detection happened. `file_*` sources carry file metadata. */
45724
+ const PRIVACY_FLAG_SOURCES = [
45725
+ 'text_prompt',
45726
+ 'file_text',
45727
+ 'file_image',
45728
+ 'file_pdf',
45729
+ 'llm_response',
45730
+ 'memory_retrieval',
45731
+ ];
45732
+ const encode = (value) => encodeURIComponent(String(value));
45733
+ const PRIVACY_FLAGS_ENDPOINTS = {
45734
+ LIST: {
45735
+ service: exports.SERVICES.DM,
45736
+ path: (org, userId) => `/api/ai-mentor/orgs/${encode(org)}/users/${encode(userId)}/privacy-flags/`,
45737
+ },
45738
+ RETRIEVE: {
45739
+ service: exports.SERVICES.DM,
45740
+ path: (org, userId, id) => `/api/ai-mentor/orgs/${encode(org)}/users/${encode(userId)}/privacy-flags/${encode(id)}/`,
45741
+ },
45742
+ };
45743
+
45744
+ /** Filter arg -> backend query key. */
45745
+ const QUERY_KEYS = {
45746
+ mentor: 'mentor',
45747
+ rail: 'rail',
45748
+ actionTaken: 'action_taken',
45749
+ source: 'source',
45750
+ sessionId: 'session_id',
45751
+ username: 'username',
45752
+ startTime: 'start_time',
45753
+ endTime: 'end_time',
45754
+ search: 'search',
45755
+ ordering: 'ordering',
45756
+ page: 'page',
45757
+ pageSize: 'page_size',
45758
+ };
45759
+ /** Builds the list query string, dropping empty filters. */
45760
+ const buildPrivacyFlagsQuery = (args) => {
45761
+ const params = new URLSearchParams();
45762
+ for (const [argKey, queryKey] of Object.entries(QUERY_KEYS)) {
45763
+ const value = args[argKey];
45764
+ if (value !== undefined && value !== null && value !== '') {
45765
+ params.append(queryKey, String(value));
45766
+ }
45767
+ }
45768
+ const query = params.toString();
45769
+ return query ? `?${query}` : '';
45770
+ };
45771
+ /**
45772
+ * GETs a DM path with the app's DM auth. Throws `{ status, body }` on non-2xx
45773
+ * so `buildEndpointFromService` keeps the HTTP status (403 stays detectable
45774
+ * and is never retried).
45775
+ */
45776
+ const fetchDmJson = async (path) => {
45777
+ const service = PRIVACY_FLAGS_ENDPOINTS.LIST.service;
45778
+ const headers = await getHeaders(service);
45779
+ const response = await fetch(`${getServiceUrl(service)}${path}`, {
45780
+ method: 'GET',
45781
+ headers: { Accept: 'application/json', ...(headers !== null && headers !== void 0 ? headers : {}) },
45782
+ credentials: 'omit',
45783
+ });
45784
+ const text = await response.text();
45785
+ let body = text;
45786
+ try {
45787
+ body = text ? JSON.parse(text) : null;
45788
+ }
45789
+ catch (_a) {
45790
+ // Non-JSON body (e.g. an HTML error page) — keep the raw text.
45791
+ }
45792
+ if (!response.ok) {
45793
+ throw { status: response.status, body };
45794
+ }
45795
+ return body;
45796
+ };
45797
+ const fetchPrivacyFlags = (args) => fetchDmJson(`${PRIVACY_FLAGS_ENDPOINTS.LIST.path(args.org, args.userId)}${buildPrivacyFlagsQuery(args)}`);
45798
+ const fetchPrivacyFlag = (args) => fetchDmJson(PRIVACY_FLAGS_ENDPOINTS.RETRIEVE.path(args.org, args.userId, args.id));
45799
+ const privacyFlagsApiSlice = react.createApi({
45800
+ reducerPath: PRIVACY_FLAGS_REDUCER_PATH,
45801
+ baseQuery: iblFakeBaseQuery,
45802
+ tagTypes: [PRIVACY_FLAGS_QUERY_KEYS.PRIVACY_FLAGS, PRIVACY_FLAGS_QUERY_KEYS.PRIVACY_FLAG],
45803
+ endpoints: (builder) => ({
45804
+ getPrivacyFlags: builder.query({
45805
+ ...buildEndpointFromService(PRIVACY_FLAGS_ENDPOINTS.LIST.service, fetchPrivacyFlags),
45806
+ providesTags: [PRIVACY_FLAGS_QUERY_KEYS.PRIVACY_FLAGS],
45807
+ }),
45808
+ getPrivacyFlag: builder.query({
45809
+ ...buildEndpointFromService(PRIVACY_FLAGS_ENDPOINTS.RETRIEVE.service, fetchPrivacyFlag),
45810
+ providesTags: (_result, _error, args) => [
45811
+ { type: PRIVACY_FLAGS_QUERY_KEYS.PRIVACY_FLAG, id: args.id },
45812
+ ],
45813
+ }),
45814
+ }),
45815
+ });
45816
+ const { useGetPrivacyFlagsQuery, useLazyGetPrivacyFlagsQuery, useGetPrivacyFlagQuery, useLazyGetPrivacyFlagQuery, } = privacyFlagsApiSlice;
45817
+
45619
45818
  /**
45620
45819
  * Privacy Router types and constants.
45621
45820
  *
@@ -49992,11 +50191,51 @@ const VIRTUAL_MACHINE_REJECTED_HOST_SUFFIXES = [
49992
50191
  ];
49993
50192
  /** `env_var` of a VM secret: a POSIX-style environment variable name. */
49994
50193
  const VIRTUAL_MACHINE_ENV_VAR_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/;
50194
+ /** The backend caps `env_var` at 128 characters. */
50195
+ const VIRTUAL_MACHINE_ENV_VAR_MAX_LENGTH = 128;
50196
+ /**
50197
+ * Variable names the UI refuses for a secret. The backend only checks the
50198
+ * POSIX shape, but the sandbox sets `env_var` in the VM's environment, so a
50199
+ * secret named PATH or LD_PRELOAD would break every command run there.
50200
+ */
50201
+ const VIRTUAL_MACHINE_RESERVED_ENV_VARS = [
50202
+ 'PATH',
50203
+ 'HOME',
50204
+ 'USER',
50205
+ 'LOGNAME',
50206
+ 'SHELL',
50207
+ 'PWD',
50208
+ 'OLDPWD',
50209
+ 'TMPDIR',
50210
+ 'TERM',
50211
+ 'LANG',
50212
+ 'LANGUAGE',
50213
+ 'LC_ALL',
50214
+ 'LD_PRELOAD',
50215
+ 'LD_LIBRARY_PATH',
50216
+ 'PYTHONPATH',
50217
+ 'PYTHONHOME',
50218
+ 'NODE_OPTIONS',
50219
+ 'HTTP_PROXY',
50220
+ 'HTTPS_PROXY',
50221
+ 'NO_PROXY',
50222
+ ];
50223
+ /** Prefixes the sandbox and ibl.ai keep for their own variables. */
50224
+ const VIRTUAL_MACHINE_RESERVED_ENV_VAR_PREFIXES = ['MSB_', 'IBLAI_'];
50225
+ /**
50226
+ * The port a bare hostname gets in an allowlist. Secrets are only ever
50227
+ * swapped into HTTPS requests, so `api.acme.com` means `api.acme.com:443`.
50228
+ */
50229
+ const VIRTUAL_MACHINE_DEFAULT_HOST_PORT = 443;
49995
50230
  /** A network policy holds between 1 and 100 hosts. */
49996
50231
  const VIRTUAL_MACHINE_MAX_POLICY_HOSTS = 100;
49997
50232
  /** An agent may bind at most 20 VM secrets. */
49998
50233
  const VIRTUAL_MACHINE_MAX_SECRETS_PER_MENTOR = 20;
49999
- /** A pasted secret value must be at least this long. */
50234
+ /**
50235
+ * The backend's floor for a pasted secret value (its output scrubber blanks
50236
+ * every occurrence of a bound value, so a very short one would blank too
50237
+ * much). The UI no longer checks it; a refusal is shown under the Key field.
50238
+ */
50000
50239
  const VIRTUAL_MACHINE_SECRET_VALUE_MIN_LENGTH = 8;
50001
50240
  /**
50002
50241
  * Default VM runtime billing: charged to the chatting user's credits, prorated
@@ -50016,12 +50255,14 @@ const VIRTUAL_MACHINE_DEFAULT_BILLING = {
50016
50255
  * Hand-written: these endpoints are newer than the pinned `@iblai/iblai-api`
50017
50256
  * release. Records are keyed in the body (PATCH) or the query string (DELETE),
50018
50257
  * never in the URL. A 403 on either list means the caller lacks the matching
50019
- * `Ibl.Mentor/VirtualMachine…/list` permission — hosts hide the pages then.
50258
+ * `Ibl.Mentor/VirtualMachine…/list` permission — hosts hide the pages then,
50259
+ * which needs the status: the base query returns failures rather than throwing
50260
+ * them, since RTK Query keeps only `{}` of a thrown `{ status, data }`.
50020
50261
  */
50021
50262
  const virtualMachineApiSlice = react.createApi({
50022
50263
  reducerPath: VIRTUAL_MACHINE_REDUCER_PATH,
50023
50264
  tagTypes: [VIRTUAL_MACHINE_QUERY_KEYS.NETWORK_POLICIES, VIRTUAL_MACHINE_QUERY_KEYS.SECRETS],
50024
- baseQuery: iblFetchBaseQuery,
50265
+ baseQuery: withReturnedErrors(iblFetchBaseQuery),
50025
50266
  endpoints: (builder) => ({
50026
50267
  // ── Network policies ────────────────────────────────────────────────
50027
50268
  listVirtualMachineNetworkPolicies: builder.query({
@@ -50102,6 +50343,21 @@ const virtualMachineApiSlice = react.createApi({
50102
50343
  });
50103
50344
  const { useListVirtualMachineNetworkPoliciesQuery, useLazyListVirtualMachineNetworkPoliciesQuery, useCreateVirtualMachineNetworkPolicyMutation, useUpdateVirtualMachineNetworkPolicyMutation, useDeleteVirtualMachineNetworkPolicyMutation, useListVirtualMachineSecretsQuery, useLazyListVirtualMachineSecretsQuery, useCreateVirtualMachineSecretMutation, useUpdateVirtualMachineSecretMutation, useDeleteVirtualMachineSecretMutation, } = virtualMachineApiSlice;
50104
50345
 
50346
+ var apiSlice = /*#__PURE__*/Object.freeze({
50347
+ __proto__: null,
50348
+ useCreateVirtualMachineNetworkPolicyMutation: useCreateVirtualMachineNetworkPolicyMutation,
50349
+ useCreateVirtualMachineSecretMutation: useCreateVirtualMachineSecretMutation,
50350
+ useDeleteVirtualMachineNetworkPolicyMutation: useDeleteVirtualMachineNetworkPolicyMutation,
50351
+ useDeleteVirtualMachineSecretMutation: useDeleteVirtualMachineSecretMutation,
50352
+ useLazyListVirtualMachineNetworkPoliciesQuery: useLazyListVirtualMachineNetworkPoliciesQuery,
50353
+ useLazyListVirtualMachineSecretsQuery: useLazyListVirtualMachineSecretsQuery,
50354
+ useListVirtualMachineNetworkPoliciesQuery: useListVirtualMachineNetworkPoliciesQuery,
50355
+ useListVirtualMachineSecretsQuery: useListVirtualMachineSecretsQuery,
50356
+ useUpdateVirtualMachineNetworkPolicyMutation: useUpdateVirtualMachineNetworkPolicyMutation,
50357
+ useUpdateVirtualMachineSecretMutation: useUpdateVirtualMachineSecretMutation,
50358
+ virtualMachineApiSlice: virtualMachineApiSlice
50359
+ });
50360
+
50105
50361
  /**
50106
50362
  * Normalise a `host:port` entry the way the backend stores it: trimmed and
50107
50363
  * lowercased.
@@ -50109,13 +50365,78 @@ const { useListVirtualMachineNetworkPoliciesQuery, useLazyListVirtualMachineNetw
50109
50365
  function normalizeHostPort(value) {
50110
50366
  return value.trim().toLowerCase();
50111
50367
  }
50368
+ const SCHEME_PORTS = { 'https:': 443, 'http:': 80 };
50369
+ // A loop rather than `/x+$/`, which takes quadratic time on a long run of x
50370
+ // that does not reach the end (CodeQL js/polynomial-redos).
50371
+ function trimChar(value, char, { start = false } = {}) {
50372
+ let from = 0;
50373
+ let to = value.length;
50374
+ if (start)
50375
+ while (from < to && value[from] === char)
50376
+ from += 1;
50377
+ while (to > from && value[to - 1] === char)
50378
+ to -= 1;
50379
+ return value.slice(from, to);
50380
+ }
50381
+ /**
50382
+ * Turn what a person typed or pasted into the `host:port` the backend stores.
50383
+ * People paste the address from a service's instructions, so a whole URL
50384
+ * (`https://api.acme.com/v1/keys`) is reduced to its host, with the scheme's
50385
+ * port unless the URL names one; `api.acme.com/v1` loses its path; a trailing
50386
+ * dot goes. Anything unparseable comes back trimmed and lowercased so
50387
+ * `validateHostPort` can explain it.
50388
+ */
50389
+ function normalizeHostInput(value, options = {}) {
50390
+ let entry = normalizeHostPort(value);
50391
+ if (entry.length === 0)
50392
+ return entry;
50393
+ let port = null;
50394
+ if (entry.includes('://')) {
50395
+ try {
50396
+ const url = new URL(entry);
50397
+ if (!url.hostname)
50398
+ return entry;
50399
+ port = url.port || (SCHEME_PORTS[url.protocol] ? String(SCHEME_PORTS[url.protocol]) : null);
50400
+ entry = url.hostname;
50401
+ }
50402
+ catch (_a) {
50403
+ return entry;
50404
+ }
50405
+ }
50406
+ else {
50407
+ const pathStart = entry.search(/[/?#]/);
50408
+ if (pathStart !== -1)
50409
+ entry = entry.slice(0, pathStart);
50410
+ }
50411
+ if (port === null) {
50412
+ const separator = entry.lastIndexOf(':');
50413
+ if (separator !== -1) {
50414
+ port = entry.slice(separator + 1);
50415
+ entry = entry.slice(0, separator);
50416
+ }
50417
+ }
50418
+ entry = trimChar(entry, '.');
50419
+ if (entry.length === 0)
50420
+ return entry;
50421
+ if (port)
50422
+ return `${entry}:${port}`;
50423
+ return options.defaultPort !== undefined ? `${entry}:${options.defaultPort}` : entry;
50424
+ }
50112
50425
  /** Split a pasted or typed string into candidate `host:port` entries. */
50113
- function splitHostPortInput(value) {
50426
+ function splitHostPortInput(value, options = {}) {
50114
50427
  return value
50115
50428
  .split(/[\s,;]+/)
50116
- .map(normalizeHostPort)
50429
+ .map((entry) => normalizeHostInput(entry, options))
50117
50430
  .filter((entry) => entry.length > 0);
50118
50431
  }
50432
+ /**
50433
+ * The `host:port` a person reads: the standard HTTPS port is implied, so
50434
+ * `api.acme.com:443` shows as `api.acme.com`; any other port stays visible.
50435
+ * The stored and compared form is never changed by this.
50436
+ */
50437
+ function formatHostPort(entry) {
50438
+ return entry.endsWith(':443') ? entry.slice(0, -4) : entry;
50439
+ }
50119
50440
  const IPV4_PATTERN = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/;
50120
50441
  /** Whether the host part is an IPv4 literal (the `host:port` grammar admits no IPv6). */
50121
50442
  function isIpAddressHost(host) {
@@ -50271,6 +50592,75 @@ function findUncoveredSecretHosts(secrets, allowedHosts) {
50271
50592
  }
50272
50593
  return uncovered;
50273
50594
  }
50595
+ /** Whether a variable name is one the VM itself relies on (see the reserved list). */
50596
+ function isReservedEnvVar(name) {
50597
+ const upper = name.toUpperCase();
50598
+ if (VIRTUAL_MACHINE_RESERVED_ENV_VARS.includes(upper))
50599
+ return true;
50600
+ return VIRTUAL_MACHINE_RESERVED_ENV_VAR_PREFIXES.some((prefix) => upper.startsWith(prefix));
50601
+ }
50602
+ const ENV_VAR_WORDS = ['KEY', 'TOKEN', 'SECRET', 'PASSWORD'];
50603
+ const ENV_VAR_FALLBACK = 'SECRET';
50604
+ /** Leaves room for a `_NN` suffix under the backend's 128-character cap. */
50605
+ const ENV_VAR_DERIVED_MAX_LENGTH = VIRTUAL_MACHINE_ENV_VAR_MAX_LENGTH - 8;
50606
+ /**
50607
+ * The variable name a secret gets from its display name, so a person never
50608
+ * has to invent one: "Acme API key" → `ACME_API_KEY`, "Clé Stripe" →
50609
+ * `CLE_STRIPE_KEY`. Accents are folded, every other run of characters becomes
50610
+ * an underscore, a leading digit gets `KEY_` in front, a name without
50611
+ * KEY/TOKEN/SECRET/PASSWORD gets `_KEY` (which also keeps "Path" from
50612
+ * becoming the VM's PATH), nothing derivable falls back to `SECRET`, and a
50613
+ * clash with `taken` gets `_2`, `_3`, …
50614
+ */
50615
+ function deriveSecretEnvVar(name, options = {}) {
50616
+ var _a;
50617
+ let base = trimChar(name
50618
+ .normalize('NFKD')
50619
+ .replace(/[\u0300-\u036f]/g, '')
50620
+ .toUpperCase()
50621
+ .replace(/[^A-Z0-9]+/g, '_'), '_', { start: true }).replace(/_{2,}/g, '_');
50622
+ if (base.length === 0)
50623
+ base = ENV_VAR_FALLBACK;
50624
+ if (/^[0-9]/.test(base))
50625
+ base = `KEY_${base}`;
50626
+ if (!ENV_VAR_WORDS.some((word) => base.split('_').includes(word)))
50627
+ base = `${base}_KEY`;
50628
+ if (isReservedEnvVar(base))
50629
+ base = `KEY_${base}`;
50630
+ base = trimChar(base.slice(0, ENV_VAR_DERIVED_MAX_LENGTH), '_');
50631
+ const taken = new Set(((_a = options.taken) !== null && _a !== void 0 ? _a : []).map((entry) => entry.toUpperCase()));
50632
+ if (!taken.has(base))
50633
+ return base;
50634
+ for (let suffix = 2;; suffix += 1) {
50635
+ const candidate = `${base}_${suffix}`;
50636
+ if (!taken.has(candidate))
50637
+ return candidate;
50638
+ }
50639
+ }
50640
+ function validateSecretEnvVar(value, options = {}) {
50641
+ var _a;
50642
+ const entry = value.trim();
50643
+ if (entry.length === 0)
50644
+ return 'required';
50645
+ if (!VIRTUAL_MACHINE_ENV_VAR_PATTERN.test(entry))
50646
+ return 'format';
50647
+ if (entry.length > VIRTUAL_MACHINE_ENV_VAR_MAX_LENGTH)
50648
+ return 'too_long';
50649
+ if (isReservedEnvVar(entry))
50650
+ return 'reserved';
50651
+ const upper = entry.toUpperCase();
50652
+ if (((_a = options.taken) !== null && _a !== void 0 ? _a : []).some((taken) => taken.toUpperCase() === upper))
50653
+ return 'taken';
50654
+ return null;
50655
+ }
50656
+ /**
50657
+ * The backend refuses a duplicate variable with a plain-string 400
50658
+ * (`"ACME_KEY already exists for this organization."`), not a field error,
50659
+ * so the form has to recognise it to put the message under the right field.
50660
+ */
50661
+ function isSecretEnvVarTakenMessage(message) {
50662
+ return /already exists/i.test(message !== null && message !== void 0 ? message : '');
50663
+ }
50274
50664
 
50275
50665
  const mentorReducer = {
50276
50666
  [mentorApiSlice.reducerPath]: mentorApiSlice.reducer,
@@ -50320,6 +50710,7 @@ const mentorReducer = {
50320
50710
  [billingCustomSlice.reducerPath]: billingCustomSlice.reducer,
50321
50711
  [retirementApiSlice.reducerPath]: retirementApiSlice.reducer,
50322
50712
  [auditLogsApiSlice.reducerPath]: auditLogsApiSlice.reducer,
50713
+ [privacyFlagsApiSlice.reducerPath]: privacyFlagsApiSlice.reducer,
50323
50714
  [monetizationApiSlice.reducerPath]: monetizationApiSlice.reducer,
50324
50715
  [coursesApiSlice.reducerPath]: coursesApiSlice.reducer,
50325
50716
  [courseMetadataApiSlice.reducerPath]: courseMetadataApiSlice.reducer,
@@ -50387,6 +50778,7 @@ const mentorMiddleware = [
50387
50778
  billingCustomSlice.middleware,
50388
50779
  retirementApiSlice.middleware,
50389
50780
  auditLogsApiSlice.middleware,
50781
+ privacyFlagsApiSlice.middleware,
50390
50782
  monetizationApiSlice.middleware,
50391
50783
  coursesApiSlice.middleware,
50392
50784
  courseMetadataApiSlice.middleware,
@@ -50602,6 +50994,12 @@ exports.PLATFORM_MEMBERSHIP_TAG = PLATFORM_MEMBERSHIP_TAG;
50602
50994
  exports.PRIVACY_ACTIONS = PRIVACY_ACTIONS;
50603
50995
  exports.PRIVACY_BLOCKED_ERROR_KIND = PRIVACY_BLOCKED_ERROR_KIND;
50604
50996
  exports.PRIVACY_ENTITY_TYPES = PRIVACY_ENTITY_TYPES;
50997
+ exports.PRIVACY_FLAGS_ENDPOINTS = PRIVACY_FLAGS_ENDPOINTS;
50998
+ exports.PRIVACY_FLAGS_QUERY_KEYS = PRIVACY_FLAGS_QUERY_KEYS;
50999
+ exports.PRIVACY_FLAGS_REDUCER_PATH = PRIVACY_FLAGS_REDUCER_PATH;
51000
+ exports.PRIVACY_FLAG_ACTIONS = PRIVACY_FLAG_ACTIONS;
51001
+ exports.PRIVACY_FLAG_RAILS = PRIVACY_FLAG_RAILS;
51002
+ exports.PRIVACY_FLAG_SOURCES = PRIVACY_FLAG_SOURCES;
50605
51003
  exports.PRIVACY_TARGET_SYSTEM = PRIVACY_TARGET_SYSTEM;
50606
51004
  exports.PROJECTS_CUSTOM_ENDPOINTS = PROJECTS_CUSTOM_ENDPOINTS;
50607
51005
  exports.PROJECTS_CUSTOM_REDUCER_PATH = PROJECTS_CUSTOM_REDUCER_PATH;
@@ -50637,8 +51035,10 @@ exports.USER_PROGRESS_DATA_POINTS = USER_PROGRESS_DATA_POINTS;
50637
51035
  exports.USER_PROGRESS_SUMMARY_TYPE = USER_PROGRESS_SUMMARY_TYPE;
50638
51036
  exports.VERCEL_SPA = VERCEL_SPA;
50639
51037
  exports.VIRTUAL_MACHINE_DEFAULT_BILLING = VIRTUAL_MACHINE_DEFAULT_BILLING;
51038
+ exports.VIRTUAL_MACHINE_DEFAULT_HOST_PORT = VIRTUAL_MACHINE_DEFAULT_HOST_PORT;
50640
51039
  exports.VIRTUAL_MACHINE_EGRESS_PROFILES = VIRTUAL_MACHINE_EGRESS_PROFILES;
50641
51040
  exports.VIRTUAL_MACHINE_ENDPOINTS = VIRTUAL_MACHINE_ENDPOINTS;
51041
+ exports.VIRTUAL_MACHINE_ENV_VAR_MAX_LENGTH = VIRTUAL_MACHINE_ENV_VAR_MAX_LENGTH;
50642
51042
  exports.VIRTUAL_MACHINE_ENV_VAR_PATTERN = VIRTUAL_MACHINE_ENV_VAR_PATTERN;
50643
51043
  exports.VIRTUAL_MACHINE_HOST_PORT_PATTERN = VIRTUAL_MACHINE_HOST_PORT_PATTERN;
50644
51044
  exports.VIRTUAL_MACHINE_MAX_POLICY_HOSTS = VIRTUAL_MACHINE_MAX_POLICY_HOSTS;
@@ -50648,6 +51048,8 @@ exports.VIRTUAL_MACHINE_QUERY_KEYS = VIRTUAL_MACHINE_QUERY_KEYS;
50648
51048
  exports.VIRTUAL_MACHINE_REDUCER_PATH = VIRTUAL_MACHINE_REDUCER_PATH;
50649
51049
  exports.VIRTUAL_MACHINE_REJECTED_HOSTS = VIRTUAL_MACHINE_REJECTED_HOSTS;
50650
51050
  exports.VIRTUAL_MACHINE_REJECTED_HOST_SUFFIXES = VIRTUAL_MACHINE_REJECTED_HOST_SUFFIXES;
51051
+ exports.VIRTUAL_MACHINE_RESERVED_ENV_VARS = VIRTUAL_MACHINE_RESERVED_ENV_VARS;
51052
+ exports.VIRTUAL_MACHINE_RESERVED_ENV_VAR_PREFIXES = VIRTUAL_MACHINE_RESERVED_ENV_VAR_PREFIXES;
50651
51053
  exports.VIRTUAL_MACHINE_SECRET_VALUE_MIN_LENGTH = VIRTUAL_MACHINE_SECRET_VALUE_MIN_LENGTH;
50652
51054
  exports.WATCHED_GROUPS_ENDPOINTS = WATCHED_GROUPS_ENDPOINTS;
50653
51055
  exports.WATCHED_GROUPS_QUERY_KEYS = WATCHED_GROUPS_QUERY_KEYS;
@@ -50673,6 +51075,7 @@ exports.billingCustomSlice = billingCustomSlice;
50673
51075
  exports.buildGlobalSearchUrl = buildGlobalSearchUrl;
50674
51076
  exports.buildLearnerCompletionUrl = buildLearnerCompletionUrl;
50675
51077
  exports.buildPinnedMessagesUrl = buildPinnedMessagesUrl;
51078
+ exports.buildPrivacyFlagsQuery = buildPrivacyFlagsQuery;
50676
51079
  exports.buildRecentMessagesUrl = buildRecentMessagesUrl;
50677
51080
  exports.buildSessionRetrieveUrl = buildSessionRetrieveUrl;
50678
51081
  exports.buildSharedSessionRetrieveUrl = buildSharedSessionRetrieveUrl;
@@ -50697,6 +51100,7 @@ exports.credentialsCustomApiSlice = credentialsCustomApiSlice;
50697
51100
  exports.customAiSearchApiSlice = customAiSearchApiSlice;
50698
51101
  exports.customDomainApiSlice = customDomainApiSlice;
50699
51102
  exports.datasetsApiSlice = datasetsApiSlice;
51103
+ exports.deriveSecretEnvVar = deriveSecretEnvVar;
50700
51104
  exports.disclaimersApiSlice = disclaimersApiSlice;
50701
51105
  exports.edxProctoringApiSlice = edxProctoringApiSlice;
50702
51106
  exports.edxSsoApiSlice = edxSsoApiSlice;
@@ -50707,6 +51111,8 @@ exports.fakeBaseQueryWithLogging = fakeBaseQueryWithLogging;
50707
51111
  exports.featureTags = featureTags;
50708
51112
  exports.fetchLatestMentorSessionId = fetchLatestMentorSessionId;
50709
51113
  exports.fetchLearnerCompletion = fetchLearnerCompletion;
51114
+ exports.fetchPrivacyFlag = fetchPrivacyFlag;
51115
+ exports.fetchPrivacyFlags = fetchPrivacyFlags;
50710
51116
  exports.fetchUserLlmUsage = fetchUserLlmUsage;
50711
51117
  exports.filterCourseUserRoles = filterCourseUserRoles;
50712
51118
  exports.filterGlobalUserRoles = filterGlobalUserRoles;
@@ -50715,6 +51121,7 @@ exports.filterSlashSkills = filterSlashSkills;
50715
51121
  exports.findResumeBlock = findResumeBlock;
50716
51122
  exports.findUncoveredSecretHosts = findUncoveredSecretHosts;
50717
51123
  exports.flattenOutline = flattenOutline;
51124
+ exports.formatHostPort = formatHostPort;
50718
51125
  exports.getNextRecentMessagesPageParam = getNextRecentMessagesPageParam;
50719
51126
  exports.getSections = getSections;
50720
51127
  exports.getSpendCapExceededError = getSpendCapExceededError;
@@ -50731,6 +51138,8 @@ exports.isPoliciesResponse = isPoliciesResponse;
50731
51138
  exports.isPrivacyBlockedError = isPrivacyBlockedError;
50732
51139
  exports.isRejectedHostname = isRejectedHostname;
50733
51140
  exports.isRejectedIpAddress = isRejectedIpAddress;
51141
+ exports.isReservedEnvVar = isReservedEnvVar;
51142
+ exports.isSecretEnvVarTakenMessage = isSecretEnvVarTakenMessage;
50734
51143
  exports.isSpendCapExceededErrorBody = isSpendCapExceededErrorBody;
50735
51144
  exports.isUserLlmUsageEmpty = isUserLlmUsageEmpty;
50736
51145
  exports.isValidHostPort = isValidHostPort;
@@ -50748,6 +51157,7 @@ exports.mentorReducer = mentorReducer;
50748
51157
  exports.moderationLogsApiReducer = moderationLogsApiReducer;
50749
51158
  exports.moderationLogsApiSlice = moderationLogsApiSlice;
50750
51159
  exports.monetizationApiSlice = monetizationApiSlice;
51160
+ exports.normalizeHostInput = normalizeHostInput;
50751
51161
  exports.normalizeHostPort = normalizeHostPort;
50752
51162
  exports.normalizeLearnerCompletionError = normalizeLearnerCompletionError;
50753
51163
  exports.normalizeOutline = normalizeOutline;
@@ -50759,6 +51169,7 @@ exports.periodicAgentsApiSlice = periodicAgentsApiSlice;
50759
51169
  exports.platformApiReducer = platformApiReducer;
50760
51170
  exports.platformApiSlice = platformApiSlice;
50761
51171
  exports.platformCustomApiSlice = platformCustomApiSlice;
51172
+ exports.privacyFlagsApiSlice = privacyFlagsApiSlice;
50762
51173
  exports.projectsApiSlice = projectsApiSlice;
50763
51174
  exports.promptsApiSlice = promptsApiSlice;
50764
51175
  exports.readMeasure = readMeasure;
@@ -51127,6 +51538,8 @@ exports.useGetPlatformImageAssetsListQuery = useGetPlatformImageAssetsListQuery;
51127
51538
  exports.useGetPlatformInfoQuery = useGetPlatformInfoQuery;
51128
51539
  exports.useGetPlatformMembershipQuery = useGetPlatformMembershipQuery;
51129
51540
  exports.useGetPlatformUserGroupDetailsQuery = useGetPlatformUserGroupDetailsQuery;
51541
+ exports.useGetPrivacyFlagQuery = useGetPrivacyFlagQuery;
51542
+ exports.useGetPrivacyFlagsQuery = useGetPrivacyFlagsQuery;
51130
51543
  exports.useGetProgramCompletionQuery = useGetProgramCompletionQuery;
51131
51544
  exports.useGetProgramListQuery = useGetProgramListQuery;
51132
51545
  exports.useGetPromptCategoriesQuery = useGetPromptCategoriesQuery;
@@ -51378,6 +51791,8 @@ exports.useLazyGetPinnedMessagesQuery = useLazyGetPinnedMessagesQuery;
51378
51791
  exports.useLazyGetPlatformAuditLogsQuery = useLazyGetPlatformAuditLogsQuery;
51379
51792
  exports.useLazyGetPlatformInfoQuery = useLazyGetPlatformInfoQuery;
51380
51793
  exports.useLazyGetPlatformMembershipQuery = useLazyGetPlatformMembershipQuery;
51794
+ exports.useLazyGetPrivacyFlagQuery = useLazyGetPrivacyFlagQuery;
51795
+ exports.useLazyGetPrivacyFlagsQuery = useLazyGetPrivacyFlagsQuery;
51381
51796
  exports.useLazyGetProgramCompletionQuery = useLazyGetProgramCompletionQuery;
51382
51797
  exports.useLazyGetProgramListQuery = useLazyGetProgramListQuery;
51383
51798
  exports.useLazyGetPromptCategoriesQuery = useLazyGetPromptCategoriesQuery;
@@ -51595,6 +52010,7 @@ exports.useUpdateGlobalMemoryMutation = useUpdateGlobalMemoryMutation;
51595
52010
  exports.useUpdateGraderCriterionMutation = useUpdateGraderCriterionMutation;
51596
52011
  exports.useUpdateHostingDomainMutation = useUpdateHostingDomainMutation;
51597
52012
  exports.useUpdateIntegrationCredentialMutation = useUpdateIntegrationCredentialMutation;
52013
+ exports.useUpdateLLMCredentialMutation = useUpdateLLMCredentialMutation;
51598
52014
  exports.useUpdateLtiKeyMutation = useUpdateLtiKeyMutation;
51599
52015
  exports.useUpdateLtiMentorMutation = useUpdateLtiMentorMutation;
51600
52016
  exports.useUpdateLtiToolMutation = useUpdateLtiToolMutation;
@@ -51681,6 +52097,7 @@ exports.userInvitationsApiSlice = userInvitationsApiSlice;
51681
52097
  exports.userLlmUsageApiSlice = userLlmUsageApiSlice;
51682
52098
  exports.validateHostPort = validateHostPort;
51683
52099
  exports.validateLearnerCompletionArgs = validateLearnerCompletionArgs;
52100
+ exports.validateSecretEnvVar = validateSecretEnvVar;
51684
52101
  exports.validateUserLlmUsageParams = validateUserLlmUsageParams;
51685
52102
  exports.virtualMachineApiSlice = virtualMachineApiSlice;
51686
52103
  exports.watchedGroupsApiSlice = watchedGroupsApiSlice;