@ionite/server 0.0.24-beta.20260907.3 → 0.0.24-beta.20260910.1

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.d.ts CHANGED
@@ -384,7 +384,7 @@ declare class InMemoryCustomerStore<TExtended = Record<string, never>> implement
384
384
  delete(id: string): Promise<number>;
385
385
  list(options?: ListOptions3): Promise<ListResult3<BaseCustomer<TExtended>>>;
386
386
  }
387
- import { AccessAssignmentStore as AccessAssignmentStore2, AccessCatalogStore as AccessCatalogStore2, BaseUser as BaseUser2, CodeCatalog, CustomerStore as CustomerStore2, IamDeltaEmitter, IamDeltaMode, Logger as Logger4, ScimUser, UserStore, Workload as Workload2, WorkloadIdentityStore } from "@ionite/core";
387
+ import { AccessAssignmentStore as AccessAssignmentStore2, AccessCatalogStore as AccessCatalogStore2, BaseCustomer as BaseCustomer2, BaseUser as BaseUser2, BaseWorkloadIdentity, CodeCatalog, CustomerStore as CustomerStore2, IamDeltaEmitter, IamDeltaMode, Logger as Logger4, ScimCustomer, ScimUser, ScimWorkload, UserStore, Workload as Workload2, WorkloadIdentityStore } from "@ionite/core";
388
388
  type FetchLike = (input: string, init?: RequestInit) => Promise<Response>;
389
389
  /** RemoteConfig-derived destination descriptor for IAM delta egress. */
390
390
  type IamDeltaConfig = {
@@ -408,6 +408,10 @@ type IamDeltaDeps = {
408
408
  codeCatalog?: CodeCatalog;
409
409
  /** Optional app mapper shared with the inbound IAM Users read surface. */
410
410
  mapUserToScim?: (stored: BaseUser2) => ScimUser | Promise<ScimUser>;
411
+ /** Optional app mapper shared with the inbound IAM Customers read surface. */
412
+ mapCustomerToScim?: (stored: BaseCustomer2) => ScimCustomer | Promise<ScimCustomer>;
413
+ /** Optional app mapper shared with the inbound IAM Workloads read surface. */
414
+ mapWorkloadToScim?: (stored: BaseWorkloadIdentity) => ScimWorkload | Promise<ScimWorkload>;
411
415
  /** Injectable fetch (defaults to global fetch); enables testing the patch path in-process. */
412
416
  fetchImpl?: FetchLike;
413
417
  };
@@ -518,13 +522,13 @@ declare const ION_CAPABILITY_CATALOG: readonly [{
518
522
  readonly requires: "AccessAssignmentStore + AccessCatalogStore";
519
523
  readonly incapableReason: "OAA projection is configured by RemoteConfig but no access/catalog store capability is wired by the application.";
520
524
  }];
521
- import { BaseCustomer as BaseCustomer2, MagicLink, MagicLinkStore } from "@ionite/core";
525
+ import { BaseCustomer as BaseCustomer3, MagicLink, MagicLinkStore } from "@ionite/core";
522
526
  /**
523
527
  * In-memory implementation of MagicLinkStore from @ionite/core.
524
528
  */
525
529
  declare class InMemoryMagicLinkStore<TExtended = Record<string, never>> implements MagicLinkStore<TExtended> {
526
530
  private magicLinks;
527
- create(token: string, customer: BaseCustomer2, expiresAt: Date): Promise<void>;
531
+ create(token: string, customer: BaseCustomer3, expiresAt: Date): Promise<void>;
528
532
  get(token: string): Promise<MagicLink<TExtended> | null>;
529
533
  getAndDelete(token: string): Promise<MagicLink<TExtended> | null>;
530
534
  delete(token: string): Promise<void>;
@@ -851,7 +855,7 @@ declare function closeAllVaultSockets(): void;
851
855
  *
852
856
  * Keep this synchronized with packages/server/package.json via publish.ts.
853
857
  */
854
- declare const ION_SDK_VERSION = "0.0.24-beta.20260907.3";
858
+ declare const ION_SDK_VERSION = "0.0.24-beta.20260910.1";
855
859
  import { Workload as CoreWorkload, FrameworkWorkloadConfig, Ionite as Ionite5, JWTAssertionClaims, Logger as Logger7, TokenValidationResult, TrustedIdp, WorkloadConfigMap, WorkloadGetToken, WorkloadIdentityStore as WorkloadIdentityStore2, WorkloadIncomingOutgoing, WorkloadTokenResponse, WorkloadTokenStore } from "@ionite/core";
856
860
  import { StandardSchemaV1 } from "@standard-schema/spec";
857
861
  /**
@@ -1114,7 +1118,7 @@ declare function revokeWorkloadToken(token: string, ion: Ionite5): Promise<void>
1114
1118
  * Framework-agnostic request handler for the Workload module (token, validate, jwks, refresh routes).
1115
1119
  */
1116
1120
  declare function workloadHandler(request: Request, ion: Ionite5): Promise<Response>;
1117
- import { BaseWorkloadIdentity, ListOptions as ListOptions5, ListResult as ListResult5, WorkloadIdentityStore as WorkloadIdentityStore3 } from "@ionite/core";
1121
+ import { BaseWorkloadIdentity as BaseWorkloadIdentity2, ListOptions as ListOptions5, ListResult as ListResult5, WorkloadIdentityStore as WorkloadIdentityStore3 } from "@ionite/core";
1118
1122
  /**
1119
1123
  * In-memory {@link WorkloadIdentityStore} implementation using Maps. Suitable for development and
1120
1124
  * testing; use a durable store (e.g. Redis/SQL) in production.
@@ -1123,12 +1127,12 @@ declare class InMemoryWorkloadIdentityStore<TExtended = Record<string, never>> i
1123
1127
  private identities;
1124
1128
  private clientIdIndex;
1125
1129
  private externalIdIndex;
1126
- get(id: string): Promise<BaseWorkloadIdentity<TExtended> | undefined>;
1127
- lookup(identity: BaseWorkloadIdentity<TExtended>): Promise<BaseWorkloadIdentity<TExtended> | undefined>;
1128
- getByExternalId(externalId: string): Promise<BaseWorkloadIdentity<TExtended> | undefined>;
1129
- upsert(identity: BaseWorkloadIdentity<TExtended>): Promise<BaseWorkloadIdentity<TExtended>>;
1130
+ get(id: string): Promise<BaseWorkloadIdentity2<TExtended> | undefined>;
1131
+ lookup(identity: BaseWorkloadIdentity2<TExtended>): Promise<BaseWorkloadIdentity2<TExtended> | undefined>;
1132
+ getByExternalId(externalId: string): Promise<BaseWorkloadIdentity2<TExtended> | undefined>;
1133
+ upsert(identity: BaseWorkloadIdentity2<TExtended>): Promise<BaseWorkloadIdentity2<TExtended>>;
1130
1134
  delete(id: string): Promise<number>;
1131
- list(options?: ListOptions5): Promise<ListResult5<BaseWorkloadIdentity<TExtended>>>;
1135
+ list(options?: ListOptions5): Promise<ListResult5<BaseWorkloadIdentity2<TExtended>>>;
1132
1136
  }
1133
1137
  import { CachedWorkloadToken, WorkloadTokenStore as WorkloadTokenStore2 } from "@ionite/core";
1134
1138
  /**
package/dist/index.js CHANGED
@@ -504,7 +504,12 @@ import {
504
504
 
505
505
  // packages/server/src/oaa.ts
506
506
  import { accessRefId, accessRootId, ION_AUTHZ_GROUP_SCHEMA, mergeCodeCatalogEntity } from "@ionite/core";
507
- import { collectReferencedDefinitions } from "@ionite/core/server";
507
+ import {
508
+ baseCustomerToScim,
509
+ baseUserToScimUser,
510
+ baseWorkloadToScim,
511
+ collectReferencedDefinitions
512
+ } from "@ionite/core/server";
508
513
 
509
514
  // packages/server/src/readiness-latch.ts
510
515
  function createReadinessLatch(name, isActive, makeTimeoutError = (timeout) => new Error(`${name} ready timed out after ${timeout}ms`)) {
@@ -589,7 +594,9 @@ function isOaaConfigured(getConfig) {
589
594
  const config = getConfig();
590
595
  return Boolean(config?.url && config.providerId && config.datasourceId);
591
596
  }
592
- function createOaaClient(log, getConfig, getTransforms, getTrustedClientGrants, getCatalog) {
597
+ function createOaaClient(log, getConfig, getTransforms, getPrincipalMappers = () => ({}), getAccessStore = () => {
598
+ return;
599
+ }, getTrustedClientGrants, getCatalog) {
593
600
  const pushIncremental = async (payload) => {
594
601
  await pushPayload(log, getRequiredConfig(getConfig), payload, { mode: "incremental" });
595
602
  };
@@ -598,9 +605,29 @@ function createOaaClient(log, getConfig, getTransforms, getTrustedClientGrants,
598
605
  isReady: latch.isReady,
599
606
  ready: latch.ready,
600
607
  refreshReadiness: latch.refresh,
608
+ population(kind) {
609
+ return principalPopulation(getConfig(), kind);
610
+ },
601
611
  async pushUser(user) {
602
612
  const config = getRequiredConfig(getConfig);
603
- await pushIncremental(singleApplicationPayload(config, { local_users: [mapUser(user, "modify")] }, true));
613
+ if (!await shouldPushPrincipal(config, "user", accessRefId(user), getAccessStore()))
614
+ return;
615
+ const mapped = await projectUser(user, getPrincipalMappers());
616
+ await pushIncremental(singleApplicationPayload(config, { local_users: [mapScimPrincipal(mapped, "user", "modify")] }, true));
617
+ },
618
+ async pushCustomer(customer) {
619
+ const config = getRequiredConfig(getConfig);
620
+ if (!await shouldPushPrincipal(config, "customer", accessRefId(customer), getAccessStore()))
621
+ return;
622
+ const mapped = await projectCustomer(customer, getPrincipalMappers());
623
+ await pushIncremental(singleApplicationPayload(config, { local_users: [mapScimPrincipal(mapped, "customer", "modify")] }, true));
624
+ },
625
+ async pushWorkload(workload) {
626
+ const config = getRequiredConfig(getConfig);
627
+ if (!await shouldPushPrincipal(config, "workload", accessRefId(workload), getAccessStore()))
628
+ return;
629
+ const mapped = await projectWorkload(workload, getPrincipalMappers());
630
+ await pushIncremental(singleApplicationPayload(config, { local_users: [mapScimPrincipal(mapped, "workload", "modify")] }, true));
604
631
  },
605
632
  async pushGroup(group) {
606
633
  const config = getRequiredConfig(getConfig);
@@ -654,6 +681,14 @@ function createOaaClient(log, getConfig, getTransforms, getTrustedClientGrants,
654
681
  const config = getRequiredConfig(getConfig);
655
682
  await pushIncremental(singleApplicationPayload(config, { local_users: [{ name: id, unique_id: id, operation: "delete" }] }, true));
656
683
  },
684
+ async deleteCustomer(id) {
685
+ const config = getRequiredConfig(getConfig);
686
+ await pushIncremental(singleApplicationPayload(config, { local_users: [deletedPrincipal(id, "customer")] }, true));
687
+ },
688
+ async deleteWorkload(id) {
689
+ const config = getRequiredConfig(getConfig);
690
+ await pushIncremental(singleApplicationPayload(config, { local_users: [deletedPrincipal(id, "workload")] }, true));
691
+ },
657
692
  async deleteGroup(id) {
658
693
  const config = getRequiredConfig(getConfig);
659
694
  await pushIncremental(singleApplicationPayload(config, { local_groups: [{ name: id, unique_id: id, operation: "delete" }] }, true));
@@ -674,7 +709,7 @@ function createOaaClient(log, getConfig, getTransforms, getTrustedClientGrants,
674
709
  const config = getRequiredConfig(getConfig);
675
710
  const incremental = options?.mode === "incremental";
676
711
  const extraAccess = incremental ? undefined : getTrustedClientGrants?.();
677
- const payload = await buildSyncPayload(config, input, getTransforms(), incremental, extraAccess);
712
+ const payload = await buildSyncPayload(config, input, getTransforms(), getPrincipalMappers(), incremental, extraAccess);
678
713
  return pushPayload(log, config, payload, options);
679
714
  }
680
715
  };
@@ -686,7 +721,7 @@ function getRequiredConfig(getConfig) {
686
721
  }
687
722
  return config;
688
723
  }
689
- async function buildSyncPayload(config, input, transforms, incremental, extraAccess) {
724
+ async function buildSyncPayload(config, input, transforms, principalMappers, incremental, extraAccess) {
690
725
  const localUsers = [];
691
726
  const localGroups = [];
692
727
  const resources = [];
@@ -695,9 +730,28 @@ async function buildSyncPayload(config, input, transforms, incremental, extraAcc
695
730
  const identityToPermissions = [];
696
731
  const op = incremental ? "modify" : undefined;
697
732
  const seenAccessKeys = new Set;
733
+ const accessChanges = [];
734
+ const accessSubjects = new Set;
698
735
  const accessKey = (change) => accessRootId(change);
736
+ for await (const edge of iterate(input.access)) {
737
+ accessChanges.push(edge);
738
+ accessSubjects.add(`${edge.subjectType}:${accessRefId(edge.subject)}`);
739
+ }
740
+ const includePrincipal = (kind, id) => principalPopulation(config, kind) === "all" || Boolean(id && accessSubjects.has(`${kind}:${id}`));
699
741
  for await (const user of iterate(input.users)) {
700
- localUsers.push(mapUser(user, op));
742
+ if (includePrincipal("user", accessRefId(user))) {
743
+ localUsers.push(mapScimPrincipal(await projectUser(user, principalMappers), "user", op));
744
+ }
745
+ }
746
+ for await (const customer of iterate(input.customers)) {
747
+ if (includePrincipal("customer", accessRefId(customer))) {
748
+ localUsers.push(mapScimPrincipal(await projectCustomer(customer, principalMappers), "customer", op));
749
+ }
750
+ }
751
+ for await (const workload of iterate(input.workloads)) {
752
+ if (includePrincipal("workload", accessRefId(workload))) {
753
+ localUsers.push(mapScimPrincipal(await projectWorkload(workload, principalMappers), "workload", op));
754
+ }
701
755
  }
702
756
  for await (const group of iterate(input.groups)) {
703
757
  const source = transformGroup(group, transforms);
@@ -719,7 +773,7 @@ async function buildSyncPayload(config, input, transforms, incremental, extraAcc
719
773
  collectedResources.push(source);
720
774
  }
721
775
  resources.push(...buildNestedResourceTree(collectedResources, op));
722
- for await (const edge of iterate(input.access)) {
776
+ for (const edge of accessChanges) {
723
777
  seenAccessKeys.add(accessKey(edge));
724
778
  applyAccessChange(edge, identityToPermissions, localUsers, applicationName(config), incremental ? "add" : undefined);
725
779
  if (typeof edge.target !== "string") {
@@ -933,17 +987,17 @@ function applyAccessChange(change, identityToPermissions, localUsers, applicatio
933
987
  const identity = accessRefId(change.subject);
934
988
  const target = accessRefId(change.target);
935
989
  let localUser = localUsers.find((user) => accessRefId(user.unique_id ?? user.name) === identity);
936
- if (change.subjectType === "workload") {
990
+ if (change.subjectType !== "user") {
937
991
  if (localUser) {
938
992
  localUser.custom_properties = {
939
993
  ...localUser.custom_properties,
940
- identity_type: "workload"
994
+ identity_type: change.subjectType
941
995
  };
942
996
  } else {
943
997
  localUser = {
944
998
  name: identity,
945
999
  unique_id: identity,
946
- custom_properties: { identity_type: "workload" },
1000
+ custom_properties: { identity_type: change.subjectType },
947
1001
  operation
948
1002
  };
949
1003
  localUsers.push(localUser);
@@ -996,30 +1050,64 @@ function applyAccessChange(change, identityToPermissions, localUsers, applicatio
996
1050
  }
997
1051
  identityToPermissions.push(access);
998
1052
  }
999
- function mapUser(user, operation) {
1053
+ async function projectUser(user, mappers) {
1054
+ const mapped = await (mappers.mapUserToScim?.(user) ?? baseUserToScimUser(user));
1055
+ return { ...mapped, id: mapped.id ?? user.id };
1056
+ }
1057
+ async function projectCustomer(customer, mappers) {
1058
+ const mapped = await (mappers.mapCustomerToScim?.(customer) ?? baseCustomerToScim(customer));
1059
+ return { ...mapped, id: mapped.id ?? customer.id };
1060
+ }
1061
+ async function projectWorkload(workload, mappers) {
1062
+ const mapped = await (mappers.mapWorkloadToScim?.(workload) ?? baseWorkloadToScim(workload));
1063
+ return { ...mapped, id: mapped.id ?? workload.id };
1064
+ }
1065
+ function mapScimPrincipal(principal, identityType, operation) {
1066
+ const { schemas: _schemas, id, displayName, userName, active, emails, groups, meta, ...custom } = principal;
1067
+ const uniqueId = stringValue(id) ?? stringValue(principal.externalId) ?? stringValue(userName) ?? "principal";
1000
1068
  return omitEmpty({
1001
- name: user.displayName ?? user.name ?? user.userName ?? user.id,
1002
- unique_id: user.id,
1003
- identities: buildOaaIdentities(user),
1004
- groups: user.groups?.map((group) => group.value),
1005
- is_active: user.active,
1006
- created_at: dateToIso(user.createdAt),
1069
+ name: stringValue(displayName) ?? stringValue(userName) ?? uniqueId,
1070
+ unique_id: uniqueId,
1071
+ identities: identityType === "customer" ? undefined : buildProjectedIdentities(principal),
1072
+ groups: identityType === "user" && Array.isArray(groups) ? groups.map((group) => typeof group === "string" ? group : stringField(group, "value")).filter((value) => Boolean(value)) : undefined,
1073
+ is_active: typeof active === "boolean" ? active : undefined,
1074
+ created_at: meta && typeof meta === "object" ? stringField(meta, "created") : undefined,
1007
1075
  custom_properties: omitEmpty({
1008
- ecid: user.ecid,
1009
- accountClass: user.accountClass,
1010
- externalId: user.externalId,
1011
- userName: user.userName,
1012
- tenantId: user.tenantId
1076
+ ...custom,
1077
+ ecid: identityType === "customer" ? undefined : projectedEcid(principal),
1078
+ accountClass: projectedAccountClass(principal),
1079
+ externalId: principal.externalId,
1080
+ userName,
1081
+ emails,
1082
+ identity_type: identityType === "user" ? undefined : identityType
1013
1083
  }),
1014
1084
  tags: [],
1015
1085
  operation
1016
1086
  });
1017
1087
  }
1018
- function buildOaaIdentities(user) {
1019
- const emails = user.email ? [user.email] : user.emails?.map((email) => email.value).filter(Boolean) ?? [];
1020
- const identities = [...user.ecid ? [user.ecid] : [], ...emails];
1088
+ function buildProjectedIdentities(principal) {
1089
+ const ecid = projectedEcid(principal);
1090
+ const projectedEmails = principal.emails;
1091
+ const emails = Array.isArray(projectedEmails) ? projectedEmails.map((email) => email && typeof email === "object" ? stringField(email, "value") : undefined).filter((value) => Boolean(value)) : [];
1092
+ const identities = [...ecid ? [ecid] : [], ...emails];
1021
1093
  return identities.length > 0 ? identities : undefined;
1022
1094
  }
1095
+ function projectedEcid(principal) {
1096
+ const extension = principal["urn:ionite:scim:schemas:extension:ion:2.0:User"];
1097
+ return stringValue(principal.ecid) ?? (extension && typeof extension === "object" ? stringField(extension, "ecid") : undefined);
1098
+ }
1099
+ function projectedAccountClass(principal) {
1100
+ const extension = principal["urn:ionite:scim:schemas:extension:ion:2.0:User"];
1101
+ return extension && typeof extension === "object" ? stringField(extension, "accountClass") : undefined;
1102
+ }
1103
+ function deletedPrincipal(id, identityType) {
1104
+ return {
1105
+ name: id,
1106
+ unique_id: id,
1107
+ custom_properties: { identity_type: identityType },
1108
+ operation: "delete"
1109
+ };
1110
+ }
1023
1111
  function mapGroup(group, operation) {
1024
1112
  const extension = authzGroupExtension(group);
1025
1113
  const id = stringField(group, "id") ?? stringField(group, "name") ?? stringField(group, "displayName");
@@ -1416,17 +1504,15 @@ function chunkString(value, size) {
1416
1504
  function byteLength(value) {
1417
1505
  return Buffer.byteLength(value, "utf8");
1418
1506
  }
1419
- function dateToIso(value) {
1420
- if (!value)
1421
- return;
1422
- return value instanceof Date ? value.toISOString() : value;
1423
- }
1424
1507
  function stringField(value, field) {
1425
1508
  if (!value || typeof value !== "object")
1426
1509
  return;
1427
1510
  const fieldValue = value[field];
1428
1511
  return typeof fieldValue === "string" && fieldValue.length > 0 ? fieldValue : undefined;
1429
1512
  }
1513
+ function stringValue(value) {
1514
+ return typeof value === "string" && value.length > 0 ? value : undefined;
1515
+ }
1430
1516
  function booleanField(value, field) {
1431
1517
  if (!value || typeof value !== "object")
1432
1518
  return;
@@ -1476,6 +1562,21 @@ function trimTrailingSlash2(value) {
1476
1562
  function applicationName(config) {
1477
1563
  return config.applicationName ?? DEFAULT_APPLICATION_NAME;
1478
1564
  }
1565
+ function principalPopulation(config, kind) {
1566
+ if (kind === "user")
1567
+ return config?.users?.population ?? "all";
1568
+ if (kind === "customer")
1569
+ return config?.customers?.population ?? "access";
1570
+ return config?.workloads?.population ?? "access";
1571
+ }
1572
+ async function shouldPushPrincipal(config, kind, id, accessStore) {
1573
+ if (principalPopulation(config, kind) === "all")
1574
+ return true;
1575
+ if (!accessStore || !id)
1576
+ return false;
1577
+ const result = await accessStore.listBySubject(id, kind, { start: 0, limit: 1 });
1578
+ return result.items.length > 0;
1579
+ }
1479
1580
  function delay(ms) {
1480
1581
  return new Promise((resolve) => setTimeout(resolve, ms));
1481
1582
  }
@@ -1494,7 +1595,7 @@ function createManagedAuthz(log, getIamDelta = () => {
1494
1595
  return;
1495
1596
  }, getIam = () => {
1496
1597
  return;
1497
- }) {
1598
+ }, getPrincipalMappers = () => ({})) {
1498
1599
  let current;
1499
1600
  let closed = false;
1500
1601
  let codeCatalog;
@@ -1504,7 +1605,7 @@ function createManagedAuthz(log, getIamDelta = () => {
1504
1605
  mapGroup: current?.mapGroup,
1505
1606
  mapRole: current?.mapRole,
1506
1607
  mapResource: current?.mapResource
1507
- }), () => configTrustedClientGrants(current), () => {
1608
+ }), getPrincipalMappers, () => current?.accessStore, () => configTrustedClientGrants(current), () => {
1508
1609
  const catalog = current?.catalogStore;
1509
1610
  return catalog || codeCatalog ? { catalog, code: codeCatalog, resources: current?.resources, cache: adjacencyCache } : undefined;
1510
1611
  });
@@ -3444,9 +3545,9 @@ import {
3444
3545
  unionCatalogRead as unionCatalogRead2
3445
3546
  } from "@ionite/core";
3446
3547
  import {
3447
- baseCustomerToScim,
3448
- baseUserToScimUser,
3449
- baseWorkloadToScim,
3548
+ baseCustomerToScim as baseCustomerToScim2,
3549
+ baseUserToScimUser as baseUserToScimUser2,
3550
+ baseWorkloadToScim as baseWorkloadToScim2,
3450
3551
  entitlementToScimGroup
3451
3552
  } from "@ionite/core/server";
3452
3553
 
@@ -4099,7 +4200,7 @@ function createManagedIamDelta(log) {
4099
4200
  return {
4100
4201
  externalId: externalId2,
4101
4202
  resourceType: "workload",
4102
- create: baseWorkloadToScim({ ...workload, externalId: externalId2 })
4203
+ create: await (deps.mapWorkloadToScim?.({ ...workload, externalId: externalId2 }) ?? baseWorkloadToScim2({ ...workload, externalId: externalId2 }))
4103
4204
  };
4104
4205
  }
4105
4206
  if (change.subjectType === "customer") {
@@ -4110,7 +4211,7 @@ function createManagedIamDelta(log) {
4110
4211
  const externalId2 = customer?.externalId ?? customer?.id ?? id;
4111
4212
  if (!externalId2)
4112
4213
  return;
4113
- const body = customer ? baseCustomerToScim({ ...customer, externalId: externalId2 }) : {
4214
+ const body = customer ? await (deps.mapCustomerToScim?.({ ...customer, externalId: externalId2 }) ?? baseCustomerToScim2({ ...customer, externalId: externalId2 })) : {
4114
4215
  schemas: ["urn:ionite:scim:schemas:core:2.0:Customer"],
4115
4216
  externalId: externalId2,
4116
4217
  displayName: externalId2,
@@ -4119,12 +4220,7 @@ function createManagedIamDelta(log) {
4119
4220
  return {
4120
4221
  externalId: externalId2,
4121
4222
  resourceType: "customer",
4122
- create: {
4123
- schemas: body.schemas ?? ["urn:ionite:scim:schemas:core:2.0:Customer"],
4124
- externalId: externalId2,
4125
- displayName: body.displayName,
4126
- active: body.active ?? true
4127
- }
4223
+ create: body
4128
4224
  };
4129
4225
  }
4130
4226
  const inline = refObject(change.subject);
@@ -4137,7 +4233,7 @@ function createManagedIamDelta(log) {
4137
4233
  const externalId = user?.externalId;
4138
4234
  if (!user || !externalId)
4139
4235
  return;
4140
- return { externalId, resourceType: "user", create: await (deps.mapUserToScim?.(user) ?? baseUserToScimUser(user)) };
4236
+ return { externalId, resourceType: "user", create: await (deps.mapUserToScim?.(user) ?? baseUserToScimUser2(user)) };
4141
4237
  };
4142
4238
  const resolveTarget = async (change) => {
4143
4239
  const inline = refObject(change.target);
@@ -4255,7 +4351,7 @@ function createManagedIamDelta(log) {
4255
4351
  }
4256
4352
  return members.length > 0 ? members : undefined;
4257
4353
  };
4258
- const projectUser = async (user) => {
4354
+ const projectUser2 = async (user) => {
4259
4355
  if (!isReady() || !kindDeltaOn("user"))
4260
4356
  return "skipped";
4261
4357
  const externalId = user.externalId;
@@ -4271,10 +4367,10 @@ function createManagedIamDelta(log) {
4271
4367
  const scim = ensureClient();
4272
4368
  if (!scim)
4273
4369
  return "skipped";
4274
- const body = await (deps.mapUserToScim?.(user) ?? baseUserToScimUser(user));
4370
+ const body = await (deps.mapUserToScim?.(user) ?? baseUserToScimUser2(user));
4275
4371
  return scim.upsertResource("user", externalId, body);
4276
4372
  };
4277
- const projectWorkload = async (workload) => {
4373
+ const projectWorkload2 = async (workload) => {
4278
4374
  if (!isReady() || !kindDeltaOn("workload"))
4279
4375
  return "skipped";
4280
4376
  const externalId = workload.externalId ?? workload.id;
@@ -4283,9 +4379,10 @@ function createManagedIamDelta(log) {
4283
4379
  const scim = ensureClient();
4284
4380
  if (!scim)
4285
4381
  return "skipped";
4286
- return scim.upsertResource("workload", externalId, baseWorkloadToScim({ ...workload, externalId }));
4382
+ const projected = await (deps.mapWorkloadToScim?.({ ...workload, externalId }) ?? baseWorkloadToScim2({ ...workload, externalId }));
4383
+ return scim.upsertResource("workload", externalId, projected);
4287
4384
  };
4288
- const projectCustomer = async (customer) => {
4385
+ const projectCustomer2 = async (customer) => {
4289
4386
  if (!isReady() || !kindDeltaOn("customer"))
4290
4387
  return "skipped";
4291
4388
  const externalId = customer.externalId ?? customer.id;
@@ -4294,13 +4391,8 @@ function createManagedIamDelta(log) {
4294
4391
  const scim = ensureClient();
4295
4392
  if (!scim)
4296
4393
  return "skipped";
4297
- const projected = baseCustomerToScim({ ...customer, externalId });
4298
- return scim.upsertResource("customer", externalId, {
4299
- schemas: projected.schemas,
4300
- externalId,
4301
- displayName: projected.displayName,
4302
- active: projected.active
4303
- });
4394
+ const projected = await (deps.mapCustomerToScim?.({ ...customer, externalId }) ?? baseCustomerToScim2({ ...customer, externalId }));
4395
+ return scim.upsertResource("customer", externalId, projected);
4304
4396
  };
4305
4397
  const projectEntitlement = async (entity, type, restoreRoots = true) => {
4306
4398
  if (!isReady() || !anyDeltaPatch())
@@ -4336,7 +4428,7 @@ function createManagedIamDelta(log) {
4336
4428
  };
4337
4429
  const emitter = {
4338
4430
  async onUserUpsert(user) {
4339
- requirePushed(await projectUser(user), "user upsert");
4431
+ requirePushed(await projectUser2(user), "user upsert");
4340
4432
  },
4341
4433
  async onUserDelete(externalId) {
4342
4434
  if (!isReady() || !kindDeltaOn("user"))
@@ -4346,6 +4438,28 @@ function createManagedIamDelta(log) {
4346
4438
  return;
4347
4439
  requirePushed(await scim.deleteResource("user", externalId), "user delete");
4348
4440
  },
4441
+ async onWorkloadUpsert(workload) {
4442
+ requirePushed(await projectWorkload2(workload), "workload upsert");
4443
+ },
4444
+ async onWorkloadDelete(externalId) {
4445
+ if (!isReady() || !kindDeltaOn("workload"))
4446
+ return;
4447
+ const scim = ensureClient();
4448
+ if (!scim)
4449
+ return;
4450
+ requirePushed(await scim.deleteResource("workload", externalId), "workload delete");
4451
+ },
4452
+ async onCustomerUpsert(customer) {
4453
+ requirePushed(await projectCustomer2(customer), "customer upsert");
4454
+ },
4455
+ async onCustomerDelete(externalId) {
4456
+ if (!isReady() || !kindDeltaOn("customer"))
4457
+ return;
4458
+ const scim = ensureClient();
4459
+ if (!scim)
4460
+ return;
4461
+ requirePushed(await scim.deleteResource("customer", externalId), "customer delete");
4462
+ },
4349
4463
  async onEntitlementUpsert(entity, type) {
4350
4464
  requirePushed(await projectEntitlement(entity, type), `${type} upsert`);
4351
4465
  },
@@ -4417,13 +4531,13 @@ function createManagedIamDelta(log) {
4417
4531
  await run(input.permissions, (value) => projectEntitlement(value, "permission", false), (value) => {
4418
4532
  return `permission upsert for ${value.id}`;
4419
4533
  });
4420
- await run(input.users, (value) => projectUser(value), (value) => {
4534
+ await run(input.users, (value) => projectUser2(value), (value) => {
4421
4535
  return `user upsert for ${value.id ?? "unknown"}`;
4422
4536
  });
4423
- await run(input.workloads, (value) => projectWorkload(value), (value) => {
4537
+ await run(input.workloads, (value) => projectWorkload2(value), (value) => {
4424
4538
  return `workload upsert for ${value.id}`;
4425
4539
  });
4426
- await run(input.customers, (value) => projectCustomer(value), (value) => {
4540
+ await run(input.customers, (value) => projectCustomer2(value), (value) => {
4427
4541
  return `customer upsert for ${value.id ?? "unknown"}`;
4428
4542
  });
4429
4543
  await run(input.access, (value) => project(value, "add"), (value) => {
@@ -9901,7 +10015,7 @@ function tenantManager(ion, options) {
9901
10015
  }
9902
10016
 
9903
10017
  // packages/server/src/version.ts
9904
- var ION_SDK_VERSION = "0.0.24-beta.20260907.3";
10018
+ var ION_SDK_VERSION = "0.0.24-beta.20260910.1";
9905
10019
 
9906
10020
  // packages/server/src/index.ts
9907
10021
  export * from "@ionite/core";
@@ -12464,6 +12578,34 @@ async function buildCapabilitiezResponse(request, ion, capabilitiez) {
12464
12578
  return denied;
12465
12579
  return Response.json(capabilitiez.build(), { status: 200 });
12466
12580
  }
12581
+ async function collectOaaAccess(accessStore) {
12582
+ if (!accessStore)
12583
+ return [];
12584
+ const roots = [];
12585
+ for await (const root of listGenerator3((start, limit) => accessStore.list({ start, limit }))) {
12586
+ roots.push(root);
12587
+ }
12588
+ return roots;
12589
+ }
12590
+ function oaaPrincipalIds(access, kind) {
12591
+ return [
12592
+ ...new Set(access.filter((root) => root.subjectType === kind).map((root) => typeof root.subject === "string" ? root.subject : root.subject.id).filter((id) => Boolean(id)))
12593
+ ];
12594
+ }
12595
+ function oaaPrincipalIterable(store, population, accessIds) {
12596
+ if (!store)
12597
+ return;
12598
+ if (population === "all") {
12599
+ return listGenerator3((start, limit) => store.list({ start, limit }));
12600
+ }
12601
+ return async function* accessPrincipals() {
12602
+ for (const id of accessIds) {
12603
+ const principal = await store.get(id);
12604
+ if (principal)
12605
+ yield principal;
12606
+ }
12607
+ }();
12608
+ }
12467
12609
  async function buildAuthzOaaSyncResponse(request, ion, frameworkConfig) {
12468
12610
  if (!ion.isReady()) {
12469
12611
  return createNotReadyResponse();
@@ -12480,16 +12622,22 @@ async function buildAuthzOaaSyncResponse(request, ion, frameworkConfig) {
12480
12622
  }
12481
12623
  const reconcile = ion.authz ? await ion.authz.reconcile() : undefined;
12482
12624
  const userStore = frameworkConfig.iam?.userStore;
12625
+ const customerStore = frameworkConfig.iam?.customerStore ?? frameworkConfig.ciam?.customerStore;
12626
+ const configuredWorkload = frameworkConfig.workload;
12627
+ const workloadIdentityStore = frameworkConfig.iam?.workloadIdentityStore ?? (configuredWorkload && "workloadIdentityStore" in configuredWorkload ? configuredWorkload.workloadIdentityStore : configuredWorkload && ("incoming" in configuredWorkload) && configuredWorkload.incoming && !Array.isArray(configuredWorkload.incoming) && ("workloadIdentityStore" in configuredWorkload.incoming) ? configuredWorkload.incoming.workloadIdentityStore : undefined);
12483
12628
  const catalogStore = unionCatalogRead3(frameworkConfig.authz?.catalog ? toCodeCatalog2(frameworkConfig.authz.catalog) : undefined, frameworkConfig.authz?.catalogStore);
12484
12629
  const accessStore = frameworkConfig.authz?.accessStore;
12485
12630
  const resourceProvider = frameworkConfig.authz?.resources;
12631
+ const access = await collectOaaAccess(accessStore);
12486
12632
  const result = await oaa.sync({
12487
- users: userStore ? listGenerator3((start, limit) => userStore.list({ start, limit })) : undefined,
12633
+ users: oaaPrincipalIterable(userStore, oaa.population("user"), oaaPrincipalIds(access, "user")),
12634
+ customers: oaaPrincipalIterable(customerStore, oaa.population("customer"), oaaPrincipalIds(access, "customer")),
12635
+ workloads: oaaPrincipalIterable(workloadIdentityStore, oaa.population("workload"), oaaPrincipalIds(access, "workload")),
12488
12636
  groups: catalogStore ? listGenerator3((start, limit) => catalogStore.groups.list({ start, limit })) : undefined,
12489
12637
  roles: catalogStore ? listGenerator3((start, limit) => catalogStore.roles.list({ start, limit })) : undefined,
12490
12638
  permissions: catalogStore ? listGenerator3((start, limit) => catalogStore.permissions.list({ start, limit })) : undefined,
12491
12639
  resources: resourceProvider ? listGenerator3((start, limit) => resourceProvider.list({ start, limit })) : undefined,
12492
- access: accessStore ? listGenerator3((start, limit) => accessStore.list({ start, limit })) : undefined
12640
+ access
12493
12641
  }, { mode: "snapshot", compression: "gzip", multipart: "auto" });
12494
12642
  return Response.json({ ...result, reconcile });
12495
12643
  }
@@ -12691,7 +12839,9 @@ function buildModules(remoteConfig, frameworkConfig, log, defaultSecret, kms, au
12691
12839
  accessStore: frameworkConfig.authz?.accessStore,
12692
12840
  catalogStore: frameworkConfig.authz?.catalogStore,
12693
12841
  codeCatalog: authzCodeCatalog,
12694
- mapUserToScim: mergedIamConfig.inboundUsers?.mapBaseUserToScim
12842
+ mapUserToScim: mergedIamConfig.inboundUsers?.mapBaseUserToScim,
12843
+ mapCustomerToScim: mergedIamConfig.inboundCustomers?.mapBaseCustomerToScim,
12844
+ mapWorkloadToScim: mergedIamConfig.inboundWorkloads?.mapBaseWorkloadToScim
12695
12845
  });
12696
12846
  let iamHandle;
12697
12847
  if (requiresIamWorkload && !workloadHandle) {
@@ -12800,7 +12950,11 @@ function ionite(source, config) {
12800
12950
  kms: createManagedKms(defaultLog),
12801
12951
  workload: createManagedWorkload(defaultLog),
12802
12952
  otel: createManagedOtel(defaultLog),
12803
- authz: createManagedAuthz(defaultLog, () => iamDeltaModule.handle(), () => resultRef?.iam),
12953
+ authz: createManagedAuthz(defaultLog, () => iamDeltaModule.handle(), () => resultRef?.iam, () => ({
12954
+ mapUserToScim: state.frameworkConfig.iam?.inboundUsers?.mapBaseUserToScim,
12955
+ mapCustomerToScim: state.frameworkConfig.iam?.inboundCustomers?.mapBaseCustomerToScim,
12956
+ mapWorkloadToScim: state.frameworkConfig.iam?.inboundWorkloads?.mapBaseWorkloadToScim
12957
+ })),
12804
12958
  iamDelta: iamDeltaModule,
12805
12959
  sso: createManagedReadiness("sso"),
12806
12960
  iam: createManagedReadiness("iam"),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ionite/server",
3
- "version": "0.0.24-beta.20260907.3",
3
+ "version": "0.0.24-beta.20260910.1",
4
4
  "description": "ionite Server (Node/server-only)",
5
5
  "private": false,
6
6
  "author": "ionite",
@@ -24,7 +24,7 @@
24
24
  "./package.json": "./package.json"
25
25
  },
26
26
  "dependencies": {
27
- "@ionite/core": "0.0.24-beta.20260907.3",
27
+ "@ionite/core": "0.0.24-beta.20260910.1",
28
28
  "@opentelemetry/api": "^1.9.1",
29
29
  "@opentelemetry/api-logs": "^0.220.0",
30
30
  "@opentelemetry/exporter-logs-otlp-http": "^0.220.0",